Auto merge of #133505 - compiler-errors:rollup-xjp8hdi, r=compiler-errors

Rollup of 12 pull requests

Successful merges:

 - #133042 (btree: add `{Entry,VacantEntry}::insert_entry`)
 - #133070 (Lexer tweaks)
 - #133136 (Support ranges in `<[T]>::get_many_mut()`)
 - #133140 (Inline ExprPrecedence::order into Expr::precedence)
 - #133155 (Yet more `rustc_mir_dataflow` cleanups)
 - #133282 (Shorten the `MaybeUninit` `Debug` implementation)
 - #133326 (Remove the `DefinitelyInitializedPlaces` analysis.)
 - #133362 (No need to re-sort existential preds in relate impl)
 - #133367 (Simplify array length mismatch error reporting (to not try to turn consts into target usizes))
 - #133394 (Bail on more errors in dyn ty lowering)
 - #133410 (target check_consistency: ensure target feature string makes some basic sense)
 - #133435 (miri: disable test_downgrade_observe test on macOS)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-11-26 21:57:32 +00:00
commit dd2837ec5d
87 changed files with 1012 additions and 1508 deletions

View file

@ -39,7 +39,9 @@ pub use crate::format::*;
use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter};
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
pub use crate::util::parser::ExprPrecedence;
use crate::util::parser::{
AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_RANGE, PREC_UNAMBIGUOUS,
};
/// A "Label" is an identifier of some point in sources,
/// e.g. in the following code:
@ -1314,53 +1316,71 @@ impl Expr {
Some(P(Ty { kind, id: self.id, span: self.span, tokens: None }))
}
pub fn precedence(&self) -> ExprPrecedence {
pub fn precedence(&self) -> i8 {
match self.kind {
ExprKind::Array(_) => ExprPrecedence::Array,
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
ExprKind::Call(..) => ExprPrecedence::Call,
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
ExprKind::Tup(_) => ExprPrecedence::Tup,
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
ExprKind::Unary(..) => ExprPrecedence::Unary,
ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit,
ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::Let(..) => ExprPrecedence::Let,
ExprKind::If(..) => ExprPrecedence::If,
ExprKind::While(..) => ExprPrecedence::While,
ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(_, _, MatchKind::Prefix) => ExprPrecedence::Match,
ExprKind::Match(_, _, MatchKind::Postfix) => ExprPrecedence::PostfixMatch,
ExprKind::Closure(..) => ExprPrecedence::Closure,
ExprKind::Block(..) => ExprPrecedence::Block,
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
ExprKind::Gen(..) => ExprPrecedence::Gen,
ExprKind::Await(..) => ExprPrecedence::Await,
ExprKind::Assign(..) => ExprPrecedence::Assign,
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
ExprKind::Field(..) => ExprPrecedence::Field,
ExprKind::Index(..) => ExprPrecedence::Index,
ExprKind::Range(..) => ExprPrecedence::Range,
ExprKind::Underscore => ExprPrecedence::Path,
ExprKind::Path(..) => ExprPrecedence::Path,
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
ExprKind::Break(..) => ExprPrecedence::Break,
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
ExprKind::Paren(..) => ExprPrecedence::Paren,
ExprKind::Try(..) => ExprPrecedence::Try,
ExprKind::Yield(..) => ExprPrecedence::Yield,
ExprKind::Yeet(..) => ExprPrecedence::Yeet,
ExprKind::Become(..) => ExprPrecedence::Become,
ExprKind::InlineAsm(..)
| ExprKind::Type(..)
| ExprKind::OffsetOf(..)
ExprKind::Closure(..) => PREC_CLOSURE,
ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
| ExprKind::Yield(..)
| ExprKind::Yeet(..)
| ExprKind::Become(..) => PREC_JUMP,
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
// ensures that `pprust` will add parentheses in the right places to get the desired
// parse.
ExprKind::Range(..) => PREC_RANGE,
// Binop-like expr kinds, handled by `AssocOp`.
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
ExprKind::Assign(..) |
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
// Unary, prefix
ExprKind::AddrOf(..)
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
// but we need to print `(let _ = a) < b` as-is with parens.
| ExprKind::Let(..)
| ExprKind::Unary(..) => PREC_PREFIX,
// Never need parens
ExprKind::Array(_)
| ExprKind::Await(..)
| ExprKind::Block(..)
| ExprKind::Call(..)
| ExprKind::ConstBlock(_)
| ExprKind::Field(..)
| ExprKind::ForLoop { .. }
| ExprKind::FormatArgs(..)
| ExprKind::MacCall(..) => ExprPrecedence::Mac,
ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err,
| ExprKind::Gen(..)
| ExprKind::If(..)
| ExprKind::IncludedBytes(..)
| ExprKind::Index(..)
| ExprKind::InlineAsm(..)
| ExprKind::Lit(_)
| ExprKind::Loop(..)
| ExprKind::MacCall(..)
| ExprKind::Match(..)
| ExprKind::MethodCall(..)
| ExprKind::OffsetOf(..)
| ExprKind::Paren(..)
| ExprKind::Path(..)
| ExprKind::Repeat(..)
| ExprKind::Struct(..)
| ExprKind::Try(..)
| ExprKind::TryBlock(..)
| ExprKind::Tup(_)
| ExprKind::Type(..)
| ExprKind::Underscore
| ExprKind::While(..)
| ExprKind::Err(_)
| ExprKind::Dummy => PREC_UNAMBIGUOUS,
}
}

View file

@ -237,121 +237,6 @@ pub const PREC_PREFIX: i8 = 50;
pub const PREC_UNAMBIGUOUS: i8 = 60;
pub const PREC_FORCE_PAREN: i8 = 100;
#[derive(Debug, Clone, Copy)]
pub enum ExprPrecedence {
Closure,
Break,
Continue,
Ret,
Yield,
Yeet,
Become,
Range,
Binary(BinOpKind),
Cast,
Assign,
AssignOp,
AddrOf,
Let,
Unary,
Call,
MethodCall,
Field,
Index,
Try,
Mac,
Array,
Repeat,
Tup,
Lit,
Path,
Paren,
If,
While,
ForLoop,
Loop,
Match,
PostfixMatch,
ConstBlock,
Block,
TryBlock,
Struct,
Gen,
Await,
Err,
}
impl ExprPrecedence {
pub fn order(self) -> i8 {
match self {
ExprPrecedence::Closure => PREC_CLOSURE,
ExprPrecedence::Break
| ExprPrecedence::Continue
| ExprPrecedence::Ret
| ExprPrecedence::Yield
| ExprPrecedence::Yeet
| ExprPrecedence::Become => PREC_JUMP,
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
// ensures that `pprust` will add parentheses in the right places to get the desired
// parse.
ExprPrecedence::Range => PREC_RANGE,
// Binop-like expr kinds, handled by `AssocOp`.
ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
ExprPrecedence::Assign |
ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
// Unary, prefix
ExprPrecedence::AddrOf
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
// but we need to print `(let _ = a) < b` as-is with parens.
| ExprPrecedence::Let
| ExprPrecedence::Unary => PREC_PREFIX,
// Never need parens
ExprPrecedence::Array
| ExprPrecedence::Await
| ExprPrecedence::Block
| ExprPrecedence::Call
| ExprPrecedence::ConstBlock
| ExprPrecedence::Field
| ExprPrecedence::ForLoop
| ExprPrecedence::Gen
| ExprPrecedence::If
| ExprPrecedence::Index
| ExprPrecedence::Lit
| ExprPrecedence::Loop
| ExprPrecedence::Mac
| ExprPrecedence::Match
| ExprPrecedence::MethodCall
| ExprPrecedence::Paren
| ExprPrecedence::Path
| ExprPrecedence::PostfixMatch
| ExprPrecedence::Repeat
| ExprPrecedence::Struct
| ExprPrecedence::Try
| ExprPrecedence::TryBlock
| ExprPrecedence::Tup
| ExprPrecedence::While
| ExprPrecedence::Err => PREC_UNAMBIGUOUS,
}
}
}
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
pub fn prec_let_scrutinee_needs_par() -> usize {
AssocOp::LAnd.precedence()

View file

@ -59,7 +59,7 @@ impl<'a> State<'a> {
}
fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) {
self.print_expr_cond_paren(expr, expr.precedence().order() < prec, fixup);
self.print_expr_cond_paren(expr, expr.precedence() < prec, fixup);
}
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
@ -615,7 +615,7 @@ impl<'a> State<'a> {
expr,
// Parenthesize if required by precedence, or in the
// case of `break 'inner: loop { break 'inner 1 } + 1`
expr.precedence().order() < parser::PREC_JUMP
expr.precedence() < parser::PREC_JUMP
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
fixup.subsequent_subexpression(),
);

View file

@ -191,6 +191,6 @@ impl FixupContext {
/// "let chain".
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|| parser::needs_par_as_let_scrutinee(expr.precedence().order())
|| parser::needs_par_as_let_scrutinee(expr.precedence())
}
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use rustc_abi::ExternAbi;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::util::parser::{AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_UNAMBIGUOUS};
use rustc_ast::{
self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label,
LitKind, TraitObjectSyntax, UintTy,
@ -1708,41 +1708,54 @@ pub struct Expr<'hir> {
}
impl Expr<'_> {
pub fn precedence(&self) -> ExprPrecedence {
pub fn precedence(&self) -> i8 {
match self.kind {
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
ExprKind::Array(_) => ExprPrecedence::Array,
ExprKind::Call(..) => ExprPrecedence::Call,
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
ExprKind::Tup(_) => ExprPrecedence::Tup,
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
ExprKind::Unary(..) => ExprPrecedence::Unary,
ExprKind::Lit(_) => ExprPrecedence::Lit,
ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::Closure { .. } => PREC_CLOSURE,
ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
| ExprKind::Yield(..)
| ExprKind::Become(..) => PREC_JUMP,
// Binop-like expr kinds, handled by `AssocOp`.
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
ExprKind::Assign(..) |
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
// Unary, prefix
ExprKind::AddrOf(..)
// Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
// However, this is not exactly right. When `let _ = a` is the LHS of a binop we
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
// but we need to print `(let _ = a) < b` as-is with parens.
| ExprKind::Let(..)
| ExprKind::Unary(..) => PREC_PREFIX,
// Never need parens
ExprKind::Array(_)
| ExprKind::Block(..)
| ExprKind::Call(..)
| ExprKind::ConstBlock(_)
| ExprKind::Field(..)
| ExprKind::If(..)
| ExprKind::Index(..)
| ExprKind::InlineAsm(..)
| ExprKind::Lit(_)
| ExprKind::Loop(..)
| ExprKind::Match(..)
| ExprKind::MethodCall(..)
| ExprKind::OffsetOf(..)
| ExprKind::Path(..)
| ExprKind::Repeat(..)
| ExprKind::Struct(..)
| ExprKind::Tup(_)
| ExprKind::Type(..)
| ExprKind::Err(_) => PREC_UNAMBIGUOUS,
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
ExprKind::If(..) => ExprPrecedence::If,
ExprKind::Let(..) => ExprPrecedence::Let,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match,
ExprKind::Closure { .. } => ExprPrecedence::Closure,
ExprKind::Block(..) => ExprPrecedence::Block,
ExprKind::Assign(..) => ExprPrecedence::Assign,
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
ExprKind::Field(..) => ExprPrecedence::Field,
ExprKind::Index(..) => ExprPrecedence::Index,
ExprKind::Path(..) => ExprPrecedence::Path,
ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
ExprKind::Break(..) => ExprPrecedence::Break,
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::Become(..) => ExprPrecedence::Become,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
ExprKind::Yield(..) => ExprPrecedence::Yield,
ExprKind::Type(..) | ExprKind::InlineAsm(..) | ExprKind::OffsetOf(..) => {
ExprPrecedence::Mac
}
ExprKind::Err(_) => ExprPrecedence::Err,
}
}

View file

@ -8,7 +8,8 @@ use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
use rustc_middle::span_bug;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::{
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, Upcast,
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
TypeVisitableExt, Upcast,
};
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
@ -92,11 +93,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
// We don't support >1 principal
if regular_traits.len() > 1 {
let _ = self.report_trait_object_addition_traits_error(&regular_traits);
} else if regular_traits.is_empty() && auto_traits.is_empty() {
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
return Ty::new_error(tcx, reported);
let guar = self.report_trait_object_addition_traits_error(&regular_traits);
return Ty::new_error(tcx, guar);
}
// We don't support empty trait objects.
if regular_traits.is_empty() && auto_traits.is_empty() {
let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
return Ty::new_error(tcx, guar);
}
// Don't create a dyn trait if we have errors in the principal.
if let Err(guar) = trait_bounds.error_reported() {
return Ty::new_error(tcx, guar);
}
// Check that there are no gross dyn-compatibility violations;

View file

@ -1011,7 +1011,7 @@ impl<'a> State<'a> {
}
fn print_expr_maybe_paren(&mut self, expr: &hir::Expr<'_>, prec: i8) {
self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
self.print_expr_cond_paren(expr, expr.precedence() < prec)
}
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
@ -1045,7 +1045,7 @@ impl<'a> State<'a> {
}
self.space();
self.word_space("=");
let npals = || parser::needs_par_as_let_scrutinee(init.precedence().order());
let npals = || parser::needs_par_as_let_scrutinee(init.precedence());
self.print_expr_cond_paren(init, Self::cond_needs_par(init) || npals())
}

View file

@ -606,7 +606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if let Ok(rest_snippet) = rest_snippet {
let sugg = if callee_expr.precedence().order() >= PREC_UNAMBIGUOUS {
let sugg = if callee_expr.precedence() >= PREC_UNAMBIGUOUS {
vec![
(up_to_rcvr_span, "".to_string()),
(rest_span, format!(".{}({rest_snippet}", segment.ident)),

View file

@ -1107,7 +1107,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}
fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
let expr_prec = self.expr.precedence().order();
let expr_prec = self.expr.precedence();
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_UNAMBIGUOUS;
let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));

View file

@ -2,7 +2,7 @@ use core::cmp::min;
use core::iter;
use hir::def_id::LocalDefId;
use rustc_ast::util::parser::{ExprPrecedence, PREC_UNAMBIGUOUS};
use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
use rustc_data_structures::packed::Pu128;
use rustc_errors::{Applicability, Diag, MultiSpan};
use rustc_hir as hir;
@ -398,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// so we remove the user's `clone` call.
{
vec![(receiver_method.ident.span, conversion_method.name.to_string())]
} else if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
} else if expr.precedence() < PREC_UNAMBIGUOUS {
vec![
(expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
@ -1376,7 +1376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
let mut sugg = if expr.precedence().order() >= PREC_UNAMBIGUOUS {
let mut sugg = if expr.precedence() >= PREC_UNAMBIGUOUS {
vec![(span.shrink_to_hi(), ".into()".to_owned())]
} else {
vec![
@ -3000,7 +3000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`",
);
let close_paren = if expr.precedence().order() < PREC_UNAMBIGUOUS {
let close_paren = if expr.precedence() < PREC_UNAMBIGUOUS {
sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
")"
} else {
@ -3025,7 +3025,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let len = src.trim_end_matches(&checked_ty.to_string()).len();
expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
},
if expr.precedence().order() < PREC_UNAMBIGUOUS {
if expr.precedence() < PREC_UNAMBIGUOUS {
// Readd `)`
format!("{expected_ty})")
} else {

View file

@ -566,19 +566,19 @@ impl Cursor<'_> {
fn c_or_byte_string(
&mut self,
mk_kind: impl FnOnce(bool) -> LiteralKind,
mk_kind_raw: impl FnOnce(Option<u8>) -> LiteralKind,
mk_kind: fn(bool) -> LiteralKind,
mk_kind_raw: fn(Option<u8>) -> LiteralKind,
single_quoted: Option<fn(bool) -> LiteralKind>,
) -> TokenKind {
match (self.first(), self.second(), single_quoted) {
('\'', _, Some(mk_kind)) => {
('\'', _, Some(single_quoted)) => {
self.bump();
let terminated = self.single_quoted_string();
let suffix_start = self.pos_within_token();
if terminated {
self.eat_literal_suffix();
}
let kind = mk_kind(terminated);
let kind = single_quoted(terminated);
Literal { kind, suffix_start }
}
('"', _, _) => {

View file

@ -77,63 +77,53 @@ fn test_too_many_hashes() {
check_raw_str(&s2, Err(RawStrError::TooManyDelimiters { found: u32::from(max_count) + 1 }));
}
// https://github.com/rust-lang/rust/issues/70528
#[test]
fn test_valid_shebang() {
// https://github.com/rust-lang/rust/issues/70528
let input = "#!/usr/bin/rustrun\nlet x = 5;";
assert_eq!(strip_shebang(input), Some(18));
}
let input = "#!/bin/bash";
assert_eq!(strip_shebang(input), Some(input.len()));
#[test]
fn test_invalid_shebang_valid_rust_syntax() {
// https://github.com/rust-lang/rust/issues/70528
let input = "#! [bad_attribute]";
let input = "#![attribute]";
assert_eq!(strip_shebang(input), None);
let input = "#! /bin/bash";
assert_eq!(strip_shebang(input), Some(input.len()));
let input = "#! [attribute]";
assert_eq!(strip_shebang(input), None);
let input = "#! /* blah */ /bin/bash";
assert_eq!(strip_shebang(input), Some(input.len()));
let input = "#! /* blah */ [attribute]";
assert_eq!(strip_shebang(input), None);
let input = "#! // blah\n/bin/bash";
assert_eq!(strip_shebang(input), Some(10)); // strip up to the newline
let input = "#! // blah\n[attribute]";
assert_eq!(strip_shebang(input), None);
let input = "#! /* blah\nblah\nblah */ /bin/bash";
assert_eq!(strip_shebang(input), Some(10));
let input = "#! /* blah\nblah\nblah */ [attribute]";
assert_eq!(strip_shebang(input), None);
let input = "#!\n/bin/sh";
assert_eq!(strip_shebang(input), Some(2));
let input = "#!\n[attribute]";
assert_eq!(strip_shebang(input), None);
}
#[test]
fn test_shebang_second_line() {
// Because shebangs are interpreted by the kernel, they must be on the first line
let input = "\n#!/bin/bash";
assert_eq!(strip_shebang(input), None);
}
#[test]
fn test_shebang_space() {
let input = "#! /bin/bash";
assert_eq!(strip_shebang(input), Some(input.len()));
}
#[test]
fn test_shebang_empty_shebang() {
let input = "#! \n[attribute(foo)]";
let input = "\n#![attribute]";
assert_eq!(strip_shebang(input), None);
}
#[test]
fn test_invalid_shebang_comment() {
let input = "#!//bin/ami/a/comment\n[";
assert_eq!(strip_shebang(input), None)
}
#[test]
fn test_invalid_shebang_another_comment() {
let input = "#!/*bin/ami/a/comment*/\n[attribute";
assert_eq!(strip_shebang(input), None)
}
#[test]
fn test_shebang_valid_rust_after() {
let input = "#!/*bin/ami/a/comment*/\npub fn main() {}";
assert_eq!(strip_shebang(input), Some(23))
}
#[test]
fn test_shebang_followed_by_attrib() {
let input = "#!/bin/rust-scripts\n#![allow_unused(true)]";
assert_eq!(strip_shebang(input), Some(19));
}
fn check_lexing(src: &str, expect: Expect) {
let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect();
expect.assert_eq(&actual)

View file

@ -151,10 +151,6 @@ impl<'tcx> Const<'tcx> {
}
impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
fn try_to_target_usize(self, interner: TyCtxt<'tcx>) -> Option<u64> {
self.try_to_target_usize(interner)
}
fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
Const::new_infer(tcx, infer)
}

View file

@ -58,12 +58,9 @@ impl<'tcx> TypeError<'tcx> {
pluralize!(values.found)
)
.into(),
TypeError::FixedArraySize(values) => format!(
"expected an array with a fixed size of {} element{}, found one with {} element{}",
values.expected,
pluralize!(values.expected),
values.found,
pluralize!(values.found)
TypeError::ArraySize(values) => format!(
"expected an array with a size of {}, found one with a size of {}",
values.expected, values.found,
)
.into(),
TypeError::ArgCount => "incorrect number of function parameters".into(),

View file

@ -3,7 +3,6 @@ use std::iter;
pub use rustc_type_ir::relate::*;
use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
use crate::ty::{self as ty, Ty, TyCtxt};
pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>;
@ -86,10 +85,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
// in `a`.
let mut a_v: Vec<_> = a.into_iter().collect();
let mut b_v: Vec<_> = b.into_iter().collect();
// `skip_binder` here is okay because `stable_cmp` doesn't look at binders
a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
a_v.dedup();
b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
b_v.dedup();
if a_v.len() != b_v.len() {
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));

View file

@ -1,6 +1,7 @@
//! Random access inspection of the results of a dataflow analysis.
use std::cmp::Ordering;
use std::ops::{Deref, DerefMut};
#[cfg(debug_assertions)]
use rustc_index::bit_set::BitSet;
@ -8,18 +9,63 @@ use rustc_middle::mir::{self, BasicBlock, Location};
use super::{Analysis, Direction, Effect, EffectIndex, Results};
/// Allows random access inspection of the results of a dataflow analysis.
/// Some `ResultsCursor`s want to own a `Results`, and some want to borrow a `Results`, either
/// mutable or immutably. This type allows all of the above. It's similar to `Cow`.
pub enum ResultsHandle<'a, 'tcx, A>
where
A: Analysis<'tcx>,
{
Borrowed(&'a Results<'tcx, A>),
BorrowedMut(&'a mut Results<'tcx, A>),
Owned(Results<'tcx, A>),
}
impl<'tcx, A> Deref for ResultsHandle<'_, 'tcx, A>
where
A: Analysis<'tcx>,
{
type Target = Results<'tcx, A>;
fn deref(&self) -> &Results<'tcx, A> {
match self {
ResultsHandle::Borrowed(borrowed) => borrowed,
ResultsHandle::BorrowedMut(borrowed) => borrowed,
ResultsHandle::Owned(owned) => owned,
}
}
}
impl<'tcx, A> DerefMut for ResultsHandle<'_, 'tcx, A>
where
A: Analysis<'tcx>,
{
fn deref_mut(&mut self) -> &mut Results<'tcx, A> {
match self {
ResultsHandle::Borrowed(_borrowed) => {
panic!("tried to deref_mut a `ResultsHandle::Borrowed")
}
ResultsHandle::BorrowedMut(borrowed) => borrowed,
ResultsHandle::Owned(owned) => owned,
}
}
}
/// Allows random access inspection of the results of a dataflow analysis. Use this when you want
/// to inspect domain values only in certain locations; use `ResultsVisitor` if you want to inspect
/// domain values in many or all locations.
///
/// This cursor only has linear performance within a basic block when its statements are visited in
/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are
/// visited in *reverse* order—performance will be quadratic in the number of statements in the
/// block. The order in which basic blocks are inspected has no impact on performance.
/// Because `Results` only has domain values for the entry of each basic block, these inspections
/// involve some amount of domain value recomputations. This cursor only has linear performance
/// within a basic block when its statements are visited in the same order as the `DIRECTION` of
/// the analysis. In the worst case—when statements are visited in *reverse* order—performance will
/// be quadratic in the number of statements in the block. The order in which basic blocks are
/// inspected has no impact on performance.
pub struct ResultsCursor<'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
body: &'mir mir::Body<'tcx>,
results: Results<'tcx, A>,
results: ResultsHandle<'mir, 'tcx, A>,
state: A::Domain,
pos: CursorPosition,
@ -47,13 +93,8 @@ where
self.body
}
/// Unwraps this cursor, returning the underlying `Results`.
pub fn into_results(self) -> Results<'tcx, A> {
self.results
}
/// Returns a new cursor that can inspect `results`.
pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self {
pub fn new(body: &'mir mir::Body<'tcx>, results: ResultsHandle<'mir, 'tcx, A>) -> Self {
let bottom_value = results.analysis.bottom_value(body);
ResultsCursor {
body,

View file

@ -9,10 +9,21 @@ use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
pub trait Direction {
const IS_FORWARD: bool;
const IS_BACKWARD: bool = !Self::IS_FORWARD;
/// Applies all effects between the given `EffectIndex`s.
/// Called by `iterate_to_fixpoint` during initial analysis computation.
fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A,
body: &mir::Body<'tcx>,
state: &mut A::Domain,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
propagate: impl FnMut(BasicBlock, &A::Domain),
) where
A: Analysis<'tcx>;
/// Called by `ResultsCursor` to recompute the domain value for a location
/// in a basic block. Applies all effects between the given `EffectIndex`s.
///
/// `effects.start()` must precede or equal `effects.end()` in this direction.
fn apply_effects_in_range<'tcx, A>(
@ -24,15 +35,9 @@ pub trait Direction {
) where
A: Analysis<'tcx>;
fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A,
state: &mut A::Domain,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
) -> TerminatorEdges<'mir, 'tcx>
where
A: Analysis<'tcx>;
/// Called by `ResultsVisitor` to recompute the analysis domain values for
/// all locations in a basic block (starting from the entry value stored
/// in `Results`) and to visit them with `vis`.
fn visit_results_in_block<'mir, 'tcx, A>(
state: &mut A::Domain,
block: BasicBlock,
@ -41,16 +46,6 @@ pub trait Direction {
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
) where
A: Analysis<'tcx>;
fn join_state_into_successors_of<'tcx, A>(
analysis: &mut A,
body: &mir::Body<'tcx>,
exit_state: &mut A::Domain,
block: BasicBlock,
edges: TerminatorEdges<'_, 'tcx>,
propagate: impl FnMut(BasicBlock, &A::Domain),
) where
A: Analysis<'tcx>;
}
/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement).
@ -61,23 +56,84 @@ impl Direction for Backward {
fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A,
body: &mir::Body<'tcx>,
state: &mut A::Domain,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
) -> TerminatorEdges<'mir, 'tcx>
where
mut propagate: impl FnMut(BasicBlock, &A::Domain),
) where
A: Analysis<'tcx>,
{
let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location);
let edges = analysis.apply_terminator_effect(state, terminator, location);
analysis.apply_terminator_effect(state, terminator, location);
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
let location = Location { block, statement_index };
analysis.apply_before_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location);
}
edges
let exit_state = state;
for pred in body.basic_blocks.predecessors()[block].iter().copied() {
match body[pred].terminator().kind {
// Apply terminator-specific edge effects.
//
// FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
mir::TerminatorKind::Call { destination, target: Some(dest), .. }
if dest == block =>
{
let mut tmp = exit_state.clone();
analysis.apply_call_return_effect(
&mut tmp,
pred,
CallReturnPlaces::Call(destination),
);
propagate(pred, &tmp);
}
mir::TerminatorKind::InlineAsm { ref targets, ref operands, .. }
if targets.contains(&block) =>
{
let mut tmp = exit_state.clone();
analysis.apply_call_return_effect(
&mut tmp,
pred,
CallReturnPlaces::InlineAsm(operands),
);
propagate(pred, &tmp);
}
mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == block => {
let mut tmp = exit_state.clone();
analysis.apply_call_return_effect(
&mut tmp,
resume,
CallReturnPlaces::Yield(resume_arg),
);
propagate(pred, &tmp);
}
mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
let mut applier = BackwardSwitchIntEdgeEffectsApplier {
body,
pred,
exit_state,
block,
propagate: &mut propagate,
effects_applied: false,
};
analysis.apply_switch_int_edge_effects(pred, discr, &mut applier);
if !applier.effects_applied {
propagate(pred, exit_state)
}
}
_ => propagate(pred, exit_state),
}
}
}
fn apply_effects_in_range<'tcx, A>(
@ -170,7 +226,6 @@ impl Direction for Backward {
vis.visit_block_end(state);
// Terminator
let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator();
results.analysis.apply_before_terminator_effect(state, term, loc);
@ -188,82 +243,13 @@ impl Direction for Backward {
vis.visit_block_start(state);
}
fn join_state_into_successors_of<'tcx, A>(
analysis: &mut A,
body: &mir::Body<'tcx>,
exit_state: &mut A::Domain,
bb: BasicBlock,
_edges: TerminatorEdges<'_, 'tcx>,
mut propagate: impl FnMut(BasicBlock, &A::Domain),
) where
A: Analysis<'tcx>,
{
for pred in body.basic_blocks.predecessors()[bb].iter().copied() {
match body[pred].terminator().kind {
// Apply terminator-specific edge effects.
//
// FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
mir::TerminatorKind::Call { destination, target: Some(dest), .. } if dest == bb => {
let mut tmp = exit_state.clone();
analysis.apply_call_return_effect(
&mut tmp,
pred,
CallReturnPlaces::Call(destination),
);
propagate(pred, &tmp);
}
mir::TerminatorKind::InlineAsm { ref targets, ref operands, .. }
if targets.contains(&bb) =>
{
let mut tmp = exit_state.clone();
analysis.apply_call_return_effect(
&mut tmp,
pred,
CallReturnPlaces::InlineAsm(operands),
);
propagate(pred, &tmp);
}
mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == bb => {
let mut tmp = exit_state.clone();
analysis.apply_call_return_effect(
&mut tmp,
resume,
CallReturnPlaces::Yield(resume_arg),
);
propagate(pred, &tmp);
}
mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
let mut applier = BackwardSwitchIntEdgeEffectsApplier {
body,
pred,
exit_state,
bb,
propagate: &mut propagate,
effects_applied: false,
};
analysis.apply_switch_int_edge_effects(pred, discr, &mut applier);
if !applier.effects_applied {
propagate(pred, exit_state)
}
}
_ => propagate(pred, exit_state),
}
}
}
}
struct BackwardSwitchIntEdgeEffectsApplier<'mir, 'tcx, D, F> {
body: &'mir mir::Body<'tcx>,
pred: BasicBlock,
exit_state: &'mir mut D,
bb: BasicBlock,
block: BasicBlock,
propagate: &'mir mut F,
effects_applied: bool,
}
@ -276,8 +262,8 @@ where
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
assert!(!self.effects_applied);
let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)];
let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
let values = &self.body.basic_blocks.switch_sources()[&(self.block, self.pred)];
let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.block });
let mut tmp = None;
for target in targets {
@ -298,11 +284,12 @@ impl Direction for Forward {
fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A,
_body: &mir::Body<'tcx>,
state: &mut A::Domain,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
) -> TerminatorEdges<'mir, 'tcx>
where
mut propagate: impl FnMut(BasicBlock, &A::Domain),
) where
A: Analysis<'tcx>,
{
for (statement_index, statement) in block_data.statements.iter().enumerate() {
@ -313,7 +300,53 @@ impl Direction for Forward {
let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location);
analysis.apply_terminator_effect(state, terminator, location)
let edges = analysis.apply_terminator_effect(state, terminator, location);
let exit_state = state;
match edges {
TerminatorEdges::None => {}
TerminatorEdges::Single(target) => propagate(target, exit_state),
TerminatorEdges::Double(target, unwind) => {
propagate(target, exit_state);
propagate(unwind, exit_state);
}
TerminatorEdges::AssignOnReturn { return_, cleanup, place } => {
// This must be done *first*, otherwise the unwind path will see the assignments.
if let Some(cleanup) = cleanup {
propagate(cleanup, exit_state);
}
if !return_.is_empty() {
analysis.apply_call_return_effect(exit_state, block, place);
for &target in return_ {
propagate(target, exit_state);
}
}
}
TerminatorEdges::SwitchInt { targets, discr } => {
let mut applier = ForwardSwitchIntEdgeEffectsApplier {
exit_state,
targets,
propagate,
effects_applied: false,
};
analysis.apply_switch_int_edge_effects(block, discr, &mut applier);
let ForwardSwitchIntEdgeEffectsApplier {
exit_state,
mut propagate,
effects_applied,
..
} = applier;
if !effects_applied {
for target in targets.all_targets() {
propagate(*target, exit_state);
}
}
}
}
}
fn apply_effects_in_range<'tcx, A>(
@ -351,7 +384,8 @@ impl Direction for Forward {
let statement = &block_data.statements[from.statement_index];
analysis.apply_statement_effect(state, statement, location);
// If we only needed to apply the after effect of the statement at `idx`, we are done.
// If we only needed to apply the after effect of the statement at `idx`, we are
// done.
if from == to {
return;
}
@ -419,62 +453,6 @@ impl Direction for Forward {
vis.visit_block_end(state);
}
fn join_state_into_successors_of<'tcx, A>(
analysis: &mut A,
_body: &mir::Body<'tcx>,
exit_state: &mut A::Domain,
bb: BasicBlock,
edges: TerminatorEdges<'_, 'tcx>,
mut propagate: impl FnMut(BasicBlock, &A::Domain),
) where
A: Analysis<'tcx>,
{
match edges {
TerminatorEdges::None => {}
TerminatorEdges::Single(target) => propagate(target, exit_state),
TerminatorEdges::Double(target, unwind) => {
propagate(target, exit_state);
propagate(unwind, exit_state);
}
TerminatorEdges::AssignOnReturn { return_, cleanup, place } => {
// This must be done *first*, otherwise the unwind path will see the assignments.
if let Some(cleanup) = cleanup {
propagate(cleanup, exit_state);
}
if !return_.is_empty() {
analysis.apply_call_return_effect(exit_state, bb, place);
for &target in return_ {
propagate(target, exit_state);
}
}
}
TerminatorEdges::SwitchInt { targets, discr } => {
let mut applier = ForwardSwitchIntEdgeEffectsApplier {
exit_state,
targets,
propagate,
effects_applied: false,
};
analysis.apply_switch_int_edge_effects(bb, discr, &mut applier);
let ForwardSwitchIntEdgeEffectsApplier {
exit_state,
mut propagate,
effects_applied,
..
} = applier;
if !effects_applied {
for target in targets.all_targets() {
propagate(*target, exit_state);
}
}
}
}
}
}
struct ForwardSwitchIntEdgeEffectsApplier<'mir, D, F> {

