From b11a76b9814081a056763e6b9943c6f620d7d966 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Tue, 23 Jun 2026 10:39:23 -0400 Subject: [PATCH 01/10] tests: modify s390x vector test to be robust to instruction scheduling A recent LLVM change causes some changes here, if I'm understanding correctly it allows some better latency reduction. From what I can tell, this test doesn't care that only a single register is used, so we use -DAG instead of -NEXT to allow some instruction reordering. By happy coincidence, the z10 and z13 code matches now, which collapsed some of the test lines. I'm happy to split them back out if that's bad for some reason though! --- tests/assembly-llvm/s390x-vector-abi.rs | 60 +++++++++---------------- 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/tests/assembly-llvm/s390x-vector-abi.rs b/tests/assembly-llvm/s390x-vector-abi.rs index 90139df17ca1a..c0f770c3f0c35 100644 --- a/tests/assembly-llvm/s390x-vector-abi.rs +++ b/tests/assembly-llvm/s390x-vector-abi.rs @@ -62,16 +62,11 @@ unsafe extern "C" fn vector_ret(x: &i8x16) -> i8x16 { *x } // CHECK-LABEL: vector_ret_large: -// z10: vl %v0, 16(%r3), 4 -// z10-NEXT: vl %v1, 0(%r3), 4 -// z10-NEXT: vst %v0, 16(%r2), 4 -// z10-NEXT: vst %v1, 0(%r2), 4 -// z10-NEXT: br %r14 -// z13: vl %v0, 0(%r3), 4 -// z13-NEXT: vl %v1, 16(%r3), 4 -// z13-NEXT: vst %v1, 16(%r2), 4 -// z13-NEXT: vst %v0, 0(%r2), 4 -// z13-NEXT: br %r14 +// CHECK-DAG: vl [[REG1:%v[0-9]+]], 16(%r3), 4 +// CHECK-DAG: vl [[REG2:%v[0-9]+]], 0(%r3), 4 +// CHECK-DAG: vst [[REG1]], 16(%r2), 4 +// CHECK-DAG: vst [[REG2]], 0(%r2), 4 +// CHECK: br %r14 #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_ret_large(x: &i8x32) -> i8x32 { @@ -95,16 +90,11 @@ unsafe extern "C" fn vector_wrapper_ret(x: &Wrapper) -> Wrapper { *x } // CHECK-LABEL: vector_wrapper_ret_large: -// z10: vl %v0, 16(%r3), 4 -// z10-NEXT: vl %v1, 0(%r3), 4 -// z10-NEXT: vst %v0, 16(%r2), 4 -// z10-NEXT: vst %v1, 0(%r2), 4 -// z10-NEXT: br %r14 -// z13: vl %v0, 16(%r3), 4 -// z13-NEXT: vst %v0, 16(%r2), 4 -// z13-NEXT: vl %v0, 0(%r3), 4 -// z13-NEXT: vst %v0, 0(%r2), 4 -// z13-NEXT: br %r14 +// CHECK-DAG: vl [[REG1:%v[0-9]+]], 16(%r3), 4 +// CHECK-DAG: vl [[REG2:%v[0-9]+]], 0(%r3), 4 +// CHECK-DAG: vst [[REG1]], 16(%r2), 4 +// CHECK-DAG: vst [[REG2]], 0(%r2), 4 +// CHECK: br %r14 #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_wrapper_ret_large(x: &Wrapper) -> Wrapper { @@ -141,16 +131,11 @@ unsafe extern "C" fn vector_wrapper_with_zst_ret( *x } // CHECK-LABEL: vector_wrapper_with_zst_ret_large: -// z10: vl %v0, 16(%r3), 4 -// z10-NEXT: vl %v1, 0(%r3), 4 -// z10-NEXT: vst %v0, 16(%r2), 4 -// z10-NEXT: vst %v1, 0(%r2), 4 -// z10-NEXT: br %r14 -// z13: vl %v0, 16(%r3), 4 -// z13-NEXT: vst %v0, 16(%r2), 4 -// z13-NEXT: vl %v0, 0(%r3), 4 -// z13-NEXT: vst %v0, 0(%r2), 4 -// z13-NEXT: br %r14 +// CHECK-DAG: vl [[REG1:%v[0-9]+]], 16(%r3), 4 +// CHECK-DAG: vl [[REG2:%v[0-9]+]], 0(%r3), 4 +// CHECK-DAG: vst [[REG1]], 16(%r2), 4 +// CHECK-DAG: vst [[REG2]], 0(%r2), 4 +// CHECK: br %r14 #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_wrapper_with_zst_ret_large( @@ -180,16 +165,11 @@ unsafe extern "C" fn vector_transparent_wrapper_ret( *x } // CHECK-LABEL: vector_transparent_wrapper_ret_large: -// z10: vl %v0, 16(%r3), 4 -// z10-NEXT: vl %v1, 0(%r3), 4 -// z10-NEXT: vst %v0, 16(%r2), 4 -// z10-NEXT: vst %v1, 0(%r2), 4 -// z10-NEXT: br %r14 -// z13: vl %v0, 0(%r3), 4 -// z13-NEXT: vl %v1, 16(%r3), 4 -// z13-NEXT: vst %v1, 16(%r2), 4 -// z13-NEXT: vst %v0, 0(%r2), 4 -// z13-NEXT: br %r14 +// CHECK-DAG: vl [[REG1:%v[0-9]+]], 16(%r3), 4 +// CHECK-DAG: vl [[REG2:%v[0-9]+]], 0(%r3), 4 +// CHECK-DAG: vst [[REG1]], 16(%r2), 4 +// CHECK-DAG: vst [[REG2]], 0(%r2), 4 +// CHECK: br %r14 #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_transparent_wrapper_ret_large( From 247e6e1ad788079a8f78875032207e98f7f7015d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 26 Jun 2026 18:12:18 +0200 Subject: [PATCH 02/10] Add missing links in integer docs --- library/core/src/num/int_macros.rs | 46 ++++++++++++++--------------- library/core/src/num/uint_macros.rs | 4 +-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 34f16184e4ec3..ade9d294e8592 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -983,7 +983,7 @@ macro_rules! int_impl { /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where - /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value + /// [`MIN`](Self::MIN) is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value /// that is too large to represent in the type. /// /// # Examples @@ -1050,7 +1050,7 @@ macro_rules! int_impl { /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// The only case where such an overflow can occur is when one divides `MIN / -1` on a signed type (where - /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value + /// [`MIN`](Self::MIN) is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value /// that is too large to represent in the type. /// /// # Examples @@ -1223,7 +1223,7 @@ macro_rules! int_impl { /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a - /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. + /// signed type (where [`MIN`](Self::MIN) is the negative minimal value), which is invalid due to implementation artifacts. /// /// # Examples /// @@ -1289,7 +1289,7 @@ macro_rules! int_impl { /// This function will always panic on overflow, regardless of whether overflow checks are enabled. /// /// The only case where such an overflow can occur is `x % y` for `MIN / -1` on a - /// signed type (where `MIN` is the negative minimal value), which is invalid due to implementation artifacts. + /// signed type (where [`MIN`](Self::MIN) is the negative minimal value), which is invalid due to implementation artifacts. /// /// # Examples /// @@ -2259,8 +2259,8 @@ macro_rules! int_impl { /// boundary of the type. /// /// The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where - /// `MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value - /// that is too large to represent in the type. In such a case, this function returns `MIN` itself. + /// [`MIN`](Self::MIN) is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value + /// that is too large to represent in the type. In such a case, this function returns [`MIN`](Self::MIN) itself. /// /// # Panics /// @@ -2284,9 +2284,9 @@ macro_rules! int_impl { /// Wrapping Euclidean division. Computes `self.div_euclid(rhs)`, /// wrapping around at the boundary of the type. /// - /// Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value + /// Wrapping will only occur in `MIN / -1` on a signed type (where [`MIN`](Self::MIN) is the negative minimal value /// for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the - /// type. In this case, this method returns `MIN` itself. + /// type. In this case, this method returns [`MIN`](Self::MIN) itself. /// /// # Panics /// @@ -2311,7 +2311,7 @@ macro_rules! int_impl { /// boundary of the type. /// /// Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` - /// invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, + /// invalid for `MIN / -1` on a signed type (where [`MIN`](Self::MIN) is the negative minimal value). In such a case, /// this function returns `0`. /// /// # Panics @@ -2336,8 +2336,8 @@ macro_rules! int_impl { /// Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around /// at the boundary of the type. /// - /// Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value - /// for the type). In this case, this method returns 0. + /// Wrapping will only occur in `MIN % -1` on a signed type (where [`MIN`](Self::MIN) is + /// the negative minimal value for the type). In this case, this method returns 0. /// /// # Panics /// @@ -2361,9 +2361,9 @@ macro_rules! int_impl { /// Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary /// of the type. /// - /// The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN` + /// The only case where such wrapping can occur is when one negates [`MIN`](Self::MIN) on a signed type (where [`MIN`](Self::MIN) /// is the negative minimal value for the type); this is a positive value that is too large to represent - /// in the type. In such a case, this function returns `MIN` itself. + /// in the type. In such a case, this function returns [`MIN`](Self::MIN) itself. /// /// # Examples /// @@ -2460,7 +2460,7 @@ macro_rules! int_impl { /// /// The only case where such wrapping can occur is when one takes the absolute value of the negative /// minimal value for the type; this is a positive value that is too large to represent in the type. In - /// such a case, this function returns `MIN` itself. + /// such a case, this function returns [`MIN`](Self::MIN) itself. /// /// # Examples /// @@ -2772,7 +2772,7 @@ macro_rules! int_impl { /// /// # Examples /// - /// Please note that this example is shared among integer types, which is why `i32` is used. + /// Please note that this example is shared among integer types, which is why [`i32`] is used. /// /// ``` /// #![feature(signed_bigint_helpers)] @@ -2950,7 +2950,7 @@ macro_rules! int_impl { /// Negates self, overflowing if this is equal to the minimum value. /// /// Returns a tuple of the negated version of self along with a boolean indicating whether an overflow - /// happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the + /// happened. If `self` is the minimum value (e.g., [`i32::MIN`] for values of type [`i32`]), then the /// minimum value will be returned again and `true` will be returned for an overflow happening. /// /// # Examples @@ -3020,7 +3020,7 @@ macro_rules! int_impl { /// /// Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow /// happened. If self is the minimum value - #[doc = concat!("(e.g., ", stringify!($SelfT), "::MIN for values of type ", stringify!($SelfT), "),")] + #[doc = concat!("(e.g., [`", stringify!($SelfT), "::MIN`] for values of type [`", stringify!($SelfT), "`]),")] /// then the minimum value will be returned again and true will be returned /// for an overflow happening. /// @@ -3177,7 +3177,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is zero or if `self` is `Self::MIN` + /// This function will panic if `rhs` is zero or if `self` is [`Self::MIN`] /// and `rhs` is -1. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples @@ -3215,7 +3215,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is zero or if `self` is `Self::MIN` and + /// This function will panic if `rhs` is zero or if `self` is [`Self::MIN`] and /// `rhs` is -1. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples @@ -3262,7 +3262,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is zero or if `self` is `Self::MIN` + /// This function will panic if `rhs` is zero or if `self` is [`Self::MIN`] /// and `rhs` is -1. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples @@ -3304,7 +3304,7 @@ macro_rules! int_impl { /// /// # Panics /// - /// This function will panic if `rhs` is zero or if `self` is `Self::MIN` + /// This function will panic if `rhs` is zero or if `self` is [`Self::MIN`] /// and `rhs` is -1. This behavior is not affected by the `overflow-checks` flag. /// /// # Examples @@ -3441,8 +3441,8 @@ macro_rules! int_impl { /// rounded down. /// /// This method might not be optimized owing to implementation details; - /// `ilog2` can produce results more efficiently for base 2, and `ilog10` - /// can produce results more efficiently for base 10. + /// [`ilog2`][Self::ilog2] can produce results more efficiently for base 2, + /// and [`ilog10`](Self::ilog10) can produce results more efficiently for base 10. /// /// # Panics /// diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 4053134d89d43..cfb5eb54fb6bc 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1721,8 +1721,8 @@ macro_rules! uint_impl { /// rounded down. /// /// This method might not be optimized owing to implementation details; - /// `ilog2` can produce results more efficiently for base 2, and `ilog10` - /// can produce results more efficiently for base 10. + /// [`ilog2`](Self::ilog2) can produce results more efficiently for base 2, + /// and [`ilog10`](Self::ilog10) can produce results more efficiently for base 10. /// /// # Panics /// From 87f3254ca008c05b1cf1b55a73f95b67717bdc1a Mon Sep 17 00:00:00 2001 From: Peter Lyons Kehl Date: Sun, 21 Jun 2026 18:59:01 -0700 Subject: [PATCH 03/10] Cross-referencing tuple_trait tracking issue, source and the Unstable Book. --- library/core/src/marker.rs | 2 +- src/doc/unstable-book/src/library-features/tuple-trait.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/doc/unstable-book/src/library-features/tuple-trait.md diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 744bd41d1139e..45b8b266a2671 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1066,7 +1066,7 @@ pub const trait Destruct: PointeeSized {} /// /// The implementation of this trait is built-in and cannot be implemented /// for any user type. -#[unstable(feature = "tuple_trait", issue = "none")] +#[unstable(feature = "tuple_trait", issue = "157987")] #[lang = "tuple_trait"] #[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")] #[rustc_deny_explicit_impl] diff --git a/src/doc/unstable-book/src/library-features/tuple-trait.md b/src/doc/unstable-book/src/library-features/tuple-trait.md new file mode 100644 index 0000000000000..5521850f12bb6 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/tuple-trait.md @@ -0,0 +1,5 @@ +# `tuple_trait` + +The tracking issue for this feature is [#157987]. + +[#157987]: https://github.com/rust-lang/rust/issues/157987 From e7da124cc26ff87439806f7b72312a96577eb02d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jun 2026 08:12:59 +1000 Subject: [PATCH 04/10] Improve documentation on lint passes To explain some non-obvious things that took me some time to work out. --- compiler/rustc_lint/src/context.rs | 48 ++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 348f1f55d3215..70638f3648552 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -46,20 +46,38 @@ type LateLintPassFactory = Box Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync>; /// Information about the registered lints. +// +// About the pass factories: these should only be called once, but since we +// want to avoid locks or interior mutability, we don't enforce this. Lints +// should, in theory, be compatible with being constructed more than once, +// though not necessarily in a sane manner. This is safe though. pub struct LintStore { /// Registered lints. lints: Vec<&'static Lint>, - /// Constructor functions for each variety of lint pass. + /// This lint pass kind is softly deprecated. It misses expanded code and has caused a few + /// errors in the past. Currently, it is only used in Clippy. New implementations + /// should avoid using this interface, as it might be removed in the future. /// - /// These should only be called once, but since we want to avoid locks or - /// interior mutability, we don't enforce this (and lints should, in theory, - /// be compatible with being constructed more than once, though not - /// necessarily in a sane manner. This is safe though.) + /// * See [rust#69838](https://github.com/rust-lang/rust/pull/69838) + /// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518) pub pre_expansion_passes: Vec, + + /// These lint passes run on AST nodes. pub early_passes: Vec, + + /// These lint passes run on HIR nodes. Each one processes an entire crate. They don't benefit + /// from incremental compilation. `late_module_passes` should be used in preference where + /// possible; only use `late_passes` for lints that implement `check_crate` and/or + /// `check_crate_post` and accumulate cross-module state. + /// + /// The exception is Clippy, which uses `late_passes` for all late lint passes. It needs + /// `check_crate`/`check_crate_post` for some of its lints and uses late lint passes throughout + /// for consistency. This is ok because Clippy isn't wired for incremental compilation. pub late_passes: Vec, - /// This is unique in that we construct them per-module, so not once. + + /// These lint passes run on HIR nodes, and are constructed per-module (i.e. multiple times). + /// They benefit from incremental compilation. pub late_module_passes: Vec, /// Lints indexed by name. @@ -166,24 +184,22 @@ impl LintStore { self.lint_groups.keys().copied() } - pub fn register_early_pass(&mut self, pass: EarlyLintPassFactory) { - self.early_passes.push(pass); - } - - /// This lint pass is softly deprecated. It misses expanded code and has caused a few - /// errors in the past. Currently, it is only used in Clippy. New implementations - /// should avoid using this interface, as it might be removed in the future. - /// - /// * See [rust#69838](https://github.com/rust-lang/rust/pull/69838) - /// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518) + /// See the comment on `LintStore::pre_expansion_passes`. pub fn register_pre_expansion_pass(&mut self, pass: EarlyLintPassFactory) { self.pre_expansion_passes.push(pass); } + /// See the comment on `LintStore::early_passes`. + pub fn register_early_pass(&mut self, pass: EarlyLintPassFactory) { + self.early_passes.push(pass); + } + + /// See the comment on `LintStore::late_passes`. pub fn register_late_pass(&mut self, pass: LateLintPassFactory) { self.late_passes.push(pass); } + /// See the comment on `LintStore::late_module_passes`. pub fn register_late_mod_pass(&mut self, pass: LateLintPassFactory) { self.late_module_passes.push(pass); } From e983dd7aff5c6d24583e1f4492c8a4db52b3f4f3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 16 Jun 2026 11:14:36 +1000 Subject: [PATCH 05/10] Fix a comment `EarlyLintPassObjects` is an old name. --- compiler/rustc_lint/src/passes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 5c101048b8010..12cf58907566d 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -203,7 +203,7 @@ macro_rules! expand_combined_early_lint_pass_methods { /// Combines multiple lints passes into a single lint pass, at compile time, /// for maximum speed. Each `check_foo` method in `$methods` within this pass /// simply calls `check_foo` once per `$pass`. Compare with -/// `EarlyLintPassObjects`, which is similar, but combines lint passes at +/// `RuntimeCombinedEarlyLintPass`, which is similar, but combines lint passes at /// runtime. #[macro_export] macro_rules! declare_combined_early_lint_pass { From 969db62833ad1c623110de0b71baf40a2028813d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Jun 2026 15:17:00 +1000 Subject: [PATCH 06/10] Rename `*CombinedModuleLateLintPass` As `*CombinedLateLintModPass`, because that matches things like `late_lint_mod`. --- compiler/rustc_lint/src/lib.rs | 12 ++++++------ src/doc/rustc-dev-guide/src/diagnostics/lintstore.md | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 9b87da79ee155..4d8194ba3e140 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -154,7 +154,7 @@ pub fn provide(providers: &mut Providers) { } fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { - late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new()); + late_lint_mod(tcx, module_def_id, BuiltinCombinedLateLintModPass::new()); } early_lint_methods!( @@ -207,7 +207,7 @@ early_lint_methods!( late_lint_methods!( declare_combined_late_lint_pass, [ - BuiltinCombinedModuleLateLintPass, + BuiltinCombinedLateLintModPass, [ ForLoopsOverFallibles: ForLoopsOverFallibles, DefaultCouldBeDerived: DefaultCouldBeDerived, @@ -279,7 +279,7 @@ late_lint_methods!( late_lint_methods!( declare_combined_late_lint_pass, [ - InternalCombinedModuleLateLintPass, + InternalCombinedLateLintModPass, [ DefaultHashTypes: DefaultHashTypes, QueryStability: QueryStability, @@ -317,7 +317,7 @@ fn register_builtins(store: &mut LintStore) { store.register_lints(&BuiltinCombinedPreExpansionLintPass::lint_vec()); store.register_lints(&BuiltinCombinedEarlyLintPass::lint_vec()); - store.register_lints(&BuiltinCombinedModuleLateLintPass::lint_vec()); + store.register_lints(&BuiltinCombinedLateLintModPass::lint_vec()); store.register_lints(&foreign_modules::lint_vec()); store.register_lints(&hardwired::lint_vec()); @@ -700,8 +700,8 @@ fn register_internals(store: &mut LintStore) { store.register_lints(&InternalCombinedEarlyLintPass::lint_vec()); store.register_early_pass(Box::new(|| Box::new(InternalCombinedEarlyLintPass::new()))); - store.register_lints(&InternalCombinedModuleLateLintPass::lint_vec()); - store.register_late_mod_pass(Box::new(|_| Box::new(InternalCombinedModuleLateLintPass::new()))); + store.register_lints(&InternalCombinedLateLintModPass::lint_vec()); + store.register_late_mod_pass(Box::new(|_| Box::new(InternalCombinedLateLintModPass::new()))); store.register_group( false, diff --git a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md index 11a7a573f38b6..baae63e96bdc7 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/lintstore.md @@ -97,7 +97,7 @@ The best way for drivers to get access to this is by overriding the Within the compiler, for performance reasons, we usually do not register dozens of lint passes. Instead, we have a single lint pass of each variety (e.g., -`BuiltinCombinedModuleLateLintPass`) which will internally call all of the +`BuiltinCombinedLateLintModPass`) which will internally call all of the individual lint passes; this is because then we get the benefits of static over dynamic dispatch for each of the (often empty) trait methods. From cd8d703f1ff9afa26cc88e8bf1496e81c79774e2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Jun 2026 15:30:20 +1000 Subject: [PATCH 07/10] Rename some lint pass things We generally write `lint_pass`/`LintPass`. This commit renames some things that only use `pass`/`Pass`. And also some `s/module/mod` changes, too. --- compiler/rustc_lint/src/context.rs | 46 ++++++++++++------------ compiler/rustc_lint/src/early.rs | 4 +-- compiler/rustc_lint/src/late.rs | 4 +-- compiler/rustc_lint/src/lib.rs | 6 ++-- src/tools/clippy/clippy_lints/src/lib.rs | 8 +++-- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 70638f3648552..040236297270a 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -61,24 +61,24 @@ pub struct LintStore { /// /// * See [rust#69838](https://github.com/rust-lang/rust/pull/69838) /// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518) - pub pre_expansion_passes: Vec, + pub pre_expansion_lint_passes: Vec, /// These lint passes run on AST nodes. - pub early_passes: Vec, + pub early_lint_passes: Vec, /// These lint passes run on HIR nodes. Each one processes an entire crate. They don't benefit - /// from incremental compilation. `late_module_passes` should be used in preference where - /// possible; only use `late_passes` for lints that implement `check_crate` and/or + /// from incremental compilation. `late_lint_mod_passes` should be used in preference where + /// possible; only use `late_lint_passes` for lints that implement `check_crate` and/or /// `check_crate_post` and accumulate cross-module state. /// - /// The exception is Clippy, which uses `late_passes` for all late lint passes. It needs + /// The exception is Clippy, which uses `late_lint_passes` for all late lint passes. It needs /// `check_crate`/`check_crate_post` for some of its lints and uses late lint passes throughout /// for consistency. This is ok because Clippy isn't wired for incremental compilation. - pub late_passes: Vec, + pub late_lint_passes: Vec, /// These lint passes run on HIR nodes, and are constructed per-module (i.e. multiple times). /// They benefit from incremental compilation. - pub late_module_passes: Vec, + pub late_lint_mod_passes: Vec, /// Lints indexed by name. by_name: UnordMap, @@ -154,10 +154,10 @@ impl LintStore { pub fn new() -> LintStore { LintStore { lints: vec![], - pre_expansion_passes: vec![], - early_passes: vec![], - late_passes: vec![], - late_module_passes: vec![], + pre_expansion_lint_passes: vec![], + early_lint_passes: vec![], + late_lint_passes: vec![], + late_lint_mod_passes: vec![], by_name: Default::default(), lint_groups: Default::default(), } @@ -184,24 +184,24 @@ impl LintStore { self.lint_groups.keys().copied() } - /// See the comment on `LintStore::pre_expansion_passes`. - pub fn register_pre_expansion_pass(&mut self, pass: EarlyLintPassFactory) { - self.pre_expansion_passes.push(pass); + /// See the comment on `LintStore::pre_expansion_lint_passes`. + pub fn register_pre_expansion_lint_pass(&mut self, pass: EarlyLintPassFactory) { + self.pre_expansion_lint_passes.push(pass); } - /// See the comment on `LintStore::early_passes`. - pub fn register_early_pass(&mut self, pass: EarlyLintPassFactory) { - self.early_passes.push(pass); + /// See the comment on `LintStore::early_lint_passes`. + pub fn register_early_lint_pass(&mut self, pass: EarlyLintPassFactory) { + self.early_lint_passes.push(pass); } - /// See the comment on `LintStore::late_passes`. - pub fn register_late_pass(&mut self, pass: LateLintPassFactory) { - self.late_passes.push(pass); + /// See the comment on `LintStore::late_lint_passes`. + pub fn register_late_lint_pass(&mut self, pass: LateLintPassFactory) { + self.late_lint_passes.push(pass); } - /// See the comment on `LintStore::late_module_passes`. - pub fn register_late_mod_pass(&mut self, pass: LateLintPassFactory) { - self.late_module_passes.push(pass); + /// See the comment on `LintStore::late_lint_mod_passes`. + pub fn register_late_lint_mod_pass(&mut self, pass: LateLintPassFactory) { + self.late_lint_mod_passes.push(pass); } /// Helper method for register_early/late_pass diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 93d150c79d0df..9c123f67abd5f 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -329,11 +329,11 @@ pub fn check_ast_node<'a>( let context = if pre_expansion { let builtin_lints = crate::BuiltinCombinedPreExpansionLintPass::new(); - let passes = &lint_store.pre_expansion_passes; + let passes = &lint_store.pre_expansion_lint_passes; run_passes(check_node, context, builtin_lints, passes) } else { let builtin_lints = crate::BuiltinCombinedEarlyLintPass::new(); - let passes = &lint_store.early_passes; + let passes = &lint_store.early_lint_passes; run_passes(check_node, context, builtin_lints, passes) }; diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index fea6b2ab2f9bd..c17fe6f2e510f 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -355,7 +355,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( // `builtin_lints` directly rather than bundling it up into the // `RuntimeCombinedLateLintPass`. let mut passes: Vec<_> = unerased_lint_store(tcx.sess) - .late_module_passes + .late_lint_mod_passes .iter() .map(|mk_pass| mk_pass(tcx)) .filter(|pass| is_lint_pass_required(skippable_lints, &pass.get_lints())) @@ -403,7 +403,7 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { // Note: `passes` is often empty after filtering. let passes: Vec<_> = unerased_lint_store(tcx.sess) - .late_passes + .late_lint_passes .iter() .map(|mk_pass| mk_pass(tcx)) .filter(|pass| is_lint_pass_required(skippable_lints, &pass.get_lints())) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4d8194ba3e140..72c9ba0e5afbf 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -698,10 +698,12 @@ fn register_builtins(store: &mut LintStore) { fn register_internals(store: &mut LintStore) { store.register_lints(&InternalCombinedEarlyLintPass::lint_vec()); - store.register_early_pass(Box::new(|| Box::new(InternalCombinedEarlyLintPass::new()))); + store.register_early_lint_pass(Box::new(|| Box::new(InternalCombinedEarlyLintPass::new()))); store.register_lints(&InternalCombinedLateLintModPass::lint_vec()); - store.register_late_mod_pass(Box::new(|_| Box::new(InternalCombinedLateLintModPass::new()))); + store.register_late_lint_mod_pass(Box::new(|_| { + Box::new(InternalCombinedLateLintModPass::new()) + })); store.register_group( false, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index d002df267027d..913be07ef326c 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -454,7 +454,9 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. // Due to the architecture of the compiler, currently `cfg_attr` attributes on crate // level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. - store.register_pre_expansion_pass(Box::new(move || Box::new(attrs::EarlyAttributes::new(conf)))); + store.register_pre_expansion_lint_pass( + Box::new(move || Box::new(attrs::EarlyAttributes::new(conf))) + ); let format_args_storage = FormatArgsStorage::default(); let attr_storage = AttrStorage::default(); @@ -462,12 +464,12 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co { let format_args = format_args_storage.clone(); let attrs = attr_storage.clone(); - store.early_passes.push(Box::new(move || { + store.early_lint_passes.push(Box::new(move || { Box::new(CombinedEarlyLintPass::new(conf, format_args.clone(), attrs.clone())) })); } - store.late_passes.push(Box::new(move |tcx: TyCtxt<'_>| { + store.late_lint_passes.push(Box::new(move |tcx: TyCtxt<'_>| { let skippable_lints = tcx.skippable_lints(()); let is_active = |lints: &rustc_lint::LintVec| is_lint_pass_required(skippable_lints, lints); Box::new(CombinedLateLintPass::new( From 879aba106a8cb86267ef498fc7e64346b90b5514 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 18 Jun 2026 15:43:57 +1000 Subject: [PATCH 08/10] Make `LintStore::*_lint_passes` non-`pub` There are `register_*_lint_pass` methods, might as well go through them. --- compiler/rustc_lint/src/context.rs | 8 ++++---- src/tools/clippy/clippy_lints/src/lib.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 040236297270a..e992f1ed385e7 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -61,10 +61,10 @@ pub struct LintStore { /// /// * See [rust#69838](https://github.com/rust-lang/rust/pull/69838) /// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518) - pub pre_expansion_lint_passes: Vec, + pub(crate) pre_expansion_lint_passes: Vec, /// These lint passes run on AST nodes. - pub early_lint_passes: Vec, + pub(crate) early_lint_passes: Vec, /// These lint passes run on HIR nodes. Each one processes an entire crate. They don't benefit /// from incremental compilation. `late_lint_mod_passes` should be used in preference where @@ -74,11 +74,11 @@ pub struct LintStore { /// The exception is Clippy, which uses `late_lint_passes` for all late lint passes. It needs /// `check_crate`/`check_crate_post` for some of its lints and uses late lint passes throughout /// for consistency. This is ok because Clippy isn't wired for incremental compilation. - pub late_lint_passes: Vec, + pub(crate) late_lint_passes: Vec, /// These lint passes run on HIR nodes, and are constructed per-module (i.e. multiple times). /// They benefit from incremental compilation. - pub late_lint_mod_passes: Vec, + pub(crate) late_lint_mod_passes: Vec, /// Lints indexed by name. by_name: UnordMap, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 913be07ef326c..a65b27f550995 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -464,12 +464,12 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co { let format_args = format_args_storage.clone(); let attrs = attr_storage.clone(); - store.early_lint_passes.push(Box::new(move || { + store.register_early_lint_pass(Box::new(move || { Box::new(CombinedEarlyLintPass::new(conf, format_args.clone(), attrs.clone())) })); } - store.late_lint_passes.push(Box::new(move |tcx: TyCtxt<'_>| { + store.register_late_lint_pass(Box::new(move |tcx: TyCtxt<'_>| { let skippable_lints = tcx.skippable_lints(()); let is_active = |lints: &rustc_lint::LintVec| is_lint_pass_required(skippable_lints, lints); Box::new(CombinedLateLintPass::new( From 480ddb0c4c92343c43eb1d2428b382f0385fedf9 Mon Sep 17 00:00:00 2001 From: Yukang Date: Sat, 27 Jun 2026 13:46:09 +0800 Subject: [PATCH 09/10] Add regression test for unexpected pointer dereference issue --- .../unexpected-pointer-deref-issue-154568.rs | 22 +++++++++++++++++++ ...expected-pointer-deref-issue-154568.stderr | 20 +++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.rs create mode 100644 tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.stderr diff --git a/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.rs b/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.rs new file mode 100644 index 0000000000000..ca97b25fa64fa --- /dev/null +++ b/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.rs @@ -0,0 +1,22 @@ +// Regression test for #154568 +//@ compile-flags: -Znext-solver=globally + +trait Role { + type Inner; +} + +struct HandshakeCallback(C); +struct Handshake(R::Inner); + +fn main() { + let callback = HandshakeCallback(()); + let handshake = Handshake(callback.0.clone()); + //~^ ERROR type annotations needed + match &handshake { + hs if (|| { + let borrowed_inner = &hs.0; + borrowed_inner == &callback.0 + })() => println!(), + _ => {} + } +} diff --git a/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.stderr b/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.stderr new file mode 100644 index 0000000000000..3c5a00744a636 --- /dev/null +++ b/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.stderr @@ -0,0 +1,20 @@ +error[E0283]: type annotations needed for `Handshake<_>` + --> $DIR/unexpected-pointer-deref-issue-154568.rs:13:9 + | +LL | let handshake = Handshake(callback.0.clone()); + | ^^^^^^^^^ ----------------------------- type must be known at this point + | + = note: the type must implement `Role` +note: required by a bound in `Handshake` + --> $DIR/unexpected-pointer-deref-issue-154568.rs:9:21 + | +LL | struct Handshake(R::Inner); + | ^^^^ required by this bound in `Handshake` +help: consider giving `handshake` an explicit type, where the type for type parameter `R` is specified + | +LL | let handshake: Handshake = Handshake(callback.0.clone()); + | ++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. From 4bbd8fcbfb100f3c25885804eb5096bfd260eb2e Mon Sep 17 00:00:00 2001 From: mu001999 Date: Mon, 8 Jun 2026 17:14:28 +0000 Subject: [PATCH 10/10] Use infer tys for synthetic params when lowering const paths point to fns --- .../src/hir_ty_lowering/mod.rs | 22 ++++++++++++++++++- .../mgca/bad-impl-trait-with-apit.rs | 13 +++++++++++ .../mgca/bad-impl-trait-with-apit.stderr | 9 ++++++++ .../mgca/synth-gen-arg-ice-158152.rs | 1 + .../mgca/synth-gen-arg-ice-158152.stderr | 13 ++++++++--- 5 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 tests/ui/const-generics/mgca/bad-impl-trait-with-apit.rs create mode 100644 tests/ui/const-generics/mgca/bad-impl-trait-with-apit.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 95a91f1444404..64b31b5efee31 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2866,7 +2866,27 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { did, path.segments.last().unwrap(), ); - ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args)) + + if self.tcx().generics_of(did).own_synthetic_params_count() == 0 { + ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args)) + } else { + let tcx = self.tcx(); + let generics = tcx.generics_of(did); + + // Use infer tys for synthetic params; otherwise the impl header's trait ref may + // contain callee-owned synthetic params and fail when instantiated with impl args. + // See issue #155834 + let args = args.iter().enumerate().map(|(index, arg)| { + let param = generics.param_at(index, tcx); + if param.kind.is_synthetic() { + self.ty_infer(Some(param), span).into() + } else { + arg + } + }); + + ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args)) + } } // Exhaustive match to be clear about what exactly we're considering to be diff --git a/tests/ui/const-generics/mgca/bad-impl-trait-with-apit.rs b/tests/ui/const-generics/mgca/bad-impl-trait-with-apit.rs new file mode 100644 index 0000000000000..c509c52951197 --- /dev/null +++ b/tests/ui/const-generics/mgca/bad-impl-trait-with-apit.rs @@ -0,0 +1,13 @@ +// Regression test for issue #155834 + +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +trait Trait {} + +impl<'t> Trait for [(); N] {} +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for implementations + +fn N(arg: impl Trait) {} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/bad-impl-trait-with-apit.stderr b/tests/ui/const-generics/mgca/bad-impl-trait-with-apit.stderr new file mode 100644 index 0000000000000..a5caa077c7620 --- /dev/null +++ b/tests/ui/const-generics/mgca/bad-impl-trait-with-apit.stderr @@ -0,0 +1,9 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations + --> $DIR/bad-impl-trait-with-apit.rs:8:25 + | +LL | impl<'t> Trait for [(); N] {} + | ^ not allowed in type signatures + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.rs b/tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.rs index 11d970534f513..53cf964b8f5a5 100644 --- a/tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.rs +++ b/tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.rs @@ -4,6 +4,7 @@ trait A {} trait Trait {} impl A<[usize; fn_item]> for () {} +//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for implementations fn fn_item(_: impl Trait) {} //~^ ERROR: type provided when a constant was expected diff --git a/tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.stderr b/tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.stderr index 0cb59587ee20b..a68c0a1cb409d 100644 --- a/tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.stderr +++ b/tests/ui/const-generics/mgca/synth-gen-arg-ice-158152.stderr @@ -1,5 +1,11 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations + --> $DIR/synth-gen-arg-ice-158152.rs:6:16 + | +LL | impl A<[usize; fn_item]> for () {} + | ^^^^^^^ not allowed in type signatures + error[E0747]: type provided when a constant was expected - --> $DIR/synth-gen-arg-ice-158152.rs:8:26 + --> $DIR/synth-gen-arg-ice-158152.rs:9:26 | LL | fn fn_item(_: impl Trait) {} | ^^^^^ @@ -9,6 +15,7 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | fn fn_item(_: impl Trait<{ usize }>) {} | + + -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0747`. +Some errors have detailed explanations: E0121, E0747. +For more information about an error, try `rustc --explain E0121`.