From 9014fdafc6040c8d4216c854e281011f4afd3a96 Mon Sep 17 00:00:00 2001 From: Trivaxy Date: Thu, 1 Jan 2026 13:09:29 +0300 Subject: [PATCH 01/25] Update link in suggestion for pinning self --- compiler/rustc_hir_typeck/src/method/suggest.rs | 5 +++-- tests/ui/async-await/issue-108572.stderr | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 331fb91becadd..8f70e70f2090c 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3589,8 +3589,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "method `poll` found on `Pin<&mut {ty_str}>`, \ see documentation for `std::pin::Pin`" )); - err.help("self type must be pinned to call `Future::poll`, \ - see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice" + err.help( + "self type must be pinned to call `Future::poll`, \ + see https://rust-lang.github.io/async-book/part-reference/pinning.html", ); } diff --git a/tests/ui/async-await/issue-108572.stderr b/tests/ui/async-await/issue-108572.stderr index 6a80bc1491062..f8da064da9c4c 100644 --- a/tests/ui/async-await/issue-108572.stderr +++ b/tests/ui/async-await/issue-108572.stderr @@ -5,7 +5,7 @@ LL | fut.poll(cx); | ^^^^ method not found in `impl Future` | = help: method `poll` found on `Pin<&mut impl Future>`, see documentation for `std::pin::Pin` - = help: self type must be pinned to call `Future::poll`, see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice + = help: self type must be pinned to call `Future::poll`, see https://rust-lang.github.io/async-book/part-reference/pinning.html help: consider pinning the expression | LL ~ let mut pinned = std::pin::pin!(fut); From 2484cfe00755af8477921d68a9c665821c0777c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Nov 2025 08:54:18 +0100 Subject: [PATCH 02/25] ptr::replace: make calls on ZST null ptr not UB --- library/core/src/ptr/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index ad74a8628c61c..cb75cd9a2a578 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1543,7 +1543,7 @@ pub const unsafe fn replace(dst: *mut T, src: T) -> T { // SAFETY: the caller must guarantee that `dst` is valid to be // cast to a mutable reference (valid for writes, aligned, initialized), // and cannot overlap `src` since `dst` must point to a distinct - // allocation. + // allocation. We are excluding null (with a ZST check) before creating a reference. unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, @@ -1554,6 +1554,13 @@ pub const unsafe fn replace(dst: *mut T, src: T) -> T { is_zst: bool = T::IS_ZST, ) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst) ); + if T::IS_ZST { + // `dst` may be valid for read and writes while also being null, in which case we cannot + // call `mem::replace`. However, we also don't have to actually do anything since there + // isn't actually any data to be copied anyway. All values of type `T` are + // bit-identical, so we can just return `src` here. + return src; + } mem::replace(&mut *dst, src) } } From b13d69f2c4a27d564ed28d644f4acde959d0c998 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 19 Feb 2026 21:10:55 +0000 Subject: [PATCH 03/25] delete some very old trivial `Box` tests --- tests/ui/box/unit/unique-assign.rs | 8 -------- tests/ui/box/unit/unique-containing-tag.rs | 24 ---------------------- tests/ui/box/unit/unique-create.rs | 10 --------- tests/ui/box/unit/unique-decl-init.rs | 7 ------- tests/ui/box/unit/unique-decl-move.rs | 7 ------- tests/ui/box/unit/unique-decl.rs | 11 ---------- tests/ui/box/unit/unique-deref.rs | 6 ------ tests/ui/box/unit/unique-drop-complex.rs | 5 ----- tests/ui/box/unit/unique-fn-arg-move.rs | 10 --------- tests/ui/box/unit/unique-fn-arg.rs | 11 ---------- tests/ui/box/unit/unique-fn-ret.rs | 9 -------- tests/ui/box/unit/unique-init.rs | 5 ----- tests/ui/box/unit/unique-log.rs | 6 ------ tests/ui/box/unit/unique-match-discrim.rs | 11 ---------- tests/ui/box/unit/unique-move-temp.rs | 8 -------- tests/ui/box/unit/unique-move.rs | 9 -------- tests/ui/box/unit/unique-rec.rs | 9 -------- 17 files changed, 156 deletions(-) delete mode 100644 tests/ui/box/unit/unique-assign.rs delete mode 100644 tests/ui/box/unit/unique-containing-tag.rs delete mode 100644 tests/ui/box/unit/unique-create.rs delete mode 100644 tests/ui/box/unit/unique-decl-init.rs delete mode 100644 tests/ui/box/unit/unique-decl-move.rs delete mode 100644 tests/ui/box/unit/unique-decl.rs delete mode 100644 tests/ui/box/unit/unique-deref.rs delete mode 100644 tests/ui/box/unit/unique-drop-complex.rs delete mode 100644 tests/ui/box/unit/unique-fn-arg-move.rs delete mode 100644 tests/ui/box/unit/unique-fn-arg.rs delete mode 100644 tests/ui/box/unit/unique-fn-ret.rs delete mode 100644 tests/ui/box/unit/unique-init.rs delete mode 100644 tests/ui/box/unit/unique-log.rs delete mode 100644 tests/ui/box/unit/unique-match-discrim.rs delete mode 100644 tests/ui/box/unit/unique-move-temp.rs delete mode 100644 tests/ui/box/unit/unique-move.rs delete mode 100644 tests/ui/box/unit/unique-rec.rs diff --git a/tests/ui/box/unit/unique-assign.rs b/tests/ui/box/unit/unique-assign.rs deleted file mode 100644 index 9a2edd806073f..0000000000000 --- a/tests/ui/box/unit/unique-assign.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -#![allow(unused_mut)] - -pub fn main() { - let mut i: Box<_>; - i = Box::new(1); - assert_eq!(*i, 1); -} diff --git a/tests/ui/box/unit/unique-containing-tag.rs b/tests/ui/box/unit/unique-containing-tag.rs deleted file mode 100644 index a9752a64f4df0..0000000000000 --- a/tests/ui/box/unit/unique-containing-tag.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -#![allow(non_camel_case_types)] - - -pub fn main() { - enum t { t1(isize), t2(isize), } - - let _x: Box<_> = Box::new(t::t1(10)); - - /*alt *x { - t1(a) { - assert_eq!(a, 10); - } - _ { panic!(); } - }*/ - - /*alt x { - Box::new(t1(a) { - assert_eq!(a, 10); - }) - _ { panic!(); } - }*/ -} diff --git a/tests/ui/box/unit/unique-create.rs b/tests/ui/box/unit/unique-create.rs deleted file mode 100644 index b3b72971e53c0..0000000000000 --- a/tests/ui/box/unit/unique-create.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -pub fn main() { - let _: Box<_> = Box::new(100); -} - -fn vec() { - vec![0]; -} diff --git a/tests/ui/box/unit/unique-decl-init.rs b/tests/ui/box/unit/unique-decl-init.rs deleted file mode 100644 index 70aad8cf57d5a..0000000000000 --- a/tests/ui/box/unit/unique-decl-init.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass - -pub fn main() { - let i: Box<_> = Box::new(1); - let j = i; - assert_eq!(*j, 1); -} diff --git a/tests/ui/box/unit/unique-decl-move.rs b/tests/ui/box/unit/unique-decl-move.rs deleted file mode 100644 index 11e94f1576da2..0000000000000 --- a/tests/ui/box/unit/unique-decl-move.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass - -pub fn main() { - let i: Box<_> = Box::new(100); - let j = i; - assert_eq!(*j, 100); -} diff --git a/tests/ui/box/unit/unique-decl.rs b/tests/ui/box/unit/unique-decl.rs deleted file mode 100644 index 1ff5c9007f4d2..0000000000000 --- a/tests/ui/box/unit/unique-decl.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - - -pub fn main() { - let _: Box; -} - -fn f(_i: Box) -> Box { - panic!(); -} diff --git a/tests/ui/box/unit/unique-deref.rs b/tests/ui/box/unit/unique-deref.rs deleted file mode 100644 index aa69a936308db..0000000000000 --- a/tests/ui/box/unit/unique-deref.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass - -pub fn main() { - let i: Box<_> = Box::new(100); - assert_eq!(*i, 100); -} diff --git a/tests/ui/box/unit/unique-drop-complex.rs b/tests/ui/box/unit/unique-drop-complex.rs deleted file mode 100644 index 6e5fb524f41e5..0000000000000 --- a/tests/ui/box/unit/unique-drop-complex.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ run-pass - -pub fn main() { - let _x: Box<_> = Box::new(vec![0,0,0,0,0]); -} diff --git a/tests/ui/box/unit/unique-fn-arg-move.rs b/tests/ui/box/unit/unique-fn-arg-move.rs deleted file mode 100644 index a57e9b932f115..0000000000000 --- a/tests/ui/box/unit/unique-fn-arg-move.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass - -fn f(i: Box) { - assert_eq!(*i, 100); -} - -pub fn main() { - let i = Box::new(100); - f(i); -} diff --git a/tests/ui/box/unit/unique-fn-arg.rs b/tests/ui/box/unit/unique-fn-arg.rs deleted file mode 100644 index 80bb2b61ff6ea..0000000000000 --- a/tests/ui/box/unit/unique-fn-arg.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass - -fn f(i: Box) { - assert_eq!(*i, 100); -} - -pub fn main() { - f(Box::new(100)); - let i = Box::new(100); - f(i); -} diff --git a/tests/ui/box/unit/unique-fn-ret.rs b/tests/ui/box/unit/unique-fn-ret.rs deleted file mode 100644 index a819dc4a5ab63..0000000000000 --- a/tests/ui/box/unit/unique-fn-ret.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -fn f() -> Box { - Box::new(100) -} - -pub fn main() { - assert_eq!(f(), Box::new(100)); -} diff --git a/tests/ui/box/unit/unique-init.rs b/tests/ui/box/unit/unique-init.rs deleted file mode 100644 index 0950c794c4804..0000000000000 --- a/tests/ui/box/unit/unique-init.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ run-pass - -pub fn main() { - let _i: Box<_> = Box::new(100); -} diff --git a/tests/ui/box/unit/unique-log.rs b/tests/ui/box/unit/unique-log.rs deleted file mode 100644 index 86c8cfac81466..0000000000000 --- a/tests/ui/box/unit/unique-log.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass - -pub fn main() { - let i: Box<_> = Box::new(100); - println!("{}", i); -} diff --git a/tests/ui/box/unit/unique-match-discrim.rs b/tests/ui/box/unit/unique-match-discrim.rs deleted file mode 100644 index c1b7b15c7c41d..0000000000000 --- a/tests/ui/box/unit/unique-match-discrim.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass -#![allow(dead_code)] -// Issue #961 - - -fn altsimple() { - match Box::new(true) { - _ => { } - } -} -pub fn main() { } diff --git a/tests/ui/box/unit/unique-move-temp.rs b/tests/ui/box/unit/unique-move-temp.rs deleted file mode 100644 index f86a2a3b7e452..0000000000000 --- a/tests/ui/box/unit/unique-move-temp.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -#![allow(unused_mut)] - -pub fn main() { - let mut i: Box<_>; - i = Box::new(100); - assert_eq!(*i, 100); -} diff --git a/tests/ui/box/unit/unique-move.rs b/tests/ui/box/unit/unique-move.rs deleted file mode 100644 index 04f7d8f051a87..0000000000000 --- a/tests/ui/box/unit/unique-move.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass -#![allow(unused_mut)] - -pub fn main() { - let i: Box<_> = Box::new(100); - let mut j; - j = i; - assert_eq!(*j, 100); -} diff --git a/tests/ui/box/unit/unique-rec.rs b/tests/ui/box/unit/unique-rec.rs deleted file mode 100644 index f13ca0c4acb37..0000000000000 --- a/tests/ui/box/unit/unique-rec.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -struct X { x: isize } - -pub fn main() { - let x: Box<_> = Box::new(X {x: 1}); - let bar = x; - assert_eq!(bar.x, 1); -} From fe29f03e8332fc7d9ebc8f846356ec8639d44cba Mon Sep 17 00:00:00 2001 From: Makai Date: Sat, 21 Feb 2026 01:25:39 +0800 Subject: [PATCH 04/25] rustc_public: `pub(crate)` the fields that shouldn't be exposed --- compiler/rustc_public/src/ty.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index d4f128f87d6ff..5d8e833ac63b1 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -862,17 +862,11 @@ pub struct Discr { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)] pub struct VariantDef { /// The variant index. - /// - /// ## Warning - /// Do not access this field directly! - pub idx: VariantIdx, + pub(crate) idx: VariantIdx, /// The data type where this variant comes from. /// For now, we use this to retrieve information about the variant itself so we don't need to /// cache more information. - /// - /// ## Warning - /// Do not access this field directly! - pub adt_def: AdtDef, + pub(crate) adt_def: AdtDef, } impl VariantDef { @@ -894,10 +888,7 @@ impl VariantDef { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct FieldDef { /// The field definition. - /// - /// ## Warning - /// Do not access this field directly! This is public for the compiler to have access to it. - pub def: DefId, + pub(crate) def: DefId, /// The field name. pub name: Symbol, From 2b3a2da610312c497cc22a49288116666be3ddda Mon Sep 17 00:00:00 2001 From: zedddie Date: Sat, 14 Feb 2026 08:31:07 +0100 Subject: [PATCH 05/25] mGCA: improve diag message with ogca --- .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 14 +++++++++----- compiler/rustc_resolve/src/diagnostics.rs | 4 +++- compiler/rustc_resolve/src/errors.rs | 12 +++++++++++- compiler/rustc_resolve/src/ident.rs | 8 ++++++++ compiler/rustc_resolve/src/late/diagnostics.rs | 2 ++ compiler/rustc_resolve/src/lib.rs | 6 +++++- tests/ui/const-generics/ogca/generic-param-rhs.rs | 9 +++++++++ .../const-generics/ogca/generic-param-rhs.stderr | 10 ++++++++++ tests/ui/const-generics/ogca/rhs-but-not-root.rs | 3 +-- .../ui/const-generics/ogca/rhs-but-not-root.stderr | 4 +++- 10 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 tests/ui/const-generics/ogca/generic-param-rhs.rs create mode 100644 tests/ui/const-generics/ogca/generic-param-rhs.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 3f82375308927..a088fdfa23661 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -385,6 +385,8 @@ impl<'tcx> ForbidMCGParamUsesFolder<'tcx> { fn error(&self) -> ErrorGuaranteed { let msg = if self.is_self_alias { "generic `Self` types are currently not permitted in anonymous constants" + } else if self.tcx.features().opaque_generic_const_args() { + "generic parameters in const blocks are only allowed as the direct value of a `type const`" } else { "generic parameters may not be used in const operations" }; @@ -403,11 +405,13 @@ impl<'tcx> ForbidMCGParamUsesFolder<'tcx> { diag.span_note(impl_.self_ty.span, "not a concrete type"); } } - if self.tcx.features().min_generic_const_args() - && !self.tcx.features().opaque_generic_const_args() - { - diag.help("add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items"); - } + if self.tcx.features().min_generic_const_args() { + if !self.tcx.features().opaque_generic_const_args() { + diag.help("add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items"); + } else { + diag.help("consider factoring the expression into a `type const` item and use it as the const argument instead"); + } + }; diag.emit() } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index ad667df47123f..675cb3e0f352d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1001,12 +1001,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ResolutionError::ParamInTyOfConstParam { name } => { self.dcx().create_err(errs::ParamInTyOfConstParam { span, name }) } - ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => { + ResolutionError::ParamInNonTrivialAnonConst { is_ogca, name, param_kind: is_type } => { self.dcx().create_err(errs::ParamInNonTrivialAnonConst { span, name, param_kind: is_type, help: self.tcx.sess.is_nightly_build(), + is_ogca, + help_ogca: is_ogca, }) } ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 1ca5c17856262..62e2c9deaf4f4 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -405,7 +405,12 @@ pub(crate) struct SelfInConstGenericTy { } #[derive(Diagnostic)] -#[diag("generic parameters may not be used in const operations")] +#[diag( + "{$is_ogca -> + [true] generic parameters in const blocks are only allowed as the direct value of a `type const` + *[false] generic parameters may not be used in const operations +}" +)] pub(crate) struct ParamInNonTrivialAnonConst { #[primary_span] #[label("cannot perform const operation using `{$name}`")] @@ -415,6 +420,11 @@ pub(crate) struct ParamInNonTrivialAnonConst { pub(crate) param_kind: ParamKindInNonTrivialAnonConst, #[help("add `#![feature(generic_const_exprs)]` to allow generic const expressions")] pub(crate) help: bool, + pub(crate) is_ogca: bool, + #[help( + "consider factoring the expression into a `type const` item and use it as the const argument instead" + )] + pub(crate) help_ogca: bool, } #[derive(Debug)] diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 59a5c0728a753..1591456108277 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1554,6 +1554,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } NoConstantGenericsReason::NonTrivialConstArg => { ResolutionError::ParamInNonTrivialAnonConst { + is_ogca: self + .tcx + .features() + .opaque_generic_const_args(), name: rib_ident.name, param_kind: ParamKindInNonTrivialAnonConst::Type, } @@ -1645,6 +1649,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } NoConstantGenericsReason::NonTrivialConstArg => { ResolutionError::ParamInNonTrivialAnonConst { + is_ogca: self + .tcx + .features() + .opaque_generic_const_args(), name: rib_ident.name, param_kind: ParamKindInNonTrivialAnonConst::Const { name: rib_ident.name, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b1d6e3526d9cd..f6bb20b7edb67 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3726,6 +3726,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { name: lifetime_ref.ident.name, param_kind: errors::ParamKindInNonTrivialAnonConst::Lifetime, help: self.r.tcx.sess.is_nightly_build(), + is_ogca: self.r.tcx.features().opaque_generic_const_args(), + help_ogca: self.r.tcx.features().opaque_generic_const_args(), }) .emit() } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1368e5deb6487..45cbc0b3c828d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -309,7 +309,11 @@ enum ResolutionError<'ra> { /// generic parameters must not be used inside const evaluations. /// /// This error is only emitted when using `min_const_generics`. - ParamInNonTrivialAnonConst { name: Symbol, param_kind: ParamKindInNonTrivialAnonConst }, + ParamInNonTrivialAnonConst { + is_ogca: bool, + name: Symbol, + param_kind: ParamKindInNonTrivialAnonConst, + }, /// generic parameters must not be used inside enum discriminants. /// /// This error is emitted even with `generic_const_exprs`. diff --git a/tests/ui/const-generics/ogca/generic-param-rhs.rs b/tests/ui/const-generics/ogca/generic-param-rhs.rs new file mode 100644 index 0000000000000..a62b509190bd6 --- /dev/null +++ b/tests/ui/const-generics/ogca/generic-param-rhs.rs @@ -0,0 +1,9 @@ +#![feature(min_generic_const_args, opaque_generic_const_args)] +#![expect(incomplete_features)] + +fn foo() {} +fn bar() { + foo::(); + //~^ ERROR: generic parameters in const blocks are only allowed as the direct value of a `type const` +} +fn main(){} diff --git a/tests/ui/const-generics/ogca/generic-param-rhs.stderr b/tests/ui/const-generics/ogca/generic-param-rhs.stderr new file mode 100644 index 0000000000000..acf3a5b21a855 --- /dev/null +++ b/tests/ui/const-generics/ogca/generic-param-rhs.stderr @@ -0,0 +1,10 @@ +error: generic parameters in const blocks are only allowed as the direct value of a `type const` + --> $DIR/generic-param-rhs.rs:6:19 + | +LL | foo::(); + | ^ + | + = help: consider factoring the expression into a `type const` item and use it as the const argument instead + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/ogca/rhs-but-not-root.rs b/tests/ui/const-generics/ogca/rhs-but-not-root.rs index 2897b16d493f7..bb6c6b667e1d0 100644 --- a/tests/ui/const-generics/ogca/rhs-but-not-root.rs +++ b/tests/ui/const-generics/ogca/rhs-but-not-root.rs @@ -5,8 +5,7 @@ // Anon consts must be the root of the RHS to be OGCA. type const FOO: usize = ID::; -//~^ ERROR generic parameters may not be used in const operations - +//~^ ERROR generic parameters in const blocks are only allowed as the direct value of a `type const` type const ID: usize = N; fn main() {} diff --git a/tests/ui/const-generics/ogca/rhs-but-not-root.stderr b/tests/ui/const-generics/ogca/rhs-but-not-root.stderr index c720b58b9bde9..6481407eedc42 100644 --- a/tests/ui/const-generics/ogca/rhs-but-not-root.stderr +++ b/tests/ui/const-generics/ogca/rhs-but-not-root.stderr @@ -1,8 +1,10 @@ -error: generic parameters may not be used in const operations +error: generic parameters in const blocks are only allowed as the direct value of a `type const` --> $DIR/rhs-but-not-root.rs:7:54 | LL | type const FOO: usize = ID::; | ^ + | + = help: consider factoring the expression into a `type const` item and use it as the const argument instead error: aborting due to 1 previous error From b9614b2dc2f0baa65469b28b88077f9775e88d13 Mon Sep 17 00:00:00 2001 From: arferreira Date: Mon, 23 Feb 2026 08:09:08 -0500 Subject: [PATCH 06/25] Fix relative path handling for --extern-html-root-url --- src/librustdoc/clean/types.rs | 11 +++- src/librustdoc/html/format.rs | 52 +++++++++++-------- src/librustdoc/html/render/context.rs | 5 +- src/librustdoc/json/mod.rs | 3 +- .../extern/extern-html-root-url-relative.rs | 15 ++++++ 5 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 tests/rustdoc-html/extern/extern-html-root-url-relative.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 8656378a1e264..b370b2bf68260 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -203,7 +203,14 @@ impl ExternalCrate { if !url.ends_with('/') { url.push('/'); } - Remote(url) + let is_absolute = url.starts_with('/') + || url.split_once("://").is_some_and(|(scheme, _)| { + scheme.bytes().next().is_some_and(|b| b.is_ascii_alphabetic()) + && scheme + .bytes() + .all(|b| b.is_ascii_alphanumeric() || matches!(b, b'+' | b'-' | b'.')) + }); + Remote { url, is_absolute } } // See if there's documentation generated into the local directory @@ -316,7 +323,7 @@ impl ExternalCrate { #[derive(Debug)] pub(crate) enum ExternalLocation { /// Remote URL root of the external crate - Remote(String), + Remote { url: String, is_absolute: bool }, /// This external crate can be found in the local doc/ folder Local, /// The external crate could not be found. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 720eb8e5e61df..3fd04449d4ccd 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -402,9 +402,10 @@ fn generate_macro_def_id_path( } let url = match cache.extern_locations[&def_id.krate] { - ExternalLocation::Remote(ref s) => { - // `ExternalLocation::Remote` always end with a `/`. - format!("{s}{path}", path = fmt::from_fn(|f| path.iter().joined("/", f))) + ExternalLocation::Remote { ref url, is_absolute } => { + let mut prefix = remote_url_prefix(url, is_absolute, cx.current.len()); + prefix.extend(path.iter().copied()); + prefix.finish() } ExternalLocation::Local => { // `root_path` always end with a `/`. @@ -458,10 +459,10 @@ fn generate_item_def_id_path( let shortty = ItemType::from_def_id(def_id, tcx); let module_fqp = to_module_fqp(shortty, &fqp); - let mut is_remote = false; + let mut is_absolute = false; - let url_parts = url_parts(cx.cache(), def_id, module_fqp, &cx.current, &mut is_remote)?; - let mut url_parts = make_href(root_path, shortty, url_parts, &fqp, is_remote); + let url_parts = url_parts(cx.cache(), def_id, module_fqp, &cx.current, &mut is_absolute)?; + let mut url_parts = make_href(root_path, shortty, url_parts, &fqp, is_absolute); if def_id != original_def_id { let kind = ItemType::from_def_id(original_def_id, tcx); url_parts = format!("{url_parts}#{kind}.{}", tcx.item_name(original_def_id)) @@ -493,18 +494,29 @@ fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] { if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] } } +fn remote_url_prefix(url: &str, is_absolute: bool, depth: usize) -> UrlPartsBuilder { + let url = url.trim_end_matches('/'); + if is_absolute { + UrlPartsBuilder::singleton(url) + } else { + let extra = depth.saturating_sub(1); + let mut b: UrlPartsBuilder = iter::repeat_n("..", extra).collect(); + b.push(url); + b + } +} + fn url_parts( cache: &Cache, def_id: DefId, module_fqp: &[Symbol], relative_to: &[Symbol], - is_remote: &mut bool, + is_absolute: &mut bool, ) -> Result { match cache.extern_locations[&def_id.krate] { - ExternalLocation::Remote(ref s) => { - *is_remote = true; - let s = s.trim_end_matches('/'); - let mut builder = UrlPartsBuilder::singleton(s); + ExternalLocation::Remote { ref url, is_absolute: abs } => { + *is_absolute = abs; + let mut builder = remote_url_prefix(url, abs, relative_to.len()); builder.extend(module_fqp.iter().copied()); Ok(builder) } @@ -518,9 +530,9 @@ fn make_href( shortty: ItemType, mut url_parts: UrlPartsBuilder, fqp: &[Symbol], - is_remote: bool, + is_absolute: bool, ) -> String { - if !is_remote && let Some(root_path) = root_path { + if !is_absolute && let Some(root_path) = root_path { let root = root_path.trim_end_matches('/'); url_parts.push_front(root); } @@ -583,7 +595,7 @@ pub(crate) fn href_with_root_path( } } - let mut is_remote = false; + let mut is_absolute = false; let (fqp, shortty, url_parts) = match cache.paths.get(&did) { Some(&(ref fqp, shortty)) => (fqp, shortty, { let module_fqp = to_module_fqp(shortty, fqp.as_slice()); @@ -597,7 +609,7 @@ pub(crate) fn href_with_root_path( let def_id_to_get = if root_path.is_some() { original_did } else { did }; if let Some(&(ref fqp, shortty)) = cache.external_paths.get(&def_id_to_get) { let module_fqp = to_module_fqp(shortty, fqp); - (fqp, shortty, url_parts(cache, did, module_fqp, relative_to, &mut is_remote)?) + (fqp, shortty, url_parts(cache, did, module_fqp, relative_to, &mut is_absolute)?) } else if matches!(def_kind, DefKind::Macro(_)) { return generate_macro_def_id_path(did, cx, root_path); } else if did.is_local() { @@ -608,7 +620,7 @@ pub(crate) fn href_with_root_path( } }; Ok(HrefInfo { - url: make_href(root_path, shortty, url_parts, fqp, is_remote), + url: make_href(root_path, shortty, url_parts, fqp, is_absolute), kind: shortty, rust_path: fqp.clone(), }) @@ -762,12 +774,10 @@ fn primitive_link_fragment( } Some(&def_id) => { let loc = match m.extern_locations[&def_id.krate] { - ExternalLocation::Remote(ref s) => { + ExternalLocation::Remote { ref url, is_absolute } => { let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()); - let builder: UrlPartsBuilder = - [s.as_str().trim_end_matches('/'), cname_sym.as_str()] - .into_iter() - .collect(); + let mut builder = remote_url_prefix(url, is_absolute, cx.current.len()); + builder.push(cname_sym.as_str()); Some(builder) } ExternalLocation::Local => { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index b0ea8776425f5..4a7b1d1d6c563 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -386,8 +386,9 @@ impl<'tcx> Context<'tcx> { let e = ExternalCrate { crate_num: cnum }; (e.name(self.tcx()), e.src_root(self.tcx())) } - ExternalLocation::Remote(ref s) => { - root = s.to_string(); + ExternalLocation::Remote { ref url, .. } => { + // FIXME: relative extern URLs are not depth-adjusted for source pages + root = url.to_string(); let e = ExternalCrate { crate_num: cnum }; (e.name(self.tcx()), e.src_root(self.tcx())) } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index a201f661d9f78..7c8e7b7669cd9 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -280,7 +280,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { types::ExternalCrate { name: e.name(self.tcx).to_string(), html_root_url: match external_location { - ExternalLocation::Remote(s) => Some(s.clone()), + // FIXME: relative extern URLs are not resolved here + ExternalLocation::Remote { url, .. } => Some(url.clone()), _ => None, }, path: self diff --git a/tests/rustdoc-html/extern/extern-html-root-url-relative.rs b/tests/rustdoc-html/extern/extern-html-root-url-relative.rs new file mode 100644 index 0000000000000..df6ebf1aedd5a --- /dev/null +++ b/tests/rustdoc-html/extern/extern-html-root-url-relative.rs @@ -0,0 +1,15 @@ +//@ compile-flags:-Z unstable-options --extern-html-root-url core=../ --extern-html-root-takes-precedence + +// At depth 1 (top-level), the href should be ../core/... +//@ has extern_html_root_url_relative/index.html +//@ has - '//a/@href' '../core/iter/index.html' +#[doc(no_inline)] +pub use std::iter; + +// At depth 2 (inside a module), the href should be ../../core/... +pub mod nested { + //@ has extern_html_root_url_relative/nested/index.html + //@ has - '//a/@href' '../../core/iter/index.html' + #[doc(no_inline)] + pub use std::iter; +} From b6083435d81a43bf9393a630804e83a2ffd5b981 Mon Sep 17 00:00:00 2001 From: Makai Date: Mon, 23 Feb 2026 22:19:51 +0800 Subject: [PATCH 07/25] implement debuginfo for unsafe binders --- .../src/debuginfo/metadata.rs | 53 ++++++++++++- .../src/debuginfo/type_names.rs | 14 +++- tests/debuginfo/unsafe-binders.rs | 76 +++++++++++++++++++ .../unsafe-binders-debuginfo.rs} | 5 +- .../unsafe-binders-debuginfo.stderr | 11 +++ 5 files changed, 155 insertions(+), 4 deletions(-) create mode 100644 tests/debuginfo/unsafe-binders.rs rename tests/{crashes/139462.rs => ui/unsafe-binders/unsafe-binders-debuginfo.rs} (58%) create mode 100644 tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index c759d46b7d2ff..04c0b6953290c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -480,8 +480,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( }, ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id), ty::Pat(base, _) => return type_di_node(cx, base), - // FIXME(unsafe_binders): impl debug info - ty::UnsafeBinder(_) => unimplemented!(), + ty::UnsafeBinder(_) => build_unsafe_binder_type_di_node(cx, t, unique_type_id), ty::Alias(..) | ty::Param(_) | ty::Bound(..) @@ -1488,6 +1487,56 @@ fn build_vtable_type_di_node<'ll, 'tcx>( .di_node } +/// Creates the debuginfo node for `unsafe<'a> T` binder types. +/// +/// We treat an unsafe binder like a struct with a single field named `inner` +/// rather than delegating to the inner type's DI node directly. This way the +/// debugger shows the binder's own type name, and the wrapped value is still +/// accessible through the `inner` field. +fn build_unsafe_binder_type_di_node<'ll, 'tcx>( + cx: &CodegenCx<'ll, 'tcx>, + binder_type: Ty<'tcx>, + unique_type_id: UniqueTypeId<'tcx>, +) -> DINodeCreationResult<'ll> { + let ty::UnsafeBinder(inner) = binder_type.kind() else { + bug!( + "Only ty::UnsafeBinder is valid for build_unsafe_binder_type_di_node. Found {:?} instead.", + binder_type + ) + }; + let inner_type = inner.skip_binder(); + let inner_type_di_node = type_di_node(cx, inner_type); + + let type_name = compute_debuginfo_type_name(cx.tcx, binder_type, true); + type_map::build_type_with_children( + cx, + type_map::stub( + cx, + Stub::Struct, + unique_type_id, + &type_name, + None, + cx.size_and_align_of(binder_type), + NO_SCOPE_METADATA, + DIFlags::FlagZero, + ), + |cx, unsafe_binder_type_di_node| { + let inner_layout = cx.layout_of(inner_type); + smallvec![build_field_di_node( + cx, + unsafe_binder_type_di_node, + "inner", + inner_layout, + Size::ZERO, + DIFlags::FlagZero, + inner_type_di_node, + None, + )] + }, + NO_GENERICS, + ) +} + /// Get the global variable for the vtable. /// /// When using global variables, we may have created an addrspacecast to get a pointer to the diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 1c88a8da5ea94..d3b2caca4742d 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -430,7 +430,19 @@ fn push_debuginfo_type_name<'tcx>( push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited); } } - ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"), + ty::UnsafeBinder(inner) => { + if cpp_like_debuginfo { + output.push_str("unsafe$<"); + } else { + output.push_str("unsafe "); + } + + push_debuginfo_type_name(tcx, inner.skip_binder(), qualified, output, visited); + + if cpp_like_debuginfo { + push_close_angle_bracket(cpp_like_debuginfo, output); + } + } ty::Param(_) | ty::Error(_) | ty::Infer(_) diff --git a/tests/debuginfo/unsafe-binders.rs b/tests/debuginfo/unsafe-binders.rs new file mode 100644 index 0000000000000..cd6c87052f2d8 --- /dev/null +++ b/tests/debuginfo/unsafe-binders.rs @@ -0,0 +1,76 @@ +//@ compile-flags: -g +//@ disable-gdb-pretty-printers +//@ ignore-backends: gcc + +// Tests that debuginfo is correctly generated for `unsafe<'a> T` binder types. + +// === GDB TESTS =================================================================================== + +//@ gdb-command:run + +//@ gdb-command:whatis binder_i32 +//@ gdb-check:type = unsafe &i32 + +//@ gdb-command:print unwrapped_i32 +//@ gdb-check:$1 = 67 + +//@ gdb-command:whatis no_lifetime +//@ gdb-check:type = unsafe i32 + +//@ gdb-command:whatis unsafe_binder_tuple +//@ gdb-check:type = unsafe (&i32, &i32) + +//@ gdb-command:whatis binder_tuple_ref +//@ gdb-check:type = (&i32, &i32) + +//@ gdb-command:whatis binder.inner +//@ gdb-check:type = unsafe &i32 + +//@ gdb-command:print wrapper.val +//@ gdb-check:$2 = 99 + +//@ gdb-command:whatis binder_raw +//@ gdb-check:type = unsafe *const i32 + +//@ gdb-command:print binder_raw_val +//@ gdb-check:$3 = 7 + +#![feature(unsafe_binders)] +#[expect(incomplete_features)] + +use std::unsafe_binder::{unwrap_binder, wrap_binder}; + +struct Wrapper { + val: i32, +} + +struct Binder { + inner: unsafe<'a> &'a i32, +} + +fn main() { + let x = 67i32; + let binder_i32: unsafe<'a> &'a i32 = unsafe { wrap_binder!(&x) }; + let unwrapped_i32: i32 = unsafe { *unwrap_binder!(binder_i32) }; + + let y = 123i32; + let no_lifetime: unsafe<> i32 = unsafe { wrap_binder!(y) }; + + let unsafe_binder_tuple: unsafe<'a> (&'a i32, &'a i32) = unsafe { + wrap_binder!((&114i32, &514i32)) + }; + let binder_tuple_ref: (&i32, &i32) = unsafe { unwrap_binder!(unsafe_binder_tuple) }; + + let val = 99i32; + let binder = Binder { inner: unsafe { wrap_binder!(&val) } }; + let wrapper = Wrapper { val: unsafe { *unwrap_binder!(binder.inner) } }; + + let z = 7i32; + let raw: *const i32 = &z; + let binder_raw: unsafe<'a> *const i32 = unsafe { wrap_binder!(raw) }; + let binder_raw_val: i32 = unsafe { *unwrap_binder!(binder_raw) }; + + gugugaga(); // #break +} + +fn gugugaga() { () } diff --git a/tests/crashes/139462.rs b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs similarity index 58% rename from tests/crashes/139462.rs rename to tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs index d3be14b2be2a3..15245d9ba4f23 100644 --- a/tests/crashes/139462.rs +++ b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.rs @@ -1,7 +1,10 @@ -//@ known-bug: #139462 +// This is a regression test for . +//@ check-pass //@ compile-flags: -Cdebuginfo=2 //@ ignore-backends: gcc #![feature(unsafe_binders)] +//~^ WARN the feature `unsafe_binders` is incomplete + use std::unsafe_binder::wrap_binder; fn main() { let foo = 0; diff --git a/tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr new file mode 100644 index 0000000000000..283b8b9c04f6f --- /dev/null +++ b/tests/ui/unsafe-binders/unsafe-binders-debuginfo.stderr @@ -0,0 +1,11 @@ +warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsafe-binders-debuginfo.rs:5:12 + | +LL | #![feature(unsafe_binders)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #130516 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + From 0da2c0c691f9e9ae984f6ae89a277413a29fc5c3 Mon Sep 17 00:00:00 2001 From: Antonio Souza Date: Mon, 23 Feb 2026 13:55:49 -0500 Subject: [PATCH 08/25] Update src/librustdoc/clean/types.rs Co-authored-by: Michael Howell --- src/librustdoc/clean/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index b370b2bf68260..9557ad3304d4e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -204,7 +204,7 @@ impl ExternalCrate { url.push('/'); } let is_absolute = url.starts_with('/') - || url.split_once("://").is_some_and(|(scheme, _)| { + || url.split_once(':').is_some_and(|(scheme, _)| { scheme.bytes().next().is_some_and(|b| b.is_ascii_alphabetic()) && scheme .bytes() From 93b997356aa3a006475c169db42d9279d745bf36 Mon Sep 17 00:00:00 2001 From: Usman Akinyemi Date: Mon, 16 Feb 2026 01:43:17 +0530 Subject: [PATCH 09/25] rustc_expand: improve diagnostics for non-repeatable metavars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Esteban Küber Signed-off-by: Usman Akinyemi --- compiler/rustc_expand/src/base.rs | 11 +++- compiler/rustc_expand/src/mbe/diagnostics.rs | 52 ++++++++++++++++++- compiler/rustc_expand/src/mbe/macro_rules.rs | 46 ++++++++++++++-- tests/ui/macros/issue-6596-1.stderr | 6 ++- tests/ui/macros/typo-in-norepeat-expr-2.rs | 42 +++++++++++++++ .../ui/macros/typo-in-norepeat-expr-2.stderr | 46 ++++++++++++++++ tests/ui/macros/typo-in-norepeat-expr.fixed | 12 +++++ tests/ui/macros/typo-in-norepeat-expr.rs | 12 +++++ tests/ui/macros/typo-in-norepeat-expr.stderr | 18 +++++++ 9 files changed, 239 insertions(+), 6 deletions(-) create mode 100644 tests/ui/macros/typo-in-norepeat-expr-2.rs create mode 100644 tests/ui/macros/typo-in-norepeat-expr-2.stderr create mode 100644 tests/ui/macros/typo-in-norepeat-expr.fixed create mode 100644 tests/ui/macros/typo-in-norepeat-expr.rs create mode 100644 tests/ui/macros/typo-in-norepeat-expr.stderr diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 476be94efd9e4..6315670b499ef 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -277,7 +277,16 @@ impl<'cx> MacroExpanderResult<'cx> { // Emit the SEMICOLON_IN_EXPRESSIONS_FROM_MACROS deprecation lint. let is_local = true; - let parser = ParserAnyMacro::from_tts(cx, tts, site_span, arm_span, is_local, macro_ident); + let parser = ParserAnyMacro::from_tts( + cx, + tts, + site_span, + arm_span, + is_local, + macro_ident, + vec![], + vec![], + ); ExpandResult::Ready(Box::new(parser)) } } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index df6903dc4937f..a689ae16ab224 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -222,11 +222,13 @@ impl<'dcx> CollectTrackerAndEmitter<'dcx, '_> { pub(super) fn emit_frag_parse_err( mut e: Diag<'_>, - parser: &Parser<'_>, + parser: &mut Parser<'_>, orig_parser: &mut Parser<'_>, site_span: Span, arm_span: Span, kind: AstFragmentKind, + bindings: Vec, + matched_rule_bindings: Vec, ) -> ErrorGuaranteed { // FIXME(davidtwco): avoid depending on the error message text if parser.token == token::Eof @@ -285,6 +287,54 @@ pub(super) fn emit_frag_parse_err( }, _ => annotate_err_with_kind(&mut e, kind, site_span), }; + + let matched_rule_bindings_names: Vec<_> = + matched_rule_bindings.iter().map(|bind| bind.name).collect(); + let bindings_name: Vec<_> = bindings.iter().map(|bind| bind.name).collect(); + if parser.token.kind == token::Dollar { + parser.bump(); + if let token::Ident(name, _) = parser.token.kind { + if let Some(matched_name) = rustc_span::edit_distance::find_best_match_for_name( + &matched_rule_bindings_names[..], + name, + None, + ) { + e.span_suggestion_verbose( + parser.token.span, + "there is a macro metavariable with similar name", + format!("{matched_name}"), + Applicability::MaybeIncorrect, + ); + } else if bindings_name.contains(&name) { + e.span_label( + parser.token.span, + format!( + "there is an macro metavariable with this name in another macro matcher" + ), + ); + } else if let Some(matched_name) = + rustc_span::edit_distance::find_best_match_for_name(&bindings_name[..], name, None) + { + e.span_suggestion_verbose( + parser.token.span, + "there is a macro metavariable with a similar name in another macro matcher", + format!("{matched_name}"), + Applicability::MaybeIncorrect, + ); + } else { + let msg = matched_rule_bindings_names + .iter() + .map(|sym| format!("${}", sym)) + .collect::>() + .join(", "); + + e.span_label(parser.token.span, format!("macro metavariable not found")); + if !matched_rule_bindings_names.is_empty() { + e.note(format!("available metavariable names are: {msg}")); + } + } + } + } e.emit() } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 7cd96211de508..07ba34626ac02 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -56,6 +56,8 @@ pub(crate) struct ParserAnyMacro<'a> { arm_span: Span, /// Whether or not this macro is defined in the current crate is_local: bool, + bindings: Vec, + matched_rule_bindings: Vec, } impl<'a> ParserAnyMacro<'a> { @@ -68,13 +70,22 @@ impl<'a> ParserAnyMacro<'a> { arm_span, is_trailing_mac, is_local, + bindings, + matched_rule_bindings, } = *self; let snapshot = &mut parser.create_snapshot_for_diagnostic(); let fragment = match parse_ast_fragment(parser, kind) { Ok(f) => f, Err(err) => { let guar = diagnostics::emit_frag_parse_err( - err, parser, snapshot, site_span, arm_span, kind, + err, + parser, + snapshot, + site_span, + arm_span, + kind, + bindings, + matched_rule_bindings, ); return kind.dummy(site_span, guar); } @@ -109,6 +120,9 @@ impl<'a> ParserAnyMacro<'a> { arm_span: Span, is_local: bool, macro_ident: Ident, + // bindings and lhs is for diagnostics + bindings: Vec, + matched_rule_bindings: Vec, ) -> Self { Self { parser: Parser::new(&cx.sess.psess, tts, None), @@ -122,6 +136,8 @@ impl<'a> ParserAnyMacro<'a> { is_trailing_mac: cx.current_expansion.is_trailing_mac, arm_span, is_local, + bindings, + matched_rule_bindings, } } } @@ -360,7 +376,7 @@ fn expand_macro<'cx>( match try_success_result { Ok((rule_index, rule, named_matches)) => { - let MacroRule::Func { rhs, .. } = rule else { + let MacroRule::Func { lhs, rhs, .. } = rule else { panic!("try_match_macro returned non-func rule"); }; let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { @@ -388,8 +404,32 @@ fn expand_macro<'cx>( cx.resolver.record_macro_rule_usage(node_id, rule_index); } + let mut bindings = vec![]; + for rule in rules { + let MacroRule::Func { lhs, .. } = rule else { continue }; + for param in lhs { + let MatcherLoc::MetaVarDecl { bind, .. } = param else { continue }; + bindings.push(*bind); + } + } + + let mut matched_rule_bindings = vec![]; + for param in lhs { + let MatcherLoc::MetaVarDecl { bind, .. } = param else { continue }; + matched_rule_bindings.push(*bind); + } + // Let the context choose how to interpret the result. Weird, but useful for X-macros. - Box::new(ParserAnyMacro::from_tts(cx, tts, sp, arm_span, is_local, name)) + Box::new(ParserAnyMacro::from_tts( + cx, + tts, + sp, + arm_span, + is_local, + name, + bindings, + matched_rule_bindings, + )) } Err(CanRetry::No(guar)) => { debug!("Will not retry matching as an error was emitted already"); diff --git a/tests/ui/macros/issue-6596-1.stderr b/tests/ui/macros/issue-6596-1.stderr index f20d67329dbe7..cb66dcc6ea890 100644 --- a/tests/ui/macros/issue-6596-1.stderr +++ b/tests/ui/macros/issue-6596-1.stderr @@ -2,11 +2,15 @@ error: expected expression, found `$` --> $DIR/issue-6596-1.rs:3:9 | LL | $nonexistent - | ^^^^^^^^^^^^ expected expression + | ^----------- + | || + | |macro metavariable not found + | expected expression ... LL | e!(foo); | ------- in this macro invocation | + = note: available metavariable names are: $inp = note: this error originates in the macro `e` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/macros/typo-in-norepeat-expr-2.rs b/tests/ui/macros/typo-in-norepeat-expr-2.rs new file mode 100644 index 0000000000000..48b64c248d637 --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr-2.rs @@ -0,0 +1,42 @@ +macro_rules! err { + (begin $follow:ident end $arg:expr) => { + [$arg] + }; + (begin1 $arg1:ident end $agr2:expr) => { + [$follow] //~ ERROR: expected expression, found `$` + //~^ NOTE: there is an macro metavariable with this name in another macro matcher + //~| NOTE: expected expression + }; +} + +macro_rules! err1 { + (begin $follow:ident end $arg:expr) => { + [$arg] + }; + (begin1 $arg1:ident end) => { + [$follo] //~ ERROR: expected expression, found `$` + //~| NOTE: expected expression + //~| HELP: there is a macro metavariable with a similar name in another macro matcher + }; +} + +macro_rules! err2 { + (begin $follow:ident end $arg:expr) => { + [$arg] + }; + (begin1 $arg1:ident end) => { + [$xyz] //~ ERROR: expected expression, found `$` + //~^ NOTE: expected expression + //~| NOTE available metavariable names are: $arg1 + //~| NOTE: macro metavariable not found + }; +} + +fn main () { + let _ = err![begin1 x end ig]; //~ NOTE: in this expansion of err! + let _ = err1![begin1 x end]; //~ NOTE: in this expansion of err1! + //~| NOTE: in this expansion of err1! + + let _ = err2![begin1 x end]; //~ NOTE: in this expansion of err2! + //~| NOTE in this expansion of err2! +} diff --git a/tests/ui/macros/typo-in-norepeat-expr-2.stderr b/tests/ui/macros/typo-in-norepeat-expr-2.stderr new file mode 100644 index 0000000000000..20390cccc9a74 --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr-2.stderr @@ -0,0 +1,46 @@ +error: expected expression, found `$` + --> $DIR/typo-in-norepeat-expr-2.rs:6:10 + | +LL | [$follow] + | ^------ + | || + | |there is an macro metavariable with this name in another macro matcher + | expected expression +... +LL | let _ = err![begin1 x end ig]; + | ---------------------- in this macro invocation + | + = note: this error originates in the macro `err` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `$` + --> $DIR/typo-in-norepeat-expr-2.rs:17:10 + | +LL | [$follo] + | ^^^^^^ expected expression +... +LL | let _ = err1![begin1 x end]; + | -------------------- in this macro invocation + | + = note: this error originates in the macro `err1` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a macro metavariable with a similar name in another macro matcher + | +LL | [$follow] + | + + +error: expected expression, found `$` + --> $DIR/typo-in-norepeat-expr-2.rs:28:10 + | +LL | [$xyz] + | ^--- + | || + | |macro metavariable not found + | expected expression +... +LL | let _ = err2![begin1 x end]; + | -------------------- in this macro invocation + | + = note: available metavariable names are: $arg1 + = note: this error originates in the macro `err2` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/typo-in-norepeat-expr.fixed b/tests/ui/macros/typo-in-norepeat-expr.fixed new file mode 100644 index 0000000000000..a59f461e63120 --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr.fixed @@ -0,0 +1,12 @@ +//@ run-rustfix +macro_rules! m { + (begin $ard:ident end) => { + [$ard] //~ ERROR: expected expression, found `$` + //~^ HELP: there is a macro metavariable with similar name + }; +} + +fn main() { + let x = 1; + let _ = m![begin x end]; +} diff --git a/tests/ui/macros/typo-in-norepeat-expr.rs b/tests/ui/macros/typo-in-norepeat-expr.rs new file mode 100644 index 0000000000000..fe554f07e7552 --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr.rs @@ -0,0 +1,12 @@ +//@ run-rustfix +macro_rules! m { + (begin $ard:ident end) => { + [$arg] //~ ERROR: expected expression, found `$` + //~^ HELP: there is a macro metavariable with similar name + }; +} + +fn main() { + let x = 1; + let _ = m![begin x end]; +} diff --git a/tests/ui/macros/typo-in-norepeat-expr.stderr b/tests/ui/macros/typo-in-norepeat-expr.stderr new file mode 100644 index 0000000000000..8f37957ea98e0 --- /dev/null +++ b/tests/ui/macros/typo-in-norepeat-expr.stderr @@ -0,0 +1,18 @@ +error: expected expression, found `$` + --> $DIR/typo-in-norepeat-expr.rs:4:10 + | +LL | [$arg] + | ^^^^ expected expression +... +LL | let _ = m![begin x end]; + | --------------- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a macro metavariable with similar name + | +LL - [$arg] +LL + [$ard] + | + +error: aborting due to 1 previous error + From 1b50859d36c54d213d77e0ff6aa9c1824a7bf10a Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Sun, 1 Feb 2026 23:13:55 -0500 Subject: [PATCH 10/25] feat: BTreeMap::merge implemented with into iterators only (similar to BTreeMap::append) --- library/alloc/src/collections/btree/append.rs | 60 +++++++++++++ library/alloc/src/collections/btree/map.rs | 75 ++++++++++++++++ .../alloc/src/collections/btree/map/tests.rs | 88 ++++++++++++++++++- library/alloctests/tests/lib.rs | 1 + 4 files changed, 223 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index 66ea22e75247c..38e4542d07905 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -33,6 +33,36 @@ impl Root { self.bulk_push(iter, length, alloc) } + /// Merges all key-value pairs from the union of two ascending iterators, + /// incrementing a `length` variable along the way. The latter makes it + /// easier for the caller to avoid a leak when a drop handler panicks. + /// + /// If both iterators produce the same key, this method constructs a pair using the + /// key from the left iterator and calls on a closure `f` to return a value given + /// the conflicting key and value from left and right iterators. + /// + /// If you want the tree to end up in a strictly ascending order, like for + /// a `BTreeMap`, both iterators should produce keys in strictly ascending + /// order, each greater than all keys in the tree, including any keys + /// already in the tree upon entry. + pub(super) fn merge_from_sorted_iters_with( + &mut self, + left: I, + right: I, + length: &mut usize, + alloc: A, + f: impl FnMut(&K, V, V) -> V, + ) where + K: Ord, + I: Iterator + FusedIterator, + { + // We prepare to merge `left` and `right` into a sorted sequence in linear time. + let iter = MergeIterWith { inner: MergeIterInner::new(left, right), f }; + + // Meanwhile, we build a tree from the sorted sequence in linear time. + self.bulk_push(iter, length, alloc) + } + /// Pushes all key-value pairs to the end of the tree, incrementing a /// `length` variable along the way. The latter makes it easier for the /// caller to avoid a leak when the iterator panicks. @@ -115,3 +145,33 @@ where } } } + +/// An iterator for merging two sorted sequences into one with +/// a callback function to return a value on conflicting keys +struct MergeIterWith> { + inner: MergeIterInner, + f: F, +} + +impl Iterator for MergeIterWith +where + F: FnMut(&K, V, V) -> V, + I: Iterator + FusedIterator, +{ + type Item = (K, V); + + /// If two keys are equal, returns the key from the left and uses `f` to return + /// a value given the conflicting key and values from left and right + fn next(&mut self) -> Option<(K, V)> { + let (a_next, b_next) = self.inner.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0)); + match (a_next, b_next) { + (Some((a_k, a_v)), Some((_, b_v))) => Some({ + let next_val = (self.f)(&a_k, a_v, b_v); + (a_k, next_val) + }), + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + (None, None) => None, + } + } +} diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 426be364a56b0..b33fd21a4a06f 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1240,6 +1240,81 @@ impl BTreeMap { ) } + /// Moves all elements from `other` into `self`, leaving `other` empty. + /// + /// If a key from `other` is already present in `self`, then the `conflict` + /// closure is used to return a value to `self`. The `conflict` + /// closure takes in a borrow of `self`'s key, `self`'s value, and `other`'s value + /// in that order. + /// + /// An example of why one might use this method over [`append`] + /// is to combine `self`'s value with `other`'s value when their keys conflict. + /// + /// Similar to [`insert`], though, the key is not overwritten, + /// which matters for types that can be `==` without being identical. + /// + /// + /// [`insert`]: BTreeMap::insert + /// [`append`]: BTreeMap::append + /// + /// # Examples + /// + /// ``` + /// #![feature(btree_merge)] + /// use std::collections::BTreeMap; + /// + /// let mut a = BTreeMap::new(); + /// a.insert(1, String::from("a")); + /// a.insert(2, String::from("b")); + /// a.insert(3, String::from("c")); // Note: Key (3) also present in b. + /// + /// let mut b = BTreeMap::new(); + /// b.insert(3, String::from("d")); // Note: Key (3) also present in a. + /// b.insert(4, String::from("e")); + /// b.insert(5, String::from("f")); + /// + /// // concatenate a's value and b's value + /// a.merge(b, |_, a_val, b_val| { + /// format!("{a_val}{b_val}") + /// }); + /// + /// assert_eq!(a.len(), 5); // all of b's keys in a + /// + /// assert_eq!(a[&1], "a"); + /// assert_eq!(a[&2], "b"); + /// assert_eq!(a[&3], "cd"); // Note: "c" has been combined with "d". + /// assert_eq!(a[&4], "e"); + /// assert_eq!(a[&5], "f"); + /// ``` + #[unstable(feature = "btree_merge", issue = "152152")] + pub fn merge(&mut self, mut other: Self, conflict: impl FnMut(&K, V, V) -> V) + where + K: Ord, + A: Clone, + { + // Do we have to append anything at all? + if other.is_empty() { + return; + } + + // We can just swap `self` and `other` if `self` is empty. + if self.is_empty() { + mem::swap(self, &mut other); + return; + } + + let self_iter = mem::replace(self, Self::new_in((*self.alloc).clone())).into_iter(); + let other_iter = mem::replace(&mut other, Self::new_in((*self.alloc).clone())).into_iter(); + let root = self.root.get_or_insert_with(|| Root::new((*self.alloc).clone())); + root.merge_from_sorted_iters_with( + self_iter, + other_iter, + &mut self.length, + (*self.alloc).clone(), + conflict, + ) + } + /// Constructs a double-ended iterator over a sub-range of elements in the map. /// The simplest way is to use the range syntax `min..max`, thus `range(min..max)` will /// yield elements from min (inclusive) to max (exclusive). diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 938e867b85812..1b07076142019 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1,9 +1,9 @@ use core::assert_matches; -use std::iter; use std::ops::Bound::{Excluded, Included, Unbounded}; use std::panic::{AssertUnwindSafe, catch_unwind}; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; +use std::{cmp, iter}; use super::*; use crate::boxed::Box; @@ -2128,6 +2128,76 @@ create_append_test!(test_append_239, 239); #[cfg(not(miri))] // Miri is too slow create_append_test!(test_append_1700, 1700); +macro_rules! create_merge_test { + ($name:ident, $len:expr) => { + #[test] + fn $name() { + let mut a = BTreeMap::new(); + for i in 0..8 { + a.insert(i, i); + } + + let mut b = BTreeMap::new(); + for i in 5..$len { + b.insert(i, 2 * i); + } + + a.merge(b, |_, a_val, b_val| a_val + b_val); + + assert_eq!(a.len(), cmp::max($len, 8)); + + for i in 0..cmp::max($len, 8) { + if i < 5 { + assert_eq!(a[&i], i); + } else { + if i < cmp::min($len, 8) { + assert_eq!(a[&i], i + 2 * i); + } else if i >= $len { + assert_eq!(a[&i], i); + } else { + assert_eq!(a[&i], 2 * i); + } + } + } + + a.check(); + assert_eq!( + a.remove(&($len - 1)), + if $len >= 5 && $len < 8 { + Some(($len - 1) + 2 * ($len - 1)) + } else { + Some(2 * ($len - 1)) + } + ); + assert_eq!(a.insert($len - 1, 20), None); + a.check(); + } + }; +} + +// These are mostly for testing the algorithm that "fixes" the right edge after insertion. +// Single node, merge conflicting key values. +create_merge_test!(test_merge_7, 7); +// Single node. +create_merge_test!(test_merge_9, 9); +// Two leafs that don't need fixing. +create_merge_test!(test_merge_17, 17); +// Two leafs where the second one ends up underfull and needs stealing at the end. +create_merge_test!(test_merge_14, 14); +// Two leafs where the second one ends up empty because the insertion finished at the root. +create_merge_test!(test_merge_12, 12); +// Three levels; insertion finished at the root. +create_merge_test!(test_merge_144, 144); +// Three levels; insertion finished at leaf while there is an empty node on the second level. +create_merge_test!(test_merge_145, 145); +// Tests for several randomly chosen sizes. +create_merge_test!(test_merge_170, 170); +create_merge_test!(test_merge_181, 181); +#[cfg(not(miri))] // Miri is too slow +create_merge_test!(test_merge_239, 239); +#[cfg(not(miri))] // Miri is too slow +create_merge_test!(test_merge_1700, 1700); + #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_append_drop_leak() { @@ -2615,3 +2685,19 @@ fn test_id_based_append() { assert_eq!(lhs.pop_first().unwrap().0.name, "lhs_k".to_string()); } + +#[test] +fn test_id_based_merge() { + let mut lhs = BTreeMap::new(); + let mut rhs = BTreeMap::new(); + + lhs.insert(IdBased { id: 0, name: "lhs_k".to_string() }, "1".to_string()); + rhs.insert(IdBased { id: 0, name: "rhs_k".to_string() }, "2".to_string()); + + lhs.merge(rhs, |_, mut lhs_val, rhs_val| { + lhs_val.push_str(&rhs_val); + lhs_val + }); + + assert_eq!(lhs.pop_first().unwrap().0.name, "lhs_k".to_string()); +} diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index e15c86496cf1b..e30bd26307fbf 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -1,5 +1,6 @@ #![feature(allocator_api)] #![feature(binary_heap_pop_if)] +#![feature(btree_merge)] #![feature(const_heap)] #![feature(deque_extend_front)] #![feature(iter_array_chunks)] From 24efac106335824fed59d1490d79d62524a85afb Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Mon, 9 Feb 2026 21:44:34 -0500 Subject: [PATCH 11/25] Optimized BTreeMap::merge using CursorMut --- library/alloc/src/collections/btree/append.rs | 60 -------- library/alloc/src/collections/btree/map.rs | 135 ++++++++++++++++-- .../alloc/src/collections/btree/map/tests.rs | 96 ++++++++++++- 3 files changed, 219 insertions(+), 72 deletions(-) diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs index 38e4542d07905..66ea22e75247c 100644 --- a/library/alloc/src/collections/btree/append.rs +++ b/library/alloc/src/collections/btree/append.rs @@ -33,36 +33,6 @@ impl Root { self.bulk_push(iter, length, alloc) } - /// Merges all key-value pairs from the union of two ascending iterators, - /// incrementing a `length` variable along the way. The latter makes it - /// easier for the caller to avoid a leak when a drop handler panicks. - /// - /// If both iterators produce the same key, this method constructs a pair using the - /// key from the left iterator and calls on a closure `f` to return a value given - /// the conflicting key and value from left and right iterators. - /// - /// If you want the tree to end up in a strictly ascending order, like for - /// a `BTreeMap`, both iterators should produce keys in strictly ascending - /// order, each greater than all keys in the tree, including any keys - /// already in the tree upon entry. - pub(super) fn merge_from_sorted_iters_with( - &mut self, - left: I, - right: I, - length: &mut usize, - alloc: A, - f: impl FnMut(&K, V, V) -> V, - ) where - K: Ord, - I: Iterator + FusedIterator, - { - // We prepare to merge `left` and `right` into a sorted sequence in linear time. - let iter = MergeIterWith { inner: MergeIterInner::new(left, right), f }; - - // Meanwhile, we build a tree from the sorted sequence in linear time. - self.bulk_push(iter, length, alloc) - } - /// Pushes all key-value pairs to the end of the tree, incrementing a /// `length` variable along the way. The latter makes it easier for the /// caller to avoid a leak when the iterator panicks. @@ -145,33 +115,3 @@ where } } } - -/// An iterator for merging two sorted sequences into one with -/// a callback function to return a value on conflicting keys -struct MergeIterWith> { - inner: MergeIterInner, - f: F, -} - -impl Iterator for MergeIterWith -where - F: FnMut(&K, V, V) -> V, - I: Iterator + FusedIterator, -{ - type Item = (K, V); - - /// If two keys are equal, returns the key from the left and uses `f` to return - /// a value given the conflicting key and values from left and right - fn next(&mut self) -> Option<(K, V)> { - let (a_next, b_next) = self.inner.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0)); - match (a_next, b_next) { - (Some((a_k, a_v)), Some((_, b_v))) => Some({ - let next_val = (self.f)(&a_k, a_v, b_v); - (a_k, next_val) - }), - (Some(a), None) => Some(a), - (None, Some(b)) => Some(b), - (None, None) => None, - } - } -} diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index b33fd21a4a06f..c3f982fcb8bd9 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1287,7 +1287,7 @@ impl BTreeMap { /// assert_eq!(a[&5], "f"); /// ``` #[unstable(feature = "btree_merge", issue = "152152")] - pub fn merge(&mut self, mut other: Self, conflict: impl FnMut(&K, V, V) -> V) + pub fn merge(&mut self, mut other: Self, mut conflict: impl FnMut(&K, V, V) -> V) where K: Ord, A: Clone, @@ -1303,16 +1303,75 @@ impl BTreeMap { return; } - let self_iter = mem::replace(self, Self::new_in((*self.alloc).clone())).into_iter(); - let other_iter = mem::replace(&mut other, Self::new_in((*self.alloc).clone())).into_iter(); - let root = self.root.get_or_insert_with(|| Root::new((*self.alloc).clone())); - root.merge_from_sorted_iters_with( - self_iter, - other_iter, - &mut self.length, - (*self.alloc).clone(), - conflict, - ) + let mut other_iter = other.into_iter(); + let (first_other_key, first_other_val) = other_iter.next().unwrap(); + + // find the first gap that has the smallest key greater than or equal to + // the first key from other + let mut self_cursor = self.lower_bound_mut(Bound::Included(&first_other_key)); + + if let Some((self_key, _)) = self_cursor.peek_next() { + match K::cmp(&first_other_key, self_key) { + Ordering::Equal => { + self_cursor.with_next(|self_key, self_val| { + conflict(self_key, self_val, first_other_val) + }); + } + Ordering::Less => + // SAFETY: we know our other_key's ordering is less than self_key, + // so inserting before will guarantee sorted order + unsafe { + self_cursor.insert_before_unchecked(first_other_key, first_other_val); + }, + Ordering::Greater => { + unreachable!("Cursor's peek_next should return None."); + } + } + } else { + // SAFETY: reaching here means our cursor is at the end + // self BTreeMap so we just insert other_key here + unsafe { + self_cursor.insert_before_unchecked(first_other_key, first_other_val); + } + } + + for (other_key, other_val) in other_iter { + loop { + if let Some((self_key, _)) = self_cursor.peek_next() { + match K::cmp(&other_key, self_key) { + Ordering::Equal => { + self_cursor.with_next(|self_key, self_val| { + conflict(self_key, self_val, other_val) + }); + break; + } + Ordering::Less => { + // SAFETY: we know our other_key's ordering is less than self_key, + // so inserting before will guarantee sorted order + unsafe { + self_cursor.insert_before_unchecked(other_key, other_val); + } + break; + } + Ordering::Greater => { + // FIXME: instead of doing a linear search here, + // this can be optimized to search the tree by starting + // from self_cursor and going towards the root and then + // back down to the proper node -- that should probably + // be a new method on Cursor*. + self_cursor.next(); + } + } + } else { + // SAFETY: reaching here means our cursor is at the end + // self BTreeMap so we just insert other_key here + unsafe { + self_cursor.insert_before_unchecked(other_key, other_val); + } + break; + } + } + } } /// Constructs a double-ended iterator over a sub-range of elements in the map. @@ -3337,6 +3396,37 @@ impl<'a, K, V, A> CursorMutKey<'a, K, V, A> { // Now the tree editing operations impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { + /// Calls a function with ownership of the next element's key and + /// and value and expects it to return a value to write + /// back to the next element's key and value. The cursor is not + /// advanced forward. + /// + /// If the cursor is at the end of the map then the function is not called + /// and this essentially does not do anything. + /// + /// # Safety + /// + /// You must ensure that the `BTreeMap` invariants are maintained. + /// Specifically: + /// + /// * The next element's key must be unique in the tree. + /// * All keys in the tree must remain in sorted order. + #[allow(dead_code)] /* This function exists for consistency with CursorMut */ + pub(super) fn with_next(&mut self, f: impl FnOnce(K, V) -> (K, V)) { + // if `f` unwinds, the next entry is already removed leaving + // the tree in valid state. + // FIXME: Once `MaybeDangling` is implemented, we can optimize + // this through using a drop handler and transmutating CursorMutKey + // to CursorMutKey, ManuallyDrop> (see PR #152418) + if let Some((k, v)) = self.remove_next() { + // SAFETY: we remove the K, V out of the next entry, + // apply 'f' to get a new (K, V), and insert it back + // into the next entry that the cursor is pointing at + let (k, v) = f(k, v); + unsafe { self.insert_after_unchecked(k, v) }; + } + } + /// Inserts a new key-value pair into the map in the gap that the /// cursor is currently pointing to. /// @@ -3542,6 +3632,29 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { } impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { + /// Calls a function with a reference to the next element's key and + /// ownership of its value. The function is expected to return a value + /// to write back to the next element's value. The cursor is not + /// advanced forward. + /// + /// If the cursor is at the end of the map then the function is not called + /// and this essentially does not do anything. + pub(super) fn with_next(&mut self, f: impl FnOnce(&K, V) -> V) { + // FIXME: This can be optimized to not do all the removing/reinserting + // logic by using ptr::read, calling `f`, and then using ptr::write. + // if `f` unwinds, then we need to remove the entry while being careful to + // not cause UB by moving or dropping the already-dropped `V` + // for the entry. Some implementation ideas: + // https://github.com/rust-lang/rust/pull/152418#discussion_r2800232576 + if let Some((k, v)) = self.remove_next() { + // SAFETY: we remove the K, V out of the next entry, + // apply 'f' to get a new V, and insert (K, V) back + // into the next entry that the cursor is pointing at + let v = f(&k, v); + unsafe { self.insert_after_unchecked(k, v) }; + } + } + /// Inserts a new key-value pair into the map in the gap that the /// cursor is currently pointing to. /// diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 1b07076142019..73546caa05eac 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -2128,6 +2128,16 @@ create_append_test!(test_append_239, 239); #[cfg(not(miri))] // Miri is too slow create_append_test!(test_append_1700, 1700); +// a inserts (0, 0)..(8, 8) to its own tree +// b inserts (5, 5 * 2)..($len, 2 * $len) to its own tree +// note that between a and b, there are duplicate keys +// between 5..min($len, 8), so on merge we add the values +// of these keys together +// we check that: +// - the merged tree 'a' has a length of max(8, $len) +// - all keys in 'a' have the correct value associated +// - removing and inserting an element into the merged +// tree 'a' still keeps it in valid tree form macro_rules! create_merge_test { ($name:ident, $len:expr) => { #[test] @@ -2239,6 +2249,84 @@ fn test_append_ord_chaos() { map2.check(); } +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_merge_drop_leak() { + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + let mut left = BTreeMap::new(); + let mut right = BTreeMap::new(); + left.insert(a.spawn(Panic::Never), ()); + left.insert(b.spawn(Panic::Never), ()); + left.insert(c.spawn(Panic::Never), ()); + right.insert(b.spawn(Panic::InDrop), ()); // first duplicate key, dropped during merge + right.insert(c.spawn(Panic::Never), ()); + + catch_unwind(move || left.merge(right, |_, _, _| ())).unwrap_err(); + assert_eq!(a.dropped(), 1); // this should not be dropped + assert_eq!(b.dropped(), 2); // key is dropped on panic + assert_eq!(c.dropped(), 2); // key is dropped on panic +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_merge_conflict_drop_leak() { + let a = CrashTestDummy::new(0); + let a_val_left = CrashTestDummy::new(0); + + let b = CrashTestDummy::new(1); + let b_val_left = CrashTestDummy::new(1); + let b_val_right = CrashTestDummy::new(1); + + let c = CrashTestDummy::new(2); + let c_val_left = CrashTestDummy::new(2); + let c_val_right = CrashTestDummy::new(2); + + let mut left = BTreeMap::new(); + let mut right = BTreeMap::new(); + + left.insert(a.spawn(Panic::Never), a_val_left.spawn(Panic::Never)); + left.insert(b.spawn(Panic::Never), b_val_left.spawn(Panic::Never)); + left.insert(c.spawn(Panic::Never), c_val_left.spawn(Panic::Never)); + right.insert(b.spawn(Panic::Never), b_val_right.spawn(Panic::Never)); + right.insert(c.spawn(Panic::Never), c_val_right.spawn(Panic::Never)); + + // First key that conflicts should + catch_unwind(move || { + left.merge(right, |_, _, _| panic!("Panic in conflict function")); + assert_eq!(left.len(), 1); // only 1 entry should be left + }) + .unwrap_err(); + assert_eq!(a.dropped(), 1); // should not panic + assert_eq!(a_val_left.dropped(), 1); // should not panic + assert_eq!(b.dropped(), 2); // should drop from panic (conflict) + assert_eq!(b_val_left.dropped(), 1); // should be 2 were it not for Rust issue #47949 + assert_eq!(b_val_right.dropped(), 1); // should be 2 were it not for Rust issue #47949 + assert_eq!(c.dropped(), 2); // should drop from panic (conflict) + assert_eq!(c_val_left.dropped(), 1); // should be 2 were it not for Rust issue #47949 + assert_eq!(c_val_right.dropped(), 1); // should be 2 were it not for Rust issue #47949 +} + +#[test] +fn test_merge_ord_chaos() { + let mut map1 = BTreeMap::new(); + map1.insert(Cyclic3::A, ()); + map1.insert(Cyclic3::B, ()); + let mut map2 = BTreeMap::new(); + map2.insert(Cyclic3::A, ()); + map2.insert(Cyclic3::B, ()); + map2.insert(Cyclic3::C, ()); // lands first, before A + map2.insert(Cyclic3::B, ()); // lands first, before C + map1.check(); + map2.check(); // keys are not unique but still strictly ascending + assert_eq!(map1.len(), 2); + assert_eq!(map2.len(), 4); + map1.merge(map2, |_, _, _| ()); + assert_eq!(map1.len(), 5); + map1.check(); +} + fn rand_data(len: usize) -> Vec<(u32, u32)> { let mut rng = DeterministicRng::new(); Vec::from_iter((0..len).map(|_| (rng.next(), rng.next()))) @@ -2695,9 +2783,15 @@ fn test_id_based_merge() { rhs.insert(IdBased { id: 0, name: "rhs_k".to_string() }, "2".to_string()); lhs.merge(rhs, |_, mut lhs_val, rhs_val| { + // confirming that lhs_val comes from lhs tree, + // rhs_val comes from rhs tree + assert_eq!(lhs_val, String::from("1")); + assert_eq!(rhs_val, String::from("2")); lhs_val.push_str(&rhs_val); lhs_val }); - assert_eq!(lhs.pop_first().unwrap().0.name, "lhs_k".to_string()); + let merged_kv_pair = lhs.pop_first().unwrap(); + assert_eq!(merged_kv_pair.0.id, 0); + assert_eq!(merged_kv_pair.0.name, "lhs_k".to_string()); } From cbdcfca40324738bf39e160538cdaf853bcc0f76 Mon Sep 17 00:00:00 2001 From: Mahdi Ali-Raihan Date: Mon, 23 Feb 2026 00:38:50 -0500 Subject: [PATCH 12/25] Swapped key comparisons to match lower_bound_mut, added FIXME comments on bulk inserting other_keys into self map, and inlined with_next() insertion on conflicts from Cursor* --- library/alloc/src/collections/btree/map.rs | 104 +++++++-------------- 1 file changed, 36 insertions(+), 68 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index c3f982fcb8bd9..d69dad70a44e9 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1253,7 +1253,6 @@ impl BTreeMap { /// Similar to [`insert`], though, the key is not overwritten, /// which matters for types that can be `==` without being identical. /// - /// /// [`insert`]: BTreeMap::insert /// [`append`]: BTreeMap::append /// @@ -1311,19 +1310,28 @@ impl BTreeMap { let mut self_cursor = self.lower_bound_mut(Bound::Included(&first_other_key)); if let Some((self_key, _)) = self_cursor.peek_next() { - match K::cmp(&first_other_key, self_key) { + match K::cmp(self_key, &first_other_key) { Ordering::Equal => { - self_cursor.with_next(|self_key, self_val| { - conflict(self_key, self_val, first_other_val) - }); + // if `f` unwinds, the next entry is already removed leaving + // the tree in valid state. + // FIXME: Once `MaybeDangling` is implemented, we can optimize + // this through using a drop handler and transmutating CursorMutKey + // to CursorMutKey, ManuallyDrop> (see PR #152418) + if let Some((k, v)) = self_cursor.remove_next() { + // SAFETY: we remove the K, V out of the next entry, + // apply 'f' to get a new (K, V), and insert it back + // into the next entry that the cursor is pointing at + let v = conflict(&k, v, first_other_val); + unsafe { self_cursor.insert_after_unchecked(k, v) }; + } } - Ordering::Less => + Ordering::Greater => // SAFETY: we know our other_key's ordering is less than self_key, // so inserting before will guarantee sorted order unsafe { self_cursor.insert_before_unchecked(first_other_key, first_other_val); }, - Ordering::Greater => { + Ordering::Less => { unreachable!("Cursor's peek_next should return None."); } } @@ -1338,22 +1346,31 @@ impl BTreeMap { for (other_key, other_val) in other_iter { loop { if let Some((self_key, _)) = self_cursor.peek_next() { - match K::cmp(&other_key, self_key) { + match K::cmp(self_key, &other_key) { Ordering::Equal => { - self_cursor.with_next(|self_key, self_val| { - conflict(self_key, self_val, other_val) - }); + // if `f` unwinds, the next entry is already removed leaving + // the tree in valid state. + // FIXME: Once `MaybeDangling` is implemented, we can optimize + // this through using a drop handler and transmutating CursorMutKey + // to CursorMutKey, ManuallyDrop> (see PR #152418) + if let Some((k, v)) = self_cursor.remove_next() { + // SAFETY: we remove the K, V out of the next entry, + // apply 'f' to get a new (K, V), and insert it back + // into the next entry that the cursor is pointing at + let v = conflict(&k, v, other_val); + unsafe { self_cursor.insert_after_unchecked(k, v) }; + } break; } - Ordering::Less => { - // SAFETY: we know our other_key's ordering is less than self_key, + Ordering::Greater => { + // SAFETY: we know our self_key's ordering is greater than other_key, // so inserting before will guarantee sorted order unsafe { self_cursor.insert_before_unchecked(other_key, other_val); } break; } - Ordering::Greater => { + Ordering::Less => { // FIXME: instead of doing a linear search here, // this can be optimized to search the tree by starting // from self_cursor and going towards the root and then @@ -1363,6 +1380,11 @@ impl BTreeMap { } } } else { + // FIXME: If we get here, that means all of other's keys are greater than + // self's keys. For performance, this should really do a bulk insertion of items + // from other_iter into the end of self `BTreeMap`. Maybe this should be + // a method for Cursor*? + // SAFETY: reaching here means our cursor is at the end // self BTreeMap so we just insert other_key here unsafe { @@ -3396,37 +3418,6 @@ impl<'a, K, V, A> CursorMutKey<'a, K, V, A> { // Now the tree editing operations impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { - /// Calls a function with ownership of the next element's key and - /// and value and expects it to return a value to write - /// back to the next element's key and value. The cursor is not - /// advanced forward. - /// - /// If the cursor is at the end of the map then the function is not called - /// and this essentially does not do anything. - /// - /// # Safety - /// - /// You must ensure that the `BTreeMap` invariants are maintained. - /// Specifically: - /// - /// * The next element's key must be unique in the tree. - /// * All keys in the tree must remain in sorted order. - #[allow(dead_code)] /* This function exists for consistency with CursorMut */ - pub(super) fn with_next(&mut self, f: impl FnOnce(K, V) -> (K, V)) { - // if `f` unwinds, the next entry is already removed leaving - // the tree in valid state. - // FIXME: Once `MaybeDangling` is implemented, we can optimize - // this through using a drop handler and transmutating CursorMutKey - // to CursorMutKey, ManuallyDrop> (see PR #152418) - if let Some((k, v)) = self.remove_next() { - // SAFETY: we remove the K, V out of the next entry, - // apply 'f' to get a new (K, V), and insert it back - // into the next entry that the cursor is pointing at - let (k, v) = f(k, v); - unsafe { self.insert_after_unchecked(k, v) }; - } - } - /// Inserts a new key-value pair into the map in the gap that the /// cursor is currently pointing to. /// @@ -3632,29 +3623,6 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { } impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { - /// Calls a function with a reference to the next element's key and - /// ownership of its value. The function is expected to return a value - /// to write back to the next element's value. The cursor is not - /// advanced forward. - /// - /// If the cursor is at the end of the map then the function is not called - /// and this essentially does not do anything. - pub(super) fn with_next(&mut self, f: impl FnOnce(&K, V) -> V) { - // FIXME: This can be optimized to not do all the removing/reinserting - // logic by using ptr::read, calling `f`, and then using ptr::write. - // if `f` unwinds, then we need to remove the entry while being careful to - // not cause UB by moving or dropping the already-dropped `V` - // for the entry. Some implementation ideas: - // https://github.com/rust-lang/rust/pull/152418#discussion_r2800232576 - if let Some((k, v)) = self.remove_next() { - // SAFETY: we remove the K, V out of the next entry, - // apply 'f' to get a new V, and insert (K, V) back - // into the next entry that the cursor is pointing at - let v = f(&k, v); - unsafe { self.insert_after_unchecked(k, v) }; - } - } - /// Inserts a new key-value pair into the map in the gap that the /// cursor is currently pointing to. /// From b3a41f2385b46a6a29fe302ca6d1fe4190b18523 Mon Sep 17 00:00:00 2001 From: arferreira Date: Tue, 24 Feb 2026 11:41:26 -0500 Subject: [PATCH 13/25] Add test cases for intra-doc links --- src/librustdoc/html/format.rs | 1 + .../extern/extern-html-root-url-relative.rs | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3fd04449d4ccd..30dacde94cf03 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -532,6 +532,7 @@ fn make_href( fqp: &[Symbol], is_absolute: bool, ) -> String { + // FIXME: relative extern URLs may break when prefixed with root_path if !is_absolute && let Some(root_path) = root_path { let root = root_path.trim_end_matches('/'); url_parts.push_front(root); diff --git a/tests/rustdoc-html/extern/extern-html-root-url-relative.rs b/tests/rustdoc-html/extern/extern-html-root-url-relative.rs index df6ebf1aedd5a..ba2b50c6bf222 100644 --- a/tests/rustdoc-html/extern/extern-html-root-url-relative.rs +++ b/tests/rustdoc-html/extern/extern-html-root-url-relative.rs @@ -1,4 +1,4 @@ -//@ compile-flags:-Z unstable-options --extern-html-root-url core=../ --extern-html-root-takes-precedence +//@ compile-flags:-Z unstable-options --extern-html-root-url core=../ --extern-html-root-takes-precedence --generate-link-to-definition // At depth 1 (top-level), the href should be ../core/... //@ has extern_html_root_url_relative/index.html @@ -9,7 +9,19 @@ pub use std::iter; // At depth 2 (inside a module), the href should be ../../core/... pub mod nested { //@ has extern_html_root_url_relative/nested/index.html - //@ has - '//a/@href' '../../core/iter/index.html' + //@ has - '//a/@href' '../../core/future/index.html' #[doc(no_inline)] - pub use std::iter; + pub use std::future; } + +// Also depth 2, but for an intra-doc link. +//@ has extern_html_root_url_relative/intra_doc_link/index.html +//@ has - '//a/@href' '../../core/ptr/fn.write.html' +/// [write]() +pub mod intra_doc_link { +} + +// link-to-definition +//@ has src/extern_html_root_url_relative/extern-html-root-url-relative.rs.html +//@ has - '//a/@href' '../../core/iter/index.html' +//@ has - '//a/@href' '../../core/future/index.html' From 327f778130aad23bbc5c668b53d8e5290dbf728c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 11:24:13 +0100 Subject: [PATCH 14/25] Migrate `rustc_privacy` to use `TyCtxt::emit_diag_node_span_lint` --- compiler/rustc_privacy/src/errors.rs | 8 ++++---- compiler/rustc_privacy/src/lib.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs index af4f0d61aa11e..afa91ddb3b012 100644 --- a/compiler/rustc_privacy/src/errors.rs +++ b/compiler/rustc_privacy/src/errors.rs @@ -1,6 +1,6 @@ use rustc_errors::codes::*; use rustc_errors::{DiagArgFromDisplay, MultiSpan}; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] @@ -87,7 +87,7 @@ pub(crate) struct ReportEffectiveVisibility { pub descr: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("{$kind} `{$descr}` from private dependency '{$krate}' in public interface")] pub(crate) struct FromPrivateDependencyInPublicInterface<'a> { pub kind: &'a str, @@ -95,7 +95,7 @@ pub(crate) struct FromPrivateDependencyInPublicInterface<'a> { pub krate: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("{$kind} `{$descr}` is reachable but cannot be named")] pub(crate) struct UnnameableTypesLint<'a> { #[label( @@ -111,7 +111,7 @@ pub(crate) struct UnnameableTypesLint<'a> { // Used for `private_interfaces` and `private_bounds` lints. // They will replace private-in-public errors and compatibility lints in future. // See https://rust-lang.github.io/rfcs/2145-type-privacy.html for more details. -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("{$ty_kind} `{$ty_descr}` is more private than the item `{$item_descr}`")] pub(crate) struct PrivateInterfacesOrBoundsLint<'a> { #[label("{$item_kind} `{$item_descr}` is reachable at visibility `{$item_vis_descr}`")] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 59fd908756b02..87b128779737b 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1416,7 +1416,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn check_def_id(&self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { if self.leaks_private_dep(def_id) { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES, self.tcx.local_def_id_to_hir_id(self.item_def_id), self.tcx.def_span(self.item_def_id.to_def_id()), @@ -1475,7 +1475,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; let span = self.tcx.def_span(self.item_def_id.to_def_id()); let vis_span = self.tcx.def_span(def_id); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint, self.tcx.local_def_id_to_hir_id(self.item_def_id), span, @@ -1565,7 +1565,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis { let hir_id = self.tcx.local_def_id_to_hir_id(def_id); let span = self.tcx.def_span(def_id.to_def_id()); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::UNNAMEABLE_TYPES, hir_id, span, From c53fbcd726fefeb0fa04365f4326c8a9f5d48b48 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 11:30:46 +0100 Subject: [PATCH 15/25] Migrate `rustc_pattern_analysis` to use `TyCtxt::emit_diag_node_span_lint` --- compiler/rustc_pattern_analysis/src/errors.rs | 8 ++++---- compiler/rustc_pattern_analysis/src/lints.rs | 2 +- compiler/rustc_pattern_analysis/src/rustc.rs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index e7448613cc14e..b27e52f32bf27 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -46,7 +46,7 @@ impl Uncovered { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("multiple patterns overlap on their endpoints")] #[note("you likely meant to write mutually exclusive ranges")] pub struct OverlappingRangeEndpoints { @@ -64,7 +64,7 @@ pub struct Overlap { pub range: String, // a printed pattern } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("exclusive range missing `{$max}`")] pub struct ExclusiveRangeMissingMax { #[label("this range doesn't match `{$max}` because `..` is an exclusive range")] @@ -80,7 +80,7 @@ pub struct ExclusiveRangeMissingMax { pub max: String, // a printed pattern } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("multiple ranges are one apart")] pub struct ExclusiveRangeMissingGap { #[label("this range doesn't match `{$gap}` because `..` is an exclusive range")] @@ -119,7 +119,7 @@ impl Subdiagnostic for GappedRange { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("some variants are not matched explicitly")] #[help("ensure that all variants are matched explicitly by adding the suggested match arms")] #[note( diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index 3da744dc8c029..314d3e60f2a41 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -74,7 +74,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>( // is not exhaustive enough. // // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. - rcx.tcx.emit_node_span_lint( + rcx.tcx.emit_diag_node_span_lint( NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level, rcx.scrut_span, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index dc38f2d8bc70f..2804a807b9939 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -948,7 +948,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { .map(|span| errors::Overlap { range: overlap_as_pat.to_string(), span }) .collect(); let pat_span = pat.data().span; - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, self.match_lint_level, pat_span, @@ -984,7 +984,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { let gap_as_pat = self.print_pat_range(&gap, *pat.ty()); if gapped_with.is_empty() { // If `gapped_with` is empty, `gap == T::MAX`. - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS, self.match_lint_level, thir_pat.span, @@ -998,7 +998,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { }, ); } else { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS, self.match_lint_level, thir_pat.span, From b55f6e3e67afaf10bc25d26fc45ab4783410212d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 11:48:50 +0100 Subject: [PATCH 16/25] Migrate `rustc_lint` to use `TyCtxt::emit_diag_node_span_lint` --- compiler/rustc_lint/src/async_closures.rs | 6 +-- compiler/rustc_lint/src/async_fn_in_trait.rs | 2 +- compiler/rustc_lint/src/dangling.rs | 4 +- compiler/rustc_lint/src/expect.rs | 2 +- compiler/rustc_lint/src/foreign_modules.rs | 2 +- .../src/function_cast_as_integer.rs | 2 +- compiler/rustc_lint/src/gpukernel_abi.rs | 2 +- compiler/rustc_lint/src/if_let_rescope.rs | 6 +-- .../rustc_lint/src/impl_trait_overcaptures.rs | 29 +++++++++----- compiler/rustc_lint/src/lints.rs | 36 ++++++++++------- compiler/rustc_lint/src/transmute.rs | 8 ++-- .../drop/drop-order-comparisons.e2021.stderr | 40 +++++++++---------- ...nt-if-let-rescope-gated.edition2021.stderr | 4 +- .../lint-if-let-rescope-with-macro.stderr | 4 +- tests/ui/drop/lint-if-let-rescope.stderr | 32 +++++++-------- ...vercaptures-2024-machine-applicable.stderr | 4 +- .../overcaptures-2024.stderr | 32 +++++++-------- 17 files changed, 114 insertions(+), 101 deletions(-) diff --git a/compiler/rustc_lint/src/async_closures.rs b/compiler/rustc_lint/src/async_closures.rs index 0d3a954667f7b..ebcafa2ad5cdb 100644 --- a/compiler/rustc_lint/src/async_closures.rs +++ b/compiler/rustc_lint/src/async_closures.rs @@ -1,5 +1,5 @@ use rustc_hir as hir; -use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::Span; @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncClosureUsage { let deletion_span = cx.tcx.sess.source_map().span_extend_while_whitespace(async_decl_span); - cx.tcx.emit_node_span_lint( + cx.tcx.emit_diag_node_span_lint( CLOSURE_RETURNING_ASYNC_BLOCK, expr.hir_id, fn_decl_span, @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncClosureUsage { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("closure returning async block can be made into an async closure")] struct ClosureReturningAsyncBlock { #[label( diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs index 9923f05df3c73..19d0a13690dbd 100644 --- a/compiler/rustc_lint/src/async_fn_in_trait.rs +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { opaq_def.def_id, " + Send", ); - cx.tcx.emit_node_span_lint( + cx.tcx.emit_diag_node_span_lint( ASYNC_FN_IN_TRAIT, item.hir_id(), async_span, diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 448c0ded637c6..668f2741bb0ab 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -186,7 +186,7 @@ fn lint_addr_of_local<'a>( && let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id) && cx.tcx.hir_enclosing_body_owner(from) == dcx.body { - cx.tcx.emit_node_span_lint( + cx.tcx.emit_diag_node_span_lint( DANGLING_POINTERS_FROM_LOCALS, expr.hir_id, expr.span, @@ -270,7 +270,7 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { && find_attr!(cx.tcx, fn_id, RustcAsPtr(_)) { // FIXME: use `emit_node_lint` when `#[primary_span]` is added. - cx.tcx.emit_node_span_lint( + cx.tcx.emit_diag_node_span_lint( DANGLING_POINTERS_FROM_TEMPORARIES, expr.hir_id, method.ident.span, diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 481e116d06e01..b7c8ff6408711 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -61,7 +61,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { { let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale }); let note = expectation.is_unfulfilled_lint_expectations; - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( UNFULFILLED_LINT_EXPECTATIONS, *hir_id, expectation.emission_span, diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index d234c68631030..b9ae354c7e18f 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -162,7 +162,7 @@ impl ClashingExternDeclarations { sub, } }; - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( CLASHING_EXTERN_DECLARATIONS, this_fi.hir_id(), mismatch_label, diff --git a/compiler/rustc_lint/src/function_cast_as_integer.rs b/compiler/rustc_lint/src/function_cast_as_integer.rs index 2a4ff1f63db52..9b530ec5568c1 100644 --- a/compiler/rustc_lint/src/function_cast_as_integer.rs +++ b/compiler/rustc_lint/src/function_cast_as_integer.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for FunctionCastsAsInteger { } let cast_from_ty = cx.typeck_results().expr_ty(cast_from_expr); if matches!(cast_from_ty.kind(), ty::FnDef(..)) { - cx.tcx.emit_node_span_lint( + cx.tcx.emit_diag_node_span_lint( FUNCTION_CASTS_AS_INTEGER, expr.hir_id, cast_to_expr.span.with_lo(cast_from_expr.span.hi() + BytePos(1)), diff --git a/compiler/rustc_lint/src/gpukernel_abi.rs b/compiler/rustc_lint/src/gpukernel_abi.rs index 4fb26739cd28a..d8c8feda94aee 100644 --- a/compiler/rustc_lint/src/gpukernel_abi.rs +++ b/compiler/rustc_lint/src/gpukernel_abi.rs @@ -173,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperGpuKernelLint { let mut checker = CheckGpuKernelTypes { tcx: cx.tcx, has_invalid: false }; input_ty.fold_with(&mut checker); if checker.has_invalid { - cx.tcx.emit_node_span_lint( + cx.tcx.emit_diag_node_span_lint( IMPROPER_GPU_KERNEL_ARG, input_hir.hir_id, input_hir.span, diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 7899d4690ea51..43c51240aa332 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -5,7 +5,7 @@ use hir::intravisit::{self, Visitor}; use rustc_ast::Recovered; use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle, msg}; use rustc_hir::{self as hir, HirIdSet}; -use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::significant_drop_order::{ extract_component_with_significant_dtor, ty_dtor_span, @@ -238,7 +238,7 @@ impl IfLetRescope { } } if let Some((span, hir_id)) = first_if_to_lint { - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( IF_LET_RESCOPE, hir_id, span, @@ -302,7 +302,7 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`if let` assigns a shorter lifetime since Edition 2024")] struct IfLetRescopeLint { #[subdiagnostic] diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index c7fa779447a49..eb904e1bc819d 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -3,13 +3,13 @@ use std::cell::LazyCell; use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{LintDiagnostic, Subdiagnostic, msg}; +use rustc_errors::{Diagnostic, Subdiagnostic, msg}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_macros::LintDiagnostic; +use rustc_macros::Diagnostic; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, relate_args_with_variances, structurally_relate_consts, @@ -345,7 +345,7 @@ where .map(|(&def_id, _)| self.tcx.def_span(def_id)) .collect(); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( IMPL_TRAIT_OVERCAPTURES, self.tcx.local_def_id_to_hir_id(opaque_def_id), opaque_span, @@ -402,7 +402,7 @@ where .iter() .all(|(def_id, _)| explicitly_captured.contains(def_id)) { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( IMPL_TRAIT_REDUNDANT_CAPTURES, self.tcx.local_def_id_to_hir_id(opaque_def_id), opaque_span, @@ -433,11 +433,17 @@ struct ImplTraitOvercapturesLint<'tcx> { suggestion: Option, } -impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) { - diag.primary_message(msg!( - "`{$self_ty}` will capture more lifetimes than possibly intended in edition 2024" - )); +impl<'a> Diagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> { + fn into_diag( + self, + dcx: rustc_errors::DiagCtxtHandle<'a>, + level: rustc_errors::Level, + ) -> rustc_errors::Diag<'a, ()> { + let mut diag = rustc_errors::Diag::new( + dcx, + level, + msg!("`{$self_ty}` will capture more lifetimes than possibly intended in edition 2024"), + ); diag.arg("self_ty", self.self_ty.to_string()) .arg("num_captured", self.num_captured) .span_note( @@ -451,12 +457,13 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> { ) .note(msg!("all lifetimes in scope will be captured by `impl Trait`s in edition 2024")); if let Some(suggestion) = self.suggestion { - suggestion.add_to_diag(diag); + suggestion.add_to_diag(&mut diag); } + diag } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("all possible in-scope parameters are already captured, so `use<...>` syntax is redundant")] struct ImplTraitRedundantCapturesLint { #[suggestion("remove the `use<...>` syntax", code = "", applicability = "machine-applicable")] diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 285a7b7f52935..4b7e102e239ec 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -4,13 +4,14 @@ use std::num::NonZero; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, - EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle, msg, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, + ElidedLifetimeInPathSubdiag, EmissionGuarantee, Level, LintDiagnostic, MultiSpan, + Subdiagnostic, SuggestionStyle, msg, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::VisitorExt; -use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::inhabitedness::InhabitedPredicate; use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; @@ -580,7 +581,7 @@ impl Subdiagnostic for BuiltinUnpermittedTypeInitSub { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] pub(crate) enum BuiltinClashingExtern<'a> { #[diag("`{$this}` redeclared with a different signature")] SameName { @@ -686,7 +687,7 @@ pub(crate) struct EnumIntrinsicsMemVariant<'a> { } // expect.rs -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("this lint expectation is unfulfilled")] pub(crate) struct Expectation { #[subdiagnostic] @@ -1341,7 +1342,7 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> { } // dangling.rs -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("this creates a dangling pointer because temporary `{$ty}` is dropped at end of statement")] #[help("bind the `{$ty}` to a variable such that it outlives the pointer returned by `{$callee}`")] #[note("a dangling pointer is safe, but dereferencing one is undefined behavior")] @@ -1357,7 +1358,7 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub temporary_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("{$fn_kind} returns a dangling pointer to dropped local variable `{$local_var_name}`")] #[note("a dangling pointer is safe, but dereferencing one is undefined behavior")] #[note("for more information, see ")] @@ -1874,7 +1875,7 @@ impl<'a> LintDiagnostic<'a, ()> for DropGlue<'_> { } // transmute.rs -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("transmuting an integer to a pointer creates a pointer without provenance")] #[note("this is dangerous because dereferencing the resulting pointer is undefined behavior")] #[note( @@ -2324,7 +2325,7 @@ impl<'a> LintDiagnostic<'a, ()> for ImproperCTypes<'_> { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("passing type `{$ty}` to a function with \"gpu-kernel\" ABI may have unexpected behavior")] #[help("use primitive types and raw pointers to get reliable behavior")] pub(crate) struct ImproperGpuKernelArg<'a> { @@ -2564,13 +2565,18 @@ pub(crate) struct AsyncFnInTraitDiag { pub sugg: Option>, } -impl<'a> LintDiagnostic<'a, ()> for AsyncFnInTraitDiag { - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { - diag.primary_message(msg!("use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified")); - diag.note(msg!("you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`")); +impl<'a> Diagnostic<'a, ()> for AsyncFnInTraitDiag { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let mut diag = Diag::new( + dcx, + level, + "use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified", + ); + diag.note("you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`"); if let Some(sugg) = self.sugg { - diag.multipart_suggestion(msg!("you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change"), sugg, Applicability::MaybeIncorrect); + diag.multipart_suggestion("you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change", sugg, Applicability::MaybeIncorrect); } + diag } } @@ -3404,7 +3410,7 @@ pub(crate) struct ReservedMultihash { pub suggestion: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("direct cast of function item into an integer")] pub(crate) struct FunctionCastsAsIntegerDiag<'tcx> { #[subdiagnostic] diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index e4716c869c5f1..7a8df8195a0e3 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -3,7 +3,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir}; -use rustc_macros::LintDiagnostic; +use rustc_macros::Diagnostic; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::sym; @@ -166,7 +166,7 @@ fn check_int_to_ptr_transmute<'tcx>( } let suffix = if mutbl.is_mut() { "_mut" } else { "" }; - cx.tcx.emit_node_span_lint( + cx.tcx.emit_diag_node_span_lint( INTEGER_TO_PTR_TRANSMUTES, expr.hir_id, expr.span, @@ -219,7 +219,7 @@ fn check_ptr_transmute_in_const<'tcx>( || matches!(cx.tcx.def_kind(body_owner_def_id), DefKind::AssocConst) { if src.is_raw_ptr() && dst.is_integral() { - cx.tcx.emit_node_span_lint( + cx.tcx.emit_diag_node_span_lint( PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, expr.hir_id, expr.span, @@ -368,7 +368,7 @@ fn check_unnecessary_transmute<'tcx>( }); } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("pointers cannot be transmuted to integers during const eval")] #[note("at compile-time, pointers do not have an integer value")] #[note( diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr index 40735650d182c..5b4e64c6da756 100644 --- a/tests/ui/drop/drop-order-comparisons.e2021.stderr +++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr @@ -192,8 +192,6 @@ LL | _ = (if let Ok(_) = e.ok(4).as_ref() { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -204,6 +202,8 @@ help: the value is now dropped here in Edition 2024 | LL | }, e.mark(2), e.ok(3)); | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see = note: `#[warn(if_let_rescope)]` implied by `#[warn(rust_2024_compatibility)]` help: a `match` with a single arm can preserve the drop order up to Edition 2021 | @@ -222,8 +222,6 @@ LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -234,6 +232,8 @@ help: the value is now dropped here in Edition 2024 | LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ _ = (match e.err(4).as_ref() { Ok(_) => {} _ => { @@ -251,8 +251,6 @@ LL | if let Ok(_) = e.err(4).as_ref() {} else { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -263,6 +261,8 @@ help: the value is now dropped here in Edition 2024 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ match e.err(4).as_ref() { Ok(_) => {} _ => { @@ -280,8 +280,6 @@ LL | if let true = e.err(9).is_ok() {} else { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -292,6 +290,8 @@ help: the value is now dropped here in Edition 2024 | LL | if let true = e.err(9).is_ok() {} else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ match e.err(9).is_ok() { true => {} _ => { @@ -309,8 +309,6 @@ LL | if let Ok(_v) = e.err(8) {} else { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -321,6 +319,8 @@ help: the value is now dropped here in Edition 2024 | LL | if let Ok(_v) = e.err(8) {} else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ match e.err(8) { Ok(_v) => {} _ => { @@ -338,8 +338,6 @@ LL | if let Ok(_) = e.err(7) {} else { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -350,6 +348,8 @@ help: the value is now dropped here in Edition 2024 | LL | if let Ok(_) = e.err(7) {} else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ match e.err(7) { Ok(_) => {} _ => { @@ -367,8 +367,6 @@ LL | if let Ok(_) = e.err(6).as_ref() {} else { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -379,6 +377,8 @@ help: the value is now dropped here in Edition 2024 | LL | if let Ok(_) = e.err(6).as_ref() {} else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ match e.err(6).as_ref() { Ok(_) => {} _ => { @@ -396,8 +396,6 @@ LL | if let Ok(_v) = e.err(5) {} else { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -408,6 +406,8 @@ help: the value is now dropped here in Edition 2024 | LL | if let Ok(_v) = e.err(5) {} else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ match e.err(5) { Ok(_v) => {} _ => { @@ -425,8 +425,6 @@ LL | if let Ok(_) = e.err(4) {} else { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -437,6 +435,8 @@ help: the value is now dropped here in Edition 2024 | LL | if let Ok(_) = e.err(4) {} else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ match e.err(4) { Ok(_) => {} _ => { @@ -454,8 +454,6 @@ LL | if let Ok(_) = e.err(4).as_ref() {} else { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -466,6 +464,8 @@ help: the value is now dropped here in Edition 2024 | LL | if let Ok(_) = e.err(4).as_ref() {} else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ match e.err(4).as_ref() { Ok(_) => {} _ => { diff --git a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr index 5f04273d336d6..feca46c2bc2dc 100644 --- a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr +++ b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr @@ -6,8 +6,6 @@ LL | if let Some(_value) = Droppy.get() { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/lint-if-let-rescope-gated.rs:14:1 | @@ -18,6 +16,8 @@ help: the value is now dropped here in Edition 2024 | LL | } else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/lint-if-let-rescope-gated.rs:10:9 | diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr index 63e30f1ab92e4..a13c84f0e527d 100644 --- a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr +++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr @@ -13,8 +13,6 @@ LL | | {} LL | | }; | |_____- in this macro invocation | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/lint-if-let-rescope-with-macro.rs:22:1 | @@ -33,6 +31,8 @@ LL | | {} LL | | {} LL | | }; | |_____- in this macro invocation + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/lint-if-let-rescope-with-macro.rs:7:9 | diff --git a/tests/ui/drop/lint-if-let-rescope.stderr b/tests/ui/drop/lint-if-let-rescope.stderr index 7cab7339fe1e5..ee2acb0d67597 100644 --- a/tests/ui/drop/lint-if-let-rescope.stderr +++ b/tests/ui/drop/lint-if-let-rescope.stderr @@ -6,8 +6,6 @@ LL | if let Some(_value) = droppy().get() { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | @@ -18,6 +16,8 @@ help: the value is now dropped here in Edition 2024 | LL | } else { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/lint-if-let-rescope.rs:3:9 | @@ -46,8 +46,6 @@ LL | if let Some(_value) = droppy().get() { LL | } else if let Some(_value) = droppy().get() { | -------- this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | @@ -68,6 +66,8 @@ help: the value is now dropped here in Edition 2024 | LL | } | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ match droppy().get() { Some(_value) => { @@ -88,8 +88,6 @@ LL | } else if let Some(_value) = droppy().get() { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | @@ -100,6 +98,8 @@ help: the value is now dropped here in Edition 2024 | LL | } else if droppy().get().is_none() { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL ~ } else { match droppy().get() { Some(_value) => { @@ -119,8 +119,6 @@ LL | if let Some(1) = { if let Some(_value) = Droppy.get() { Some(1) } else | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | @@ -131,6 +129,8 @@ help: the value is now dropped here in Edition 2024 | LL | if let Some(1) = { if let Some(_value) = Droppy.get() { Some(1) } else { None } } { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL - if let Some(1) = { if let Some(_value) = Droppy.get() { Some(1) } else { None } } { @@ -145,8 +145,6 @@ LL | if (if let Some(_value) = droppy().get() { true } else { false }) { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | @@ -157,6 +155,8 @@ help: the value is now dropped here in Edition 2024 | LL | if (if let Some(_value) = droppy().get() { true } else { false }) { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL - if (if let Some(_value) = droppy().get() { true } else { false }) { @@ -171,8 +171,6 @@ LL | } else if (((if let Some(_value) = droppy().get() { true } else { false | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | @@ -183,6 +181,8 @@ help: the value is now dropped here in Edition 2024 | LL | } else if (((if let Some(_value) = droppy().get() { true } else { false }))) { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL - } else if (((if let Some(_value) = droppy().get() { true } else { false }))) { @@ -197,8 +197,6 @@ LL | while (if let Some(_value) = droppy().get() { false } else { true }) { | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: value invokes this custom destructor --> $DIR/lint-if-let-rescope.rs:11:1 | @@ -209,6 +207,8 @@ help: the value is now dropped here in Edition 2024 | LL | while (if let Some(_value) = droppy().get() { false } else { true }) { | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL - while (if let Some(_value) = droppy().get() { false } else { true }) { @@ -223,13 +223,13 @@ LL | if let Some(_value) = Some((droppy(), ()).1) {} else {} | | | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion | - = warning: this changes meaning in Rust 2024 - = note: for more information, see help: the value is now dropped here in Edition 2024 --> $DIR/lint-if-let-rescope.rs:97:51 | LL | if let Some(_value) = Some((droppy(), ()).1) {} else {} | ^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: a `match` with a single arm can preserve the drop order up to Edition 2021 | LL - if let Some(_value) = Some((droppy(), ()).1) {} else {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr index 980ddedc255bf..ff904de61d2c3 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024-machine-applicable.stderr @@ -4,14 +4,14 @@ error: `impl Sized` will capture more lifetimes than possibly intended in editio LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^^^^^^^^^ | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds --> $DIR/overcaptures-2024-machine-applicable.rs:9:10 | LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/overcaptures-2024-machine-applicable.rs:7:9 | diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr index dc9f1c218d9f3..a3c84a89fb415 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr @@ -4,14 +4,14 @@ error: `impl Sized` will capture more lifetimes than possibly intended in editio LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^^^^^^^^^ | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds --> $DIR/overcaptures-2024.rs:7:10 | LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/overcaptures-2024.rs:5:9 | @@ -28,14 +28,14 @@ error: `impl Sized` will capture more lifetimes than possibly intended in editio LL | fn implicit(x: &i32) -> impl Sized { *x } | ^^^^^^^^^^ | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds --> $DIR/overcaptures-2024.rs:11:16 | LL | fn implicit(x: &i32) -> impl Sized { *x } | ^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn implicit(x: &i32) -> impl Sized + use<> { *x } @@ -47,14 +47,14 @@ error: `impl Sized + '_` will capture more lifetimes than possibly intended in e LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } | ^^^^^^^^^^^^^^^ | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds --> $DIR/overcaptures-2024.rs:17:24 | LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } | ^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self } @@ -66,14 +66,14 @@ error: `impl Sized` will capture more lifetimes than possibly intended in editio LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} | ^^^^^^^^^^ | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds --> $DIR/overcaptures-2024.rs:29:23 | LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} | ^^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized + use<>> {} @@ -85,8 +85,6 @@ error: `impl Sized` will capture more lifetimes than possibly intended in editio LL | fn apit(_: &impl Sized) -> impl Sized {} | ^^^^^^^^^^ | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds --> $DIR/overcaptures-2024.rs:33:12 | @@ -98,6 +96,8 @@ note: you could use a `use<...>` bound to explicitly specify captures, but argum | LL | fn apit(_: &impl Sized) -> impl Sized {} | ^^^^^^^^^^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: use the precise capturing `use<...>` syntax to make the captures explicit | LL - fn apit(_: &impl Sized) -> impl Sized {} @@ -110,8 +110,6 @@ error: `impl Sized` will capture more lifetimes than possibly intended in editio LL | fn apit2(_: &impl Sized, _: U) -> impl Sized {} | ^^^^^^^^^^ | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds --> $DIR/overcaptures-2024.rs:37:16 | @@ -123,6 +121,8 @@ note: you could use a `use<...>` bound to explicitly specify captures, but argum | LL | fn apit2(_: &impl Sized, _: U) -> impl Sized {} | ^^^^^^^^^^ + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: use the precise capturing `use<...>` syntax to make the captures explicit | LL - fn apit2(_: &impl Sized, _: U) -> impl Sized {} @@ -135,14 +135,14 @@ error: `impl Sized` will capture more lifetimes than possibly intended in editio LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized {} | ^^^^^^^^^^ | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds --> $DIR/overcaptures-2024.rs:41:19 | LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized {} | ^^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {} @@ -154,14 +154,14 @@ error: `impl Clone` will capture more lifetimes than possibly intended in editio LL | pub fn parens(x: &i32) -> &impl Clone { x } | ^^^^^^^^^^ | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: specifically, this lifetime is in scope but not mentioned in the type's bounds --> $DIR/overcaptures-2024.rs:45:18 | LL | pub fn parens(x: &i32) -> &impl Clone { x } | ^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: use the precise capturing `use<...>` syntax to make the captures explicit | LL | pub fn parens(x: &i32) -> &(impl Clone + use<>) { x } From d926c1b06e885db77fa96881b7ef53d8aef33ffe Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 11:59:19 +0100 Subject: [PATCH 17/25] Migrate `rustc_mir_build` to use `TyCtxt::emit_diag_node_span_lint` --- compiler/rustc_mir_build/src/builder/mod.rs | 2 +- .../rustc_mir_build/src/check_unsafety.rs | 73 ++++++++++--------- compiler/rustc_mir_build/src/errors.rs | 48 ++++++------ .../src/thir/pattern/check_match.rs | 6 +- .../safe-calls.stderr | 2 +- tests/ui/rust-2024/unsafe-env.e2021.stderr | 2 +- tests/ui/rust-2024/unsafe-env.e2024.stderr | 6 +- ...edition-2024-unsafe_op_in_unsafe_fn.stderr | 2 +- .../edition_2024_default.stderr | 2 +- .../in_2024_compatibility.stderr | 2 +- .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 12 +-- .../wrapping-unsafe-block-sugg.stderr | 16 ++-- 12 files changed, 87 insertions(+), 86 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index c8ca7bfccc07c..3835811571746 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -921,7 +921,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .as_ref() .unwrap_crate_local() .lint_root; - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::UNREACHABLE_CODE, lint_root, target_loc.span, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 24c85b7ec3f5d..e3fa4802518a7 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -108,7 +108,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { }) .unwrap_or_default(); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( DEPRECATED_SAFE_2024, self.hir_context, span, @@ -780,7 +780,7 @@ impl UnsafeOpKind { // FIXME: ideally we would want to trim the def paths, but this is not // feasible with the current lint emission API (see issue #106126). match self { - CallToUnsafeFunction(Some(did)) => tcx.emit_node_span_lint( + CallToUnsafeFunction(Some(did)) => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -790,7 +790,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - CallToUnsafeFunction(None) => tcx.emit_node_span_lint( + CallToUnsafeFunction(None) => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -799,7 +799,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfInlineAssembly => tcx.emit_node_span_lint( + UseOfInlineAssembly => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -808,7 +808,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - InitializingTypeWith => tcx.emit_node_span_lint( + InitializingTypeWith => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -817,7 +817,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - InitializingTypeWithUnsafeField => tcx.emit_node_span_lint( + InitializingTypeWithUnsafeField => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -826,7 +826,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfMutableStatic => tcx.emit_node_span_lint( + UseOfMutableStatic => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -835,7 +835,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfExternStatic => tcx.emit_node_span_lint( + UseOfExternStatic => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -844,7 +844,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfUnsafeField => tcx.emit_node_span_lint( + UseOfUnsafeField => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -853,7 +853,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - DerefOfRawPointer => tcx.emit_node_span_lint( + DerefOfRawPointer => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -862,7 +862,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - AccessToUnionField => tcx.emit_node_span_lint( + AccessToUnionField => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -871,7 +871,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - MutationOfLayoutConstrainedField => tcx.emit_node_span_lint( + MutationOfLayoutConstrainedField => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -880,7 +880,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - BorrowOfLayoutConstrainedField => tcx.emit_node_span_lint( + BorrowOfLayoutConstrainedField => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -889,29 +889,30 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - CallToFunctionWith { function, missing, build_enabled } => tcx.emit_node_span_lint( - UNSAFE_OP_IN_UNSAFE_FN, - hir_id, - span, - UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { + CallToFunctionWith { function, missing, build_enabled } => tcx + .emit_diag_node_span_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, span, - function: with_no_trimmed_paths!(tcx.def_path_str(*function)), - missing_target_features: DiagArgValue::StrListSepByAnd( - missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), - ), - missing_target_features_count: missing.len(), - note: !build_enabled.is_empty(), - build_target_features: DiagArgValue::StrListSepByAnd( - build_enabled - .iter() - .map(|feature| Cow::from(feature.to_string())) - .collect(), - ), - build_target_features_count: build_enabled.len(), - unsafe_not_inherited_note, - }, - ), - UnsafeBinderCast => tcx.emit_node_span_lint( + UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { + span, + function: with_no_trimmed_paths!(tcx.def_path_str(*function)), + missing_target_features: DiagArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), + ), + missing_target_features_count: missing.len(), + note: !build_enabled.is_empty(), + build_target_features: DiagArgValue::StrListSepByAnd( + build_enabled + .iter() + .map(|feature| Cow::from(feature.to_string())) + .collect(), + ), + build_target_features_count: build_enabled.len(), + unsafe_not_inherited_note, + }, + ), + UnsafeBinderCast => tcx.emit_diag_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -1200,7 +1201,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { warnings.sort_by_key(|w| w.block_span); for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings { let block_span = tcx.sess.source_map().guess_head_span(block_span); - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( UNUSED_UNSAFE, hir_id, block_span, diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 5a93c7cbdc7a9..fead221b9a0ca 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -3,13 +3,13 @@ use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, Subdiagnostic, msg, }; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; use rustc_pattern_analysis::errors::Uncovered; use rustc_pattern_analysis::rustc::RustcPatCtxt; use rustc_span::{Ident, Span, Symbol}; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("call to deprecated safe function `{$function}` is unsafe and requires unsafe block")] pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { #[label("call to unsafe function")] @@ -35,7 +35,7 @@ pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafeSub { pub(crate) right: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("call to unsafe function `{$function}` is unsafe and requires unsafe block", code = E0133)] #[note("consult the function's documentation for information on how to avoid undefined behavior")] pub(crate) struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe { @@ -46,7 +46,7 @@ pub(crate) struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("call to unsafe function is unsafe and requires unsafe block", code = E0133)] #[note("consult the function's documentation for information on how to avoid undefined behavior")] pub(crate) struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { @@ -56,7 +56,7 @@ pub(crate) struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("use of inline assembly is unsafe and requires unsafe block", code = E0133)] #[note("inline assembly is entirely unchecked and can cause undefined behavior")] pub(crate) struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { @@ -66,7 +66,7 @@ pub(crate) struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block", code = E0133)] #[note( "initializing a layout restricted type's field with a value outside the valid range is undefined behavior" @@ -78,7 +78,7 @@ pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("initializing type with an unsafe field is unsafe and requires unsafe block", code = E0133)] #[note("unsafe fields may carry library invariants")] pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithUnsafeFieldRequiresUnsafe { @@ -88,7 +88,7 @@ pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithUnsafeFieldRequiresUnsaf pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("use of mutable static is unsafe and requires unsafe block", code = E0133)] #[note( "mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior" @@ -100,7 +100,7 @@ pub(crate) struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("use of extern static is unsafe and requires unsafe block", code = E0133)] #[note( "extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior" @@ -112,7 +112,7 @@ pub(crate) struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("use of unsafe field is unsafe and requires unsafe block", code = E0133)] #[note("unsafe fields may carry library invariants")] pub(crate) struct UnsafeOpInUnsafeFnUseOfUnsafeFieldRequiresUnsafe { @@ -122,7 +122,7 @@ pub(crate) struct UnsafeOpInUnsafeFnUseOfUnsafeFieldRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("dereference of raw pointer is unsafe and requires unsafe block", code = E0133)] #[note( "raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior" @@ -134,7 +134,7 @@ pub(crate) struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("access to union field is unsafe and requires unsafe block", code = E0133)] #[note( "the field may not be properly initialized: using uninitialized data will cause undefined behavior" @@ -146,7 +146,7 @@ pub(crate) struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "mutation of layout constrained field is unsafe and requires unsafe block", code = E0133 @@ -159,7 +159,7 @@ pub(crate) struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsa pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "borrow of layout constrained field with interior mutability is unsafe and requires unsafe block", code = E0133, @@ -171,7 +171,7 @@ pub(crate) struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "unsafe binder cast is unsafe and requires unsafe block information that may be required to uphold safety guarantees of a type", code = E0133, @@ -183,7 +183,7 @@ pub(crate) struct UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe { pub(crate) unsafe_not_inherited_note: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block", code = E0133)] #[help( "in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> @@ -631,7 +631,7 @@ impl Subdiagnostic for UnsafeNotInheritedLintNote { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unnecessary `unsafe` block")] pub(crate) struct UnusedUnsafe { #[label("unnecessary `unsafe` block")] @@ -755,7 +755,7 @@ pub(crate) struct NonConstPath { pub(crate) span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unreachable pattern")] pub(crate) struct UnreachablePattern<'tcx> { #[label("no value can reach this")] @@ -809,7 +809,7 @@ pub(crate) struct WantedConstant { pub(crate) const_path: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unreachable {$descr}")] pub(crate) struct UnreachableDueToUninhabited<'desc, 'tcx> { pub descr: &'desc str, @@ -874,7 +874,7 @@ pub(crate) struct UpperRangeBoundCannotBeMin { pub(crate) span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`", code = E0170)] pub(crate) struct BindingsWithVariantName { #[suggestion( @@ -887,7 +887,7 @@ pub(crate) struct BindingsWithVariantName { pub(crate) name: Ident, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "irrefutable `if let` {$count -> [one] pattern @@ -905,7 +905,7 @@ pub(crate) struct IrrefutableLetPatternsIfLet { pub(crate) count: usize, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "irrefutable `if let` guard {$count -> [one] pattern @@ -923,7 +923,7 @@ pub(crate) struct IrrefutableLetPatternsIfLetGuard { pub(crate) count: usize, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "irrefutable `let...else` {$count -> [one] pattern @@ -941,7 +941,7 @@ pub(crate) struct IrrefutableLetPatternsLetElse { pub(crate) count: usize, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "irrefutable `while let` {$count -> [one] pattern diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 9231b425c4c37..5ebfd8000ef85 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -797,7 +797,7 @@ fn check_for_bindings_named_same_as_variants( { let variant_count = edef.variants().len(); let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did())); - cx.tcx.emit_node_span_lint( + cx.tcx.emit_diag_node_span_lint( BINDINGS_WITH_VARIANT_NAME, cx.hir_source, pat.span, @@ -839,7 +839,7 @@ fn report_irrefutable_let_patterns( ) { macro_rules! emit_diag { ($lint:tt) => {{ - tcx.emit_node_span_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count }); + tcx.emit_diag_node_span_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count }); }}; } @@ -924,7 +924,7 @@ fn report_unreachable_pattern<'p, 'tcx>( lint.covered_by_many = Some(multispan); } } - cx.tcx.emit_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint); + cx.tcx.emit_diag_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint); } /// Detect typos that were meant to be a `const` but were interpreted as a new pattern binding. diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr index e16841b369db9..43cb9eb12e17a 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr @@ -79,7 +79,6 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: for more information, see = help: in order for the call to be safe, the context requires the following additional target feature: sse2 = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` note: an unsafe function restricts its caller, but its body is safe by default @@ -87,6 +86,7 @@ note: an unsafe function restricts its caller, but its body is safe by default | LL | unsafe fn needs_unsafe_block() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see note: the lint level is defined here --> $DIR/safe-calls.rs:65:8 | diff --git a/tests/ui/rust-2024/unsafe-env.e2021.stderr b/tests/ui/rust-2024/unsafe-env.e2021.stderr index a73db9fd60c73..fc3279af43bb8 100644 --- a/tests/ui/rust-2024/unsafe-env.e2021.stderr +++ b/tests/ui/rust-2024/unsafe-env.e2021.stderr @@ -4,13 +4,13 @@ error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe LL | unsafe_fn(); | ^^^^^^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/unsafe-env.rs:8:1 | LL | unsafe fn unsafe_fn() { | ^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see note: the lint level is defined here --> $DIR/unsafe-env.rs:7:8 | diff --git a/tests/ui/rust-2024/unsafe-env.e2024.stderr b/tests/ui/rust-2024/unsafe-env.e2024.stderr index cb48ae231f274..0473e9a2c4ae2 100644 --- a/tests/ui/rust-2024/unsafe-env.e2024.stderr +++ b/tests/ui/rust-2024/unsafe-env.e2024.stderr @@ -4,13 +4,13 @@ error[E0133]: call to unsafe function `std::env::set_var` is unsafe and requires LL | env::set_var("FOO", "BAR"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/unsafe-env.rs:8:1 | LL | unsafe fn unsafe_fn() { | ^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see note: the lint level is defined here --> $DIR/unsafe-env.rs:7:8 | @@ -23,8 +23,8 @@ error[E0133]: call to unsafe function `std::env::remove_var` is unsafe and requi LL | env::remove_var("FOO"); | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior + = note: for more information, see error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block --> $DIR/unsafe-env.rs:14:9 @@ -32,8 +32,8 @@ error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe LL | unsafe_fn(); | ^^^^^^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior + = note: for more information, see error[E0133]: call to unsafe function `set_var` is unsafe and requires unsafe block --> $DIR/unsafe-env.rs:22:5 diff --git a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr index b6804511ac235..01189f15c3fea 100644 --- a/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr +++ b/tests/ui/unsafe/edition-2024-unsafe_op_in_unsafe_fn.stderr @@ -4,13 +4,13 @@ warning[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe blo LL | unsf(); | ^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/edition-2024-unsafe_op_in_unsafe_fn.rs:8:1 | LL | unsafe fn foo() { | ^^^^^^^^^^^^^^^ + = note: for more information, see = note: `#[warn(unsafe_op_in_unsafe_fn)]` (part of `#[warn(rust_2024_compatibility)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr index 35f9d3a4ebc4c..23cb42013633d 100644 --- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/edition_2024_default.stderr @@ -4,13 +4,13 @@ warning[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe blo LL | unsf(); | ^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/edition_2024_default.rs:11:1 | LL | unsafe fn foo() { | ^^^^^^^^^^^^^^^ + = note: for more information, see = note: `#[warn(unsafe_op_in_unsafe_fn)]` (part of `#[warn(rust_2024_compatibility)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr index 0c4070068d0b2..d9d42695d5b31 100644 --- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/in_2024_compatibility.stderr @@ -4,13 +4,13 @@ error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block LL | unsf(); | ^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/in_2024_compatibility.rs:6:1 | LL | unsafe fn foo() { | ^^^^^^^^^^^^^^^ + = note: for more information, see note: the lint level is defined here --> $DIR/in_2024_compatibility.rs:1:9 | diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr index 3e43840cf6cb3..5ba70b882f813 100644 --- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -4,13 +4,13 @@ error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block LL | unsf(); | ^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:8:1 | LL | unsafe fn deny_level() { | ^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see note: the lint level is defined here --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:1:9 | @@ -23,8 +23,8 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe block LL | *PTR; | ^^^^ dereference of raw pointer | - = note: for more information, see = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + = note: for more information, see error[E0133]: use of mutable static is unsafe and requires unsafe block --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:13:5 @@ -32,8 +32,8 @@ error[E0133]: use of mutable static is unsafe and requires unsafe block LL | VOID = (); | ^^^^ use of mutable static | - = note: for more information, see = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + = note: for more information, see error: unnecessary `unsafe` block --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5 @@ -53,13 +53,13 @@ error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block LL | unsf(); | ^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:23:1 | LL | unsafe fn warning_level() { | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see note: the lint level is defined here --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:8 | @@ -73,8 +73,8 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe block LL | *PTR; | ^^^^ dereference of raw pointer | - = note: for more information, see = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + = note: for more information, see error[E0133]: use of mutable static is unsafe and requires unsafe block --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5 @@ -82,8 +82,8 @@ error[E0133]: use of mutable static is unsafe and requires unsafe block LL | VOID = (); | ^^^^ use of mutable static | - = note: for more information, see = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + = note: for more information, see error: unnecessary `unsafe` block --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5 diff --git a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr index f7dbf39e6f261..3308a0807db6f 100644 --- a/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr +++ b/tests/ui/unsafe/unsafe_op_in_unsafe_fn/wrapping-unsafe-block-sugg.stderr @@ -4,13 +4,13 @@ error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block LL | unsf(); | ^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/wrapping-unsafe-block-sugg.rs:11:1 | LL | pub unsafe fn foo() { | ^^^^^^^^^^^^^^^^^^^ + = note: for more information, see note: the lint level is defined here --> $DIR/wrapping-unsafe-block-sugg.rs:4:9 | @@ -23,8 +23,8 @@ error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block LL | unsf(); | ^^^^^^ call to unsafe function | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior + = note: for more information, see error[E0133]: dereference of raw pointer is unsafe and requires unsafe block --> $DIR/wrapping-unsafe-block-sugg.rs:25:13 @@ -32,13 +32,13 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe block LL | let y = *x; | ^^ dereference of raw pointer | - = note: for more information, see = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/wrapping-unsafe-block-sugg.rs:23:1 | LL | pub unsafe fn bar(x: *const i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see error[E0133]: dereference of raw pointer is unsafe and requires unsafe block --> $DIR/wrapping-unsafe-block-sugg.rs:29:9 @@ -46,8 +46,8 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe block LL | y + *x | ^^ dereference of raw pointer | - = note: for more information, see = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + = note: for more information, see error[E0133]: use of mutable static is unsafe and requires unsafe block --> $DIR/wrapping-unsafe-block-sugg.rs:38:13 @@ -55,13 +55,13 @@ error[E0133]: use of mutable static is unsafe and requires unsafe block LL | let y = BAZ; | ^^^ use of mutable static | - = note: for more information, see = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/wrapping-unsafe-block-sugg.rs:36:1 | LL | pub unsafe fn baz() -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see error[E0133]: use of mutable static is unsafe and requires unsafe block --> $DIR/wrapping-unsafe-block-sugg.rs:42:9 @@ -69,8 +69,8 @@ error[E0133]: use of mutable static is unsafe and requires unsafe block LL | y + BAZ | ^^^ use of mutable static | - = note: for more information, see = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + = note: for more information, see error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block --> $DIR/wrapping-unsafe-block-sugg.rs:48:36 @@ -81,13 +81,13 @@ LL | macro_rules! unsafe_macro { () => (unsf()) } LL | unsafe_macro!(); | --------------- in this macro invocation | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior note: an unsafe function restricts its caller, but its body is safe by default --> $DIR/wrapping-unsafe-block-sugg.rs:58:1 | LL | pub unsafe fn unsafe_in_macro() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: for more information, see = note: this error originates in the macro `unsafe_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block @@ -99,8 +99,8 @@ LL | macro_rules! unsafe_macro { () => (unsf()) } LL | unsafe_macro!(); | --------------- in this macro invocation | - = note: for more information, see = note: consult the function's documentation for information on how to avoid undefined behavior + = note: for more information, see = note: this error originates in the macro `unsafe_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 8 previous errors From 480aa4d87e812756888db626f035cfaf35f025f4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 12:13:33 +0100 Subject: [PATCH 18/25] Migrate `rustc_mir_transform` to use `TyCtxt::emit_diag_node_span_lint` --- .../src/check_call_recursion.rs | 2 +- .../src/check_const_item_mutation.rs | 4 +- compiler/rustc_mir_transform/src/coroutine.rs | 2 +- compiler/rustc_mir_transform/src/errors.rs | 64 +++++++++++-------- .../src/ffi_unwind_calls.rs | 4 +- .../src/function_item_references.rs | 2 +- .../src/known_panics_lint.rs | 2 +- .../src/lint_tail_expr_drop_order.rs | 6 +- compiler/rustc_mir_transform/src/liveness.rs | 12 ++-- .../drop/drop-order-comparisons.e2021.stderr | 20 +++--- .../ui/drop/lint-tail-expr-drop-order.stderr | 30 ++++----- ...expr_drop_order-on-coroutine-unwind.stderr | 4 +- 12 files changed, 81 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs index cac6308617acf..baefeaa730479 100644 --- a/compiler/rustc_mir_transform/src/check_call_recursion.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -83,7 +83,7 @@ fn check_recursion<'tcx>( let sp = tcx.def_span(def_id); let hir_id = tcx.local_def_id_to_hir_id(def_id); - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( UNCONDITIONAL_RECURSION, hir_id, sp, diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 375db17fb73a0..20daa9179930d 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -104,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { && let Some((lint_root, span, item)) = self.should_lint_const_item_usage(lhs, def_id, loc) { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( CONST_ITEM_MUTATION, lint_root, span, @@ -150,7 +150,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { if let Some((lint_root, span, item)) = self.should_lint_const_item_usage(place, def_id, lint_loc) { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( CONST_ITEM_MUTATION, lint_root, span, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index c83b10a5e583a..3d4e201a8f17b 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1990,7 +1990,7 @@ fn check_must_not_suspend_def( if let Some(reason_str) = find_attr!(tcx, def_id, MustNotSupend {reason} => reason) { let reason = reason_str.map(|s| errors::MustNotSuspendReason { span: data.source_span, reason: s }); - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( rustc_session::lint::builtin::MUST_NOT_SUSPEND, hir_id, data.source_span, diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 7421a55f2a79b..34720fc2f2958 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -1,6 +1,8 @@ use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintDiagnostic, Subdiagnostic, msg}; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_errors::{ + Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, msg, +}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::mir::AssertKind; use rustc_middle::query::Key; use rustc_middle::ty::TyCtxt; @@ -48,7 +50,7 @@ pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>( ); } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("function cannot return without recursing")] #[help("a `loop` may express intention better if this is on purpose")] pub(crate) struct UnconditionalRecursion { @@ -70,7 +72,7 @@ pub(crate) struct InvalidForceInline { pub reason: &'static str, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] pub(crate) enum ConstMutate { #[diag("attempting to modify a `const` item")] #[note( @@ -129,21 +131,26 @@ pub(crate) enum AssertLintKind { UnconditionalPanic, } -impl<'a, P: std::fmt::Debug> LintDiagnostic<'a, ()> for AssertLint

{ - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { - diag.primary_message(match self.lint_kind { - AssertLintKind::ArithmeticOverflow => { - msg!("this arithmetic operation will overflow") - } - AssertLintKind::UnconditionalPanic => { - msg!("this operation will panic at runtime") - } - }); +impl<'a, P: std::fmt::Debug> Diagnostic<'a, ()> for AssertLint

{ + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let mut diag = Diag::new( + dcx, + level, + match self.lint_kind { + AssertLintKind::ArithmeticOverflow => { + msg!("this arithmetic operation will overflow") + } + AssertLintKind::UnconditionalPanic => { + msg!("this operation will panic at runtime") + } + }, + ); let label = self.assert_kind.diagnostic_message(); self.assert_kind.add_args(&mut |name, value| { diag.arg(name, value); }); diag.span_label(self.span, label); + diag } } @@ -156,14 +163,14 @@ impl AssertLintKind { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("call to inline assembly that may unwind")] pub(crate) struct AsmUnwindCall { #[label("call to inline assembly that may unwind")] pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "call to {$foreign -> [true] foreign function @@ -181,7 +188,7 @@ pub(crate) struct FfiUnwindCall { pub foreign: bool, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("taking a reference to a function item does not give a function pointer")] pub(crate) struct FnItemRef { #[suggestion( @@ -194,14 +201,14 @@ pub(crate) struct FnItemRef { pub ident: Ident, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("value captured by `{$name}` is never read")] #[help("did you mean to capture by reference instead?")] pub(crate) struct UnusedCaptureMaybeCaptureRef { pub name: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("variable `{$name}` is assigned to, but never used")] #[note("consider using `_{$name}` instead")] pub(crate) struct UnusedVarAssignedOnly { @@ -210,7 +217,7 @@ pub(crate) struct UnusedVarAssignedOnly { pub typo: Option, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("value assigned to `{$name}` is never read")] pub(crate) struct UnusedAssign { pub name: Symbol, @@ -237,14 +244,14 @@ pub(crate) struct UnusedAssignSuggestion { pub rhs_borrow_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("value passed to `{$name}` is never read")] #[help("maybe it is overwritten before being read?")] pub(crate) struct UnusedAssignPassed { pub name: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unused variable: `{$name}`")] pub(crate) struct UnusedVariable { pub name: Symbol, @@ -331,11 +338,13 @@ pub(crate) struct MustNotSupend<'a, 'tcx> { } // Needed for def_path_str -impl<'a> LintDiagnostic<'a, ()> for MustNotSupend<'_, '_> { - fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) { - diag.primary_message(msg!( - "{$pre}`{$def_path}`{$post} held across a suspend point, but should not be" - )); +impl<'a> Diagnostic<'a, ()> for MustNotSupend<'_, '_> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let mut diag = Diag::new( + dcx, + level, + msg!("{$pre}`{$def_path}`{$post} held across a suspend point, but should not be"), + ); diag.span_label(self.yield_sp, msg!("the value is held across this suspend point")); if let Some(reason) = self.reason { diag.subdiagnostic(reason); @@ -344,6 +353,7 @@ impl<'a> LintDiagnostic<'a, ()> for MustNotSupend<'_, '_> { diag.arg("pre", self.pre); diag.arg("def_path", self.tcx.def_path_str(self.def_id)); diag.arg("post", self.post); + diag } } diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 06e7bf974b515..2314864e17d52 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -63,7 +63,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { .lint_root; let span = terminator.source_info.span; - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( FFI_UNWIND_CALLS, lint_root, span, @@ -115,7 +115,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { let span = terminator.source_info.span; let foreign = fn_def_id.is_some(); - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( FFI_UNWIND_CALLS, lint_root, span, diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 2ae8f43cf6c81..7b35c18773fac 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -175,7 +175,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { ret, ); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( FUNCTION_ITEM_REFERENCES, lint_root, span, diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 873f6a01ec360..9c3b67d43abf3 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -297,7 +297,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let source_info = self.body.source_info(location); if let Some(lint_root) = self.lint_root(*source_info) { let span = source_info.span; - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint_kind.lint(), lint_root, span, diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 2f733f54b26c9..17bd630be2d88 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -10,7 +10,7 @@ use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::MixedBitSet; use rustc_index::{IndexSlice, IndexVec}; -use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::bug; use rustc_middle::mir::{ self, BasicBlock, Body, ClearCrossCrate, Local, Location, MirDumper, Place, StatementKind, @@ -451,7 +451,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< } let span = local_labels[0].span; - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( lint::builtin::TAIL_EXPR_DROP_ORDER, lint_root.unwrap_or(CRATE_HIR_ID), span, @@ -498,7 +498,7 @@ fn assign_observables_names( names } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("relative drop order changing in Rust 2024")] struct TailExprDropOrderLint<'a> { #[subdiagnostic] diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 3fbe1e398a181..0817022d5642b 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -968,7 +968,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { let typo = maybe_suggest_typo(); errors::UnusedVariableSugg::TryPrefix { spans: vec![def_span], name, typo } }; - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( lint::builtin::UNUSED_VARIABLES, hir_id, def_span, @@ -1018,7 +1018,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { } let typo = maybe_suggest_typo(); - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( lint::builtin::UNUSED_VARIABLES, hir_id, def_span, @@ -1060,7 +1060,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { errors::UnusedVariableSugg::TryPrefix { name, typo, spans: vec![def_span] } }; - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( lint::builtin::UNUSED_VARIABLES, hir_id, spans, @@ -1126,20 +1126,20 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { source_info.span, self.body, ); - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( lint::builtin::UNUSED_ASSIGNMENTS, hir_id, source_info.span, errors::UnusedAssign { name, help: suggestion.is_none(), suggestion }, ) } - AccessKind::Param => tcx.emit_node_span_lint( + AccessKind::Param => tcx.emit_diag_node_span_lint( lint::builtin::UNUSED_ASSIGNMENTS, hir_id, source_info.span, errors::UnusedAssignPassed { name }, ), - AccessKind::Capture => tcx.emit_node_span_lint( + AccessKind::Capture => tcx.emit_diag_node_span_lint( lint::builtin::UNUSED_ASSIGNMENTS, hir_id, decl_span, diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr index 5b4e64c6da756..b1f0967103ab5 100644 --- a/tests/ui/drop/drop-order-comparisons.e2021.stderr +++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr @@ -26,8 +26,6 @@ LL | | }, e.mark(3), e.ok(4)); | |__________________________this value will be stored in a temporary; let us call it `#1` | `#1` will be dropped later as of Edition 2024 | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#3` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -49,6 +47,8 @@ note: `#2` invokes this custom destructor LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/drop-order-comparisons.rs:30:25 | @@ -74,8 +74,6 @@ LL | | }, e.mark(1), e.ok(4)); | |__________________________this value will be stored in a temporary; let us call it `#1` | `#1` will be dropped later as of Edition 2024 | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#2` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -87,6 +85,8 @@ note: `#1` invokes this custom destructor LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see warning: relative drop order changing in Rust 2024 --> $DIR/drop-order-comparisons.rs:102:19 @@ -106,8 +106,6 @@ LL | | }, e.mark(1), e.ok(4)); | |__________________________this value will be stored in a temporary; let us call it `#1` | `#1` will be dropped later as of Edition 2024 | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#2` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -119,6 +117,8 @@ note: `#1` invokes this custom destructor LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see warning: relative drop order changing in Rust 2024 --> $DIR/drop-order-comparisons.rs:223:24 @@ -138,8 +138,6 @@ LL | | }, e.mark(2), e.ok(3)); | |__________________________this value will be stored in a temporary; let us call it `#1` | `#1` will be dropped later as of Edition 2024 | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#2` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -151,6 +149,8 @@ note: `#1` invokes this custom destructor LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see warning: relative drop order changing in Rust 2024 --> $DIR/drop-order-comparisons.rs:249:24 @@ -170,8 +170,6 @@ LL | | }, e.mark(2), e.ok(3)); | |__________________________this value will be stored in a temporary; let us call it `#1` | `#1` will be dropped later as of Edition 2024 | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#2` invokes this custom destructor --> $DIR/drop-order-comparisons.rs:503:1 | @@ -183,6 +181,8 @@ note: `#1` invokes this custom destructor LL | impl<'b> Drop for LogDrop<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see warning: `if let` assigns a shorter lifetime since Edition 2024 --> $DIR/drop-order-comparisons.rs:125:13 diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr index c69c58aa1ab77..d638d6bd7f029 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.stderr +++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr @@ -16,8 +16,6 @@ LL | x.get() + LoudDropper.get() LL | } | - now the temporary value is dropped here, before the local variables in the block or statement | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | @@ -29,6 +27,8 @@ note: `x` invokes this custom destructor LL | impl Drop for LoudDropper { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/lint-tail-expr-drop-order.rs:6:9 | @@ -53,8 +53,6 @@ LL | x.get() + LoudDropper.get() LL | } | - now the temporary value is dropped here, before the local variables in the block or statement | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | @@ -66,6 +64,8 @@ note: `x` invokes this custom destructor LL | impl Drop for LoudDropper { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see error: relative drop order changing in Rust 2024 --> $DIR/lint-tail-expr-drop-order.rs:92:7 @@ -85,8 +85,6 @@ LL | { LoudDropper.get() } LL | } | - now the temporary value is dropped here, before the local variables in the block or statement | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | @@ -98,6 +96,8 @@ note: `x` invokes this custom destructor LL | impl Drop for LoudDropper { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see error: relative drop order changing in Rust 2024 --> $DIR/lint-tail-expr-drop-order.rs:145:5 @@ -117,14 +117,14 @@ LL | LoudDropper.get() LL | } | - now the temporary value is dropped here, before the local variables in the block or statement | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | LL | impl Drop for LoudDropper { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see error: relative drop order changing in Rust 2024 --> $DIR/lint-tail-expr-drop-order.rs:162:14 @@ -144,9 +144,9 @@ LL | extract(&T::default()) LL | } | - now the temporary value is dropped here, before the local variables in the block or statement | + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages = warning: this changes meaning in Rust 2024 = note: for more information, see - = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages error: relative drop order changing in Rust 2024 --> $DIR/lint-tail-expr-drop-order.rs:176:5 @@ -166,8 +166,6 @@ LL | LoudDropper.get() LL | } | - now the temporary value is dropped here, before the local variables in the block or statement | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | @@ -179,6 +177,8 @@ note: `x` invokes this custom destructor LL | impl Drop for LoudDropper { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see error: relative drop order changing in Rust 2024 --> $DIR/lint-tail-expr-drop-order.rs:220:5 @@ -198,8 +198,6 @@ LL | LoudDropper3.get() LL | } | - now the temporary value is dropped here, before the local variables in the block or statement | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:193:5 | @@ -211,6 +209,8 @@ note: `x` invokes this custom destructor LL | impl Drop for LoudDropper2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see error: relative drop order changing in Rust 2024 --> $DIR/lint-tail-expr-drop-order.rs:233:13 @@ -230,8 +230,6 @@ LL | let _x = LoudDropper; LL | )); | - now the temporary value is dropped here, before the local variables in the block or statement | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#1` invokes this custom destructor --> $DIR/lint-tail-expr-drop-order.rs:10:1 | @@ -243,6 +241,8 @@ note: `_x` invokes this custom destructor LL | impl Drop for LoudDropper { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see error: aborting due to 8 previous errors diff --git a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr index 94977185ced82..f89d1d3c2ceb7 100644 --- a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr +++ b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr @@ -22,8 +22,6 @@ LL | } LL | } | - now the temporary value is dropped here, before the local variables in the block or statement | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: `#2` invokes this custom destructor --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:9:1 | @@ -40,6 +38,8 @@ note: `e` invokes this custom destructor LL | impl std::ops::Drop for Drop { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:6:9 | From f02ce9648fc0666561b15769464b5a157f6f4d70 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 14:21:11 +0100 Subject: [PATCH 19/25] Migrate `rustc_monomorphize` to use `TyCtxt::emit_diag_node_span_lint` --- compiler/rustc_monomorphize/src/errors.rs | 4 ++-- compiler/rustc_monomorphize/src/mono_checks/move_check.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 62a8743873bdb..27705a9837ad3 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_macros::{Diagnostic, LintDiagnostic}; +use rustc_macros::Diagnostic; use rustc_middle::ty::{Instance, Ty}; use rustc_span::{Span, Symbol}; @@ -24,7 +24,7 @@ pub(crate) struct NoOptimizedMir { pub instance: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("moving {$size} bytes")] #[note( "the current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = \"...\"]`" diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs index a8f3104c0d98d..12aa918513834 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs @@ -174,7 +174,7 @@ impl<'tcx> MoveCheckVisitor<'tcx> { } } - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( LARGE_ASSIGNMENTS, lint_root, reported_span, From 8f63c0003818078d262840ae9de1c5dc42c12aab Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 15:00:04 +0100 Subject: [PATCH 20/25] Migrate `rustc_passes` to use `TyCtxt::emit_diag_node_span_lint` --- compiler/rustc_middle/src/middle/stability.rs | 18 +++++-- compiler/rustc_passes/src/check_attr.rs | 48 +++++++++---------- compiler/rustc_passes/src/dead.rs | 4 +- compiler/rustc_passes/src/errors.rs | 42 ++++++++-------- compiler/rustc_passes/src/stability.rs | 8 ++-- 5 files changed, 66 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 4f0073b93ebad..bd0fad55bc0f2 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,7 +4,7 @@ use std::num::NonZero; use rustc_ast::NodeId; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintBuffer, msg}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintBuffer, LintDiagnostic, msg}; use rustc_feature::GateIssue; use rustc_hir::attrs::{DeprecatedSince, Deprecation}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -125,7 +125,19 @@ pub struct Deprecated { pub since_kind: DeprecatedSinceKind, } -impl<'a, G: EmissionGuarantee> rustc_errors::LintDiagnostic<'a, G> for Deprecated { +impl<'a, G: EmissionGuarantee> rustc_errors::Diagnostic<'a, G> for Deprecated { + fn into_diag( + self, + dcx: rustc_errors::DiagCtxtHandle<'a>, + level: rustc_errors::Level, + ) -> Diag<'a, G> { + let mut diag = Diag::new(dcx, level, ""); + self.decorate_lint(&mut diag); + diag + } +} + +impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for Deprecated { fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { diag.primary_message(match &self.since_kind { DeprecatedSinceKind::InEffect => msg!( @@ -245,7 +257,7 @@ fn late_report_deprecation( note: depr.note.map(|ident| ident.name), since_kind: deprecated_since_kind(is_in_effect, depr.since), }; - tcx.emit_node_span_lint(lint, hir_id, method_span, diag); + tcx.emit_diag_node_span_lint(lint, hir_id, method_span, diag); } /// Result of `TyCtxt::eval_stability`. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index b3dc48ea62f7f..aa898f2d8a439 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -33,7 +33,7 @@ use rustc_hir::{ Item, ItemKind, MethodKind, Node, ParamName, PartialConstStability, Safety, Stability, StabilityLevel, Target, TraitItem, find_attr, }; -use rustc_macros::LintDiagnostic; +use rustc_macros::Diagnostic; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; @@ -57,18 +57,18 @@ use tracing::debug; use crate::errors; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#[diagnostic::on_unimplemented]` can only be applied to trait definitions")] struct DiagnosticOnUnimplementedOnlyForTraits; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#[diagnostic::on_const]` can only be applied to trait impls")] struct DiagnosticOnConstOnlyForTraitImpls { #[label("not a trait impl")] item_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#[diagnostic::on_const]` can only be applied to non-const trait impls")] struct DiagnosticOnConstOnlyForNonConstTraitImpls { #[label("this is a const trait impl")] @@ -453,7 +453,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .span_until_char(attr_span, '[') .shrink_to_hi(); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -464,7 +464,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }, ) } - ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( + ast::AttrStyle::Inner => self.tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -595,7 +595,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if _impl.of_trait.is_none() ) { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, @@ -613,7 +613,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { directive: Option<&Directive>, ) { if !matches!(target, Target::Trait) { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, @@ -668,7 +668,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ItemLike::Item(it) => match it.expect_impl().constness { Constness::Const => { let item_span = self.tcx.hir_span(hir_id); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, @@ -682,7 +682,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } let item_span = self.tcx.hir_span(hir_id); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, @@ -707,11 +707,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let attrs = self.tcx.codegen_fn_attrs(did); // Not checking naked as `#[inline]` is forbidden for naked functions anyways. if attrs.contains_extern_indicator() { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, - errors::InlineIgnoredForExported {}, + errors::InlineIgnoredForExported, ); } } @@ -1058,7 +1058,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Use | Target::ExternCrate => {} _ => { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, span, @@ -1073,7 +1073,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_masked(&self, span: Span, hir_id: HirId, target: Target) { if target != Target::ExternCrate { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, span, @@ -1086,7 +1086,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } if self.tcx.extern_mod_stmt_cnum(hir_id.owner.def_id).is_none() { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, span, @@ -1238,7 +1238,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, @@ -1475,7 +1475,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let ItemLike::Item(item) = item { is_c_like_enum(item) } else { false } })) { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( CONFLICTING_REPR_HINTS, hir_id, hint_spans.collect::>(), @@ -1571,7 +1571,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id)) == DefKind::Impl { of_trait: true } => { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, @@ -1592,7 +1592,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let is_decl_macro = !macro_definition.macro_rules; if is_decl_macro { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, @@ -1644,7 +1644,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .span_until_char(attr_span, '[') .shrink_to_hi(); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, @@ -1655,7 +1655,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }, ) } - Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( + Some(ast::AttrStyle::Inner) | None => self.tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span(), @@ -1681,7 +1681,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; }; - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span(), @@ -1849,7 +1849,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { "#[export_name]" }; - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::UNUSED_ATTRIBUTES, hir_id, no_mangle_span, @@ -2193,7 +2193,7 @@ fn check_duplicates( } else { (attr_span, *entry.get()) }; - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( UNUSED_ATTRIBUTES, hir_id, this, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index f6d00f5342f27..0f5dd1ceda5b4 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -232,7 +232,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && !assign.span.from_expansion() { let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( lint::builtin::DEAD_CODE, assign.hir_id, assign.span, @@ -1104,7 +1104,7 @@ impl<'tcx> DeadVisitor<'tcx> { }; let hir_id = tcx.local_def_id_to_hir_id(first_item.def_id); - self.tcx.emit_node_span_lint(DEAD_CODE, hir_id, MultiSpan::from_spans(spans), diag); + self.tcx.emit_diag_node_span_lint(DEAD_CODE, hir_id, MultiSpan::from_spans(spans), diag); } fn warn_multiple( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4bb8b06f129cc..560f84260aa70 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -8,14 +8,14 @@ use rustc_errors::{ }; use rustc_hir::Target; use rustc_hir::attrs::{MirDialect, MirPhase}; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{MainDefinition, Ty}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; use crate::check_attr::ProcMacroKind; use crate::lang_items::Duplicate; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#[diagnostic::do_not_recommend]` can only be placed on trait implementations")] pub(crate) struct IncorrectDoNotRecommendLocation; @@ -45,7 +45,7 @@ pub(crate) struct ConstContinueAttr { pub node_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`{$no_mangle_attr}` attribute may not be used in combination with `{$export_name_attr}`")] pub(crate) struct MixedExportNameAndNoMangle { #[label("`{$no_mangle_attr}` is ignored")] @@ -62,7 +62,7 @@ pub(crate) struct MixedExportNameAndNoMangle { pub export_name_attr: &'static str, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("crate-level attribute should be an inner attribute")] pub(crate) struct OuterCrateLevelAttr { #[subdiagnostic] @@ -76,7 +76,7 @@ pub(crate) struct OuterCrateLevelAttrSuggestion { pub bang_position: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("crate-level attribute should be in the root module")] pub(crate) struct InnerCrateLevelAttr; @@ -152,7 +152,7 @@ pub(crate) struct DocInlineConflict { pub spans: MultiSpan, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("this attribute can only be applied to a `use` item")] #[note( "read for more information" @@ -164,7 +164,7 @@ pub(crate) struct DocInlineOnlyUse { pub item_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("this attribute can only be applied to an `extern crate` item")] #[note( "read for more information" @@ -176,7 +176,7 @@ pub(crate) struct DocMaskedOnlyExternCrate { pub item_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("this attribute cannot be applied to an `extern crate self` item")] pub(crate) struct DocMaskedNotExternCrateSelf { #[label("not applicable on `extern crate self` items")] @@ -192,7 +192,7 @@ pub(crate) struct BothFfiConstAndPure { pub attr_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("attribute should be applied to an `extern` block with non-Rust ABI")] #[warning( "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" @@ -253,7 +253,7 @@ pub(crate) struct InvalidReprAlignForTarget { pub size: u64, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("conflicting representation hints", code = E0566)] pub(crate) struct ReprConflictingLint; @@ -302,7 +302,7 @@ pub(crate) struct RustcForceInlineCoro { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] pub(crate) enum MacroExport { #[diag("`#[macro_export]` has no effect on declarative macro definitions")] #[note("declarative macros follow the same exporting rules as regular items")] @@ -323,7 +323,7 @@ pub(crate) enum UnusedNote { LinkerMessagesBinaryCrateOnly, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unused attribute")] pub(crate) struct Unused { #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] @@ -347,7 +347,7 @@ pub(crate) struct InvalidMayDangle { pub attr_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unused attribute")] pub(crate) struct UnusedDuplicate { #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] @@ -371,7 +371,7 @@ pub(crate) struct UnusedMultiple { pub name: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("this `#[deprecated]` annotation has no effect")] pub(crate) struct DeprecatedAnnotationHasNoEffect { #[suggestion( @@ -803,7 +803,7 @@ pub(crate) struct IncorrectCrateType { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "useless assignment of {$is_field_assign -> [true] field @@ -815,12 +815,12 @@ pub(crate) struct UselessAssignment<'a> { pub ty: Ty<'a>, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#[inline]` is ignored on externally exported functions")] #[help( "externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`" )] -pub(crate) struct InlineIgnoredForExported {} +pub(crate) struct InlineIgnoredForExported; #[derive(Diagnostic)] #[diag("{$repr}")] @@ -1041,7 +1041,7 @@ pub(crate) struct ConstStableNotStable { pub const_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] pub(crate) enum MultipleDeadCodes<'tcx> { #[diag( "{ $multiple -> @@ -1169,7 +1169,7 @@ pub(crate) struct ProcMacroBadSig { pub kind: ProcMacroKind, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable" )] @@ -1178,7 +1178,7 @@ pub(crate) struct UnnecessaryStableFeature { pub since: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}`" )] @@ -1200,7 +1200,7 @@ pub(crate) struct UnnecessaryPartialStableFeature { pub implies: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("an `#[unstable]` annotation here has no effect")] #[note("see issue #55436 for more information")] pub(crate) struct IneffectiveUnstableImpl; diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6fd28c78740cd..927eb04cb55e3 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -642,7 +642,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { && c.fully_stable && !unstable_feature_bound_in_effect { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id(), span, @@ -859,7 +859,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { note: Some(deprecation), since_kind: lint::DeprecatedSinceKind::InEffect, }; - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( DEPRECATED, id, method_span.unwrap_or(path.span), @@ -1130,7 +1130,7 @@ fn unnecessary_partially_stable_feature_lint( implies: Symbol, since: Symbol, ) { - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, @@ -1153,7 +1153,7 @@ fn unnecessary_stable_feature_lint( if since.as_str() == VERSION_PLACEHOLDER { since = sym::env_CFG_RELEASE; } - tcx.emit_node_span_lint( + tcx.emit_diag_node_span_lint( lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, From 1c6c0f73160c08984ae37ad606b1765b3b8848e6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 15:13:57 +0100 Subject: [PATCH 21/25] Migrate `rustc_trait_selection` to use `TyCtxt::emit_diag_node_span_lint` --- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/errors.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index aa898f2d8a439..27cfc7cb1a0e4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -639,7 +639,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } }); if !has_generic { - self.tcx.emit_node_span_lint( + self.tcx.emit_diag_node_span_lint( MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, hir_id, span, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 560f84260aa70..b9ada150d0301 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1450,7 +1450,7 @@ pub(crate) struct FunctionNamesDuplicated { pub spans: Vec, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("there is no parameter `{$argument_name}` on trait `{$trait_name}`")] pub(crate) struct UnknownFormatParameterForOnUnimplementedAttr { pub argument_name: Symbol, From 2bb3b01af24afd90157660cb64de891699de20d8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 15:47:11 +0100 Subject: [PATCH 22/25] Replace `TyCtxt::emit_node_span_lint` with `emit_diag_node_span_lint` --- compiler/rustc_borrowck/src/lib.rs | 7 +- .../rustc_codegen_ssa/src/target_features.rs | 2 +- .../rustc_const_eval/src/const_eval/error.rs | 2 +- .../src/const_eval/machine.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 2 +- .../src/check/compare_impl_item/refine.rs | 4 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +- .../src/coherence/orphan.rs | 4 +- .../src/hir_ty_lowering/dyn_trait.rs | 2 +- compiler/rustc_hir_typeck/src/cast.rs | 6 +- compiler/rustc_hir_typeck/src/fallback.rs | 4 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- .../rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_lint/src/async_closures.rs | 2 +- compiler/rustc_lint/src/async_fn_in_trait.rs | 2 +- compiler/rustc_lint/src/dangling.rs | 4 +- compiler/rustc_lint/src/expect.rs | 2 +- compiler/rustc_lint/src/foreign_modules.rs | 2 +- .../src/function_cast_as_integer.rs | 2 +- compiler/rustc_lint/src/gpukernel_abi.rs | 2 +- compiler/rustc_lint/src/if_let_rescope.rs | 2 +- .../rustc_lint/src/impl_trait_overcaptures.rs | 4 +- compiler/rustc_lint/src/transmute.rs | 4 +- compiler/rustc_middle/src/middle/stability.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 18 +---- compiler/rustc_mir_build/src/builder/mod.rs | 2 +- .../rustc_mir_build/src/check_unsafety.rs | 73 +++++++++---------- .../src/thir/pattern/check_match.rs | 6 +- .../src/check_call_recursion.rs | 2 +- .../src/check_const_item_mutation.rs | 4 +- compiler/rustc_mir_transform/src/coroutine.rs | 2 +- .../src/ffi_unwind_calls.rs | 4 +- .../src/function_item_references.rs | 2 +- .../src/known_panics_lint.rs | 2 +- .../src/lint_tail_expr_drop_order.rs | 2 +- compiler/rustc_mir_transform/src/liveness.rs | 12 +-- .../src/mono_checks/move_check.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 40 +++++----- compiler/rustc_passes/src/dead.rs | 4 +- compiler/rustc_passes/src/stability.rs | 8 +- compiler/rustc_pattern_analysis/src/lints.rs | 2 +- compiler/rustc_pattern_analysis/src/rustc.rs | 6 +- compiler/rustc_privacy/src/lib.rs | 6 +- 43 files changed, 123 insertions(+), 145 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 259c6cd7728ce..2fc057ae38823 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2698,12 +2698,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - tcx.emit_diag_node_span_lint( - UNUSED_MUT, - lint_root, - span, - VarNeedNotMut { span: mut_span }, - ) + tcx.emit_node_span_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) } } } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index d7f871527e3d1..e9209657984e0 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -75,7 +75,7 @@ pub(crate) fn from_target_feature_attr( // For "neon" specifically, we emit an FCW instead of a hard error. // See . if tcx.sess.target.arch == Arch::AArch64 && name.as_str() == "neon" { - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( AARCH64_SOFTFLOAT_NEON, tcx.local_def_id_to_hir_id(did), feature_span, diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 7efef74e70aa3..6694a6e8ae403 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -256,5 +256,5 @@ pub(super) fn lint<'tcx, L>( { let (span, frames) = get_span_and_frames(tcx, &machine.stack); - tcx.emit_diag_node_span_lint(lint, machine.best_lint_scope(*tcx), span, decorator(frames)); + tcx.emit_node_span_lint(lint, machine.best_lint_scope(*tcx), span, decorator(frames)); } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 3da9f2e2cdcdf..c2b3ea19c3f48 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -718,7 +718,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { .level .is_error(); let span = ecx.cur_span(); - ecx.tcx.emit_diag_node_span_lint( + ecx.tcx.emit_node_span_lint( rustc_session::lint::builtin::LONG_RUNNING_CONST_EVAL, hir_id, span, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a6a1b95ce4c1a..2068fc0ab978c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1256,7 +1256,7 @@ fn check_impl_items_against_trait<'tcx>( } if self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(ty_trait_item.def_id) { - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( rustc_lint_defs::builtin::DEAD_CODE, tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()), tcx.def_span(ty_impl_item.def_id), diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 0944edd86ef19..31104411ab55b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -345,7 +345,7 @@ fn report_mismatched_rpitit_signature<'tcx>( with_no_trimmed_paths!(with_types_for_signature!(format!("{return_ty}"))); let span = unmatched_bound.unwrap_or(span); - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE }, tcx.local_def_id_to_hir_id(impl_m_def_id.expect_local()), span, @@ -442,7 +442,7 @@ fn report_mismatched_rpitit_captures<'tcx>( .sort_by_cached_key(|arg| !matches!(arg.kind(), ty::GenericArgKind::Lifetime(_))); let suggestion = format!("use<{}>", trait_captured_args.iter().join(", ")); - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE }, tcx.local_def_id_to_hir_id(impl_opaque_def_id), use_bound_span, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 5a4d1794623f1..426331b33bd90 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -797,7 +797,7 @@ fn lint_item_shadowing_supertrait_item<'tcx>(tcx: TyCtxt<'tcx>, trait_item_def_i errors::SupertraitItemShadowee::Several { traits: traits.into(), spans: spans.into() } }; - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( SHADOWING_SUPERTRAIT_ITEMS, tcx.local_def_id_to_hir_id(trait_item_def_id), tcx.def_span(trait_item_def_id), @@ -2458,7 +2458,7 @@ fn lint_redundant_lifetimes<'tcx>( && outlives_env.free_region_map().sub_free_regions(tcx, victim, candidate) { shadowed.insert(victim); - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( rustc_lint_defs::builtin::REDUNDANT_LIFETIMES, tcx.local_def_id_to_hir_id(def_id.expect_local()), tcx.def_span(def_id), diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index b5e40058e7533..f1e138dbcb97a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -497,13 +497,13 @@ fn lint_uncovered_ty_params<'tcx>( let name = tcx.item_ident(param_def_id); match local_ty { - Some(local_type) => tcx.emit_diag_node_span_lint( + Some(local_type) => tcx.emit_node_span_lint( UNCOVERED_PARAM_IN_PROJECTION, hir_id, span, errors::TyParamFirstLocalLint { span, note: (), param: name, local_type }, ), - None => tcx.emit_diag_node_span_lint( + None => tcx.emit_node_span_lint( UNCOVERED_PARAM_IN_PROJECTION, hir_id, span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 459d13e46e854..7b8e09943df71 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -291,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME(mgca): Ideally we would generalize the name of this lint to sth. like // `unused_associated_item_bindings` since this can now also trigger on *const* // projections / assoc *const* bindings. - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( UNUSED_ASSOCIATED_TYPE_BOUNDS, hir_id, span, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index af529386eee2a..eaa87f1d4cbc6 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -687,7 +687,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); - fcx.tcx.emit_diag_node_span_lint( + fcx.tcx.emit_node_span_lint( lint, self.expr.hir_id, self.span, @@ -1125,7 +1125,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg }; - fcx.tcx.emit_diag_node_span_lint( + fcx.tcx.emit_node_span_lint( lint::builtin::LOSSY_PROVENANCE_CASTS, self.expr.hir_id, self.span, @@ -1141,7 +1141,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg }; - fcx.tcx.emit_diag_node_span_lint( + fcx.tcx.emit_node_span_lint( lint::builtin::FUZZY_PROVENANCE_CASTS, self.expr.hir_id, self.span, diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 79fdfd3563676..c10e7f3bfb8b9 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -238,7 +238,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let sugg = self.try_to_suggest_annotations(&[root_vid], coercion_graph); for (hir_id, span, reason) in affected_unsafe_infer_vars { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, hir_id, span, @@ -304,7 +304,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { { self.adjust_fulfillment_error_for_expr_obligation(never_error); let sugg = self.try_to_suggest_annotations(diverging_vids, coercions); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, self.tcx.local_def_id_to_hir_id(self.body_id), self.tcx.def_span(self.body_id), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 81523cdf633d5..1931222bba30e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1145,7 +1145,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); return (Ty::new_error(self.tcx, guar), res); } else { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( SELF_CONSTRUCTOR_FROM_OUTER_ITEM, hir_id, path_span, diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 6e5b05a8191fc..608bc7dffd9c0 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -717,7 +717,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { SupertraitItemShadowee::Several { traits: traits.into(), spans: spans.into() } }; - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( RESOLVING_TO_ITEMS_SHADOWING_SUPERTRAIT_ITEMS, segment.hir_id, segment.ident.span, diff --git a/compiler/rustc_lint/src/async_closures.rs b/compiler/rustc_lint/src/async_closures.rs index ebcafa2ad5cdb..0bc245c742b2e 100644 --- a/compiler/rustc_lint/src/async_closures.rs +++ b/compiler/rustc_lint/src/async_closures.rs @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncClosureUsage { let deletion_span = cx.tcx.sess.source_map().span_extend_while_whitespace(async_decl_span); - cx.tcx.emit_diag_node_span_lint( + cx.tcx.emit_node_span_lint( CLOSURE_RETURNING_ASYNC_BLOCK, expr.hir_id, fn_decl_span, diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs index 19d0a13690dbd..9923f05df3c73 100644 --- a/compiler/rustc_lint/src/async_fn_in_trait.rs +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { opaq_def.def_id, " + Send", ); - cx.tcx.emit_diag_node_span_lint( + cx.tcx.emit_node_span_lint( ASYNC_FN_IN_TRAIT, item.hir_id(), async_span, diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 668f2741bb0ab..448c0ded637c6 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -186,7 +186,7 @@ fn lint_addr_of_local<'a>( && let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id) && cx.tcx.hir_enclosing_body_owner(from) == dcx.body { - cx.tcx.emit_diag_node_span_lint( + cx.tcx.emit_node_span_lint( DANGLING_POINTERS_FROM_LOCALS, expr.hir_id, expr.span, @@ -270,7 +270,7 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { && find_attr!(cx.tcx, fn_id, RustcAsPtr(_)) { // FIXME: use `emit_node_lint` when `#[primary_span]` is added. - cx.tcx.emit_diag_node_span_lint( + cx.tcx.emit_node_span_lint( DANGLING_POINTERS_FROM_TEMPORARIES, expr.hir_id, method.ident.span, diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index b7c8ff6408711..481e116d06e01 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -61,7 +61,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { { let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale }); let note = expectation.is_unfulfilled_lint_expectations; - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( UNFULFILLED_LINT_EXPECTATIONS, *hir_id, expectation.emission_span, diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index b9ae354c7e18f..d234c68631030 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -162,7 +162,7 @@ impl ClashingExternDeclarations { sub, } }; - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( CLASHING_EXTERN_DECLARATIONS, this_fi.hir_id(), mismatch_label, diff --git a/compiler/rustc_lint/src/function_cast_as_integer.rs b/compiler/rustc_lint/src/function_cast_as_integer.rs index 9b530ec5568c1..2a4ff1f63db52 100644 --- a/compiler/rustc_lint/src/function_cast_as_integer.rs +++ b/compiler/rustc_lint/src/function_cast_as_integer.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for FunctionCastsAsInteger { } let cast_from_ty = cx.typeck_results().expr_ty(cast_from_expr); if matches!(cast_from_ty.kind(), ty::FnDef(..)) { - cx.tcx.emit_diag_node_span_lint( + cx.tcx.emit_node_span_lint( FUNCTION_CASTS_AS_INTEGER, expr.hir_id, cast_to_expr.span.with_lo(cast_from_expr.span.hi() + BytePos(1)), diff --git a/compiler/rustc_lint/src/gpukernel_abi.rs b/compiler/rustc_lint/src/gpukernel_abi.rs index d8c8feda94aee..4fb26739cd28a 100644 --- a/compiler/rustc_lint/src/gpukernel_abi.rs +++ b/compiler/rustc_lint/src/gpukernel_abi.rs @@ -173,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperGpuKernelLint { let mut checker = CheckGpuKernelTypes { tcx: cx.tcx, has_invalid: false }; input_ty.fold_with(&mut checker); if checker.has_invalid { - cx.tcx.emit_diag_node_span_lint( + cx.tcx.emit_node_span_lint( IMPROPER_GPU_KERNEL_ARG, input_hir.hir_id, input_hir.span, diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 43c51240aa332..ba196ef301c0d 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -238,7 +238,7 @@ impl IfLetRescope { } } if let Some((span, hir_id)) = first_if_to_lint { - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( IF_LET_RESCOPE, hir_id, span, diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index eb904e1bc819d..3e18e918439ca 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -345,7 +345,7 @@ where .map(|(&def_id, _)| self.tcx.def_span(def_id)) .collect(); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( IMPL_TRAIT_OVERCAPTURES, self.tcx.local_def_id_to_hir_id(opaque_def_id), opaque_span, @@ -402,7 +402,7 @@ where .iter() .all(|(def_id, _)| explicitly_captured.contains(def_id)) { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( IMPL_TRAIT_REDUNDANT_CAPTURES, self.tcx.local_def_id_to_hir_id(opaque_def_id), opaque_span, diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index 7a8df8195a0e3..b55d209130b02 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -166,7 +166,7 @@ fn check_int_to_ptr_transmute<'tcx>( } let suffix = if mutbl.is_mut() { "_mut" } else { "" }; - cx.tcx.emit_diag_node_span_lint( + cx.tcx.emit_node_span_lint( INTEGER_TO_PTR_TRANSMUTES, expr.hir_id, expr.span, @@ -219,7 +219,7 @@ fn check_ptr_transmute_in_const<'tcx>( || matches!(cx.tcx.def_kind(body_owner_def_id), DefKind::AssocConst) { if src.is_raw_ptr() && dst.is_integral() { - cx.tcx.emit_diag_node_span_lint( + cx.tcx.emit_node_span_lint( PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, expr.hir_id, expr.span, diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index bd0fad55bc0f2..ff6baabbb29a0 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -257,7 +257,7 @@ fn late_report_deprecation( note: depr.note.map(|ident| ident.name), since_kind: deprecated_since_kind(is_in_effect, depr.since), }; - tcx.emit_diag_node_span_lint(lint, hir_id, method_span, diag); + tcx.emit_node_span_lint(lint, hir_id, method_span, diag); } /// Result of `TyCtxt::eval_stability`. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9eb41e57d4dce..d21f07a23e328 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2495,26 +2495,10 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_outlives(xs)) } - /// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`, - /// typically generated by `#[derive(LintDiagnostic)]`). - #[track_caller] - pub fn emit_node_span_lint( - self, - lint: &'static Lint, - hir_id: HirId, - span: impl Into, - decorator: impl for<'a> LintDiagnostic<'a, ()>, - ) { - let level = self.lint_level_at_node(lint, hir_id); - lint_level(self.sess, lint, level, Some(span.into()), |lint| { - decorator.decorate_lint(lint); - }) - } - /// Emit a lint at `span` from a lint struct (some type that implements `Diagnostic`, /// typically generated by `#[derive(Diagnostic)]`). #[track_caller] - pub fn emit_diag_node_span_lint( + pub fn emit_node_span_lint( self, lint: &'static Lint, hir_id: HirId, diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 3835811571746..c8ca7bfccc07c 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -921,7 +921,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .as_ref() .unwrap_crate_local() .lint_root; - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::UNREACHABLE_CODE, lint_root, target_loc.span, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index e3fa4802518a7..24c85b7ec3f5d 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -108,7 +108,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { }) .unwrap_or_default(); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( DEPRECATED_SAFE_2024, self.hir_context, span, @@ -780,7 +780,7 @@ impl UnsafeOpKind { // FIXME: ideally we would want to trim the def paths, but this is not // feasible with the current lint emission API (see issue #106126). match self { - CallToUnsafeFunction(Some(did)) => tcx.emit_diag_node_span_lint( + CallToUnsafeFunction(Some(did)) => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -790,7 +790,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - CallToUnsafeFunction(None) => tcx.emit_diag_node_span_lint( + CallToUnsafeFunction(None) => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -799,7 +799,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfInlineAssembly => tcx.emit_diag_node_span_lint( + UseOfInlineAssembly => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -808,7 +808,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - InitializingTypeWith => tcx.emit_diag_node_span_lint( + InitializingTypeWith => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -817,7 +817,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - InitializingTypeWithUnsafeField => tcx.emit_diag_node_span_lint( + InitializingTypeWithUnsafeField => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -826,7 +826,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfMutableStatic => tcx.emit_diag_node_span_lint( + UseOfMutableStatic => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -835,7 +835,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfExternStatic => tcx.emit_diag_node_span_lint( + UseOfExternStatic => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -844,7 +844,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - UseOfUnsafeField => tcx.emit_diag_node_span_lint( + UseOfUnsafeField => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -853,7 +853,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - DerefOfRawPointer => tcx.emit_diag_node_span_lint( + DerefOfRawPointer => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -862,7 +862,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - AccessToUnionField => tcx.emit_diag_node_span_lint( + AccessToUnionField => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -871,7 +871,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - MutationOfLayoutConstrainedField => tcx.emit_diag_node_span_lint( + MutationOfLayoutConstrainedField => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -880,7 +880,7 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - BorrowOfLayoutConstrainedField => tcx.emit_diag_node_span_lint( + BorrowOfLayoutConstrainedField => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -889,30 +889,29 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - CallToFunctionWith { function, missing, build_enabled } => tcx - .emit_diag_node_span_lint( - UNSAFE_OP_IN_UNSAFE_FN, - hir_id, + CallToFunctionWith { function, missing, build_enabled } => tcx.emit_node_span_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { span, - UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { - span, - function: with_no_trimmed_paths!(tcx.def_path_str(*function)), - missing_target_features: DiagArgValue::StrListSepByAnd( - missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), - ), - missing_target_features_count: missing.len(), - note: !build_enabled.is_empty(), - build_target_features: DiagArgValue::StrListSepByAnd( - build_enabled - .iter() - .map(|feature| Cow::from(feature.to_string())) - .collect(), - ), - build_target_features_count: build_enabled.len(), - unsafe_not_inherited_note, - }, - ), - UnsafeBinderCast => tcx.emit_diag_node_span_lint( + function: with_no_trimmed_paths!(tcx.def_path_str(*function)), + missing_target_features: DiagArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), + ), + missing_target_features_count: missing.len(), + note: !build_enabled.is_empty(), + build_target_features: DiagArgValue::StrListSepByAnd( + build_enabled + .iter() + .map(|feature| Cow::from(feature.to_string())) + .collect(), + ), + build_target_features_count: build_enabled.len(), + unsafe_not_inherited_note, + }, + ), + UnsafeBinderCast => tcx.emit_node_span_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, @@ -1201,7 +1200,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { warnings.sort_by_key(|w| w.block_span); for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings { let block_span = tcx.sess.source_map().guess_head_span(block_span); - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( UNUSED_UNSAFE, hir_id, block_span, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 5ebfd8000ef85..9231b425c4c37 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -797,7 +797,7 @@ fn check_for_bindings_named_same_as_variants( { let variant_count = edef.variants().len(); let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did())); - cx.tcx.emit_diag_node_span_lint( + cx.tcx.emit_node_span_lint( BINDINGS_WITH_VARIANT_NAME, cx.hir_source, pat.span, @@ -839,7 +839,7 @@ fn report_irrefutable_let_patterns( ) { macro_rules! emit_diag { ($lint:tt) => {{ - tcx.emit_diag_node_span_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count }); + tcx.emit_node_span_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count }); }}; } @@ -924,7 +924,7 @@ fn report_unreachable_pattern<'p, 'tcx>( lint.covered_by_many = Some(multispan); } } - cx.tcx.emit_diag_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint); + cx.tcx.emit_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint); } /// Detect typos that were meant to be a `const` but were interpreted as a new pattern binding. diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs index baefeaa730479..cac6308617acf 100644 --- a/compiler/rustc_mir_transform/src/check_call_recursion.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -83,7 +83,7 @@ fn check_recursion<'tcx>( let sp = tcx.def_span(def_id); let hir_id = tcx.local_def_id_to_hir_id(def_id); - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( UNCONDITIONAL_RECURSION, hir_id, sp, diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 20daa9179930d..375db17fb73a0 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -104,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { && let Some((lint_root, span, item)) = self.should_lint_const_item_usage(lhs, def_id, loc) { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( CONST_ITEM_MUTATION, lint_root, span, @@ -150,7 +150,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { if let Some((lint_root, span, item)) = self.should_lint_const_item_usage(place, def_id, lint_loc) { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( CONST_ITEM_MUTATION, lint_root, span, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 3d4e201a8f17b..c83b10a5e583a 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1990,7 +1990,7 @@ fn check_must_not_suspend_def( if let Some(reason_str) = find_attr!(tcx, def_id, MustNotSupend {reason} => reason) { let reason = reason_str.map(|s| errors::MustNotSuspendReason { span: data.source_span, reason: s }); - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( rustc_session::lint::builtin::MUST_NOT_SUSPEND, hir_id, data.source_span, diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 2314864e17d52..06e7bf974b515 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -63,7 +63,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { .lint_root; let span = terminator.source_info.span; - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( FFI_UNWIND_CALLS, lint_root, span, @@ -115,7 +115,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { let span = terminator.source_info.span; let foreign = fn_def_id.is_some(); - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( FFI_UNWIND_CALLS, lint_root, span, diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 7b35c18773fac..2ae8f43cf6c81 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -175,7 +175,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { ret, ); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( FUNCTION_ITEM_REFERENCES, lint_root, span, diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 9c3b67d43abf3..873f6a01ec360 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -297,7 +297,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let source_info = self.body.source_info(location); if let Some(lint_root) = self.lint_root(*source_info) { let span = source_info.span; - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint_kind.lint(), lint_root, span, diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 17bd630be2d88..667a702e40565 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -451,7 +451,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< } let span = local_labels[0].span; - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( lint::builtin::TAIL_EXPR_DROP_ORDER, lint_root.unwrap_or(CRATE_HIR_ID), span, diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 0817022d5642b..3fbe1e398a181 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -968,7 +968,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { let typo = maybe_suggest_typo(); errors::UnusedVariableSugg::TryPrefix { spans: vec![def_span], name, typo } }; - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( lint::builtin::UNUSED_VARIABLES, hir_id, def_span, @@ -1018,7 +1018,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { } let typo = maybe_suggest_typo(); - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( lint::builtin::UNUSED_VARIABLES, hir_id, def_span, @@ -1060,7 +1060,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { errors::UnusedVariableSugg::TryPrefix { name, typo, spans: vec![def_span] } }; - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( lint::builtin::UNUSED_VARIABLES, hir_id, spans, @@ -1126,20 +1126,20 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> { source_info.span, self.body, ); - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( lint::builtin::UNUSED_ASSIGNMENTS, hir_id, source_info.span, errors::UnusedAssign { name, help: suggestion.is_none(), suggestion }, ) } - AccessKind::Param => tcx.emit_diag_node_span_lint( + AccessKind::Param => tcx.emit_node_span_lint( lint::builtin::UNUSED_ASSIGNMENTS, hir_id, source_info.span, errors::UnusedAssignPassed { name }, ), - AccessKind::Capture => tcx.emit_diag_node_span_lint( + AccessKind::Capture => tcx.emit_node_span_lint( lint::builtin::UNUSED_ASSIGNMENTS, hir_id, decl_span, diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs index 12aa918513834..a8f3104c0d98d 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs @@ -174,7 +174,7 @@ impl<'tcx> MoveCheckVisitor<'tcx> { } } - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( LARGE_ASSIGNMENTS, lint_root, reported_span, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 27cfc7cb1a0e4..d3a39909077b0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -453,7 +453,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .span_until_char(attr_span, '[') .shrink_to_hi(); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -464,7 +464,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }, ) } - ast::AttrStyle::Inner => self.tcx.emit_diag_node_span_lint( + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span, @@ -595,7 +595,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if _impl.of_trait.is_none() ) { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, @@ -613,7 +613,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { directive: Option<&Directive>, ) { if !matches!(target, Target::Trait) { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, @@ -639,7 +639,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } }); if !has_generic { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, hir_id, span, @@ -668,7 +668,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ItemLike::Item(it) => match it.expect_impl().constness { Constness::Const => { let item_span = self.tcx.hir_span(hir_id); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, @@ -682,7 +682,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } let item_span = self.tcx.hir_span(hir_id); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, hir_id, attr_span, @@ -707,7 +707,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let attrs = self.tcx.codegen_fn_attrs(did); // Not checking naked as `#[inline]` is forbidden for naked functions anyways. if attrs.contains_extern_indicator() { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, @@ -1058,7 +1058,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Use | Target::ExternCrate => {} _ => { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, span, @@ -1073,7 +1073,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_doc_masked(&self, span: Span, hir_id: HirId, target: Target) { if target != Target::ExternCrate { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, span, @@ -1086,7 +1086,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } if self.tcx.extern_mod_stmt_cnum(hir_id.owner.def_id).is_none() { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, hir_id, span, @@ -1238,7 +1238,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, @@ -1475,7 +1475,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let ItemLike::Item(item) = item { is_c_like_enum(item) } else { false } })) { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( CONFLICTING_REPR_HINTS, hir_id, hint_spans.collect::>(), @@ -1571,7 +1571,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id)) == DefKind::Impl { of_trait: true } => { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, @@ -1592,7 +1592,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let is_decl_macro = !macro_definition.macro_rules; if is_decl_macro { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, @@ -1644,7 +1644,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .span_until_char(attr_span, '[') .shrink_to_hi(); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, @@ -1655,7 +1655,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }, ) } - Some(ast::AttrStyle::Inner) | None => self.tcx.emit_diag_node_span_lint( + Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span(), @@ -1681,7 +1681,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; }; - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr.span(), @@ -1849,7 +1849,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { "#[export_name]" }; - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::UNUSED_ATTRIBUTES, hir_id, no_mangle_span, @@ -2193,7 +2193,7 @@ fn check_duplicates( } else { (attr_span, *entry.get()) }; - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, this, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 0f5dd1ceda5b4..f6d00f5342f27 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -232,7 +232,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && !assign.span.from_expansion() { let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::DEAD_CODE, assign.hir_id, assign.span, @@ -1104,7 +1104,7 @@ impl<'tcx> DeadVisitor<'tcx> { }; let hir_id = tcx.local_def_id_to_hir_id(first_item.def_id); - self.tcx.emit_diag_node_span_lint(DEAD_CODE, hir_id, MultiSpan::from_spans(spans), diag); + self.tcx.emit_node_span_lint(DEAD_CODE, hir_id, MultiSpan::from_spans(spans), diag); } fn warn_multiple( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 927eb04cb55e3..6fd28c78740cd 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -642,7 +642,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { && c.fully_stable && !unstable_feature_bound_in_effect { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id(), span, @@ -859,7 +859,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { note: Some(deprecation), since_kind: lint::DeprecatedSinceKind::InEffect, }; - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( DEPRECATED, id, method_span.unwrap_or(path.span), @@ -1130,7 +1130,7 @@ fn unnecessary_partially_stable_feature_lint( implies: Symbol, since: Symbol, ) { - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, @@ -1153,7 +1153,7 @@ fn unnecessary_stable_feature_lint( if since.as_str() == VERSION_PLACEHOLDER { since = sym::env_CFG_RELEASE; } - tcx.emit_diag_node_span_lint( + tcx.emit_node_span_lint( lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index 314d3e60f2a41..3da744dc8c029 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -74,7 +74,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>( // is not exhaustive enough. // // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. - rcx.tcx.emit_diag_node_span_lint( + rcx.tcx.emit_node_span_lint( NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level, rcx.scrut_span, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 2804a807b9939..dc38f2d8bc70f 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -948,7 +948,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { .map(|span| errors::Overlap { range: overlap_as_pat.to_string(), span }) .collect(); let pat_span = pat.data().span; - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, self.match_lint_level, pat_span, @@ -984,7 +984,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { let gap_as_pat = self.print_pat_range(&gap, *pat.ty()); if gapped_with.is_empty() { // If `gapped_with` is empty, `gap == T::MAX`. - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS, self.match_lint_level, thir_pat.span, @@ -998,7 +998,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { }, ); } else { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::NON_CONTIGUOUS_RANGE_ENDPOINTS, self.match_lint_level, thir_pat.span, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 87b128779737b..59fd908756b02 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1416,7 +1416,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn check_def_id(&self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { if self.leaks_private_dep(def_id) { - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES, self.tcx.local_def_id_to_hir_id(self.item_def_id), self.tcx.def_span(self.item_def_id.to_def_id()), @@ -1475,7 +1475,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; let span = self.tcx.def_span(self.item_def_id.to_def_id()); let vis_span = self.tcx.def_span(def_id); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint, self.tcx.local_def_id_to_hir_id(self.item_def_id), span, @@ -1565,7 +1565,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis { let hir_id = self.tcx.local_def_id_to_hir_id(def_id); let span = self.tcx.def_span(def_id.to_def_id()); - self.tcx.emit_diag_node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::UNNAMEABLE_TYPES, hir_id, span, From 8fa1fca9f6e0f903ed4e90f5b131433b992d8495 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 24 Feb 2026 17:42:44 +0100 Subject: [PATCH 23/25] Apply new change from `lint_level` into `diag_lint_level` --- compiler/rustc_middle/src/lint.rs | 36 ++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 28ca6f9fcac20..08ccc4a0fca41 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -550,17 +550,6 @@ pub fn diag_lint_level<'a, D: Diagnostic<'a, ()> + 'a>( Level::Warn => rustc_errors::Level::Warning, Level::Deny | Level::Forbid => rustc_errors::Level::Error, }; - // Finally, run `decorate`. `decorate` can call `trimmed_path_str` (directly or indirectly), - // so we need to make sure when we do call `decorate` that the diagnostic is eventually - // emitted or we'll get a `must_produce_diag` ICE. - // - // When is a diagnostic *eventually* emitted? Well, that is determined by 2 factors: - // 1. If the corresponding `rustc_errors::Level` is beyond warning, i.e. `ForceWarning(_)` - // or `Error`, then the diagnostic will be emitted regardless of CLI options. - // 2. If the corresponding `rustc_errors::Level` is warning, then that can be affected by - // `-A warnings` or `--cap-lints=xxx` on the command line. In which case, the diagnostic - // will be emitted if `can_emit_warnings` is true. - let skip = err_level == rustc_errors::Level::Warning && !sess.dcx().can_emit_warnings(); let disable_suggestions = if let Some(ref span) = span // If this code originates in a foreign macro, aka something that this crate @@ -580,12 +569,35 @@ pub fn diag_lint_level<'a, D: Diagnostic<'a, ()> + 'a>( // allow individual lints to opt-out from being reported. let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none()); - if !incompatible && !lint.report_in_external_macro { + // In rustc, for the find_attr macro, we want to always emit this. + // This completely circumvents normal lint checking, which usually doesn't happen for macros from other crates. + // However, we kind of want that when using find_attr from another rustc crate. So we cheat a little. + let is_in_find_attr = sess.enable_internal_lints() + && span.as_ref().is_some_and(|span| { + span.primary_spans().iter().any(|s| { + s.source_callee().is_some_and(|i| { + matches!(i.kind, ExpnKind::Macro(_, name) if name.as_str() == "find_attr") + }) + }) + }); + + if !incompatible && !lint.report_in_external_macro && !is_in_find_attr { // Don't continue further, since we don't want to have // `diag_span_note_once` called for a diagnostic that isn't emitted. return; } } + // Finally, run `decorate`. `decorate` can call `trimmed_path_str` (directly or indirectly), + // so we need to make sure when we do call `decorate` that the diagnostic is eventually + // emitted or we'll get a `must_produce_diag` ICE. + // + // When is a diagnostic *eventually* emitted? Well, that is determined by 2 factors: + // 1. If the corresponding `rustc_errors::Level` is beyond warning, i.e. `ForceWarning(_)` + // or `Error`, then the diagnostic will be emitted regardless of CLI options. + // 2. If the corresponding `rustc_errors::Level` is warning, then that can be affected by + // `-A warnings` or `--cap-lints=xxx` on the command line. In which case, the diagnostic + // will be emitted if `can_emit_warnings` is true. + let skip = err_level == rustc_errors::Level::Warning && !sess.dcx().can_emit_warnings(); let mut err: Diag<'_, ()> = if !skip { decorate(sess.dcx(), err_level) From 8971ad85af554a2352865bf0e51d2cd16c519622 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 24 Feb 2026 12:22:20 +1100 Subject: [PATCH 24/25] Fix attribute parser and kind names. For the attribute `FooBar` the parser is generally called `FooBarParser` and the kind is called `AttributeKind::FooBar`. This commit renames some cases that don't match that pattern. The most common cases: - Adding `Rustc` to the front of the parser name for a `rustc_*` attribute. - Adding `Parser` to the end of a parser name. - Slight word variations, e.g. `Deprecation` instead of `Deprecated`, `Pointer` instead of `Ptr`, `Stability` instead of `Stable`. --- .../src/attributes/allow_unstable.rs | 4 +- .../src/attributes/codegen_attrs.rs | 14 ++--- .../src/attributes/deprecation.rs | 7 ++- .../src/attributes/dummy.rs | 4 +- .../src/attributes/link_attrs.rs | 4 +- .../src/attributes/lint_helpers.rs | 16 +++--- .../rustc_attr_parsing/src/attributes/repr.rs | 18 +++---- .../src/attributes/rustc_internal.rs | 18 +++---- .../src/attributes/stability.rs | 6 +-- .../src/attributes/traits.rs | 32 ++++++------ .../src/attributes/transparency.rs | 4 +- compiler/rustc_attr_parsing/src/context.rs | 52 +++++++++---------- .../rustc_codegen_ssa/src/codegen_attrs.rs | 4 +- compiler/rustc_expand/src/base.rs | 2 +- .../rustc_hir/src/attrs/data_structures.rs | 26 +++++----- .../rustc_hir/src/attrs/encode_cross_crate.rs | 10 ++-- compiler/rustc_hir/src/hir.rs | 4 +- .../rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_lint/src/ptr_nulls.rs | 4 +- compiler/rustc_passes/src/check_attr.rs | 10 ++-- compiler/rustc_passes/src/stability.rs | 12 ++--- src/librustdoc/json/conversions.rs | 2 +- .../passes/collect_intra_doc_links.rs | 4 +- tests/pretty/delegation-inherit-attributes.pp | 6 +-- tests/pretty/delegation-inline-attribute.pp | 8 +-- tests/ui-fulldeps/internal-lints/find_attr.rs | 2 +- .../internal-lints/find_attr.stderr | 4 +- tests/ui/unpretty/deprecated-attr.stdout | 12 ++--- 28 files changed, 145 insertions(+), 146 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 4f1a8cd8b403c..c2511ac75d5d2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -52,8 +52,8 @@ impl CombineAttributeParser for UnstableFeatureBoundParser { } } -pub(crate) struct AllowConstFnUnstableParser; -impl CombineAttributeParser for AllowConstFnUnstableParser { +pub(crate) struct RustcAllowConstFnUnstableParser; +impl CombineAttributeParser for RustcAllowConstFnUnstableParser { const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable]; type Item = Symbol; const CONVERT: ConvertFn = diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 485307622291e..4909e0d35173c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -153,9 +153,9 @@ impl SingleAttributeParser for ExportNameParser { } } -pub(crate) struct ObjcClassParser; +pub(crate) struct RustcObjcClassParser; -impl SingleAttributeParser for ObjcClassParser { +impl SingleAttributeParser for RustcObjcClassParser { const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; @@ -185,9 +185,9 @@ impl SingleAttributeParser for ObjcClassParser { } } -pub(crate) struct ObjcSelectorParser; +pub(crate) struct RustcObjcSelectorParser; -impl SingleAttributeParser for ObjcSelectorParser { +impl SingleAttributeParser for RustcObjcSelectorParser { const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; @@ -709,13 +709,13 @@ impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisPa const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis; } -pub(crate) struct EiiForeignItemParser; +pub(crate) struct RustcEiiForeignItemParser; -impl NoArgsAttributeParser for EiiForeignItemParser { +impl NoArgsAttributeParser for RustcEiiForeignItemParser { const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiForeignItem; + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem; } pub(crate) struct PatchableFunctionEntryParser; diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index c055c2936e953..a2c7e459e0df8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -7,8 +7,6 @@ use crate::session_diagnostics::{ DeprecatedItemSuggestion, InvalidSince, MissingNote, MissingSince, }; -pub(crate) struct DeprecationParser; - fn get( cx: &AcceptContext<'_, '_, S>, name: Symbol, @@ -33,7 +31,8 @@ fn get( } } -impl SingleAttributeParser for DeprecationParser { +pub(crate) struct DeprecatedParser; +impl SingleAttributeParser for DeprecatedParser { const PATH: &[Symbol] = &[sym::deprecated]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; @@ -164,7 +163,7 @@ impl SingleAttributeParser for DeprecationParser { return None; } - Some(AttributeKind::Deprecation { + Some(AttributeKind::Deprecated { deprecation: Deprecation { since, note, suggestion }, span: cx.attr_span, }) diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 9f97af48afa05..71d10b23a37f6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -7,8 +7,8 @@ use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::target_checking::{ALL_TARGETS, AllowedTargets}; -pub(crate) struct DummyParser; -impl SingleAttributeParser for DummyParser { +pub(crate) struct RustcDummyParser; +impl SingleAttributeParser for RustcDummyParser { const PATH: &[Symbol] = &[sym::rustc_dummy]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 21c05611ce292..c4a483157a19d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -524,8 +524,8 @@ impl NoArgsAttributeParser for FfiPureParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure; } -pub(crate) struct StdInternalSymbolParser; -impl NoArgsAttributeParser for StdInternalSymbolParser { +pub(crate) struct RustcStdInternalSymbolParser; +impl NoArgsAttributeParser for RustcStdInternalSymbolParser { const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 60e83a6083ede..76bddacd20bf4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -1,7 +1,7 @@ use super::prelude::*; -pub(crate) struct AsPtrParser; -impl NoArgsAttributeParser for AsPtrParser { +pub(crate) struct RustcAsPtrParser; +impl NoArgsAttributeParser for RustcAsPtrParser { const PATH: &[Symbol] = &[sym::rustc_as_ptr]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ @@ -14,8 +14,8 @@ impl NoArgsAttributeParser for AsPtrParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAsPtr; } -pub(crate) struct PubTransparentParser; -impl NoArgsAttributeParser for PubTransparentParser { +pub(crate) struct RustcPubTransparentParser; +impl NoArgsAttributeParser for RustcPubTransparentParser { const PATH: &[Symbol] = &[sym::rustc_pub_transparent]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ @@ -26,8 +26,8 @@ impl NoArgsAttributeParser for PubTransparentParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent; } -pub(crate) struct PassByValueParser; -impl NoArgsAttributeParser for PassByValueParser { +pub(crate) struct RustcPassByValueParser; +impl NoArgsAttributeParser for RustcPassByValueParser { const PATH: &[Symbol] = &[sym::rustc_pass_by_value]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ @@ -38,8 +38,8 @@ impl NoArgsAttributeParser for PassByValueParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassByValue; } -pub(crate) struct RustcShouldNotBeCalledOnConstItems; -impl NoArgsAttributeParser for RustcShouldNotBeCalledOnConstItems { +pub(crate) struct RustcShouldNotBeCalledOnConstItemsParser; +impl NoArgsAttributeParser for RustcShouldNotBeCalledOnConstItemsParser { const PATH: &[Symbol] = &[sym::rustc_should_not_be_called_on_const_items]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index fb0b8df652848..f0fc2a5b5e939 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -269,9 +269,9 @@ fn parse_alignment(node: &LitKind) -> Result { /// Parse #[align(N)]. #[derive(Default)] -pub(crate) struct AlignParser(Option<(Align, Span)>); +pub(crate) struct RustcAlignParser(Option<(Align, Span)>); -impl AlignParser { +impl RustcAlignParser { const PATH: &[Symbol] = &[sym::rustc_align]; const TEMPLATE: AttributeTemplate = template!(List: &[""]); @@ -308,7 +308,7 @@ impl AlignParser { } } -impl AttributeParser for AlignParser { +impl AttributeParser for RustcAlignParser { const ATTRIBUTES: AcceptMapping = &[(Self::PATH, Self::TEMPLATE, Self::parse)]; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), @@ -321,29 +321,29 @@ impl AttributeParser for AlignParser { fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { let (align, span) = self.0?; - Some(AttributeKind::Align { align, span }) + Some(AttributeKind::RustcAlign { align, span }) } } #[derive(Default)] -pub(crate) struct AlignStaticParser(AlignParser); +pub(crate) struct RustcAlignStaticParser(RustcAlignParser); -impl AlignStaticParser { +impl RustcAlignStaticParser { const PATH: &[Symbol] = &[sym::rustc_align_static]; - const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; + const TEMPLATE: AttributeTemplate = RustcAlignParser::TEMPLATE; fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { self.0.parse(cx, args) } } -impl AttributeParser for AlignStaticParser { +impl AttributeParser for RustcAlignStaticParser { const ATTRIBUTES: AcceptMapping = &[(Self::PATH, Self::TEMPLATE, Self::parse)]; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { let (align, span) = self.0.0?; - Some(AttributeKind::Align { align, span }) + Some(AttributeKind::RustcAlign { align, span }) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index c18e292027517..85e7112adbc21 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -71,9 +71,9 @@ impl SingleAttributeParser for RustcMustImplementOneOfParser { } } -pub(crate) struct RustcNeverReturnsNullPointerParser; +pub(crate) struct RustcNeverReturnsNullPtrParser; -impl NoArgsAttributeParser for RustcNeverReturnsNullPointerParser { +impl NoArgsAttributeParser for RustcNeverReturnsNullPtrParser { const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ @@ -83,7 +83,7 @@ impl NoArgsAttributeParser for RustcNeverReturnsNullPointerParser { Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), ]); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPointer; + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPtr; } pub(crate) struct RustcNoImplicitAutorefsParser; @@ -1215,9 +1215,10 @@ impl NoArgsAttributeParser for RustcNonnullOptimizationGuaranteedPa const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonnullOptimizationGuaranteed; } -pub(crate) struct RustcSymbolName; +pub(crate) struct RustcSymbolNameParser; -impl SingleAttributeParser for RustcSymbolName { +impl SingleAttributeParser for RustcSymbolNameParser { + const PATH: &[Symbol] = &[sym::rustc_symbol_name]; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::TraitImpl)), @@ -1228,7 +1229,6 @@ impl SingleAttributeParser for RustcSymbolName { Allow(Target::Impl { of_trait: false }), ]); const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const PATH: &[Symbol] = &[sym::rustc_symbol_name]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { @@ -1240,9 +1240,10 @@ impl SingleAttributeParser for RustcSymbolName { } } -pub(crate) struct RustcDefPath; +pub(crate) struct RustcDefPathParser; -impl SingleAttributeParser for RustcDefPath { +impl SingleAttributeParser for RustcDefPathParser { + const PATH: &[Symbol] = &[sym::rustc_def_path]; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::TraitImpl)), @@ -1253,7 +1254,6 @@ impl SingleAttributeParser for RustcDefPath { Allow(Target::Impl { of_trait: false }), ]); const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const PATH: &[Symbol] = &[sym::rustc_def_path]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index a2be2d42b3e1a..941885d232c27 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -177,15 +177,15 @@ impl AttributeParser for BodyStabilityParser { } } -pub(crate) struct ConstStabilityIndirectParser; -impl NoArgsAttributeParser for ConstStabilityIndirectParser { +pub(crate) struct RustcConstStableIndirectParser; +impl NoArgsAttributeParser for RustcConstStableIndirectParser { const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), ]); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConstStabilityIndirect; + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConstStableIndirect; } #[derive(Default)] diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index ceaa43948d676..c09e151fc70c1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -9,8 +9,8 @@ use crate::parser::ArgParser; use crate::target_checking::Policy::{Allow, Warn}; use crate::target_checking::{ALL_TARGETS, AllowedTargets}; -pub(crate) struct SkipDuringMethodDispatchParser; -impl SingleAttributeParser for SkipDuringMethodDispatchParser { +pub(crate) struct RustcSkipDuringMethodDispatchParser; +impl SingleAttributeParser for RustcSkipDuringMethodDispatchParser { const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; @@ -58,8 +58,8 @@ impl SingleAttributeParser for SkipDuringMethodDispatchParser { } } -pub(crate) struct ParenSugarParser; -impl NoArgsAttributeParser for ParenSugarParser { +pub(crate) struct RustcParenSugarParser; +impl NoArgsAttributeParser for RustcParenSugarParser { const PATH: &[Symbol] = &[sym::rustc_paren_sugar]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); @@ -81,16 +81,16 @@ impl NoArgsAttributeParser for MarkerParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::Marker; } -pub(crate) struct DenyExplicitImplParser; -impl NoArgsAttributeParser for DenyExplicitImplParser { +pub(crate) struct RustcDenyExplicitImplParser; +impl NoArgsAttributeParser for RustcDenyExplicitImplParser { const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDenyExplicitImpl; } -pub(crate) struct DynIncompatibleTraitParser; -impl NoArgsAttributeParser for DynIncompatibleTraitParser { +pub(crate) struct RustcDynIncompatibleTraitParser; +impl NoArgsAttributeParser for RustcDynIncompatibleTraitParser { const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); @@ -99,16 +99,16 @@ impl NoArgsAttributeParser for DynIncompatibleTraitParser { // Specialization -pub(crate) struct SpecializationTraitParser; -impl NoArgsAttributeParser for SpecializationTraitParser { +pub(crate) struct RustcSpecializationTraitParser; +impl NoArgsAttributeParser for RustcSpecializationTraitParser { const PATH: &[Symbol] = &[sym::rustc_specialization_trait]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcSpecializationTrait; } -pub(crate) struct UnsafeSpecializationMarkerParser; -impl NoArgsAttributeParser for UnsafeSpecializationMarkerParser { +pub(crate) struct RustcUnsafeSpecializationMarkerParser; +impl NoArgsAttributeParser for RustcUnsafeSpecializationMarkerParser { const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); @@ -117,16 +117,16 @@ impl NoArgsAttributeParser for UnsafeSpecializationMarkerParser { // Coherence -pub(crate) struct CoinductiveParser; -impl NoArgsAttributeParser for CoinductiveParser { +pub(crate) struct RustcCoinductiveParser; +impl NoArgsAttributeParser for RustcCoinductiveParser { const PATH: &[Symbol] = &[sym::rustc_coinductive]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoinductive; } -pub(crate) struct AllowIncoherentImplParser; -impl NoArgsAttributeParser for AllowIncoherentImplParser { +pub(crate) struct RustcAllowIncoherentImplParser; +impl NoArgsAttributeParser for RustcAllowIncoherentImplParser { const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 7fa4487b7c691..58b4a0b2fb1ad 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -2,9 +2,9 @@ use rustc_span::hygiene::Transparency; use super::prelude::*; -pub(crate) struct TransparencyParser; +pub(crate) struct RustcMacroTransparencyParser; -impl SingleAttributeParser for TransparencyParser { +impl SingleAttributeParser for RustcMacroTransparencyParser { const PATH: &[Symbol] = &[sym::rustc_macro_transparency]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 2cb5e6d8f6149..b82607e7c450d 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -141,8 +141,6 @@ macro_rules! attribute_parsers { attribute_parsers!( pub(crate) static ATTRIBUTE_PARSERS = [ // tidy-alphabetical-start - AlignParser, - AlignStaticParser, BodyStabilityParser, ConfusablesParser, ConstStabilityParser, @@ -151,13 +149,14 @@ attribute_parsers!( NakedParser, OnConstParser, OnUnimplementedParser, + RustcAlignParser, + RustcAlignStaticParser, RustcCguTestAttributeParser, StabilityParser, UsedParser, // tidy-alphabetical-end // tidy-alphabetical-start - Combine, Combine, Combine, Combine, @@ -166,6 +165,7 @@ attribute_parsers!( Combine, Combine, Combine, + Combine, Combine, Combine, Combine, @@ -180,9 +180,8 @@ attribute_parsers!( Single, Single, Single, - Single, + Single, Single, - Single, Single, Single, Single, @@ -196,8 +195,6 @@ attribute_parsers!( Single, Single, Single, - Single, - Single, Single, Single, Single, @@ -208,44 +205,40 @@ attribute_parsers!( Single, Single, Single, - Single, + Single, Single, Single, Single, + Single, Single, Single, Single, Single, Single, Single, + Single, Single, Single, + Single, + Single, Single, Single, Single, - Single, + Single, + Single, Single, Single, Single, - Single, Single, - Single, Single, Single, - Single>, Single>, - Single>, Single>, - Single>, Single>, Single>, Single>, - Single>, Single>, Single>, - Single>, - Single>, - Single>, Single>, Single>, Single>, @@ -266,29 +259,33 @@ attribute_parsers!( Single>, Single>, Single>, - Single>, - Single>, Single>, Single>, Single>, Single>, Single>, Single>, - Single>, Single>, Single>, + Single>, + Single>, Single>, Single>, + Single>, + Single>, Single>, Single>, Single>, + Single>, Single>, Single>, Single>, Single>, Single>, Single>, + Single>, Single>, + Single>, Single>, Single>, Single>, @@ -300,7 +297,7 @@ attribute_parsers!( Single>, Single>, Single>, - Single>, + Single>, Single>, Single>, Single>, @@ -310,21 +307,24 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, + Single>, Single>, Single>, Single>, + Single>, Single>, Single>, - Single>, + Single>, + Single>, + Single>, Single>, Single>, + Single>, Single>, Single>, - Single>, - Single>, Single>, Single>, - Single>, // tidy-alphabetical-end ]; ); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 6b0d46f5dc5d1..43f039cc5ebfd 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -80,7 +80,7 @@ fn process_builtin_attrs( interesting_spans.inline = Some(*span); } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, - AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), + AttributeKind::RustcAlign { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::LinkName { name, .. } => { // FIXME Remove check for foreign functions once #[link_name] on non-foreign // functions is a hard error @@ -223,7 +223,7 @@ fn process_builtin_attrs( AttributeKind::RustcObjcSelector { methname, .. } => { codegen_fn_attrs.objc_selector = Some(*methname); } - AttributeKind::EiiForeignItem => { + AttributeKind::RustcEiiForeignItem => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::EXTERNALLY_IMPLEMENTABLE_ITEM; } AttributeKind::EiiImpls(impls) => { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index ae3022b83e564..225906dfba2de 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -974,7 +974,7 @@ impl SyntaxExtension { stability, deprecation: find_attr!( attrs, - Deprecation { deprecation, .. } => *deprecation + Deprecated { deprecation, .. } => *deprecation ), helper_attrs, edition, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index f9cb557d020dd..68f5bb94c3fe8 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -846,13 +846,6 @@ pub struct RustcCleanQueries { #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub enum AttributeKind { // tidy-alphabetical-start - /// Represents `#[align(N)]`. - // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity - Align { - align: Align, - span: Span, - }, - /// Represents `#[allow_internal_unsafe]`. AllowInternalUnsafe(Span), @@ -911,7 +904,7 @@ pub enum AttributeKind { DefaultLibAllocator, /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute). - Deprecation { + Deprecated { deprecation: Deprecation, span: Span, }, @@ -938,9 +931,6 @@ pub enum AttributeKind { /// Implementation detail of `#[eii]` EiiDeclaration(EiiDecl), - /// Implementation detail of `#[eii]` - EiiForeignItem, - /// Implementation detail of `#[eii]` EiiImpls(ThinVec), @@ -1169,6 +1159,13 @@ pub enum AttributeKind { kind: RustcAbiAttrKind, }, + /// Represents `#[align(N)]`. + // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity + RustcAlign { + align: Align, + span: Span, + }, + /// Represents `#[rustc_allocator]` RustcAllocator, @@ -1230,7 +1227,7 @@ pub enum AttributeKind { }, /// Represents `#[rustc_const_stable_indirect]`. - RustcConstStabilityIndirect, + RustcConstStableIndirect, /// Represents `#[rustc_conversion_suggestion]` RustcConversionSuggestion, @@ -1284,6 +1281,9 @@ pub enum AttributeKind { /// Represents `#[rustc_effective_visibility]`. RustcEffectiveVisibility, + /// Implementation detail of `#[eii]` + RustcEiiForeignItem, + /// Represents `#[rustc_evaluate_where_clauses]` RustcEvaluateWhereClauses, @@ -1352,7 +1352,7 @@ pub enum AttributeKind { }, /// Represents `#[rustc_never_returns_null_ptr]` - RustcNeverReturnsNullPointer, + RustcNeverReturnsNullPtr, /// Represents `#[rustc_never_type_options]`. RustcNeverTypeOptions { diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 1743eef1d8f2c..c50d38b6d673a 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -18,7 +18,6 @@ impl AttributeKind { match self { // tidy-alphabetical-start - Align { .. } => No, AllowInternalUnsafe(..) => Yes, AllowInternalUnstable(..) => Yes, AutomaticallyDerived(..) => Yes, @@ -36,12 +35,11 @@ impl AttributeKind { CustomMir(_, _, _) => Yes, DebuggerVisualizer(..) => No, DefaultLibAllocator => No, - Deprecation { .. } => Yes, + Deprecated { .. } => Yes, DoNotRecommend { .. } => Yes, Doc(_) => Yes, DocComment { .. } => Yes, EiiDeclaration(_) => Yes, - EiiForeignItem => No, EiiImpls(..) => No, ExportName { .. } => Yes, ExportStable => No, @@ -97,6 +95,7 @@ impl AttributeKind { RegisterTool(..) => No, Repr { .. } => No, RustcAbi { .. } => No, + RustcAlign { .. } => No, RustcAllocator => No, RustcAllocatorZeroed => No, RustcAllocatorZeroedVariant { .. } => Yes, @@ -112,7 +111,7 @@ impl AttributeKind { RustcCoinductive(..) => No, RustcConfusables { .. } => Yes, RustcConstStability { .. } => Yes, - RustcConstStabilityIndirect => No, + RustcConstStableIndirect => No, RustcConversionSuggestion => Yes, RustcDeallocator => No, RustcDefPath(..) => No, @@ -130,6 +129,7 @@ impl AttributeKind { RustcDumpVtable(..) => No, RustcDynIncompatibleTrait(..) => No, RustcEffectiveVisibility => Yes, + RustcEiiForeignItem => No, RustcEvaluateWhereClauses => Yes, RustcHasIncoherentInherentImpls => Yes, RustcHiddenTypeOfOpaques => No, @@ -150,7 +150,7 @@ impl AttributeKind { RustcMain => No, RustcMir(..) => Yes, RustcMustImplementOneOf { .. } => No, - RustcNeverReturnsNullPointer => Yes, + RustcNeverReturnsNullPtr => Yes, RustcNeverTypeOptions { .. } => No, RustcNoImplicitAutorefs => Yes, RustcNoImplicitBounds => No, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 960fd206041a8..373d61978439e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1378,7 +1378,7 @@ impl AttributeExt for Attribute { Attribute::Unparsed(u) => u.span, // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, - Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, + Attribute::Parsed(AttributeKind::Deprecated { span, .. }) => *span, Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) => cfgs[0].1, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } @@ -1420,7 +1420,7 @@ impl AttributeExt for Attribute { #[inline] fn deprecation_note(&self) -> Option { match &self { - Attribute::Parsed(AttributeKind::Deprecation { deprecation, .. }) => deprecation.note, + Attribute::Parsed(AttributeKind::Deprecated { deprecation, .. }) => deprecation.note, _ => None, } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a6a1b95ce4c1a..621e91525ade3 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -977,7 +977,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), (0, _) => ("const", "consts", None), _ => ("type or const", "types or consts", None), }; - let name = if find_attr!(tcx, def_id, EiiForeignItem) { + let name = if find_attr!(tcx, def_id, RustcEiiForeignItem) { "externally implementable items" } else { "foreign items" diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 18a80684fa44e..1e1bbf51fcb9b 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -72,14 +72,14 @@ fn useless_check<'a, 'tcx: 'a>( e = e.peel_blocks(); if let ExprKind::MethodCall(_, _expr, [], _) = e.kind && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) - && find_attr!(cx.tcx, def_id, RustcNeverReturnsNullPointer) + && find_attr!(cx.tcx, def_id, RustcNeverReturnsNullPtr) && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { return Some(UselessPtrNullChecksDiag::FnRet { fn_name }); } else if let ExprKind::Call(path, _args) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() - && find_attr!(cx.tcx, def_id, RustcNeverReturnsNullPointer) + && find_attr!(cx.tcx, def_id, RustcNeverReturnsNullPtr) && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { return Some(UselessPtrNullChecksDiag::FnRet { fn_name }); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index b3dc48ea62f7f..89fbb9fd86681 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -179,7 +179,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::RustcAllowConstFnUnstable(_, first_span)) => { self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target) } - Attribute::Parsed(AttributeKind::Deprecation {span: attr_span, .. }) => { + Attribute::Parsed(AttributeKind::Deprecated { span: attr_span, .. }) => { self.check_deprecated(hir_id, *attr_span, target) } Attribute::Parsed(AttributeKind::TargetFeature{ attr_span, ..}) => { @@ -191,7 +191,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::RustcPubTransparent(attr_span)) => { self.check_rustc_pub_transparent(attr_span, span, attrs) } - Attribute::Parsed(AttributeKind::Align { align, span: attr_span }) => { + Attribute::Parsed(AttributeKind::RustcAlign { align, span: attr_span }) => { self.check_align(*align, *attr_span) } Attribute::Parsed(AttributeKind::Naked(..)) => { @@ -253,7 +253,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // `#[doc]` is actually a lot more than just doc comments, so is checked below | AttributeKind::DocComment {..} | AttributeKind::EiiDeclaration { .. } - | AttributeKind::EiiForeignItem | AttributeKind::ExportName { .. } | AttributeKind::ExportStable | AttributeKind::Feature(..) @@ -308,7 +307,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcCoherenceIsCore(..) | AttributeKind::RustcCoinductive(..) | AttributeKind::RustcConfusables { .. } - | AttributeKind::RustcConstStabilityIndirect + | AttributeKind::RustcConstStableIndirect | AttributeKind::RustcConversionSuggestion | AttributeKind::RustcDeallocator | AttributeKind::RustcDefPath(..) @@ -326,6 +325,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDumpVtable(..) | AttributeKind::RustcDynIncompatibleTrait(..) | AttributeKind::RustcEffectiveVisibility + | AttributeKind::RustcEiiForeignItem | AttributeKind::RustcEvaluateWhereClauses | AttributeKind::RustcHasIncoherentInherentImpls | AttributeKind::RustcHiddenTypeOfOpaques @@ -344,7 +344,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcMacroTransparency(_) | AttributeKind::RustcMain | AttributeKind::RustcMir(_) - | AttributeKind::RustcNeverReturnsNullPointer + | AttributeKind::RustcNeverReturnsNullPtr | AttributeKind::RustcNeverTypeOptions {..} | AttributeKind::RustcNoImplicitAutorefs | AttributeKind::RustcNoImplicitBounds diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6fd28c78740cd..97d09e39b08b8 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -97,7 +97,7 @@ fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind { fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { let depr = find_attr!(tcx, def_id, - Deprecation { deprecation, span: _ } => *deprecation + Deprecated { deprecation, span: _ } => *deprecation ); let Some(depr) = depr else { @@ -209,22 +209,22 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option *stability); // After checking the immediate attributes, get rid of the span and compute implied // const stability: inherit feature gate from regular stability. let mut const_stab = const_stab - .map(|const_stab| ConstStability::from_partial(const_stab, const_stability_indirect)); + .map(|const_stab| ConstStability::from_partial(const_stab, const_stable_indirect)); // If this is a const fn but not annotated with stability markers, see if we can inherit // regular stability. @@ -335,7 +335,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { if stab.is_none() && depr.map_or(false, |d| d.attr.is_since_rustc_version()) - && let Some(span) = find_attr_span!(Deprecation) + && let Some(span) = find_attr_span!(Deprecated) { self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span }); } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 599d7b10005d9..c42ea8bf1e2d1 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -916,7 +916,7 @@ fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>) }; vec![match kind { - AK::Deprecation { .. } => return Vec::new(), // Handled separately into Item::deprecation. + AK::Deprecated { .. } => return Vec::new(), // Handled separately into Item::deprecation. AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), AK::MacroExport { .. } => Attribute::MacroExport, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1da191c903871..47a92be3ec6ef 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1109,7 +1109,7 @@ impl LinkCollector<'_, '_> { // Also resolve links in the note text of `#[deprecated]`. for attr in &item.attrs.other_attrs { - let Attribute::Parsed(AttributeKind::Deprecation { span: depr_span, deprecation }) = + let Attribute::Parsed(AttributeKind::Deprecated { span: depr_span, deprecation }) = attr else { continue; @@ -1127,7 +1127,7 @@ impl LinkCollector<'_, '_> { // inlined item. // let item_id = if let Some(inline_stmt_id) = item.inline_stmt_id - && find_attr!(tcx, inline_stmt_id, Deprecation {span, ..} if span == depr_span) + && find_attr!(tcx, inline_stmt_id, Deprecated { span, ..} if span == depr_span) { inline_stmt_id.to_def_id() } else { diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp index bfe5ba03c37d4..72493f557dfc2 100644 --- a/tests/pretty/delegation-inherit-attributes.pp +++ b/tests/pretty/delegation-inherit-attributes.pp @@ -22,11 +22,11 @@ fn foo_no_reason(x: usize) -> usize { x } #[attr = Cold] - #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] fn bar(x: usize) -> usize { x } } -#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] +#[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] #[attr = MustUse {reason: "foo: some reason"}] #[attr = Inline(Hint)] fn foo1(arg0: _) -> _ { to_reuse::foo(self + 1) } @@ -35,7 +35,7 @@ #[attr = Inline(Hint)] fn foo_no_reason(arg0: _) -> _ { to_reuse::foo_no_reason(self + 1) } -#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] +#[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] #[attr = MustUse {reason: "some reason"}] #[attr = Inline(Hint)] fn foo2(arg0: _) -> _ { to_reuse::foo(self + 1) } diff --git a/tests/pretty/delegation-inline-attribute.pp b/tests/pretty/delegation-inline-attribute.pp index 54442a210d937..125ed1c298262 100644 --- a/tests/pretty/delegation-inline-attribute.pp +++ b/tests/pretty/delegation-inline-attribute.pp @@ -46,7 +46,7 @@ // Check that #[inline(hint)] is added when other attributes present in inner reuse #[attr = Cold] #[attr = MustUse] - #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] #[attr = Inline(Hint)] fn foo1(arg0: _) -> _ { to_reuse::foo(self / 2) } @@ -62,7 +62,7 @@ #[attr = Cold] #[attr = MustUse] #[attr = Inline(Never)] - #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] fn foo4(arg0: _) -> _ { to_reuse::foo(self / 2) } }.foo() } @@ -70,7 +70,7 @@ // Check that #[inline(hint)] is added when there are other attributes present in trait reuse #[attr = Cold] #[attr = MustUse] - #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] #[attr = Inline(Hint)] fn foo1(self: _) -> _ { self.0.foo1() } @@ -86,7 +86,7 @@ #[attr = Cold] #[attr = MustUse] #[attr = Inline(Never)] - #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] fn foo4(self: _) -> _ { self.0.foo4() } } diff --git a/tests/ui-fulldeps/internal-lints/find_attr.rs b/tests/ui-fulldeps/internal-lints/find_attr.rs index bb0c8c486bcdb..90b9b96ba54ef 100644 --- a/tests/ui-fulldeps/internal-lints/find_attr.rs +++ b/tests/ui-fulldeps/internal-lints/find_attr.rs @@ -13,7 +13,7 @@ fn main() { find_attr!(attrs, AttributeKind::Inline(..)); //~^ ERROR use of `AttributeKind` in `find_attr!(...)` invocation - find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecation {..}); + find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecated {..}); //~^ ERROR use of `AttributeKind` in `find_attr!(...)` invocation //~| ERROR use of `AttributeKind` in `find_attr!(...)` invocation diff --git a/tests/ui-fulldeps/internal-lints/find_attr.stderr b/tests/ui-fulldeps/internal-lints/find_attr.stderr index b7291ecbb84d9..8cb1003b0aa1e 100644 --- a/tests/ui-fulldeps/internal-lints/find_attr.stderr +++ b/tests/ui-fulldeps/internal-lints/find_attr.stderr @@ -15,7 +15,7 @@ LL | #![deny(rustc::bad_use_of_find_attr)] error: use of `AttributeKind` in `find_attr!(...)` invocation --> $DIR/find_attr.rs:16:23 | -LL | find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecation {..}); +LL | find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecated {..}); | ^^^^^^^^^^^^^ | = note: `find_attr!(...)` already imports `AttributeKind::*` @@ -24,7 +24,7 @@ LL | find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecatio error: use of `AttributeKind` in `find_attr!(...)` invocation --> $DIR/find_attr.rs:16:51 | -LL | find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecation {..}); +LL | find_attr!(attrs, AttributeKind::Inline{..} | AttributeKind::Deprecated {..}); | ^^^^^^^^^^^^^ | = note: `find_attr!(...)` already imports `AttributeKind::*` diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout index 32d5cf06a3d67..4ba5b0b366df9 100644 --- a/tests/ui/unpretty/deprecated-attr.stdout +++ b/tests/ui/unpretty/deprecated-attr.stdout @@ -5,28 +5,28 @@ use ::std::prelude::rust_2015::*; //@ check-pass //@ edition: 2015 -#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] +#[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] struct PlainDeprecated; -#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, +#[attr = Deprecated {deprecation: Deprecation {since: Unspecified, note: here's why this is deprecated#0}}] struct DirectNote; -#[attr = Deprecation {deprecation: Deprecation {since: Unspecified, +#[attr = Deprecated {deprecation: Deprecation {since: Unspecified, note: here's why this is deprecated#0}}] struct ExplicitNote; -#[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), +#[attr = Deprecated {deprecation: Deprecation {since: NonStandard("1.2.3"), note: here's why this is deprecated#0}}] struct SinceAndNote; -#[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"), +#[attr = Deprecated {deprecation: Deprecation {since: NonStandard("1.2.3"), note: here's why this is deprecated#0}}] struct FlippedOrder; fn f() { // Attribute is ignored here (with a warning), but still preserved in HIR - #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Deprecated {deprecation: Deprecation {since: Unspecified}}] 0 } From f2f8743b4eec101b1100cb0b04ac1b0cb8e3bff8 Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Tue, 24 Feb 2026 16:58:07 -0500 Subject: [PATCH 25/25] Give a better error when updating a submodule fails Previously this would sometimes just say "unexpected output ``", which was extremely unhelpful. The actual issue was that I had a `.jj` directory but not a `.git` directory, so it couldn't run `git submodule update.` --- src/bootstrap/src/core/config/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index e975d71c8c70b..17f256188e1be 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2426,7 +2426,7 @@ pub(crate) fn update_submodule<'a>( let actual_hash = recorded .split_whitespace() .nth(2) - .unwrap_or_else(|| panic!("unexpected output `{recorded}`")); + .unwrap_or_else(|| panic!("unexpected output `{recorded}` when updating {relative_path}")); if actual_hash == checked_out_hash { // already checked out