View file

@ -230,16 +230,3 @@ where
write!(f, "{}", ctxt.move_data().move_paths[*self])
}
}
impl<T, C> DebugWithContext<C> for crate::lattice::Dual<T>
where
T: DebugWithContext<C>,
{
fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(self.0).fmt_with(ctxt, f)
}
fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(self.0).fmt_diff_with(&old.0, ctxt, f)
}
}

View file

@ -47,20 +47,16 @@ where
{
pub(crate) fn new(
body: &'mir Body<'tcx>,
results: Results<'tcx, A>,
results: &'mir Results<'tcx, A>,
style: OutputStyle,
) -> Self {
let reachable = mir::traversal::reachable_as_bitset(body);
Formatter { cursor: results.into_results_cursor(body).into(), style, reachable }
Formatter { cursor: results.as_results_cursor(body).into(), style, reachable }
}
fn body(&self) -> &'mir Body<'tcx> {
self.cursor.borrow().body()
}
pub(crate) fn into_results(self) -> Results<'tcx, A> {
self.cursor.into_inner().into_results()
}
}
/// A pair of a basic block and an index into that basic blocks `successors`.

View file

@ -25,8 +25,8 @@
//!
//! ## `PartialOrd`
//!
//! Given that they represent partially ordered sets, you may be surprised that [`JoinSemiLattice`]
//! and [`MeetSemiLattice`] do not have [`PartialOrd`] as a supertrait. This
//! Given that it represents a partially ordered set, you may be surprised that [`JoinSemiLattice`]
//! does not have [`PartialOrd`] as a supertrait. This
//! is because most standard library types use lexicographic ordering instead of set inclusion for
//! their `PartialOrd` impl. Since we do not actually need to compare lattice elements to run a
//! dataflow analysis, there's no need for a newtype wrapper with a custom `PartialOrd` impl. The
@ -58,23 +58,6 @@ pub trait JoinSemiLattice: Eq {
fn join(&mut self, other: &Self) -> bool;
}
/// A [partially ordered set][poset] that has a [greatest lower bound][glb] for any pair of
/// elements in the set.
///
/// Dataflow analyses only require that their domains implement [`JoinSemiLattice`], not
/// `MeetSemiLattice`. However, types that will be used as dataflow domains should implement both
/// so that they can be used with [`Dual`].
///
/// [glb]: https://en.wikipedia.org/wiki/Infimum_and_supremum
/// [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set
pub trait MeetSemiLattice: Eq {
/// Computes the greatest lower bound of two elements, storing the result in `self` and
/// returning `true` if `self` has changed.
///
/// The lattice meet operator is abbreviated as `∧`.
fn meet(&mut self, other: &Self) -> bool;
}
/// A set that has a "bottom" element, which is less than or equal to any other element.
pub trait HasBottom {
const BOTTOM: Self;
@ -105,17 +88,6 @@ impl JoinSemiLattice for bool {
}
}
impl MeetSemiLattice for bool {
fn meet(&mut self, other: &Self) -> bool {
if let (true, false) = (*self, *other) {
*self = false;
return true;
}
false
}
}
impl HasBottom for bool {
const BOTTOM: Self = false;
@ -145,18 +117,6 @@ impl<I: Idx, T: JoinSemiLattice> JoinSemiLattice for IndexVec<I, T> {
}
}
impl<I: Idx, T: MeetSemiLattice> MeetSemiLattice for IndexVec<I, T> {
fn meet(&mut self, other: &Self) -> bool {
assert_eq!(self.len(), other.len());
let mut changed = false;
for (a, b) in iter::zip(self, other) {
changed |= a.meet(b);
}
changed
}
}
/// A `BitSet` represents the lattice formed by the powerset of all possible values of
/// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices,
/// one for each possible value of `T`.
@ -166,60 +126,12 @@ impl<T: Idx> JoinSemiLattice for BitSet<T> {
}
}
impl<T: Idx> MeetSemiLattice for BitSet<T> {
fn meet(&mut self, other: &Self) -> bool {
self.intersect(other)
}
}
impl<T: Idx> JoinSemiLattice for ChunkedBitSet<T> {
fn join(&mut self, other: &Self) -> bool {
self.union(other)
}
}
impl<T: Idx> MeetSemiLattice for ChunkedBitSet<T> {
fn meet(&mut self, other: &Self) -> bool {
self.intersect(other)
}
}
/// The counterpart of a given semilattice `T` using the [inverse order].
///
/// The dual of a join-semilattice is a meet-semilattice and vice versa. For example, the dual of a
/// powerset has the empty set as its top element and the full set as its bottom element and uses
/// set *intersection* as its join operator.
///
/// [inverse order]: https://en.wikipedia.org/wiki/Duality_(order_theory)
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Dual<T>(pub T);
impl<T: Idx> BitSetExt<T> for Dual<BitSet<T>> {
fn contains(&self, elem: T) -> bool {
self.0.contains(elem)
}
fn union(&mut self, other: &HybridBitSet<T>) {
self.0.union(other);
}
fn subtract(&mut self, other: &HybridBitSet<T>) {
self.0.subtract(other);
}
}
impl<T: MeetSemiLattice> JoinSemiLattice for Dual<T> {
fn join(&mut self, other: &Self) -> bool {
self.0.meet(&other.0)
}
}
impl<T: JoinSemiLattice> MeetSemiLattice for Dual<T> {
fn meet(&mut self, other: &Self) -> bool {
self.0.join(&other.0)
}
}
/// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no
/// value of `T` is comparable with any other.
///
@ -257,22 +169,6 @@ impl<T: Clone + Eq> JoinSemiLattice for FlatSet<T> {
}
}
impl<T: Clone + Eq> MeetSemiLattice for FlatSet<T> {
fn meet(&mut self, other: &Self) -> bool {
let result = match (&*self, other) {
(Self::Bottom, _) | (_, Self::Top) => return false,
(Self::Elem(ref a), Self::Elem(ref b)) if a == b => return false,
(Self::Top, Self::Elem(ref x)) => Self::Elem(x.clone()),
_ => Self::Bottom,
};
*self = result;
true
}
}
impl<T> HasBottom for FlatSet<T> {
const BOTTOM: Self = Self::Bottom;

View file

@ -8,8 +8,9 @@
//! The `impls` module contains several examples of dataflow analyses.
//!
//! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From
//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem,
//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses
//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem
//! (good for inspecting a small number of locations), or implement the `ResultsVisitor` interface
//! and use `visit_results` (good for inspecting many or all locations). The following example uses
//! the `ResultsCursor` approach.
//!
//! ```ignore (cross-crate-imports)
@ -278,22 +279,17 @@ pub trait Analysis<'tcx> {
// every iteration.
let mut state = self.bottom_value(body);
while let Some(bb) = dirty_queue.pop() {
let bb_data = &body[bb];
// Set the state to the entry state of the block.
// This is equivalent to `state = entry_sets[bb].clone()`,
// but it saves an allocation, thus improving compile times.
state.clone_from(&entry_sets[bb]);
// Apply the block transfer function, using the cached one if it exists.
let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data);
Self::Direction::join_state_into_successors_of(
Self::Direction::apply_effects_in_block(
&mut self,
body,
&mut state,
bb,
edges,
&body[bb],
|target: BasicBlock, state: &Self::Domain| {
let set_changed = entry_sets[target].join(state);
if set_changed {
@ -306,14 +302,13 @@ pub trait Analysis<'tcx> {
let results = Results { analysis: self, entry_sets };
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
let res = write_graphviz_results(tcx, body, &results, pass_name);
if let Err(e) = res {
error!("Failed to write graphviz dataflow results: {}", e);
}
results
} else {
results
}
results
}
}
@ -378,16 +373,6 @@ impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> {
}
}
impl<T: Idx> GenKill<T> for lattice::Dual<BitSet<T>> {
fn gen_(&mut self, elem: T) {
self.0.insert(elem);
}
fn kill(&mut self, elem: T) {
self.0.remove(elem);
}
}
// NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Effect {

View file

@ -17,10 +17,13 @@ use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
use crate::errors::{
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
};
use crate::framework::cursor::ResultsHandle;
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
/// A dataflow analysis that has converged to fixpoint.
/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the
/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly
/// by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls).
#[derive(Clone)]
pub struct Results<'tcx, A>
where
@ -34,12 +37,30 @@ impl<'tcx, A> Results<'tcx, A>
where
A: Analysis<'tcx>,
{
/// Creates a `ResultsCursor` that can inspect these `Results`.
/// Creates a `ResultsCursor` that can inspect these `Results`. Immutably borrows the `Results`,
/// which is appropriate when the `Results` is used outside the cursor.
pub fn as_results_cursor<'mir>(
&'mir self,
body: &'mir mir::Body<'tcx>,
) -> ResultsCursor<'mir, 'tcx, A> {
ResultsCursor::new(body, ResultsHandle::Borrowed(self))
}
/// Creates a `ResultsCursor` that can mutate these `Results`. Mutably borrows the `Results`,
/// which is appropriate when the `Results` is used outside the cursor.
pub fn as_results_cursor_mut<'mir>(
&'mir mut self,
body: &'mir mir::Body<'tcx>,
) -> ResultsCursor<'mir, 'tcx, A> {
ResultsCursor::new(body, ResultsHandle::BorrowedMut(self))
}
/// Creates a `ResultsCursor` that takes ownership of the `Results`.
pub fn into_results_cursor<'mir>(
self,
body: &'mir mir::Body<'tcx>,
) -> ResultsCursor<'mir, 'tcx, A> {
ResultsCursor::new(body, self)
ResultsCursor::new(body, ResultsHandle::Owned(self))
}
/// Gets the dataflow state for the given block.
@ -74,9 +95,9 @@ where
pub(super) fn write_graphviz_results<'tcx, A>(
tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
results: Results<'tcx, A>,
results: &Results<'tcx, A>,
pass_name: Option<&'static str>,
) -> (std::io::Result<()>, Results<'tcx, A>)
) -> std::io::Result<()>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@ -87,7 +108,7 @@ where
let def_id = body.source.def_id();
let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
// Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
return (Ok(()), results);
return Ok(());
};
let file = try {
@ -104,12 +125,12 @@ where
create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
}
_ => return (Ok(()), results),
_ => return Ok(()),
}
};
let mut file = match file {
Ok(f) => f,
Err(e) => return (Err(e), results),
Err(e) => return Err(e),
};
let style = match attrs.formatter {
@ -132,7 +153,7 @@ where
file.write_all(&buf)?;
};
(lhs, graphviz.into_results())
lhs
}
#[derive(Default)]

