diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 5b5ffe11379a..ecb6ef5a2a64 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -39,7 +39,9 @@
use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter};
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
-pub use crate::util::parser::ExprPrecedence;
+use crate::util::parser::{
+ AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_RANGE, PREC_UNAMBIGUOUS,
+};
/// A "Label" is an identifier of some point in sources,
/// e.g. in the following code:
@@ -1314,53 +1316,71 @@ pub fn to_ty(&self) -> Option
> {
Some(P(Ty { kind, id: self.id, span: self.span, tokens: None }))
}
- pub fn precedence(&self) -> ExprPrecedence {
+ pub fn precedence(&self) -> i8 {
match self.kind {
- ExprKind::Array(_) => ExprPrecedence::Array,
- ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
- ExprKind::Call(..) => ExprPrecedence::Call,
- ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
- ExprKind::Tup(_) => ExprPrecedence::Tup,
- ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
- ExprKind::Unary(..) => ExprPrecedence::Unary,
- ExprKind::Lit(_) | ExprKind::IncludedBytes(..) => ExprPrecedence::Lit,
- ExprKind::Cast(..) => ExprPrecedence::Cast,
- ExprKind::Let(..) => ExprPrecedence::Let,
- ExprKind::If(..) => ExprPrecedence::If,
- ExprKind::While(..) => ExprPrecedence::While,
- ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop,
- ExprKind::Loop(..) => ExprPrecedence::Loop,
- ExprKind::Match(_, _, MatchKind::Prefix) => ExprPrecedence::Match,
- ExprKind::Match(_, _, MatchKind::Postfix) => ExprPrecedence::PostfixMatch,
- ExprKind::Closure(..) => ExprPrecedence::Closure,
- ExprKind::Block(..) => ExprPrecedence::Block,
- ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
- ExprKind::Gen(..) => ExprPrecedence::Gen,
- ExprKind::Await(..) => ExprPrecedence::Await,
- ExprKind::Assign(..) => ExprPrecedence::Assign,
- ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
- ExprKind::Field(..) => ExprPrecedence::Field,
- ExprKind::Index(..) => ExprPrecedence::Index,
- ExprKind::Range(..) => ExprPrecedence::Range,
- ExprKind::Underscore => ExprPrecedence::Path,
- ExprKind::Path(..) => ExprPrecedence::Path,
- ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
- ExprKind::Break(..) => ExprPrecedence::Break,
- ExprKind::Continue(..) => ExprPrecedence::Continue,
- ExprKind::Ret(..) => ExprPrecedence::Ret,
- ExprKind::Struct(..) => ExprPrecedence::Struct,
- ExprKind::Repeat(..) => ExprPrecedence::Repeat,
- ExprKind::Paren(..) => ExprPrecedence::Paren,
- ExprKind::Try(..) => ExprPrecedence::Try,
- ExprKind::Yield(..) => ExprPrecedence::Yield,
- ExprKind::Yeet(..) => ExprPrecedence::Yeet,
- ExprKind::Become(..) => ExprPrecedence::Become,
- ExprKind::InlineAsm(..)
- | ExprKind::Type(..)
- | ExprKind::OffsetOf(..)
+ ExprKind::Closure(..) => PREC_CLOSURE,
+
+ ExprKind::Break(..)
+ | ExprKind::Continue(..)
+ | ExprKind::Ret(..)
+ | ExprKind::Yield(..)
+ | ExprKind::Yeet(..)
+ | ExprKind::Become(..) => PREC_JUMP,
+
+ // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
+ // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
+ // ensures that `pprust` will add parentheses in the right places to get the desired
+ // parse.
+ ExprKind::Range(..) => PREC_RANGE,
+
+ // Binop-like expr kinds, handled by `AssocOp`.
+ ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
+ ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
+
+ ExprKind::Assign(..) |
+ ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
+
+ // Unary, prefix
+ ExprKind::AddrOf(..)
+ // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
+ // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
+ // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
+ // but we need to print `(let _ = a) < b` as-is with parens.
+ | ExprKind::Let(..)
+ | ExprKind::Unary(..) => PREC_PREFIX,
+
+ // Never need parens
+ ExprKind::Array(_)
+ | ExprKind::Await(..)
+ | ExprKind::Block(..)
+ | ExprKind::Call(..)
+ | ExprKind::ConstBlock(_)
+ | ExprKind::Field(..)
+ | ExprKind::ForLoop { .. }
| ExprKind::FormatArgs(..)
- | ExprKind::MacCall(..) => ExprPrecedence::Mac,
- ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err,
+ | ExprKind::Gen(..)
+ | ExprKind::If(..)
+ | ExprKind::IncludedBytes(..)
+ | ExprKind::Index(..)
+ | ExprKind::InlineAsm(..)
+ | ExprKind::Lit(_)
+ | ExprKind::Loop(..)
+ | ExprKind::MacCall(..)
+ | ExprKind::Match(..)
+ | ExprKind::MethodCall(..)
+ | ExprKind::OffsetOf(..)
+ | ExprKind::Paren(..)
+ | ExprKind::Path(..)
+ | ExprKind::Repeat(..)
+ | ExprKind::Struct(..)
+ | ExprKind::Try(..)
+ | ExprKind::TryBlock(..)
+ | ExprKind::Tup(_)
+ | ExprKind::Type(..)
+ | ExprKind::Underscore
+ | ExprKind::While(..)
+ | ExprKind::Err(_)
+ | ExprKind::Dummy => PREC_UNAMBIGUOUS,
}
}
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index d8dad4550c0c..ed9265d51598 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -237,121 +237,6 @@ pub fn can_continue_expr_unambiguously(&self) -> bool {
pub const PREC_UNAMBIGUOUS: i8 = 60;
pub const PREC_FORCE_PAREN: i8 = 100;
-#[derive(Debug, Clone, Copy)]
-pub enum ExprPrecedence {
- Closure,
- Break,
- Continue,
- Ret,
- Yield,
- Yeet,
- Become,
-
- Range,
-
- Binary(BinOpKind),
-
- Cast,
-
- Assign,
- AssignOp,
-
- AddrOf,
- Let,
- Unary,
-
- Call,
- MethodCall,
- Field,
- Index,
- Try,
- Mac,
-
- Array,
- Repeat,
- Tup,
- Lit,
- Path,
- Paren,
- If,
- While,
- ForLoop,
- Loop,
- Match,
- PostfixMatch,
- ConstBlock,
- Block,
- TryBlock,
- Struct,
- Gen,
- Await,
- Err,
-}
-
-impl ExprPrecedence {
- pub fn order(self) -> i8 {
- match self {
- ExprPrecedence::Closure => PREC_CLOSURE,
-
- ExprPrecedence::Break
- | ExprPrecedence::Continue
- | ExprPrecedence::Ret
- | ExprPrecedence::Yield
- | ExprPrecedence::Yeet
- | ExprPrecedence::Become => PREC_JUMP,
-
- // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
- // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
- // ensures that `pprust` will add parentheses in the right places to get the desired
- // parse.
- ExprPrecedence::Range => PREC_RANGE,
-
- // Binop-like expr kinds, handled by `AssocOp`.
- ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
- ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
-
- ExprPrecedence::Assign |
- ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
-
- // Unary, prefix
- ExprPrecedence::AddrOf
- // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
- // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
- // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
- // but we need to print `(let _ = a) < b` as-is with parens.
- | ExprPrecedence::Let
- | ExprPrecedence::Unary => PREC_PREFIX,
-
- // Never need parens
- ExprPrecedence::Array
- | ExprPrecedence::Await
- | ExprPrecedence::Block
- | ExprPrecedence::Call
- | ExprPrecedence::ConstBlock
- | ExprPrecedence::Field
- | ExprPrecedence::ForLoop
- | ExprPrecedence::Gen
- | ExprPrecedence::If
- | ExprPrecedence::Index
- | ExprPrecedence::Lit
- | ExprPrecedence::Loop
- | ExprPrecedence::Mac
- | ExprPrecedence::Match
- | ExprPrecedence::MethodCall
- | ExprPrecedence::Paren
- | ExprPrecedence::Path
- | ExprPrecedence::PostfixMatch
- | ExprPrecedence::Repeat
- | ExprPrecedence::Struct
- | ExprPrecedence::Try
- | ExprPrecedence::TryBlock
- | ExprPrecedence::Tup
- | ExprPrecedence::While
- | ExprPrecedence::Err => PREC_UNAMBIGUOUS,
- }
- }
-}
-
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
pub fn prec_let_scrutinee_needs_par() -> usize {
AssocOp::LAnd.precedence()
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 893bfaf8f712..04ec135c4289 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -59,7 +59,7 @@ fn print_call_post(&mut self, args: &[P]) {
}
fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) {
- self.print_expr_cond_paren(expr, expr.precedence().order() < prec, fixup);
+ self.print_expr_cond_paren(expr, expr.precedence() < prec, fixup);
}
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
@@ -615,7 +615,7 @@ pub(super) fn print_expr_outer_attr_style(
expr,
// Parenthesize if required by precedence, or in the
// case of `break 'inner: loop { break 'inner 1 } + 1`
- expr.precedence().order() < parser::PREC_JUMP
+ expr.precedence() < parser::PREC_JUMP
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
fixup.subsequent_subexpression(),
);
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
index 50fd12a4e8b6..6f5382ce61d3 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
@@ -191,6 +191,6 @@ pub(crate) fn would_cause_statement_boundary(self, expr: &Expr) -> bool {
/// "let chain".
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
- || parser::needs_par_as_let_scrutinee(expr.precedence().order())
+ || parser::needs_par_as_let_scrutinee(expr.precedence())
}
}
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index fc889c12cb92..12dec75e65cf 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,7 +1,7 @@
use std::fmt;
use rustc_abi::ExternAbi;
-use rustc_ast::util::parser::ExprPrecedence;
+use rustc_ast::util::parser::{AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_UNAMBIGUOUS};
use rustc_ast::{
self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label,
LitKind, TraitObjectSyntax, UintTy,
@@ -1708,41 +1708,54 @@ pub struct Expr<'hir> {
}
impl Expr<'_> {
- pub fn precedence(&self) -> ExprPrecedence {
+ pub fn precedence(&self) -> i8 {
match self.kind {
- ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
- ExprKind::Array(_) => ExprPrecedence::Array,
- ExprKind::Call(..) => ExprPrecedence::Call,
- ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
- ExprKind::Tup(_) => ExprPrecedence::Tup,
- ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
- ExprKind::Unary(..) => ExprPrecedence::Unary,
- ExprKind::Lit(_) => ExprPrecedence::Lit,
- ExprKind::Cast(..) => ExprPrecedence::Cast,
+ ExprKind::Closure { .. } => PREC_CLOSURE,
+
+ ExprKind::Break(..)
+ | ExprKind::Continue(..)
+ | ExprKind::Ret(..)
+ | ExprKind::Yield(..)
+ | ExprKind::Become(..) => PREC_JUMP,
+
+ // Binop-like expr kinds, handled by `AssocOp`.
+ ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
+ ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
+
+ ExprKind::Assign(..) |
+ ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
+
+ // Unary, prefix
+ ExprKind::AddrOf(..)
+ // Here `let pats = expr` has `let pats =` as a "unary" prefix of `expr`.
+ // However, this is not exactly right. When `let _ = a` is the LHS of a binop we
+ // need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
+ // but we need to print `(let _ = a) < b` as-is with parens.
+ | ExprKind::Let(..)
+ | ExprKind::Unary(..) => PREC_PREFIX,
+
+ // Never need parens
+ ExprKind::Array(_)
+ | ExprKind::Block(..)
+ | ExprKind::Call(..)
+ | ExprKind::ConstBlock(_)
+ | ExprKind::Field(..)
+ | ExprKind::If(..)
+ | ExprKind::Index(..)
+ | ExprKind::InlineAsm(..)
+ | ExprKind::Lit(_)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ | ExprKind::MethodCall(..)
+ | ExprKind::OffsetOf(..)
+ | ExprKind::Path(..)
+ | ExprKind::Repeat(..)
+ | ExprKind::Struct(..)
+ | ExprKind::Tup(_)
+ | ExprKind::Type(..)
+ | ExprKind::Err(_) => PREC_UNAMBIGUOUS,
+
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
- ExprKind::If(..) => ExprPrecedence::If,
- ExprKind::Let(..) => ExprPrecedence::Let,
- ExprKind::Loop(..) => ExprPrecedence::Loop,
- ExprKind::Match(..) => ExprPrecedence::Match,
- ExprKind::Closure { .. } => ExprPrecedence::Closure,
- ExprKind::Block(..) => ExprPrecedence::Block,
- ExprKind::Assign(..) => ExprPrecedence::Assign,
- ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
- ExprKind::Field(..) => ExprPrecedence::Field,
- ExprKind::Index(..) => ExprPrecedence::Index,
- ExprKind::Path(..) => ExprPrecedence::Path,
- ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
- ExprKind::Break(..) => ExprPrecedence::Break,
- ExprKind::Continue(..) => ExprPrecedence::Continue,
- ExprKind::Ret(..) => ExprPrecedence::Ret,
- ExprKind::Become(..) => ExprPrecedence::Become,
- ExprKind::Struct(..) => ExprPrecedence::Struct,
- ExprKind::Repeat(..) => ExprPrecedence::Repeat,
- ExprKind::Yield(..) => ExprPrecedence::Yield,
- ExprKind::Type(..) | ExprKind::InlineAsm(..) | ExprKind::OffsetOf(..) => {
- ExprPrecedence::Mac
- }
- ExprKind::Err(_) => ExprPrecedence::Err,
}
}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 5e27ace4cbe4..f6e227377b9b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -8,7 +8,8 @@
use rustc_middle::span_bug;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::{
- self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, Upcast,
+ self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
+ TypeVisitableExt, Upcast,
};
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
@@ -92,11 +93,20 @@ pub(super) fn lower_trait_object_ty(
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
+
+ // We don't support >1 principal
if regular_traits.len() > 1 {
- let _ = self.report_trait_object_addition_traits_error(®ular_traits);
- } else if regular_traits.is_empty() && auto_traits.is_empty() {
- let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
- return Ty::new_error(tcx, reported);
+ let guar = self.report_trait_object_addition_traits_error(®ular_traits);
+ return Ty::new_error(tcx, guar);
+ }
+ // We don't support empty trait objects.
+ if regular_traits.is_empty() && auto_traits.is_empty() {
+ let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
+ return Ty::new_error(tcx, guar);
+ }
+ // Don't create a dyn trait if we have errors in the principal.
+ if let Err(guar) = trait_bounds.error_reported() {
+ return Ty::new_error(tcx, guar);
}
// Check that there are no gross dyn-compatibility violations;
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 1dedf11f7ad1..64c6969d4b9c 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1011,7 +1011,7 @@ fn print_call_post(&mut self, args: &[hir::Expr<'_>]) {
}
fn print_expr_maybe_paren(&mut self, expr: &hir::Expr<'_>, prec: i8) {
- self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
+ self.print_expr_cond_paren(expr, expr.precedence() < prec)
}
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
@@ -1045,7 +1045,7 @@ fn print_let(&mut self, pat: &hir::Pat<'_>, ty: Option<&hir::Ty<'_>>, init: &hir
}
self.space();
self.word_space("=");
- let npals = || parser::needs_par_as_let_scrutinee(init.precedence().order());
+ let npals = || parser::needs_par_as_let_scrutinee(init.precedence());
self.print_expr_cond_paren(init, Self::cond_needs_par(init) || npals())
}
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index e6e0f62b54d2..a92482e6a0e3 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -606,7 +606,7 @@ fn suggest_call_as_method(
};
if let Ok(rest_snippet) = rest_snippet {
- let sugg = if callee_expr.precedence().order() >= PREC_UNAMBIGUOUS {
+ let sugg = if callee_expr.precedence() >= PREC_UNAMBIGUOUS {
vec![
(up_to_rcvr_span, "".to_string()),
(rest_span, format!(".{}({rest_snippet}", segment.ident)),
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 483a8d1d9a9d..0c3f21d540dc 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -1107,7 +1107,7 @@ fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
}
fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
- let expr_prec = self.expr.precedence().order();
+ let expr_prec = self.expr.precedence();
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_UNAMBIGUOUS;
let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 707d98d8311b..b493a61b9f44 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -2,7 +2,7 @@
use core::iter;
use hir::def_id::LocalDefId;
-use rustc_ast::util::parser::{ExprPrecedence, PREC_UNAMBIGUOUS};
+use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
use rustc_data_structures::packed::Pu128;
use rustc_errors::{Applicability, Diag, MultiSpan};
use rustc_hir as hir;
@@ -398,7 +398,7 @@ pub(crate) fn suggest_deref_ref_or_into(
// so we remove the user's `clone` call.
{
vec![(receiver_method.ident.span, conversion_method.name.to_string())]
- } else if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
+ } else if expr.precedence() < PREC_UNAMBIGUOUS {
vec![
(expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
@@ -1376,7 +1376,7 @@ pub(crate) fn suggest_into(
{
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
- let mut sugg = if expr.precedence().order() >= PREC_UNAMBIGUOUS {
+ let mut sugg = if expr.precedence() >= PREC_UNAMBIGUOUS {
vec![(span.shrink_to_hi(), ".into()".to_owned())]
} else {
vec![
@@ -3000,7 +3000,7 @@ pub(crate) fn suggest_cast(
"change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`",
);
- let close_paren = if expr.precedence().order() < PREC_UNAMBIGUOUS {
+ let close_paren = if expr.precedence() < PREC_UNAMBIGUOUS {
sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
")"
} else {
@@ -3025,7 +3025,7 @@ pub(crate) fn suggest_cast(
let len = src.trim_end_matches(&checked_ty.to_string()).len();
expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
},
- if expr.precedence().order() < PREC_UNAMBIGUOUS {
+ if expr.precedence() < PREC_UNAMBIGUOUS {
// Readd `)`
format!("{expected_ty})")
} else {
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index bcb103957bad..b584e7afd98f 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -566,19 +566,19 @@ fn invalid_ident(&mut self) -> TokenKind {
fn c_or_byte_string(
&mut self,
- mk_kind: impl FnOnce(bool) -> LiteralKind,
- mk_kind_raw: impl FnOnce(Option) -> LiteralKind,
+ mk_kind: fn(bool) -> LiteralKind,
+ mk_kind_raw: fn(Option) -> LiteralKind,
single_quoted: Option LiteralKind>,
) -> TokenKind {
match (self.first(), self.second(), single_quoted) {
- ('\'', _, Some(mk_kind)) => {
+ ('\'', _, Some(single_quoted)) => {
self.bump();
let terminated = self.single_quoted_string();
let suffix_start = self.pos_within_token();
if terminated {
self.eat_literal_suffix();
}
- let kind = mk_kind(terminated);
+ let kind = single_quoted(terminated);
Literal { kind, suffix_start }
}
('"', _, _) => {
diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs
index 556bbf1f5182..db7225fc2a81 100644
--- a/compiler/rustc_lexer/src/tests.rs
+++ b/compiler/rustc_lexer/src/tests.rs
@@ -77,63 +77,53 @@ fn test_too_many_hashes() {
check_raw_str(&s2, Err(RawStrError::TooManyDelimiters { found: u32::from(max_count) + 1 }));
}
+// https://github.com/rust-lang/rust/issues/70528
#[test]
fn test_valid_shebang() {
- // https://github.com/rust-lang/rust/issues/70528
- let input = "#!/usr/bin/rustrun\nlet x = 5;";
- assert_eq!(strip_shebang(input), Some(18));
-}
+ let input = "#!/bin/bash";
+ assert_eq!(strip_shebang(input), Some(input.len()));
-#[test]
-fn test_invalid_shebang_valid_rust_syntax() {
- // https://github.com/rust-lang/rust/issues/70528
- let input = "#! [bad_attribute]";
+ let input = "#![attribute]";
+ assert_eq!(strip_shebang(input), None);
+
+ let input = "#! /bin/bash";
+ assert_eq!(strip_shebang(input), Some(input.len()));
+
+ let input = "#! [attribute]";
+ assert_eq!(strip_shebang(input), None);
+
+ let input = "#! /* blah */ /bin/bash";
+ assert_eq!(strip_shebang(input), Some(input.len()));
+
+ let input = "#! /* blah */ [attribute]";
+ assert_eq!(strip_shebang(input), None);
+
+ let input = "#! // blah\n/bin/bash";
+ assert_eq!(strip_shebang(input), Some(10)); // strip up to the newline
+
+ let input = "#! // blah\n[attribute]";
+ assert_eq!(strip_shebang(input), None);
+
+ let input = "#! /* blah\nblah\nblah */ /bin/bash";
+ assert_eq!(strip_shebang(input), Some(10));
+
+ let input = "#! /* blah\nblah\nblah */ [attribute]";
+ assert_eq!(strip_shebang(input), None);
+
+ let input = "#!\n/bin/sh";
+ assert_eq!(strip_shebang(input), Some(2));
+
+ let input = "#!\n[attribute]";
assert_eq!(strip_shebang(input), None);
-}
-#[test]
-fn test_shebang_second_line() {
// Because shebangs are interpreted by the kernel, they must be on the first line
let input = "\n#!/bin/bash";
assert_eq!(strip_shebang(input), None);
-}
-#[test]
-fn test_shebang_space() {
- let input = "#! /bin/bash";
- assert_eq!(strip_shebang(input), Some(input.len()));
-}
-
-#[test]
-fn test_shebang_empty_shebang() {
- let input = "#! \n[attribute(foo)]";
+ let input = "\n#![attribute]";
assert_eq!(strip_shebang(input), None);
}
-#[test]
-fn test_invalid_shebang_comment() {
- let input = "#!//bin/ami/a/comment\n[";
- assert_eq!(strip_shebang(input), None)
-}
-
-#[test]
-fn test_invalid_shebang_another_comment() {
- let input = "#!/*bin/ami/a/comment*/\n[attribute";
- assert_eq!(strip_shebang(input), None)
-}
-
-#[test]
-fn test_shebang_valid_rust_after() {
- let input = "#!/*bin/ami/a/comment*/\npub fn main() {}";
- assert_eq!(strip_shebang(input), Some(23))
-}
-
-#[test]
-fn test_shebang_followed_by_attrib() {
- let input = "#!/bin/rust-scripts\n#![allow_unused(true)]";
- assert_eq!(strip_shebang(input), Some(19));
-}
-
fn check_lexing(src: &str, expect: Expect) {
let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect();
expect.assert_eq(&actual)
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index c4d86c3210e8..d27205e26abb 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -151,10 +151,6 @@ pub fn new_error_with_message>(
}
impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> {
- fn try_to_target_usize(self, interner: TyCtxt<'tcx>) -> Option {
- self.try_to_target_usize(interner)
- }
-
fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self {
Const::new_infer(tcx, infer)
}
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 43d243b0584e..4a82af325595 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -58,12 +58,9 @@ fn report_maybe_different(expected: &str, found: &str) -> String {
pluralize!(values.found)
)
.into(),
- TypeError::FixedArraySize(values) => format!(
- "expected an array with a fixed size of {} element{}, found one with {} element{}",
- values.expected,
- pluralize!(values.expected),
- values.found,
- pluralize!(values.found)
+ TypeError::ArraySize(values) => format!(
+ "expected an array with a size of {}, found one with a size of {}",
+ values.expected, values.found,
)
.into(),
TypeError::ArgCount => "incorrect number of function parameters".into(),
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index b06687490d26..afdec7a86d44 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -3,7 +3,6 @@
pub use rustc_type_ir::relate::*;
use crate::ty::error::{ExpectedFound, TypeError};
-use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
use crate::ty::{self as ty, Ty, TyCtxt};
pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult, T>;
@@ -86,10 +85,7 @@ fn relate>>(
// in `a`.
let mut a_v: Vec<_> = a.into_iter().collect();
let mut b_v: Vec<_> = b.into_iter().collect();
- // `skip_binder` here is okay because `stable_cmp` doesn't look at binders
- a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
a_v.dedup();
- b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
b_v.dedup();
if a_v.len() != b_v.len() {
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index 5ebb343f4e19..11cf8c3e8984 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -1,6 +1,7 @@
//! Random access inspection of the results of a dataflow analysis.
use std::cmp::Ordering;
+use std::ops::{Deref, DerefMut};
#[cfg(debug_assertions)]
use rustc_index::bit_set::BitSet;
@@ -8,18 +9,63 @@
use super::{Analysis, Direction, Effect, EffectIndex, Results};
-/// Allows random access inspection of the results of a dataflow analysis.
+/// Some `ResultsCursor`s want to own a `Results`, and some want to borrow a `Results`, either
+/// mutable or immutably. This type allows all of the above. It's similar to `Cow`.
+pub enum ResultsHandle<'a, 'tcx, A>
+where
+ A: Analysis<'tcx>,
+{
+ Borrowed(&'a Results<'tcx, A>),
+ BorrowedMut(&'a mut Results<'tcx, A>),
+ Owned(Results<'tcx, A>),
+}
+
+impl<'tcx, A> Deref for ResultsHandle<'_, 'tcx, A>
+where
+ A: Analysis<'tcx>,
+{
+ type Target = Results<'tcx, A>;
+
+ fn deref(&self) -> &Results<'tcx, A> {
+ match self {
+ ResultsHandle::Borrowed(borrowed) => borrowed,
+ ResultsHandle::BorrowedMut(borrowed) => borrowed,
+ ResultsHandle::Owned(owned) => owned,
+ }
+ }
+}
+
+impl<'tcx, A> DerefMut for ResultsHandle<'_, 'tcx, A>
+where
+ A: Analysis<'tcx>,
+{
+ fn deref_mut(&mut self) -> &mut Results<'tcx, A> {
+ match self {
+ ResultsHandle::Borrowed(_borrowed) => {
+ panic!("tried to deref_mut a `ResultsHandle::Borrowed")
+ }
+ ResultsHandle::BorrowedMut(borrowed) => borrowed,
+ ResultsHandle::Owned(owned) => owned,
+ }
+ }
+}
+
+/// Allows random access inspection of the results of a dataflow analysis. Use this when you want
+/// to inspect domain values only in certain locations; use `ResultsVisitor` if you want to inspect
+/// domain values in many or all locations.
///
-/// This cursor only has linear performance within a basic block when its statements are visited in
-/// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are
-/// visited in *reverse* order—performance will be quadratic in the number of statements in the
-/// block. The order in which basic blocks are inspected has no impact on performance.
+/// Because `Results` only has domain values for the entry of each basic block, these inspections
+/// involve some amount of domain value recomputations. This cursor only has linear performance
+/// within a basic block when its statements are visited in the same order as the `DIRECTION` of
+/// the analysis. In the worst case—when statements are visited in *reverse* order—performance will
+/// be quadratic in the number of statements in the block. The order in which basic blocks are
+/// inspected has no impact on performance.
pub struct ResultsCursor<'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
body: &'mir mir::Body<'tcx>,
- results: Results<'tcx, A>,
+ results: ResultsHandle<'mir, 'tcx, A>,
state: A::Domain,
pos: CursorPosition,
@@ -47,13 +93,8 @@ pub fn body(&self) -> &'mir mir::Body<'tcx> {
self.body
}
- /// Unwraps this cursor, returning the underlying `Results`.
- pub fn into_results(self) -> Results<'tcx, A> {
- self.results
- }
-
/// Returns a new cursor that can inspect `results`.
- pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self {
+ pub fn new(body: &'mir mir::Body<'tcx>, results: ResultsHandle<'mir, 'tcx, A>) -> Self {
let bottom_value = results.analysis.bottom_value(body);
ResultsCursor {
body,
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 9a5cf9d4e84f..566a6b09b2b1 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -9,10 +9,21 @@
pub trait Direction {
const IS_FORWARD: bool;
-
const IS_BACKWARD: bool = !Self::IS_FORWARD;
- /// Applies all effects between the given `EffectIndex`s.
+ /// Called by `iterate_to_fixpoint` during initial analysis computation.
+ fn apply_effects_in_block<'mir, 'tcx, A>(
+ analysis: &mut A,
+ body: &mir::Body<'tcx>,
+ state: &mut A::Domain,
+ block: BasicBlock,
+ block_data: &'mir mir::BasicBlockData<'tcx>,
+ propagate: impl FnMut(BasicBlock, &A::Domain),
+ ) where
+ A: Analysis<'tcx>;
+
+ /// Called by `ResultsCursor` to recompute the domain value for a location
+ /// in a basic block. Applies all effects between the given `EffectIndex`s.
///
/// `effects.start()` must precede or equal `effects.end()` in this direction.
fn apply_effects_in_range<'tcx, A>(
@@ -24,15 +35,9 @@ fn apply_effects_in_range<'tcx, A>(
) where
A: Analysis<'tcx>;
- fn apply_effects_in_block<'mir, 'tcx, A>(
- analysis: &mut A,
- state: &mut A::Domain,
- block: BasicBlock,
- block_data: &'mir mir::BasicBlockData<'tcx>,
- ) -> TerminatorEdges<'mir, 'tcx>
- where
- A: Analysis<'tcx>;
-
+ /// Called by `ResultsVisitor` to recompute the analysis domain values for
+ /// all locations in a basic block (starting from the entry value stored
+ /// in `Results`) and to visit them with `vis`.
fn visit_results_in_block<'mir, 'tcx, A>(
state: &mut A::Domain,
block: BasicBlock,
@@ -41,16 +46,6 @@ fn visit_results_in_block<'mir, 'tcx, A>(
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
) where
A: Analysis<'tcx>;
-
- fn join_state_into_successors_of<'tcx, A>(
- analysis: &mut A,
- body: &mir::Body<'tcx>,
- exit_state: &mut A::Domain,
- block: BasicBlock,
- edges: TerminatorEdges<'_, 'tcx>,
- propagate: impl FnMut(BasicBlock, &A::Domain),
- ) where
- A: Analysis<'tcx>;
}
/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement).
@@ -61,23 +56,84 @@ impl Direction for Backward {
fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A,
+ body: &mir::Body<'tcx>,
state: &mut A::Domain,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
- ) -> TerminatorEdges<'mir, 'tcx>
- where
+ mut propagate: impl FnMut(BasicBlock, &A::Domain),
+ ) where
A: Analysis<'tcx>,
{
let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location);
- let edges = analysis.apply_terminator_effect(state, terminator, location);
+ analysis.apply_terminator_effect(state, terminator, location);
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
let location = Location { block, statement_index };
analysis.apply_before_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location);
}
- edges
+
+ let exit_state = state;
+ for pred in body.basic_blocks.predecessors()[block].iter().copied() {
+ match body[pred].terminator().kind {
+ // Apply terminator-specific edge effects.
+ //
+ // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
+ mir::TerminatorKind::Call { destination, target: Some(dest), .. }
+ if dest == block =>
+ {
+ let mut tmp = exit_state.clone();
+ analysis.apply_call_return_effect(
+ &mut tmp,
+ pred,
+ CallReturnPlaces::Call(destination),
+ );
+ propagate(pred, &tmp);
+ }
+
+ mir::TerminatorKind::InlineAsm { ref targets, ref operands, .. }
+ if targets.contains(&block) =>
+ {
+ let mut tmp = exit_state.clone();
+ analysis.apply_call_return_effect(
+ &mut tmp,
+ pred,
+ CallReturnPlaces::InlineAsm(operands),
+ );
+ propagate(pred, &tmp);
+ }
+
+ mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == block => {
+ let mut tmp = exit_state.clone();
+ analysis.apply_call_return_effect(
+ &mut tmp,
+ resume,
+ CallReturnPlaces::Yield(resume_arg),
+ );
+ propagate(pred, &tmp);
+ }
+
+ mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
+ let mut applier = BackwardSwitchIntEdgeEffectsApplier {
+ body,
+ pred,
+ exit_state,
+ block,
+ propagate: &mut propagate,
+ effects_applied: false,
+ };
+
+ analysis.apply_switch_int_edge_effects(pred, discr, &mut applier);
+
+ if !applier.effects_applied {
+ propagate(pred, exit_state)
+ }
+ }
+
+ _ => propagate(pred, exit_state),
+ }
+ }
}
fn apply_effects_in_range<'tcx, A>(
@@ -170,7 +226,6 @@ fn visit_results_in_block<'mir, 'tcx, A>(
vis.visit_block_end(state);
- // Terminator
let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator();
results.analysis.apply_before_terminator_effect(state, term, loc);
@@ -188,82 +243,13 @@ fn visit_results_in_block<'mir, 'tcx, A>(
vis.visit_block_start(state);
}
-
- fn join_state_into_successors_of<'tcx, A>(
- analysis: &mut A,
- body: &mir::Body<'tcx>,
- exit_state: &mut A::Domain,
- bb: BasicBlock,
- _edges: TerminatorEdges<'_, 'tcx>,
- mut propagate: impl FnMut(BasicBlock, &A::Domain),
- ) where
- A: Analysis<'tcx>,
- {
- for pred in body.basic_blocks.predecessors()[bb].iter().copied() {
- match body[pred].terminator().kind {
- // Apply terminator-specific edge effects.
- //
- // FIXME(ecstaticmorse): Avoid cloning the exit state unconditionally.
- mir::TerminatorKind::Call { destination, target: Some(dest), .. } if dest == bb => {
- let mut tmp = exit_state.clone();
- analysis.apply_call_return_effect(
- &mut tmp,
- pred,
- CallReturnPlaces::Call(destination),
- );
- propagate(pred, &tmp);
- }
-
- mir::TerminatorKind::InlineAsm { ref targets, ref operands, .. }
- if targets.contains(&bb) =>
- {
- let mut tmp = exit_state.clone();
- analysis.apply_call_return_effect(
- &mut tmp,
- pred,
- CallReturnPlaces::InlineAsm(operands),
- );
- propagate(pred, &tmp);
- }
-
- mir::TerminatorKind::Yield { resume, resume_arg, .. } if resume == bb => {
- let mut tmp = exit_state.clone();
- analysis.apply_call_return_effect(
- &mut tmp,
- resume,
- CallReturnPlaces::Yield(resume_arg),
- );
- propagate(pred, &tmp);
- }
-
- mir::TerminatorKind::SwitchInt { targets: _, ref discr } => {
- let mut applier = BackwardSwitchIntEdgeEffectsApplier {
- body,
- pred,
- exit_state,
- bb,
- propagate: &mut propagate,
- effects_applied: false,
- };
-
- analysis.apply_switch_int_edge_effects(pred, discr, &mut applier);
-
- if !applier.effects_applied {
- propagate(pred, exit_state)
- }
- }
-
- _ => propagate(pred, exit_state),
- }
- }
- }
}
struct BackwardSwitchIntEdgeEffectsApplier<'mir, 'tcx, D, F> {
body: &'mir mir::Body<'tcx>,
pred: BasicBlock,
exit_state: &'mir mut D,
- bb: BasicBlock,
+ block: BasicBlock,
propagate: &'mir mut F,
effects_applied: bool,
}
@@ -276,8 +262,8 @@ impl super::SwitchIntEdgeEffects for BackwardSwitchIntEdgeEffectsApplie
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
assert!(!self.effects_applied);
- let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)];
- let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
+ let values = &self.body.basic_blocks.switch_sources()[&(self.block, self.pred)];
+ let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.block });
let mut tmp = None;
for target in targets {
@@ -298,11 +284,12 @@ impl Direction for Forward {
fn apply_effects_in_block<'mir, 'tcx, A>(
analysis: &mut A,
+ _body: &mir::Body<'tcx>,
state: &mut A::Domain,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
- ) -> TerminatorEdges<'mir, 'tcx>
- where
+ mut propagate: impl FnMut(BasicBlock, &A::Domain),
+ ) where
A: Analysis<'tcx>,
{
for (statement_index, statement) in block_data.statements.iter().enumerate() {
@@ -313,7 +300,53 @@ fn apply_effects_in_block<'mir, 'tcx, A>(
let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location);
- analysis.apply_terminator_effect(state, terminator, location)
+ let edges = analysis.apply_terminator_effect(state, terminator, location);
+
+ let exit_state = state;
+ match edges {
+ TerminatorEdges::None => {}
+ TerminatorEdges::Single(target) => propagate(target, exit_state),
+ TerminatorEdges::Double(target, unwind) => {
+ propagate(target, exit_state);
+ propagate(unwind, exit_state);
+ }
+ TerminatorEdges::AssignOnReturn { return_, cleanup, place } => {
+ // This must be done *first*, otherwise the unwind path will see the assignments.
+ if let Some(cleanup) = cleanup {
+ propagate(cleanup, exit_state);
+ }
+
+ if !return_.is_empty() {
+ analysis.apply_call_return_effect(exit_state, block, place);
+ for &target in return_ {
+ propagate(target, exit_state);
+ }
+ }
+ }
+ TerminatorEdges::SwitchInt { targets, discr } => {
+ let mut applier = ForwardSwitchIntEdgeEffectsApplier {
+ exit_state,
+ targets,
+ propagate,
+ effects_applied: false,
+ };
+
+ analysis.apply_switch_int_edge_effects(block, discr, &mut applier);
+
+ let ForwardSwitchIntEdgeEffectsApplier {
+ exit_state,
+ mut propagate,
+ effects_applied,
+ ..
+ } = applier;
+
+ if !effects_applied {
+ for target in targets.all_targets() {
+ propagate(*target, exit_state);
+ }
+ }
+ }
+ }
}
fn apply_effects_in_range<'tcx, A>(
@@ -351,7 +384,8 @@ fn apply_effects_in_range<'tcx, A>(
let statement = &block_data.statements[from.statement_index];
analysis.apply_statement_effect(state, statement, location);
- // If we only needed to apply the after effect of the statement at `idx`, we are done.
+ // If we only needed to apply the after effect of the statement at `idx`, we are
+ // done.
if from == to {
return;
}
@@ -419,62 +453,6 @@ fn visit_results_in_block<'mir, 'tcx, A>(
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> {
diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
index ed540cd148c4..c177d98106f3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
@@ -230,16 +230,3 @@ fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", ctxt.move_data().move_paths[*self])
}
}
-
-impl DebugWithContext for crate::lattice::Dual
-where
- T: DebugWithContext,
-{
- 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)
- }
-}
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 98a4f58cb5dc..6e4994af8b4e 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -47,20 +47,16 @@ impl<'mir, 'tcx, A> Formatter<'mir, 'tcx, A>
{
pub(crate) fn new(
body: &'mir Body<'tcx>,
- results: Results<'tcx, A>,
+ results: &'mir Results<'tcx, A>,
style: OutputStyle,
) -> Self {
let reachable = mir::traversal::reachable_as_bitset(body);
- Formatter { cursor: results.into_results_cursor(body).into(), style, reachable }
+ Formatter { cursor: results.as_results_cursor(body).into(), style, reachable }
}
fn body(&self) -> &'mir Body<'tcx> {
self.cursor.borrow().body()
}
-
- pub(crate) fn into_results(self) -> Results<'tcx, A> {
- self.cursor.into_inner().into_results()
- }
}
/// A pair of a basic block and an index into that basic blocks `successors`.
diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
index 4d03ee53b7c0..6d2a7a099a09 100644
--- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
@@ -25,8 +25,8 @@
//!
//! ## `PartialOrd`
//!
-//! Given that they represent partially ordered sets, you may be surprised that [`JoinSemiLattice`]
-//! and [`MeetSemiLattice`] do not have [`PartialOrd`] as a supertrait. This
+//! Given that it represents a partially ordered set, you may be surprised that [`JoinSemiLattice`]
+//! does not have [`PartialOrd`] as a supertrait. This
//! is because most standard library types use lexicographic ordering instead of set inclusion for
//! their `PartialOrd` impl. Since we do not actually need to compare lattice elements to run a
//! dataflow analysis, there's no need for a newtype wrapper with a custom `PartialOrd` impl. The
@@ -58,23 +58,6 @@ pub trait JoinSemiLattice: Eq {
fn join(&mut self, other: &Self) -> bool;
}
-/// A [partially ordered set][poset] that has a [greatest lower bound][glb] for any pair of
-/// elements in the set.
-///
-/// Dataflow analyses only require that their domains implement [`JoinSemiLattice`], not
-/// `MeetSemiLattice`. However, types that will be used as dataflow domains should implement both
-/// so that they can be used with [`Dual`].
-///
-/// [glb]: https://en.wikipedia.org/wiki/Infimum_and_supremum
-/// [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set
-pub trait MeetSemiLattice: Eq {
- /// Computes the greatest lower bound of two elements, storing the result in `self` and
- /// returning `true` if `self` has changed.
- ///
- /// The lattice meet operator is abbreviated as `∧`.
- fn meet(&mut self, other: &Self) -> bool;
-}
-
/// A set that has a "bottom" element, which is less than or equal to any other element.
pub trait HasBottom {
const BOTTOM: Self;
@@ -105,17 +88,6 @@ fn join(&mut self, other: &Self) -> bool {
}
}
-impl MeetSemiLattice for bool {
- fn meet(&mut self, other: &Self) -> bool {
- if let (true, false) = (*self, *other) {
- *self = false;
- return true;
- }
-
- false
- }
-}
-
impl HasBottom for bool {
const BOTTOM: Self = false;
@@ -145,18 +117,6 @@ fn join(&mut self, other: &Self) -> bool {
}
}
-impl MeetSemiLattice for IndexVec {
- fn meet(&mut self, other: &Self) -> bool {
- assert_eq!(self.len(), other.len());
-
- let mut changed = false;
- for (a, b) in iter::zip(self, other) {
- changed |= a.meet(b);
- }
- changed
- }
-}
-
/// A `BitSet` represents the lattice formed by the powerset of all possible values of
/// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices,
/// one for each possible value of `T`.
@@ -166,60 +126,12 @@ fn join(&mut self, other: &Self) -> bool {
}
}
-impl MeetSemiLattice for BitSet {
- fn meet(&mut self, other: &Self) -> bool {
- self.intersect(other)
- }
-}
-
impl JoinSemiLattice for ChunkedBitSet {
fn join(&mut self, other: &Self) -> bool {
self.union(other)
}
}
-impl MeetSemiLattice for ChunkedBitSet {
- 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(pub T);
-
-impl BitSetExt for Dual> {
- fn contains(&self, elem: T) -> bool {
- self.0.contains(elem)
- }
-
- fn union(&mut self, other: &HybridBitSet) {
- self.0.union(other);
- }
-
- fn subtract(&mut self, other: &HybridBitSet) {
- self.0.subtract(other);
- }
-}
-
-impl JoinSemiLattice for Dual {
- fn join(&mut self, other: &Self) -> bool {
- self.0.meet(&other.0)
- }
-}
-
-impl MeetSemiLattice for Dual {
- fn meet(&mut self, other: &Self) -> bool {
- self.0.join(&other.0)
- }
-}
-
/// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no
/// value of `T` is comparable with any other.
///
@@ -257,22 +169,6 @@ fn join(&mut self, other: &Self) -> bool {
}
}
-impl MeetSemiLattice for FlatSet {
- 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 HasBottom for FlatSet {
const BOTTOM: Self = Self::Bottom;
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 244dfe26ad36..bb652a75caa3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -8,8 +8,9 @@
//! The `impls` module contains several examples of dataflow analyses.
//!
//! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From
-//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem,
-//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses
+//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem
+//! (good for inspecting a small number of locations), or implement the `ResultsVisitor` interface
+//! and use `visit_results` (good for inspecting many or all locations). The following example uses
//! the `ResultsCursor` approach.
//!
//! ```ignore (cross-crate-imports)
@@ -278,22 +279,17 @@ fn iterate_to_fixpoint<'mir>(
// every iteration.
let mut state = self.bottom_value(body);
while let Some(bb) = dirty_queue.pop() {
- let bb_data = &body[bb];
-
// Set the state to the entry state of the block.
// This is equivalent to `state = entry_sets[bb].clone()`,
// but it saves an allocation, thus improving compile times.
state.clone_from(&entry_sets[bb]);
- // Apply the block transfer function, using the cached one if it exists.
- let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data);
-
- Self::Direction::join_state_into_successors_of(
+ Self::Direction::apply_effects_in_block(
&mut self,
body,
&mut state,
bb,
- edges,
+ &body[bb],
|target: BasicBlock, state: &Self::Domain| {
let set_changed = entry_sets[target].join(state);
if set_changed {
@@ -306,14 +302,13 @@ fn iterate_to_fixpoint<'mir>(
let results = Results { analysis: self, entry_sets };
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
- let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
+ let res = write_graphviz_results(tcx, body, &results, pass_name);
if let Err(e) = res {
error!("Failed to write graphviz dataflow results: {}", e);
}
- results
- } else {
- results
}
+
+ results
}
}
@@ -378,16 +373,6 @@ fn kill(&mut self, elem: T) {
}
}
-impl GenKill for lattice::Dual> {
- fn gen_(&mut self, elem: T) {
- self.0.insert(elem);
- }
-
- fn kill(&mut self, elem: T) {
- self.0.remove(elem);
- }
-}
-
// NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Effect {
diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index ff6cafbfbaee..8493a7aa44bb 100644
--- a/compiler/rustc_mir_dataflow/src/framework/results.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -17,10 +17,13 @@
use crate::errors::{
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
};
+use crate::framework::cursor::ResultsHandle;
pub type EntrySets<'tcx, A> = IndexVec>::Domain>;
-/// A dataflow analysis that has converged to fixpoint.
+/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the
+/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly
+/// by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls).
#[derive(Clone)]
pub struct Results<'tcx, A>
where
@@ -34,12 +37,30 @@ impl<'tcx, A> Results<'tcx, A>
where
A: Analysis<'tcx>,
{
- /// Creates a `ResultsCursor` that can inspect these `Results`.
+ /// Creates a `ResultsCursor` that can inspect these `Results`. Immutably borrows the `Results`,
+ /// which is appropriate when the `Results` is used outside the cursor.
+ pub fn as_results_cursor<'mir>(
+ &'mir self,
+ body: &'mir mir::Body<'tcx>,
+ ) -> ResultsCursor<'mir, 'tcx, A> {
+ ResultsCursor::new(body, ResultsHandle::Borrowed(self))
+ }
+
+ /// Creates a `ResultsCursor` that can mutate these `Results`. Mutably borrows the `Results`,
+ /// which is appropriate when the `Results` is used outside the cursor.
+ pub fn as_results_cursor_mut<'mir>(
+ &'mir mut self,
+ body: &'mir mir::Body<'tcx>,
+ ) -> ResultsCursor<'mir, 'tcx, A> {
+ ResultsCursor::new(body, ResultsHandle::BorrowedMut(self))
+ }
+
+ /// Creates a `ResultsCursor` that takes ownership of the `Results`.
pub fn into_results_cursor<'mir>(
self,
body: &'mir mir::Body<'tcx>,
) -> ResultsCursor<'mir, 'tcx, A> {
- ResultsCursor::new(body, self)
+ ResultsCursor::new(body, ResultsHandle::Owned(self))
}
/// Gets the dataflow state for the given block.
@@ -74,9 +95,9 @@ pub fn visit_reachable_with<'mir>(
pub(super) fn write_graphviz_results<'tcx, A>(
tcx: TyCtxt<'tcx>,
body: &mir::Body<'tcx>,
- results: Results<'tcx, A>,
+ results: &Results<'tcx, A>,
pass_name: Option<&'static str>,
-) -> (std::io::Result<()>, Results<'tcx, A>)
+) -> std::io::Result<()>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext,
@@ -87,7 +108,7 @@ pub(super) fn write_graphviz_results<'tcx, A>(
let def_id = body.source.def_id();
let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
// Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
- return (Ok(()), results);
+ return Ok(());
};
let file = try {
@@ -104,12 +125,12 @@ pub(super) fn write_graphviz_results<'tcx, A>(
create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
}
- _ => return (Ok(()), results),
+ _ => return Ok(()),
}
};
let mut file = match file {
Ok(f) => f,
- Err(e) => return (Err(e), results),
+ Err(e) => return Err(e),
};
let style = match attrs.formatter {
@@ -132,7 +153,7 @@ pub(super) fn write_graphviz_results<'tcx, A>(
file.write_all(&buf)?;
};
- (lhs, graphviz.into_results())
+ lhs
}
#[derive(Default)]
diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
index 5c7539eed4d6..bde41974d472 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -26,7 +26,9 @@ pub fn visit_results<'mir, 'tcx, A>(
}
}
-/// A visitor over the results of an `Analysis`.
+/// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in
+/// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain
+/// locations.
pub trait ResultsVisitor<'mir, 'tcx, A>
where
A: Analysis<'tcx>,
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 859019fd1f6e..cec654cac725 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -15,7 +15,7 @@
pub struct MaybeBorrowedLocals;
impl MaybeBorrowedLocals {
- pub(super) fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
+ pub(super) fn transfer_function<'a, T>(trans: &'a mut T) -> TransferFunction<'a, T> {
TransferFunction { trans }
}
}
@@ -39,7 +39,7 @@ fn apply_statement_effect(
statement: &Statement<'tcx>,
location: Location,
) {
- self.transfer_function(trans).visit_statement(statement, location);
+ Self::transfer_function(trans).visit_statement(statement, location);
}
fn apply_terminator_effect<'mir>(
@@ -48,7 +48,7 @@ fn apply_terminator_effect<'mir>(
terminator: &'mir Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx> {
- self.transfer_function(trans).visit_terminator(terminator, location);
+ Self::transfer_function(trans).visit_terminator(terminator, location);
terminator.edges()
}
}
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index 9bb50d1e056b..2c10d4b1cd35 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -12,7 +12,7 @@
use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
use crate::{
Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry,
- drop_flag_effects_for_location, lattice, on_all_children_bits, on_lookup_result_bits,
+ drop_flag_effects_for_location, on_all_children_bits, on_lookup_result_bits,
};
/// `MaybeInitializedPlaces` tracks all places that might be
@@ -42,10 +42,10 @@
/// }
/// ```
///
-/// To determine whether a place *must* be initialized at a
-/// particular control-flow point, one can take the set-difference
-/// between this data and the data from `MaybeUninitializedPlaces` at the
-/// corresponding control-flow point.
+/// To determine whether a place is *definitely* initialized at a
+/// particular control-flow point, one can take the set-complement
+/// of the data from `MaybeUninitializedPlaces` at the corresponding
+/// control-flow point.
///
/// Similarly, at a given `drop` statement, the set-intersection
/// between this data and `MaybeUninitializedPlaces` yields the set of
@@ -117,10 +117,10 @@ fn move_data(&self) -> &MoveData<'tcx> {
/// }
/// ```
///
-/// To determine whether a place *must* be uninitialized at a
-/// particular control-flow point, one can take the set-difference
-/// between this data and the data from `MaybeInitializedPlaces` at the
-/// corresponding control-flow point.
+/// To determine whether a place is *definitely* uninitialized at a
+/// particular control-flow point, one can take the set-complement
+/// of the data from `MaybeInitializedPlaces` at the corresponding
+/// control-flow point.
///
/// Similarly, at a given `drop` statement, the set-intersection
/// between this data and `MaybeInitializedPlaces` yields the set of
@@ -170,57 +170,6 @@ fn move_data(&self) -> &MoveData<'tcx> {
}
}
-/// `DefinitelyInitializedPlaces` tracks all places that are definitely
-/// initialized upon reaching a particular point in the control flow
-/// for a function.
-///
-/// For example, in code like the following, we have corresponding
-/// dataflow information shown in the right-hand comments.
-///
-/// ```rust
-/// struct S;
-/// fn foo(pred: bool) { // definite-init:
-/// // { }
-/// let a = S; let mut b = S; let c; let d; // {a, b }
-///
-/// if pred {
-/// drop(a); // { b, }
-/// b = S; // { b, }
-///
-/// } else {
-/// drop(b); // {a, }
-/// d = S; // {a, d}
-///
-/// } // { }
-///
-/// c = S; // { c }
-/// }
-/// ```
-///
-/// To determine whether a place *may* be uninitialized at a
-/// particular control-flow point, one can take the set-complement
-/// of this data.
-///
-/// Similarly, at a given `drop` statement, the set-difference between
-/// this data and `MaybeInitializedPlaces` yields the set of places
-/// that would require a dynamic drop-flag at that statement.
-pub struct DefinitelyInitializedPlaces<'a, 'tcx> {
- body: &'a Body<'tcx>,
- move_data: &'a MoveData<'tcx>,
-}
-
-impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
- pub fn new(body: &'a Body<'tcx>, move_data: &'a MoveData<'tcx>) -> Self {
- DefinitelyInitializedPlaces { body, move_data }
- }
-}
-
-impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
- fn move_data(&self) -> &MoveData<'tcx> {
- self.move_data
- }
-}
-
/// `EverInitializedPlaces` tracks all places that might have ever been
/// initialized upon reaching a particular point in the control flow
/// for a function, without an intervening `StorageDead`.
@@ -293,19 +242,6 @@ fn update_bits(
}
}
-impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
- fn update_bits(
- trans: &mut >::Domain,
- path: MovePathIndex,
- state: DropFlagState,
- ) {
- match state {
- DropFlagState::Absent => trans.kill(path),
- DropFlagState::Present => trans.gen_(path),
- }
- }
-}
-
impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
/// We use a chunked bitset to avoid paying too high a memory footprint.
@@ -554,70 +490,6 @@ fn apply_switch_int_edge_effects(
}
}
-impl<'a, 'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
- /// Use set intersection as the join operator.
- type Domain = lattice::Dual>;
-
- const NAME: &'static str = "definite_init";
-
- fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
- // bottom = initialized (start_block_effect counters this at outset)
- lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len()))
- }
-
- // sets on_entry bits for Arg places
- fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
- state.0.clear();
-
- drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| {
- assert!(s == DropFlagState::Present);
- state.0.insert(path);
- });
- }
-
- fn apply_statement_effect(
- &mut self,
- trans: &mut Self::Domain,
- _statement: &mir::Statement<'tcx>,
- location: Location,
- ) {
- drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
- Self::update_bits(trans, path, s)
- })
- }
-
- fn apply_terminator_effect<'mir>(
- &mut self,
- trans: &mut Self::Domain,
- terminator: &'mir mir::Terminator<'tcx>,
- location: Location,
- ) -> TerminatorEdges<'mir, 'tcx> {
- drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
- Self::update_bits(trans, path, s)
- });
- terminator.edges()
- }
-
- fn apply_call_return_effect(
- &mut self,
- trans: &mut Self::Domain,
- _block: mir::BasicBlock,
- return_places: CallReturnPlaces<'_, 'tcx>,
- ) {
- return_places.for_each(|place| {
- // when a call returns successfully, that means we need to set
- // the bits for that dest_place to 1 (initialized).
- on_lookup_result_bits(
- self.move_data(),
- self.move_data().rev_lookup.find(place.as_ref()),
- |mpi| {
- trans.gen_(mpi);
- },
- );
- });
- }
-}
-
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
/// There can be many more `InitIndex` than there are locals in a MIR body.
/// We use a chunked bitset to avoid paying too high a memory footprint.
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 9b5bfa9bfa00..57ded63c9baa 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -9,8 +9,7 @@
pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals};
pub use self::initialized::{
- DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeInitializedPlaces,
- MaybeUninitializedPlaces,
+ EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
};
pub use self::liveness::{
MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 576289e228ad..a6a4f849720f 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -135,7 +135,7 @@ fn apply_before_statement_effect(
loc: Location,
) {
// If a place is borrowed in a statement, it needs storage for that statement.
- self.borrowed_locals.mut_analysis().apply_statement_effect(trans, stmt, loc);
+ MaybeBorrowedLocals::transfer_function(trans).visit_statement(stmt, loc);
match &stmt.kind {
StatementKind::StorageDead(l) => trans.kill(*l),
@@ -180,10 +180,7 @@ fn apply_before_terminator_effect(
loc: Location,
) {
// If a place is borrowed in a terminator, it needs storage for that terminator.
- self.borrowed_locals
- .mut_analysis()
- .transfer_function(trans)
- .visit_terminator(terminator, loc);
+ MaybeBorrowedLocals::transfer_function(trans).visit_terminator(terminator, loc);
match &terminator.kind {
TerminatorKind::Call { destination, .. } => {
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 99d0ccde1052..34ef8afdde32 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -12,9 +12,7 @@
PeekMustBePlaceOrRefPlace, StopAfterDataFlowEndedCompilation,
};
use crate::framework::BitSetExt;
-use crate::impls::{
- DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
-};
+use crate::impls::{MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces};
use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
use crate::{Analysis, JoinSemiLattice, ResultsCursor};
@@ -56,13 +54,6 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
}
- if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
- let flow_def_inits =
- DefinitelyInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(tcx, body, None);
-
- sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
- }
-
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None);
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 8295a806d712..ae5506b05e74 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -676,12 +676,11 @@ fn locals_live_across_suspend_points<'tcx>(
let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
- // Calculate the MIR locals that we actually need to keep storage around
- // for.
- let mut requires_storage_cursor =
+ // Calculate the MIR locals that we need to keep storage around for.
+ let mut requires_storage_results =
MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
- .iterate_to_fixpoint(tcx, body, None)
- .into_results_cursor(body);
+ .iterate_to_fixpoint(tcx, body, None);
+ let mut requires_storage_cursor = requires_storage_results.as_results_cursor_mut(body);
// Calculate the liveness of MIR locals ignoring borrows.
let mut liveness =
@@ -754,7 +753,7 @@ fn locals_live_across_suspend_points<'tcx>(
body,
&saved_locals,
always_live_locals.clone(),
- requires_storage_cursor.into_results(),
+ requires_storage_results,
);
LivenessInfo {
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 5023e83bd67c..8db3b174a89f 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -18,6 +18,7 @@
use rustc_span::{BytePos, Pos, Span};
use tracing::debug;
+use crate::lexer::diagnostics::TokenTreeDiagInfo;
use crate::lexer::unicode_chars::UNICODE_ARRAY;
use crate::{errors, make_unclosed_delims_error};
@@ -56,7 +57,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
}
let cursor = Cursor::new(src);
- let string_reader = StringReader {
+ let mut lexer = Lexer {
psess,
start_pos,
pos: start_pos,
@@ -65,34 +66,31 @@ pub(crate) fn lex_token_trees<'psess, 'src>(
override_span,
nbsp_is_whitespace: false,
last_lifetime: None,
+ token: Token::dummy(),
+ diag_info: TokenTreeDiagInfo::default(),
};
- let (stream, res, unmatched_delims) =
- tokentrees::TokenTreesReader::lex_all_token_trees(string_reader);
- match res {
- Ok(()) if unmatched_delims.is_empty() => Ok(stream),
- _ => {
- // Return error if there are unmatched delimiters or unclosed delimiters.
- // We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
- // because the delimiter mismatch is more likely to be the root cause of error
+ let (_open_spacing, stream, res) = lexer.lex_token_trees(/* is_delimited */ false);
+ let unmatched_delims = lexer.diag_info.unmatched_delims;
- let mut buffer = Vec::with_capacity(1);
- for unmatched in unmatched_delims {
- if let Some(err) = make_unclosed_delims_error(unmatched, psess) {
- buffer.push(err);
- }
- }
- if let Err(errs) = res {
- // Add unclosing delimiter or diff marker errors
- for err in errs {
- buffer.push(err);
- }
- }
- Err(buffer)
+ if res.is_ok() && unmatched_delims.is_empty() {
+ Ok(stream)
+ } else {
+ // Return error if there are unmatched delimiters or unclosed delimiters.
+ // We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
+ // because the delimiter mismatch is more likely to be the root cause of error
+ let mut buffer: Vec<_> = unmatched_delims
+ .into_iter()
+ .filter_map(|unmatched_delim| make_unclosed_delims_error(unmatched_delim, psess))
+ .collect();
+ if let Err(errs) = res {
+ // Add unclosing delimiter or diff marker errors
+ buffer.extend(errs);
}
+ Err(buffer)
}
}
-struct StringReader<'psess, 'src> {
+struct Lexer<'psess, 'src> {
psess: &'psess ParseSess,
/// Initial position, read-only.
start_pos: BytePos,
@@ -111,9 +109,14 @@ struct StringReader<'psess, 'src> {
/// Track the `Span` for the leading `'` of the last lifetime. Used for
/// diagnostics to detect possible typo where `"` was meant.
last_lifetime: Option,
+
+ /// The current token.
+ token: Token,
+
+ diag_info: TokenTreeDiagInfo,
}
-impl<'psess, 'src> StringReader<'psess, 'src> {
+impl<'psess, 'src> Lexer<'psess, 'src> {
fn dcx(&self) -> DiagCtxtHandle<'psess> {
self.psess.dcx()
}
@@ -124,7 +127,7 @@ fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span {
/// Returns the next token, paired with a bool indicating if the token was
/// preceded by whitespace.
- fn next_token(&mut self) -> (Token, bool) {
+ fn next_token_from_cursor(&mut self) -> (Token, bool) {
let mut preceded_by_whitespace = false;
let mut swallow_next_invalid = 0;
// Skip trivial (whitespace & comments) tokens
@@ -231,7 +234,8 @@ fn next_token(&mut self) -> (Token, bool) {
.push(span);
token::Ident(sym, IdentIsRaw::No)
}
- // split up (raw) c string literals to an ident and a string literal when edition < 2021.
+ // split up (raw) c string literals to an ident and a string literal when edition <
+ // 2021.
rustc_lexer::TokenKind::Literal {
kind: kind @ (LiteralKind::CStr { .. } | LiteralKind::RawCStr { .. }),
suffix_start: _,
@@ -252,7 +256,9 @@ fn next_token(&mut self) -> (Token, bool) {
let prefix_span = self.mk_sp(start, lit_start);
return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace);
}
- rustc_lexer::TokenKind::GuardedStrPrefix => self.maybe_report_guarded_str(start, str_before),
+ rustc_lexer::TokenKind::GuardedStrPrefix => {
+ self.maybe_report_guarded_str(start, str_before)
+ }
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
let suffix_start = start + BytePos(suffix_start);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
@@ -296,13 +302,20 @@ fn next_token(&mut self) -> (Token, bool) {
if prefix_span.at_least_rust_2021() {
let span = self.mk_sp(start, self.pos);
- let lifetime_name_without_tick = Symbol::intern(&self.str_from(ident_start));
+ let lifetime_name_without_tick =
+ Symbol::intern(&self.str_from(ident_start));
if !lifetime_name_without_tick.can_be_raw() {
- self.dcx().emit_err(errors::CannotBeRawLifetime { span, ident: lifetime_name_without_tick });
+ self.dcx().emit_err(
+ errors::CannotBeRawLifetime {
+ span,
+ ident: lifetime_name_without_tick
+ }
+ );
}
// Put the `'` back onto the lifetime name.
- let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.as_str().len() + 1);
+ let mut lifetime_name =
+ String::with_capacity(lifetime_name_without_tick.as_str().len() + 1);
lifetime_name.push('\'');
lifetime_name += lifetime_name_without_tick.as_str();
let sym = Symbol::intern(&lifetime_name);
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index 7b21ffacc841..c6c9eb3b0b26 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -4,41 +4,19 @@
use rustc_errors::{Applicability, PErr};
use rustc_span::symbol::kw;
-use super::diagnostics::{
- TokenTreeDiagInfo, report_suspicious_mismatch_block, same_indentation_level,
-};
-use super::{StringReader, UnmatchedDelim};
+use super::diagnostics::{report_suspicious_mismatch_block, same_indentation_level};
+use super::{Lexer, UnmatchedDelim};
use crate::Parser;
-pub(super) struct TokenTreesReader<'psess, 'src> {
- string_reader: StringReader<'psess, 'src>,
- /// The "next" token, which has been obtained from the `StringReader` but
- /// not yet handled by the `TokenTreesReader`.
- token: Token,
- diag_info: TokenTreeDiagInfo,
-}
-
-impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
- pub(super) fn lex_all_token_trees(
- string_reader: StringReader<'psess, 'src>,
- ) -> (TokenStream, Result<(), Vec>>, Vec) {
- let mut tt_reader = TokenTreesReader {
- string_reader,
- token: Token::dummy(),
- diag_info: TokenTreeDiagInfo::default(),
- };
- let (_open_spacing, stream, res) = tt_reader.lex_token_trees(/* is_delimited */ false);
- (stream, res, tt_reader.diag_info.unmatched_delims)
- }
-
+impl<'psess, 'src> Lexer<'psess, 'src> {
// Lex into a token stream. The `Spacing` in the result is that of the
// opening delimiter.
- fn lex_token_trees(
+ pub(super) fn lex_token_trees(
&mut self,
is_delimited: bool,
) -> (Spacing, TokenStream, Result<(), Vec>>) {
// Move past the opening delimiter.
- let (_, open_spacing) = self.bump(false);
+ let open_spacing = self.bump_minimal();
let mut buf = Vec::new();
loop {
@@ -71,7 +49,7 @@ fn lex_token_trees(
}
_ => {
// Get the next normal token.
- let (this_tok, this_spacing) = self.bump(true);
+ let (this_tok, this_spacing) = self.bump();
buf.push(TokenTree::Token(this_tok, this_spacing));
}
}
@@ -80,7 +58,7 @@ fn lex_token_trees(
fn eof_err(&mut self) -> PErr<'psess> {
let msg = "this file contains an unclosed delimiter";
- let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg);
+ let mut err = self.dcx().struct_span_err(self.token.span, msg);
let unclosed_delimiter_show_limit = 5;
let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_braces.len());
@@ -110,7 +88,7 @@ fn eof_err(&mut self) -> PErr<'psess> {
report_suspicious_mismatch_block(
&mut err,
&self.diag_info,
- self.string_reader.psess.source_map(),
+ self.psess.source_map(),
*delim,
)
}
@@ -136,7 +114,7 @@ fn lex_token_tree_open_delim(
// Expand to cover the entire delimited token tree.
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
- let sm = self.string_reader.psess.source_map();
+ let sm = self.psess.source_map();
let close_spacing = match self.token.kind {
// Correct delimiter.
@@ -160,7 +138,7 @@ fn lex_token_tree_open_delim(
}
// Move past the closing delimiter.
- self.bump(false).1
+ self.bump_minimal()
}
// Incorrect delimiter.
token::CloseDelim(close_delim) => {
@@ -203,7 +181,7 @@ fn lex_token_tree_open_delim(
// bar(baz(
// } // Incorrect delimiter but matches the earlier `{`
if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) {
- self.bump(false).1
+ self.bump_minimal()
} else {
// The choice of value here doesn't matter.
Spacing::Alone
@@ -225,14 +203,14 @@ fn lex_token_tree_open_delim(
}
// Move on to the next token, returning the current token and its spacing.
- // Will glue adjacent single-char tokens together if `glue` is set.
- fn bump(&mut self, glue: bool) -> (Token, Spacing) {
+ // Will glue adjacent single-char tokens together.
+ fn bump(&mut self) -> (Token, Spacing) {
let (this_spacing, next_tok) = loop {
- let (next_tok, is_next_tok_preceded_by_whitespace) = self.string_reader.next_token();
+ let (next_tok, is_next_tok_preceded_by_whitespace) = self.next_token_from_cursor();
if is_next_tok_preceded_by_whitespace {
break (Spacing::Alone, next_tok);
- } else if glue && let Some(glued) = self.token.glue(&next_tok) {
+ } else if let Some(glued) = self.token.glue(&next_tok) {
self.token = glued;
} else {
let this_spacing = if next_tok.is_punct() {
@@ -249,6 +227,26 @@ fn bump(&mut self, glue: bool) -> (Token, 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(
&mut self,
tts: TokenStream,
@@ -256,7 +254,7 @@ fn unclosed_delim_err(
) -> Vec> {
// If there are unclosed delims, see if there are diff markers and if so, point them
// out instead of complaining about the unclosed delims.
- let mut parser = Parser::new(self.string_reader.psess, tts, None);
+ let mut parser = Parser::new(self.psess, tts, None);
let mut diff_errs = vec![];
// Suggest removing a `{` we think appears in an `if`/`while` condition.
// We want to suggest removing a `{` only if we think we're in an `if`/`while` condition,
@@ -314,14 +312,9 @@ fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'psess> {
// An unexpected closing delimiter (i.e., there is no matching opening delimiter).
let token_str = token_to_string(&self.token);
let msg = format!("unexpected closing delimiter: `{token_str}`");
- let mut err = self.string_reader.dcx().struct_span_err(self.token.span, msg);
+ let mut err = self.dcx().struct_span_err(self.token.span, msg);
- report_suspicious_mismatch_block(
- &mut err,
- &self.diag_info,
- self.string_reader.psess.source_map(),
- delim,
- );
+ report_suspicious_mismatch_block(&mut err, &self.diag_info, self.psess.source_map(), delim);
err.span_label(self.token.span, "unexpected closing delimiter");
err
}
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index d78b3664b1ee..42eef27803eb 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -4,7 +4,7 @@
use rustc_span::symbol::kw;
use rustc_span::{BytePos, Pos, Span};
-use super::StringReader;
+use super::Lexer;
use crate::errors::TokenSubstitution;
use crate::token::{self, Delimiter};
@@ -338,7 +338,7 @@
];
pub(super) fn check_for_substitution(
- reader: &StringReader<'_, '_>,
+ lexer: &Lexer<'_, '_>,
pos: BytePos,
ch: char,
count: usize,
@@ -351,11 +351,11 @@ pub(super) fn check_for_substitution(
let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
let msg = format!("substitution character not found for '{ch}'");
- reader.dcx().span_bug(span, msg);
+ lexer.dcx().span_bug(span, msg);
};
// special help suggestion for "directed" double quotes
- let sugg = if let Some(s) = peek_delimited(&reader.src[reader.src_index(pos)..], '“', '”') {
+ let sugg = if let Some(s) = peek_delimited(&lexer.src[lexer.src_index(pos)..], '“', '”') {
let span = Span::with_root_ctxt(
pos,
pos + Pos::from_usize('“'.len_utf8() + s.len() + '”'.len_utf8()),
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index c4326427f67b..004b5b348136 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,11 +1,12 @@
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token};
+use rustc_ast::util::parser::AssocOp;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{
- self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, ExprPrecedence,
- LocalKind, MacCall, Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd,
- RangeSyntax, Stmt, StmtKind,
+ self as ast, Arm, AttrVec, BinOpKind, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall,
+ Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt,
+ StmtKind,
};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey};
@@ -458,7 +459,7 @@ fn maybe_recover_trailing_expr(
.create_err(UnexpectedExpressionInPattern {
span,
is_bound,
- expr_precedence: expr.precedence().order(),
+ expr_precedence: expr.precedence(),
})
.stash(span, StashKey::ExprInPat)
.unwrap(),
@@ -545,7 +546,8 @@ fn maybe_add_suggestions_then_emit(
let expr = match &err.args["expr_precedence"] {
DiagArgValue::Number(expr_precedence) => {
if *expr_precedence
- <= ExprPrecedence::Binary(BinOpKind::Eq).order() as i32
+ <= AssocOp::from_ast_binop(BinOpKind::Eq).precedence()
+ as i32
{
format!("({expr})")
} else {
@@ -568,8 +570,9 @@ fn maybe_add_suggestions_then_emit(
}
Some(guard) => {
// Are parentheses required around the old guard?
- let wrap_guard = guard.precedence().order()
- <= ExprPrecedence::Binary(BinOpKind::And).order();
+ let wrap_guard = guard.precedence()
+ <= AssocOp::from_ast_binop(BinOpKind::And).precedence()
+ as i8;
err.subdiagnostic(
UnexpectedExpressionInPatternSugg::UpdateGuard {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 46e245fb71f1..5252c446e1d3 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1728,7 +1728,6 @@
rustc_partition_reused,
rustc_pass_by_value,
rustc_peek,
- rustc_peek_definite_init,
rustc_peek_liveness,
rustc_peek_maybe_init,
rustc_peek_maybe_uninit,
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index 522b9f837d7c..3225cdc759d9 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -1,5 +1,7 @@
use std::assert_matches::assert_matches;
+use rustc_data_structures::fx::FxHashSet;
+
use super::super::*;
// Test target self-consistency and JSON encoding/decoding roundtrip.
@@ -173,6 +175,27 @@ fn check_consistency(&self) {
}
_ => {}
}
+
+ // 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
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index c7ad14ac0bfc..0f9d4cb1982d 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -1792,12 +1792,12 @@ pub fn type_error_additional_suggestions(
fn suggest_specify_actual_length(
&self,
- terr: TypeError<'_>,
- trace: &TypeTrace<'_>,
+ terr: TypeError<'tcx>,
+ trace: &TypeTrace<'tcx>,
span: Span,
) -> Option {
let hir = self.tcx.hir();
- let TypeError::FixedArraySize(sz) = terr else {
+ let TypeError::ArraySize(sz) = terr else {
return None;
};
let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) {
@@ -1838,9 +1838,14 @@ fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result {
if let Some(tykind) = tykind
&& let hir::TyKind::Array(_, length) = tykind
&& let hir::ArrayLen::Body(ct) = length
+ && let Some((scalar, ty)) = sz.found.try_to_scalar()
+ && ty == self.tcx.types.usize
{
let span = ct.span();
- Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found })
+ Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength {
+ span,
+ length: scalar.to_target_usize(&self.tcx).unwrap(),
+ })
} else {
None
}
diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs
index 59dea7695111..55671b84dbc4 100644
--- a/compiler/rustc_type_ir/src/error.rs
+++ b/compiler/rustc_type_ir/src/error.rs
@@ -29,7 +29,7 @@ pub enum TypeError {
Mutability,
ArgumentMutability(usize),
TupleSize(ExpectedFound),
- FixedArraySize(ExpectedFound),
+ ArraySize(ExpectedFound),
ArgCount,
RegionsDoesNotOutlive(I::Region, I::Region),
@@ -69,7 +69,7 @@ pub fn must_include_note(self) -> bool {
use self::TypeError::*;
match self {
CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | PolarityMismatch(_) | Mismatch
- | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
+ | AbiMismatch(_) | ArraySize(_) | ArgumentSorts(..) | Sorts(_)
| VariadicMismatch(_) | TargetFeatureCast(_) => false,
Mutability
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 3793d2c5241f..a201f2b1c11f 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -257,8 +257,6 @@ pub trait Const>:
+ Relate
+ Flags
{
- fn try_to_target_usize(self, interner: I) -> Option;
-
fn new_infer(interner: I, var: ty::InferConst) -> Self;
fn new_var(interner: I, var: ty::ConstVid) -> Self;
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index 6b301b160605..0b013b2017f1 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -501,19 +501,10 @@ pub fn structurally_relate_tys>(
let t = relation.relate(a_t, b_t)?;
match relation.relate(sz_a, sz_b) {
Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)),
- Err(err) => {
- // Check whether the lengths are both concrete/known values,
- // but are unequal, for better diagnostics.
- let sz_a = sz_a.try_to_target_usize(cx);
- let sz_b = sz_b.try_to_target_usize(cx);
-
- match (sz_a, sz_b) {
- (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => {
- Err(TypeError::FixedArraySize(ExpectedFound::new(sz_a_val, sz_b_val)))
- }
- _ => Err(err),
- }
+ Err(TypeError::ConstMismatch(_)) => {
+ Err(TypeError::ArraySize(ExpectedFound::new(sz_a, sz_b)))
}
+ Err(e) => Err(e),
}
}
diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs
index 75bb86916a88..0da6af54bc22 100644
--- a/library/alloc/src/collections/btree/map/entry.rs
+++ b/library/alloc/src/collections/btree/map/entry.rs
@@ -269,6 +269,31 @@ pub fn and_modify(self, f: F) -> Self
Vacant(entry) => Vacant(entry),
}
}
+
+ /// Sets the value of the entry, and returns an `OccupiedEntry`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(btree_entry_insert)]
+ /// use std::collections::BTreeMap;
+ ///
+ /// let mut map: BTreeMap<&str, String> = BTreeMap::new();
+ /// let entry = map.entry("poneyland").insert_entry("hoho".to_string());
+ ///
+ /// assert_eq!(entry.key(), &"poneyland");
+ /// ```
+ #[inline]
+ #[unstable(feature = "btree_entry_insert", issue = "65225")]
+ pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> {
+ match self {
+ Occupied(mut entry) => {
+ entry.insert(value);
+ entry
+ }
+ Vacant(entry) => entry.insert_entry(value),
+ }
+ }
}
impl<'a, K: Ord, V: Default, A: Allocator + Clone> Entry<'a, K, V, A> {
@@ -348,41 +373,61 @@ pub fn into_key(self) -> K {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_confusables("push", "put")]
- pub fn insert(mut self, value: V) -> &'a mut V {
- let out_ptr = match self.handle {
+ pub fn insert(self, value: V) -> &'a mut V {
+ self.insert_entry(value).into_mut()
+ }
+
+ /// Sets the value of the entry with the `VacantEntry`'s key,
+ /// and returns an `OccupiedEntry`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(btree_entry_insert)]
+ /// use std::collections::BTreeMap;
+ /// use std::collections::btree_map::Entry;
+ ///
+ /// let mut map: BTreeMap<&str, u32> = BTreeMap::new();
+ ///
+ /// if let Entry::Vacant(o) = map.entry("poneyland") {
+ /// let entry = o.insert_entry(37);
+ /// assert_eq!(entry.get(), &37);
+ /// }
+ /// assert_eq!(map["poneyland"], 37);
+ /// ```
+ #[unstable(feature = "btree_entry_insert", issue = "65225")]
+ pub fn insert_entry(mut self, value: V) -> OccupiedEntry<'a, K, V, A> {
+ let handle = match self.handle {
None => {
// SAFETY: There is no tree yet so no reference to it exists.
- let map = unsafe { self.dormant_map.awaken() };
- let mut root = NodeRef::new_leaf(self.alloc.clone());
- let val_ptr = root.borrow_mut().push(self.key, value);
- map.root = Some(root.forget_type());
- map.length = 1;
- val_ptr
- }
- Some(handle) => {
- let new_handle =
- handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
- drop(ins.left);
- // SAFETY: Pushing a new root node doesn't invalidate
- // handles to existing nodes.
- let map = unsafe { self.dormant_map.reborrow() };
- let root = map.root.as_mut().unwrap(); // same as ins.left
- root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right)
- });
-
- // Get the pointer to the value
- let val_ptr = new_handle.into_val_mut();
-
- // SAFETY: We have consumed self.handle.
- let map = unsafe { self.dormant_map.awaken() };
- map.length += 1;
- val_ptr
+ let map = unsafe { self.dormant_map.reborrow() };
+ let root = map.root.insert(NodeRef::new_leaf(self.alloc.clone()).forget_type());
+ // SAFETY: We *just* created the root as a leaf, and we're
+ // stacking the new handle on the original borrow lifetime.
+ unsafe {
+ let mut leaf = root.borrow_mut().cast_to_leaf_unchecked();
+ leaf.push_with_handle(self.key, value)
+ }
}
+ Some(handle) => handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
+ drop(ins.left);
+ // SAFETY: Pushing a new root node doesn't invalidate
+ // handles to existing nodes.
+ let map = unsafe { self.dormant_map.reborrow() };
+ let root = map.root.as_mut().unwrap(); // same as ins.left
+ root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
+ }),
};
- // Now that we have finished growing the tree using borrowed references,
- // dereference the pointer to a part of it, that we picked up along the way.
- unsafe { &mut *out_ptr }
+ // SAFETY: modifying the length doesn't invalidate handles to existing nodes.
+ unsafe { self.dormant_map.reborrow().length += 1 };
+
+ OccupiedEntry {
+ handle: handle.forget_node_type(),
+ dormant_map: self.dormant_map,
+ alloc: self.alloc,
+ _marker: PhantomData,
+ }
}
}
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 64a13bb6a0b3..0c93eff0d20f 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -739,7 +739,7 @@ pub fn force(
impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> {
/// Unsafely asserts to the compiler the static information that this node is a `Leaf`.
- unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> {
+ pub unsafe fn cast_to_leaf_unchecked(self) -> NodeRef, K, V, marker::Leaf> {
debug_assert!(self.height == 0);
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
}
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 58315cb74f0a..27273e4eedf3 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -255,7 +255,11 @@ fn clone(&self) -> Self {
#[stable(feature = "maybe_uninit_debug", since = "1.41.0")]
impl fmt::Debug for MaybeUninit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.pad(type_name::())
+ // 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::();
+ let short_name = full_name.split_once("mem::maybe_uninit::").unwrap().1;
+ f.pad(short_name)
}
}
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index c855f963771e..b3defba5a982 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -10,10 +10,10 @@
use crate::intrinsics::{exact_div, select_unpredictable, unchecked_sub};
use crate::mem::{self, SizedTypeProperties};
use crate::num::NonZero;
-use crate::ops::{Bound, OneSidedRange, Range, RangeBounds};
+use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive};
use crate::simd::{self, Simd};
use crate::ub_checks::assert_unsafe_precondition;
-use crate::{fmt, hint, ptr, slice};
+use crate::{fmt, hint, ptr, range, slice};
#[unstable(
feature = "slice_internals",
@@ -4469,6 +4469,12 @@ pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
/// Returns mutable references to many indices at once, without doing any checks.
///
+ /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note
+ /// that this method takes an array, so all indices must be of the same type.
+ /// If passed an array of `usize`s this method gives back an array of mutable references
+ /// to single elements, while if passed an array of ranges it gives back an array of
+ /// mutable references to slices.
+ ///
/// For a safe alternative see [`get_many_mut`].
///
/// # Safety
@@ -4489,30 +4495,49 @@ pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
/// *b *= 100;
/// }
/// assert_eq!(x, &[10, 2, 400]);
+ ///
+ /// unsafe {
+ /// let [a, b] = x.get_many_unchecked_mut([0..1, 1..3]);
+ /// a[0] = 8;
+ /// b[0] = 88;
+ /// b[1] = 888;
+ /// }
+ /// assert_eq!(x, &[8, 88, 888]);
+ ///
+ /// unsafe {
+ /// let [a, b] = x.get_many_unchecked_mut([1..=2, 0..=0]);
+ /// a[0] = 11;
+ /// a[1] = 111;
+ /// b[0] = 1;
+ /// }
+ /// assert_eq!(x, &[1, 11, 111]);
/// ```
///
/// [`get_many_mut`]: slice::get_many_mut
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
#[unstable(feature = "get_many_mut", issue = "104642")]
#[inline]
- pub unsafe fn get_many_unchecked_mut(
+ pub unsafe fn get_many_unchecked_mut(
&mut self,
- indices: [usize; N],
- ) -> [&mut T; N] {
+ indices: [I; N],
+ ) -> [&mut I::Output; N]
+ where
+ I: GetManyMutIndex + SliceIndex,
+ {
// NB: This implementation is written as it is because any variation of
// `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy,
// or generate worse code otherwise. This is also why we need to go
// through a raw pointer here.
let slice: *mut [T] = self;
- let mut arr: mem::MaybeUninit<[&mut T; N]> = mem::MaybeUninit::uninit();
+ let mut arr: mem::MaybeUninit<[&mut I::Output; N]> = mem::MaybeUninit::uninit();
let arr_ptr = arr.as_mut_ptr();
// SAFETY: We expect `indices` to contain disjunct values that are
// in bounds of `self`.
unsafe {
for i in 0..N {
- let idx = *indices.get_unchecked(i);
- *(*arr_ptr).get_unchecked_mut(i) = &mut *slice.get_unchecked_mut(idx);
+ let idx = indices.get_unchecked(i).clone();
+ arr_ptr.cast::<&mut I::Output>().add(i).write(&mut *slice.get_unchecked_mut(idx));
}
arr.assume_init()
}
@@ -4520,8 +4545,18 @@ pub unsafe fn get_many_unchecked_mut(
/// Returns mutable references to many indices at once.
///
- /// Returns an error if any index is out-of-bounds, or if the same index was
- /// passed more than once.
+ /// An index can be either a `usize`, a [`Range`] or a [`RangeInclusive`]. Note
+ /// that this method takes an array, so all indices must be of the same type.
+ /// If passed an array of `usize`s this method gives back an array of mutable references
+ /// to single elements, while if passed an array of ranges it gives back an array of
+ /// mutable references to slices.
+ ///
+ /// Returns an error if any index is out-of-bounds, or if there are overlapping indices.
+ /// An empty range is not considered to overlap if it is located at the beginning or at
+ /// the end of another range, but is considered to overlap if it is located in the middle.
+ ///
+ /// This method does a O(n^2) check to check that there are no overlapping indices, so be careful
+ /// when passing many indices.
///
/// # Examples
///
@@ -4534,13 +4569,30 @@ pub unsafe fn get_many_unchecked_mut(
/// *b = 612;
/// }
/// assert_eq!(v, &[413, 2, 612]);
+ ///
+ /// if let Ok([a, b]) = v.get_many_mut([0..1, 1..3]) {
+ /// a[0] = 8;
+ /// b[0] = 88;
+ /// b[1] = 888;
+ /// }
+ /// assert_eq!(v, &[8, 88, 888]);
+ ///
+ /// if let Ok([a, b]) = v.get_many_mut([1..=2, 0..=0]) {
+ /// a[0] = 11;
+ /// a[1] = 111;
+ /// b[0] = 1;
+ /// }
+ /// assert_eq!(v, &[1, 11, 111]);
/// ```
#[unstable(feature = "get_many_mut", issue = "104642")]
#[inline]
- pub fn get_many_mut(
+ pub fn get_many_mut(
&mut self,
- indices: [usize; N],
- ) -> Result<[&mut T; N], GetManyMutError> {
+ indices: [I; N],
+ ) -> Result<[&mut I::Output; N], GetManyMutError>
+ where
+ I: GetManyMutIndex + SliceIndex,
+ {
if !get_many_check_valid(&indices, self.len()) {
return Err(GetManyMutError { _private: () });
}
@@ -4885,14 +4937,15 @@ fn as_slice(&self) -> &[Self::Item] {
///
/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
/// comparison operations.
-fn get_many_check_valid(indices: &[usize; N], len: usize) -> bool {
+#[inline]
+fn get_many_check_valid(indices: &[I; N], len: usize) -> bool {
// NB: The optimizer should inline the loops into a sequence
// of instructions without additional branching.
let mut valid = true;
- for (i, &idx) in indices.iter().enumerate() {
- valid &= idx < len;
- for &idx2 in &indices[..i] {
- valid &= idx != idx2;
+ for (i, idx) in indices.iter().enumerate() {
+ valid &= idx.is_in_bounds(len);
+ for idx2 in &indices[..i] {
+ valid &= !idx.is_overlapping(idx2);
}
}
valid
@@ -4916,6 +4969,7 @@ fn as_slice(&self) -> &[Self::Item] {
#[unstable(feature = "get_many_mut", issue = "104642")]
// NB: The N here is there to be forward-compatible with adding more details
// to the error type at a later point
+#[derive(Clone, PartialEq, Eq)]
pub struct GetManyMutError {
_private: (),
}
@@ -4933,3 +4987,111 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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 {}
+ #[unstable(feature = "get_many_mut_helpers", issue = "none")]
+ impl Sealed for RangeInclusive {}
+ #[unstable(feature = "get_many_mut_helpers", issue = "none")]
+ impl Sealed for range::Range {}
+ #[unstable(feature = "get_many_mut_helpers", issue = "none")]
+ impl Sealed for range::RangeInclusive {}
+}
+
+/// 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 {
+ #[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 {
+ #[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 {
+ #[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 {
+ #[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))
+ }
+}
diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs
index 704d24613994..f7512abae382 100644
--- a/library/core/tests/fmt/mod.rs
+++ b/library/core/tests/fmt/mod.rs
@@ -43,3 +43,10 @@ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
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");
+}
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 9ae2bcc85264..510dd4967c96 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -2,6 +2,7 @@
use core::cmp::Ordering;
use core::mem::MaybeUninit;
use core::num::NonZero;
+use core::ops::{Range, RangeInclusive};
use core::slice;
#[test]
@@ -2553,6 +2554,14 @@ fn test_get_many_mut_normal_2() {
*a += 10;
*b += 100;
assert_eq!(v, vec![101, 2, 3, 14, 5]);
+
+ let [a, b] = v.get_many_mut([0..=1, 2..=2]).unwrap();
+ assert_eq!(a, &mut [101, 2][..]);
+ assert_eq!(b, &mut [3][..]);
+ a[0] += 10;
+ a[1] += 20;
+ b[0] += 100;
+ assert_eq!(v, vec![111, 22, 103, 14, 5]);
}
#[test]
@@ -2563,12 +2572,23 @@ fn test_get_many_mut_normal_3() {
*b += 100;
*c += 1000;
assert_eq!(v, vec![11, 2, 1003, 4, 105]);
+
+ let [a, b, c] = v.get_many_mut([0..1, 4..5, 1..4]).unwrap();
+ assert_eq!(a, &mut [11][..]);
+ assert_eq!(b, &mut [105][..]);
+ assert_eq!(c, &mut [2, 1003, 4][..]);
+ a[0] += 10;
+ b[0] += 100;
+ c[0] += 1000;
+ assert_eq!(v, vec![21, 1002, 1003, 4, 205]);
}
#[test]
fn test_get_many_mut_empty() {
let mut v = vec![1, 2, 3, 4, 5];
- let [] = v.get_many_mut([]).unwrap();
+ let [] = v.get_many_mut::([]).unwrap();
+ let [] = v.get_many_mut::, 0>([]).unwrap();
+ let [] = v.get_many_mut::, 0>([]).unwrap();
assert_eq!(v, vec![1, 2, 3, 4, 5]);
}
@@ -2606,6 +2626,54 @@ fn test_get_many_mut_duplicate() {
assert!(v.get_many_mut([1, 3, 3, 4]).is_err());
}
+#[test]
+fn test_get_many_mut_range_oob() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ assert!(v.get_many_mut([0..6]).is_err());
+ assert!(v.get_many_mut([5..6]).is_err());
+ assert!(v.get_many_mut([6..6]).is_err());
+ assert!(v.get_many_mut([0..=5]).is_err());
+ assert!(v.get_many_mut([0..=6]).is_err());
+ assert!(v.get_many_mut([5..=5]).is_err());
+}
+
+#[test]
+fn test_get_many_mut_range_overlapping() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ assert!(v.get_many_mut([0..1, 0..2]).is_err());
+ assert!(v.get_many_mut([0..1, 1..2, 0..1]).is_err());
+ assert!(v.get_many_mut([0..3, 1..1]).is_err());
+ assert!(v.get_many_mut([0..3, 1..2]).is_err());
+ assert!(v.get_many_mut([0..=0, 2..=2, 0..=1]).is_err());
+ assert!(v.get_many_mut([0..=4, 0..=0]).is_err());
+ assert!(v.get_many_mut([4..=4, 0..=0, 3..=4]).is_err());
+}
+
+#[test]
+fn test_get_many_mut_range_empty_at_edge() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ assert_eq!(
+ v.get_many_mut([0..0, 0..5, 5..5]),
+ Ok([&mut [][..], &mut [1, 2, 3, 4, 5], &mut []]),
+ );
+ assert_eq!(
+ v.get_many_mut([0..0, 0..1, 1..1, 1..2, 2..2, 2..3, 3..3, 3..4, 4..4, 4..5, 5..5]),
+ Ok([
+ &mut [][..],
+ &mut [1],
+ &mut [],
+ &mut [2],
+ &mut [],
+ &mut [3],
+ &mut [],
+ &mut [4],
+ &mut [],
+ &mut [5],
+ &mut [],
+ ]),
+ );
+}
+
#[test]
fn test_slice_from_raw_parts_in_const() {
static FANCY: i32 = 4;
diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs
index 29cad4400f18..48d442921f7f 100644
--- a/library/std/src/sync/rwlock/tests.rs
+++ b/library/std/src/sync/rwlock/tests.rs
@@ -511,12 +511,15 @@ fn test_downgrade_basic() {
}
#[test]
+// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
+// See for details.
+#[cfg_attr(all(miri, target_os = "macos"), ignore)]
fn test_downgrade_observe() {
// Taken from the test `test_rwlock_downgrade` from:
// https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs
const W: usize = 20;
- const N: usize = 100;
+ const N: usize = if cfg!(miri) { 40 } else { 100 };
// This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring
// that the value they wrote has not changed after downgrading.
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index fce7f9985ea1..1eebfc22af28 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -963,7 +963,7 @@ fn report<'tcx>(
// expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's
// `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary.
/*
- expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
+ expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence() < PREC_PREFIX {
Cow::Owned(format!("({expr_str})"))
} else {
expr_str
@@ -1003,7 +1003,7 @@ fn report<'tcx>(
Node::Expr(e) => match e.kind {
ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false),
ExprKind::Call(..) => (PREC_UNAMBIGUOUS, matches!(expr.kind, ExprKind::Field(..))),
- _ => (e.precedence().order(), false),
+ _ => (e.precedence(), false),
},
_ => (0, false),
};
@@ -1016,7 +1016,7 @@ fn report<'tcx>(
);
let sugg = if !snip_is_macro
- && (calls_field || expr.precedence().order() < precedence)
+ && (calls_field || expr.precedence() < precedence)
&& !has_enclosing_paren(&snip)
&& !is_in_tuple
{
@@ -1071,7 +1071,7 @@ fn report<'tcx>(
let (snip, snip_is_macro) =
snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
let sugg =
- if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
+ if !snip_is_macro && expr.precedence() < precedence && !has_enclosing_paren(&snip) {
format!("{prefix}({snip})")
} else {
format!("{prefix}{snip}")
@@ -1158,7 +1158,7 @@ fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: H
},
Some(parent) if !parent.span.from_expansion() => {
// Double reference might be needed at this point.
- if parent.precedence().order() == PREC_UNAMBIGUOUS {
+ if parent.precedence() == PREC_UNAMBIGUOUS {
// Parentheses would be needed here, don't lint.
*outer_pat = None;
} else {
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index 70f76ced09a4..35dc8e9aa4e2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
if !prefix.is_empty()
&& (
// Precedence of internal expression is less than or equal to precedence of `&expr`.
- arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression)
+ arg_expression.precedence() <= PREC_PREFIX || is_range_literal(arg_expression)
)
{
arg_snip = format!("({arg_snip})").into();
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index d38560998a5a..9c6df4d8ac0d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -117,7 +117,7 @@ pub(super) fn check_with<'tcx, F>(
// it's being passed by value.
let scrutinee = peel_hir_expr_refs(scrutinee).0;
let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
- let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_UNAMBIGUOUS {
+ let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence() < PREC_UNAMBIGUOUS {
format!("({scrutinee_str})")
} else {
scrutinee_str.into()
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index f84d9fadb85c..a0ba2aaf5523 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -58,7 +58,7 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
{
let mut applicability = Applicability::MachineApplicable;
let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability);
- let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) {
+ let suggestion = if !from_macro && exp.precedence() < PREC_PREFIX && !has_enclosing_paren(&snip) {
format!("-({snip})")
} else {
format!("-{snip}")
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 0ac818c21d9b..79baa914b031 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -85,7 +85,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx 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 parent_expr = get_parent_expr(cx, expr);
- let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence().order() > PREC_PREFIX);
+ let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence() > PREC_PREFIX);
if expr_ty == indexed_ty {
if expr_ref_count > indexed_ref_count {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
index fca332dba401..cad15b1e9826 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
@@ -1,7 +1,7 @@
use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
-use rustc_ast::ExprPrecedence;
+use rustc_ast::util::parser::AssocOp;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Node};
use rustc_hir_typeck::cast::check_cast;
@@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
};
if let Node::Expr(parent) = cx.tcx.parent_hir_node(e.hir_id)
- && parent.precedence().order() > ExprPrecedence::Cast.order()
+ && parent.precedence() > AssocOp::As.precedence() as i8
{
sugg = format!("({sugg})");
}
diff --git a/tests/crashes/126359.rs b/tests/crashes/126359.rs
deleted file mode 100644
index 4b28c466b55c..000000000000
--- a/tests/crashes/126359.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ known-bug: rust-lang/rust#126359
-
-struct OppOrder {
- arr: [T; N],
-}
-
-fn main() {
- let _ = OppOrder::<3, u32> { arr: [0, 0, 0] };
-}
diff --git a/tests/crashes/130521.rs b/tests/crashes/130521.rs
index ccc2b444b822..ebcfacf96238 100644
--- a/tests/crashes/130521.rs
+++ b/tests/crashes/130521.rs
@@ -1,7 +1,7 @@
//@ known-bug: #130521
#![feature(dyn_compatible_for_dispatch)]
-struct Vtable(dyn Cap);
+struct Vtable(dyn Cap<'static>);
trait Cap<'a> {}
diff --git a/tests/crashes/131101.rs b/tests/crashes/131101.rs
deleted file mode 100644
index 3ec441101b7d..000000000000
--- a/tests/crashes/131101.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ known-bug: #131101
-trait Foo {
- fn do_x(&self) -> [u8; N];
-}
-
-struct Bar;
-
-impl Foo for Bar {
- fn do_x(&self) -> [u8; 3] {
- [0u8; 3]
- }
-}
diff --git a/tests/rustdoc-ui/unable-fulfill-trait.rs b/tests/rustdoc-ui/unable-fulfill-trait.rs
index 4edc7ab76c19..49dce32072b6 100644
--- a/tests/rustdoc-ui/unable-fulfill-trait.rs
+++ b/tests/rustdoc-ui/unable-fulfill-trait.rs
@@ -3,7 +3,6 @@
pub struct Foo<'a, 'b, T> {
field1: dyn Bar<'a, 'b>,
//~^ ERROR
- //~| ERROR
}
pub trait Bar<'x, 's, U>
diff --git a/tests/rustdoc-ui/unable-fulfill-trait.stderr b/tests/rustdoc-ui/unable-fulfill-trait.stderr
index 12e53546cdac..2786a005cd18 100644
--- a/tests/rustdoc-ui/unable-fulfill-trait.stderr
+++ b/tests/rustdoc-ui/unable-fulfill-trait.stderr
@@ -5,7 +5,7 @@ LL | field1: dyn Bar<'a, 'b>,
| ^^^ expected 1 generic argument
|
note: trait defined here, with 1 generic parameter: `U`
- --> $DIR/unable-fulfill-trait.rs:9:11
+ --> $DIR/unable-fulfill-trait.rs:8:11
|
LL | pub trait Bar<'x, 's, U>
| ^^^ -
@@ -14,13 +14,6 @@ help: add missing generic argument
LL | field1: dyn Bar<'a, 'b, U>,
| +++
-error[E0227]: ambiguous lifetime bound, explicit lifetime bound required
- --> $DIR/unable-fulfill-trait.rs:4:13
- |
-LL | field1: dyn Bar<'a, 'b>,
- | ^^^^^^^^^^^^^^^
+error: aborting due to 1 previous error
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0107, E0227.
-For more information about an error, try `rustc --explain E0107`.
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/array-slice-vec/match_arr_unknown_len.stderr b/tests/ui/array-slice-vec/match_arr_unknown_len.stderr
index 3ed0d6bdf3ac..f617ff339383 100644
--- a/tests/ui/array-slice-vec/match_arr_unknown_len.stderr
+++ b/tests/ui/array-slice-vec/match_arr_unknown_len.stderr
@@ -2,10 +2,7 @@ error[E0308]: mismatched types
--> $DIR/match_arr_unknown_len.rs:3:9
|
LL | [1, 2] => true,
- | ^^^^^^ expected `2`, found `N`
- |
- = note: expected array `[u32; 2]`
- found array `[u32; N]`
+ | ^^^^^^ expected an array with a size of 2, found one with a size of N
error: aborting due to 1 previous error
diff --git a/tests/ui/associated-types/issue-22560.rs b/tests/ui/associated-types/issue-22560.rs
index 44be8817b08c..465aea515eef 100644
--- a/tests/ui/associated-types/issue-22560.rs
+++ b/tests/ui/associated-types/issue-22560.rs
@@ -7,9 +7,6 @@ trait Sub {
}
type Test = dyn Add + Sub;
-//~^ ERROR E0393
-//~| ERROR E0191
-//~| ERROR E0393
-//~| ERROR E0225
+//~^ ERROR E0225
fn main() { }
diff --git a/tests/ui/associated-types/issue-22560.stderr b/tests/ui/associated-types/issue-22560.stderr
index 834040490f94..d0b6adc520c7 100644
--- a/tests/ui/associated-types/issue-22560.stderr
+++ b/tests/ui/associated-types/issue-22560.stderr
@@ -9,56 +9,6 @@ LL | type Test = dyn Add + Sub;
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit
-error[E0191]: the value of the associated types `Output` in `Add`, `Output` in `Sub` must be specified
- --> $DIR/issue-22560.rs:9:17
- |
-LL | type Output;
- | ----------- `Output` defined here
-...
-LL | type Output;
- | ----------- `Output` defined here
-...
-LL | type Test = dyn Add + Sub;
- | ^^^ ^^^ associated type `Output` must be specified
- | |
- | associated type `Output` must be specified
- |
-help: specify the associated types
- |
-LL | type Test = dyn Add