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

View file

@ -191,6 +191,6 @@ impl FixupContext {
/// "let chain". /// "let chain".
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool { pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr) 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 std::fmt;
use rustc_abi::ExternAbi; 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::{ use rustc_ast::{
self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label,
LitKind, TraitObjectSyntax, UintTy, LitKind, TraitObjectSyntax, UintTy,
@ -1708,41 +1708,54 @@ pub struct Expr<'hir> {
} }
impl Expr<'_> { impl Expr<'_> {
pub fn precedence(&self) -> ExprPrecedence { pub fn precedence(&self) -> i8 {
match self.kind { match self.kind {
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock, ExprKind::Closure { .. } => PREC_CLOSURE,
ExprKind::Array(_) => ExprPrecedence::Array,
ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::Break(..)
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, | ExprKind::Continue(..)
ExprKind::Tup(_) => ExprPrecedence::Tup, | ExprKind::Ret(..)
ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node), | ExprKind::Yield(..)
ExprKind::Unary(..) => ExprPrecedence::Unary, | ExprKind::Become(..) => PREC_JUMP,
ExprKind::Lit(_) => ExprPrecedence::Lit,
ExprKind::Cast(..) => ExprPrecedence::Cast, // 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::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::span_bug;
use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::{ 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_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; 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<_>) = let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
// We don't support >1 principal
if regular_traits.len() > 1 { if regular_traits.len() > 1 {
let _ = self.report_trait_object_addition_traits_error(&regular_traits); let guar = self.report_trait_object_addition_traits_error(&regular_traits);
} else if regular_traits.is_empty() && auto_traits.is_empty() { return Ty::new_error(tcx, guar);
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds); }
return Ty::new_error(tcx, reported); // 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; // 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) { 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 /// 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.space();
self.word_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()) 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 { 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![ vec![
(up_to_rcvr_span, "".to_string()), (up_to_rcvr_span, "".to_string()),
(rest_span, format!(".{}({rest_snippet}", segment.ident)), (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) { 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_parens = expr_prec < rustc_ast::util::parser::PREC_UNAMBIGUOUS;
let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize)); 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 core::iter;
use hir::def_id::LocalDefId; 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_data_structures::packed::Pu128;
use rustc_errors::{Applicability, Diag, MultiSpan}; use rustc_errors::{Applicability, Diag, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
@ -398,7 +398,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// so we remove the user's `clone` call. // so we remove the user's `clone` call.
{ {
vec![(receiver_method.ident.span, conversion_method.name.to_string())] 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![ vec![
(expr.span.shrink_to_lo(), "(".to_string()), (expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)), (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 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())] vec![(span.shrink_to_hi(), ".into()".to_owned())]
} else { } else {
vec![ vec![
@ -3000,7 +3000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`", "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())); sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
")" ")"
} else { } else {
@ -3025,7 +3025,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let len = src.trim_end_matches(&checked_ty.to_string()).len(); let len = src.trim_end_matches(&checked_ty.to_string()).len();
expr.span.with_lo(expr.span.lo() + BytePos(len as u32)) expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
}, },
if expr.precedence().order() < PREC_UNAMBIGUOUS { if expr.precedence() < PREC_UNAMBIGUOUS {
// Readd `)` // Readd `)`
format!("{expected_ty})") format!("{expected_ty})")
} else { } else {

View file

@ -566,19 +566,19 @@ impl Cursor<'_> {
fn c_or_byte_string( fn c_or_byte_string(
&mut self, &mut self,
mk_kind: impl FnOnce(bool) -> LiteralKind, mk_kind: fn(bool) -> LiteralKind,
mk_kind_raw: impl FnOnce(Option<u8>) -> LiteralKind, mk_kind_raw: fn(Option<u8>) -> LiteralKind,
single_quoted: Option<fn(bool) -> LiteralKind>, single_quoted: Option<fn(bool) -> LiteralKind>,
) -> TokenKind { ) -> TokenKind {
match (self.first(), self.second(), single_quoted) { match (self.first(), self.second(), single_quoted) {
('\'', _, Some(mk_kind)) => { ('\'', _, Some(single_quoted)) => {
self.bump(); self.bump();
let terminated = self.single_quoted_string(); let terminated = self.single_quoted_string();
let suffix_start = self.pos_within_token(); let suffix_start = self.pos_within_token();
if terminated { if terminated {
self.eat_literal_suffix(); self.eat_literal_suffix();
} }
let kind = mk_kind(terminated); let kind = single_quoted(terminated);
Literal { kind, suffix_start } 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 })); check_raw_str(&s2, Err(RawStrError::TooManyDelimiters { found: u32::from(max_count) + 1 }));
} }
// https://github.com/rust-lang/rust/issues/70528
#[test] #[test]
fn test_valid_shebang() { fn test_valid_shebang() {
// https://github.com/rust-lang/rust/issues/70528 let input = "#!/bin/bash";
let input = "#!/usr/bin/rustrun\nlet x = 5;"; assert_eq!(strip_shebang(input), Some(input.len()));
assert_eq!(strip_shebang(input), Some(18));
}
#[test] let input = "#![attribute]";
fn test_invalid_shebang_valid_rust_syntax() { assert_eq!(strip_shebang(input), None);
// https://github.com/rust-lang/rust/issues/70528
let input = "#! [bad_attribute]"; 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); 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 // Because shebangs are interpreted by the kernel, they must be on the first line
let input = "\n#!/bin/bash"; let input = "\n#!/bin/bash";
assert_eq!(strip_shebang(input), None); assert_eq!(strip_shebang(input), None);
}
#[test] let input = "\n#![attribute]";
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)]";
assert_eq!(strip_shebang(input), None); 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) { fn check_lexing(src: &str, expect: Expect) {
let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect(); let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect();
expect.assert_eq(&actual) 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> { 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 { fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
Const::new_infer(tcx, infer) Const::new_infer(tcx, infer)
} }

View file

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

View file

@ -3,7 +3,6 @@ use std::iter;
pub use rustc_type_ir::relate::*; pub use rustc_type_ir::relate::*;
use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
use crate::ty::{self as ty, Ty, TyCtxt}; use crate::ty::{self as ty, Ty, TyCtxt};
pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>; 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`. // in `a`.
let mut a_v: Vec<_> = a.into_iter().collect(); let mut a_v: Vec<_> = a.into_iter().collect();
let mut b_v: Vec<_> = b.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(); a_v.dedup();
b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
b_v.dedup(); b_v.dedup();
if a_v.len() != b_v.len() { if a_v.len() != b_v.len() {
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))); return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));

View file

@ -1,6 +1,7 @@
//! Random access inspection of the results of a dataflow analysis. //! Random access inspection of the results of a dataflow analysis.
use std::cmp::Ordering; use std::cmp::Ordering;
use std::ops::{Deref, DerefMut};
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
@ -8,18 +9,63 @@ use rustc_middle::mir::{self, BasicBlock, Location};
use super::{Analysis, Direction, Effect, EffectIndex, Results}; 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 /// Because `Results` only has domain values for the entry of each basic block, these inspections
/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are /// involve some amount of domain value recomputations. This cursor only has linear performance
/// visited in *reverse* order—performance will be quadratic in the number of statements in the /// within a basic block when its statements are visited in the same order as the `DIRECTION` of
/// block. The order in which basic blocks are inspected has no impact on performance. /// 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> pub struct ResultsCursor<'mir, 'tcx, A>
where where
A: Analysis<'tcx>, A: Analysis<'tcx>,
{ {
body: &'mir mir::Body<'tcx>, body: &'mir mir::Body<'tcx>,
results: Results<'tcx, A>, results: ResultsHandle<'mir, 'tcx, A>,
state: A::Domain, state: A::Domain,
pos: CursorPosition, pos: CursorPosition,
@ -47,13 +93,8 @@ where
self.body 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`. /// 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); let bottom_value = results.analysis.bottom_value(body);
ResultsCursor { ResultsCursor {
body, body,

View file

@ -9,10 +9,21 @@ use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
pub trait Direction { pub trait Direction {
const IS_FORWARD: bool; const IS_FORWARD: bool;
const IS_BACKWARD: bool = !Self::IS_FORWARD; 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. /// `effects.start()` must precede or equal `effects.end()` in this direction.
fn apply_effects_in_range<'tcx, A>( fn apply_effects_in_range<'tcx, A>(
@ -24,15 +35,9 @@ pub trait Direction {
) where ) where
A: Analysis<'tcx>; A: Analysis<'tcx>;
fn apply_effects_in_block<'mir, 'tcx, A>( /// Called by `ResultsVisitor` to recompute the analysis domain values for
analysis: &mut A, /// all locations in a basic block (starting from the entry value stored
state: &mut A::Domain, /// in `Results`) and to visit them with `vis`.
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
) -> TerminatorEdges<'mir, 'tcx>
where
A: Analysis<'tcx>;
fn visit_results_in_block<'mir, 'tcx, A>( fn visit_results_in_block<'mir, 'tcx, A>(
state: &mut A::Domain, state: &mut A::Domain,
block: BasicBlock, block: BasicBlock,
@ -41,16 +46,6 @@ pub trait Direction {
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>, vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
) where ) where
A: Analysis<'tcx>; 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). /// 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>( fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A, analysis: &mut A,
body: &mir::Body<'tcx>,
state: &mut A::Domain, state: &mut A::Domain,
block: BasicBlock, block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>, block_data: &'mir mir::BasicBlockData<'tcx>,
) -> TerminatorEdges<'mir, 'tcx> mut propagate: impl FnMut(BasicBlock, &A::Domain),
where ) where
A: Analysis<'tcx>, A: Analysis<'tcx>,
{ {
let terminator = block_data.terminator(); let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() }; let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location); 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() { for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
let location = Location { block, statement_index }; let location = Location { block, statement_index };
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_before_statement_effect(state, statement, location);
analysis.apply_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>( fn apply_effects_in_range<'tcx, A>(
@ -170,7 +226,6 @@ impl Direction for Backward {
vis.visit_block_end(state); vis.visit_block_end(state);
// Terminator
let loc = Location { block, statement_index: block_data.statements.len() }; let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator(); let term = block_data.terminator();
results.analysis.apply_before_terminator_effect(state, term, loc); results.analysis.apply_before_terminator_effect(state, term, loc);
@ -188,82 +243,13 @@ impl Direction for Backward {
vis.visit_block_start(state); 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> { struct BackwardSwitchIntEdgeEffectsApplier<'mir, 'tcx, D, F> {
body: &'mir mir::Body<'tcx>, body: &'mir mir::Body<'tcx>,
pred: BasicBlock, pred: BasicBlock,
exit_state: &'mir mut D, exit_state: &'mir mut D,
bb: BasicBlock, block: BasicBlock,
propagate: &'mir mut F, propagate: &'mir mut F,
effects_applied: bool, effects_applied: bool,
} }
@ -276,8 +262,8 @@ where
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) { fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
assert!(!self.effects_applied); assert!(!self.effects_applied);
let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)]; let values = &self.body.basic_blocks.switch_sources()[&(self.block, self.pred)];
let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb }); let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.block });
let mut tmp = None; let mut tmp = None;
for target in targets { for target in targets {
@ -298,11 +284,12 @@ impl Direction for Forward {
fn apply_effects_in_block<'mir, 'tcx, A>( fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A, analysis: &mut A,
_body: &mir::Body<'tcx>,
state: &mut A::Domain, state: &mut A::Domain,
block: BasicBlock, block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>, block_data: &'mir mir::BasicBlockData<'tcx>,
) -> TerminatorEdges<'mir, 'tcx> mut propagate: impl FnMut(BasicBlock, &A::Domain),
where ) where
A: Analysis<'tcx>, A: Analysis<'tcx>,
{ {
for (statement_index, statement) in block_data.statements.iter().enumerate() { for (statement_index, statement) in block_data.statements.iter().enumerate() {
@ -313,7 +300,53 @@ impl Direction for Forward {
let terminator = block_data.terminator(); let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() }; let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location); 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>( fn apply_effects_in_range<'tcx, A>(
@ -351,7 +384,8 @@ impl Direction for Forward {
let statement = &block_data.statements[from.statement_index]; let statement = &block_data.statements[from.statement_index];
analysis.apply_statement_effect(state, statement, location); 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 { if from == to {
return; return;
} }
@ -419,62 +453,6 @@ impl Direction for Forward {
vis.visit_block_end(state); 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> { struct ForwardSwitchIntEdgeEffectsApplier<'mir, D, F> {

View file

@ -230,16 +230,3 @@ where
write!(f, "{}", ctxt.move_data().move_paths[*self]) 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( pub(crate) fn new(
body: &'mir Body<'tcx>, body: &'mir Body<'tcx>,
results: Results<'tcx, A>, results: &'mir Results<'tcx, A>,
style: OutputStyle, style: OutputStyle,
) -> Self { ) -> Self {
let reachable = mir::traversal::reachable_as_bitset(body); 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> { fn body(&self) -> &'mir Body<'tcx> {
self.cursor.borrow().body() 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`. /// A pair of a basic block and an index into that basic blocks `successors`.

View file

@ -25,8 +25,8 @@
//! //!
//! ## `PartialOrd` //! ## `PartialOrd`
//! //!
//! Given that they represent partially ordered sets, you may be surprised that [`JoinSemiLattice`] //! Given that it represents a partially ordered set, you may be surprised that [`JoinSemiLattice`]
//! and [`MeetSemiLattice`] do not have [`PartialOrd`] as a supertrait. This //! does not have [`PartialOrd`] as a supertrait. This
//! is because most standard library types use lexicographic ordering instead of set inclusion for //! 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 //! 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 //! 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; 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. /// A set that has a "bottom" element, which is less than or equal to any other element.
pub trait HasBottom { pub trait HasBottom {
const BOTTOM: Self; 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 { impl HasBottom for bool {
const BOTTOM: Self = false; 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 /// 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, /// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices,
/// one for each possible value of `T`. /// 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> { impl<T: Idx> JoinSemiLattice for ChunkedBitSet<T> {
fn join(&mut self, other: &Self) -> bool { fn join(&mut self, other: &Self) -> bool {
self.union(other) 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 /// 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. /// 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> { impl<T> HasBottom for FlatSet<T> {
const BOTTOM: Self = Self::Bottom; const BOTTOM: Self = Self::Bottom;

View file

@ -8,8 +8,9 @@
//! The `impls` module contains several examples of dataflow analyses. //! 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 //! 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, //! 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 //! (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. //! the `ResultsCursor` approach.
//! //!
//! ```ignore (cross-crate-imports) //! ```ignore (cross-crate-imports)
@ -278,22 +279,17 @@ pub trait Analysis<'tcx> {
// every iteration. // every iteration.
let mut state = self.bottom_value(body); let mut state = self.bottom_value(body);
while let Some(bb) = dirty_queue.pop() { while let Some(bb) = dirty_queue.pop() {
let bb_data = &body[bb];
// Set the state to the entry state of the block. // Set the state to the entry state of the block.
// This is equivalent to `state = entry_sets[bb].clone()`, // This is equivalent to `state = entry_sets[bb].clone()`,
// but it saves an allocation, thus improving compile times. // but it saves an allocation, thus improving compile times.
state.clone_from(&entry_sets[bb]); state.clone_from(&entry_sets[bb]);
// Apply the block transfer function, using the cached one if it exists. Self::Direction::apply_effects_in_block(
let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data);
Self::Direction::join_state_into_successors_of(
&mut self, &mut self,
body, body,
&mut state, &mut state,
bb, bb,
edges, &body[bb],
|target: BasicBlock, state: &Self::Domain| { |target: BasicBlock, state: &Self::Domain| {
let set_changed = entry_sets[target].join(state); let set_changed = entry_sets[target].join(state);
if set_changed { if set_changed {
@ -306,14 +302,13 @@ pub trait Analysis<'tcx> {
let results = Results { analysis: self, entry_sets }; let results = Results { analysis: self, entry_sets };
if tcx.sess.opts.unstable_opts.dump_mir_dataflow { 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 { if let Err(e) = res {
error!("Failed to write graphviz dataflow results: {}", e); 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. // NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Effect { enum Effect {

View file

@ -17,10 +17,13 @@ use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
use crate::errors::{ use crate::errors::{
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
}; };
use crate::framework::cursor::ResultsHandle;
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>; 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)] #[derive(Clone)]
pub struct Results<'tcx, A> pub struct Results<'tcx, A>
where where
@ -34,12 +37,30 @@ impl<'tcx, A> Results<'tcx, A>
where where
A: Analysis<'tcx>, 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>( pub fn into_results_cursor<'mir>(
self, self,
body: &'mir mir::Body<'tcx>, body: &'mir mir::Body<'tcx>,
) -> ResultsCursor<'mir, 'tcx, A> { ) -> ResultsCursor<'mir, 'tcx, A> {
ResultsCursor::new(body, self) ResultsCursor::new(body, ResultsHandle::Owned(self))
} }
/// Gets the dataflow state for the given block. /// Gets the dataflow state for the given block.
@ -74,9 +95,9 @@ where
pub(super) fn write_graphviz_results<'tcx, A>( pub(super) fn write_graphviz_results<'tcx, A>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>, body: &mir::Body<'tcx>,
results: Results<'tcx, A>, results: &Results<'tcx, A>,
pass_name: Option<&'static str>, pass_name: Option<&'static str>,
) -> (std::io::Result<()>, Results<'tcx, A>) ) -> std::io::Result<()>
where where
A: Analysis<'tcx>, A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>, A::Domain: DebugWithContext<A>,
@ -87,7 +108,7 @@ where
let def_id = body.source.def_id(); let def_id = body.source.def_id();
let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else { let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
// Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse` // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
return (Ok(()), results); return Ok(());
}; };
let file = try { let file = try {
@ -104,12 +125,12 @@ where
create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
} }
_ => return (Ok(()), results), _ => return Ok(()),
} }
}; };
let mut file = match file { let mut file = match file {
Ok(f) => f, Ok(f) => f,
Err(e) => return (Err(e), results), Err(e) => return Err(e),
}; };
let style = match attrs.formatter { let style = match attrs.formatter {
@ -132,7 +153,7 @@ where
file.write_all(&buf)?; file.write_all(&buf)?;
}; };
(lhs, graphviz.into_results()) lhs
} }
#[derive(Default)] #[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> pub trait ResultsVisitor<'mir, 'tcx, A>
where where
A: Analysis<'tcx>, A: Analysis<'tcx>,

View file

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

View file

@ -12,7 +12,7 @@ use crate::framework::SwitchIntEdgeEffects;
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
use crate::{ use crate::{
Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry, 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 /// `MaybeInitializedPlaces` tracks all places that might be
@ -42,10 +42,10 @@ use crate::{
/// } /// }
/// ``` /// ```
/// ///
/// To determine whether a place *must* be initialized at a /// To determine whether a place is *definitely* initialized at a
/// particular control-flow point, one can take the set-difference /// particular control-flow point, one can take the set-complement
/// between this data and the data from `MaybeUninitializedPlaces` at the /// of the data from `MaybeUninitializedPlaces` at the corresponding
/// corresponding control-flow point. /// control-flow point.
/// ///
/// Similarly, at a given `drop` statement, the set-intersection /// Similarly, at a given `drop` statement, the set-intersection
/// between this data and `MaybeUninitializedPlaces` yields the set of /// 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 /// To determine whether a place is *definitely* uninitialized at a
/// particular control-flow point, one can take the set-difference /// particular control-flow point, one can take the set-complement
/// between this data and the data from `MaybeInitializedPlaces` at the /// of the data from `MaybeInitializedPlaces` at the corresponding
/// corresponding control-flow point. /// control-flow point.
/// ///
/// Similarly, at a given `drop` statement, the set-intersection /// Similarly, at a given `drop` statement, the set-intersection
/// between this data and `MaybeInitializedPlaces` yields the set of /// 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 /// `EverInitializedPlaces` tracks all places that might have ever been
/// initialized upon reaching a particular point in the control flow /// initialized upon reaching a particular point in the control flow
/// for a function, without an intervening `StorageDead`. /// 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> { impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
/// There can be many more `MovePathIndex` than there are locals in a MIR body. /// 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. /// 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> { impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
/// There can be many more `InitIndex` than there are locals in a MIR body. /// 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. /// 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::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals};
pub use self::initialized::{ pub use self::initialized::{
DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeInitializedPlaces, EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
MaybeUninitializedPlaces,
}; };
pub use self::liveness::{ pub use self::liveness::{
MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction, MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,

View file

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

View file

@ -12,9 +12,7 @@ use crate::errors::{
PeekMustBePlaceOrRefPlace, StopAfterDataFlowEndedCompilation, PeekMustBePlaceOrRefPlace, StopAfterDataFlowEndedCompilation,
}; };
use crate::framework::BitSetExt; use crate::framework::BitSetExt;
use crate::impls::{ use crate::impls::{MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces};
DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
};
use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex}; use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
use crate::{Analysis, JoinSemiLattice, ResultsCursor}; 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)); 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() { if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None); 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); 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 // Calculate the MIR locals that we need to keep storage around for.
// for. let mut requires_storage_results =
let mut requires_storage_cursor =
MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body)) MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
.iterate_to_fixpoint(tcx, body, None) .iterate_to_fixpoint(tcx, body, None);
.into_results_cursor(body); let mut requires_storage_cursor = requires_storage_results.as_results_cursor_mut(body);
// Calculate the liveness of MIR locals ignoring borrows. // Calculate the liveness of MIR locals ignoring borrows.
let mut liveness = let mut liveness =
@ -754,7 +753,7 @@ fn locals_live_across_suspend_points<'tcx>(
body, body,
&saved_locals, &saved_locals,
always_live_locals.clone(), always_live_locals.clone(),
requires_storage_cursor.into_results(), requires_storage_results,
); );
LivenessInfo { LivenessInfo {

View file

@ -18,6 +18,7 @@ use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, Pos, Span}; use rustc_span::{BytePos, Pos, Span};
use tracing::debug; use tracing::debug;
use crate::lexer::diagnostics::TokenTreeDiagInfo;
use crate::lexer::unicode_chars::UNICODE_ARRAY; use crate::lexer::unicode_chars::UNICODE_ARRAY;
use crate::{errors, make_unclosed_delims_error}; 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 cursor = Cursor::new(src);
let string_reader = StringReader { let mut lexer = Lexer {
psess, psess,
start_pos, start_pos,
pos: start_pos, pos: start_pos,
@ -65,34 +66,31 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
override_span, override_span,
nbsp_is_whitespace: false, nbsp_is_whitespace: false,
last_lifetime: None, last_lifetime: None,
token: Token::dummy(),
diag_info: TokenTreeDiagInfo::default(),
}; };
let (stream, res, unmatched_delims) = let (_open_spacing, stream, res) = lexer.lex_token_trees(/* is_delimited */ false);
tokentrees::TokenTreesReader::lex_all_token_trees(string_reader); let unmatched_delims = lexer.diag_info.unmatched_delims;
match res {
Ok(()) if unmatched_delims.is_empty() => Ok(stream), if res.is_ok() && unmatched_delims.is_empty() {
_ => { Ok(stream)
} else {
// Return error if there are unmatched delimiters or unclosed delimiters. // Return error if there are unmatched delimiters or unclosed delimiters.
// We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch // 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 // because the delimiter mismatch is more likely to be the root cause of error
let mut buffer: Vec<_> = unmatched_delims
let mut buffer = Vec::with_capacity(1); .into_iter()
for unmatched in unmatched_delims { .filter_map(|unmatched_delim| make_unclosed_delims_error(unmatched_delim, psess))
if let Some(err) = make_unclosed_delims_error(unmatched, psess) { .collect();
buffer.push(err);
}
}
if let Err(errs) = res { if let Err(errs) = res {
// Add unclosing delimiter or diff marker errors // Add unclosing delimiter or diff marker errors
for err in errs { buffer.extend(errs);
buffer.push(err);
}
} }
Err(buffer) Err(buffer)
} }
}
} }
struct StringReader<'psess, 'src> { struct Lexer<'psess, 'src> {
psess: &'psess ParseSess, psess: &'psess ParseSess,
/// Initial position, read-only. /// Initial position, read-only.
start_pos: BytePos, start_pos: BytePos,
@ -111,9 +109,14 @@ struct StringReader<'psess, 'src> {
/// Track the `Span` for the leading `'` of the last lifetime. Used for /// Track the `Span` for the leading `'` of the last lifetime. Used for
/// diagnostics to detect possible typo where `"` was meant. /// diagnostics to detect possible typo where `"` was meant.
last_lifetime: Option<Span>, 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> { fn dcx(&self) -> DiagCtxtHandle<'psess> {
self.psess.dcx() 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 /// Returns the next token, paired with a bool indicating if the token was
/// preceded by whitespace. /// 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 preceded_by_whitespace = false;
let mut swallow_next_invalid = 0; let mut swallow_next_invalid = 0;
// Skip trivial (whitespace & comments) tokens // Skip trivial (whitespace & comments) tokens
@ -231,7 +234,8 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
.push(span); .push(span);
token::Ident(sym, IdentIsRaw::No) 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 { rustc_lexer::TokenKind::Literal {
kind: kind @ (LiteralKind::CStr { .. } | LiteralKind::RawCStr { .. }), kind: kind @ (LiteralKind::CStr { .. } | LiteralKind::RawCStr { .. }),
suffix_start: _, suffix_start: _,
@ -252,7 +256,9 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
let prefix_span = self.mk_sp(start, lit_start); let prefix_span = self.mk_sp(start, lit_start);
return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace); 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 } => { rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
let suffix_start = start + BytePos(suffix_start); let suffix_start = start + BytePos(suffix_start);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind); 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() { if prefix_span.at_least_rust_2021() {
let span = self.mk_sp(start, self.pos); 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() { 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. // 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.push('\'');
lifetime_name += lifetime_name_without_tick.as_str(); lifetime_name += lifetime_name_without_tick.as_str();
let sym = Symbol::intern(&lifetime_name); 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_errors::{Applicability, PErr};
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
use super::diagnostics::{ use super::diagnostics::{report_suspicious_mismatch_block, same_indentation_level};
TokenTreeDiagInfo, report_suspicious_mismatch_block, same_indentation_level, use super::{Lexer, UnmatchedDelim};
};
use super::{StringReader, UnmatchedDelim};
use crate::Parser; use crate::Parser;
pub(super) struct TokenTreesReader<'psess, 'src> { impl<'psess, 'src> Lexer<'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)
}
// Lex into a token stream. The `Spacing` in the result is that of the // Lex into a token stream. The `Spacing` in the result is that of the
// opening delimiter. // opening delimiter.
fn lex_token_trees( pub(super) fn lex_token_trees(
&mut self, &mut self,
is_delimited: bool, is_delimited: bool,
) -> (Spacing, TokenStream, Result<(), Vec<PErr<'psess>>>) { ) -> (Spacing, TokenStream, Result<(), Vec<PErr<'psess>>>) {
// Move past the opening delimiter. // Move past the opening delimiter.
let (_, open_spacing) = self.bump(false); let open_spacing = self.bump_minimal();
let mut buf = Vec::new(); let mut buf = Vec::new();
loop { loop {
@ -71,7 +49,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
} }
_ => { _ => {
// Get the next normal token. // 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)); 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> { fn eof_err(&mut self) -> PErr<'psess> {
let msg = "this file contains an unclosed delimiter"; 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 unclosed_delimiter_show_limit = 5;
let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_braces.len()); 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( report_suspicious_mismatch_block(
&mut err, &mut err,
&self.diag_info, &self.diag_info,
self.string_reader.psess.source_map(), self.psess.source_map(),
*delim, *delim,
) )
} }
@ -136,7 +114,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
// Expand to cover the entire delimited token tree. // Expand to cover the entire delimited token tree.
let delim_span = DelimSpan::from_pair(pre_span, self.token.span); 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 { let close_spacing = match self.token.kind {
// Correct delimiter. // Correct delimiter.
@ -160,7 +138,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
} }
// Move past the closing delimiter. // Move past the closing delimiter.
self.bump(false).1 self.bump_minimal()
} }
// Incorrect delimiter. // Incorrect delimiter.
token::CloseDelim(close_delim) => { token::CloseDelim(close_delim) => {
@ -203,7 +181,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
// bar(baz( // bar(baz(
// } // Incorrect delimiter but matches the earlier `{` // } // Incorrect delimiter but matches the earlier `{`
if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) { if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) {
self.bump(false).1 self.bump_minimal()
} else { } else {
// The choice of value here doesn't matter. // The choice of value here doesn't matter.
Spacing::Alone 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. // Move on to the next token, returning the current token and its spacing.
// Will glue adjacent single-char tokens together if `glue` is set. // Will glue adjacent single-char tokens together.
fn bump(&mut self, glue: bool) -> (Token, Spacing) { fn bump(&mut self) -> (Token, Spacing) {
let (this_spacing, next_tok) = loop { 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 { if is_next_tok_preceded_by_whitespace {
break (Spacing::Alone, next_tok); 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; self.token = glued;
} else { } else {
let this_spacing = if next_tok.is_punct() { let this_spacing = if next_tok.is_punct() {
@ -249,6 +227,26 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
(this_tok, this_spacing) (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( fn unclosed_delim_err(
&mut self, &mut self,
tts: TokenStream, tts: TokenStream,
@ -256,7 +254,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
) -> Vec<PErr<'psess>> { ) -> Vec<PErr<'psess>> {
// If there are unclosed delims, see if there are diff markers and if so, point them // If there are unclosed delims, see if there are diff markers and if so, point them
// out instead of complaining about the unclosed delims. // 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![]; let mut diff_errs = vec![];
// Suggest removing a `{` we think appears in an `if`/`while` condition. // 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, // 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). // An unexpected closing delimiter (i.e., there is no matching opening delimiter).
let token_str = token_to_string(&self.token); let token_str = token_to_string(&self.token);
let msg = format!("unexpected closing delimiter: `{token_str}`"); 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( report_suspicious_mismatch_block(&mut err, &self.diag_info, self.psess.source_map(), delim);
&mut err,
&self.diag_info,
self.string_reader.psess.source_map(),
delim,
);
err.span_label(self.token.span, "unexpected closing delimiter"); err.span_label(self.token.span, "unexpected closing delimiter");
err err
} }

View file

@ -4,7 +4,7 @@
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
use rustc_span::{BytePos, Pos, Span}; use rustc_span::{BytePos, Pos, Span};
use super::StringReader; use super::Lexer;
use crate::errors::TokenSubstitution; use crate::errors::TokenSubstitution;
use crate::token::{self, Delimiter}; use crate::token::{self, Delimiter};
@ -338,7 +338,7 @@ const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[
]; ];
pub(super) fn check_for_substitution( pub(super) fn check_for_substitution(
reader: &StringReader<'_, '_>, lexer: &Lexer<'_, '_>,
pos: BytePos, pos: BytePos,
ch: char, ch: char,
count: usize, 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 Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
let msg = format!("substitution character not found for '{ch}'"); 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 // 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( let span = Span::with_root_ctxt(
pos, pos,
pos + Pos::from_usize('“'.len_utf8() + s.len() + '”'.len_utf8()), 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::mut_visit::{self, MutVisitor};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token}; use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::visit::{self, Visitor}; use rustc_ast::visit::{self, Visitor};
use rustc_ast::{ use rustc_ast::{
self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, ExprPrecedence, self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall,
LocalKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt,
RangeSyntax, Stmt, StmtKind, StmtKind,
}; };
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey}; use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey};
@ -458,7 +459,7 @@ impl<'a> Parser<'a> {
.create_err(UnexpectedExpressionInPattern { .create_err(UnexpectedExpressionInPattern {
span, span,
is_bound, is_bound,
expr_precedence: expr.precedence().order(), expr_precedence: expr.precedence(),
}) })
.stash(span, StashKey::ExprInPat) .stash(span, StashKey::ExprInPat)
.unwrap(), .unwrap(),
@ -545,7 +546,8 @@ impl<'a> Parser<'a> {
let expr = match &err.args["expr_precedence"] { let expr = match &err.args["expr_precedence"] {
DiagArgValue::Number(expr_precedence) => { DiagArgValue::Number(expr_precedence) => {
if *expr_precedence if *expr_precedence
<= ExprPrecedence::Binary(BinOpKind::Eq).order() as i32 <= AssocOp::from_ast_binop(BinOpKind::Eq).precedence()
as i32
{ {
format!("({expr})") format!("({expr})")
} else { } else {
@ -568,8 +570,9 @@ impl<'a> Parser<'a> {
} }
Some(guard) => { Some(guard) => {
// Are parentheses required around the old guard? // Are parentheses required around the old guard?
let wrap_guard = guard.precedence().order() let wrap_guard = guard.precedence()
<= ExprPrecedence::Binary(BinOpKind::And).order(); <= AssocOp::from_ast_binop(BinOpKind::And).precedence()
as i8;
err.subdiagnostic( err.subdiagnostic(
UnexpectedExpressionInPatternSugg::UpdateGuard { UnexpectedExpressionInPatternSugg::UpdateGuard {

View file

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

View file

@ -1,5 +1,7 @@
use std::assert_matches::assert_matches; use std::assert_matches::assert_matches;
use rustc_data_structures::fx::FxHashSet;
use super::super::*; use super::super::*;
// Test target self-consistency and JSON encoding/decoding roundtrip. // 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 // 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( fn suggest_specify_actual_length(
&self, &self,
terr: TypeError<'_>, terr: TypeError<'tcx>,
trace: &TypeTrace<'_>, trace: &TypeTrace<'tcx>,
span: Span, span: Span,
) -> Option<TypeErrorAdditionalDiags> { ) -> Option<TypeErrorAdditionalDiags> {
let hir = self.tcx.hir(); let hir = self.tcx.hir();
let TypeError::FixedArraySize(sz) = terr else { let TypeError::ArraySize(sz) = terr else {
return None; return None;
}; };
let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) { 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 if let Some(tykind) = tykind
&& let hir::TyKind::Array(_, length) = tykind && let hir::TyKind::Array(_, length) = tykind
&& let hir::ArrayLen::Body(ct) = length && let hir::ArrayLen::Body(ct) = length
&& let Some((scalar, ty)) = sz.found.try_to_scalar()
&& ty == self.tcx.types.usize
{ {
let span = ct.span(); let span = ct.span();
Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found }) Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength {
span,
length: scalar.to_target_usize(&self.tcx).unwrap(),
})
} else { } else {
None None
} }

View file

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

View file

@ -257,8 +257,6 @@ pub trait Const<I: Interner<Const = Self>>:
+ Relate<I> + Relate<I>
+ Flags + Flags
{ {
fn try_to_target_usize(self, interner: I) -> Option<u64>;
fn new_infer(interner: I, var: ty::InferConst) -> Self; fn new_infer(interner: I, var: ty::InferConst) -> Self;
fn new_var(interner: I, var: ty::ConstVid) -> 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)?; let t = relation.relate(a_t, b_t)?;
match relation.relate(sz_a, sz_b) { match relation.relate(sz_a, sz_b) {
Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)), Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)),
Err(err) => { Err(TypeError::ConstMismatch(_)) => {
// Check whether the lengths are both concrete/known values, Err(TypeError::ArraySize(ExpectedFound::new(sz_a, sz_b)))
// 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(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), 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> { 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")] #[stable(feature = "rust1", since = "1.0.0")]
#[rustc_confusables("push", "put")] #[rustc_confusables("push", "put")]
pub fn insert(mut self, value: V) -> &'a mut V { pub fn insert(self, value: V) -> &'a mut V {
let out_ptr = match self.handle { 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 => { None => {
// SAFETY: There is no tree yet so no reference to it exists. // SAFETY: There is no tree yet so no reference to it exists.
let map = unsafe { self.dormant_map.awaken() }; let map = unsafe { self.dormant_map.reborrow() };
let mut root = NodeRef::new_leaf(self.alloc.clone()); let root = map.root.insert(NodeRef::new_leaf(self.alloc.clone()).forget_type());
let val_ptr = root.borrow_mut().push(self.key, value); // SAFETY: We *just* created the root as a leaf, and we're
map.root = Some(root.forget_type()); // stacking the new handle on the original borrow lifetime.
map.length = 1; unsafe {
val_ptr let mut leaf = root.borrow_mut().cast_to_leaf_unchecked();
leaf.push_with_handle(self.key, value)
} }
Some(handle) => { }
let new_handle = Some(handle) => handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
drop(ins.left); drop(ins.left);
// SAFETY: Pushing a new root node doesn't invalidate // SAFETY: Pushing a new root node doesn't invalidate
// handles to existing nodes. // handles to existing nodes.
let map = unsafe { self.dormant_map.reborrow() }; let map = unsafe { self.dormant_map.reborrow() };
let root = map.root.as_mut().unwrap(); // same as ins.left 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) root.push_internal_level(self.alloc.clone()).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
}
}; };
// Now that we have finished growing the tree using borrowed references, // SAFETY: modifying the length doesn't invalidate handles to existing nodes.
// dereference the pointer to a part of it, that we picked up along the way. unsafe { self.dormant_map.reborrow().length += 1 };
unsafe { &mut *out_ptr }
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> { 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`. /// 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); debug_assert!(self.height == 0);
NodeRef { height: self.height, node: self.node, _marker: PhantomData } 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")] #[stable(feature = "maybe_uninit_debug", since = "1.41.0")]
impl<T> fmt::Debug for MaybeUninit<T> { impl<T> fmt::Debug for MaybeUninit<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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::intrinsics::{exact_div, select_unpredictable, unchecked_sub};
use crate::mem::{self, SizedTypeProperties}; use crate::mem::{self, SizedTypeProperties};
use crate::num::NonZero; 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::simd::{self, Simd};
use crate::ub_checks::assert_unsafe_precondition; use crate::ub_checks::assert_unsafe_precondition;
use crate::{fmt, hint, ptr, slice}; use crate::{fmt, hint, ptr, range, slice};
#[unstable( #[unstable(
feature = "slice_internals", feature = "slice_internals",
@ -4469,6 +4469,12 @@ impl<T> [T] {
/// Returns mutable references to many indices at once, without doing any checks. /// 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`]. /// For a safe alternative see [`get_many_mut`].
/// ///
/// # Safety /// # Safety
@ -4489,30 +4495,49 @@ impl<T> [T] {
/// *b *= 100; /// *b *= 100;
/// } /// }
/// assert_eq!(x, &[10, 2, 400]); /// 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 /// [`get_many_mut`]: slice::get_many_mut
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
#[unstable(feature = "get_many_mut", issue = "104642")] #[unstable(feature = "get_many_mut", issue = "104642")]
#[inline] #[inline]
pub unsafe fn get_many_unchecked_mut<const N: usize>( pub unsafe fn get_many_unchecked_mut<I, const N: usize>(
&mut self, &mut self,
indices: [usize; N], indices: [I; N],
) -> [&mut T; N] { ) -> [&mut I::Output; N]
where
I: GetManyMutIndex + SliceIndex<Self>,
{
// NB: This implementation is written as it is because any variation of // NB: This implementation is written as it is because any variation of
// `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy, // `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 // or generate worse code otherwise. This is also why we need to go
// through a raw pointer here. // through a raw pointer here.
let slice: *mut [T] = self; 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(); let arr_ptr = arr.as_mut_ptr();
// SAFETY: We expect `indices` to contain disjunct values that are // SAFETY: We expect `indices` to contain disjunct values that are
// in bounds of `self`. // in bounds of `self`.
unsafe { unsafe {
for i in 0..N { for i in 0..N {
let idx = *indices.get_unchecked(i); let idx = indices.get_unchecked(i).clone();
*(*arr_ptr).get_unchecked_mut(i) = &mut *slice.get_unchecked_mut(idx); arr_ptr.cast::<&mut I::Output>().add(i).write(&mut *slice.get_unchecked_mut(idx));
} }
arr.assume_init() arr.assume_init()
} }
@ -4520,8 +4545,18 @@ impl<T> [T] {
/// Returns mutable references to many indices at once. /// Returns mutable references to many indices at once.
/// ///
/// Returns an error if any index is out-of-bounds, or if the same index was /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note
/// passed more than once. /// 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 /// # Examples
/// ///
@ -4534,13 +4569,30 @@ impl<T> [T] {
/// *b = 612; /// *b = 612;
/// } /// }
/// assert_eq!(v, &[413, 2, 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")] #[unstable(feature = "get_many_mut", issue = "104642")]
#[inline] #[inline]
pub fn get_many_mut<const N: usize>( pub fn get_many_mut<I, const N: usize>(
&mut self, &mut self,
indices: [usize; N], indices: [I; N],
) -> Result<[&mut T; N], GetManyMutError<N>> { ) -> Result<[&mut I::Output; N], GetManyMutError<N>>
where
I: GetManyMutIndex + SliceIndex<Self>,
{
if !get_many_check_valid(&indices, self.len()) { if !get_many_check_valid(&indices, self.len()) {
return Err(GetManyMutError { _private: () }); 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, ..` /// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
/// comparison operations. /// 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 // NB: The optimizer should inline the loops into a sequence
// of instructions without additional branching. // of instructions without additional branching.
let mut valid = true; let mut valid = true;
for (i, &idx) in indices.iter().enumerate() { for (i, idx) in indices.iter().enumerate() {
valid &= idx < len; valid &= idx.is_in_bounds(len);
for &idx2 in &indices[..i] { for idx2 in &indices[..i] {
valid &= idx != idx2; valid &= !idx.is_overlapping(idx2);
} }
} }
valid 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")] #[unstable(feature = "get_many_mut", issue = "104642")]
// NB: The N here is there to be forward-compatible with adding more details // NB: The N here is there to be forward-compatible with adding more details
// to the error type at a later point // to the error type at a later point
#[derive(Clone, PartialEq, Eq)]
pub struct GetManyMutError<const N: usize> { pub struct GetManyMutError<const N: usize> {
_private: (), _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) 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 "); 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::cmp::Ordering;
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use core::num::NonZero; use core::num::NonZero;
use core::ops::{Range, RangeInclusive};
use core::slice; use core::slice;
#[test] #[test]
@ -2553,6 +2554,14 @@ fn test_get_many_mut_normal_2() {
*a += 10; *a += 10;
*b += 100; *b += 100;
assert_eq!(v, vec![101, 2, 3, 14, 5]); 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] #[test]
@ -2563,12 +2572,23 @@ fn test_get_many_mut_normal_3() {
*b += 100; *b += 100;
*c += 1000; *c += 1000;
assert_eq!(v, vec![11, 2, 1003, 4, 105]); 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] #[test]
fn test_get_many_mut_empty() { fn test_get_many_mut_empty() {
let mut v = vec![1, 2, 3, 4, 5]; 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]); 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()); 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] #[test]
fn test_slice_from_raw_parts_in_const() { fn test_slice_from_raw_parts_in_const() {
static FANCY: i32 = 4; static FANCY: i32 = 4;

View file

@ -511,12 +511,15 @@ fn test_downgrade_basic() {
} }
#[test] #[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() { fn test_downgrade_observe() {
// Taken from the test `test_rwlock_downgrade` from: // Taken from the test `test_rwlock_downgrade` from:
// https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs
const W: usize = 20; 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 // 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. // 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_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.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})")) Cow::Owned(format!("({expr_str})"))
} else { } else {
expr_str expr_str
@ -1003,7 +1003,7 @@ fn report<'tcx>(
Node::Expr(e) => match e.kind { Node::Expr(e) => match e.kind {
ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false), ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false),
ExprKind::Call(..) => (PREC_UNAMBIGUOUS, matches!(expr.kind, ExprKind::Field(..))), ExprKind::Call(..) => (PREC_UNAMBIGUOUS, matches!(expr.kind, ExprKind::Field(..))),
_ => (e.precedence().order(), false), _ => (e.precedence(), false),
}, },
_ => (0, false), _ => (0, false),
}; };
@ -1016,7 +1016,7 @@ fn report<'tcx>(
); );
let sugg = if !snip_is_macro let sugg = if !snip_is_macro
&& (calls_field || expr.precedence().order() < precedence) && (calls_field || expr.precedence() < precedence)
&& !has_enclosing_paren(&snip) && !has_enclosing_paren(&snip)
&& !is_in_tuple && !is_in_tuple
{ {
@ -1071,7 +1071,7 @@ fn report<'tcx>(
let (snip, snip_is_macro) = let (snip, snip_is_macro) =
snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app); snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
let sugg = 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})") format!("{prefix}({snip})")
} else { } else {
format!("{prefix}{snip}") format!("{prefix}{snip}")
@ -1158,7 +1158,7 @@ impl<'tcx> Dereferencing<'tcx> {
}, },
Some(parent) if !parent.span.from_expansion() => { Some(parent) if !parent.span.from_expansion() => {
// Double reference might be needed at this point. // 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. // Parentheses would be needed here, don't lint.
*outer_pat = None; *outer_pat = None;
} else { } else {

View file

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

View file

@ -117,7 +117,7 @@ where
// it's being passed by value. // it's being passed by value.
let scrutinee = peel_hir_expr_refs(scrutinee).0; let scrutinee = peel_hir_expr_refs(scrutinee).0;
let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); 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})") format!("({scrutinee_str})")
} else { } else {
scrutinee_str.into() 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 mut applicability = Applicability::MachineApplicable;
let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability); 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})") format!("-({snip})")
} else { } else {
format!("-{snip}") 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 (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 (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
let parent_expr = get_parent_expr(cx, expr); 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_ty == indexed_ty {
if expr_ref_count > indexed_ref_count { if expr_ref_count > indexed_ref_count {

View file

@ -1,7 +1,7 @@
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use rustc_ast::ExprPrecedence; use rustc_ast::util::parser::AssocOp;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Expr, Node}; use rustc_hir::{Expr, Node};
use rustc_hir_typeck::cast::check_cast; 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) 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})"); 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 //@ known-bug: #130521
#![feature(dyn_compatible_for_dispatch)] #![feature(dyn_compatible_for_dispatch)]
struct Vtable(dyn Cap); struct Vtable(dyn Cap<'static>);
trait Cap<'a> {} 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> { pub struct Foo<'a, 'b, T> {
field1: dyn Bar<'a, 'b>, field1: dyn Bar<'a, 'b>,
//~^ ERROR //~^ ERROR
//~| ERROR
} }
pub trait Bar<'x, 's, U> pub trait Bar<'x, 's, U>

View file

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

View file

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

View file

@ -7,9 +7,6 @@ trait Sub<Rhs=Self> {
} }
type Test = dyn Add + Sub; type Test = dyn Add + Sub;
//~^ ERROR E0393 //~^ ERROR E0225
//~| ERROR E0191
//~| ERROR E0393
//~| ERROR E0225
fn main() { } 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 {}` = 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> = 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 error: aborting due to 1 previous error
--> $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[E0393]: the type parameter `Rhs` must be explicitly specified For more information about this error, try `rustc --explain E0225`.
--> $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`.

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>; 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 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>; 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 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>; 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 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>; 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 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>; type Bal<Rhs> = dyn X<Rhs>;
//~^ ERROR the value of the associated types //~^ 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> {}` = 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> = 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 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>; LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
| -------- ^^^^^^^^ additional non-auto trait | -------- ^^^^^^^^ 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> {}` = 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> = 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 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>; LL | type Baz<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Y<Rhs>;
| -------- ^^^^^^^^ additional non-auto trait | -------- ^^^^^^^^ 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> {}` = 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> = 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 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>; LL | type Bat<Rhs> = dyn Add<Rhs> + Sub<Rhs> + Fine<Rhs>;
| -------- ^^^^^^^^ additional non-auto trait | -------- ^^^^^^^^ 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> {}` = 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> = 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 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>; LL | type Bal<Rhs> = dyn X<Rhs>;
| ^^^^^^ associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified | ^^^^^^ 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 = 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. Some errors have detailed explanations: E0191, E0225.
For more information about an error, try `rustc --explain E0191`. 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 --> $DIR/const-argument-cross-crate-mismatch.rs:6:67
| |
LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); 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 | arguments to this struct are incorrect
| |
@ -16,7 +16,7 @@ error[E0308]: mismatched types
--> $DIR/const-argument-cross-crate-mismatch.rs:8:65 --> $DIR/const-argument-cross-crate-mismatch.rs:8:65
| |
LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); 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 | 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] { LL | fn test<const N: usize, const M: usize>() -> [u8; M] {
| ------- expected `[u8; M]` because of return type | ------- expected `[u8; M]` because of return type
LL | [0; N] LL | [0; N]
| ^^^^^^ expected `M`, found `N` | ^^^^^^ expected an array with a size of M, found one with a size of N
|
= note: expected array `[u8; M]`
found array `[u8; N]`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

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

View file

@ -3,9 +3,6 @@
trait Trait<const N: dyn Trait = bar> { trait Trait<const N: dyn Trait = bar> {
//~^ ERROR: cannot find value `bar` in this scope //~^ ERROR: cannot find value `bar` in this scope
//~| ERROR: cycle detected when computing type of `Trait::N` //~| 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() {} 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 = 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 error: aborting due to 2 previous errors
--> $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[E0038]: the trait `Trait` cannot be made into an object Some errors have detailed explanations: E0391, E0425.
--> $DIR/not_wf_param_in_rpitit.rs:3:13 For more information about an error, try `rustc --explain E0391`.
|
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`.

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/array-literal-len-mismatch.rs:1:26 --> $DIR/array-literal-len-mismatch.rs:1:26
| |
LL | const NUMBERS: [u8; 3] = [10, 20]; 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` | 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 BONG: [i32; (ARR[0] - 41) as usize] = [5];
const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; const BLUB: [i32; (ARR[0] - 40) as usize] = [5];
//~^ ERROR: mismatched types //~^ 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]; const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99];
//~^ ERROR: mismatched types //~^ ERROR: mismatched types
//~| expected an array with a fixed size of 1 element, found one with 2 elements //~| expected an array
fn main() { fn main() {
let _ = VAL; let _ = VAL;

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/const-array-oob-arith.rs:5:45 --> $DIR/const-array-oob-arith.rs:5:45
| |
LL | const BLUB: [i32; (ARR[0] - 40) as usize] = [5]; 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` | help: consider specifying the actual array length: `1`
@ -10,7 +10,7 @@ error[E0308]: mismatched types
--> $DIR/const-array-oob-arith.rs:8:44 --> $DIR/const-array-oob-arith.rs:8:44
| |
LL | const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99]; 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` | 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 --> $DIR/array-len-mismatch.rs:6:26
| |
LL | let wrong: [u8; 3] = [10, 20]; 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` | | help: consider specifying the actual array length: `2`
| expected due to this | expected due to this
@ -11,7 +11,7 @@ error[E0308]: mismatched types
--> $DIR/array-len-mismatch.rs:9:26 --> $DIR/array-len-mismatch.rs:9:26
| |
LL | let wrong: [u8; 3] = returns_arr(); 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` | | help: consider specifying the actual array length: `2`
| expected due to this | expected due to this

View file

@ -8,5 +8,4 @@ fn main()
println!("{:?}",(vfnfer[0] as dyn Fn)(3)); println!("{:?}",(vfnfer[0] as dyn Fn)(3));
//~^ ERROR the precise format of `Fn`-family traits' //~^ ERROR the precise format of `Fn`-family traits'
//~| ERROR missing generics for trait `Fn` //~| 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)); LL | println!("{:?}",(vfnfer[0] as dyn Fn<Args>)(3));
| ++++++ | ++++++
error[E0191]: the value of the associated type `Output` in `FnOnce` must be specified error: aborting due to 2 previous errors
--> $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 3 previous errors Some errors have detailed explanations: E0107, E0658.
Some errors have detailed explanations: E0107, E0191, E0658.
For more information about an error, try `rustc --explain E0107`. 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 pub struct Foo<T = Box<Trait<DefaultFoo>>>; //~ ERROR cycle detected
//~^ ERROR `T` is never used //~^ ERROR `T` is never used
//~| ERROR `Trait` cannot be made into an object
type DefaultFoo = Foo; type DefaultFoo = Foo;
fn main() { fn main() {

View file

@ -5,7 +5,7 @@ LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
| ^^^^^^^^^^ | ^^^^^^^^^^
| |
note: ...which requires expanding type alias `DefaultFoo`... note: ...which requires expanding type alias `DefaultFoo`...
--> $DIR/issue-34373.rs:10:19 --> $DIR/issue-34373.rs:9:19
| |
LL | type DefaultFoo = Foo; 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 = 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 error[E0392]: type parameter `T` is never used
--> $DIR/issue-34373.rs:7:16 --> $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: 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 = 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. Some errors have detailed explanations: E0391, E0392.
For more information about an error, try `rustc --explain E0038`. 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 { pub struct Foo {
i: Box<dyn T<usize, usize, usize, usize, B=usize>>, 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>>, 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 error: aborting due to 1 previous error
--> $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 2 previous errors For more information about this error, try `rustc --explain E0107`.
Some errors have detailed explanations: E0107, E0191.
For more information about an error, try `rustc --explain E0107`.

View file

@ -3,7 +3,4 @@ trait Trait {}
pub fn main() { pub fn main() {
let x: Vec<dyn Trait + Sized> = Vec::new(); let x: Vec<dyn Trait + Sized> = Vec::new();
//~^ ERROR only auto traits can be used as additional traits in a trait object //~^ 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 {}` = 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> = 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 error: aborting due to 1 previous error
--> $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[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time For more information about this error, try `rustc --explain E0225`.
--> $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`.

View file

@ -7,5 +7,4 @@ fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
fn main() { fn main() {
size_of_copy::<dyn Misc + Copy>(); size_of_copy::<dyn Misc + Copy>();
//~^ ERROR only auto traits can be used as additional traits in a trait object //~^ 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 {}` = 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> = 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 error: aborting due to 1 previous error
--> $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 2 previous errors For more information about this error, try `rustc --explain E0225`.
Some errors have detailed explanations: E0225, E0277.
For more information about an error, try `rustc --explain E0225`.

View file

@ -1,11 +1,6 @@
trait Trait<const N: Trait = bar> { trait Trait<const N: Trait = bar> {
//~^ ERROR cannot find value `bar` in this scope //~^ ERROR cannot find value `bar` in this scope
//~| ERROR cycle detected when computing type of `Trait::N` //~| 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 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 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 { 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 expected value, found builtin type `u32`
//~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions //~| 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 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 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 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 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 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> { LL | trait Trait<const N: Trait = bar> {
| - first use of `N` | - first use of `N`
@ -14,13 +14,13 @@ LL | trait Trait<const N: Trait = bar> {
| ^^^ not found in this scope | ^^^ not found in this scope
error[E0423]: expected value, found builtin type `u32` 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 { LL | fn fnc<const N: Trait = u32>(&self) -> Trait {
| ^^^ not a value | ^^^ not a value
error[E0425]: cannot find value `bar` in this scope 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 LL | bar
| ^^^ not found in this scope | ^^^ 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 = 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 warning: trait objects without an explicit `dyn` are deprecated
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21 --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44
|
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
| |
LL | fn fnc<const N: Trait = u32>(&self) -> Trait { 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 { LL | fn fnc<const N: Trait = u32>(&self) -> dyn Trait {
| +++ | +++
warning: trait objects without an explicit `dyn` are deprecated 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:1:22 --> $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! = 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: 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` help: if this is a dyn-compatible trait, use `dyn`
| |
LL | trait Trait<const N: dyn Trait = bar> { LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
| +++ | +++
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
error: associated item referring to unboxed trait object for its own 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> { LL | trait Trait<const N: Trait = bar> {
| ----- in this trait | ----- 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 { LL | fn fnc<const N: Trait = u32>(&self) -> Self {
| ~~~~ | ~~~~
warning: trait objects without an explicit `dyn` are deprecated error: aborting due to 7 previous errors; 3 warnings emitted
--> $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[E0038]: the trait `Trait` cannot be made into an object Some errors have detailed explanations: E0391, E0403, E0423, E0425.
--> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:11:21 For more information about an error, try `rustc --explain E0391`.
|
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`.