View file

@ -26,7 +26,9 @@ pub fn visit_results<'mir, 'tcx, A>(
}
}
/// A visitor over the results of an `Analysis`.
/// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in
/// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain
/// locations.
pub trait ResultsVisitor<'mir, 'tcx, A>
where
A: Analysis<'tcx>,

View file

@ -15,7 +15,7 @@ use crate::{Analysis, GenKill};
pub struct MaybeBorrowedLocals;
impl MaybeBorrowedLocals {
pub(super) fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
pub(super) fn transfer_function<'a, T>(trans: &'a mut T) -> TransferFunction<'a, T> {
TransferFunction { trans }
}
}
@ -39,7 +39,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
statement: &Statement<'tcx>,
location: Location,
) {
self.transfer_function(trans).visit_statement(statement, location);
Self::transfer_function(trans).visit_statement(statement, location);
}
fn apply_terminator_effect<'mir>(
@ -48,7 +48,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
terminator: &'mir Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx> {
self.transfer_function(trans).visit_terminator(terminator, location);
Self::transfer_function(trans).visit_terminator(terminator, location);
terminator.edges()
}
}

View file

@ -12,7 +12,7 @@ use crate::framework::SwitchIntEdgeEffects;
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
use crate::{
Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry,
drop_flag_effects_for_location, lattice, on_all_children_bits, on_lookup_result_bits,
drop_flag_effects_for_location, on_all_children_bits, on_lookup_result_bits,
};
/// `MaybeInitializedPlaces` tracks all places that might be
@ -42,10 +42,10 @@ use crate::{
/// }
/// ```
///
/// To determine whether a place *must* be initialized at a
/// particular control-flow point, one can take the set-difference
/// between this data and the data from `MaybeUninitializedPlaces` at the
/// corresponding control-flow point.
/// To determine whether a place is *definitely* initialized at a
/// particular control-flow point, one can take the set-complement
/// of the data from `MaybeUninitializedPlaces` at the corresponding
/// control-flow point.
///
/// Similarly, at a given `drop` statement, the set-intersection
/// between this data and `MaybeUninitializedPlaces` yields the set of
@ -117,10 +117,10 @@ impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> {
/// }
/// ```
///
/// To determine whether a place *must* be uninitialized at a
/// particular control-flow point, one can take the set-difference
/// between this data and the data from `MaybeInitializedPlaces` at the
/// corresponding control-flow point.
/// To determine whether a place is *definitely* uninitialized at a
/// particular control-flow point, one can take the set-complement
/// of the data from `MaybeInitializedPlaces` at the corresponding
/// control-flow point.
///
/// Similarly, at a given `drop` statement, the set-intersection
/// between this data and `MaybeInitializedPlaces` yields the set of
@ -170,57 +170,6 @@ impl<'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
}
}
/// `DefinitelyInitializedPlaces` tracks all places that are definitely
/// initialized upon reaching a particular point in the control flow
/// for a function.
///
/// For example, in code like the following, we have corresponding
/// dataflow information shown in the right-hand comments.
///
/// ```rust
/// struct S;
/// fn foo(pred: bool) { // definite-init:
/// // { }
/// let a = S; let mut b = S; let c; let d; // {a, b }
///
/// if pred {
/// drop(a); // { b, }
/// b = S; // { b, }
///
/// } else {
/// drop(b); // {a, }
/// d = S; // {a, d}
///
/// } // { }
///
/// c = S; // { c }
/// }
/// ```
///
/// To determine whether a place *may* be uninitialized at a
/// particular control-flow point, one can take the set-complement
/// of this data.
///
/// Similarly, at a given `drop` statement, the set-difference between
/// this data and `MaybeInitializedPlaces` yields the set of places
/// that would require a dynamic drop-flag at that statement.
pub struct DefinitelyInitializedPlaces<'a, 'tcx> {
body: &'a Body<'tcx>,
move_data: &'a MoveData<'tcx>,
}
impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
pub fn new(body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
DefinitelyInitializedPlaces { body, move_data }
}
}
impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
fn move_data(&self) -> &MoveData<'tcx> {
self.move_data
}
}
/// `EverInitializedPlaces` tracks all places that might have ever been
/// initialized upon reaching a particular point in the control flow
/// for a function, without an intervening `StorageDead`.
@ -293,19 +242,6 @@ impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {
}
}
impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
fn update_bits(
trans: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex,
state: DropFlagState,
) {
match state {
DropFlagState::Absent => trans.kill(path),
DropFlagState::Present => trans.gen_(path),
}
}
}
impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
/// We use a chunked bitset to avoid paying too high a memory footprint.
@ -554,70 +490,6 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
}
}
impl<'a, 'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
/// Use set intersection as the join operator.
type Domain = lattice::Dual<BitSet<MovePathIndex>>;
const NAME: &'static str = "definite_init";
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
// bottom = initialized (start_block_effect counters this at outset)
lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len()))
}
// sets on_entry bits for Arg places
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
state.0.clear();
drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
assert!(s == DropFlagState::Present);
state.0.insert(path);
});
}
fn apply_statement_effect(
&mut self,
trans: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
location: Location,
) {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
Self::update_bits(trans, path, s)
})
}
fn apply_terminator_effect<'mir>(
&mut self,
trans: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx> {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
Self::update_bits(trans, path, s)
});
terminator.edges()
}
fn apply_call_return_effect(
&mut self,
trans: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
return_places.for_each(|place| {
// when a call returns successfully, that means we need to set
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(
self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()),
|mpi| {
trans.gen_(mpi);
},
);
});
}
}
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
/// There can be many more `InitIndex` than there are locals in a MIR body.
/// We use a chunked bitset to avoid paying too high a memory footprint.

