From a4bd5f55e7f93baca5ffc398a429a0039517a318 Mon Sep 17 00:00:00 2001 From: thiago-fealves Date: Sun, 3 May 2026 18:47:34 -0300 Subject: [PATCH 01/13] compiler: suggest `.collect()` when `String` is expected and `Iterator` is found This commit adds a diagnostic suggestion to help users who forget to call `.collect()` when they have an iterator and the function or variable expects a `String`. The logic checks if the expected type is `std::string::String` and if the found type implements the `Iterator` trait, if so the compiler provides a suggestion to add `.collect()` Includes also a UI test to verify if the suggestion appears correctly --- compiler/rustc_hir_typeck/src/demand.rs | 1 + .../src/fn_ctxt/suggestions.rs | 72 +++++++++++++++++++ tests/ui/suggestions/suggest-collect.rs | 16 +++++ tests/ui/suggestions/suggest-collect.stderr | 63 ++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 tests/ui/suggestions/suggest-collect.rs create mode 100644 tests/ui/suggestions/suggest-collect.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 5454b282d5226..6e4d6aa80a63a 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -40,6 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_semicolon_in_repeat_expr(err, expr, expr_ty) || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr) || self.suggest_option_to_bool(err, expr, expr_ty, expected) + || self.suggest_collect(err, expr, expected, expr_ty) || self.suggest_compatible_variants(err, expr, expected, expr_ty) || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty) || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index afd5356d5a1e7..1ce004e11e996 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -250,6 +250,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Suggests calling `.collect()` on an `Iterator` it can be collected in the return type + /// ```compile_fail + /// let x: String = "foo".chars().map(|c| c); // with a .collect() here the code compiles + /// ``` + pub(crate) fn suggest_collect( + &self, + err: &mut Diag<'_>, + expr: &hir::Expr<'_>, + expected_type: Ty<'tcx>, + found_type: Ty<'tcx>, + ) -> bool { + let tcx = self.tcx; + let expected = self.resolve_vars_if_possible(expected_type); + let found = self.resolve_vars_if_possible(found_type); + + if expected.references_error() || found.references_error() { + return false; + } + + if expected.is_unit() { + return false; + } + + let Some(iterator_trait_id) = tcx.get_diagnostic_item(sym::Iterator) else { + return false; + }; + + if !self + .infcx + .type_implements_trait(iterator_trait_id, [found], self.param_env) + .must_apply_modulo_regions() + { + return false; + } + + let Some(from_iterator_trait_id) = tcx.get_diagnostic_item(sym::FromIterator) else { + return false; + }; + + let Some(iterator_item_id) = tcx + .associated_items(iterator_trait_id) + .in_definition_order() + .find(|item| item.name() == sym::Item) + .map(|item| item.def_id) + else { + return false; + }; + + let item_type = Ty::new_projection(tcx, iterator_item_id, [found]); + let item_type = + self.normalize(expr.span, rustc_middle::ty::Unnormalized::new_wip(item_type)); + + let can_collect = self + .infcx + .type_implements_trait(from_iterator_trait_id, [expected, item_type], self.param_env) + .may_apply(); + + if can_collect { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "consider using `.collect()` to convert the `Iterator` into a `{expected}`" + ), + ".collect()", + rustc_errors::Applicability::MaybeIncorrect, + ); + return true; + } + + false + } + pub(crate) fn suggest_remove_last_method_call( &self, err: &mut Diag<'_>, diff --git a/tests/ui/suggestions/suggest-collect.rs b/tests/ui/suggestions/suggest-collect.rs new file mode 100644 index 0000000000000..44e8909fca20f --- /dev/null +++ b/tests/ui/suggestions/suggest-collect.rs @@ -0,0 +1,16 @@ +fn main() { + let _x: String = "hello".chars().map(|c| c); + //~^ ERROR mismatched types + //~| HELP consider using `.collect()` to convert the `Iterator` into a `String` + + let _y: Vec = vec![1, 2, 3].into_iter().map(|x| x); + //~^ ERROR mismatched types + //~| HELP consider using `.collect()` to convert the `Iterator` into a `Vec` + + let res: Result, _> = ["1", "2"].into_iter().map(|s| s.parse::()); + //~^ ERROR mismatched types + //~| HELP consider using `.collect()` to convert the `Iterator` into a `Result, _>` + let (a, b): (Vec, Vec) = vec![1, 2].into_iter().map(|x| (x, x)); + //~^ ERROR mismatched types + //~| HELP consider using `.collect()` to convert the `Iterator` into a `(Vec, Vec)` +} diff --git a/tests/ui/suggestions/suggest-collect.stderr b/tests/ui/suggestions/suggest-collect.stderr new file mode 100644 index 0000000000000..a7bca2bbcaa7b --- /dev/null +++ b/tests/ui/suggestions/suggest-collect.stderr @@ -0,0 +1,63 @@ +error[E0308]: mismatched types + --> $DIR/suggest-collect.rs:2:22 + | +LL | let _x: String = "hello".chars().map(|c| c); + | ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `String`, found `Map, {closure@...}>` + | | + | expected due to this + | + = note: expected struct `String` + found struct `Map, {closure@$DIR/suggest-collect.rs:2:42: 2:45}>` +help: consider using `.collect()` to convert the `Iterator` into a `String` + | +LL | let _x: String = "hello".chars().map(|c| c).collect(); + | ++++++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-collect.rs:6:24 + | +LL | let _y: Vec = vec![1, 2, 3].into_iter().map(|x| x); + | -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Vec`, found `Map, {closure@...}>` + | | + | expected due to this + | + = note: expected struct `Vec` + found struct `Map, {closure@$DIR/suggest-collect.rs:6:54: 6:57}>` +help: consider using `.collect()` to convert the `Iterator` into a `Vec` + | +LL | let _y: Vec = vec![1, 2, 3].into_iter().map(|x| x).collect(); + | ++++++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-collect.rs:10:36 + | +LL | let res: Result, _> = ["1", "2"].into_iter().map(|s| s.parse::()); + | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result, _>`, found `Map, {closure@...}>` + | | + | expected due to this + | + = note: expected enum `Result, _>` + found struct `Map, {closure@$DIR/suggest-collect.rs:10:63: 10:66}>` +help: consider using `.collect()` to convert the `Iterator` into a `Result, _>` + | +LL | let res: Result, _> = ["1", "2"].into_iter().map(|s| s.parse::()).collect(); + | ++++++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-collect.rs:13:40 + | +LL | let (a, b): (Vec, Vec) = vec![1, 2].into_iter().map(|x| (x, x)); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(Vec, Vec)`, found `Map, {closure@...}>` + | | + | expected due to this + | + = note: expected tuple `(Vec, Vec)` + found struct `Map, {closure@$DIR/suggest-collect.rs:13:67: 13:70}>` +help: consider using `.collect()` to convert the `Iterator` into a `(Vec, Vec)` + | +LL | let (a, b): (Vec, Vec) = vec![1, 2].into_iter().map(|x| (x, x)).collect(); + | ++++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From e1941ffee672efea442b269011d6b40be6dbbff9 Mon Sep 17 00:00:00 2001 From: Thiago Felipe Alves do Carmo <63806038+thiago-fealves@users.noreply.github.com> Date: Mon, 4 May 2026 15:47:45 +0000 Subject: [PATCH 02/13] Update compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs Co-authored-by: Qai Juang --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1ce004e11e996..77aa9fb3daab8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -265,11 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected = self.resolve_vars_if_possible(expected_type); let found = self.resolve_vars_if_possible(found_type); - if expected.references_error() || found.references_error() { - return false; - } - - if expected.is_unit() { + if expected.references_error() || found.references_error() || expected.is_unit() { return false; } From 31e0383ea645f38402fe2bce2859490b6a55d965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 May 2026 02:29:42 +0000 Subject: [PATCH 03/13] rustfmt matches with comments in or-patterns Using https://github.com/rust-lang/rustfmt/pull/6893, reformat the codebase. The result is that matches that *would have* been formatted under normal circumstances get their expected format. These match expressions were being entirely skipped because they contain or-patterns with comments in between patterns, causing rustfmt to bail out entirely. The or-patterns with comments themselves remain untouched, but now the match arm bodies and other patterns without comments do get formatted under that PR. Because the fix in rustfmt isn't landed yet, I reworked some of the or-patterns with comments so that formatting doesn't regress. Tried doing this only in larger blocks that are more likely to regress in the meantime. --- compiler/rustc_ast/src/ast.rs | 20 +- compiler/rustc_ast/src/token.rs | 47 ++-- compiler/rustc_borrowck/src/def_use.rs | 7 +- compiler/rustc_borrowck/src/lib.rs | 43 ++-- .../src/polonius/legacy/loan_invalidations.rs | 8 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 33 ++- .../src/const_eval/valtrees.rs | 31 +-- compiler/rustc_hir/src/hir.rs | 19 +- .../rustc_hir_typeck/src/method/suggest.rs | 34 +-- compiler/rustc_lint/src/builtin.rs | 3 +- compiler/rustc_lint/src/lifetime_syntax.rs | 17 +- compiler/rustc_lint/src/unused.rs | 38 ++- compiler/rustc_middle/src/ty/sty.rs | 10 +- .../src/move_paths/builder.rs | 7 +- .../src/dataflow_const_prop.rs | 9 +- .../src/known_panics_lint.rs | 4 +- compiler/rustc_mir_transform/src/validate.rs | 23 +- .../rustc_parse/src/parser/diagnostics.rs | 36 +-- compiler/rustc_parse/src/parser/expr.rs | 7 +- .../rustc_parse/src/parser/nonterminal.rs | 14 +- compiler/rustc_resolve/src/late.rs | 12 +- .../rustc_resolve/src/late/diagnostics.rs | 29 ++- compiler/rustc_resolve/src/macros.rs | 3 +- .../traits/fulfillment_errors.rs | 232 ++++++++++-------- .../src/traits/auto_trait.rs | 31 +-- .../src/traits/dyn_compatibility.rs | 37 ++- .../src/traits/fulfill.rs | 2 +- .../src/maybe_transmutable/mod.rs | 2 +- compiler/rustc_ty_utils/src/sig_types.rs | 43 +++- 29 files changed, 456 insertions(+), 345 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 52b54655d1ca1..bc9f142e4a25c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1557,12 +1557,10 @@ impl Expr { } match &self.kind { - ExprKind::Closure(closure) => { - match closure.fn_decl.output { - FnRetTy::Default(_) => ExprPrecedence::Jump, - FnRetTy::Ty(_) => prefix_attrs_precedence(&self.attrs), - } - } + ExprKind::Closure(closure) => match closure.fn_decl.output { + FnRetTy::Default(_) => ExprPrecedence::Jump, + FnRetTy::Ty(_) => prefix_attrs_precedence(&self.attrs), + }, ExprKind::Break(_ /*label*/, value) | ExprKind::Ret(value) @@ -1584,18 +1582,16 @@ impl Expr { ExprKind::Binary(op, ..) => op.node.precedence(), ExprKind::Cast(..) => ExprPrecedence::Cast, - ExprKind::Assign(..) | - ExprKind::AssignOp(..) => ExprPrecedence::Assign, + ExprKind::Assign(..) | ExprKind::AssignOp(..) => ExprPrecedence::Assign, // Unary, prefix - ExprKind::AddrOf(..) + ExprKind::AddrOf(..) => ExprPrecedence::Prefix, + // 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::Move(..) - | ExprKind::Unary(..) => ExprPrecedence::Prefix, + ExprKind::Let(..) | ExprKind::Move(..) | ExprKind::Unary(..) => ExprPrecedence::Prefix, // Need parens if and only if there are prefix attributes. ExprKind::Array(_) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 743e60d2f3bb2..e1746039963f4 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -688,10 +688,10 @@ impl Token { Lifetime(..) | // labeled loop Pound => true, // expression attributes OpenInvisible(InvisibleOrigin::MetaVar( - MetaVarKind::Block | - MetaVarKind::Expr { .. } | - MetaVarKind::Literal | - MetaVarKind::Path + MetaVarKind::Block + | MetaVarKind::Expr { .. } + | MetaVarKind::Literal + | MetaVarKind::Path, )) => true, _ => false, } @@ -717,12 +717,12 @@ impl Token { Shl => true, // path (double UFCS) Or => matches!(pat_kind, PatWithOr), // leading vert `|` or-pattern OpenInvisible(InvisibleOrigin::MetaVar( - MetaVarKind::Expr { .. } | - MetaVarKind::Literal | - MetaVarKind::Meta { .. } | - MetaVarKind::Pat(_) | - MetaVarKind::Path | - MetaVarKind::Ty { .. } + MetaVarKind::Expr { .. } + | MetaVarKind::Literal + | MetaVarKind::Meta { .. } + | MetaVarKind::Pat(_) + | MetaVarKind::Path + | MetaVarKind::Ty { .. }, )) => true, _ => false, } @@ -733,20 +733,19 @@ impl Token { match self.uninterpolate().kind { Ident(name, is_raw) => ident_can_begin_type(name, self.span, is_raw), // type name or keyword - OpenParen | // tuple - OpenBracket | // array - Bang | // never - Star | // raw pointer - And | // reference - AndAnd | // double reference - Question | // maybe bound in trait object - Lifetime(..) | // lifetime bound in trait object - Lt | Shl | // associated path - PathSep => true, // global path - OpenInvisible(InvisibleOrigin::MetaVar( - MetaVarKind::Ty { .. } | - MetaVarKind::Path - )) => true, + OpenParen // tuple + | OpenBracket // array + | Bang // never + | Star // raw pointer + | And // reference + | AndAnd // double reference + | Question // maybe bound in trait object + | Lifetime(..) // lifetime bound in trait object + | Lt | Shl // associated path + | PathSep => true, // global path + OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Ty { .. } | MetaVarKind::Path)) => { + true + } // For anonymous structs or unions, which only appear in specific positions // (type of struct fields or union fields), we don't consider them as regular types _ => false, diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index 502265a83523e..8813ef5249262 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -60,8 +60,7 @@ pub(crate) fn categorize(context: PlaceContext) -> Option { PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) | - PlaceContext::MutatingUse(MutatingUseContext::Retag) => - Some(DefUse::Use), + PlaceContext::MutatingUse(MutatingUseContext::Retag) => Some(DefUse::Use), /////////////////////////////////////////////////////////////////////////// // DROP USES @@ -70,9 +69,7 @@ pub(crate) fn categorize(context: PlaceContext) -> Option { // call to `std::mem::drop()`). For the purposes of NLL, // uses in drop are special because `#[may_dangle]` // attributes can affect whether lifetimes must be live. - - PlaceContext::MutatingUse(MutatingUseContext::Drop) => - Some(DefUse::Drop), + PlaceContext::MutatingUse(MutatingUseContext::Drop) => Some(DefUse::Drop), // Debug info is neither def nor use. PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8b9f4291603a9..107ca87376015 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -833,19 +833,21 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( span, "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", - ) - } + ), + }, // Only relevant for mir typeck - StatementKind::AscribeUserType(..) + StatementKind::AscribeUserType(..) => {} // Only relevant for liveness and unsafeck - | StatementKind::PlaceMention(..) + StatementKind::PlaceMention(..) => {} // Doesn't have any language semantics - | StatementKind::Coverage(..) + StatementKind::Coverage(..) => {} // These do not actually affect borrowck - | StatementKind::ConstEvalCounter - | StatementKind::StorageLive(..) => {} + StatementKind::ConstEvalCounter | StatementKind::StorageLive(..) => {} // This does not affect borrowck - StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => { + StatementKind::BackwardIncompatibleDropHint { + place, + reason: BackwardIncompatibleDropReason::Edition2024, + } => { self.check_backward_incompatible_drop(location, **place, state); } StatementKind::StorageDead(local) => { @@ -857,8 +859,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, state, ); } - StatementKind::Nop - | StatementKind::SetDiscriminant { .. } => { + StatementKind::Nop | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") } } @@ -2243,10 +2244,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => - // assigning to (P->variant) is okay if assigning to `P` is okay - // - // FIXME: is this true even if P is an adt with a dtor? - { } + // assigning to (P->variant) is okay if assigning to `P` is okay + // + // FIXME: is this true even if P is an adt with a dtor? + {} ProjectionElem::UnwrapUnsafeBinder(_) => { check_parent_of_field(self, location, place_base, span, state); @@ -2255,8 +2256,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // assigning to (*P) requires P to be initialized ProjectionElem::Deref => { self.check_if_full_path_is_moved( - location, InitializationRequiringAction::Use, - (place_base, span), state); + location, + InitializationRequiringAction::Use, + (place_base, span), + state, + ); // (base initialized; no need to // recur further) break; @@ -2275,8 +2279,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { match base_ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( - location, InitializationRequiringAction::Assignment, - (place_base, span), state); + location, + InitializationRequiringAction::Assignment, + (place_base, span), + state, + ); // (base initialized; no need to // recur further) diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 31df87dabf815..5a33b2d5bbe5b 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -56,11 +56,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { StatementKind::Intrinsic(NonDivergingIntrinsic::Assume(op)) => { self.consume_operand(location, op); } - StatementKind::Intrinsic(NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { - src, - dst, - count, - })) => { + StatementKind::Intrinsic(NonDivergingIntrinsic::CopyNonOverlapping( + CopyNonOverlapping { src, dst, count }, + )) => { self.consume_operand(location, src); self.consume_operand(location, dst); self.consume_operand(location, count); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 0feb22e8d1d70..90ac8c89ba9ad 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -454,13 +454,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Pair(lldata, llextra) } mir::CastKind::PointerCoercion( - PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _ + PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, + _, ) => { bug!("{kind:?} is for borrowck, and should never appear in codegen"); } - mir::CastKind::PtrToPtr - if bx.cx().is_backend_scalar_pair(operand.layout) => - { + mir::CastKind::PtrToPtr if bx.cx().is_backend_scalar_pair(operand.layout) => { if let OperandValue::Pair(data_ptr, meta) = operand.val { if bx.cx().is_backend_scalar_pair(cast) { OperandValue::Pair(data_ptr, meta) @@ -483,7 +482,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // path as the other integer-to-X casts. | mir::CastKind::PointerWithExposedProvenance => { let imm = operand.immediate(); - let abi::BackendRepr::Scalar(from_scalar) = operand.layout.backend_repr else { + let abi::BackendRepr::Scalar(from_scalar) = operand.layout.backend_repr + else { bug!("Found non-scalar for operand {operand:?}"); }; let from_backend_ty = bx.cx().immediate_backend_type(operand.layout); @@ -498,11 +498,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("Found non-scalar for cast {cast:?}"); }; - self.cast_immediate(bx, imm, from_scalar, from_backend_ty, to_scalar, to_backend_ty) - .map(OperandValue::Immediate) - .unwrap_or_else(|| { - bug!("Unsupported cast of {operand:?} to {cast:?}"); - }) + self.cast_immediate( + bx, + imm, + from_scalar, + from_backend_ty, + to_scalar, + to_backend_ty, + ) + .map(OperandValue::Immediate) + .unwrap_or_else(|| { + bug!("Unsupported cast of {operand:?} to {cast:?}"); + }) } mir::CastKind::Transmute | mir::CastKind::Subtype => { self.codegen_transmute_operand(bx, operand, cast) @@ -553,6 +560,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { move_annotation: None, } } + mir::Rvalue::BinaryOp(op, (ref lhs, ref rhs)) => { let lhs = self.codegen_operand(bx, lhs); let rhs = self.codegen_operand(bx, rhs); @@ -666,7 +674,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; OperandRef { val: OperandValue::Immediate(static_), layout, move_annotation: None } } + mir::Rvalue::Use(ref operand, _) => self.codegen_operand(bx, operand), + mir::Rvalue::Repeat(ref elem, len_const) => { // All arrays have `BackendRepr::Memory`, so only the ZST cases // end up here. Anything else forces the destination local to be @@ -682,6 +692,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { move_annotation: None, } } + mir::Rvalue::Aggregate(ref kind, ref fields) => { let (variant_index, active_field_index) = match **kind { mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { @@ -719,12 +730,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } + mir::Rvalue::WrapUnsafeBinder(ref operand, binder_ty) => { let operand = self.codegen_operand(bx, operand); let binder_ty = self.monomorphize(binder_ty); let layout = bx.cx().layout_of(binder_ty); OperandRef { val: operand.val, layout, move_annotation: None } } + mir::Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"), } } diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 0169dc7ed99df..9fe3bff071f15 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -109,8 +109,7 @@ fn const_to_valtree_inner<'tcx>( // switch to the base type. place.layout = ecx.layout_of(*base).unwrap(); ensure_sufficient_stack(|| const_to_valtree_inner(ecx, &place, num_nodes)) - }, - + } ty::RawPtr(_, _) => { // Not all raw pointers are allowed, as we cannot properly test them for @@ -137,23 +136,19 @@ fn const_to_valtree_inner<'tcx>( // agree with runtime equality tests. ty::FnPtr(..) => Err(ValTreeCreationError::NonSupportedType(ty)), - ty::Ref(_, _, _) => { + ty::Ref(_, _, _) => { let derefd_place = ecx.deref_pointer(place).report_err()?; const_to_valtree_inner(ecx, &derefd_place, num_nodes) } - ty::Str | ty::Slice(_) | ty::Array(_, _) => { - slice_branches(ecx, place, num_nodes) - } + ty::Str | ty::Slice(_) | ty::Array(_, _) => slice_branches(ecx, place, num_nodes), // Trait objects are not allowed in type level constants, as we have no concept for // resolving their backing type, even if we can do that at const eval time. We may // hypothetically be able to allow `dyn StructuralPartialEq` trait objects in the future, // but it is unclear if this is useful. ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType(ty)), - ty::Tuple(elem_tys) => { - branches(ecx, place, elem_tys.len(), None, num_nodes) - } + ty::Tuple(elem_tys) => branches(ecx, place, elem_tys.len(), None, num_nodes), ty::Adt(def, _) => { if def.is_union() { @@ -163,22 +158,30 @@ fn const_to_valtree_inner<'tcx>( } let variant = ecx.read_discriminant(place).report_err()?; - branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) + branches( + ecx, + place, + def.variant(variant).fields.len(), + def.is_enum().then_some(variant), + num_nodes, + ) } + // FIXME(oli-obk): we could look behind opaque types + ty::Alias(..) => Err(ValTreeCreationError::NonSupportedType(ty)), + + // FIXME(oli-obk): we can probably encode closures just like structs + ty::Closure(..) => Err(ValTreeCreationError::NonSupportedType(ty)), + ty::Never | ty::Error(_) | ty::Foreign(..) | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) - // FIXME(oli-obk): we could look behind opaque types - | ty::Alias(..) | ty::Param(_) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(_) - // FIXME(oli-obk): we can probably encode closures just like structs - | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 501ecadd392fc..55153001d7ccf 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2471,12 +2471,10 @@ impl Expr<'_> { }; match &self.kind { - ExprKind::Closure(closure) => { - match closure.fn_decl.output { - FnRetTy::DefaultReturn(_) => ExprPrecedence::Jump, - FnRetTy::Return(_) => prefix_attrs_precedence(), - } - } + ExprKind::Closure(closure) => match closure.fn_decl.output { + FnRetTy::DefaultReturn(_) => ExprPrecedence::Jump, + FnRetTy::Return(_) => prefix_attrs_precedence(), + }, ExprKind::Break(..) | ExprKind::Ret(..) @@ -2487,17 +2485,16 @@ impl Expr<'_> { ExprKind::Binary(op, ..) => op.node.precedence(), ExprKind::Cast(..) => ExprPrecedence::Cast, - ExprKind::Assign(..) | - ExprKind::AssignOp(..) => ExprPrecedence::Assign, + ExprKind::Assign(..) | ExprKind::AssignOp(..) => ExprPrecedence::Assign, // Unary, prefix - ExprKind::AddrOf(..) + ExprKind::AddrOf(..) => ExprPrecedence::Prefix, + // 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(..) => ExprPrecedence::Prefix, + ExprKind::Let(..) | ExprKind::Unary(..) => ExprPrecedence::Prefix, // Need parens if and only if there are prefix attributes. ExprKind::Array(_) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d773420512590..0bdd6ce4b05cc 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1903,10 +1903,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (FxIndexSet::default(), FxIndexSet::default(), Vec::new()) }); entry.0.insert(cause_span); - entry.1.insert(( - cause_span, - cause_msg, - )); + entry.1.insert((cause_span, cause_msg)); entry.2.push(p); skip_list.insert(p); manually_impl = true; @@ -1918,16 +1915,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: item_span, .. })) => { - let sized_pred = - unsatisfied_predicates.iter().any(|(pred, _, _)| { - match pred.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) - && pred.polarity == ty::PredicatePolarity::Positive - } - _ => false, + let sized_pred = unsatisfied_predicates.iter().any(|(pred, _, _)| { + match pred.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) + && pred.polarity == ty::PredicatePolarity::Positive } - }); + _ => false, + } + }); for param in generics.params { if param.span == cause_span && sized_pred { let (sp, sugg) = match param.colon_span { @@ -1954,7 +1950,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { entry.2.push(p); if cause_span != *item_span { entry.0.insert(cause_span); - entry.1.insert((cause_span, "unsatisfied trait bound introduced here".to_string())); + entry.1.insert(( + cause_span, + "unsatisfied trait bound introduced here".to_string(), + )); } else { if let Some(of_trait) = of_trait { entry.0.insert(of_trait.trait_ref.path.span); @@ -1967,7 +1966,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { entry.1.insert((self_ty.span, String::new())); } Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait { is_auto: rustc_ast::ast::IsAuto::Yes, .. }, + kind: hir::ItemKind::Trait { is_auto: rustc_ast::ast::IsAuto::Yes, .. }, span: item_span, .. })) => { @@ -1994,7 +1993,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); entry.0.insert(cause_span); entry.1.insert((ident.span, String::new())); - entry.1.insert((cause_span, "unsatisfied trait bound introduced here".to_string())); + entry.1.insert(( + cause_span, + "unsatisfied trait bound introduced here".to_string(), + )); entry.2.push(p); } _ => { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ea0791783a642..0e4ee0a557030 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1510,8 +1510,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { for &(predicate, span) in predicates.predicates { let predicate_kind_name = match predicate.kind().skip_binder() { ClauseKind::Trait(..) => "trait", - ClauseKind::TypeOutlives(..) | - ClauseKind::RegionOutlives(..) => "lifetime", + ClauseKind::TypeOutlives(..) | ClauseKind::RegionOutlives(..) => "lifetime", ClauseKind::UnstableFeature(_) // `ConstArgHasType` is never global as `ct` is always a param diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs index 6c65673acd0d8..1f3ecb03ebfc6 100644 --- a/compiler/rustc_lint/src/lifetime_syntax.rs +++ b/compiler/rustc_lint/src/lifetime_syntax.rs @@ -169,28 +169,19 @@ impl LifetimeSyntaxCategory { // E.g. `ContainsLifetime<'_>`. (ExplicitAnonymous, Path { .. }) | // E.g. `+ '_`, `+ use<'_>`. - (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => { - Some(Self::Elided) - } + (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => Some(Self::Elided), // E.g. `ContainsLifetime`. - (Implicit, Path { .. }) => { - Some(Self::Hidden) - } + (Implicit, Path { .. }) => Some(Self::Hidden), // E.g. `&'a T`. (ExplicitBound, Reference) | // E.g. `ContainsLifetime<'a>`. (ExplicitBound, Path { .. }) | // E.g. `+ 'a`, `+ use<'a>`. - (ExplicitBound, OutlivesBound | PreciseCapturing) => { - Some(Self::Named) - } + (ExplicitBound, OutlivesBound | PreciseCapturing) => Some(Self::Named), - (Implicit, OutlivesBound | PreciseCapturing) | - (_, Other) => { - None - } + (Implicit, OutlivesBound | PreciseCapturing) | (_, Other) => None, } } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0cb7b4cce8462..ed7afa1c711de 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -761,23 +761,39 @@ impl EarlyLintPass for UnusedParens { let keep_space = (false, false); match &p.kind { // Do not lint on `(..)` as that will result in the other arms being useless. - Paren(_) + Paren(_) => {} // The other cases do not contain sub-patterns. - | Missing | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) - | Path(..) | Err(_) => {}, + Missing + | Wild + | Never + | Rest + | Expr(..) + | MacCall(..) + | Range(..) + | Ident(.., None) + | Path(..) + | Err(_) => {} // These are list-like patterns; parens can always be removed. - TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { - self.check_unused_parens_pat(cx, p, false, false, keep_space); - }, - Struct(_, _, fps, _) => for f in fps { - self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space); - }, + TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => { + for p in ps { + self.check_unused_parens_pat(cx, p, false, false, keep_space); + } + } + Struct(_, _, fps, _) => { + for f in fps { + self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space); + } + } // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106. - Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => self.check_unused_parens_pat(cx, p, true, false, keep_space), + Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => { + self.check_unused_parens_pat(cx, p, true, false, keep_space) + } // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342. // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106. // FIXME(pin_ergonomics): check pinned patterns - Ref(p, _, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space), + Ref(p, _, m) => { + self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space) + } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 112ad65e19bff..f208182c997f0 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1751,15 +1751,15 @@ impl<'tcx> Ty<'tcx> { | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never - | ty::Error(_) + | ty::Error(_) => Ok(tcx.types.unit), // Extern types have metadata = (). - | ty::Foreign(..) + ty::Foreign(..) => Ok(tcx.types.unit), // If returned by `struct_tail_raw` this is a unit struct // without any fields, or not a struct, and therefore is Sized. - | ty::Adt(..) + ty::Adt(..) => Ok(tcx.types.unit), // If returned by `struct_tail_raw` this is the empty tuple, // a.k.a. unit type, which is Sized - | ty::Tuple(..) => Ok(tcx.types.unit), + ty::Tuple(..) => Ok(tcx.types.unit), ty::Str | ty::Slice(_) => Ok(tcx.types.usize), @@ -1772,7 +1772,7 @@ impl<'tcx> Ty<'tcx> { // metadata of `tail`. ty::Param(_) | ty::Alias(..) => Err(tail), - | ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"), + ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"), ty::Infer(ty::TyVar(_)) | ty::Pat(..) diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 905f36a3edb06..5982475361ca8 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -450,12 +450,12 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { match term.kind { TerminatorKind::Goto { target: _ } | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::FalseUnwind { .. } => {} // In some sense returning moves the return place into the current // call's destination, however, since there are no statements after // this that could possibly access the return place, this doesn't // need recording. - | TerminatorKind::Return + TerminatorKind::Return | TerminatorKind::UnwindResume | TerminatorKind::UnwindTerminate(_) | TerminatorKind::CoroutineDrop @@ -510,8 +510,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { } => { for op in operands { match *op { - InlineAsmOperand::In { reg: _, ref value } - => { + InlineAsmOperand::In { reg: _, ref value } => { self.gather_operand(value); } InlineAsmOperand::Out { reg: _, late: _, place, .. } => { diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 1c465977ec6ca..c83cfba34f790 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -871,8 +871,9 @@ fn try_write_constant<'tcx>( ty::FnDef(..) => {} // Those are scalars, must be handled above. - ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => - throw_machine_stop_str!("primitive type with provenance"), + ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { + throw_machine_stop_str!("primitive type with provenance") + } ty::Tuple(elem_tys) => { for (i, elem) in elem_tys.iter().enumerate() { @@ -898,7 +899,9 @@ fn try_write_constant<'tcx>( throw_machine_stop_str!("discriminant with provenance") }; let discr_bits = discr.to_bits(discr.size()); - let Some((variant, _)) = def.discriminants(*ecx.tcx).find(|(_, var)| discr_bits == var.val) else { + let Some((variant, _)) = + def.discriminants(*ecx.tcx).find(|(_, var)| discr_bits == var.val) + else { throw_machine_stop_str!("illegal discriminant for enum") }; let Some(variant_place) = map.apply(place, TrackElem::Variant(variant)) else { diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 6c2ca9166b101..9f187c5c75959 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -955,7 +955,9 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { self.can_const_prop[local] = ConstPropMode::NoPropagation; } MutatingUse(MutatingUseContext::Projection) - | NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"), + | NonMutatingUse(NonMutatingUseContext::Projection) => { + bug!("visit_place should not pass {context:?} for {local:?}") + } } } } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 746662e6a302f..df789618ad908 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -145,26 +145,21 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> { let src = self.body.basic_blocks.get(location.block).unwrap(); match (src.is_cleanup, bb.is_cleanup, edge_kind) { // Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges - (false, false, EdgeKind::Normal) + (false, false, EdgeKind::Normal) => {} // Cleanup blocks can jump to cleanup blocks along non-unwind edges - | (true, true, EdgeKind::Normal) => {} + (true, true, EdgeKind::Normal) => {} // Non-cleanup blocks can jump to cleanup blocks along unwind edges (false, true, EdgeKind::Unwind) => { self.unwind_edge_count += 1; } // All other jumps are invalid - _ => { - self.fail( - location, - format!( - "{:?} edge to {:?} violates unwind invariants (cleanup {:?} -> {:?})", - edge_kind, - bb, - src.is_cleanup, - bb.is_cleanup, - ) - ) - } + _ => self.fail( + location, + format!( + "{:?} edge to {:?} violates unwind invariants (cleanup {:?} -> {:?})", + edge_kind, bb, src.is_cleanup, bb.is_cleanup, + ), + ), } } else { self.fail(location, format!("encountered jump to invalid basic block {bb:?}")) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 47ac91feefd4b..f935f43d336c8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1349,19 +1349,19 @@ impl<'a> Parser<'a> { (BinOpKind::Gt, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) | (BinOpKind::Ge, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) => { let expr_to_str = |e: &Expr| { - self.span_to_snippet(e.span) - .unwrap_or_else(|_| pprust::expr_to_string(e)) + self.span_to_snippet(e.span).unwrap_or_else(|_| pprust::expr_to_string(e)) }; - err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::SplitComparison { - span: inner_op.span.shrink_to_hi(), - middle_term: expr_to_str(r1), - }); + err.chaining_sugg = + Some(ComparisonOperatorsCannotBeChainedSugg::SplitComparison { + span: inner_op.span.shrink_to_hi(), + middle_term: expr_to_str(r1), + }); false // Keep the current parse behavior, where the AST is `(x < y) < z`. } // `x == y < z` ( BinOpKind::Eq, - AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge) + AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge), ) => { // Consume `z`/outer-op-rhs. let snapshot = self.create_snapshot_for_diagnostic(); @@ -1369,10 +1369,11 @@ impl<'a> Parser<'a> { Ok(r2) => { // We are sure that outer-op-rhs could be consumed, the suggestion is // likely correct. - err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize { - left: r1.span.shrink_to_lo(), - right: r2.span.shrink_to_hi(), - }); + err.chaining_sugg = + Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize { + left: r1.span.shrink_to_lo(), + right: r2.span.shrink_to_hi(), + }); true } Err(expr_err) => { @@ -1385,17 +1386,18 @@ impl<'a> Parser<'a> { // `x > y == z` ( BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge, - AssocOp::Binary(BinOpKind::Eq) + AssocOp::Binary(BinOpKind::Eq), ) => { let snapshot = self.create_snapshot_for_diagnostic(); // At this point it is always valid to enclose the lhs in parentheses, no // further checks are necessary. match self.parse_expr() { Ok(_) => { - err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize { - left: l1.span.shrink_to_lo(), - right: r1.span.shrink_to_hi(), - }); + err.chaining_sugg = + Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize { + left: l1.span.shrink_to_lo(), + right: r1.span.shrink_to_hi(), + }); true } Err(expr_err) => { @@ -1405,7 +1407,7 @@ impl<'a> Parser<'a> { } } } - _ => false + _ => false, }; } false diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e5de0d972df6a..957ed9ab55e0a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1107,9 +1107,7 @@ impl<'a> Parser<'a> { match &*components { // 1e2 - [IdentLike(i)] => { - DestructuredFloat::Single(Symbol::intern(i), span) - } + [IdentLike(i)] => DestructuredFloat::Single(Symbol::intern(i), span), // 1. [IdentLike(left), Punct('.')] => { let (left_span, dot_span) = if can_take_span_apart() { @@ -1126,7 +1124,8 @@ impl<'a> Parser<'a> { [IdentLike(left), Punct('.'), IdentLike(right)] => { let (left_span, dot_span, right_span) = if can_take_span_apart() { let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len())); - let dot_span = span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1)); + let dot_span = + span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1)); let right_span = span.with_lo(dot_span.hi()); (left_span, dot_span, right_span) } else { diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 6ca7f89c76776..1b1d7ddb24b1b 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -26,18 +26,16 @@ impl<'a> Parser<'a> { | MetaVarKind::Pat(_) | MetaVarKind::Expr { .. } | MetaVarKind::Ty { .. } - | MetaVarKind::Literal // `true`, `false` | MetaVarKind::Meta { .. } | MetaVarKind::Path => true, + // `true`, `false` + MetaVarKind::Literal => true, - MetaVarKind::Item - | MetaVarKind::Block - | MetaVarKind::Vis - | MetaVarKind::Guard => false, + MetaVarKind::Item | MetaVarKind::Block | MetaVarKind::Vis | MetaVarKind::Guard => { + false + } - MetaVarKind::Ident - | MetaVarKind::Lifetime - | MetaVarKind::TT => unreachable!(), + MetaVarKind::Ident | MetaVarKind::Lifetime | MetaVarKind::TT => unreachable!(), } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index e8bd3abdc621e..a1d496337dbb6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4397,7 +4397,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } Some(res) } - Res::Def(DefKind::Ctor(..) | DefKind::Const { .. } | DefKind::AssocConst { .. } | DefKind::Static { .. }, _) => { + Res::Def( + DefKind::Ctor(..) + | DefKind::Const { .. } + | DefKind::AssocConst { .. } + | DefKind::Static { .. }, + _, + ) => { // This is unambiguously a fresh binding, either syntactically // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves // to something unusable as a pattern (e.g., constructor function), @@ -4429,7 +4435,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { article: res.article(), shadowed_binding: res, shadowed_binding_span: self.r.def_span(def_id), - } + }, ); None } @@ -4442,7 +4448,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // so delay a bug instead of ICEing. self.r.dcx().span_delayed_bug( ident.span, - "unexpected `SelfCtor` in pattern, expected identifier" + "unexpected `SelfCtor` in pattern, expected identifier", ); None } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 10c864226d220..0f3d256f5158d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3468,7 +3468,11 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if !self.diag_metadata.currently_processing_generic_args && !single_uppercase_char { return (None, None); } - match (self.diag_metadata.current_item, single_uppercase_char, self.diag_metadata.currently_processing_generic_args) { + match ( + self.diag_metadata.current_item, + single_uppercase_char, + self.diag_metadata.currently_processing_generic_args, + ) { (Some(Item { kind: ItemKind::Fn(fn_), .. }), _, _) if fn_.ident.name == sym::main => { // Ignore `fn main()` as we don't want to suggest `fn main()` } @@ -3481,7 +3485,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { | kind @ ItemKind::Union(..), .. }), - true, _ + true, + _, ) // Without the 2nd `true`, we'd suggest `impl ` for `impl T` when a type `T` isn't found | (Some(Item { kind: kind @ ItemKind::Impl(..), .. }), true, true) @@ -3501,7 +3506,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let (msg, sugg) = match source { PathSource::Type | PathSource::PreciseCapturingArg(TypeNS) => { - if let Some(err) = self.detect_and_suggest_const_parameter_error(path, source) { + if let Some(err) = + self.detect_and_suggest_const_parameter_error(path, source) + { return (None, Some(err)); } ("you might be missing a type parameter", ident) @@ -3516,8 +3523,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let span = if let [.., bound] = ¶m.bounds[..] { bound.span() } else if let GenericParam { - kind: GenericParamKind::Const { ty, span: _, default }, .. - } = param { + kind: GenericParamKind::Const { ty, span: _, default }, + .. + } = param + { default.as_ref().map(|def| def.value.span).unwrap_or(ty.span) } else { param.ident.span @@ -3528,12 +3537,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { }; // Do not suggest if this is coming from macro expansion. if span.can_be_used_for_suggestions() { - return (Some(( - span.shrink_to_hi(), - msg, - sugg, - Applicability::MaybeIncorrect, - )), None); + return ( + Some((span.shrink_to_hi(), msg, sugg, Applicability::MaybeIncorrect)), + None, + ); } } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 206e32f61b485..f4166fb29f77f 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1273,8 +1273,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PathResult::NonModule(..) | // HACK(Urgau): This shouldn't be necessary PathResult::Failed { is_error_from_last_segment: false, .. } => { - self.dcx() - .emit_err(errors::CfgAccessibleUnsure { span }); + self.dcx().emit_err(errors::CfgAccessibleUnsure { span }); // If we get a partially resolved NonModule in one namespace, we should get the // same result in any other namespaces, so we can return early. diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 4b67cada078a4..0ade2391e13dd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -73,10 +73,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { root_obligation.cause.code().peel_derives() && !obligation.predicate.has_non_region_infer() { - if let Some(cause) = self - .tcx - .diagnostic_hir_wf_check((tcx.erase_and_anonymize_regions(obligation.predicate), *wf_loc)) - { + if let Some(cause) = self.tcx.diagnostic_hir_wf_check(( + tcx.erase_and_anonymize_regions(obligation.predicate), + *wf_loc, + )) { obligation.cause = cause.clone(); span = obligation.cause.span; } @@ -89,13 +89,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } = *obligation.cause.code() { debug!("ObligationCauseCode::CompareImplItemObligation"); - return self.report_extra_impl_obligation( - span, - impl_item_def_id, - trait_item_def_id, - &format!("`{}`", obligation.predicate), - ) - .emit() + return self + .report_extra_impl_obligation( + span, + impl_item_def_id, + trait_item_def_id, + &format!("`{}`", obligation.predicate), + ) + .emit(); } // Report a const-param specific error @@ -116,7 +117,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // // We rely on a few heuristics to identify cases where this root // obligation is more important than the leaf obligation: - let (main_trait_predicate, main_obligation) = if let ty::PredicateKind::Clause( + let (main_trait_predicate, main_obligation) = + if let ty::PredicateKind::Clause( ty::ClauseKind::Trait(root_pred) ) = root_obligation.predicate.kind().skip_binder() && !leaf_trait_predicate.self_ty().skip_binder().has_escaping_bound_vars() @@ -146,26 +148,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // The root trait is not `Unsize`, as to avoid talking about it in // `tests/ui/coercion/coerce-issue-49593-box-never.rs`. && !self.tcx.is_lang_item(root_pred.def_id(), LangItem::Unsize) - { - ( - self.resolve_vars_if_possible( - root_obligation.predicate.kind().rebind(root_pred), - ), - root_obligation, - ) - } else { - (leaf_trait_predicate, &obligation) - }; + { + ( + self.resolve_vars_if_possible( + root_obligation.predicate.kind().rebind(root_pred), + ), + root_obligation, + ) + } else { + (leaf_trait_predicate, &obligation) + }; - if let Some(guar) = self.emit_specialized_closure_kind_error( - &obligation, - leaf_trait_predicate, - ) { + if let Some(guar) = self + .emit_specialized_closure_kind_error(&obligation, leaf_trait_predicate) + { return guar; } - if let Err(guar) = leaf_trait_predicate.error_reported() - { + if let Err(guar) = leaf_trait_predicate.error_reported() { return guar; } // Silence redundant errors on binding access that are already @@ -185,29 +185,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) .unwrap_or_default(); - let CustomDiagnostic { - message, - label, - notes, - parent_label, - } = self.on_unimplemented_note(main_trait_predicate, main_obligation, &mut long_ty_file); + let CustomDiagnostic { message, label, notes, parent_label } = self + .on_unimplemented_note( + main_trait_predicate, + main_obligation, + &mut long_ty_file, + ); let have_alt_message = message.is_some() || label.is_some(); - let message = message.unwrap_or_else(|| self.get_standard_error_message( - main_trait_predicate, - None, - post_message, - &mut long_ty_file, - )); - let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id()); + let message = message.unwrap_or_else(|| { + self.get_standard_error_message( + main_trait_predicate, + None, + post_message, + &mut long_ty_file, + ) + }); + let is_try_conversion = + self.is_try_conversion(span, main_trait_predicate.def_id()); let is_question_mark = matches!( root_obligation.cause.code().peel_derives(), ObligationCauseCode::QuestionMark, - ) && !( - self.tcx.is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id()) - || self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try) - ); + ) && !(self + .tcx + .is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id()) + || self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try)); let is_unsize = self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize); let question_mark_message = "the question mark operation (`?`) implicitly \ @@ -240,13 +243,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (message, notes) }; - let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item( - main_trait_predicate.def_id(), - LangItem::TransmuteTrait, - ) { + let (err_msg, safe_transmute_explanation) = if self + .tcx + .is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait) + { // Recompute the safe transmute reason and use that for the error reporting - let (report_obligation, report_pred) = - self.select_transmute_obligation_for_reporting( + let (report_obligation, report_pred) = self + .select_transmute_obligation_for_reporting( &obligation, main_trait_predicate, root_obligation, @@ -258,13 +261,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, ) { GetSafeTransmuteErrorAndReason::Silent => { - return self.dcx().span_delayed_bug( - span, "silent safe transmute error" - ); - } - GetSafeTransmuteErrorAndReason::Default => { - (message, None) + return self + .dcx() + .span_delayed_bug(span, "silent safe transmute error"); } + GetSafeTransmuteErrorAndReason::Default => (message, None), GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation, @@ -285,15 +286,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { let trait_ref = leaf_trait_predicate.skip_binder().trait_ref; - if let Some(found_ty) = trait_ref.args.get(1).and_then(|arg| arg.as_type()) + if let Some(found_ty) = + trait_ref.args.get(1).and_then(|arg| arg.as_type()) { let ty = main_trait_predicate.skip_binder().self_ty(); - if let Some(cast_ty) = self.find_explicit_cast_type( - obligation.param_env, - found_ty, - ty, - ) { + if let Some(cast_ty) = + self.find_explicit_cast_type(obligation.param_env, found_ty, ty) + { let found_ty_str = self.tcx.short_string(found_ty, &mut long_ty_file); let cast_ty_str = @@ -306,13 +306,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - *err.long_ty_path() = long_ty_file; let mut suggested = false; let mut noted_missing_impl = false; if is_try_conversion || is_question_mark { - (suggested, noted_missing_impl) = self.try_conversion_context(&obligation, main_trait_predicate, &mut err); + (suggested, noted_missing_impl) = self.try_conversion_context( + &obligation, + main_trait_predicate, + &mut err, + ); } suggested |= self.detect_negative_literal( @@ -378,8 +381,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let ty_span = match leaf_trait_predicate.self_ty().skip_binder().kind() { - ty::Adt(def, _) if def.did().is_local() - && !self.can_suggest_derive(&obligation, leaf_trait_predicate) => self.tcx.def_span(def.did()), + ty::Adt(def, _) + if def.did().is_local() + && !self + .can_suggest_derive(&obligation, leaf_trait_predicate) => + { + self.tcx.def_span(def.did()) + } _ => DUMMY_SP, }; if let Some(s) = label { @@ -391,8 +399,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // `std::marker::Sized` is not implemented for `T`" as we will point // at the type param with a label to suggest constraining it. && !self.tcx.is_diagnostic_item(sym::FromResidual, leaf_trait_predicate.def_id()) - // Don't say "the trait `FromResidual>` is - // not implemented for `Result`". + // Don't say "the trait `FromResidual>` is + // not implemented for `Result`". { // We do this just so that the JSON output's `help` position is the // right one and not `file.rs:1:1`. The render is the same. @@ -404,7 +412,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } else if let Some(custom_explanation) = safe_transmute_explanation { err.span_label(span, custom_explanation); - } else if (explanation.len() > self.tcx.sess.diagnostic_width() || ty_span != DUMMY_SP) && !noted_missing_impl { + } else if (explanation.len() > self.tcx.sess.diagnostic_width() + || ty_span != DUMMY_SP) + && !noted_missing_impl + { // Really long types don't look good as span labels, instead move it // to a `help`. err.span_label(span, "unsatisfied trait bound"); @@ -423,7 +434,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let ObligationCauseCode::Coercion { source, target } = *obligation.cause.code().peel_derives() { - if self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Sized) { + if self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Sized) + { self.suggest_borrowing_for_object_cast( &mut err, root_obligation, @@ -445,10 +457,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.span_label(tcx.def_span(body), s); } - self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_predicate); - self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate); - suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate); - suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate); + self.suggest_floating_point_literal( + &obligation, + &mut err, + leaf_trait_predicate, + ); + self.suggest_dereferencing_index( + &obligation, + &mut err, + leaf_trait_predicate, + ); + suggested |= + self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate); + suggested |= + self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate); suggested |= self.suggest_cast_to_fn_pointer( &obligation, &mut err, @@ -456,15 +478,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { main_trait_predicate, span, ); - suggested |= - self.suggest_remove_reference(&obligation, &mut err, leaf_trait_predicate); + suggested |= self.suggest_remove_reference( + &obligation, + &mut err, + leaf_trait_predicate, + ); suggested |= self.suggest_semicolon_removal( &obligation, &mut err, span, leaf_trait_predicate, ); - self.note_different_trait_with_same_name(&mut err, &obligation, leaf_trait_predicate); + self.note_different_trait_with_same_name( + &mut err, + &obligation, + leaf_trait_predicate, + ); self.note_adt_version_mismatch(&mut err, leaf_trait_predicate); self.suggest_remove_await(&obligation, &mut err); self.suggest_derive(&obligation, &mut err, leaf_trait_predicate); @@ -478,7 +507,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - if self.suggest_add_clone_to_arg(&obligation, &mut err, leaf_trait_predicate) { + if self.suggest_add_clone_to_arg( + &obligation, + &mut err, + leaf_trait_predicate, + ) { return err.emit(); } @@ -553,11 +586,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { \ for more information)", ); - err.help("you might have intended to use the type `()` here instead"); + err.help( + "you might have intended to use the type `()` here instead", + ); } } - self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause); + self.explain_hrtb_projection( + &mut err, + leaf_trait_predicate, + obligation.param_env, + &obligation.cause, + ); self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_predicate); // Return early if the trait is Debug or Display and the invocation @@ -586,9 +626,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => { - self.report_host_effect_error(bound_predicate.rebind(predicate), &obligation, span) - } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => self + .report_host_effect_error( + bound_predicate.rebind(predicate), + &obligation, + span, + ), ty::PredicateKind::Subtype(predicate) => { // Errors for Subtype predicates show up as @@ -668,17 +711,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - // Errors for `ConstEvaluatable` predicates show up as - // `SelectionError::ConstEvalFailure`, - // not `Unimplemented`. + // Errors for `ConstEvaluatable`, `ConstEquate` predicates show up as + // `SelectionError::ConstEvalFailure`, not `Unimplemented`. + // Ambiguous predicates should never error. + // We never return `Err` when proving `UnstableFeature`` goal. ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - // Errors for `ConstEquate` predicates show up as - // `SelectionError::ConstEvalFailure`, - // not `Unimplemented`. | ty::PredicateKind::ConstEquate { .. } - // Ambiguous predicates should never error | ty::PredicateKind::Ambiguous - // We never return Err when proving UnstableFeature goal. | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature { .. }) | ty::PredicateKind::NormalizesTo { .. } | ty::PredicateKind::AliasRelate { .. } @@ -736,12 +775,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Already reported in the query. - SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) | - // Already reported. - SelectionError::Overflow(OverflowError::Error(guar)) => { + SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) + | SelectionError::Overflow(OverflowError::Error(guar)) => { self.set_tainted_by_errors(guar); - return guar - }, + return guar; + } SelectionError::Overflow(_) => { bug!("overflow should be handled before the `report_selection_error` path"); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 646945990a1d5..af104a56202b0 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -740,7 +740,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); selcx.infcx.enter_forall(binder, |pred| { - selcx.infcx.register_region_outlives_constraint(pred, ty::VisibleForLeakCheck::Yes,&dummy_cause); + selcx.infcx.register_region_outlives_constraint( + pred, + ty::VisibleForLeakCheck::Yes, + &dummy_cause, + ); }); } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => { @@ -757,11 +761,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { ); } (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { - selcx.infcx.register_type_outlives_constraint( - t_a, - r_b, - &dummy_cause, - ); + selcx.infcx.register_type_outlives_constraint(t_a, r_b, &dummy_cause); } _ => {} }; @@ -769,11 +769,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { let evaluate = |c: ty::Const<'tcx>| { if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { - let ct = super::try_evaluate_const( - selcx.infcx, - c, - obligation.param_env, - ); + let ct = + super::try_evaluate_const(selcx.infcx, c, obligation.param_env); if let Err(EvaluateConstErr::InvalidConstParamTy(_)) = ct { self.tcx.dcx().emit_err(UnableToConstructConstantValue { @@ -790,8 +787,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { - match selcx.infcx.at(&obligation.cause, obligation.param_env).eq(DefineOpaqueTypes::Yes,c1, c2) - { + match selcx.infcx.at(&obligation.cause, obligation.param_env).eq( + DefineOpaqueTypes::Yes, + c1, + c2, + ) { Ok(_) => (), Err(_) => return false, } @@ -810,12 +810,13 @@ impl<'tcx> AutoTraitFinder<'tcx> { | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::Subtype(..) - // FIXME(generic_const_exprs): you can absolutely add this as a where clauses - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {} ty::PredicateKind::Ambiguous => return false, + + // FIXME(generic_const_exprs): you can absolutely add this as a where clauses + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => return false, }; } true diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index d1522ec89a016..c48e56c06d6ba 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -223,7 +223,17 @@ fn predicate_references_self<'tcx>( match predicate.kind().skip_binder() { ty::ClauseKind::Trait(ref data) => { // In the case of a trait predicate, we can skip the "self" type. - data.trait_ref.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp) + data.trait_ref.args[1..] + .iter() + .any(|&arg| { + contains_illegal_self_type_reference( + tcx, + trait_def_id, + arg, + allow_self_projections, + ) + }) + .then_some(sp) } ty::ClauseKind::Projection(ref data) => { // And similarly for projections. This should be redundant with @@ -241,18 +251,31 @@ fn predicate_references_self<'tcx>( // // This is ALT2 in issue #56288, see that for discussion of the // possible alternatives. - data.projection_term.args[1..].iter().any(|&arg| contains_illegal_self_type_reference(tcx, trait_def_id, arg, allow_self_projections)).then_some(sp) + data.projection_term.args[1..] + .iter() + .any(|&arg| { + contains_illegal_self_type_reference( + tcx, + trait_def_id, + arg, + allow_self_projections, + ) + }) + .then_some(sp) + } + ty::ClauseKind::ConstArgHasType(_ct, ty) => { + contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections) + .then_some(sp) } - ty::ClauseKind::ConstArgHasType(_ct, ty) => contains_illegal_self_type_reference(tcx, trait_def_id, ty, allow_self_projections).then_some(sp), ty::ClauseKind::WellFormed(..) | ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..) - // FIXME(generic_const_exprs): this can mention `Self` - | ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::HostEffect(..) - | ty::ClauseKind::UnstableFeature(_) - => None, + | ty::ClauseKind::UnstableFeature(_) => None, + + // FIXME(generic_const_exprs): this can mention `Self` + ty::ClauseKind::ConstEvaluatable(..) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index ce8f05637f9a6..914e103afded3 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -464,7 +464,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { bug!("AliasRelate is only used by the new solver") } ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => { - unreachable!("unexpected higher ranked `UnstableFeature` goal") + unreachable!("unexpected higher ranked `UnstableFeature` goal") } }, Some(pred) => match pred { diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 062de4b5d08a7..b748611be383f 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -330,7 +330,7 @@ impl Answer { // If either is an error, return it | (Answer::No(reason), _) | (_, Answer::No(reason)) => Answer::No(reason), // If only one side has a condition, pass it along - | (Answer::Yes, other) | (other, Answer::Yes) => other, + (Answer::Yes, other) | (other, Answer::Yes) => other, // If both sides have IfAll conditions, merge them (Answer::If(Condition::IfAll(mut lhs)), Answer::If(Condition::IfAll(ref mut rhs))) => { lhs.append(rhs); diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index ab4bfd998cf34..ebec1888e6a95 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -41,10 +41,13 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( try_visit!(visitor.visit(span, pred.skip_norm_wip())); } } - // Walk over the type behind the alias - DefKind::TyAlias { .. } | DefKind::AssocTy | - // Walk over the type of the item - DefKind::Static { .. } | DefKind::Const { .. } | DefKind::AssocConst { .. } | DefKind::AnonConst => { + // Walk over the type behind the alias or the type of the item + DefKind::TyAlias { .. } + | DefKind::AssocTy + | DefKind::Static { .. } + | DefKind::Const { .. } + | DefKind::AssocConst { .. } + | DefKind::AnonConst => { if let Some(ty) = tcx.hir_node_by_def_id(item).ty() { // If the type of the item uses `_`, we're gonna error out anyway, but // typeck (which type_of invokes below), will call back into opaque_types_defined_by @@ -53,14 +56,21 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( return V::Result::output(); } // Associated types in traits don't necessarily have a type that we can visit - try_visit!(visitor.visit(ty.span, tcx.type_of(item).instantiate_identity().skip_norm_wip())); + try_visit!( + visitor + .visit(ty.span, tcx.type_of(item).instantiate_identity().skip_norm_wip()) + ); } for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { try_visit!(visitor.visit(span, pred.skip_norm_wip())); } } DefKind::OpaqueTy => { - for (pred, span) in tcx.explicit_item_bounds(item).iter_identity_copied().map(Unnormalized::skip_norm_wip) { + for (pred, span) in tcx + .explicit_item_bounds(item) + .iter_identity_copied() + .map(Unnormalized::skip_norm_wip) + { try_visit!(visitor.visit(span, pred)); } } @@ -87,15 +97,26 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( DefKind::InlineConst | DefKind::Closure | DefKind::SyntheticCoroutineBody => {} DefKind::Impl { of_trait } => { if of_trait { - let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().trait_ref.path.span; - let args = &tcx.impl_trait_ref(item).instantiate_identity().skip_norm_wip().args[1..]; + let span = tcx + .hir_node_by_def_id(item) + .expect_item() + .expect_impl() + .of_trait + .unwrap() + .trait_ref + .path + .span; + let args = + &tcx.impl_trait_ref(item).instantiate_identity().skip_norm_wip().args[1..]; try_visit!(visitor.visit(span, args)); } let span = match tcx.hir_node_by_def_id(item).ty() { Some(ty) => ty.span, _ => tcx.def_span(item), }; - try_visit!(visitor.visit(span, tcx.type_of(item).instantiate_identity().skip_norm_wip())); + try_visit!( + visitor.visit(span, tcx.type_of(item).instantiate_identity().skip_norm_wip()) + ); for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { try_visit!(visitor.visit(span, pred.skip_norm_wip())); } @@ -105,7 +126,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( try_visit!(visitor.visit(span, pred.skip_norm_wip())); } } - | DefKind::Variant + DefKind::Variant | DefKind::TyParam | DefKind::ConstParam | DefKind::Ctor(_, _) @@ -117,7 +138,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( ) } // These don't have any types, but are visited during privacy checking. - | DefKind::ExternCrate + DefKind::ExternCrate | DefKind::ForeignMod | DefKind::ForeignTy | DefKind::Macro(_) From 701e4942ed6b1c3e487b66b4a1bd4ea8d25015b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 May 2026 02:40:58 +0000 Subject: [PATCH 04/13] Remove a bunch of stray backticks Thanks VSCode! --- .../src/error_reporting/traits/fulfillment_errors.rs | 2 +- .../clippy_lints/src/default_numeric_fallback.rs | 2 +- src/tools/miri/src/shims/os_str.rs | 2 +- src/tools/run-make-support/src/external_deps/rustc.rs | 4 ++-- src/tools/rust-analyzer/crates/hir-ty/src/traits.rs | 10 +++++----- src/tools/rust-analyzer/crates/mbe/src/parser.rs | 2 +- .../crates/project-model/src/workspace.rs | 2 +- .../dont-ice-when-body-tainted-by-errors.rs | 2 +- tests/ui/parser/const-block-items/pub.rs | 2 +- tests/ui/parser/raw/raw-idents.rs | 2 +- .../normalize/indirectly-constrained-term.rs | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 0ade2391e13dd..bf881feb60158 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -714,7 +714,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Errors for `ConstEvaluatable`, `ConstEquate` predicates show up as // `SelectionError::ConstEvalFailure`, not `Unimplemented`. // Ambiguous predicates should never error. - // We never return `Err` when proving `UnstableFeature`` goal. + // We never return `Err` when proving `UnstableFeature` goal. ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate { .. } | ty::PredicateKind::Ambiguous diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index f93f682bc9298..8ec095cc24dde 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> { if let Some(fn_sig) = self.cx.tcx.parent_hir_node(expr.hir_id).fn_sig() && let FnRetTy::Return(_ty) = fn_sig.decl.output { - // We cannot check the exact type since it's a `hir::Ty`` which does not implement `is_numeric` + // We cannot check the exact type since it's a `hir::Ty` which does not implement `is_numeric` self.ty_bounds.push(ExplicitTyBound(true)); for stmt in *stmts { self.visit_stmt(stmt); diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index db9cb3a7a32bd..78e7f2d418c30 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -282,7 +282,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { *c = sep; } } - // If this starts with `//?/`, it was probably produced by `unix_to_windows`` and we + // If this starts with `//?/`, it was probably produced by `unix_to_windows` and we // remove the `//?` that got added to get the Unix path back out. if path.get(0..4) == Some(&[sep, sep, b'?'.into(), sep]) { // Remove first 3 characters. It still starts with `/` so it is absolute on Unix. diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index e8645e00e1852..b5d9593ae9a6a 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -190,14 +190,14 @@ impl Rustc { self } - /// Specify path to the output file. Equivalent to `-o`` in rustc. + /// Specify path to the output file. Equivalent to `-o` in rustc. pub fn output>(&mut self, path: P) -> &mut Self { self.cmd.arg("-o"); self.cmd.arg(path.as_ref()); self } - /// Specify path to the output directory. Equivalent to `--out-dir`` in rustc. + /// Specify path to the output directory. Equivalent to `--out-dir` in rustc. pub fn out_dir>(&mut self, path: P) -> &mut Self { self.cmd.arg("--out-dir"); self.cmd.arg(path.as_ref()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index ad1c3fb709c9d..9582f2ceba831 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -232,11 +232,11 @@ pub fn is_inherent_impl_coherent(db: &dyn HirDatabase, def_map: &DefMap, impl_id /// Checks whether the impl satisfies the orphan rules. /// -/// Given `impl Trait for T0`, an `impl`` is valid only if at least one of the following is true: +/// Given `impl Trait for T0`, an `impl` is valid only if at least one of the following is true: /// - Trait is a local trait /// - All of -/// - At least one of the types `T0..=Tn`` must be a local type. Let `Ti`` be the first such type. -/// - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`) +/// - At least one of the types `T0..=Tn` must be a local type. Let `Ti` be the first such type. +/// - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti` (excluding `Ti`) pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool { let Some(impl_trait) = db.impl_trait(impl_) else { // not a trait impl @@ -277,10 +277,10 @@ pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool } } }; - // - At least one of the types `T0..=Tn`` must be a local type. Let `Ti`` be the first such type. + // - At least one of the types `T0..=Tn` must be a local type. Let `Ti` be the first such type. // FIXME: param coverage - // - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti`` (excluding `Ti`) + // - No uncovered type parameters `P1..=Pn` may appear in `T0..Ti` (excluding `Ti`) let is_not_orphan = trait_ref.args.types().any(|ty| match unwrap_fundamental(ty).kind() { TyKind::Adt(adt_def, _) => is_local(adt_def.def_id().module(db).krate(db)), TyKind::Error(_) => true, diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs index 796ee62d48e3a..9fbd06cf88626 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs @@ -109,7 +109,7 @@ pub(crate) enum Op { }, Count { name: Symbol, - // FIXME: `usize`` once we drop support for 1.76 + // FIXME: `usize` once we drop support for 1.76 depth: Option, }, Concat { diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 29a19bc32e453..675533645d0db 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -748,7 +748,7 @@ impl ProjectWorkspace { .packages() .filter_map(|pkg| { if ws[pkg].is_local { - // the local ones are included in the main `PackageRoot`` below + // the local ones are included in the main `PackageRoot` below return None; } let pkg_root = ws[pkg].manifest.parent().to_path_buf(); diff --git a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs index f90d10ebe854b..1bbff34292c39 100644 --- a/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs +++ b/tests/ui/async-await/async-closures/dont-ice-when-body-tainted-by-errors.rs @@ -11,7 +11,7 @@ pub fn main() { // Type error here taints the environment. This causes us to fallback all // variables to `Error`. This means that when we compute the upvars for the // *outer* coroutine-closure, we don't actually see any upvars since `MemCategorization` - // and `ExprUseVisitor`` will bail early when it sees error. This means + // and `ExprUseVisitor` will bail early when it sees error. This means // that our underlying assumption that the parent and child captures are // compatible ends up being broken, previously leading to an ICE. trait_error::<()>(); diff --git a/tests/ui/parser/const-block-items/pub.rs b/tests/ui/parser/const-block-items/pub.rs index b76d30d9bda18..4bff11a5a5ad6 100644 --- a/tests/ui/parser/const-block-items/pub.rs +++ b/tests/ui/parser/const-block-items/pub.rs @@ -2,7 +2,7 @@ //@ check-pass -// FIXME(const_block_items): `pub`` is useless here +// FIXME(const_block_items): `pub` is useless here pub const { assert!(true); } diff --git a/tests/ui/parser/raw/raw-idents.rs b/tests/ui/parser/raw/raw-idents.rs index 4e1e6b124c311..fd0a4c7522a09 100644 --- a/tests/ui/parser/raw/raw-idents.rs +++ b/tests/ui/parser/raw/raw-idents.rs @@ -6,7 +6,7 @@ //@[e2024] edition:2024 // Ensure that all (usable as identifier) keywords work as raw identifiers in all positions. -// This was motivated by issue #137128, where `r#move`/`r#static`` did not work as `const` names +// This was motivated by issue #137128, where `r#move`/`r#static` did not work as `const` names // due to a parser check not acounting for raw identifiers. #![crate_type = "lib"] diff --git a/tests/ui/traits/next-solver/normalize/indirectly-constrained-term.rs b/tests/ui/traits/next-solver/normalize/indirectly-constrained-term.rs index 380477c2c3c67..55fb751d26973 100644 --- a/tests/ui/traits/next-solver/normalize/indirectly-constrained-term.rs +++ b/tests/ui/traits/next-solver/normalize/indirectly-constrained-term.rs @@ -17,7 +17,7 @@ // We prove `Projection( as Unconstrained>::Assoc, ())`. This normalizes // ` as Unconstrained>::Assoc` to `?1` and eagerly computes the nested // goals `[Projection(::Assoc, ?1), Trait(?1: NoImpl)]`. -// These goals are both ambiguous. `NormalizesTo`` then returns `?1` as the +// These goals are both ambiguous. `NormalizesTo` then returns `?1` as the // normalized-to type. It discards the nested goals, forcing the certainty of // the normalization to `Maybe`. Unifying `?1` with `()` succeeds¹. However, // this is never propagated to the `?1: NoImpl` goal, as it only exists inside From 19c636511095f8f9dd9247c55034a903e2593ea2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 May 2026 14:37:12 +1000 Subject: [PATCH 05/13] Inline and remove `late_lint_crate_inner` It has a single call site. --- compiler/rustc_lint/src/late.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 3cc0d46d8541f..0a074c6652a1d 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -439,14 +439,6 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { filtered_passes.push(Box::new(HardwiredLints)); let pass = RuntimeCombinedLateLintPass { passes: &mut filtered_passes[..] }; - late_lint_crate_inner(tcx, context, pass); -} - -fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>( - tcx: TyCtxt<'tcx>, - context: LateContext<'tcx>, - pass: T, -) { let mut cx = LateContextAndPass { context, pass }; // Visit the whole crate. From 40332688e0185b6ea6f1ba7286958d7bea1b18e8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 May 2026 17:57:02 +1000 Subject: [PATCH 06/13] Remove an unnecessary `push` argument It's always `None`. --- compiler/rustc_lint/src/early.rs | 2 +- compiler/rustc_lint/src/levels.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 903e223e97938..df6683c14df42 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -53,7 +53,7 @@ impl<'ecx, T: EarlyLintPass> EarlyContextAndPass<'ecx, T> { { let is_crate_node = id == ast::CRATE_NODE_ID; debug!(?id); - let push = self.context.builder.push(attrs, is_crate_node, None); + let push = self.context.builder.push(attrs, is_crate_node); debug!("early context: enter_attrs({:?})", attrs); lint_callback!(self, check_attributes, attrs); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index ad74b0ee906a1..25cc788b63bfa 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -417,13 +417,12 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { &mut self, attrs: &[ast::Attribute], is_crate_node: bool, - source_hir_id: Option, ) -> BuilderPush { let prev = self.provider.cur; self.provider.cur = self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev }); - self.add(attrs, is_crate_node, source_hir_id); + self.add(attrs, is_crate_node, None); if self.provider.current_specs().is_empty() { self.provider.sets.list.pop(); From 379caad45e1be85b384b578cc53d5f1b0e017782 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 19 Feb 2026 13:04:31 +0000 Subject: [PATCH 07/13] Remove driver_lint_caps It was only used by rustdoc and doesn't seem like it was necessary there. No tests fail at least. --- compiler/rustc_driver_impl/src/lib.rs | 1 - compiler/rustc_interface/src/interface.rs | 7 ++---- compiler/rustc_interface/src/tests.rs | 10 +------- compiler/rustc_middle/src/lint.rs | 5 ---- compiler/rustc_session/src/session.rs | 5 ---- .../examples/rustc-interface-example.rs | 9 ++++--- .../rustc-interface-getting-diagnostics.rs | 3 +-- src/librustdoc/core.rs | 3 +-- src/librustdoc/doctest.rs | 5 ++-- src/librustdoc/lint.rs | 24 ++++--------------- tests/ui-fulldeps/run-compiler-twice.rs | 1 - 11 files changed, 15 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 31353d1eac0fb..7f9f83b5c963d 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -213,7 +213,6 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) output_dir: odir, ice_file, file_loader: None, - lint_caps: Default::default(), psess_created: None, track_state: None, register_lints: None, diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 875ed4ae5d307..2b90606c83f29 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use rustc_ast::{LitKind, MetaItemKind, token}; use rustc_codegen_ssa::traits::CodegenBackend; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::jobserver::{self, Proxy}; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; use rustc_lint::LintStore; @@ -18,7 +18,7 @@ use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_query_impl::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; use rustc_session::parse::ParseSess; -use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint}; +use rustc_session::{CompilerIO, EarlyDiagCtxt, Session}; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs}; use rustc_span::{FileName, sym}; use tracing::trace; @@ -330,8 +330,6 @@ pub struct Config { /// running rustc without having to save". (See #102759.) pub file_loader: Option>, - pub lint_caps: FxHashMap, - /// This is a callback from the driver that is called when [`ParseSess`] is created. pub psess_created: Option>, @@ -427,7 +425,6 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se output_file: config.output_file, temps_dir, }, - config.lint_caps, target, util::rustc_version_str().unwrap_or("unknown"), config.ice_file, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 0837e7767605c..6788582e2c613 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -68,15 +68,7 @@ where static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false); - let sess = build_session( - sessopts, - io, - Default::default(), - target, - "", - None, - &USING_INTERNAL_FEATURES, - ); + let sess = build_session(sessopts, io, target, "", None, &USING_INTERNAL_FEATURES); let cfg = parse_cfg(sess.dcx(), matches.opt_strs("cfg")); let cfg = build_configuration(&sess, cfg); f(sess, cfg) diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 41eeb1fc9811f..7abbd777d13ec 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -167,11 +167,6 @@ pub fn reveal_actual_level_spec( level_spec.level = min(level_spec.level, sess.opts.lint_cap.unwrap_or(Level::Forbid)); }; - // Ensure that we never exceed driver level. - if let Some(driver_level) = sess.driver_lint_caps.get(&lint) { - level_spec.level = min(level_spec.level, *driver_level); - } - level_spec } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 003164e8f9054..1fe5aa1fd12b3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -117,9 +117,6 @@ pub struct Session { /// This only ever stores a `LintStore` but we don't want a dependency on that type here. pub lint_store: Option>, - /// Cap lint level specified by a driver specifically. - pub driver_lint_caps: FxHashMap, - /// Tracks the current behavior of the CTFE engine when an error occurs. /// Options range from returning the error without a backtrace to returning an error /// and immediately printing the backtrace to stderr. @@ -1005,7 +1002,6 @@ fn default_emitter(sopts: &config::Options, source_map: Arc) -> Box, target: Target, cfg_version: &'static str, ice_file: Option, @@ -1111,7 +1107,6 @@ pub fn build_session( timings, code_stats: Default::default(), lint_store: None, - driver_lint_caps, ctfe_backtrace, miri_unleashed_features: Lock::new(Default::default()), asm_arch, diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs index 4601d9adbb640..37e971ce568db 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs @@ -28,12 +28,11 @@ fn main() { println!("{HELLO}"); } "# - .into(), + .into(), }, - output_dir: None, // Option - output_file: None, // Option - file_loader: None, // Option> - lint_caps: FxHashMap::default(), // FxHashMap + output_dir: None, // Option + output_file: None, // Option + file_loader: None, // Option> // This is a callback from the driver that is called when [`ParseSess`] is created. psess_created: None, //Option> // This is a callback from the driver that is called when we're registering lints; diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs index ea2a772703bbd..0ec146f67a0d4 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs @@ -59,14 +59,13 @@ fn main() { let x: &str = 1; } " - .into(), + .into(), }, crate_cfg: Vec::new(), crate_check_cfg: Vec::new(), output_dir: None, output_file: None, file_loader: None, - lint_caps: rustc_hash::FxHashMap::default(), psess_created: Some(Box::new(|parse_sess| { parse_sess.dcx().set_emitter(Box::new(DebugEmitter { source_map: parse_sess.clone_source_map(), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 21ce508d8560c..3f5a50e6af197 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -238,7 +238,7 @@ pub(crate) fn create_config( ]; lints_to_show.extend(crate::lint::RUSTDOC_LINTS.iter().map(|lint| lint.name.to_string())); - let (lint_opts, lint_caps) = crate::lint::init_lints(lints_to_show, lint_opts, |lint| { + let lint_opts = crate::lint::init_lints(lints_to_show, lint_opts, |lint| { Some((lint.name_lower(), lint::Allow)) }); @@ -293,7 +293,6 @@ pub(crate) fn create_config( Some(render_options.output.clone()) }, file_loader: None, - lint_caps, psess_created: None, track_state: None, register_lints: Some(Box::new(crate::lint::register_lints)), diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 6ec4aaf282238..6d5e12f0ddb63 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -144,7 +144,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_owned(), ]; - let (lint_opts, lint_caps) = init_lints(allowed_lints, options.lint_opts.clone(), |lint| { + let lint_opts = init_lints(allowed_lints, options.lint_opts.clone(), |lint| { if lint.name == invalid_codeblock_attributes_name { None } else { @@ -162,7 +162,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions search_paths: options.libs.clone(), crate_types, lint_opts, - lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)), + lint_cap: None, cg: options.codegen_options.clone(), externs: options.externs.clone(), unstable_features: options.unstable_features, @@ -189,7 +189,6 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions output_file: None, output_dir: None, file_loader: None, - lint_caps, psess_created: None, track_state: None, register_lints: Some(Box::new(crate::lint::register_lints)), diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index b09ea05688595..1a3e6d4bf51fb 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -1,6 +1,5 @@ use std::sync::LazyLock as Lazy; -use rustc_data_structures::fx::FxHashMap; use rustc_lint::LintStore; use rustc_lint_defs::{Lint, LintId, declare_tool_lint}; use rustc_session::{Session, lint}; @@ -14,14 +13,12 @@ use rustc_session::{Session, lint}; /// through the "WARNINGS" lint. To prevent this to happen, we set it back to its "normal" level /// inside this function. /// -/// It returns a tuple containing: -/// * Vector of tuples of lints' name and their associated "max" level -/// * HashMap of lint id with their associated "max" level +/// It returns a vector of tuples of lints' name and their associated "max" level pub(crate) fn init_lints( mut allowed_lints: Vec, lint_opts: Vec<(String, lint::Level)>, filter_call: F, -) -> (Vec<(String, lint::Level)>, FxHashMap) +) -> Vec<(String, lint::Level)> where F: Fn(&lint::Lint) -> Option<(String, lint::Level)>, { @@ -36,7 +33,7 @@ where .chain(rustc_lint::SoftLints::lint_vec()) }; - let lint_opts = lints() + lints() .filter_map(|lint| { // Permit feature-gated lints to avoid feature errors when trying to // allow all lints. @@ -47,20 +44,7 @@ where } }) .chain(lint_opts) - .collect::>(); - - let lint_caps = lints() - .filter_map(|lint| { - // We don't want to allow *all* lints so let's ignore - // those ones. - if allowed_lints.iter().any(|l| lint.name == l) { - None - } else { - Some((lint::LintId::of(lint), lint::Allow)) - } - }) - .collect(); - (lint_opts, lint_caps) + .collect::>() } macro_rules! declare_rustdoc_lint { diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs index d99d9c42d547f..6afb88d24cff2 100644 --- a/tests/ui-fulldeps/run-compiler-twice.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -64,7 +64,6 @@ fn compile(code: String, output: PathBuf, sysroot: Sysroot, linker: Option<&Path output_dir: None, ice_file: None, file_loader: None, - lint_caps: Default::default(), psess_created: None, track_state: None, register_lints: None, From 124126e0839b6a2aaa94cc7df1ca520122c66ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9D=E5=80=89=E6=B0=B4=E5=B8=8C?= Date: Fri, 15 May 2026 00:06:14 +0800 Subject: [PATCH 08/13] Test EII UI tests with prefer-dynamic --- tests/ui/eii/default/auxiliary/decl_with_default.rs | 1 - tests/ui/eii/default/auxiliary/decl_with_default_panics.rs | 1 - tests/ui/eii/default/auxiliary/impl1.rs | 1 - tests/ui/eii/default/call_default.rs | 1 - tests/ui/eii/default/call_default_panics.rs | 1 - tests/ui/eii/default/call_impl.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl1.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl2.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl3.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl4.rs | 1 - tests/ui/eii/duplicate/duplicate1.rs | 1 - tests/ui/eii/duplicate/duplicate1.stderr | 4 ++-- tests/ui/eii/duplicate/duplicate2.rs | 1 - tests/ui/eii/duplicate/duplicate2.stderr | 4 ++-- tests/ui/eii/duplicate/duplicate3.rs | 1 - tests/ui/eii/duplicate/duplicate3.stderr | 4 ++-- tests/ui/eii/static/auxiliary/cross_crate_def.rs | 1 - 17 files changed, 6 insertions(+), 20 deletions(-) diff --git a/tests/ui/eii/default/auxiliary/decl_with_default.rs b/tests/ui/eii/default/auxiliary/decl_with_default.rs index 8d962c19c94d9..ba855cb854afd 100644 --- a/tests/ui/eii/default/auxiliary/decl_with_default.rs +++ b/tests/ui/eii/default/auxiliary/decl_with_default.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs b/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs index 14778a40cde4a..3867bfb85c9fe 100644 --- a/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs +++ b/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ needs-unwind //@ exec-env:RUST_BACKTRACE=1 #![crate_type = "rlib"] diff --git a/tests/ui/eii/default/auxiliary/impl1.rs b/tests/ui/eii/default/auxiliary/impl1.rs index 3510ea1eb3f27..84edf24e12816 100644 --- a/tests/ui/eii/default/auxiliary/impl1.rs +++ b/tests/ui/eii/default/auxiliary/impl1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index 8806c7fa7d8ce..07b2a650d3c42 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default.rs //@ run-pass //@ check-run-results diff --git a/tests/ui/eii/default/call_default_panics.rs b/tests/ui/eii/default/call_default_panics.rs index db664e0cbcb0d..379ba8ea070b6 100644 --- a/tests/ui/eii/default/call_default_panics.rs +++ b/tests/ui/eii/default/call_default_panics.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default_panics.rs //@ edition: 2021 //@ run-pass diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs index 1a972774beaeb..4553427b8c799 100644 --- a/tests/ui/eii/default/call_impl.rs +++ b/tests/ui/eii/default/call_impl.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default.rs //@ aux-build: impl1.rs //@ run-pass diff --git a/tests/ui/eii/duplicate/auxiliary/impl1.rs b/tests/ui/eii/duplicate/auxiliary/impl1.rs index e99932c69b90b..ffa2cd79818cc 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl1.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl2.rs b/tests/ui/eii/duplicate/auxiliary/impl2.rs index 3a09c824b8292..592234f53fd40 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl2.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl2.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl3.rs b/tests/ui/eii/duplicate/auxiliary/impl3.rs index 09bdd8509da29..5e9fdaba0bb6b 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl3.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl3.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl4.rs b/tests/ui/eii/duplicate/auxiliary/impl4.rs index fd68a83de1252..068cc18d78e6a 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl4.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl4.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs index 2128cac70eb30..3d770232af50f 100644 --- a/tests/ui/eii/duplicate/duplicate1.rs +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ ignore-backends: gcc diff --git a/tests/ui/eii/duplicate/duplicate1.stderr b/tests/ui/eii/duplicate/duplicate1.stderr index 54cc141f88694..f691043e6a597 100644 --- a/tests/ui/eii/duplicate/duplicate1.stderr +++ b/tests/ui/eii/duplicate/duplicate1.stderr @@ -1,10 +1,10 @@ error: multiple implementations of `#[eii1]` - --> $DIR/auxiliary/impl1.rs:10:1 + --> $DIR/auxiliary/impl1.rs:9:1 | LL | fn other(x: u64) { | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` | - ::: $DIR/auxiliary/impl2.rs:10:1 + ::: $DIR/auxiliary/impl2.rs:9:1 | LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs index b0f1b1266e4ca..4311969ed8894 100644 --- a/tests/ui/eii/duplicate/duplicate2.rs +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ aux-build: impl3.rs diff --git a/tests/ui/eii/duplicate/duplicate2.stderr b/tests/ui/eii/duplicate/duplicate2.stderr index 033e43c8b2fbd..492d2b3e6004b 100644 --- a/tests/ui/eii/duplicate/duplicate2.stderr +++ b/tests/ui/eii/duplicate/duplicate2.stderr @@ -1,10 +1,10 @@ error: multiple implementations of `#[eii1]` - --> $DIR/auxiliary/impl1.rs:10:1 + --> $DIR/auxiliary/impl1.rs:9:1 | LL | fn other(x: u64) { | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` | - ::: $DIR/auxiliary/impl2.rs:10:1 + ::: $DIR/auxiliary/impl2.rs:9:1 | LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs index 4b2b0fc111b58..4504ba30c246e 100644 --- a/tests/ui/eii/duplicate/duplicate3.rs +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ aux-build: impl3.rs diff --git a/tests/ui/eii/duplicate/duplicate3.stderr b/tests/ui/eii/duplicate/duplicate3.stderr index 801d40e69c552..f3ca087a27325 100644 --- a/tests/ui/eii/duplicate/duplicate3.stderr +++ b/tests/ui/eii/duplicate/duplicate3.stderr @@ -1,10 +1,10 @@ error: multiple implementations of `#[eii1]` - --> $DIR/auxiliary/impl1.rs:10:1 + --> $DIR/auxiliary/impl1.rs:9:1 | LL | fn other(x: u64) { | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` | - ::: $DIR/auxiliary/impl2.rs:10:1 + ::: $DIR/auxiliary/impl2.rs:9:1 | LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` diff --git a/tests/ui/eii/static/auxiliary/cross_crate_def.rs b/tests/ui/eii/static/auxiliary/cross_crate_def.rs index 70933440a62be..56d3f6fcdc557 100644 --- a/tests/ui/eii/static/auxiliary/cross_crate_def.rs +++ b/tests/ui/eii/static/auxiliary/cross_crate_def.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] From 5cd51c0edd2118b8799f6c8656e3753afd411e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 16 May 2026 00:33:43 +0000 Subject: [PATCH 09/13] Place comment in the right place --- compiler/rustc_borrowck/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 107ca87376015..e80969cd0cbb2 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2239,14 +2239,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // None case => assigning to `x` does not require `x` be initialized. for (place_base, elem) in place.iter_projections().rev() { match elem { - ProjectionElem::Index(_/*operand*/) | - ProjectionElem::OpaqueCast(_) | - ProjectionElem::ConstantIndex { .. } | + ProjectionElem::Index(_/*operand*/) + | ProjectionElem::OpaqueCast(_) // assigning to P[i] requires P to be valid. - ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => - // assigning to (P->variant) is okay if assigning to `P` is okay - // - // FIXME: is this true even if P is an adt with a dtor? + | ProjectionElem::ConstantIndex { .. } + // assigning to (P->variant) is okay if assigning to `P` is okay + // + // FIXME: is this true even if P is an adt with a dtor? + | ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) => {} ProjectionElem::UnwrapUnsafeBinder(_) => { From 87821d9f784fe4f3a408919c21c7b1aaa3a50255 Mon Sep 17 00:00:00 2001 From: Eval Exec Date: Sat, 16 May 2026 03:14:52 -0400 Subject: [PATCH 10/13] Add regression test for issue 41261 --- .../ambiguous-cast-suggestion-issue-41261.rs | 19 +++++++++++++++++++ ...biguous-cast-suggestion-issue-41261.stderr | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/inference/ambiguous-cast-suggestion-issue-41261.rs create mode 100644 tests/ui/inference/ambiguous-cast-suggestion-issue-41261.stderr diff --git a/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.rs b/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.rs new file mode 100644 index 0000000000000..b1c4dfb9f1003 --- /dev/null +++ b/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.rs @@ -0,0 +1,19 @@ +//@ edition: 2021 + +// Regression test for issue #41261. +// The diagnostic should point at the ambiguous cast, not at the later method call. + +struct S { + v: Vec<(u32, Vec)>, +} + +impl S { + pub fn remove(&mut self, i: u32) -> Option> { + self.v.get_mut(i as _).map(|&mut (_, ref mut v2)| { + //~^ ERROR type annotations needed + v2.drain(..) + }) + } +} + +fn main() {} diff --git a/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.stderr b/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.stderr new file mode 100644 index 0000000000000..da66f6237203e --- /dev/null +++ b/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `&mut (_, _)` + --> $DIR/ambiguous-cast-suggestion-issue-41261.rs:12:37 + | +LL | self.v.get_mut(i as _).map(|&mut (_, ref mut v2)| { + | ^^^^^^^^^^^^^^^^^^^^ +LL | +LL | v2.drain(..) + | -- type must be known at this point + | +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified + | +LL | self.v.get_mut(i as _).map(|&mut (_, ref mut v2): &mut (_, _)| { + | +++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. From 22cf1fb6fe6b97ebc190824375a2c9701abb850a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 May 2026 17:58:21 +1000 Subject: [PATCH 11/13] Split `LintExpectationId` `LintExpectationId` has two variants, `Unstable` and `Stable`. There are some places where both variants are possible, but there are also places where only one of `Unstable` or `Stable` is possible. This commit encodes this into the type system by introducing new types `UnstableLintExpectationId` and `StableLintExpectationId`. The variants of `LintExpectationId` now enclose these. This makes it clearer what values are possible where. Other things of note: - `LintLevelsProvider` gets an associated type and some method changes. - `LintContext` gets an associated type. - `LevelSpec` is made generic. `UnstableLevelSpec` and `StableLevelSpec` typedefs are added. - The unstable types are now guaranteed by the type system to never be stably hashed. Previously this was a runtime check. --- compiler/rustc_codegen_ssa/src/lib.rs | 6 +- compiler/rustc_lint/src/context.rs | 23 ++- compiler/rustc_lint/src/expect.rs | 30 ++-- compiler/rustc_lint/src/levels.rs | 162 ++++++++++-------- compiler/rustc_lint_defs/src/lib.rs | 69 ++++---- compiler/rustc_middle/src/lint.rs | 61 ++++--- compiler/rustc_middle/src/queries.rs | 4 +- compiler/rustc_passes/src/dead.rs | 11 +- .../clippy/clippy_lints/src/duplicate_mod.rs | 6 +- 9 files changed, 211 insertions(+), 161 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index ec1eb7eeb6fc0..fc57310804873 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -26,7 +26,7 @@ use rustc_lint_defs::builtin::LINKER_INFO; use rustc_macros::{Decodable, Encodable}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::lint::LevelSpec; +use rustc_middle::lint::StableLevelSpec; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::SymbolExportKind; @@ -342,8 +342,8 @@ impl CompiledModules { /// Instead, encode exactly the information we need. #[derive(Copy, Clone, Debug, Encodable, Decodable)] pub struct CodegenLintLevelSpecs { - linker_messages: LevelSpec, - linker_info: LevelSpec, + linker_messages: StableLevelSpec, + linker_info: StableLevelSpec, } impl CodegenLintLevelSpecs { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 4825b61bc6e41..3cbd02e2ed8d9 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -20,14 +20,17 @@ use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_hir::{Pat, PatKind}; use rustc_middle::bug; -use rustc_middle::lint::LevelSpec; +use rustc_middle::lint::{LevelSpec, StableLevelSpec, UnstableLevelSpec}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths}; use rustc_middle::ty::{ self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode, Unnormalized, }; -use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId}; +use rustc_session::lint::{ + FutureIncompatibleInfo, Lint, LintExpectationId, LintId, StableLintExpectationId, + UnstableLintExpectationId, +}; use rustc_session::{DynLintStore, Session}; use rustc_span::edit_distance::find_best_match_for_names; use rustc_span::{Ident, Span, Symbol, sym}; @@ -510,6 +513,8 @@ pub struct EarlyContext<'a> { } pub trait LintContext { + type LintExpectationId: Copy + Into; + fn sess(&self) -> &Session; // FIXME: These methods should not take an Into -- instead, callers should need to @@ -538,7 +543,7 @@ pub trait LintContext { } /// This returns the lint level spec for the given lint at the current location. - fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec; + fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec; /// This function can be used to manually fulfill an expectation. This can /// be used for lints which contain several spans, and should be suppressed, @@ -547,7 +552,7 @@ pub trait LintContext { /// Note that this function should only be called for [`LintExpectationId`]s /// retrieved from the current lint pass. Buffered or manually created ids can /// cause ICEs. - fn fulfill_expectation(&self, expectation: LintExpectationId) { + fn fulfill_expectation(&self, expectation: Self::LintExpectationId) { // We need to make sure that submitted expectation ids are correctly fulfilled suppressed // and stored between compilation sessions. To not manually do these steps, we simply create // a dummy diagnostic and emit it as usual, which will be suppressed and stored like a @@ -556,7 +561,7 @@ pub trait LintContext { .dcx() .struct_expect( "this is a dummy diagnostic, to submit and store an expectation", - expectation, + expectation.into(), ) .emit(); } @@ -585,6 +590,8 @@ impl<'a> EarlyContext<'a> { } impl<'tcx> LintContext for LateContext<'tcx> { + type LintExpectationId = StableLintExpectationId; + /// Gets the overall compiler `Session` object. fn sess(&self) -> &Session { self.tcx.sess @@ -604,12 +611,14 @@ impl<'tcx> LintContext for LateContext<'tcx> { } } - fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec { + fn get_lint_level_spec(&self, lint: &'static Lint) -> StableLevelSpec { self.tcx.lint_level_spec_at_node(lint, self.last_node_with_lint_attrs) } } impl LintContext for EarlyContext<'_> { + type LintExpectationId = UnstableLintExpectationId; + /// Gets the overall compiler `Session` object. fn sess(&self) -> &Session { self.builder.sess() @@ -624,7 +633,7 @@ impl LintContext for EarlyContext<'_> { self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorator) } - fn get_lint_level_spec(&self, lint: &'static Lint) -> LevelSpec { + fn get_lint_level_spec(&self, lint: &'static Lint) -> UnstableLevelSpec { self.builder.lint_level_spec(lint) } } diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 481e116d06e01..5364a4141805b 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -2,8 +2,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::lint::LintExpectation; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::LintExpectationId; use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS; +use rustc_session::lint::{LintExpectationId, StableLintExpectationId}; use rustc_span::Symbol; use crate::lints::{Expectation, ExpectationNote}; @@ -12,7 +12,7 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { lint_expectations, check_expectations, ..*providers }; } -fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExpectation)> { +fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(StableLintExpectationId, LintExpectation)> { let krate = tcx.hir_crate_items(()); let mut expectations = Vec::new(); @@ -31,30 +31,22 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { // Turn a `LintExpectationId` into a `(AttrId, lint_index)` pair. let canonicalize_id = |expect_id: &LintExpectationId| { - match *expect_id { - LintExpectationId::Unstable { attr_id, lint_index: Some(lint_index) } => { - (attr_id, lint_index) - } - LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { + let (attr_id, lint_index) = match *expect_id { + LintExpectationId::Unstable(id) => (id.attr_id, id.lint_index), + LintExpectationId::Stable(id) => { // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok. - let attr_id = tcx.hir_attrs(hir_id)[attr_index as usize].id(); - - (attr_id, lint_index) + (tcx.hir_attrs(id.hir_id)[id.attr_index as usize].id(), id.lint_index) } - _ => panic!("fulfilled expectations must have a lint index"), - } + }; + (attr_id, lint_index.expect("fulfilled expectations must have a lint index")) }; let fulfilled_expectations: FxHashSet<_> = fulfilled_expectations.iter().map(canonicalize_id).collect(); for (expect_id, expectation) in lint_expectations { - // This check will always be true, since `lint_expectations` only holds stable ids - let LintExpectationId::Stable { hir_id, .. } = expect_id else { - unreachable!("at this stage all `LintExpectationId`s are stable"); - }; - - let expect_id = canonicalize_id(expect_id); + let hir_id = expect_id.hir_id; + let expect_id = canonicalize_id(&LintExpectationId::Stable(*expect_id)); if !fulfilled_expectations.contains(&expect_id) && tool_filter.is_none_or(|filter| expectation.lint_tool == Some(filter)) @@ -63,7 +55,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { let note = expectation.is_unfulfilled_lint_expectations; tcx.emit_node_span_lint( UNFULFILLED_LINT_EXPECTATIONS, - *hir_id, + hir_id, expectation.emission_span, Expectation { rationale, note }, ); diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 25cc788b63bfa..3ac1d0e08af73 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,3 +1,5 @@ +use std::fmt::Debug; + use rustc_ast as ast; use rustc_ast::attr::AttributeExt; use rustc_ast_pretty::pprust; @@ -11,8 +13,8 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_index::IndexVec; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ - LevelSpec, LintExpectation, LintLevelSource, ShallowLintLevelMap, emit_lint_base, - reveal_actual_level_spec, + LevelSpec, LintExpectation, LintLevelSource, ShallowLintLevelMap, StableLevelSpec, + UnstableLevelSpec, emit_lint_base, reveal_actual_level_spec, }; use rustc_middle::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; @@ -21,8 +23,10 @@ use rustc_session::lint::builtin::{ self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES, }; -use rustc_session::lint::{Level, Lint, LintExpectationId, LintId}; -use rustc_span::{DUMMY_SP, Span, Symbol, sym}; +use rustc_session::lint::{ + Level, Lint, LintExpectationId, LintId, StableLintExpectationId, UnstableLintExpectationId, +}; +use rustc_span::{AttrId, DUMMY_SP, Span, Symbol, sym}; use tracing::{debug, instrument}; use crate::builtin::MISSING_DOCS; @@ -64,9 +68,7 @@ rustc_index::newtype_index! { /// to find the specifications for a given lint. #[derive(Debug)] struct LintSet { - // -A,-W,-D flags, a `Symbol` for the flag itself and `LevelSpec` for which - // flag. - specs: FxIndexMap, + specs: FxIndexMap, parent: LintStackIndex, } @@ -79,9 +81,9 @@ impl LintLevelSets { &self, lint: &'static Lint, idx: LintStackIndex, - aux: Option<&FxIndexMap>, + aux: Option<&FxIndexMap>, sess: &Session, - ) -> LevelSpec { + ) -> UnstableLevelSpec { reveal_actual_level_spec(sess, LintId::of(lint), |id| { self.raw_lint_level_spec(id, idx, aux) }) @@ -91,8 +93,8 @@ impl LintLevelSets { &self, id: LintId, mut idx: LintStackIndex, - aux: Option<&FxIndexMap>, - ) -> Option { + aux: Option<&FxIndexMap>, + ) -> Option { if let Some(specs) = aux && let Some(level_spec) = specs.get(&id) { @@ -213,26 +215,53 @@ pub struct TopDown { } pub trait LintLevelsProvider { - fn current_specs(&self) -> &FxIndexMap; - fn insert(&mut self, id: LintId, level_spec: LevelSpec); - fn get_lint_level_spec(&self, lint: &'static Lint, sess: &Session) -> LevelSpec; - fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation); + type LintExpectationId: Copy + Debug + Into; + + fn current_specs(&self) -> &FxIndexMap>; + + fn insert(&mut self, id: LintId, level_spec: LevelSpec); + + fn get_lint_level_spec( + &self, + lint: &'static Lint, + sess: &Session, + ) -> LevelSpec; + + fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation); + + fn mk_lint_expectation_id( + &self, + attr_id: AttrId, + attr_index: usize, + lint_index: Option, + ) -> Self::LintExpectationId; } impl LintLevelsProvider for TopDown { - fn current_specs(&self) -> &FxIndexMap { + type LintExpectationId = UnstableLintExpectationId; + + fn current_specs(&self) -> &FxIndexMap { &self.sets.list[self.cur].specs } - fn insert(&mut self, id: LintId, level_spec: LevelSpec) { + fn insert(&mut self, id: LintId, level_spec: UnstableLevelSpec) { self.sets.list[self.cur].specs.insert(id, level_spec); } - fn get_lint_level_spec(&self, lint: &'static Lint, sess: &Session) -> LevelSpec { + fn get_lint_level_spec(&self, lint: &'static Lint, sess: &Session) -> UnstableLevelSpec { self.sets.get_lint_level_spec(lint, self.cur, Some(self.current_specs()), sess) } - fn push_expectation(&mut self, _: LintExpectationId, _: LintExpectation) {} + fn push_expectation(&mut self, _: Self::LintExpectationId, _: LintExpectation) {} + + fn mk_lint_expectation_id( + &self, + attr_id: AttrId, + _attr_index: usize, + lint_index: Option, + ) -> Self::LintExpectationId { + UnstableLintExpectationId { attr_id, lint_index } + } } struct LintLevelQueryMap<'tcx> { @@ -240,33 +269,44 @@ struct LintLevelQueryMap<'tcx> { cur: HirId, specs: ShallowLintLevelMap, /// Empty hash map to simplify code. - empty: FxIndexMap, + empty: FxIndexMap, attrs: &'tcx hir::AttributeMap<'tcx>, } impl LintLevelsProvider for LintLevelQueryMap<'_> { - fn current_specs(&self) -> &FxIndexMap { + type LintExpectationId = StableLintExpectationId; + + fn current_specs(&self) -> &FxIndexMap { self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty) } - fn insert(&mut self, id: LintId, level_spec: LevelSpec) { + + fn insert(&mut self, id: LintId, level_spec: StableLevelSpec) { self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, level_spec); } - fn get_lint_level_spec(&self, lint: &'static Lint, _: &Session) -> LevelSpec { + + fn get_lint_level_spec(&self, lint: &'static Lint, _: &Session) -> StableLevelSpec { self.specs.lint_level_spec_at_node(self.tcx, LintId::of(lint), self.cur) } - fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) { + + fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation) { self.specs.expectations.push((id, expectation)) } + + fn mk_lint_expectation_id( + &self, + _attr_id: AttrId, + attr_index: usize, + lint_index: Option, + ) -> Self::LintExpectationId { + let attr_index = attr_index.try_into().unwrap(); + StableLintExpectationId { hir_id: self.cur, attr_index, lint_index } + } } impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { fn add_id(&mut self, hir_id: HirId) { self.provider.cur = hir_id; - self.add( - self.provider.attrs.get(hir_id.local_id), - hir_id == hir::CRATE_HIR_ID, - Some(hir_id), - ); + self.add(self.provider.attrs.get(hir_id.local_id), hir_id == hir::CRATE_HIR_ID); } } @@ -386,7 +426,7 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { crate_attrs: &[ast::Attribute], ) -> Self { let mut builder = Self::new(sess, features, lint_added_lints, store, registered_tools); - builder.add(crate_attrs, true, None); + builder.add(crate_attrs, true); builder } @@ -413,16 +453,12 @@ impl<'s> LintLevelsBuilder<'s, TopDown> { /// `#[allow]` /// /// Don't forget to call `pop`! - pub(crate) fn push( - &mut self, - attrs: &[ast::Attribute], - is_crate_node: bool, - ) -> BuilderPush { + pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush { let prev = self.provider.cur; self.provider.cur = self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev }); - self.add(attrs, is_crate_node, None); + self.add(attrs, is_crate_node); if self.provider.current_specs().is_empty() { self.provider.sets.list.pop(); @@ -446,7 +482,10 @@ impl Drop for BuilderPush { } } -impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { +impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> +where + LevelSpec: Into, +{ pub(crate) fn sess(&self) -> &Session { self.sess } @@ -455,11 +494,11 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { self.features } - fn current_specs(&self) -> &FxIndexMap { + fn current_specs(&self) -> &FxIndexMap> { self.provider.current_specs() } - fn insert(&mut self, id: LintId, level_spec: LevelSpec) { + fn insert(&mut self, id: LintId, level_spec: LevelSpec) { self.provider.insert(id, level_spec) } @@ -536,7 +575,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { /// Attempts to insert the `id` to `LevelSpec` map entry. If unsuccessful /// (e.g. if a forbid was already inserted on the same scope), then emits a /// diagnostic with no change to `specs`. - fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec) { + fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec) { let level = level_spec.level(); let lint_id = level_spec.lint_id(); let src = level_spec.src; @@ -561,7 +600,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { // as preventing `allow(lint)` for some lint `lint` in // `lint_group`. For now, issue a future-compatibility // warning for this case. - let id_name = id.lint.name_lower(); let fcw_warning = match old_src { LintLevelSource::Default => false, LintLevelSource::Node { name, .. } => self.store.is_lint_group(name), @@ -572,7 +610,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { fcw_warning, self.current_specs(), old_src, - id_name + id.lint.name_lower(), ); let sub = match old_src { LintLevelSource::Default => { @@ -637,12 +675,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { }; } - fn add( - &mut self, - attrs: &[impl AttributeExt], - is_crate_node: bool, - source_hir_id: Option, - ) { + fn add(&mut self, attrs: &[impl AttributeExt], is_crate_node: bool) { let sess = self.sess; for (attr_index, attr) in attrs.iter().enumerate() { if attr.is_automatically_derived_attr() { @@ -662,23 +695,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { continue; } - let (level, lint_id) = match Level::from_opt_symbol(attr.name()) { + let level = match Level::from_opt_symbol(attr.name()) { None => continue, - // `Expect` is the only lint level with a `LintExpectationId` that can be created - // from an attribute. - Some(Level::Expect) => { - let id = if let Some(hir_id) = source_hir_id { - LintExpectationId::Stable { - hir_id, - attr_index: attr_index.try_into().unwrap(), - lint_index: None, - } - } else { - LintExpectationId::Unstable { attr_id: attr.id(), lint_index: None } - }; - (Level::Expect, Some(id)) - } - Some(level) => (level, None), + Some(level) => level, }; let Some(mut metas) = attr.meta_item_list() else { continue }; @@ -726,10 +745,15 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } for (lint_index, li) in metas.iter_mut().enumerate() { - let mut lint_id = lint_id; - if let Some(id) = &mut lint_id { - id.set_lint_index(Some(lint_index as u16)); - } + // `Expect` is the only lint level with a `LintExpectationId` that can be created + // from an attribute. + let lint_id = (level == Level::Expect).then(|| { + self.provider.mk_lint_expectation_id( + attr.id(), + attr_index, + Some(lint_index as u16), + ) + }); let sp = li.span(); let meta_item = match li { @@ -987,7 +1011,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { } /// Find the lint level for a lint. - pub fn lint_level_spec(&self, lint: &'static Lint) -> LevelSpec { + pub fn lint_level_spec(&self, lint: &'static Lint) -> LevelSpec { self.provider.get_lint_level_spec(lint, self.sess) } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 2e690c7185f8c..fc8b2b65a8d48 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -100,47 +100,48 @@ pub enum Applicability { /// have that amount of lints listed. `u16` values should therefore suffice. #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Encodable, Decodable)] pub enum LintExpectationId { - /// Used for lints emitted during the `EarlyLintPass`. This id is not - /// hash stable and should not be cached. - Unstable { attr_id: AttrId, lint_index: Option }, - /// The [`HirId`] that the lint expectation is attached to. This id is - /// stable and can be cached. The additional index ensures that nodes with - /// several expectations can correctly match diagnostics to the individual - /// expectation. - Stable { hir_id: HirId, attr_index: u16, lint_index: Option }, -} - -impl LintExpectationId { - pub fn is_stable(&self) -> bool { - match self { - LintExpectationId::Unstable { .. } => false, - LintExpectationId::Stable { .. } => true, - } - } + Unstable(UnstableLintExpectationId), + Stable(StableLintExpectationId), +} - pub fn set_lint_index(&mut self, new_lint_index: Option) { - let (LintExpectationId::Unstable { lint_index, .. } - | LintExpectationId::Stable { lint_index, .. }) = self; +/// Used for lints emitted during the `EarlyLintPass`. This id is not hash +/// stable and should not be cached. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Encodable, Decodable)] +pub struct UnstableLintExpectationId { + pub attr_id: AttrId, + pub lint_index: Option, +} - *lint_index = new_lint_index +impl From for LintExpectationId { + fn from(id: UnstableLintExpectationId) -> LintExpectationId { + LintExpectationId::Unstable(id) } } -impl StableHash for LintExpectationId { +/// The [`HirId`] that the lint expectation is attached to. This id is stable +/// and can be cached. The additional index ensures that nodes with several +/// expectations can correctly match diagnostics to the individual expectation. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Encodable, Decodable)] +pub struct StableLintExpectationId { + pub hir_id: HirId, + pub attr_index: u16, + pub lint_index: Option, +} + +impl StableHash for StableLintExpectationId { #[inline] fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { - match self { - LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { - hir_id.stable_hash(hcx, hasher); - attr_index.stable_hash(hcx, hasher); - lint_index.stable_hash(hcx, hasher); - } - _ => { - unreachable!( - "StableHash should only be called for filled and stable `LintExpectationId`" - ) - } - } + let StableLintExpectationId { hir_id, attr_index, lint_index } = self; + + hir_id.stable_hash(hcx, hasher); + attr_index.stable_hash(hcx, hasher); + lint_index.expect("must be filled to call `stable_hash`").stable_hash(hcx, hasher); + } +} + +impl From for LintExpectationId { + fn from(id: StableLintExpectationId) -> LintExpectationId { + LintExpectationId::Stable(id) } } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 41eeb1fc9811f..c1a9c6df72ae3 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -8,7 +8,8 @@ use rustc_lint_defs::EditionFcw; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_session::Session; use rustc_session::lint::{ - FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId, builtin, + FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId, StableLintExpectationId, + UnstableLintExpectationId, builtin, }; use rustc_span::{DUMMY_SP, ExpnKind, Span, Symbol, kw}; use tracing::instrument; @@ -55,7 +56,7 @@ impl LintLevelSource { /// Convenience helper for things that are frequently used together. #[derive(Copy, Clone, Debug, StableHash, Encodable, Decodable)] -pub struct LevelSpec { +pub struct LevelSpec { // This field *must* be private. It must be set in tandem with `lint_id`, only in // `LevelSpec::new`, because only certain `level`/`lint_id` combinations are valid. See // `LevelSpec::new` for those combinations. @@ -68,18 +69,17 @@ pub struct LevelSpec { level: Level, // This field *must* be private. See the comment on `level`. - lint_id: Option, + lint_id: Option, pub src: LintLevelSource, } -impl LevelSpec { +pub type UnstableLevelSpec = LevelSpec; +pub type StableLevelSpec = LevelSpec; + +impl LevelSpec { // Panics if an invalid `level`/`lint_id` combination is given. - pub fn new( - level: Level, - lint_id: Option, - src: LintLevelSource, - ) -> LevelSpec { + pub fn new(level: Level, lint_id: Option, src: LintLevelSource) -> LevelSpec { match (level, lint_id) { (Level::Allow | Level::Warn | Level::Deny | Level::Forbid, None) => {} (Level::Expect, Some(_)) => {} @@ -101,29 +101,45 @@ impl LevelSpec { self.level == Level::Expect } - pub fn lint_id(self) -> Option { + pub fn lint_id(self) -> Option { self.lint_id } } +impl From for LevelSpec { + fn from(level: UnstableLevelSpec) -> LevelSpec { + let LevelSpec { level, lint_id, src } = level; + let lint_id = lint_id.map(LintExpectationId::Unstable); + LevelSpec { level, lint_id, src } + } +} + +impl From for LevelSpec { + fn from(level: StableLevelSpec) -> LevelSpec { + let LevelSpec { level, lint_id, src } = level; + let lint_id = lint_id.map(LintExpectationId::Stable); + LevelSpec { level, lint_id, src } + } +} + /// Return type for the `shallow_lint_levels_on` query. /// /// This map represents the set of allowed lints and allowance levels given /// by the attributes for *a single HirId*. #[derive(Default, Debug, StableHash)] pub struct ShallowLintLevelMap { - pub expectations: Vec<(LintExpectationId, LintExpectation)>, - pub specs: SortedMap>, + pub expectations: Vec<(StableLintExpectationId, LintExpectation)>, + pub specs: SortedMap>, } /// Verify the effect of special annotations: `warnings` lint level and lint caps. /// /// The return of this function is suitable for diagnostics. -pub fn reveal_actual_level_spec( +pub fn reveal_actual_level_spec( sess: &Session, lint: LintId, - probe_for_lint_level_spec: impl Fn(LintId) -> Option, -) -> LevelSpec { + probe_for_lint_level_spec: impl Fn(LintId) -> Option>, +) -> LevelSpec { let level_spec = probe_for_lint_level_spec(lint); // If `level` is none then we actually assume the default level for this lint. @@ -185,7 +201,7 @@ impl ShallowLintLevelMap { tcx: TyCtxt<'_>, id: LintId, start: HirId, - ) -> Option { + ) -> Option { if let Some(map) = self.specs.get(&start.local_id) && let Some(level_spec) = map.get(&id) { @@ -212,7 +228,12 @@ impl ShallowLintLevelMap { /// Fetch and return the user-visible lint level spec for the given lint at the given HirId. #[instrument(level = "trace", skip(self, tcx), ret)] - pub fn lint_level_spec_at_node(&self, tcx: TyCtxt<'_>, lint: LintId, cur: HirId) -> LevelSpec { + pub fn lint_level_spec_at_node( + &self, + tcx: TyCtxt<'_>, + lint: LintId, + cur: HirId, + ) -> StableLevelSpec { reveal_actual_level_spec(tcx.sess, lint, |lint| { self.probe_for_lint_level_spec(tcx, lint, cur) }) @@ -221,7 +242,7 @@ impl ShallowLintLevelMap { impl TyCtxt<'_> { /// Fetch and return the user-visible lint level spec for the given lint at the given HirId. - pub fn lint_level_spec_at_node(self, lint: &'static Lint, id: HirId) -> LevelSpec { + pub fn lint_level_spec_at_node(self, lint: &'static Lint, id: HirId) -> StableLevelSpec { self.shallow_lint_levels_on(id.owner).lint_level_spec_at_node(self, LintId::of(lint), id) } } @@ -362,7 +383,7 @@ fn explain_lint_level_source( pub fn emit_lint_base<'a, D: Diagnostic<'a, ()> + 'a>( sess: &'a Session, lint: &'static Lint, - level_spec: LevelSpec, + level_spec: impl Into, span: Option, decorate: D, ) { @@ -556,7 +577,7 @@ pub fn emit_lint_base<'a, D: Diagnostic<'a, ()> + 'a>( emit_lint_base_impl( sess, lint, - level_spec, + level_spec.into(), span, Box::new(move |dcx, level| decorate.into_diag(dcx, level)), ); diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index a9fc5dcac8f29..d62e4ec941d21 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -75,7 +75,7 @@ use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolMangli use rustc_session::cstore::{ CrateDepKind, CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib, }; -use rustc_session::lint::LintExpectationId; +use rustc_session::lint::StableLintExpectationId; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, LocalExpnId, Span, Spanned, Symbol}; use rustc_target::spec::PanicStrategy; @@ -558,7 +558,7 @@ rustc_queries! { desc { "looking up lint levels for `{}`", tcx.def_path_str(key) } } - query lint_expectations(_: ()) -> &'tcx Vec<(LintExpectationId, LintExpectation)> { + query lint_expectations(_: ()) -> &'tcx Vec<(StableLintExpectationId, LintExpectation)> { arena_cache desc { "computing `#[expect]`ed lints in this crate" } } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 5d3ea7e2c237c..92a0f14f3e94e 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::{self, AssocTag, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; use rustc_session::lint::builtin::{DEAD_CODE, DEAD_CODE_PUB_IN_BINARY}; -use rustc_session::lint::{self, Lint, LintExpectationId}; +use rustc_session::lint::{self, Lint, StableLintExpectationId}; use rustc_span::{Symbol, kw}; use crate::errors::{ @@ -1035,7 +1035,7 @@ fn mark_live_symbols_and_ignored_derived_traits( struct DeadItem { def_id: LocalDefId, name: Symbol, - level_plus: (lint::Level, Option), + level_plus: (lint::Level, Option), } struct DeadVisitor<'tcx> { @@ -1082,7 +1082,10 @@ impl<'tcx> DeadVisitor<'tcx> { ShouldWarnAboutField::Yes } - fn def_lint_level_plus(&self, id: LocalDefId) -> (lint::Level, Option) { + fn def_lint_level_plus( + &self, + id: LocalDefId, + ) -> (lint::Level, Option) { let hir_id = self.tcx.local_def_id_to_hir_id(id); let level_spec = self.tcx.lint_level_spec_at_node(self.target_lint, hir_id); (level_spec.level(), level_spec.lint_id()) @@ -1267,7 +1270,7 @@ impl<'tcx> DeadVisitor<'tcx> { return; } // FIXME: `dead_codes` should probably be morally equivalent to - // `IndexMap<(Level, LintExpectationId), (DefId, Symbol)>` + // `IndexMap<(Level, StableLintExpectationId), (DefId, Symbol)>` dead_codes.sort_by_key(|v| v.level_plus.0); for group in dead_codes.chunk_by(|a, b| a.level_plus == b.level_plus) { self.lint_at_single_level(&group, participle, Some(def_id), report_on); diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs index cb3cb2479beed..f1837e776e824 100644 --- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs +++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind}; use rustc_errors::MultiSpan; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; -use rustc_middle::lint::LevelSpec; +use rustc_middle::lint::UnstableLevelSpec; use rustc_session::impl_lint_pass; use rustc_span::{FileName, Span}; use std::collections::BTreeMap; @@ -51,7 +51,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]); struct Modules { local_path: PathBuf, spans: Vec, - lint_level_specs: Vec, + lint_level_specs: Vec, } #[derive(Default)] @@ -96,7 +96,7 @@ impl EarlyLintPass for DuplicateMod { .zip(lint_level_specs) .filter_map(|(span, level_spec)| { if let Some(id) = level_spec.lint_id() { - cx.fulfill_expectation(id); + cx.fulfill_expectation(id.into()); } (!matches!(level_spec.level(), Level::Allow | Level::Expect)).then_some(*span) From 36738a1f0ea86192f4c15313271a095a1d9b7e0c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 May 2026 11:05:48 +1000 Subject: [PATCH 12/13] Remove some low-value method wrappers I find these make the code harder to understand. --- compiler/rustc_lint/src/levels.rs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 3ac1d0e08af73..b8da46594cfc2 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -494,14 +494,6 @@ where self.features } - fn current_specs(&self) -> &FxIndexMap> { - self.provider.current_specs() - } - - fn insert(&mut self, id: LintId, level_spec: LevelSpec) { - self.provider.insert(id, level_spec) - } - fn add_command_line(&mut self) { for &(ref lint_name, level) in &self.sess.opts.lint_opts { // Checks the validity of lint names derived from the command line. @@ -558,7 +550,7 @@ where }; for &id in ids { // ForceWarn and Forbid cannot be overridden - if let Some(level_spec) = self.current_specs().get(&id) + if let Some(level_spec) = self.provider.current_specs().get(&id) && matches!(level_spec.level(), Level::ForceWarn | Level::Forbid) { continue; @@ -566,7 +558,7 @@ where if self.check_gated_lint(id, DUMMY_SP, true) { let src = LintLevelSource::CommandLine(lint_flag_val, level); - self.insert(id, LevelSpec::new(level, None, src)); + self.provider.insert(id, LevelSpec::new(level, None, src)); } } } @@ -608,7 +600,7 @@ where debug!( "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}", fcw_warning, - self.current_specs(), + self.provider.current_specs(), old_src, id.lint.name_lower(), ); @@ -664,14 +656,14 @@ where match (old_level, level) { // If the new level is an expectation store it in `ForceWarn` (Level::ForceWarn, Level::Expect) => { - self.insert(id, LevelSpec::new(Level::ForceWarn, lint_id, old_src)) + self.provider.insert(id, LevelSpec::new(Level::ForceWarn, lint_id, old_src)) } // Keep `ForceWarn` level but drop the expectation (Level::ForceWarn, _) => { - self.insert(id, LevelSpec::new(Level::ForceWarn, None, old_src)) + self.provider.insert(id, LevelSpec::new(Level::ForceWarn, None, old_src)) } // Set the lint level as normal - _ => self.insert(id, LevelSpec::new(level, lint_id, src)), + _ => self.provider.insert(id, LevelSpec::new(level, lint_id, src)), }; } @@ -679,7 +671,7 @@ where let sess = self.sess; for (attr_index, attr) in attrs.iter().enumerate() { if attr.is_automatically_derived_attr() { - self.insert( + self.provider.insert( LintId::of(SINGLE_USE_LIFETIMES), LevelSpec::new(Level::Allow, None, LintLevelSource::Default), ); @@ -688,7 +680,7 @@ where // `#[doc(hidden)]` disables missing_docs check. if attr.is_doc_hidden() { - self.insert( + self.provider.insert( LintId::of(MISSING_DOCS), LevelSpec::new(Level::Allow, None, LintLevelSource::Default), ); @@ -925,7 +917,7 @@ where } if self.lint_added_lints && !is_crate_node { - for (id, level_spec) in self.current_specs().iter() { + for (id, level_spec) in self.provider.current_specs().iter() { if !id.lint.crate_level_only { continue; } From 6c9d519d37493f076d9983cf4c8b7fb9f90de8ff Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 May 2026 12:40:44 +1000 Subject: [PATCH 13/13] Add some comments to `ShallowLintLevelMap` Describing things that took me a while to work out. --- compiler/rustc_middle/src/lint.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index c1a9c6df72ae3..aa4b8f1d12c9f 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -124,12 +124,15 @@ impl From for LevelSpec { /// Return type for the `shallow_lint_levels_on` query. /// -/// This map represents the set of allowed lints and allowance levels given -/// by the attributes for *a single HirId*. +/// This map represents lints levels given by the attributes for *a single HirId*. #[derive(Default, Debug, StableHash)] pub struct ShallowLintLevelMap { - pub expectations: Vec<(StableLintExpectationId, LintExpectation)>, + // All the specs for this HirId. This is accessed frequently, e.g. for every lint emitted. pub specs: SortedMap>, + + // Additional information about the `expect` specs for this HirId. This is consulted only once + // per compilation session, in `check_expectations`/`lint_expectations`. + pub expectations: Vec<(StableLintExpectationId, LintExpectation)>, } /// Verify the effect of special annotations: `warnings` lint level and lint caps.