View file

@ -9,8 +9,7 @@ mod storage_liveness;
pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals};
pub use self::initialized::{
DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeInitializedPlaces,
MaybeUninitializedPlaces,
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
};
pub use self::liveness::{
MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,

View file

@ -135,7 +135,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
loc: Location,
) {
// If a place is borrowed in a statement, it needs storage for that statement.
self.borrowed_locals.mut_analysis().apply_statement_effect(trans, stmt, loc);
MaybeBorrowedLocals::transfer_function(trans).visit_statement(stmt, loc);
match &stmt.kind {
StatementKind::StorageDead(l) => trans.kill(*l),
@ -180,10 +180,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
loc: Location,
) {
// If a place is borrowed in a terminator, it needs storage for that terminator.
self.borrowed_locals
.mut_analysis()
.transfer_function(trans)
.visit_terminator(terminator, loc);
MaybeBorrowedLocals::transfer_function(trans).visit_terminator(terminator, loc);
match &terminator.kind {
TerminatorKind::Call { destination, .. } => {

View file

@ -12,9 +12,7 @@ use crate::errors::{
PeekMustBePlaceOrRefPlace, StopAfterDataFlowEndedCompilation,
};
use crate::framework::BitSetExt;
use crate::impls::{
DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
};
use crate::impls::{MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces};
use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
use crate::{Analysis, JoinSemiLattice, ResultsCursor};
@ -56,13 +54,6 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
}
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
let flow_def_inits =
DefinitelyInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(tcx, body, None);
sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
}
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None);

View file

@ -676,12 +676,11 @@ fn locals_live_across_suspend_points<'tcx>(
let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
// Calculate the MIR locals that we actually need to keep storage around
// for.
let mut requires_storage_cursor =
// Calculate the MIR locals that we need to keep storage around for.
let mut requires_storage_results =
MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
.iterate_to_fixpoint(tcx, body, None)
.into_results_cursor(body);
.iterate_to_fixpoint(tcx, body, None);
let mut requires_storage_cursor = requires_storage_results.as_results_cursor_mut(body);
// Calculate the liveness of MIR locals ignoring borrows.
let mut liveness =
@ -754,7 +753,7 @@ fn locals_live_across_suspend_points<'tcx>(
body,
&saved_locals,
always_live_locals.clone(),
requires_storage_cursor.into_results(),
requires_storage_results,
);
LivenessInfo {

View file

@ -18,6 +18,7 @@ use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, Pos, Span};
use tracing::debug;
use crate::lexer::diagnostics::TokenTreeDiagInfo;
use crate::lexer::unicode_chars::UNICODE_ARRAY;
use crate::{errors, make_unclosed_delims_error};
@ -56,7 +57,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
}
let cursor = Cursor::new(src);
let string_reader = StringReader {
let mut lexer = Lexer {
psess,
start_pos,
pos: start_pos,
@ -65,34 +66,31 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
override_span,
nbsp_is_whitespace: false,
last_lifetime: None,
token: Token::dummy(),
diag_info: TokenTreeDiagInfo::default(),
};
let (stream, res, unmatched_delims) =
tokentrees::TokenTreesReader::lex_all_token_trees(string_reader);
match res {
Ok(()) if unmatched_delims.is_empty() => Ok(stream),
_ => {
// Return error if there are unmatched delimiters or unclosed delimiters.
// We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
// because the delimiter mismatch is more likely to be the root cause of error
let (_open_spacing, stream, res) = lexer.lex_token_trees(/* is_delimited */ false);
let unmatched_delims = lexer.diag_info.unmatched_delims;
let mut buffer = Vec::with_capacity(1);
for unmatched in unmatched_delims {
if let Some(err) = make_unclosed_delims_error(unmatched, psess) {
buffer.push(err);
}
}
if let Err(errs) = res {
// Add unclosing delimiter or diff marker errors
for err in errs {
buffer.push(err);
}
}
Err(buffer)
if res.is_ok() && unmatched_delims.is_empty() {
Ok(stream)
} else {
// Return error if there are unmatched delimiters or unclosed delimiters.
// We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
// because the delimiter mismatch is more likely to be the root cause of error
let mut buffer: Vec<_> = unmatched_delims
.into_iter()
.filter_map(|unmatched_delim| make_unclosed_delims_error(unmatched_delim, psess))
.collect();
if let Err(errs) = res {
// Add unclosing delimiter or diff marker errors
buffer.extend(errs);
}
Err(buffer)
}
}
struct StringReader<'psess, 'src> {
struct Lexer<'psess, 'src> {
psess: &'psess ParseSess,
/// Initial position, read-only.
start_pos: BytePos,
@ -111,9 +109,14 @@ struct StringReader<'psess, 'src> {
/// Track the `Span` for the leading `'` of the last lifetime. Used for
/// diagnostics to detect possible typo where `"` was meant.
last_lifetime: Option<Span>,
/// The current token.
token: Token,
diag_info: TokenTreeDiagInfo,
}
impl<'psess, 'src> StringReader<'psess, 'src> {
impl<'psess, 'src> Lexer<'psess, 'src> {
fn dcx(&self) -> DiagCtxtHandle<'psess> {
self.psess.dcx()
}
@ -124,7 +127,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
/// Returns the next token, paired with a bool indicating if the token was
/// preceded by whitespace.
fn next_token(&mut self) -> (Token, bool) {
fn next_token_from_cursor(&mut self) -> (Token, bool) {
let mut preceded_by_whitespace = false;
let mut swallow_next_invalid = 0;
// Skip trivial (whitespace & comments) tokens
@ -231,7 +234,8 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
.push(span);
token::Ident(sym, IdentIsRaw::No)
}
// split up (raw) c string literals to an ident and a string literal when edition < 2021.
// split up (raw) c string literals to an ident and a string literal when edition <
// 2021.
rustc_lexer::TokenKind::Literal {
kind: kind @ (LiteralKind::CStr { .. } | LiteralKind::RawCStr { .. }),
suffix_start: _,
@ -252,7 +256,9 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
let prefix_span = self.mk_sp(start, lit_start);
return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace);
}
rustc_lexer::TokenKind::GuardedStrPrefix => self.maybe_report_guarded_str(start, str_before),
rustc_lexer::TokenKind::GuardedStrPrefix => {
self.maybe_report_guarded_str(start, str_before)
}
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
let suffix_start = start + BytePos(suffix_start);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
@ -296,13 +302,20 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
if prefix_span.at_least_rust_2021() {
let span = self.mk_sp(start, self.pos);
let lifetime_name_without_tick = Symbol::intern(&self.str_from(ident_start));
let lifetime_name_without_tick =
Symbol::intern(&self.str_from(ident_start));
if !lifetime_name_without_tick.can_be_raw() {
self.dcx().emit_err(errors::CannotBeRawLifetime { span, ident: lifetime_name_without_tick });
self.dcx().emit_err(
errors::CannotBeRawLifetime {
span,
ident: lifetime_name_without_tick
}
);
}
// Put the `'` back onto the lifetime name.
let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.as_str().len() + 1);
let mut lifetime_name =
String::with_capacity(lifetime_name_without_tick.as_str().len() + 1);
lifetime_name.push('\'');
lifetime_name += lifetime_name_without_tick.as_str();
let sym = Symbol::intern(&lifetime_name);

View file

@ -4,41 +4,19 @@ use rustc_ast_pretty::pprust::token_to_string;
use rustc_errors::{Applicability, PErr};
use rustc_span::symbol::kw;
use super::diagnostics::{
TokenTreeDiagInfo, report_suspicious_mismatch_block, same_indentation_level,
};
use super::{StringReader, UnmatchedDelim};
use super::diagnostics::{report_suspicious_mismatch_block, same_indentation_level};
use super::{Lexer, UnmatchedDelim};
use crate::Parser;
pub(super) struct TokenTreesReader<'psess, 'src> {
string_reader: StringReader<'psess, 'src>,
/// The "next" token, which has been obtained from the `StringReader` but
/// not yet handled by the `TokenTreesReader`.
token: Token,
diag_info: TokenTreeDiagInfo,
}
impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
pub(super) fn lex_all_token_trees(
string_reader: StringReader<'psess, 'src>,
) -> (TokenStream, Result<(), Vec<PErr<'psess>>>, Vec<UnmatchedDelim>) {
let mut tt_reader = TokenTreesReader {
string_reader,
token: Token::dummy(),
diag_info: TokenTreeDiagInfo::default(),
};
let (_open_spacing, stream, res) = tt_reader.lex_token_trees(/* is_delimited */ false);
(stream, res, tt_reader.diag_info.unmatched_delims)
}
impl<'psess, 'src> Lexer<'psess, 'src> {
// Lex into a token stream. The `Spacing` in the result is that of the
// opening delimiter.
fn lex_token_trees(
pub(super) fn lex_token_trees(
&mut self,
is_delimited: bool,
) -> (Spacing, TokenStream, Result<(), Vec<PErr<'psess>>>) {
// Move past the opening delimiter.
let (_, open_spacing) = self.bump(false);
let open_spacing = self.bump_minimal();
let mut buf = Vec::new();
loop {
@ -71,7 +49,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
}
_ => {
// Get the next normal token.
let (this_tok, this_spacing) = self.bump(true);
let (this_tok, this_spacing) = self.bump();
buf.push(TokenTree::Token(this_tok, this_spacing));
}
}
@ -80,7 +58,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
fn eof_err(&mut self) -> PErr<'psess> {
let msg = "this file contains an unclosed delimiter";
let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg);
let mut err = self.dcx().struct_span_err(self.token.span, msg);
let unclosed_delimiter_show_limit = 5;
let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_braces.len());
@ -110,7 +88,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
report_suspicious_mismatch_block(
&mut err,
&self.diag_info,
self.string_reader.psess.source_map(),
self.psess.source_map(),
*delim,
)
}
@ -136,7 +114,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
// Expand to cover the entire delimited token tree.
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
let sm = self.string_reader.psess.source_map();
let sm = self.psess.source_map();
let close_spacing = match self.token.kind {
// Correct delimiter.
@ -160,7 +138,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
}
// Move past the closing delimiter.
self.bump(false).1
self.bump_minimal()
}
// Incorrect delimiter.
token::CloseDelim(close_delim) => {
@ -203,7 +181,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
// bar(baz(
// } // Incorrect delimiter but matches the earlier `{`
if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) {
self.bump(false).1
self.bump_minimal()
} else {
// The choice of value here doesn't matter.
Spacing::Alone
@ -225,14 +203,14 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
}
// Move on to the next token, returning the current token and its spacing.
// Will glue adjacent single-char tokens together if `glue` is set.
fn bump(&mut self, glue: bool) -> (Token, Spacing) {
// Will glue adjacent single-char tokens together.
fn bump(&mut self) -> (Token, Spacing) {
let (this_spacing, next_tok) = loop {
let (next_tok, is_next_tok_preceded_by_whitespace) = self.string_reader.next_token();
let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
if is_next_tok_preceded_by_whitespace {
break (Spacing::Alone, next_tok);
} else if glue && let Some(glued) = self.token.glue(&next_tok) {
} else if let Some(glued) = self.token.glue(&next_tok) {
self.token = glued;
} else {
let this_spacing = if next_tok.is_punct() {
@ -249,6 +227,26 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
(this_tok, this_spacing)
}
// Cut-down version of `bump` used when the token kind is known in advance.
fn bump_minimal(&mut self) -> Spacing {
let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
let this_spacing = if is_next_tok_preceded_by_whitespace {
Spacing::Alone
} else {
if next_tok.is_punct() {
Spacing::Joint
} else if next_tok == token::Eof {
Spacing::Alone
} else {
Spacing::JointHidden
}
};
self.token = next_tok;
this_spacing
}
fn unclosed_delim_err(
&mut self,
tts: TokenStream,
@ -256,7 +254,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
) -> Vec<PErr<'psess>> {
// If there are unclosed delims, see if there are diff markers and if so, point them
// out instead of complaining about the unclosed delims.
let mut parser = Parser::new(self.string_reader.psess, tts, None);
let mut parser = Parser::new(self.psess, tts, None);
let mut diff_errs = vec![];
// Suggest removing a `{` we think appears in an `if`/`while` condition.
// We want to suggest removing a `{` only if we think we're in an `if`/`while` condition,
@ -314,14 +312,9 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
// An unexpected closing delimiter (i.e., there is no matching opening delimiter).
let token_str = token_to_string(&self.token);
let msg = format!("unexpected closing delimiter: `{token_str}`");
let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg);
let mut err = self.dcx().struct_span_err(self.token.span, msg);
report_suspicious_mismatch_block(
&mut err,
&self.diag_info,
self.string_reader.psess.source_map(),
delim,
);
report_suspicious_mismatch_block(&mut err, &self.diag_info, self.psess.source_map(), delim);
err.span_label(self.token.span, "unexpected closing delimiter");
err
}

View file

@ -4,7 +4,7 @@
use rustc_span::symbol::kw;
use rustc_span::{BytePos, Pos, Span};
use super::StringReader;
use super::Lexer;
use crate::errors::TokenSubstitution;
use crate::token::{self, Delimiter};
@ -338,7 +338,7 @@ const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[
];
pub(super) fn check_for_substitution(
reader: &StringReader<'_, '_>,
lexer: &Lexer<'_, '_>,
pos: BytePos,
ch: char,
count: usize,
@ -351,11 +351,11 @@ pub(super) fn check_for_substitution(
let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
let msg = format!("substitution character not found for '{ch}'");
reader.dcx().span_bug(span, msg);
lexer.dcx().span_bug(span, msg);
};
// special help suggestion for "directed" double quotes
let sugg = if let Some(s) = peek_delimited(&reader.src[reader.src_index(pos)..], '“', '”') {
let sugg = if let Some(s) = peek_delimited(&lexer.src[lexer.src_index(pos)..], '“', '”') {
let span = Span::with_root_ctxt(
pos,
pos + Pos::from_usize('“'.len_utf8() + s.len() + '”'.len_utf8()),

View file

@ -1,11 +1,12 @@
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{
self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, ExprPrecedence,
LocalKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd,
RangeSyntax, Stmt, StmtKind,
self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall,
Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt,
StmtKind,
};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey};
@ -458,7 +459,7 @@ impl<'a> Parser<'a> {
.create_err(UnexpectedExpressionInPattern {
span,
is_bound,
expr_precedence: expr.precedence().order(),
expr_precedence: expr.precedence(),
})
.stash(span, StashKey::ExprInPat)
.unwrap(),
@ -545,7 +546,8 @@ impl<'a> Parser<'a> {
let expr = match &err.args["expr_precedence"] {
DiagArgValue::Number(expr_precedence) => {
if *expr_precedence
<= ExprPrecedence::Binary(BinOpKind::Eq).order() as i32
<= AssocOp::from_ast_binop(BinOpKind::Eq).precedence()
as i32
{
format!("({expr})")
} else {
@ -568,8 +570,9 @@ impl<'a> Parser<'a> {
}
Some(guard) => {
// Are parentheses required around the old guard?
let wrap_guard = guard.precedence().order()
<= ExprPrecedence::Binary(BinOpKind::And).order();
let wrap_guard = guard.precedence()
<= AssocOp::from_ast_binop(BinOpKind::And).precedence()
as i8;
err.subdiagnostic(
UnexpectedExpressionInPatternSugg::UpdateGuard {

View file

@ -1728,7 +1728,6 @@ symbols! {
rustc_partition_reused,
rustc_pass_by_value,
rustc_peek,
rustc_peek_definite_init,
rustc_peek_liveness,
rustc_peek_maybe_init,
rustc_peek_maybe_uninit,

View file

@ -1,5 +1,7 @@
use std::assert_matches::assert_matches;
use rustc_data_structures::fx::FxHashSet;
use super::super::*;
// Test target self-consistency and JSON encoding/decoding roundtrip.
@ -173,6 +175,27 @@ impl Target {
}
_ => {}
}
// Check that the given target-features string makes some basic sense.
if !self.features.is_empty() {
let mut features_enabled = FxHashSet::default();
let mut features_disabled = FxHashSet::default();
for feat in self.features.split(',') {
if let Some(feat) = feat.strip_prefix("+") {
features_enabled.insert(feat);
if features_disabled.contains(feat) {
panic!("target feature `{feat}` is both enabled and disabled");
}
} else if let Some(feat) = feat.strip_prefix("-") {
features_disabled.insert(feat);
if features_enabled.contains(feat) {
panic!("target feature `{feat}` is both enabled and disabled");
}
} else {
panic!("target feature `{feat}` is invalid, must start with `+` or `-`");
}
}
}
}
// Add your target to the whitelist if it has `std` library

View file

@ -1792,12 +1792,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn suggest_specify_actual_length(
&self,
terr: TypeError<'_>,
trace: &TypeTrace<'_>,
terr: TypeError<'tcx>,
trace: &TypeTrace<'tcx>,
span: Span,
) -> Option<TypeErrorAdditionalDiags> {
let hir = self.tcx.hir();
let TypeError::FixedArraySize(sz) = terr else {
let TypeError::ArraySize(sz) = terr else {
return None;
};
let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) {
@ -1838,9 +1838,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let Some(tykind) = tykind
&& let hir::TyKind::Array(_, length) = tykind
&& let hir::ArrayLen::Body(ct) = length
&& let Some((scalar, ty)) = sz.found.try_to_scalar()
&& ty == self.tcx.types.usize
{
let span = ct.span();
Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found })
Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength {
span,
length: scalar.to_target_usize(&self.tcx).unwrap(),
})
} else {
None
}

View file

@ -29,7 +29,7 @@ pub enum TypeError<I: Interner> {
Mutability,
ArgumentMutability(usize),
TupleSize(ExpectedFound<usize>),
FixedArraySize(ExpectedFound<u64>),
ArraySize(ExpectedFound<I::Const>),
ArgCount,
RegionsDoesNotOutlive(I::Region, I::Region),
@ -69,7 +69,7 @@ impl<I: Interner> TypeError<I> {
use self::TypeError::*;
match self {
CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | PolarityMismatch(_) | Mismatch
| AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
| AbiMismatch(_) | ArraySize(_) | ArgumentSorts(..) | Sorts(_)
| VariadicMismatch(_) | TargetFeatureCast(_) => false,
Mutability

View file

@ -257,8 +257,6 @@ pub trait Const<I: Interner<Const = Self>>:
+ Relate<I>
+ Flags
{
fn try_to_target_usize(self, interner: I) -> Option<u64>;
fn new_infer(interner: I, var: ty::InferConst) -> Self;
fn new_var(interner: I, var: ty::ConstVid) -> Self;

View file

@ -501,19 +501,10 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
let t = relation.relate(a_t, b_t)?;
match relation.relate(sz_a, sz_b) {
Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)),
Err(err) => {
// Check whether the lengths are both concrete/known values,
// but are unequal, for better diagnostics.
let sz_a = sz_a.try_to_target_usize(cx);
let sz_b = sz_b.try_to_target_usize(cx);
match (sz_a, sz_b) {
(Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => {
Err(TypeError::FixedArraySize(ExpectedFound::new(sz_a_val, sz_b_val)))
}
_ => Err(err),
}
Err(TypeError::ConstMismatch(_)) => {
Err(TypeError::ArraySize(ExpectedFound::new(sz_a, sz_b)))
}
Err(e) => Err(e),
}
}

View file

@ -269,6 +269,31 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> {
Vacant(entry) => Vacant(entry),
}
}
/// Sets the value of the entry, and returns an `OccupiedEntry`.
///
/// # Examples
///
/// ```
/// #![feature(btree_entry_insert)]
/// use std::collections::BTreeMap;
///
/// let mut map: BTreeMap<&str, String> = BTreeMap::new();
/// let entry = map.entry("poneyland").insert_entry("hoho".to_string());
///
/// assert_eq!(entry.key(), &"poneyland");
/// ```
#[inline]
#[unstable(feature = "btree_entry_insert", issue = "65225")]
pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> {
match self {
Occupied(mut entry) => {
entry.insert(value);
entry
}
Vacant(entry) => entry.insert_entry(value),
}
}
}
impl<'a, K: Ord, V: Default, A: Allocator + Clone> Entry<'a, K, V, A> {
@ -348,41 +373,61 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_confusables("push", "put")]
pub fn insert(mut self, value: V) -> &'a mut V {
let out_ptr = match self.handle {
pub fn insert(self, value: V) -> &'a mut V {
self.insert_entry(value).into_mut()
}
/// Sets the value of the entry with the `VacantEntry`'s key,
/// and returns an `OccupiedEntry`.
///
/// # Examples
///
/// ```
/// #![feature(btree_entry_insert)]
/// use std::collections::BTreeMap;
/// use std::collections::btree_map::Entry;
///
/// let mut map: BTreeMap<&str, u32> = BTreeMap::new();
///
/// if let Entry::Vacant(o) = map.entry("poneyland") {
/// let entry = o.insert_entry(37);
/// assert_eq!(entry.get(), &37);
/// }
/// assert_eq!(map["poneyland"], 37);
/// ```
#[unstable(feature = "btree_entry_insert", issue = "65225")]
pub fn insert_entry(mut self, value: V) -> OccupiedEntry<'a, K, V, A> {
let handle = match self.handle {
None => {
// SAFETY: There is no tree yet so no reference to it exists.
let map = unsafe { self.dormant_map.awaken() };
let mut root = NodeRef::new_leaf(self.alloc.clone());
let val_ptr = root.borrow_mut().push(self.key, value);
map.root = Some(root.forget_type());
map.length = 1;
val_ptr
}
Some(handle) => {
let new_handle =
handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
drop(ins.left);
// SAFETY: Pushing a new root node doesn't invalidate
// handles to existing nodes.
let map = unsafe { self.dormant_map.reborrow() };
let root = map.root.as_mut().unwrap(); // same as ins.left
root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right)
});
// Get the pointer to the value
let val_ptr = new_handle.into_val_mut();
// SAFETY: We have consumed self.handle.
let map = unsafe { self.dormant_map.awaken() };
map.length += 1;
val_ptr
let map = unsafe { self.dormant_map.reborrow() };
let root = map.root.insert(NodeRef::new_leaf(self.alloc.clone()).forget_type());
// SAFETY: We *just* created the root as a leaf, and we're
// stacking the new handle on the original borrow lifetime.
unsafe {
let mut leaf = root.borrow_mut().cast_to_leaf_unchecked();
leaf.push_with_handle(self.key, value)
}
}
Some(handle) => handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
drop(ins.left);
// SAFETY: Pushing a new root node doesn't invalidate
// handles to existing nodes.
let map = unsafe { self.dormant_map.reborrow() };
let root = map.root.as_mut().unwrap(); // same as ins.left
root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
}),
};
// Now that we have finished growing the tree using borrowed references,
// dereference the pointer to a part of it, that we picked up along the way.
unsafe { &mut *out_ptr }
// SAFETY: modifying the length doesn't invalidate handles to existing nodes.
unsafe { self.dormant_map.reborrow().length += 1 };
OccupiedEntry {
handle: handle.forget_node_type(),
dormant_map: self.dormant_map,
alloc: self.alloc,
_marker: PhantomData,
}
}
}

View file

@ -739,7 +739,7 @@ impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
/// Unsafely asserts to the compiler the static information that this node is a `Leaf`.
unsafe fn cast_to_leaf_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
pub unsafe fn cast_to_leaf_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
debug_assert!(self.height == 0);
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
}

View file

@ -255,7 +255,11 @@ impl<T: Copy> Clone for MaybeUninit<T> {
#[stable(feature = "maybe_uninit_debug", since = "1.41.0")]
impl<T> fmt::Debug for MaybeUninit<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad(type_name::<Self>())
// NB: there is no `.pad_fmt` so we can't use a simpler `format_args!("MaybeUninit<{..}>").
// This needs to be adjusted if `MaybeUninit` moves modules.
let full_name = type_name::<Self>();
let short_name = full_name.split_once("mem::maybe_uninit::").unwrap().1;
f.pad(short_name)
}
}

View file

@ -10,10 +10,10 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less};
use crate::intrinsics::{exact_div, select_unpredictable, unchecked_sub};
use crate::mem::{self, SizedTypeProperties};
use crate::num::NonZero;
use crate::ops::{Bound, OneSidedRange, Range, RangeBounds};
use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive};
use crate::simd::{self, Simd};
use crate::ub_checks::assert_unsafe_precondition;
use crate::{fmt, hint, ptr, slice};
use crate::{fmt, hint, ptr, range, slice};
#[unstable(
feature = "slice_internals",
@ -4469,6 +4469,12 @@ impl<T> [T] {
/// Returns mutable references to many indices at once, without doing any checks.
///
/// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note
/// that this method takes an array, so all indices must be of the same type.
/// If passed an array of `usize`s this method gives back an array of mutable references
/// to single elements, while if passed an array of ranges it gives back an array of
/// mutable references to slices.
///
/// For a safe alternative see [`get_many_mut`].
///
/// # Safety
@ -4489,30 +4495,49 @@ impl<T> [T] {
/// *b *= 100;
/// }
/// assert_eq!(x, &[10, 2, 400]);
///
/// unsafe {
/// let [a, b] = x.get_many_unchecked_mut([0..1, 1..3]);
/// a[0] = 8;
/// b[0] = 88;
/// b[1] = 888;
/// }
/// assert_eq!(x, &[8, 88, 888]);
///
/// unsafe {
/// let [a, b] = x.get_many_unchecked_mut([1..=2, 0..=0]);
/// a[0] = 11;
/// a[1] = 111;
/// b[0] = 1;
/// }
/// assert_eq!(x, &[1, 11, 111]);
/// ```
///
/// [`get_many_mut`]: slice::get_many_mut
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
#[unstable(feature = "get_many_mut", issue = "104642")]
#[inline]
pub unsafe fn get_many_unchecked_mut<const N: usize>(
pub unsafe fn get_many_unchecked_mut<I, const N: usize>(
&mut self,
indices: [usize; N],
) -> [&mut T; N] {
indices: [I; N],
) -> [&mut I::Output; N]
where
I: GetManyMutIndex + SliceIndex<Self>,
{
// NB: This implementation is written as it is because any variation of
// `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy,
// or generate worse code otherwise. This is also why we need to go
// through a raw pointer here.
let slice: *mut [T] = self;
let mut arr: mem::MaybeUninit<[&mut T; N]> = mem::MaybeUninit::uninit();
let mut arr: mem::MaybeUninit<[&mut I::Output; N]> = mem::MaybeUninit::uninit();
let arr_ptr = arr.as_mut_ptr();
// SAFETY: We expect `indices` to contain disjunct values that are
// in bounds of `self`.
unsafe {
for i in 0..N {
let idx = *indices.get_unchecked(i);
*(*arr_ptr).get_unchecked_mut(i) = &mut *slice.get_unchecked_mut(idx);
let idx = indices.get_unchecked(i).clone();
arr_ptr.cast::<&mut I::Output>().add(i).write(&mut *slice.get_unchecked_mut(idx));
}
arr.assume_init()
}
@ -4520,8 +4545,18 @@ impl<T> [T] {
/// Returns mutable references to many indices at once.
///
/// Returns an error if any index is out-of-bounds, or if the same index was
/// passed more than once.
/// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note
/// that this method takes an array, so all indices must be of the same type.
/// If passed an array of `usize`s this method gives back an array of mutable references
/// to single elements, while if passed an array of ranges it gives back an array of
/// mutable references to slices.
///
/// Returns an error if any index is out-of-bounds, or if there are overlapping indices.
/// An empty range is not considered to overlap if it is located at the beginning or at
/// the end of another range, but is considered to overlap if it is located in the middle.
///
/// This method does a O(n^2) check to check that there are no overlapping indices, so be careful
/// when passing many indices.
///
/// # Examples
///
@ -4534,13 +4569,30 @@ impl<T> [T] {
/// *b = 612;
/// }
/// assert_eq!(v, &[413, 2, 612]);
///
/// if let Ok([a, b]) = v.get_many_mut([0..1, 1..3]) {
/// a[0] = 8;
/// b[0] = 88;
/// b[1] = 888;
/// }
/// assert_eq!(v, &[8, 88, 888]);
///
/// if let Ok([a, b]) = v.get_many_mut([1..=2, 0..=0]) {
/// a[0] = 11;
/// a[1] = 111;
/// b[0] = 1;
/// }
/// assert_eq!(v, &[1, 11, 111]);
/// ```
#[unstable(feature = "get_many_mut", issue = "104642")]
#[inline]
pub fn get_many_mut<const N: usize>(
pub fn get_many_mut<I, const N: usize>(
&mut self,
indices: [usize; N],
) -> Result<[&mut T; N], GetManyMutError<N>> {
indices: [I; N],
) -> Result<[&mut I::Output; N], GetManyMutError<N>>
where
I: GetManyMutIndex + SliceIndex<Self>,
{
if !get_many_check_valid(&indices, self.len()) {
return Err(GetManyMutError { _private: () });
}
@ -4885,14 +4937,15 @@ impl<T, const N: usize> SlicePattern for [T; N] {
///
/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
/// comparison operations.
fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> bool {
#[inline]
fn get_many_check_valid<I: GetManyMutIndex, const N: usize>(indices: &[I; N], len: usize) -> bool {
// NB: The optimizer should inline the loops into a sequence
// of instructions without additional branching.
let mut valid = true;
for (i, &idx) in indices.iter().enumerate() {
valid &= idx < len;
for &idx2 in &indices[..i] {
valid &= idx != idx2;
for (i, idx) in indices.iter().enumerate() {
valid &= idx.is_in_bounds(len);
for idx2 in &indices[..i] {
valid &= !idx.is_overlapping(idx2);
}
}
valid
@ -4916,6 +4969,7 @@ fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> boo
#[unstable(feature = "get_many_mut", issue = "104642")]
// NB: The N here is there to be forward-compatible with adding more details
// to the error type at a later point
#[derive(Clone, PartialEq, Eq)]
pub struct GetManyMutError<const N: usize> {
_private: (),
}
@ -4933,3 +4987,111 @@ impl<const N: usize> fmt::Display for GetManyMutError<N> {
fmt::Display::fmt("an index is out of bounds or appeared multiple times in the array", f)
}
}
mod private_get_many_mut_index {
use super::{Range, RangeInclusive, range};
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
pub trait Sealed {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
impl Sealed for usize {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
impl Sealed for Range<usize> {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
impl Sealed for RangeInclusive<usize> {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
impl Sealed for range::Range<usize> {}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
impl Sealed for range::RangeInclusive<usize> {}
}
/// A helper trait for `<[T]>::get_many_mut()`.
///
/// # Safety
///
/// If `is_in_bounds()` returns `true` and `is_overlapping()` returns `false`,
/// it must be safe to index the slice with the indices.
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
pub unsafe trait GetManyMutIndex: Clone + private_get_many_mut_index::Sealed {
/// Returns `true` if `self` is in bounds for `len` slice elements.
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
fn is_in_bounds(&self, len: usize) -> bool;
/// Returns `true` if `self` overlaps with `other`.
///
/// Note that we don't consider zero-length ranges to overlap at the beginning or the end,
/// but do consider them to overlap in the middle.
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
fn is_overlapping(&self, other: &Self) -> bool;
}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for usize {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
*self < len
}
#[inline]
fn is_overlapping(&self, other: &Self) -> bool {
*self == *other
}
}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for Range<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
(self.start <= self.end) & (self.end <= len)
}
#[inline]
fn is_overlapping(&self, other: &Self) -> bool {
(self.start < other.end) & (other.start < self.end)
}
}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for RangeInclusive<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
(self.start <= self.end) & (self.end < len)
}
#[inline]
fn is_overlapping(&self, other: &Self) -> bool {
(self.start <= other.end) & (other.start <= self.end)
}
}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for range::Range<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
Range::from(*self).is_in_bounds(len)
}
#[inline]
fn is_overlapping(&self, other: &Self) -> bool {
Range::from(*self).is_overlapping(&Range::from(*other))
}
}
#[unstable(feature = "get_many_mut_helpers", issue = "none")]
// SAFETY: We implement `is_in_bounds()` and `is_overlapping()` correctly.
unsafe impl GetManyMutIndex for range::RangeInclusive<usize> {
#[inline]
fn is_in_bounds(&self, len: usize) -> bool {
RangeInclusive::from(*self).is_in_bounds(len)
}
#[inline]
fn is_overlapping(&self, other: &Self) -> bool {
RangeInclusive::from(*self).is_overlapping(&RangeInclusive::from(*other))
}
}

View file

@ -43,3 +43,10 @@ fn pad_integral_resets() {
assert_eq!(format!("{Bar:<03}"), "1 0051 ");
}
#[test]
fn test_maybe_uninit_short() {
// Ensure that the trimmed `MaybeUninit` Debug implementation doesn't break
let x = core::mem::MaybeUninit::new(0u32);
assert_eq!(format!("{x:?}"), "MaybeUninit<u32>");
}

View file

@ -2,6 +2,7 @@ use core::cell::Cell;
use core::cmp::Ordering;
use core::mem::MaybeUninit;
use core::num::NonZero;
use core::ops::{Range, RangeInclusive};
use core::slice;
#[test]
@ -2553,6 +2554,14 @@ fn test_get_many_mut_normal_2() {
*a += 10;
*b += 100;
assert_eq!(v, vec![101, 2, 3, 14, 5]);
let [a, b] = v.get_many_mut([0..=1, 2..=2]).unwrap();
assert_eq!(a, &mut [101, 2][..]);
assert_eq!(b, &mut [3][..]);
a[0] += 10;
a[1] += 20;
b[0] += 100;
assert_eq!(v, vec![111, 22, 103, 14, 5]);
}
#[test]
@ -2563,12 +2572,23 @@ fn test_get_many_mut_normal_3() {
*b += 100;
*c += 1000;
assert_eq!(v, vec![11, 2, 1003, 4, 105]);
let [a, b, c] = v.get_many_mut([0..1, 4..5, 1..4]).unwrap();
assert_eq!(a, &mut [11][..]);
assert_eq!(b, &mut [105][..]);
assert_eq!(c, &mut [2, 1003, 4][..]);
a[0] += 10;
b[0] += 100;
c[0] += 1000;
assert_eq!(v, vec![21, 1002, 1003, 4, 205]);
}
#[test]
fn test_get_many_mut_empty() {
let mut v = vec![1, 2, 3, 4, 5];
let [] = v.get_many_mut([]).unwrap();
let [] = v.get_many_mut::<usize, 0>([]).unwrap();
let [] = v.get_many_mut::<RangeInclusive<usize>, 0>([]).unwrap();
let [] = v.get_many_mut::<Range<usize>, 0>([]).unwrap();
assert_eq!(v, vec![1, 2, 3, 4, 5]);
}
@ -2606,6 +2626,54 @@ fn test_get_many_mut_duplicate() {
assert!(v.get_many_mut([1, 3, 3, 4]).is_err());
}
#[test]
fn test_get_many_mut_range_oob() {
let mut v = vec![1, 2, 3, 4, 5];
assert!(v.get_many_mut([0..6]).is_err());
assert!(v.get_many_mut([5..6]).is_err());
assert!(v.get_many_mut([6..6]).is_err());
assert!(v.get_many_mut([0..=5]).is_err());
assert!(v.get_many_mut([0..=6]).is_err());
assert!(v.get_many_mut([5..=5]).is_err());
}
#[test]
fn test_get_many_mut_range_overlapping() {
let mut v = vec![1, 2, 3, 4, 5];
assert!(v.get_many_mut([0..1, 0..2]).is_err());
assert!(v.get_many_mut([0..1, 1..2, 0..1]).is_err());
assert!(v.get_many_mut([0..3, 1..1]).is_err());
assert!(v.get_many_mut([0..3, 1..2]).is_err());
assert!(v.get_many_mut([0..=0, 2..=2, 0..=1]).is_err());
assert!(v.get_many_mut([0..=4, 0..=0]).is_err());
assert!(v.get_many_mut([4..=4, 0..=0, 3..=4]).is_err());
}
#[test]
fn test_get_many_mut_range_empty_at_edge() {
let mut v = vec![1, 2, 3, 4, 5];
assert_eq!(
v.get_many_mut([0..0, 0..5, 5..5]),
Ok([&mut [][..], &mut [1, 2, 3, 4, 5], &mut []]),
);
assert_eq!(
v.get_many_mut([0..0, 0..1, 1..1, 1..2, 2..2, 2..3, 3..3, 3..4, 4..4, 4..5, 5..5]),
Ok([
&mut [][..],
&mut [1],
&mut [],
&mut [2],
&mut [],
&mut [3],
&mut [],
&mut [4],
&mut [],
&mut [5],
&mut [],
]),
);
}
#[test]
fn test_slice_from_raw_parts_in_const() {
static FANCY: i32 = 4;

View file

@ -511,12 +511,15 @@ fn test_downgrade_basic() {
}
#[test]
// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
// See <https://github.com/rust-lang/rust/issues/121950> for details.
#[cfg_attr(all(miri, target_os = "macos"), ignore)]
fn test_downgrade_observe() {
// Taken from the test `test_rwlock_downgrade` from:
// https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs
const W: usize = 20;
const N: usize = 100;
const N: usize = if cfg!(miri) { 40 } else { 100 };
// This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring
// that the value they wrote has not changed after downgrading.

View file

@ -963,7 +963,7 @@ fn report<'tcx>(
// expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's
// `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary.
/*
expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence() < PREC_PREFIX {
Cow::Owned(format!("({expr_str})"))
} else {
expr_str
@ -1003,7 +1003,7 @@ fn report<'tcx>(
Node::Expr(e) => match e.kind {
ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false),
ExprKind::Call(..) => (PREC_UNAMBIGUOUS, matches!(expr.kind, ExprKind::Field(..))),
_ => (e.precedence().order(), false),
_ => (e.precedence(), false),
},
_ => (0, false),
};
@ -1016,7 +1016,7 @@ fn report<'tcx>(
);
let sugg = if !snip_is_macro
&& (calls_field || expr.precedence().order() < precedence)
&& (calls_field || expr.precedence() < precedence)
&& !has_enclosing_paren(&snip)
&& !is_in_tuple
{
@ -1071,7 +1071,7 @@ fn report<'tcx>(
let (snip, snip_is_macro) =
snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
let sugg =
if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
if !snip_is_macro && expr.precedence() < precedence && !has_enclosing_paren(&snip) {
format!("{prefix}({snip})")
} else {
format!("{prefix}{snip}")
@ -1158,7 +1158,7 @@ impl<'tcx> Dereferencing<'tcx> {
},
Some(parent) if !parent.span.from_expansion() => {
// Double reference might be needed at this point.
if parent.precedence().order() == PREC_UNAMBIGUOUS {
if parent.precedence() == PREC_UNAMBIGUOUS {
// Parentheses would be needed here, don't lint.
*outer_pat = None;
} else {

View file

@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
if !prefix.is_empty()
&& (
// Precedence of internal expression is less than or equal to precedence of `&expr`.
arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression)
arg_expression.precedence() <= PREC_PREFIX || is_range_literal(arg_expression)
)
{
arg_snip = format!("({arg_snip})").into();

View file

@ -117,7 +117,7 @@ where
// it's being passed by value.
let scrutinee = peel_hir_expr_refs(scrutinee).0;
let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_UNAMBIGUOUS {
let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence() < PREC_UNAMBIGUOUS {
format!("({scrutinee_str})")
} else {
scrutinee_str.into()

View file

@ -58,7 +58,7 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
{
let mut applicability = Applicability::MachineApplicable;
let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability);
let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) {
let suggestion = if !from_macro && exp.precedence() < PREC_PREFIX && !has_enclosing_paren(&snip) {
format!("-({snip})")
} else {
format!("-{snip}")

View file

@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr));
let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
let parent_expr = get_parent_expr(cx, expr);
let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence().order() > PREC_PREFIX);
let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence() > PREC_PREFIX);
if expr_ty == indexed_ty {
if expr_ref_count > indexed_ref_count {

View file

@ -1,7 +1,7 @@
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use rustc_ast::ExprPrecedence;
use rustc_ast::util::parser::AssocOp;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Node};
use rustc_hir_typeck::cast::check_cast;
@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
};
if let Node::Expr(parent) = cx.tcx.parent_hir_node(e.hir_id)
&& parent.precedence().order() > ExprPrecedence::Cast.order()
&& parent.precedence() > AssocOp::As.precedence() as i8
{
sugg = format!("({sugg})");
}

View file

@ -1,9 +0,0 @@
//@ known-bug: rust-lang/rust#126359
struct OppOrder<const N: u8 = 3, T = u32> {
arr: [T; N],
}
fn main() {
let _ = OppOrder::<3, u32> { arr: [0, 0, 0] };
}

View file

@ -1,7 +1,7 @@
//@ known-bug: #130521
#![feature(dyn_compatible_for_dispatch)]
struct Vtable(dyn Cap);
struct Vtable(dyn Cap<'static>);
trait Cap<'a> {}

View file

@ -1,12 +0,0 @@
//@ known-bug: #131101
trait Foo<const N: u8> {
fn do_x(&self) -> [u8; N];
}
struct Bar;
impl Foo<const 3> for Bar {
fn do_x(&self) -> [u8; 3] {
[0u8; 3]
}
}

View file

@ -3,7 +3,6 @@
pub struct Foo<'a, 'b, T> {
field1: dyn Bar<'a, 'b>,
//~^ ERROR
//~| ERROR
}
pub trait Bar<'x, 's, U>

View file

@ -5,7 +5,7 @@ LL | field1: dyn Bar<'a, 'b>,
| ^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `U`
--> $DIR/unable-fulfill-trait.rs:9:11
--> $DIR/unable-fulfill-trait.rs:8:11
|
LL | pub trait Bar<'x, 's, U>
| ^^^ -
@ -14,13 +14,6 @@ help: add missing generic argument
LL | field1: dyn Bar<'a, 'b, U>,
| +++
error[E0227]: ambiguous lifetime bound, explicit lifetime bound required
--> $DIR/unable-fulfill-trait.rs:4:13
|
LL | field1: dyn Bar<'a, 'b>,
| ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0107, E0227.
For more information about an error, try `rustc --explain E0107`.
For more information about this error, try `rustc --explain E0107`.

View file

@ -2,10 +2,7 @@ error[E0308]: mismatched types
--> $DIR/match_arr_unknown_len.rs:3:9
|
LL | [1, 2] => true,
| ^^^^^^ expected `2`, found `N`
|
= note: expected array `[u32; 2]`
found array `[u32; N]`
| ^^^^^^ expected an array with a size of 2, found one with a size of N
error: aborting due to 1 previous error

View file

@ -7,9 +7,6 @@ trait Sub<Rhs=Self> {
}
type Test = dyn Add + Sub;
//~^ ERROR E0393
//~| ERROR E0191
//~| ERROR E0393
//~| ERROR E0225
//~^ ERROR E0225
fn main() { }

View file

@ -9,56 +9,6 @@ LL | type Test = dyn Add + Sub;
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0191]: the value of the associated types `Output` in `Add`, `Output` in `Sub` must be specified
--> $DIR/issue-22560.rs:9:17
|
LL | type Output;
| ----------- `Output` defined here
...
LL | type Output;
| ----------- `Output` defined here
...
LL | type Test = dyn Add + Sub;
| ^^^ ^^^ associated type `Output` must be specified
| |
| associated type `Output` must be specified
|
help: specify the associated types
|
LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
error: aborting due to 1 previous error
error[E0393]: the type parameter `Rhs` must be explicitly specified
--> $DIR/issue-22560.rs:9:17
|
LL | trait Add<Rhs=Self> {
| ------------------- type parameter `Rhs` must be specified for this
...
LL | type Test = dyn Add + Sub;
| ^^^
|
= note: because of the default `Self` reference, type parameters must be specified on object types
help: set the type parameter to the desired type
|
LL | type Test = dyn Add<Rhs> + Sub;
| +++++
error[E0393]: the type parameter `Rhs` must be explicitly specified
--> $DIR/issue-22560.rs:9:23
|
LL | trait Sub<Rhs=Self> {
| ------------------- type parameter `Rhs` must be specified for this
...
LL | type Test = dyn Add + Sub;
| ^^^
|
= note: because of the default `Self` reference, type parameters must be specified on object types
help: set the type parameter to the desired type
|
LL | type Test = dyn Add + Sub<Rhs>;
| +++++
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0191, E0225, E0393.
For more information about an error, try `rustc --explain E0191`.
For more information about this error, try `rustc --explain E0225`.

View file

@ -11,16 +11,12 @@ trait Fine<Rhs>: Div<Rhs, Output = Rhs> {}
type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>;
//~^ ERROR only auto traits can be used as additional traits in a trait object
//~| ERROR the value of the associated types
type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
//~^ ERROR only auto traits can be used as additional traits in a trait object
//~| ERROR the value of the associated types
type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
//~^ ERROR only auto traits can be used as additional traits in a trait object
//~| ERROR the value of the associated types
type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
//~^ ERROR only auto traits can be used as additional traits in a trait object
//~| ERROR the value of the associated types
type Bal<Rhs> = dyn X<Rhs>;
//~^ ERROR the value of the associated types

View file

@ -9,26 +9,8 @@ LL | type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>;
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs> {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0191]: the value of the associated types `A` in `Y`, `Output` in `Add`, `Output` in `Mul`, `Output` in `Sub` must be specified
--> $DIR/missing-associated-types.rs:12:21
|
LL | type A;
| ------ `A` defined here
...
LL | type Foo<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Y<Rhs>;
| ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated type `A` must be specified
| | | |
| | | associated type `Output` must be specified
| | associated type `Output` must be specified
| associated type `Output` must be specified
|
help: specify the associated types
|
LL | type Foo<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + X<Rhs, Output = Type> + Y<Rhs, A = Type>;
| ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
error[E0225]: only auto traits can be used as additional traits in a trait object
--> $DIR/missing-associated-types.rs:15:32
--> $DIR/missing-associated-types.rs:14:32
|
LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
| -------- ^^^^^^^^ additional non-auto trait
@ -38,33 +20,8 @@ LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs> {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0191]: the value of the associated types `A` and `B` in `Z`, `Output` and `Output` in `Div`, `Output` in `Add`, `Output` in `Mul`, `Output` in `Sub` must be specified
--> $DIR/missing-associated-types.rs:15:21
|
LL | type A;
| ------ `A` defined here
LL | type B;
| ------ `B` defined here
...
LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
| ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated types `A`, `B`, `Output` must be specified
| | | |
| | | associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified
| | associated type `Output` must be specified
| associated type `Output` must be specified
|
help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
--> $DIR/missing-associated-types.rs:15:43
|
LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
| ^^^^^^
help: specify the associated types
|
LL | type Bar<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + X<Rhs> + Z<Rhs, A = Type, B = Type, Output = Type>;
| ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0225]: only auto traits can be used as additional traits in a trait object
--> $DIR/missing-associated-types.rs:18:32
--> $DIR/missing-associated-types.rs:16:32
|
LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
| -------- ^^^^^^^^ additional non-auto trait
@ -74,25 +31,8 @@ LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + Y<Rhs> {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0191]: the value of the associated types `A` in `Y`, `Output` in `Add`, `Output` in `Sub` must be specified
--> $DIR/missing-associated-types.rs:18:21
|
LL | type A;
| ------ `A` defined here
...
LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
| ^^^^^^^^ ^^^^^^^^ ^^^^^^ associated type `A` must be specified
| | |
| | associated type `Output` must be specified
| associated type `Output` must be specified
|
help: specify the associated types
|
LL | type Baz<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + Y<Rhs, A = Type>;
| ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
error[E0225]: only auto traits can be used as additional traits in a trait object
--> $DIR/missing-associated-types.rs:21:32
--> $DIR/missing-associated-types.rs:18:32
|
LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
| -------- ^^^^^^^^ additional non-auto trait
@ -102,28 +42,15 @@ LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<Rhs> + Sub<Rhs> + Fine<Rhs> {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0191]: the value of the associated types `Output` in `Add`, `Output` in `Sub` must be specified
--> $DIR/missing-associated-types.rs:21:21
|
LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
| ^^^^^^^^ ^^^^^^^^ associated type `Output` must be specified
| |
| associated type `Output` must be specified
|
help: specify the associated types
|
LL | type Bat<Rhs> = dyn Add<Rhs, Output = Type> + Sub<Rhs, Output = Type> + Fine<Rhs>;
| ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
error[E0191]: the value of the associated types `Output` in `Div`, `Output` in `Mul` must be specified
--> $DIR/missing-associated-types.rs:24:21
--> $DIR/missing-associated-types.rs:20:21
|
LL | type Bal<Rhs> = dyn X<Rhs>;
| ^^^^^^ associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified
|
= help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types
error: aborting due to 9 previous errors
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0191, E0225.
For more information about an error, try `rustc --explain E0191`.

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/const-argument-cross-crate-mismatch.rs:6:67
|
LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
| ------------------------- ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
| ------------------------- ^^^^^^^^^^ expected an array with a size of 3, found one with a size of 2
| |
| arguments to this struct are incorrect
|
@ -16,7 +16,7 @@ error[E0308]: mismatched types
--> $DIR/const-argument-cross-crate-mismatch.rs:8:65
|
LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
| ------------------------- ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements
| ------------------------- ^^^^^^^^^^^^^^^ expected an array with a size of 2, found one with a size of 3
| |
| arguments to this struct are incorrect
|

View file

@ -4,10 +4,7 @@ error[E0308]: mismatched types
LL | fn test<const N: usize, const M: usize>() -> [u8; M] {
| ------- expected `[u8; M]` because of return type
LL | [0; N]
| ^^^^^^ expected `M`, found `N`
|
= note: expected array `[u8; M]`
found array `[u8; N]`
| ^^^^^^ expected an array with a size of M, found one with a size of N
error: aborting due to 1 previous error

View file

@ -10,12 +10,10 @@ error[E0308]: mismatched types
--> $DIR/issue-62504.rs:18:21
|
LL | ArrayHolder([0; Self::SIZE])
| ----------- ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
| ----------- ^^^^^^^^^^^^^^^ expected an array with a size of X, found one with a size of Self::SIZE
| |
| arguments to this struct are incorrect
|
= note: expected array `[u32; X]`
found array `[u32; Self::SIZE]`
note: tuple struct defined here
--> $DIR/issue-62504.rs:14:8
|

View file

@ -3,9 +3,6 @@
trait Trait<const N: dyn Trait = bar> {
//~^ ERROR: cannot find value `bar` in this scope
//~| ERROR: cycle detected when computing type of `Trait::N`
//~| ERROR: the trait `Trait` cannot be made into an object
//~| ERROR: the trait `Trait` cannot be made into an object
//~| ERROR: the trait `Trait` cannot be made into an object
async fn a() {}
}

View file

@ -18,77 +18,7 @@ LL | trait Trait<const N: dyn Trait = bar> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/not_wf_param_in_rpitit.rs:3:22
|
LL | trait Trait<const N: dyn Trait = bar> {
| ^^^^^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/not_wf_param_in_rpitit.rs:9:14
|
LL | trait Trait<const N: dyn Trait = bar> {
| ----- this trait cannot be made into an object...
...
LL | async fn a() {}
| ^ ...because associated function `a` has no `self` parameter
help: consider turning `a` into a method by giving it a `&self` argument
|
LL | async fn a(&self) {}
| +++++
help: alternatively, consider constraining `a` so it does not apply to trait objects
|
LL | async fn a() where Self: Sized {}
| +++++++++++++++++
error: aborting due to 2 previous errors
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/not_wf_param_in_rpitit.rs:3:13
|
LL | trait Trait<const N: dyn Trait = bar> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/not_wf_param_in_rpitit.rs:9:14
|
LL | trait Trait<const N: dyn Trait = bar> {
| ----- this trait cannot be made into an object...
...
LL | async fn a() {}
| ^ ...because associated function `a` has no `self` parameter
help: consider turning `a` into a method by giving it a `&self` argument
|
LL | async fn a(&self) {}
| +++++
help: alternatively, consider constraining `a` so it does not apply to trait objects
|
LL | async fn a() where Self: Sized {}
| +++++++++++++++++
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/not_wf_param_in_rpitit.rs:3:13
|
LL | trait Trait<const N: dyn Trait = bar> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/not_wf_param_in_rpitit.rs:9:14
|
LL | trait Trait<const N: dyn Trait = bar> {
| ----- this trait cannot be made into an object...
...
LL | async fn a() {}
| ^ ...because associated function `a` has no `self` parameter
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider turning `a` into a method by giving it a `&self` argument
|
LL | async fn a(&self) {}
| +++++
help: alternatively, consider constraining `a` so it does not apply to trait objects
|
LL | async fn a() where Self: Sized {}
| +++++++++++++++++
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0038, E0391, E0425.
For more information about an error, try `rustc --explain E0038`.
Some errors have detailed explanations: E0391, E0425.
For more information about an error, try `rustc --explain E0391`.

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/array-literal-len-mismatch.rs:1:26
|
LL | const NUMBERS: [u8; 3] = [10, 20];
| - ^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
| - ^^^^^^^^ expected an array with a size of 3, found one with a size of 2
| |
| help: consider specifying the actual array length: `2`

View file

@ -0,0 +1,10 @@
struct BadArraySize<const N: u8> {
arr: [i32; N],
//~^ ERROR the constant `N` is not of type `usize`
}
fn main() {
let _ = BadArraySize::<2> { arr: [0, 0, 0] };
//~^ ERROR mismatched types
//~| ERROR the constant `2` is not of type `usize`
}

View file

@ -0,0 +1,21 @@
error: the constant `N` is not of type `usize`
--> $DIR/bad-array-size-in-type-err.rs:2:10
|
LL | arr: [i32; N],
| ^^^^^^^^ expected `usize`, found `u8`
error[E0308]: mismatched types
--> $DIR/bad-array-size-in-type-err.rs:7:38
|
LL | let _ = BadArraySize::<2> { arr: [0, 0, 0] };
| ^^^^^^^^^ expected an array with a size of 2, found one with a size of 3
error: the constant `2` is not of type `usize`
--> $DIR/bad-array-size-in-type-err.rs:7:38
|
LL | let _ = BadArraySize::<2> { arr: [0, 0, 0] };
| ^^^^^^^^^ expected `usize`, found `u8`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -4,10 +4,10 @@ const VAL: i32 = ARR[IDX];
const BONG: [i32; (ARR[0] - 41) as usize] = [5];
const BLUB: [i32; (ARR[0] - 40) as usize] = [5];
//~^ ERROR: mismatched types
//~| expected an array with a fixed size of 2 elements, found one with 1 element
//~| expected an array
const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99];
//~^ ERROR: mismatched types
//~| expected an array with a fixed size of 1 element, found one with 2 elements
//~| expected an array
fn main() {
let _ = VAL;

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/const-array-oob-arith.rs:5:45
|
LL | const BLUB: [i32; (ARR[0] - 40) as usize] = [5];
| ---------------------- ^^^ expected an array with a fixed size of 2 elements, found one with 1 element
| ---------------------- ^^^ expected an array with a size of 2, found one with a size of 1
| |
| help: consider specifying the actual array length: `1`
@ -10,7 +10,7 @@ error[E0308]: mismatched types
--> $DIR/const-array-oob-arith.rs:8:44
|
LL | const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99];
| ---------------------- ^^^^^^^ expected an array with a fixed size of 1 element, found one with 2 elements
| ---------------------- ^^^^^^^ expected an array with a size of 1, found one with a size of 2
| |
| help: consider specifying the actual array length: `2`

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/array-len-mismatch.rs:6:26
|
LL | let wrong: [u8; 3] = [10, 20];
| ------- ^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
| ------- ^^^^^^^^ expected an array with a size of 3, found one with a size of 2
| | |
| | help: consider specifying the actual array length: `2`
| expected due to this
@ -11,7 +11,7 @@ error[E0308]: mismatched types
--> $DIR/array-len-mismatch.rs:9:26
|
LL | let wrong: [u8; 3] = returns_arr();
| ------- ^^^^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
| ------- ^^^^^^^^^^^^^ expected an array with a size of 3, found one with a size of 2
| | |
| | help: consider specifying the actual array length: `2`
| expected due to this

View file

@ -8,5 +8,4 @@ fn main()
println!("{:?}",(vfnfer[0] as dyn Fn)(3));
//~^ ERROR the precise format of `Fn`-family traits'
//~| ERROR missing generics for trait `Fn`
//~| ERROR the value of the associated type `Output` in `FnOnce`
}

View file

@ -19,13 +19,7 @@ help: add missing generic argument
LL | println!("{:?}",(vfnfer[0] as dyn Fn<Args>)(3));
| ++++++
error[E0191]: the value of the associated type `Output` in `FnOnce` must be specified
--> $DIR/issue-23024.rs:8:39
|
LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3));
| ^^ help: specify the associated type: `Fn::<Output = Type>`
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0107, E0191, E0658.
Some errors have detailed explanations: E0107, E0658.
For more information about an error, try `rustc --explain E0107`.

View file

@ -6,7 +6,6 @@ trait Trait<T> {
pub struct Foo<T = Box<Trait<DefaultFoo>>>; //~ ERROR cycle detected
//~^ ERROR `T` is never used
//~| ERROR `Trait` cannot be made into an object
type DefaultFoo = Foo;
fn main() {

View file

@ -5,7 +5,7 @@ LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
| ^^^^^^^^^^
|
note: ...which requires expanding type alias `DefaultFoo`...
--> $DIR/issue-34373.rs:10:19
--> $DIR/issue-34373.rs:9:19
|
LL | type DefaultFoo = Foo;
| ^^^
@ -17,28 +17,6 @@ LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/issue-34373.rs:7:24
|
LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
| ^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/issue-34373.rs:4:8
|
LL | trait Trait<T> {
| ----- this trait cannot be made into an object...
LL | fn foo(_: T) {}
| ^^^ ...because associated function `foo` has no `self` parameter
help: consider turning `foo` into a method by giving it a `&self` argument
|
LL | fn foo(&self, _: T) {}
| ++++++
help: alternatively, consider constraining `foo` so it does not apply to trait objects
|
LL | fn foo(_: T) where Self: Sized {}
| +++++++++++++++++
error[E0392]: type parameter `T` is never used
--> $DIR/issue-34373.rs:7:16
|
@ -48,7 +26,7 @@ LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
error: aborting due to 3 previous errors
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0038, E0391, E0392.
For more information about an error, try `rustc --explain E0038`.
Some errors have detailed explanations: E0391, E0392.
For more information about an error, try `rustc --explain E0391`.

View file

@ -1,51 +0,0 @@
// General test of maybe_uninits state computed by MIR dataflow.
#![feature(core_intrinsics, rustc_attrs)]
use std::intrinsics::rustc_peek;
use std::mem::{drop, replace};
struct S(i32);
#[rustc_mir(rustc_peek_definite_init,stop_after_dataflow)]
fn foo(test: bool, x: &mut S, y: S, mut z: S) -> S {
let ret;
// `ret` starts off uninitialized
rustc_peek(&ret); //~ ERROR rustc_peek: bit not set
// All function formal parameters start off initialized.
rustc_peek(&x);
rustc_peek(&y);
rustc_peek(&z);
ret = if test {
::std::mem::replace(x, y)
} else {
z = y;
z
};
// `z` may be uninitialized here.
rustc_peek(&z); //~ ERROR rustc_peek: bit not set
// `y` is definitely uninitialized here.
rustc_peek(&y); //~ ERROR rustc_peek: bit not set
// `x` is still (definitely) initialized (replace above is a reborrow).
rustc_peek(&x);
::std::mem::drop(x);
// `x` is *definitely* uninitialized here
rustc_peek(&x); //~ ERROR rustc_peek: bit not set
// `ret` is now definitely initialized (via `if` above).
rustc_peek(&ret);
ret
}
fn main() {
foo(true, &mut S(13), S(14), S(15));
foo(false, &mut S(13), S(14), S(15));
}

View file

@ -1,28 +0,0 @@
error: rustc_peek: bit not set
--> $DIR/def-inits-1.rs:14:5
|
LL | rustc_peek(&ret);
| ^^^^^^^^^^^^^^^^
error: rustc_peek: bit not set
--> $DIR/def-inits-1.rs:30:5
|
LL | rustc_peek(&z);
| ^^^^^^^^^^^^^^
error: rustc_peek: bit not set
--> $DIR/def-inits-1.rs:33:5
|
LL | rustc_peek(&y);
| ^^^^^^^^^^^^^^
error: rustc_peek: bit not set
--> $DIR/def-inits-1.rs:41:5
|
LL | rustc_peek(&x);
| ^^^^^^^^^^^^^^
error: stop_after_dataflow ended compilation
error: aborting due to 5 previous errors

View file

@ -5,8 +5,7 @@ pub trait T<X, Y> {
}
pub struct Foo {
i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
//~^ ERROR must be specified
//~| ERROR trait takes 2 generic arguments but 4 generic arguments were supplied
//~^ ERROR trait takes 2 generic arguments but 4 generic arguments were supplied
}

View file

@ -14,19 +14,6 @@ help: replace the generic bounds with the associated types
LL | i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
| +++ +++
error[E0191]: the value of the associated types `C` and `A` in `T` must be specified
--> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
|
LL | type A;
| ------ `A` defined here
LL | type B;
LL | type C;
| ------ `C` defined here
...
LL | i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified
error: aborting due to 1 previous error
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0107, E0191.
For more information about an error, try `rustc --explain E0107`.
For more information about this error, try `rustc --explain E0107`.

View file

@ -3,7 +3,4 @@ trait Trait {}
pub fn main() {
let x: Vec<dyn Trait + Sized> = Vec::new();
//~^ ERROR only auto traits can be used as additional traits in a trait object
//~| ERROR the size for values of type
//~| ERROR the size for values of type
//~| ERROR the size for values of type
}

View file

@ -9,37 +9,6 @@ LL | let x: Vec<dyn Trait + Sized> = Vec::new();
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Trait + Sized {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
--> $DIR/bad-sized.rs:4:12
|
LL | let x: Vec<dyn Trait + Sized> = Vec::new();
| ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Trait`
note: required by an implicit `Sized` bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
error: aborting due to 1 previous error
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
--> $DIR/bad-sized.rs:4:37
|
LL | let x: Vec<dyn Trait + Sized> = Vec::new();
| ^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Trait`
note: required by a bound in `Vec::<T>::new`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
--> $DIR/bad-sized.rs:4:37
|
LL | let x: Vec<dyn Trait + Sized> = Vec::new();
| ^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn Trait`
note: required by an implicit `Sized` bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0225, E0277.
For more information about an error, try `rustc --explain E0225`.
For more information about this error, try `rustc --explain E0225`.

View file

@ -7,5 +7,4 @@ fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
fn main() {
size_of_copy::<dyn Misc + Copy>();
//~^ ERROR only auto traits can be used as additional traits in a trait object
//~| ERROR the trait bound `dyn Misc: Copy` is not satisfied
}

View file

@ -9,19 +9,6 @@ LL | size_of_copy::<dyn Misc + Copy>();
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied
--> $DIR/issue-32963.rs:8:20
|
LL | size_of_copy::<dyn Misc + Copy>();
| ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
|
note: required by a bound in `size_of_copy`
--> $DIR/issue-32963.rs:5:20
|
LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
| ^^^^ required by this bound in `size_of_copy`
error: aborting due to 1 previous error
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0225, E0277.
For more information about an error, try `rustc --explain E0225`.
For more information about this error, try `rustc --explain E0225`.

View file

@ -1,11 +1,6 @@
trait Trait<const N: Trait = bar> {
//~^ ERROR cannot find value `bar` in this scope
//~| ERROR cycle detected when computing type of `Trait::N`
//~| ERROR the trait `Trait` cannot be made into an object
//~| ERROR the trait `Trait` cannot be made into an object
//~| ERROR the trait `Trait` cannot be made into an object
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
fn fnc<const N: Trait = u32>(&self) -> Trait {
@ -13,9 +8,6 @@ trait Trait<const N: Trait = bar> {
//~| ERROR expected value, found builtin type `u32`
//~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
//~| ERROR associated item referring to unboxed trait object for its own trait
//~| ERROR the trait `Trait` cannot be made into an object
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
//~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]

View file

@ -1,5 +1,5 @@
error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:18
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:18
|
LL | trait Trait<const N: Trait = bar> {
| - first use of `N`
@ -14,13 +14,13 @@ LL | trait Trait<const N: Trait = bar> {
| ^^^ not found in this scope
error[E0423]: expected value, found builtin type `u32`
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:29
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:29
|
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^ not a value
error[E0425]: cannot find value `bar` in this scope
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:23:9
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:15:9
|
LL | bar
| ^^^ not found in this scope
@ -53,27 +53,8 @@ LL | trait Trait<const N: Trait = bar> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:12
|
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^^^^^^^^^^^^^^^^^^
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
|
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
help: if this is a dyn-compatible trait, use `dyn`
|
LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
| +++
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44
|
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^^^
@ -85,54 +66,27 @@ help: if this is a dyn-compatible trait, use `dyn`
LL | fn fnc<const N: Trait = u32>(&self) -> dyn Trait {
| +++
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:12
|
LL | trait Trait<const N: Trait = bar> {
| ^^^^^
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^^^^^^^^^^^^^^^^^^
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:21
|
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: if this is a dyn-compatible trait, use `dyn`
|
LL | trait Trait<const N: dyn Trait = bar> {
| +++
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
|
LL | trait Trait<const N: Trait = bar> {
| ^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
|
LL | trait Trait<const N: Trait = bar> {
| ----- this trait cannot be made into an object...
...
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^ ...because method `fnc` has generic type parameters
= help: consider moving `fnc` to another trait
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13
|
LL | trait Trait<const N: Trait = bar> {
| ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
|
LL | trait Trait<const N: Trait = bar> {
| ----- this trait cannot be made into an object...
...
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^ ...because method `fnc` has generic type parameters
= help: consider moving `fnc` to another trait
LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
| +++
error: associated item referring to unboxed trait object for its own trait
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:44
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44
|
LL | trait Trait<const N: Trait = bar> {
| ----- in this trait
@ -145,54 +99,7 @@ help: you might have meant to use `Self` to refer to the implementing type
LL | fn fnc<const N: Trait = u32>(&self) -> Self {
| ~~~~
warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
|
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^^^
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: if this is a dyn-compatible trait, use `dyn`
|
LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
| +++
error: aborting due to 7 previous errors; 3 warnings emitted
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21
|
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
|
LL | trait Trait<const N: Trait = bar> {
| ----- this trait cannot be made into an object...
...
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^ ...because method `fnc` has generic type parameters
= help: consider moving `fnc` to another trait
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13
|
LL | trait Trait<const N: Trait = bar> {
| ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:8
|
LL | trait Trait<const N: Trait = bar> {
| ----- this trait cannot be made into an object...
...
LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^ ...because method `fnc` has generic type parameters
= help: consider moving `fnc` to another trait
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 11 previous errors; 5 warnings emitted
Some errors have detailed explanations: E0038, E0391, E0403, E0423, E0425.
For more information about an error, try `rustc --explain E0038`.
Some errors have detailed explanations: E0391, E0403, E0423, E0425.
For more information about an error, try `rustc --explain E0391`.