From 93c8b747658e5616d739ff22deab809785909232 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Aug 2026 16:04:22 +0200 Subject: [PATCH 01/56] document that t-lang does not need involvement for unobservable intrinsics --- library/core/src/intrinsics/mod.rs | 31 +++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 2316fc4318918..5596ef029bcc8 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -10,6 +10,30 @@ //! and , //! and for const evaluation in . //! +//! Intrinsics don't need a body. However, they optionally can have a body, which we call the +//! "fallback body". This will be used by codegen backends that do not have a dedicated +//! implementation of the intrinsic, making it easier to add new intrinsics for specific operations +//! without having to implement them in each codegen backend. The fallback body obviously has to be +//! a valid implementation of the documented specification of the intrinsic. In some cases, the +//! fallback body will be *equivalent* to the specification. Note that this is a strong requirement: +//! if the spec says "UB if input `x` is even", then a valid implementation can just ignore this and +//! do whatever it wants in that case; an *equivalent* implementation needs to actually check this +//! condition and trigger UB in that case (e.g. by using `hint::assert_unchecked()`). Similar, if +//! the spec says "returns `x` or `y` non-deterministically", then an *equivalent* implementation +//! must actually do non-deterministic choice and return either value (e.g. by invoking some other +//! language operation that has the same non-determinism). Intrinsics with such a fallback body that +//! is equivalent to the spec may be marked with `#[miri::intrinsic_fallback_is_spec]`; the fallback +//! body will then also be used by Miri for UB checking. When in doubt, do not use this attribute or +//! ask the Miri maintainers for advice. +//! +//! Intrinsics are, in general, language extensions. Therefore, t-lang should be involved whenever a +//! new intrinsic is exposed to stable code. However, if an intrinsic is marked +//! `#[miri::intrinsic_fallback_is_spec]` with a fallback body that only uses stable features (or if +//! such a fallback body could be written, but for one reason or another the actual fallback body is +//! different), and if it also does not make other promises that go beyond observable program +//! behavior (such as steering the optimizer in a particular direction), then an intrinsic may be +//! used without t-lang involvement. +//! //! # Const intrinsics //! //! In order to make an intrinsic unstable usable at compile-time, copy the implementation from @@ -19,9 +43,10 @@ //! wg-const-eval. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, -//! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change requires -//! T-lang approval, because it may bake a feature into the language that cannot be replicated in -//! user code without compiler support. +//! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change +//! requires T-lang approval, because it may bake a feature into the language that cannot be +//! replicated in user code without compiler support. The same exception as above applies for +//! `#[miri::intrinsic_fallback_is_spec]` intrinsics. //! //! # Volatiles //! From 1b08f986cae27968173afa4ab6cc9d47eb4a704c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Aug 2026 21:47:00 +1000 Subject: [PATCH 02/56] Slightly extend `tests/run-make/target-specs/rmake.rs` The `require-explicit-cpu.json` case currently prints a "default target CPU" line; test for this. (It will change in the next commit.) --- tests/run-make/target-specs/rmake.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index 6c88f3164e9e4..39a153262d11c 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -95,5 +95,10 @@ fn main() { .crate_type("lib") .arg("-Ctarget-cpu=generic") .run(); - rustc().arg("-Zunstable-options").target("require-explicit-cpu").print("target-cpus").run(); + rustc() + .arg("-Zunstable-options") + .target("require-explicit-cpu") + .print("target-cpus") + .run() + .assert_stdout_contains("default target CPU"); } From 39ca15cd9807aa9de2c4303ad095a785f900b671 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Aug 2026 21:30:09 +1000 Subject: [PATCH 03/56] Adjust when "This is the default target CPU..." message is printed Specifically, don't print it when `need_explicit_cpu` is set, because it doesn't really make sense in that context. Right now among builtin targets this only affects the `amdgcn-amd-amdhsa` target, but it will also be relevant for the `avr2` target in the next commit. It also affects the `require-explicit-cpu.json` case in `tests/run-make/target-specs/rmake.rs`. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 5 +++-- tests/run-make/target-specs/rmake.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 298b58dd0007f..cebc3ffc2bbdd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -497,10 +497,11 @@ fn print_target_cpus(sess: &Session, tm: &llvm::TargetMachine, out: &mut String) cpu_name: &'a str, remark: String, } - // Compare CPU against current target to label the default. + // Compare CPU against current target to label the default. Do not print it if + // `need_explicit_cpu` is set, because in that case the concept of default makes less sense. let target_cpu = handle_native(&sess.target.cpu); let make_remark = |cpu_name| { - if cpu_name == target_cpu { + if cpu_name == target_cpu && !sess.target.need_explicit_cpu { // FIXME(#132514): This prints the LLVM target string, which can be // different from the Rust target string. Is that intended? let target = &sess.target.llvm_target; diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index 39a153262d11c..4deb7c9bfcc93 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -100,5 +100,5 @@ fn main() { .target("require-explicit-cpu") .print("target-cpus") .run() - .assert_stdout_contains("default target CPU"); + .assert_stdout_not_contains("default target CPU"); } From ac05dbe149bef0b486eb890fa3e6a90fd0059a16 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Aug 2026 16:07:47 +1000 Subject: [PATCH 04/56] Explicitly set the `cpu` field for `avr-none` Currently rustc uses LLVM's `TargetMachine::getMCSubtargetInfo` method to access an `MCSubtargetInfo` to do feature testing. The next commit will change the feature testing to instead use an alternative pathway, LLVM's `Target::createMCSubtargetInfo` method. The two pathways have some slight differences. One difference relates to the `avr-none` target. Currently its `cpu` field isn't set so it gets the default "generic" value, which is not a valid AVR CPU name. This was hidden by the fact that the current LLVM pathway goes through the `getCPU` function in `AVRTargetMachine.cpp`, which rewrites "generic" as "avr2". But the alternative LLVM pathway doesn't rewrite "generic". Without an adjustment, we would get some behavioural differences with the alternative pathway, such as "unrecognized processor" errors and empty base feature sets. Therefore, this commit sets `cpu` to "avr2", a more obviously correct choice, and what the current LLVM pathway is effectively doing behind the scenes. You might think this would change the code generated by default, but `avr-none` has `need_explicit_cpu` set to true, so that's not the case, because a missing `-Ctarget-cpu` will trigger a fatal error before codegen. But `cpu` can still reach non-codegen paths (e.g. feature/cfg computation in session setup, and `--print`) so we need a valid backend name. A consequence of this is that `--print target-spec-json` will emit `cpu: "avr2"`. Another consequence is that the `requires_consistent_cpu` check will compare a crate built without `-Ctarget-cpu` (non-codegen only) against "avr2" instead of "generic". The commit also modifies two tests. In both cases, the test passes in this commit with or without the explicit `cpu` field. But in the next commit (using the alternative pathway) both tests would fail without the explicit `cpu` field: - `tests/ui/abi/avr-sram.rs` would fail with ``` 'generic' is not a recognized processor for this target (ignoring processor) 'generic' is not a recognized processor for this target (ignoring processor) warning: target feature `sram` must be enabled to ensure that the ABI of the current target can be implemented correctly ``` - `tests/run-make/print-cfg/rmake.rs` would fail because all features would be missing. Finally, the field docs for `TargetOptions` are tweaked to clarify the interplay between `cpu` and `need_explicit_cpu`. --- compiler/rustc_target/src/spec/mod.rs | 9 +++++---- .../rustc_target/src/spec/targets/avr_none.rs | 1 + tests/run-make/print-cfg/rmake.rs | 15 ++++++++++++++- tests/ui/abi/avr-sram.rs | 17 +++++++++++++++-- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a1c8fd304cd94..f0efba6c8aaac 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2260,11 +2260,12 @@ pub struct TargetOptions { /// Extra arguments to pass to the external assembler (when used) pub asm_args: StaticCow<[StaticCow]>, - /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults - /// to "generic". + /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Must be a name the backend + /// accepts. Defaults to "generic" (which some backends won't accept). pub cpu: StaticCow, - /// Whether a cpu needs to be explicitly set. - /// Set to true if there is no default cpu. Defaults to false. + /// Whether a cpu needs to be explicitly set via `-Ctarget-cpu` for codegen to run. (Even if + /// true, `cpu` is still consulted on non-codegen paths such as cfg/feature computation.) + /// Defaults to false. pub need_explicit_cpu: bool, /// Whether `-Ctarget-cpu` is treated as a target modifier. If this is set /// all crates that are linked together must have been compiled with the diff --git a/compiler/rustc_target/src/spec/targets/avr_none.rs b/compiler/rustc_target/src/spec/targets/avr_none.rs index 0dcd2428fc703..d4b0bf64206c7 100644 --- a/compiler/rustc_target/src/spec/targets/avr_none.rs +++ b/compiler/rustc_target/src/spec/targets/avr_none.rs @@ -14,6 +14,7 @@ pub(crate) fn target() -> Target { pointer_width: 16, options: TargetOptions { c_int_width: 16, + cpu: "avr2".into(), exe_suffix: ".elf".into(), linker: Some("avr-gcc".into()), eh_frame_header: false, diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index d5de89c0de151..62b28ef84909d 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -14,7 +14,7 @@ use std::collections::HashSet; use std::iter::FromIterator; use std::path::PathBuf; -use run_make_support::{rfs, rustc}; +use run_make_support::{llvm_components_contain, rfs, rustc}; struct PrintCfg { target: &'static str, @@ -73,6 +73,19 @@ fn main() { includes: &["target_has_threads"], disallow: &[], }); + // AVR is experimental, so don't assume it's supported. + if llvm_components_contain("avr") { + check(PrintCfg { + target: "avr-none", + args: &[], + includes: &[ + "target_feature=\"addsubiw\"", + "target_feature=\"ijmpcall\"", + "target_feature=\"lpm\"", + ], + disallow: &[], + }); + } } fn check(PrintCfg { target, args, includes, disallow }: PrintCfg) { diff --git a/tests/ui/abi/avr-sram.rs b/tests/ui/abi/avr-sram.rs index 0266f7d6b22ca..7b8ec5ee8fa0c 100644 --- a/tests/ui/abi/avr-sram.rs +++ b/tests/ui/abi/avr-sram.rs @@ -1,12 +1,25 @@ -//@ revisions: has_sram no_sram disable_sram -//@ build-pass +//@ revisions: has_sram no_sram disable_sram default_cpu +// +//@[has_sram] build-pass //@[has_sram] compile-flags: --target avr-none -C target-cpu=atmega328p //@[has_sram] needs-llvm-components: avr +// +//@[no_sram] build-pass //@[no_sram] compile-flags: --target avr-none -C target-cpu=attiny11 //@[no_sram] needs-llvm-components: avr +// +//@[disable_sram] build-pass //@[disable_sram] compile-flags: --target avr-none -C target-cpu=atmega328p -C target-feature=-sram //@[disable_sram] needs-llvm-components: avr +// +// Note: this revision relies on `need_explicit_cpu` only being enforced at codegen, which is why +// it uses `check-pass` instead of `build-pass`. +//@[default_cpu] check-pass +//@[default_cpu] compile-flags: --target avr-none +//@[default_cpu] needs-llvm-components: avr +// //@ ignore-backends: gcc +// //[no_sram,disable_sram]~? WARN target feature `sram` must be enabled //[disable_sram]~? WARN target feature `sram` cannot be disabled with `-Ctarget-feature` From 0911b0a3feb3b68632274a93a6c5eaf3a2023ea4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 31 Aug 2026 10:02:13 +1000 Subject: [PATCH 05/56] Simplify `OwnedTargetMachine` The `repr(transparent)` isn't necessary: there are no casts or transmutes involving it, and it's not passed by value across an FFI boundary. The `PhantomData` also isn't necessary: the type isn't generic so variance isn't a factor; the `Drop` impl doesn't involve `may_dangle`; and the `NonNull` field means the type is `!Send`/`!Sync` with or without the `PhantomData`. --- compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 350d4ce9ee331..5b1046817c904 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -1,5 +1,4 @@ use std::ffi::CStr; -use std::marker::PhantomData; use std::ptr::NonNull; use rustc_data_structures::small_c_str::SmallCStr; @@ -9,10 +8,8 @@ use crate::llvm; /// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions. /// Not cloneable as there is no clone function for llvm::TargetMachine. -#[repr(transparent)] pub struct OwnedTargetMachine { tm_unique: NonNull, - phantom: PhantomData, } impl OwnedTargetMachine { @@ -71,7 +68,7 @@ impl OwnedTargetMachine { }; NonNull::new(tm_ptr) - .map(|tm_unique| Self { tm_unique, phantom: PhantomData }) + .map(|tm_unique| Self { tm_unique }) .ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) }) } From 7f0581d42e299ea0824c13338832daa20d442e62 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Aug 2026 09:15:34 +1000 Subject: [PATCH 06/56] Fix initialization cycle in `target_config` `llvm::target_config` creates `target_machine` by calling `create_informational_target_machine`, which calls `target_machine_factory`, which uses `internal_target_features`. But this is just before `internal_target_features` is initialized! So we should move `internal_target_features` initialization before `target_machine`, right? But `internal_target_features` initialization involves a closure that inspects `target_machine`. There is a cyclic dependency. There is enough function nesting here that it's hard to spot. In practice this cycle doesn't cause problems because the closure doesn't inspect the parts of `target_machine` that depend on `internal_target_features`. But it demonstrates how startup initialization is all tangled up, and it's blocking some cleanups I am doing in #161432 relating to the dangerous uses of `Session` before it's fully initialized. Therefore, this commit changes the first part: instead of creating an `OwnedTargetMachine` we create an `OwnedMCSubtargetInfo`. This is a smaller type that has the feature information we need but doesn't depend on `internal_target_features`. Under the covers we are now using LLVM's `Target::createMCSubtargetInfo` instead of `TargetMachine::getMCSubtargetInfo` so that we avoid having to create a `TargetMachine` at this early stage. This eliminates the cycle. (`TargetMachine` can still be created later on, once we're past this fraught initialization.) There are some slight differences between these two approaches, and the preceding commits fixed up some issues there. Some details about this commit: - The new `OwnedMCSubtargetInfo` is similar to the existing `OwnedTargetMachine`. - `create_informational_target_machine` no longer needs a `for_cfg` parameter, because the one site where `for_cfg` was true has been removed. - `LLVMRustCreateMCSubtargetInfo` mostly replicates part of `LLVMRustCreateTargetMachine` - `LLVMRustMCSubtargetInfoHasFeature` partly replicates `LLVMRustHasFeature`. - `LLVMRustHasFeature` is no longer needed. - The error message for `custom-target-invalid-llvm-target.rs` changed. --- compiler/rustc_codegen_llvm/src/back/mod.rs | 1 + .../src/back/owned_mc_subtarget_info.rs | 49 +++++++++++++++++++ .../src/back/owned_target_machine.rs | 2 +- compiler/rustc_codegen_llvm/src/back/write.rs | 12 ++--- compiler/rustc_codegen_llvm/src/context.rs | 2 +- .../rustc_codegen_llvm/src/diagnostics.rs | 5 ++ compiler/rustc_codegen_llvm/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 15 +++++- compiler/rustc_codegen_llvm/src/llvm_util.rs | 24 ++++++--- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 30 +++++++++--- .../custom-target-invalid-llvm-target.rs | 2 +- .../custom-target-invalid-llvm-target.stderr | 2 +- 12 files changed, 118 insertions(+), 30 deletions(-) create mode 100644 compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs diff --git a/compiler/rustc_codegen_llvm/src/back/mod.rs b/compiler/rustc_codegen_llvm/src/back/mod.rs index 6cb89f80ab89a..de6007c17bfff 100644 --- a/compiler/rustc_codegen_llvm/src/back/mod.rs +++ b/compiler/rustc_codegen_llvm/src/back/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod archive; pub(crate) mod lto; +pub(crate) mod owned_mc_subtarget_info; pub(crate) mod owned_target_machine; mod profiling; pub(crate) mod write; diff --git a/compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs b/compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs new file mode 100644 index 0000000000000..f57368e755add --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/back/owned_mc_subtarget_info.rs @@ -0,0 +1,49 @@ +use std::ffi::CStr; +use std::ptr::NonNull; + +use rustc_data_structures::small_c_str::SmallCStr; + +use crate::diagnostics::LlvmError; +use crate::llvm; + +/// Responsible for safely creating and disposing llvm::MCSubtargetInfo via ffi functions. +/// Not cloneable as there is no clone function for llvm::MCSubtargetInfo. +pub(crate) struct OwnedMCSubtargetInfo { + info_unique: NonNull, +} + +impl OwnedMCSubtargetInfo { + pub(crate) fn new( + triple: &CStr, + cpu: &CStr, + features: &CStr, + ) -> Result> { + // SAFETY: llvm::LLVMRustCreateMCSubtargetInfo copies pointed-to data. + let info_ptr = unsafe { + llvm::LLVMRustCreateMCSubtargetInfo(triple.as_ptr(), cpu.as_ptr(), features.as_ptr()) + }; + + NonNull::new(info_ptr) + .map(|info_unique| Self { info_unique }) + .ok_or_else(|| LlvmError::CreateMCSubtargetInfo { triple: SmallCStr::from(triple) }) + } + + pub(crate) fn has_feature(&self, feature: &CStr) -> bool { + // SAFETY: `new` ensures we have a valid pointer created by + // `llvm::LLVMRustCreateMCSubtargetInfo`. + unsafe { + llvm::LLVMRustMCSubtargetInfoHasFeature(self.info_unique.as_ref(), feature.as_ptr()) + } + } +} + +impl Drop for OwnedMCSubtargetInfo { + fn drop(&mut self) { + // SAFETY: `new` ensures we have a valid pointer created by + // `llvm::LLVMRustCreateMCSubtargetInfo` and `OwnedMCSubtargetInfo` is not copyable so + // there is no double free or use after free. + unsafe { + llvm::LLVMRustDisposeMCSubtargetInfo(self.info_unique); + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 5b1046817c904..5a1dc8080c2c1 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -38,7 +38,7 @@ impl OwnedTargetMachine { use_wasm_eh: bool, large_data_threshold: u64, ) -> Result> { - // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data + // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed-to data. let tm_ptr = unsafe { llvm::LLVMRustCreateTargetMachine( triple.as_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index b8952ffc6bf81..3884f5af7f46a 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -100,17 +100,12 @@ fn write_output_file<'ll>( result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output })) } -/// If `for_cfg` is `true` then we are creating this machine for the purpose of populating -/// [`rustc_codegen_ssa::TargetConfig`] based on what LLVM actually enables in this configuration. -/// `-Ctarget-feature` should be ignored in that case since it is already processed separately. -pub(crate) fn create_informational_target_machine( - sess: &Session, - for_cfg: bool, -) -> OwnedTargetMachine { +pub(crate) fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine { let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None }; // Can't use query system here quite yet because this function is invoked before the query // system/tcx is set up. - let features = llvm_util::global_llvm_features(sess, for_cfg); + let features = llvm_util::global_llvm_features(sess, /* for_cfg */ false); + target_machine_factory(sess, config::OptLevel::No, &features)(sess.dcx(), config) } @@ -212,7 +207,6 @@ pub(crate) fn target_machine_factory( let code_model = to_llvm_code_model(sess.code_model()); - // This is used to set cfg_has_threads, so all logic must be in this method. let singlethread = sess.target.singlethread(&sess.internal_target_features); let triple = SmallCStr::new(&versioned_llvm_target(sess)); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 853c4bfc9ca3f..f913bda10052e 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -228,7 +228,7 @@ pub(crate) unsafe fn create_module<'ll>( // Ensure the data-layout values hardcoded remain the defaults. { - let tm = crate::back::write::create_informational_target_machine(sess, false); + let tm = crate::back::write::create_informational_target_machine(sess); unsafe { llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm.raw()); } diff --git a/compiler/rustc_codegen_llvm/src/diagnostics.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs index 54f8ffbb881da..c981b5eaeb730 100644 --- a/compiler/rustc_codegen_llvm/src/diagnostics.rs +++ b/compiler/rustc_codegen_llvm/src/diagnostics.rs @@ -119,6 +119,8 @@ pub(crate) enum LlvmError<'a> { WriteOutput { path: &'a Path }, #[diag("could not create LLVM TargetMachine for triple: {$triple}")] CreateTargetMachine { triple: SmallCStr }, + #[diag("could not create LLVM MCSubtargetInfo for triple: {$triple}")] + CreateMCSubtargetInfo { triple: SmallCStr }, #[diag("failed to run LLVM passes")] RunLlvmPasses, #[diag("failed to write LLVM IR to {$path}")] @@ -145,6 +147,9 @@ impl Diagnostic<'_, G> for WithLlvmError<'_> { CreateTargetMachine { .. } => { msg!("could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}") } + CreateMCSubtargetInfo { .. } => { + msg!("could not create LLVM MCSubtargetInfo for triple: {$triple}: {$llvm_err}") + } RunLlvmPasses => msg!("failed to run LLVM passes: {$llvm_err}"), WriteIr { .. } => msg!("failed to write LLVM IR to {$path}: {$llvm_err}"), PrepareThinLtoContext => { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 552a91ffee071..29fcb69ff28fc 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -247,7 +247,7 @@ impl CodegenBackend for LlvmCodegenBackend { fn provide(&self, providers: &mut Providers) { providers.queries.global_backend_features = - |tcx, ()| llvm_util::global_llvm_features(tcx.sess, false) + |tcx, ()| llvm_util::global_llvm_features(tcx.sess, /* for_cfg */ false) } fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) { @@ -493,7 +493,7 @@ impl ModuleLlvm { ModuleLlvm { llmod_raw, llcx, - tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess, false)), + tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)), } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 05d3bd0b08b95..8551f9b6fb3fe 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -720,6 +720,7 @@ unsafe extern "C" { pub type TargetMachine; } unsafe extern "C" { + pub(crate) type MCSubtargetInfo; pub(crate) type Twine; pub(crate) type DiagnosticInfo; pub(crate) type SMDiagnostic; @@ -2362,7 +2363,6 @@ unsafe extern "C" { pub(crate) fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString); pub(crate) fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString); - pub(crate) fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool; pub(crate) fn LLVMRustTargetHasMnemonic(T: &TargetMachine, s: *const c_char) -> bool; pub(crate) fn LLVMRustPrintTargetCPUs(TM: &TargetMachine, OutStr: &RustString); @@ -2404,6 +2404,19 @@ unsafe extern "C" { LargeDataThreshold: u64, ) -> *mut TargetMachine; + pub(crate) fn LLVMRustCreateMCSubtargetInfo( + TripleStr: *const c_char, + CPU: *const c_char, + Features: *const c_char, + ) -> *mut MCSubtargetInfo; + + pub(crate) fn LLVMRustMCSubtargetInfoHasFeature( + MCInfo: &MCSubtargetInfo, + Feature: *const c_char, + ) -> bool; + + pub(crate) fn LLVMRustDisposeMCSubtargetInfo(MCInfo: ptr::NonNull); + pub(crate) fn LLVMRustAddLibraryInfo<'a>( T: &TargetMachine, PM: &PassManager<'a>, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index cebc3ffc2bbdd..7090e21e863df 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,6 +6,7 @@ use std::sync::Once; use std::{ptr, slice, str}; use libc::c_int; +use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::target_features::internal_target_features; use rustc_codegen_ssa::{TargetConfig, target_features}; @@ -20,7 +21,8 @@ use rustc_target::spec::{ }; use smallvec::{SmallVec, smallvec}; -use crate::back::write::create_informational_target_machine; +use crate::back::owned_mc_subtarget_info::OwnedMCSubtargetInfo; +use crate::back::write::{create_informational_target_machine, llvm_err}; use crate::{diagnostics, llvm}; static INIT: Once = Once::new(); @@ -318,7 +320,14 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option TargetConfig { - let target_machine = create_informational_target_machine(sess, true); + require_inited(); + let target_features = global_llvm_features(sess, /* for_cfg */ true); + + let triple = SmallCStr::new(&versioned_llvm_target(sess)); + let cpu = SmallCStr::new(target_cpu(sess)); + let features = CString::new(target_features.join(",")).unwrap(); + let mc_subtarget_info = OwnedMCSubtargetInfo::new(&triple, &cpu, &features) + .unwrap_or_else(|err| llvm_err(sess.dcx(), err)); let internal_target_features = internal_target_features( sess, @@ -329,16 +338,17 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig { }, |feature| { // This closure determines whether the target CPU has the feature according to LLVM. We - // do *not* consider the `-Ctarget-feature`s here, as that will be handled later in + // do *not* consider the `-Ctarget-feature`s here (that's why we passed `for_cfg: true` + // to `global_llvm_features` above) because that will be handled later in // `internal_target_features`. if let Some(feat) = to_llvm_features(sess, feature) { // All the LLVM features this expands to must be enabled. for llvm_feature in feat { let cstr = SmallCStr::new(llvm_feature); - // `LLVMRustHasFeature` is moderately expensive. On targets with many + // `has_feature` is moderately expensive. On targets with many // features (e.g. x86) these calls take a non-trivial fraction of runtime // when compiling very small programs. - if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } { + if !mc_subtarget_info.has_feature(&cstr) { return false; } } @@ -479,7 +489,7 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> { pub(crate) fn print(req: &PrintRequest, out: &mut String, sess: &Session) { require_inited(); - let tm = create_informational_target_machine(sess, false); + let tm = create_informational_target_machine(sess); match req.kind { PrintKind::TargetCPUs => print_target_cpus(sess, tm.raw(), out), PrintKind::TargetFeatures => print_target_features(sess, tm.raw(), out), @@ -777,7 +787,7 @@ pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> { pub(crate) fn target_has_mnemonic(sess: &Session, mnemonic: &str) -> bool { require_inited(); - let tm = create_informational_target_machine(sess, false); + let tm = create_informational_target_machine(sess); let cstr = SmallCStr::new(mnemonic); unsafe { llvm::LLVMRustTargetHasMnemonic(tm.raw(), cstr.as_ptr()) } } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 6fd78c6bde4be..0e75c95763bd9 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -91,15 +91,31 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char *FileName) { timeTraceProfilerCleanup(); } -extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, - const char *Feature) { - TargetMachine *Target = unwrap(TM); -#if LLVM_VERSION_GE(23, 0) - const MCSubtargetInfo &MCInfo = Target->getMCSubtargetInfo(); +extern "C" MCSubtargetInfo * +LLVMRustCreateMCSubtargetInfo(const char *TripleStr, const char *CPU, + const char *Features) { + std::string Error; + auto Trip = Triple(Triple::normalize(TripleStr)); + const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip, Error); + if (TheTarget == nullptr) { + LLVMRustSetLastError(Error.c_str()); + return nullptr; + } + +#if LLVM_VERSION_GE(22, 0) + return TheTarget->createMCSubtargetInfo(Trip, CPU, Features); #else - const MCSubtargetInfo &MCInfo = *Target->getMCSubtargetInfo(); + return TheTarget->createMCSubtargetInfo(Trip.str(), CPU, Features); #endif - return MCInfo.checkFeatures(std::string("+") + Feature); +} + +extern "C" bool LLVMRustMCSubtargetInfoHasFeature(MCSubtargetInfo *MCInfo, + const char *Feature) { + return MCInfo->checkFeatures(std::string("+") + Feature); +} + +extern "C" void LLVMRustDisposeMCSubtargetInfo(MCSubtargetInfo *MCInfo) { + delete MCInfo; } /// Check whether the target has a specific assembly mnemonic like `ret` or diff --git a/tests/ui/codegen/custom-target-invalid-llvm-target.rs b/tests/ui/codegen/custom-target-invalid-llvm-target.rs index 72c80cd7af4f1..d90b56c5d13c0 100644 --- a/tests/ui/codegen/custom-target-invalid-llvm-target.rs +++ b/tests/ui/codegen/custom-target-invalid-llvm-target.rs @@ -7,4 +7,4 @@ fn main() {} -//~? ERROR failed to parse target machine config to target machine +//~? ERROR could not create LLVM MCSubtargetInfo for triple: not-a-real-target diff --git a/tests/ui/codegen/custom-target-invalid-llvm-target.stderr b/tests/ui/codegen/custom-target-invalid-llvm-target.stderr index d5ac437a2b646..e2e844fa1bce7 100644 --- a/tests/ui/codegen/custom-target-invalid-llvm-target.stderr +++ b/tests/ui/codegen/custom-target-invalid-llvm-target.stderr @@ -1,2 +1,2 @@ -error: failed to parse target machine config to target machine: could not create LLVM TargetMachine for triple: not-a-real-target +error: could not create LLVM MCSubtargetInfo for triple: not-a-real-target: No available targets are compatible with triple "not-a-real-target" From bc21abbd79ba45a2a770dde28f26479ccc5a2e4e Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 3 Sep 2026 07:43:04 -0400 Subject: [PATCH 07/56] Garbage-collect old incremental compilation sessions --- compiler/rustc_incremental/src/persist/fs.rs | 8 +++-- .../run-make/incremental-session-gc/empty.rs | 2 ++ .../run-make/incremental-session-gc/rmake.rs | 33 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/run-make/incremental-session-gc/empty.rs create mode 100644 tests/run-make/incremental-session-gc/rmake.rs diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index de543ef0c53bc..6dcccccf0d31a 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -702,8 +702,10 @@ pub(crate) fn garbage_collect_session_directories( lock_file_to_session_dir.items().filter_map(|(lock_file_name, directory_name)| { debug!("garbage_collect_session_directories() - inspecting: {}", directory_name); - if directory_name.as_str() == current_session_directory_name { - // Skipping our own directory is, unfortunately, important for correctness. + if directory_name.as_str() == current_session_directory_name + && !is_finalized(directory_name) + { + // Skipping our own active directory is important for correctness. // // To summarize #147821: we will try to lock directories before deciding they can be // garbage collected, but the ability of `flock::Lock` to detect a lock held *by the @@ -722,6 +724,8 @@ pub(crate) fn garbage_collect_session_directories( // It's not clear that `flock::Lock` can be fixed for this in general, and our own // incremental session directory is the only one which this process may own, so skip // it here and avoid the problem. We know it's not garbage anyway: we're using it. + // Once finalized, its lock is released. Include it in collection so we keep only + // the newest completed session. return None; } diff --git a/tests/run-make/incremental-session-gc/empty.rs b/tests/run-make/incremental-session-gc/empty.rs new file mode 100644 index 0000000000000..da27b7f3463da --- /dev/null +++ b/tests/run-make/incremental-session-gc/empty.rs @@ -0,0 +1,2 @@ +#![feature(no_core)] +#![no_core] diff --git a/tests/run-make/incremental-session-gc/rmake.rs b/tests/run-make/incremental-session-gc/rmake.rs new file mode 100644 index 0000000000000..a8ffe15b26dfb --- /dev/null +++ b/tests/run-make/incremental-session-gc/rmake.rs @@ -0,0 +1,33 @@ +//! Successful sequential builds should retain only the newest incremental session. +//! The current session must participate in garbage collection once it is finalized. + +use std::path::PathBuf; + +use run_make_support::{rfs, rustc, shallow_find_directories}; + +fn main() { + let compile = || { + rustc().input("empty.rs").crate_type("rlib").emit("metadata").incremental("incr").run(); + }; + + compile(); + let mut previous = session_dir(); + rfs::write(previous.join("sentinel"), "previous session"); + + for _ in 0..2 { + compile(); + let current = session_dir(); + assert_ne!(previous, current); + assert!(!previous.exists(), "superseded session was not collected: {previous:?}"); + assert_eq!(rfs::read_to_string(current.join("sentinel")), "previous session"); + previous = current; + } +} + +fn session_dir() -> PathBuf { + let crate_dirs = shallow_find_directories("incr", |_| true); + assert_eq!(crate_dirs.len(), 1); + let sessions = shallow_find_directories(&crate_dirs[0], |_| true); + assert_eq!(sessions.len(), 1, "expected only the newest completed session: {sessions:?}"); + sessions.into_iter().next().unwrap() +} From f178bea2aa40b5b9840caded683a5b4b7f5e208a Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 4 Sep 2026 12:34:09 -0400 Subject: [PATCH 08/56] Preserve the current finalized incremental session --- compiler/rustc_incremental/src/persist/fs.rs | 6 +++++- tests/run-make/incremental-session-gc/rmake.rs | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 6dcccccf0d31a..a62250139e36e 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -724,7 +724,7 @@ pub(crate) fn garbage_collect_session_directories( // It's not clear that `flock::Lock` can be fixed for this in general, and our own // incremental session directory is the only one which this process may own, so skip // it here and avoid the problem. We know it's not garbage anyway: we're using it. - // Once finalized, its lock is released. Include it in collection so we keep only + // Once finalized, its lock is released. Include it in collection so we keep // the newest completed session. return None; } @@ -822,6 +822,10 @@ pub(crate) fn garbage_collect_session_directories( // Delete all but the most recent of the candidates all_except_most_recent(deletion_candidates).into_items().all(|(path, lock)| { + if path.file_name() == Some(current_session_directory_name) { + return true; + } + debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); if let Err(err) = std_fs::remove_dir_all(&path) { diff --git a/tests/run-make/incremental-session-gc/rmake.rs b/tests/run-make/incremental-session-gc/rmake.rs index a8ffe15b26dfb..dd4b300a5ced0 100644 --- a/tests/run-make/incremental-session-gc/rmake.rs +++ b/tests/run-make/incremental-session-gc/rmake.rs @@ -22,6 +22,23 @@ fn main() { assert_eq!(rfs::read_to_string(current.join("sentinel")), "previous session"); previous = current; } + + let crate_dir = previous.parent().unwrap(); + let (prefix, hash) = previous.file_name().unwrap().to_str().unwrap().rsplit_once('-').unwrap(); + let newer = crate_dir.join(format!("s-zzzzzzzzzz-0000000-{hash}")); + rfs::rename(&previous, &newer); + rfs::rename( + crate_dir.join(format!("{prefix}.lock")), + crate_dir.join("s-zzzzzzzzzz-0000000.lock"), + ); + + compile(); + let sessions = shallow_find_directories(crate_dir, |_| true); + assert_eq!(sessions.len(), 2, "{sessions:?}"); + assert!(sessions.contains(&newer)); + let current = sessions.into_iter().find(|session| *session != newer).unwrap(); + assert!(!current.file_name().unwrap().to_str().unwrap().ends_with("-working")); + assert_eq!(rfs::read_to_string(current.join("sentinel")), "previous session"); } fn session_dir() -> PathBuf { From 768091d99822f98e57b3e41413c819b95281ff3b Mon Sep 17 00:00:00 2001 From: Aditya Pratap Singh Date: Sat, 5 Sep 2026 01:14:27 +0530 Subject: [PATCH 09/56] fix: don't panic on doc comments attached to literal expressions --- src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs | 2 +- src/tools/rust-analyzer/crates/syntax/src/tests.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs index ced9163f661af..2b1c91f20517d 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs @@ -335,7 +335,7 @@ impl ast::Literal { pub fn token(&self) -> SyntaxToken { self.syntax() .children_with_tokens() - .find(|e| e.kind() != ATTR && !e.kind().is_trivia()) + .find(|e| !ast::AnyAttr::can_cast(e.kind()) && !e.kind().is_trivia()) .and_then(|e| e.into_token()) .unwrap() } diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests.rs b/src/tools/rust-analyzer/crates/syntax/src/tests.rs index e5beb44f42ec7..1002fdd902d29 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/tests.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/tests.rs @@ -126,6 +126,12 @@ fn self_hosting_parsing() { } } +#[test] +fn doc_comment_on_literal_expr() { + let parse = SourceFile::parse("fn f() { ///\n0..0; }", parser::Edition::CURRENT); + assert!(parse.errors().is_empty()); +} + fn test_data_dir() -> PathBuf { project_root().into_std_path_buf().join("crates/syntax/test_data") } From f8326c98fc14ad6fea7cbf8fd5e058cbc46f2df6 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 6 Sep 2026 19:28:10 +0500 Subject: [PATCH 10/56] ide: fix doc comment offset calculation --- .../rust-analyzer/crates/ide/src/doc_links.rs | 5 ++- .../crates/ide/src/goto_definition.rs | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index c152d7e9cc964..94e7db9390bc3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -312,7 +312,10 @@ impl DocCommentToken { let DocCommentToken { prefix_len, doc_token } = self; // offset relative to the comments contents let original_start = doc_token.text_range().start(); - let relative_comment_offset = offset - original_start - prefix_len; + // If the cursor points inside the comment like `///` or to the first quote in `#[doc = "..."]` + // (i.e. relative_comment_offset is None) then we return w/o definition. + let relative_comment_offset = + offset.checked_sub(original_start)?.checked_sub(prefix_len)?; sema.descend_into_macros(doc_token).into_iter().find_map(|t| { let (node, descended_prefix_len, is_inner) = match_ast!{ diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 033de7dcc20b4..bb317525dd5d8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -723,6 +723,13 @@ mod tests { assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}") } + #[track_caller] + fn check_no_definition(#[rust_analyzer::rust_fixture] ra_fixture: &str) { + let (analysis, position) = fixture::position(ra_fixture); + let navs = analysis.goto_definition(position, &TEST_CONFIG).unwrap(); + assert!(navs.is_none(), "didn't expect this to resolve anywhere: {navs:?}"); + } + fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, _) = fixture::annotations(ra_fixture); let navs = analysis @@ -2132,6 +2139,30 @@ pub fn foo() { } ) } + #[test] + fn no_panic_on_offset_inside_doc_comment_prefix() { + // If the cursor (offset) points inside `///`/`//!`/the opening quote, i.e. before the docs' contents, + // this should not create navigation. + check_no_definition( + r#" +$0/// [`S`] +struct S; +"#, + ); + check_no_definition( + r#" +//$0! [`S`] +struct S; +"#, + ); + check_no_definition( + r#" +#[doc = $0"[`S`]"] +struct S; +"#, + ); + } + #[test] fn goto_def_for_intra_doc_link_outer_same_file() { check( From af3f278c5f3e84d40b81b8bcb0beb9715cdb8487 Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Mon, 7 Sep 2026 07:13:35 -0700 Subject: [PATCH 11/56] internal: Add regression test for 'failed to unify type errors' panic The panic was fixed in 7fbbd2039c30fa944ec534d6f54569015b36e939, but it didn't have a test. Add a test as suggested by @A4-Tacks, based on a minimised repro I'd seen (this panic was the most common I'd seen on the latest rust-analyzer version). AI disclosure: Test code with some help by Claude Opus 5, commit message by me. --- .../ide-diagnostics/src/handlers/typed_hole.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index e2d31503f1d08..e93e74177abe8 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -464,6 +464,20 @@ fn main() { m!(generic::); } } +"#, + ); + } + + #[test] + fn term_search_lookup_const() { + check_diagnostics( + r#" +struct S { f: i32 } +const C: i32 = 0; +fn main() { + let _: S = _; + //^ 💡 error: invalid `_` expression, expected type `S` +} "#, ); } From 071f269c78d4032ebe5aea9bbb27974438f81a57 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Thu, 3 Sep 2026 15:22:22 +0200 Subject: [PATCH 12/56] fix: restore the `#[deprecated]` attr Accidentally removed during https://github.com/rust-lang/rust-analyzer/commit/492420db8aadb6535f8c75f38d6b867d2d412295 --- src/tools/rust-analyzer/crates/hir-expand/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index f7ac3f1c02694..e8d61a6eadf63 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -537,6 +537,12 @@ impl MacroCallId { /// query, only typing in the macro call itself changes the returned /// subtree. #[salsa::tracked(returns(ref))] + #[allow( + useless_deprecated, + unused_attributes, + reason = "salsa bug, see https://github.com/salsa-rs/salsa/issues/1307" + )] + #[deprecated = "calling this is incorrect, call `macro_arg_considering_derives` instead"] fn macro_arg(self, db: &dyn SourceDatabase) -> MacroArgResult { let loc = self.loc(db); From ccfeaac5ebe8e533a11588573000ef3961913464 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Tue, 11 Aug 2026 16:40:30 +0200 Subject: [PATCH 13/56] remove `allow`s that are no longer necessary Mostly thanks to FPs having gotten fixed --- src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs | 4 ---- .../rust-analyzer/crates/hir-def/src/hir/format_args.rs | 1 - src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs | 1 - .../crates/hir-ty/src/consteval/tests/intrinsics.rs | 2 +- src/tools/rust-analyzer/crates/hir-ty/src/infer.rs | 5 ----- src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs | 2 -- src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs | 1 - src/tools/rust-analyzer/crates/ide/src/hover.rs | 1 - src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs | 2 +- .../crates/rust-analyzer/tests/slow-tests/main.rs | 1 - src/tools/rust-analyzer/lib/la-arena/src/map.rs | 2 -- src/tools/rust-analyzer/lib/text-size/src/serde_impls.rs | 1 - 12 files changed, 2 insertions(+), 21 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs index c38ceccd1fc09..92400d0715395 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs @@ -119,10 +119,6 @@ pub struct Key { } impl Key { - #[allow( - clippy::new_without_default, - reason = "this a const fn, so it can't be default yet. See " - )] pub(crate) const fn new() -> Key { Key { _phantom: PhantomData } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index 366857f233168..855b16bc28673 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -169,7 +169,6 @@ enum PositionUsedAs { } use PositionUsedAs::*; -#[allow(clippy::unnecessary_lazy_evaluations)] pub(crate) fn parse( s: &ast::String, string_ptr: AstPtr, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 8781358822064..2fda00d6af8d0 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -343,7 +343,6 @@ pub(crate) fn reverse_fixups(tt: &mut TopSubtree, undo_info: &SyntaxFixupUndoInf let top_subtree = tt.top_subtree(); let open_span = top_subtree.delimiter.open; let close_span = top_subtree.delimiter.close; - #[allow(deprecated)] if never!( close_span.anchor.ast_id == FIXUP_DUMMY_AST_ID || open_span.anchor.ast_id == FIXUP_DUMMY_AST_ID diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index 898d9ea8edf3d..1dad8dad73192 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -469,7 +469,7 @@ fn floating_point() { IsSigned::Yes, )), ); - #[allow(unknown_lints, clippy::unnecessary_min_or_max)] + #[allow(clippy::unnecessary_min_or_max)] check_number( r#" #[rustc_intrinsic] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 0ab147096a749..f93c5a2ebbff1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -109,12 +109,7 @@ use crate::{ utils::TargetFeatureIsSafeInTarget, }; -// This lint has a false positive here. See the link below for details. -// -// https://github.com/rust-lang/rust/issues/57411 -#[allow(unreachable_pub)] pub use coerce::could_coerce; -#[allow(unreachable_pub)] pub use unify::{could_unify, could_unify_deeply}; use cast::{CastCheck, CastError}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index d6db51dec52b9..32866c12e23e1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -309,7 +309,6 @@ const STACK_OFFSET: usize = 1 << 30; const HEAP_OFFSET: usize = 1 << 29; impl Address { - #[allow(clippy::double_parens)] fn from_bytes<'db>(it: &[u8]) -> Result<'db, Self> { Ok(Address::from_usize(from_bytes!(usize, it))) } @@ -2093,7 +2092,6 @@ impl<'a, 'db> Evaluator<'a, 'db> { } } - #[allow(clippy::double_parens)] fn allocate_const_in_heap( &mut self, locals: &Locals<'a, 'db>, diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index ab5a0f70f5a69..c87a10d8e85b7 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -315,7 +315,6 @@ impl<'db, 'sema> Matcher<'db, 'sema> { Ok(()) } - #[allow(clippy::only_used_in_recursion)] fn check_constraint( &self, constraint: &Constraint, diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 92473de4e634f..6f5878071aaa8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -156,7 +156,6 @@ pub(crate) fn hover( Some(res) } -#[allow(clippy::field_reassign_with_default)] fn hover_offset( sema: &Semantics<'_, RootDatabase>, FilePosition { file_id, offset }: FilePosition, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 7fc04a05155f8..c3255b7c86d6c 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -10,7 +10,7 @@ #![cfg(feature = "in-rust-tree")] #![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span, rustc_private)] -#![expect(internal_features, clippy::disallowed_types, clippy::print_stderr)] +#![expect(internal_features)] #![allow(unused_features, unused_crate_dependencies)] #![deny(deprecated_safe, clippy::undocumented_unsafe_blocks)] #![cfg_attr(test, expect(unreachable_pub))] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 56629f79ea216..4199cb29e66d2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -8,7 +8,6 @@ //! specific JSON shapes here -- there's little value in such tests, as we can't //! be sure without a real client anyway. -#![allow(clippy::disallowed_types)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] diff --git a/src/tools/rust-analyzer/lib/la-arena/src/map.rs b/src/tools/rust-analyzer/lib/la-arena/src/map.rs index 6e7528c4f7fd4..5aa36e7ae74ac 100644 --- a/src/tools/rust-analyzer/lib/la-arena/src/map.rs +++ b/src/tools/rust-analyzer/lib/la-arena/src/map.rs @@ -252,8 +252,6 @@ where { /// Ensures a value is in the entry by inserting the default value if empty, and returns a mutable reference /// to the value in the entry. - // BUG this clippy lint is a false positive - #[allow(clippy::unwrap_or_default)] pub fn or_default(self) -> &'a mut V { self.or_insert_with(Default::default) } diff --git a/src/tools/rust-analyzer/lib/text-size/src/serde_impls.rs b/src/tools/rust-analyzer/lib/text-size/src/serde_impls.rs index 4cd41618c2d7a..6b555d2a99c1b 100644 --- a/src/tools/rust-analyzer/lib/text-size/src/serde_impls.rs +++ b/src/tools/rust-analyzer/lib/text-size/src/serde_impls.rs @@ -31,7 +31,6 @@ impl Serialize for TextRange { } impl<'de> Deserialize<'de> for TextRange { - #[allow(clippy::nonminimal_bool)] fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, From 1aa9a9e22ccfba52b79d64af249050af89762ab3 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 8 Sep 2026 04:51:31 +0300 Subject: [PATCH 14/56] Fix `hir::Type` owner mismatches between anon consts By not giving anon consts their own owner. This eases work and does not cause harm. I had to revert making `TypeOwnerId` lifetime'd unfortunately but it was not hard (so it won't be hard to put it back when needed). --- .../crates/hir/src/diagnostics.rs | 14 +++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 63 ++++++++----------- .../crates/hir/src/source_analyzer.rs | 2 +- .../src/handlers/type_mismatch.rs | 21 +++++++ 4 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 5c3b628f386d5..a1ff564edcf56 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -1175,7 +1175,11 @@ impl<'a, 'db> DiagnosticsCollector<'a, 'db> { } fn collect_anon_const(&mut self, source_map: &ExpressionStoreSourceMap, def: AnonConstId<'db>) { - self.emit_inference_errors(def.into(), source_map, def.into()); + self.emit_inference_errors( + def.into(), + source_map, + TypeOwnerId::from_anon_const(def, self.db), + ); } fn collect_enum(&mut self, def: EnumId) { @@ -1232,7 +1236,7 @@ impl<'a, 'db> DiagnosticsCollector<'a, 'db> { } } - fn collect_def_with_body(&mut self, def: DefWithBodyId, type_owner: TypeOwnerId<'db>) { + fn collect_def_with_body(&mut self, def: DefWithBodyId, type_owner: TypeOwnerId) { let (body, source_map) = Body::with_source_map(self.db, def); self.collect_expr_store(body, source_map); @@ -1284,7 +1288,7 @@ impl<'a, 'db> DiagnosticsCollector<'a, 'db> { &mut self, def: InferBodyId<'db>, source_map: &ExpressionStoreSourceMap, - type_owner: TypeOwnerId<'db>, + type_owner: TypeOwnerId, ) { let infer = InferenceResult::of(self.db, def); @@ -1548,7 +1552,7 @@ impl<'db> AnyDiagnostic<'db> { edition: Edition, d: &'db InferenceDiagnostic, source_map: &ExpressionStoreSourceMap, - type_owner: TypeOwnerId<'db>, + type_owner: TypeOwnerId, ) -> Option> { let expr_syntax = |expr| Self::expr_syntax(expr, source_map); let pat_syntax = |pat| Self::pat_syntax(pat, source_map); @@ -1918,7 +1922,7 @@ impl<'db> AnyDiagnostic<'db> { db: &'db dyn HirDatabase, d: &'db SolverDiagnosticKind, span: SpanSyntax, - type_owner: TypeOwnerId<'db>, + type_owner: TypeOwnerId, ) -> Option> { let interner = DbInterner::new_no_crate(db); Some(match d { diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 34b9ede4985a6..6dd85ebc8814a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1299,7 +1299,7 @@ impl<'db> AnonConst<'db> { pub fn ty(self, db: &'db dyn HirDatabase) -> Type<'db> { let loc = self.id.loc(db); - Type { owner: self.id.into(), ty: loc.ty.get() } + Type { owner: TypeOwnerId::from_anon_const(self.id, db), ty: loc.ty.get() } } pub fn eval( @@ -1550,7 +1550,7 @@ impl Function { } } - fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId<'db>, PolyFnSig<'db>) { + fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId, PolyFnSig<'db>) { let fn_ptr = self.fn_ptr_type(db); let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.skip_binder().kind() else { unreachable!(); @@ -1558,7 +1558,7 @@ impl Function { (fn_ptr.owner, sig_tys.with(hdr)) } - fn erased_fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId<'db>, FnSig<'db>) { + fn erased_fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (TypeOwnerId, FnSig<'db>) { let (owner, sig) = self.fn_sig(db); let sig = DbInterner::new_no_crate(db).instantiate_bound_regions_with_erased(sig); (owner, sig) @@ -3124,21 +3124,17 @@ impl GenericDef { // We cannot call this `Substitution` unfortunately... #[derive(Debug)] pub struct GenericSubstitution<'db> { - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, def: GenericDefId, subst: GenericArgs<'db>, } impl<'db> GenericSubstitution<'db> { - fn new(def: GenericDefId, subst: GenericArgs<'db>, owner: TypeOwnerId<'db>) -> Self { + fn new(def: GenericDefId, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Self { Self { owner, def, subst } } - fn new_from_fn( - def: Function, - subst: GenericArgs<'db>, - owner: TypeOwnerId<'db>, - ) -> Option { + fn new_from_fn(def: Function, subst: GenericArgs<'db>, owner: TypeOwnerId) -> Option { match def.id { AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, owner)), AnyFunctionId::BuiltinDeriveImplMethod { .. } => None, @@ -3965,7 +3961,7 @@ impl Impl { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TraitRef<'db> { - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, trait_ref: hir_ty::next_solver::TraitRef<'db>, } @@ -4003,7 +3999,7 @@ enum AnyClosureId<'db> { #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Closure<'db> { - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, id: AnyClosureId<'db>, subst: GenericArgs<'db>, } @@ -4347,23 +4343,26 @@ impl CaptureUsageSource { } #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -enum TypeOwnerId<'db> { +enum TypeOwnerId { GenericDefId(GenericDefId), BuiltinDeriveImplId(BuiltinDeriveImplId), - AnonConstId(AnonConstId<'db>), // FIXME: What do when we unify two different crates? Currently we just randomly keep one. NoParams(base_db::Crate), } impl_from!( - impl<'db> GenericDefId, - BuiltinDeriveImplId, - AnonConstId<'db> - for TypeOwnerId<'db> + BuiltinDeriveImplId + for TypeOwnerId ); -impl TypeOwnerId<'_> { +impl TypeOwnerId { + /// We associated anon consts with their parent, because they can never have generics of their own. + /// It can have *less* than the parent, but providing more generic args is not a problem. + fn from_anon_const<'db>(id: AnonConstId<'db>, db: &'db dyn HirDatabase) -> TypeOwnerId { + TypeOwnerId::GenericDefId(id.loc(db).owner.generic_def(db)) + } + fn unify(self, other: Self) -> Option { match (self, other) { (TypeOwnerId::NoParams(_), owner) => Some(owner), @@ -4394,7 +4393,7 @@ impl TypeOwnerId<'_> { } let self_def = match self { TypeOwnerId::GenericDefId(def) => def, - TypeOwnerId::BuiltinDeriveImplId(_) | TypeOwnerId::AnonConstId(_) => return false, + TypeOwnerId::BuiltinDeriveImplId(_) => return false, TypeOwnerId::NoParams(_) => return true, }; let self_def = match self_def { @@ -4408,9 +4407,7 @@ impl TypeOwnerId<'_> { }; let rebase_into_def = match rebase_into { TypeOwnerId::GenericDefId(def) => def, - TypeOwnerId::BuiltinDeriveImplId(_) - | TypeOwnerId::AnonConstId(_) - | TypeOwnerId::NoParams(_) => return false, + TypeOwnerId::BuiltinDeriveImplId(_) | TypeOwnerId::NoParams(_) => return false, }; let rebase_into_parent = match rebase_into_def { GenericDefId::ConstId(def) => def.loc(db).container, @@ -4429,7 +4426,7 @@ impl TypeOwnerId<'_> { /// with types of different origins will cause errors or panics. Instead, use the `instantiate` methods. #[derive(Clone, Debug)] pub struct Type<'db> { - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, ty: EarlyBinder<'db, Ty<'db>>, } @@ -4513,7 +4510,6 @@ impl<'db> Type<'db> { TypeOwnerId::BuiltinDeriveImplId(def) => { GenericArgs::error_for_item(interner, def.into()) } - TypeOwnerId::AnonConstId(def) => GenericArgs::error_for_item(interner, def.into()), TypeOwnerId::NoParams(_) => GenericArgs::empty(interner), }; Type::no_params(krate, self.ty.instantiate(interner, args).skip_norm_wip()) @@ -4527,7 +4523,6 @@ impl<'db> Type<'db> { TypeOwnerId::BuiltinDeriveImplId(def) => { generic_args_from_tys(interner, def.into(), args) } - TypeOwnerId::AnonConstId(def) => generic_args_from_tys(interner, def.into(), args), TypeOwnerId::NoParams(krate) => { (GenericArgs::empty(interner), TypeOwnerId::NoParams(krate)) } @@ -4546,7 +4541,6 @@ impl<'db> Type<'db> { let owner = match ty.owner { TypeOwnerId::GenericDefId(def) => def.into(), TypeOwnerId::BuiltinDeriveImplId(def) => def.into(), - TypeOwnerId::AnonConstId(def) => def.into(), TypeOwnerId::NoParams(_) => return ty.ty.skip_binder(), }; let args = GenericArgs::for_item(infcx.interner, owner, |_, param, _, _| { @@ -4624,7 +4618,7 @@ impl<'db> Type<'db> { tys: impl IntoIterator>>, ) -> Self { let interner = DbInterner::new_no_crate(db); - let mut owner = None::>; + let mut owner = None::; let ty = EarlyBinder::bind(Ty::new_tup_from_iter( interner, tys.into_iter().map(|ty| { @@ -4840,7 +4834,6 @@ impl<'db> Type<'db> { TypeOwnerId::BuiltinDeriveImplId(def) => { hir_def::HasModule::krate(&def.loc(db).adt, db) } - TypeOwnerId::AnonConstId(def) => hir_def::HasModule::krate(&def, db), TypeOwnerId::NoParams(krate) => krate, } } @@ -4856,10 +4849,6 @@ impl<'db> Type<'db> { param_env: hir_ty::builtin_derive::param_env(interner, def), krate, }, - TypeOwnerId::AnonConstId(def) => ParamEnvAndCrate { - param_env: db.trait_environment(def.loc(db).owner.generic_def(db)), - krate, - }, TypeOwnerId::NoParams(_) => { ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate } } @@ -5681,7 +5670,7 @@ impl<'db> Type<'db> { pub fn walk(&self, db: &'db dyn HirDatabase, callback: impl FnMut(Type<'db>)) { struct Visitor<'db, F> { db: &'db dyn HirDatabase, - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, callback: F, visited: FxHashSet>, } @@ -6144,7 +6133,7 @@ pub enum PredicatePolarity { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitPredicate<'db> { inner: hir_ty::next_solver::TraitPredicate<'db>, - owner: TypeOwnerId<'db>, + owner: TypeOwnerId, } impl<'db> TraitPredicate<'db> { @@ -6549,8 +6538,8 @@ fn generic_args_from_tys<'db>( interner: DbInterner<'db>, def_id: SolverDefId<'db>, args: impl IntoIterator>>, -) -> (GenericArgs<'db>, TypeOwnerId<'db>) { - let mut owner = None::>; +) -> (GenericArgs<'db>, TypeOwnerId) { + let mut owner = None::; let mut args = args.into_iter(); let args = GenericArgs::for_item(interner, def_id, |_, id, _, _| { if matches!(id, GenericParamId::TypeParamId(_)) diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 907193fe1d7ff..021b89677d283 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -78,7 +78,7 @@ pub(crate) struct SourceAnalyzer<'db> { pub(crate) file_id: HirFileId, pub(crate) resolver: Resolver<'db>, pub(crate) body_or_sig: Option>, - pub(crate) type_owner: TypeOwnerId<'db>, + pub(crate) type_owner: TypeOwnerId, pub(crate) infer_body: Option>, } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index f70795ed29bde..1e92a795e47a9 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -2019,4 +2019,25 @@ fn test(_: Result) { "#, ); } + + #[test] + fn regression_23313() { + check_diagnostics( + r#" +fn hello_world() {} + +struct Wrapper ()>; + +impl ()> Wrapper<{ + Wrapper::<{hello_world}>::call(); + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no such associated item + }> { +//^ 💡 error: expected fn(), found () + fn hello_world() { + F(); + } +} + "#, + ); + } } From 0de0415a3747f6df951c3c5d23df86e897bde813 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 8 Sep 2026 04:53:16 +0300 Subject: [PATCH 15/56] Remove some unused code --- .../crates/hir-ty/src/diagnostics.rs | 5 +---- .../hir-ty/src/diagnostics/unsafe_check.rs | 19 ------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs index 047a348fb09a7..17ec211bb579c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs @@ -9,8 +9,5 @@ pub use crate::diagnostics::{ expr::{ BodyValidationDiagnostic, record_literal_missing_fields, record_pattern_missing_fields, }, - unsafe_check::{ - InsideUnsafeBlock, UnsafetyReason, missing_unsafe, unsafe_operations, - unsafe_operations_for_body, - }, + unsafe_check::{InsideUnsafeBlock, UnsafetyReason, missing_unsafe, unsafe_operations}, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index ca843c8690f28..bc2e21d0e16e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -101,25 +101,6 @@ enum UnsafeDiagnostic { DeprecatedSafe2024 { node: ExprId, inside_unsafe_block: InsideUnsafeBlock }, } -pub fn unsafe_operations_for_body( - db: &dyn HirDatabase, - infer: &InferenceResult<'_>, - def: DefWithBodyId, - body: &Body, - callback: &mut dyn FnMut(ExprOrPatId), -) { - let mut visitor_callback = |diag| { - if let UnsafeDiagnostic::UnsafeOperation { node, .. } = diag { - callback(node); - } - }; - let mut visitor = UnsafeVisitor::new(db, infer, body, def.into(), &mut visitor_callback); - visitor.walk_expr(body.root_expr()); - for param in &body.params { - visitor.walk_pat(param.formal); - } -} - pub fn unsafe_operations( db: &dyn HirDatabase, infer: &InferenceResult<'_>, From a57cd314e0f6c61386d98a5989439800e766ed69 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 8 Sep 2026 07:30:12 +0300 Subject: [PATCH 16/56] Do not fill the body for `Drop::drop()` and `#[rustc_must_implement_one_of]` When invoking the "Add missing impl members" assist. --- .../src/handlers/add_missing_impl_members.rs | 108 +++++++++++++++++- .../ide-assists/src/handlers/generate_impl.rs | 1 + .../replace_derive_with_manual_impl.rs | 1 + .../crates/ide-assists/src/utils.rs | 6 +- .../crates/test-utils/src/minicore.rs | 6 +- 5 files changed, 117 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 9f9bb1d131548..ebbde8ce3c37d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -161,6 +161,7 @@ fn add_missing_impl_members_inner( trait_, &impl_def, &target_scope, + mode, ); let Some((first_new_item, other_items)) = new_item.split_first() else { @@ -2747,7 +2748,9 @@ pub trait Read { } impl Read for () { - $0fn read_buf() {} + fn read_buf() { + ${0:todo!()} + } } "#, ); @@ -2887,7 +2890,9 @@ pub trait Read { } impl Read for () { - $0fn read() {} + fn read() { + ${0:todo!()} + } } "#, ); @@ -2918,7 +2923,104 @@ pub trait Read { } impl Read for () { - $0fn read_buf() {} + fn read_buf() { + ${0:todo!()} + } +} + "#, + ); + } + + #[test] + fn required_method_with_body() { + check_assist( + add_missing_impl_members, + r#" +//- minicore: drop, pin +struct Foo; + +impl Drop for Foo { + $0 +} + "#, + r#" +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) { + ${0:todo!()} + } +} + "#, + ); + + check_assist( + add_missing_impl_members, + r#" +#[rustc_must_implement_one_of(read_buf, read)] +pub trait Read { + fn read() { + Self::read_buf() + } + fn read_buf() { + Self::read(); + } +} + +impl Read for () { + $0 +} + "#, + r#" +#[rustc_must_implement_one_of(read_buf, read)] +pub trait Read { + fn read() { + Self::read_buf() + } + fn read_buf() { + Self::read(); + } +} + +impl Read for () { + fn read_buf() { + ${0:todo!()} + } +} + "#, + ); + check_assist( + add_missing_default_members, + r#" +#[rustc_must_implement_one_of(read_buf, read)] +pub trait Read { + fn read() { + Self::read_buf() + } + fn read_buf() { + Self::read(); + } +} + +impl Read for () { + $0 +} + "#, + r#" +#[rustc_must_implement_one_of(read_buf, read)] +pub trait Read { + fn read() { + Self::read_buf() + } + fn read_buf() { + Self::read(); + } +} + +impl Read for () { + $0fn read() { + Self::read_buf() + } } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs index d88a94e2f7307..5813a92427cb1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs @@ -205,6 +205,7 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_, '_> hir_trait, &impl_, &target_scope, + DefaultMethods::No, ); let assoc_item_list = make.assoc_item_list(assoc_items); make_impl_(Some(assoc_item_list)) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 8648a013438e7..1ca291c5775a7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -252,6 +252,7 @@ fn impl_def_from_trait( trait_, &impl_def, &target_scope, + DefaultMethods::No, ); let assoc_item_list = if let Some((first, other)) = assoc_items.split_first() { let first_item = if let ast::AssocItem::Fn(func) = first diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index e5e735faf6f93..68e7544e7d76b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -204,6 +204,7 @@ pub fn add_trait_assoc_items_to_impl( trait_: hir::Trait, impl_: &ast::Impl, target_scope: &hir::SemanticsScope<'_>, + default_mode: DefaultMethods, ) -> Vec { let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; original_items @@ -240,7 +241,10 @@ pub fn add_trait_assoc_items_to_impl( ast::AssocItem::cast(editor.finish().new_root().clone()).unwrap() }) .filter_map(|item| match item { - ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { + // We can check `fn_.body().is_none()`, but this is actually not what we want to check: some functions (`Drop::drop()` + // or `#[rustc_must_implement_one_of]`) have a default body that should be ignored. So the criteria is whether + // we requested required or defaulted methods, and not whether the method actually has a body. + ast::AssocItem::Fn(fn_) if default_mode == DefaultMethods::No => { let (fn_editor, fn_) = SyntaxEditor::with_ast_node(&fn_); let fill_expr: ast::Expr = match config.expr_fill_default { ExprFillDefaultMode::Todo | ExprFillDefaultMode::Default => make.expr_todo(), diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 0d9bb4f92bdc0..129e63d3988b5 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -670,7 +670,11 @@ pub mod ops { // region:drop #[lang = "drop"] pub trait Drop { - fn drop(&mut self); + fn drop(&mut self) { + // region:pin + Drop::pin_drop(crate::pin::Pin::new(self)) + // endregion:pin + } // region:pin fn pin_drop(self: crate::pin::Pin<&mut Self>) {} From 9fdf3cd2d59ee5090b6744f747ee0a0f8f8372b3 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 8 Sep 2026 22:19:21 +0300 Subject: [PATCH 17/56] Do not run the "Generate lints and feature flags" CI workflow on forks Because it's hugely annoying. --- src/tools/rust-analyzer/.github/workflows/gen-lints.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rust-analyzer/.github/workflows/gen-lints.yml b/src/tools/rust-analyzer/.github/workflows/gen-lints.yml index c978e3571c40d..05dfdc2fc4534 100644 --- a/src/tools/rust-analyzer/.github/workflows/gen-lints.yml +++ b/src/tools/rust-analyzer/.github/workflows/gen-lints.yml @@ -11,6 +11,7 @@ defaults: jobs: lints-gen: + if: ${{ github.repository == 'rust-lang/rust-analyzer' || github.event_name == 'workflow_dispatch' }} name: Generate lints runs-on: ubuntu-latest permissions: From 1793d1e8c4732751593c007f533470744e2a1fa9 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 8 Sep 2026 23:56:53 +0300 Subject: [PATCH 18/56] Stop at eager macro recursion overflow We tracked the depth perfectly but didn't do anything with it. Also fix the depth tracking for expression stores (it didn't intern the new ID with an incremented depth). --- .../crates/hir-def/src/attrs/docs.rs | 1 + .../crates/hir-def/src/expr_store/expander.rs | 3 +- .../rust-analyzer/crates/hir-def/src/lib.rs | 2 ++ .../macro_expansion_tests/builtin_fn_macro.rs | 31 +++++++++++++++++++ .../crates/hir-def/src/nameres/assoc.rs | 1 + .../crates/hir-def/src/nameres/collector.rs | 3 ++ .../crates/hir-expand/src/eager.rs | 17 ++++++++-- 7 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs index ac8ca70ccc4b9..583bde92679dd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attrs/docs.rs @@ -608,6 +608,7 @@ fn expand_doc_macro_call<'db>( ExpandTo::Expr, expander.krate, expander.macro_depth + 1, + expander.recursion_limit, |path| { expander.resolver.resolve_path_as_macro_def(expander.db, path, Some(MacroSubNs::Bang)) }, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index a974815cc6423..12a2263697908 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -111,7 +111,8 @@ impl<'db> Expander<'db> { call_site.ctx, expands_to, krate, - this.macro_depth, + this.macro_depth + 1, + this.recursion_limit, |path| resolver(path).map(|it| it.definition(db)), eager_callback, ) { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 0712a025b49cb..77d00072fd2df 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -1442,6 +1442,7 @@ pub fn macro_call_as_call_id( expand_to: ExpandTo, krate: Crate, macro_depth: u32, + recursion_limit: u32, resolver: impl Fn(&ModPath) -> Option + Copy, eager_callback: &mut dyn FnMut( InFile<(syntax::AstPtr, span::FileAstId)>, @@ -1459,6 +1460,7 @@ pub fn macro_call_as_call_id( def, call_site, macro_depth, + recursion_limit, &|path| resolver(path).filter(MacroDefId::is_fn_like), eager_callback, ), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 7120980dd30cf..1ba636ee901c5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -628,3 +628,34 @@ const _: bool = foo::<(), fn() -> Foo>(1, ); "#]], ); } + +#[test] +fn eager_recursion_limit() { + check( + r#" +//- minicore: concat + +macro_rules! concat_separator { + () => { + concat!("", concat_separator!()) + }; +} + +fn main() { + concat_separator!() +} + "#, + expect![[r#" + +macro_rules! concat_separator { + () => { + concat!("", concat_separator!()) + }; +} + +fn main() { + concat!("", concat_separator!()) +} + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index 8dea9a4eda1da..0e27d74516007 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -323,6 +323,7 @@ impl<'db> AssocItemCollector<'db> { ExpandTo::Items, self.module_id.krate(self.db), self.macro_depth + 1, + self.def_map.recursion_limit(), resolver, &mut |ptr, call_id| { self.macro_calls.push((ptr.map(|(_, it)| it.upcast()), call_id)) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index ce359ebda6af2..e40e4d99bdbd0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -1360,6 +1360,7 @@ impl<'db> DefCollector<'db> { *expand_to, self.def_map.krate, directive.depth, + self.def_map.recursion_limit(), resolver_def_id, &mut |ptr, call_id| { eager_callback_buffer.push((directive.module_id, ptr, call_id)); @@ -1793,6 +1794,7 @@ impl<'db> DefCollector<'db> { *expand_to, self.def_map.krate, directive.depth, + self.def_map.recursion_limit(), |path| { let resolved_res = self.def_map.resolve_path_fp_with_macro( self.crate_local_def_map.unwrap_or(&self.local_def_map), @@ -2698,6 +2700,7 @@ impl ModCollector<'_, '_> { expand_to, self.def_collector.def_map.krate, self.macro_depth + 1, + self.def_collector.def_map.recursion_limit(), |path| { path.as_ident().and_then(|name| { let def_map = &self.def_collector.def_map; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index 7002b70a7687b..e0058b78d9e53 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -26,8 +26,8 @@ use syntax::{ use syntax_bridge::DocCommentDesugarMode; use crate::{ - AstId, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, InFile, - MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, + AstId, EagerCallInfo, ExpandError, ExpandErrorKind, ExpandResult, ExpandTo, ExpansionSpanMap, + InFile, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, ast::{self, AstNode}, mod_path::ModPath, }; @@ -45,6 +45,7 @@ pub fn expand_eager_macro_input( def: MacroDefId, call_site: SyntaxContext, macro_depth: u32, + recursion_limit: u32, resolver: &dyn Fn(&ModPath) -> Option, eager_callback: EagerCallBackFn<'_>, ) -> ExpandResult> { @@ -79,6 +80,7 @@ pub fn expand_eager_macro_input( krate, call_site, macro_depth, + recursion_limit, resolver, eager_callback, ) @@ -155,6 +157,7 @@ fn eager_macro_recur( krate: Crate, call_site: SyntaxContext, macro_depth: u32, + recursion_limit: u32, macro_resolver: &dyn Fn(&ModPath) -> Option, eager_callback: EagerCallBackFn<'_>, ) -> ExpandResult> { @@ -213,6 +216,14 @@ fn eager_macro_recur( } }; let ast_id = curr.file_id.ast_id_map(db).ast_id(&call); + + if macro_depth > recursion_limit { + return ExpandResult::only_err(ExpandError::new( + span_map.span_at(call.syntax().text_range().start()), + ExpandErrorKind::RecursionOverflow, + )); + } + let ExpandResult { value, err } = match def.kind { MacroDefKind::BuiltInEager(..) => { let ExpandResult { value, err } = expand_eager_macro_input( @@ -223,6 +234,7 @@ fn eager_macro_recur( def, call_site, macro_depth + 1, + recursion_limit, macro_resolver, eager_callback, ); @@ -277,6 +289,7 @@ fn eager_macro_recur( krate, call_site, macro_depth + 1, + recursion_limit, macro_resolver, eager_callback, ); From 6ab34158229d7c8504e46b78008f5b06c40c9158 Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Tue, 8 Sep 2026 22:48:36 +0200 Subject: [PATCH 19/56] Stabilize `unsafe_cell_access` --- library/core/src/cell.rs | 12 ++++++------ .../lint/const-item-interior-mutations-const-cell.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index d332908954b8f..47312b2bd5649 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2368,7 +2368,6 @@ impl UnsafeCell { /// # Examples /// /// ``` - /// #![feature(unsafe_cell_access)] /// use std::cell::UnsafeCell; /// /// let uc = UnsafeCell::new(5); @@ -2377,7 +2376,8 @@ impl UnsafeCell { /// assert_eq!(old, 5); /// ``` #[inline] - #[unstable(feature = "unsafe_cell_access", issue = "136327")] + #[stable(feature = "unsafe_cell_access", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unsafe_cell_access", since = "CURRENT_RUSTC_VERSION")] #[rustc_should_not_be_called_on_const_items] pub const unsafe fn replace(&self, value: T) -> T { // SAFETY: pointer comes from `&self` so naturally satisfies invariants. @@ -2510,7 +2510,6 @@ impl UnsafeCell { /// # Examples /// /// ``` - /// #![feature(unsafe_cell_access)] /// use std::cell::UnsafeCell; /// /// let uc = UnsafeCell::new(5); @@ -2519,7 +2518,8 @@ impl UnsafeCell { /// assert_eq!(val, &5); /// ``` #[inline] - #[unstable(feature = "unsafe_cell_access", issue = "136327")] + #[stable(feature = "unsafe_cell_access", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unsafe_cell_access", since = "CURRENT_RUSTC_VERSION")] #[rustc_should_not_be_called_on_const_items] pub const unsafe fn as_ref_unchecked(&self) -> &T { // SAFETY: pointer comes from `&self` so naturally satisfies ptr-to-ref invariants. @@ -2538,7 +2538,6 @@ impl UnsafeCell { /// # Examples /// /// ``` - /// #![feature(unsafe_cell_access)] /// use std::cell::UnsafeCell; /// /// let uc = UnsafeCell::new(5); @@ -2547,7 +2546,8 @@ impl UnsafeCell { /// assert_eq!(uc.into_inner(), 6); /// ``` #[inline] - #[unstable(feature = "unsafe_cell_access", issue = "136327")] + #[stable(feature = "unsafe_cell_access", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unsafe_cell_access", since = "CURRENT_RUSTC_VERSION")] #[allow(clippy::mut_from_ref)] #[rustc_should_not_be_called_on_const_items] pub const unsafe fn as_mut_unchecked(&self) -> &mut T { diff --git a/tests/ui/lint/const-item-interior-mutations-const-cell.rs b/tests/ui/lint/const-item-interior-mutations-const-cell.rs index 22b465fa0a951..a5a9d6565d1fe 100644 --- a/tests/ui/lint/const-item-interior-mutations-const-cell.rs +++ b/tests/ui/lint/const-item-interior-mutations-const-cell.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(unsafe_cell_access)] + #![feature(sync_unsafe_cell)] #![feature(once_cell_try_insert)] #![feature(once_cell_try)] From 77db98fcc6ee06d0ae5eac08e70b73f3363b0ead Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Tue, 11 Aug 2026 16:40:30 +0200 Subject: [PATCH 20/56] use `expect` for lints we actually expect ..and explain the reasoning using `reason`. Sometimes `expect` wouldn't work (for _reasons_), so keep `allow` in those cases. `lsp-extensions.md` didn't need updating, as the changes in `lsp/ext.rs` only touch the `allow` attribute. --- .../rust-analyzer/crates/hir-def/src/expr_store/scope.rs | 5 ++++- src/tools/rust-analyzer/crates/hir-expand/src/eager.rs | 2 +- src/tools/rust-analyzer/crates/hir-expand/src/lib.rs | 2 +- .../crates/hir-ty/src/consteval/tests/intrinsics.rs | 3 ++- src/tools/rust-analyzer/crates/hir-ty/src/traits.rs | 2 +- src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs | 6 +++--- .../rust-analyzer/crates/rust-analyzer/src/flycheck.rs | 2 +- .../rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs | 7 ++++++- src/tools/rust-analyzer/crates/stdx/src/rand.rs | 2 +- src/tools/rust-analyzer/crates/toolchain/src/lib.rs | 2 +- .../docs/book/src/contributing/lsp-extensions.md | 2 +- src/tools/rust-analyzer/lib/line-index/src/tests.rs | 5 ++++- 12 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs index 24baa0f8c8d89..ee43ee5cc47b4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs @@ -115,7 +115,10 @@ impl ExprScopes { } /// If `scope` refers to a macro def scope, returns the corresponding `MacroId`. - #[allow(clippy::borrowed_box)] // If we return `&MacroDefId` we need to move it, this way we just clone the `Box`. + #[expect( + clippy::borrowed_box, + reason = "If we return `&MacroDefId` we need to move it, this way we just clone the `Box`." + )] pub fn macro_def(&self, scope: ScopeId) -> Option<&Box> { match &self.scopes[scope].kind { ScopeKind::MacroDef(macro_def) => Some(macro_def), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index 7002b70a7687b..918ccac815601 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -62,7 +62,7 @@ pub fn expand_eager_macro_input( macro_depth, }; let arg_id = MacroCallId::new(db, loc); - #[allow(deprecated)] // builtin eager macros are never derives + #[expect(deprecated, reason = "builtin eager macros are never derives")] let (_, _, span) = arg_id.macro_arg(db); let ExpandResult { value: (arg_exp, arg_exp_map), err: parse_err } = arg_id.parse_macro_expansion(db); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index e8d61a6eadf63..e646c21ec8c5e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -519,7 +519,7 @@ impl MacroCallId { /// This is not connected to the database so it does not cache the result. However, the inner [macro_arg] query is /// /// [macro_arg]: Self::macro_arg - #[allow(deprecated)] // we are macro_arg_considering_derives + #[expect(deprecated, reason = "we are `macro_arg_considering_derives`")] pub fn macro_arg_considering_derives<'db>( self, db: &'db dyn SourceDatabase, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index 1dad8dad73192..ab6294cb375df 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -469,7 +469,8 @@ fn floating_point() { IsSigned::Yes, )), ); - #[allow(clippy::unnecessary_min_or_max)] + // FIXME: this should be an `expect`, but that currently results in `lint_expectation_unfulfilled` + #[allow(clippy::unnecessary_min_or_max, reason = "for symmetry with the expression in `GOAL`")] check_number( r#" #[rustc_intrinsic] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index f3aa024399e06..61f0e17cc9984 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -391,6 +391,6 @@ pub fn check_orphan_rules<'db>(db: &'db dyn HirDatabase, impl_: ImplId) -> bool } _ => false, }); - #[allow(clippy::let_and_return)] + #[allow(clippy::let_and_return, reason = "the name clarifies the meaning of the boolean")] is_not_orphan } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs index 09a270c143888..ee61cab4828c5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/ra_fixture.rs @@ -307,7 +307,7 @@ impl IsEmpty for SmallVec<[T; N]> { } } -#[allow(clippy::disallowed_types)] +#[expect(clippy::disallowed_types, reason = "generic allows for `FxHashMap`")] impl IsEmpty for std::collections::HashMap { fn is_empty(&self) -> bool { self.is_empty() @@ -376,7 +376,7 @@ impl UpmapFromRaFixture for SmallVec<[T; } } -#[allow(clippy::disallowed_types)] +#[expect(clippy::disallowed_types, reason = "generic allows for `FxHashMap`")] impl UpmapFromRaFixture for std::collections::HashMap { @@ -391,7 +391,7 @@ impl UpmapFromRaFixture for std::collections::HashMap { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 85edb239e3f57..7f1f4ef137054 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -490,7 +490,7 @@ impl<'a> Substitutions<'a> { /// /// Same for {saved_file}. /// - #[allow(clippy::disallowed_types)] /* generic parameter allows for FxHashMap */ + #[expect(clippy::disallowed_types, reason = "generic parameter allows for `FxHashMap`")] fn substitute( self, template: &project_json::Runnable, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 8e0bb285c2318..19e067334e008 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -4,7 +4,12 @@ // might strip `false` values from the JSON payload due to their reserialization logic turning false // into null which will then cause them to be omitted in the resolve request. See https://github.com/rust-lang/rust-analyzer/issues/18767 -#![allow(clippy::disallowed_types)] +// FIXME: ideally we'd put this on `SnippetWorkspaceEdit.change_annotations`, but that doesn't work, +// most likely because the lint fires in the impls generated by the derives as well. +#![expect( + clippy::disallowed_types, + reason = "`SnippetWorkspaceEdit.change_annotations` needs to match `lsp_types::WorkspaceEdit.change_annotations` for the `From` impl" +)] use std::ops; diff --git a/src/tools/rust-analyzer/crates/stdx/src/rand.rs b/src/tools/rust-analyzer/crates/stdx/src/rand.rs index e028990900af6..07dfa6ef8877c 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/rand.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/rand.rs @@ -14,6 +14,6 @@ pub fn shuffle(slice: &mut [T], mut rand_index: impl FnMut(usize) -> usize) { pub fn seed() -> u64 { use std::hash::{BuildHasher, Hasher}; - #[allow(clippy::disallowed_types)] + #[expect(clippy::disallowed_types, reason = "we need a source of randomness for the seed")] std::collections::hash_map::RandomState::new().build_hasher().finish() } diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs index 6bed98f4cd2d7..26883add08699 100644 --- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs +++ b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs @@ -74,7 +74,7 @@ impl Tool { // Prevent rustup from automatically installing toolchains, see https://github.com/rust-lang/rust-analyzer/issues/20719. pub const NO_RUSTUP_AUTO_INSTALL_ENV: (&str, &str) = ("RUSTUP_AUTO_INSTALL", "0"); -#[allow(clippy::disallowed_types)] /* generic parameter allows for FxHashMap */ +#[expect(clippy::disallowed_types, reason = "generic parameter allows for `FxHashMap`")] pub fn command( cmd: impl AsRef, working_directory: impl AsRef, diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md index da4a5aaa686c5..42bdb5dc1055a 100644 --- a/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md @@ -1,5 +1,5 @@ $DIR/named-fn-trait-parameters.rs:28:20 - | -LL | self1: impl Fn(self), - | ^^^^ must be the first parameter of an associated function - -error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:30:20 - | -LL | self2: impl Fn(self, self), - | ^^^^ must be the first parameter of an associated function - -error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:30:26 + --> $DIR/named-fn-trait-parameters.rs:29:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:33:26 + --> $DIR/named-fn-trait-parameters.rs:31:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function error: expected type, found `1` - --> $DIR/named-fn-trait-parameters.rs:48:19 + --> $DIR/named-fn-trait-parameters.rs:46:19 | LL | pat1: impl Fn(1..3: bool), | ^ expected type error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:50:25 + --> $DIR/named-fn-trait-parameters.rs:48:25 | LL | pat2: impl Fn((x, y): (bool, bool)), | ^ unexpected token after this error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:52:25 + --> $DIR/named-fn-trait-parameters.rs:50:25 | LL | pat3: impl Fn(Thing { a, b }: Thing), | ^ expected one of `!`, `(`, `+`, `::`, or `<` error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:54:27 + --> $DIR/named-fn-trait-parameters.rs:52:27 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^ expected one of `!`, `(`, `+`, `::`, or `<` error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:56:30 + --> $DIR/named-fn-trait-parameters.rs:54:30 | LL | pat5: impl Fn((((((x))))): bool), | ^ unexpected token after this error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:59:20 - | -LL | self1: impl Fn(self), // FIXME should be accepted - | ^^^^ must be the first parameter of an associated function - -error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:61:20 - | -LL | self2: impl Fn(self, self), - | ^^^^ must be the first parameter of an associated function - -error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:61:26 + --> $DIR/named-fn-trait-parameters.rs:58:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:64:26 + --> $DIR/named-fn-trait-parameters.rs:60:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function -error: aborting due to 18 previous errors +error: aborting due to 14 previous errors From acc7dd9f869024ae59d889f96ae2d3347f1e692f Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 12:15:44 +0200 Subject: [PATCH 30/56] Add `FnContext::ParenthesizedArgumentList` --- compiler/rustc_parse/src/parser/diagnostics.rs | 1 + compiler/rustc_parse/src/parser/function.rs | 2 ++ compiler/rustc_parse/src/parser/path.rs | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 6d4a0215eb7b3..a8bc293d96751 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2379,6 +2379,7 @@ impl<'a> Parser<'a> { target: match context { FnContext::Trait => "methods without bodies", FnContext::FunctionPtrType => "function pointer types", + FnContext::ParenthesizedArgumentList => "parenthesized argument list", FnContext::Free => unreachable!("This method is not called in free functions, as patterns are always allowed there"), FnContext::Impl => unreachable!("This method is not called in impls, as patterns are always allowed there"), }, diff --git a/compiler/rustc_parse/src/parser/function.rs b/compiler/rustc_parse/src/parser/function.rs index 57fe19226066c..2224bf1ec8efa 100644 --- a/compiler/rustc_parse/src/parser/function.rs +++ b/compiler/rustc_parse/src/parser/function.rs @@ -103,6 +103,8 @@ pub(crate) enum FnContext { Free, /// A Function Pointer Type `fn(..)`. FunctionPtrType, + /// A Parenthesized Argument List `impl Fn(...)` + ParenthesizedArgumentList, /// A Trait context. Trait, /// An Impl block. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index c15928dddea3f..1fe4d72b3cee1 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -401,7 +401,7 @@ impl<'a> Parser<'a> { let parse_params_result = self.parse_paren_comma_seq(|p| { // Inside parenthesized type arguments, we want types only, not names. let mode = FnParseMode { - context: FnContext::Free, + context: FnContext::ParenthesizedArgumentList, req_name: |_, _| false, req_body: false, }; From 19c0f5c216dfe0d63ceb605827fb92229f59a70d Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 12:35:23 +0200 Subject: [PATCH 31/56] Don't suggest using a pattern when `recover_arg_parse` fails While the stderrs in this commit are neutral, some better some worse, there were quite a few bad diagnostics if we enable `recover_arg_parse` for parenthesized argument lists --- compiler/rustc_parse/src/parser/function.rs | 14 ++++++++++++-- .../dotdotdot-rest-pattern-suggestion-span.rs | 2 +- .../dotdotdot-rest-pattern-suggestion-span.stderr | 4 ++-- tests/ui/parser/issue-116781.rs | 4 ++-- tests/ui/parser/issue-116781.stderr | 8 ++++---- .../rfc-2565-param-attrs/attr-without-param.rs | 2 +- .../rfc-2565-param-attrs/attr-without-param.stderr | 4 ++-- 7 files changed, 24 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_parse/src/parser/function.rs b/compiler/rustc_parse/src/parser/function.rs index 2224bf1ec8efa..a042826c231a8 100644 --- a/compiler/rustc_parse/src/parser/function.rs +++ b/compiler/rustc_parse/src/parser/function.rs @@ -816,9 +816,19 @@ impl<'a> Parser<'a> { Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err), Err(err) if recover_arg_parse => { // Recover from attempting to parse the argument as a type without pattern. - err.cancel(); this.restore_snapshot(parser_snapshot_before_ty); - this.recover_arg_parse(fn_parse_mode.context)? + match this.recover_arg_parse(fn_parse_mode.context) { + Ok(res) => { + // We managed to parse the argument as a pattern, cancel the original error and emit a better one + err.cancel(); + res + } + Err(new_err) => { + // We did not manage to parse the argument as a pattern, avoid suggesting a pattern and emit the original error + new_err.cancel(); + return Err(err); + } + } } Err(err) => return Err(err), } diff --git a/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.rs b/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.rs index 0db10726c5dc4..36091b480d3c3 100644 --- a/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.rs +++ b/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.rs @@ -10,7 +10,7 @@ impl S { fn f(···>) } //~| ERROR unknown start of token //~| ERROR unknown start of token //~| ERROR unexpected `...` -//~| ERROR expected `:`, found `>` +//~| ERROR unexpected token: `>` //~| ERROR expected one of //~| ERROR associated function in `impl` without body //~| ERROR cannot find type `S` in this scope diff --git a/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.stderr b/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.stderr index d483c40ca5e0b..0889ca8a495af 100644 --- a/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.stderr +++ b/tests/ui/parser/dotdotdot-rest-pattern-suggestion-span.stderr @@ -48,11 +48,11 @@ LL - impl S { fn f(···>) } LL + impl S { fn f(..>) } | -error: expected `:`, found `>` +error: unexpected token: `>` --> $DIR/dotdotdot-rest-pattern-suggestion-span.rs:8:18 | LL | impl S { fn f(···>) } - | ^ expected `:` + | ^ unexpected token after this error: expected one of `->`, `where`, or `{`, found `}` --> $DIR/dotdotdot-rest-pattern-suggestion-span.rs:8:21 diff --git a/tests/ui/parser/issue-116781.rs b/tests/ui/parser/issue-116781.rs index 176350fe2eec6..5ff0989b3df00 100644 --- a/tests/ui/parser/issue-116781.rs +++ b/tests/ui/parser/issue-116781.rs @@ -1,8 +1,8 @@ #[derive(Debug)] struct Foo { #[cfg(true)] - field: fn(($),), //~ ERROR expected pattern, found `$` - //~^ ERROR expected pattern, found `$` + field: fn(($),), //~ ERROR expected type, found `$` + //~^ ERROR expected type, found `$` } fn main() {} diff --git a/tests/ui/parser/issue-116781.stderr b/tests/ui/parser/issue-116781.stderr index 1a77b60a50dc8..fdfadf4a9e313 100644 --- a/tests/ui/parser/issue-116781.stderr +++ b/tests/ui/parser/issue-116781.stderr @@ -1,14 +1,14 @@ -error: expected pattern, found `$` +error: expected type, found `$` --> $DIR/issue-116781.rs:4:16 | LL | field: fn(($),), - | ^ expected pattern + | ^ expected type -error: expected pattern, found `$` +error: expected type, found `$` --> $DIR/issue-116781.rs:4:16 | LL | field: fn(($),), - | ^ expected pattern + | ^ expected type | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs index 14402eaeecac1..d775545dd571c 100644 --- a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs +++ b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs @@ -11,7 +11,7 @@ impl T for S { #[cfg(false)] trait T { - fn f(#[attr]); //~ ERROR expected argument name, found `)` + fn f(#[attr]); //~ ERROR expected type, found `)` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr index 2fa03f3cb0bba..65b265fb6289a 100644 --- a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr +++ b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.stderr @@ -10,11 +10,11 @@ error: expected parameter name, found `)` LL | fn f(#[attr]) {} | ^ expected parameter name -error: expected argument name, found `)` +error: expected type, found `)` --> $DIR/attr-without-param.rs:14:17 | LL | fn f(#[attr]); - | ^ expected argument name + | ^ expected type error: aborting due to 3 previous errors From e603db4aa67c4149543a79dc5fbdc466f334f0e2 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 12:39:16 +0200 Subject: [PATCH 32/56] Enable `recover_arg_parse` for parenthesized argument lists --- compiler/rustc_parse/src/parser/path.rs | 2 +- tests/ui/fn/named-fn-trait-parameters.rs | 21 +-- tests/ui/fn/named-fn-trait-parameters.stderr | 147 ++++++++++++++---- .../issues/issue-103748-ICE-wrong-braces.rs | 1 + .../issue-103748-ICE-wrong-braces.stderr | 10 +- 5 files changed, 135 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 1fe4d72b3cee1..e4ba1e7d18e51 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -405,7 +405,7 @@ impl<'a> Parser<'a> { req_name: |_, _| false, req_body: false, }; - let param = p.parse_param_general(&mode, first_param, false)?; + let param = p.parse_param_general(&mode, first_param, true)?; first_param = false; if !matches!(param.pat.kind, PatKind::Missing) { self.psess diff --git a/tests/ui/fn/named-fn-trait-parameters.rs b/tests/ui/fn/named-fn-trait-parameters.rs index 746854ab7f4e2..16dd8e8cf6d5a 100644 --- a/tests/ui/fn/named-fn-trait-parameters.rs +++ b/tests/ui/fn/named-fn-trait-parameters.rs @@ -15,15 +15,16 @@ fn allowed( // Patterns are semantically rejected fn semantics( pat1: impl Fn(1..3: bool), - //~^ ERROR expected type, found `1` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat2: impl Fn((x, y): (bool, bool)), - //~^ ERROR unexpected token: `:` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat3: impl Fn(Thing { a, b }: Thing), - //~^ ERROR expected one of `!`, `(`, `+`, `::`, or `<`, found `{` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat4: impl Fn(NoThing { a, b }: NoThing), - //~^ ERROR expected one of `!`, `(`, `+`, `::`, or `<`, found `{` + //~^ ERROR patterns aren't allowed in parenthesized argument list + //~| ERROR cannot find type `NoThing` in this scope pat5: impl Fn((((((x))))): bool), - //~^ ERROR unexpected token: `:` + //~^ ERROR patterns aren't allowed in parenthesized argument list self1: impl Fn(self), self2: impl Fn(self, self), @@ -44,15 +45,15 @@ fn semantics( #[cfg(false)] fn syntax( pat1: impl Fn(1..3: bool), - //~^ ERROR expected type, found `1` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat2: impl Fn((x, y): (bool, bool)), - //~^ ERROR unexpected token: `:` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat3: impl Fn(Thing { a, b }: Thing), - //~^ ERROR expected one of `!`, `(`, `+`, `::`, or `<`, found `{` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat4: impl Fn(NoThing { a, b }: NoThing), - //~^ ERROR expected one of `!`, `(`, `+`, `::`, or `<`, found `{` + //~^ ERROR patterns aren't allowed in parenthesized argument list pat5: impl Fn((((((x))))): bool), - //~^ ERROR unexpected token: `:` + //~^ ERROR patterns aren't allowed in parenthesized argument list self1: impl Fn(self), self2: impl Fn(self, self), diff --git a/tests/ui/fn/named-fn-trait-parameters.stderr b/tests/ui/fn/named-fn-trait-parameters.stderr index 1321afb77a735..5f3a802e07372 100644 --- a/tests/ui/fn/named-fn-trait-parameters.stderr +++ b/tests/ui/fn/named-fn-trait-parameters.stderr @@ -1,86 +1,165 @@ -error: expected type, found `1` +error[E0642]: patterns aren't allowed in parenthesized argument list --> $DIR/named-fn-trait-parameters.rs:17:19 | LL | pat1: impl Fn(1..3: bool), - | ^ expected type + | ^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat1: impl Fn(1..3: bool), +LL + pat1: impl Fn(_: bool), + | -error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:19:25 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:19:19 | LL | pat2: impl Fn((x, y): (bool, bool)), - | ^ unexpected token after this + | ^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat2: impl Fn((x, y): (bool, bool)), +LL + pat2: impl Fn(_: (bool, bool)), + | -error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:21:25 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:21:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), - | ^ expected one of `!`, `(`, `+`, `::`, or `<` + | ^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat3: impl Fn(Thing { a, b }: Thing), +LL + pat3: impl Fn(_: Thing), + | -error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:23:27 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:23:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), - | ^ expected one of `!`, `(`, `+`, `::`, or `<` + | ^^^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat4: impl Fn(NoThing { a, b }: NoThing), +LL + pat4: impl Fn(_: NoThing), + | -error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:25:30 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:26:19 | LL | pat5: impl Fn((((((x))))): bool), - | ^ unexpected token after this + | ^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat5: impl Fn((((((x))))): bool), +LL + pat5: impl Fn(_: bool), + | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:29:26 + --> $DIR/named-fn-trait-parameters.rs:30:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:31:26 + --> $DIR/named-fn-trait-parameters.rs:32:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function -error: expected type, found `1` - --> $DIR/named-fn-trait-parameters.rs:46:19 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:47:19 | LL | pat1: impl Fn(1..3: bool), - | ^ expected type + | ^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat1: impl Fn(1..3: bool), +LL + pat1: impl Fn(_: bool), + | -error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:48:25 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:49:19 | LL | pat2: impl Fn((x, y): (bool, bool)), - | ^ unexpected token after this + | ^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat2: impl Fn((x, y): (bool, bool)), +LL + pat2: impl Fn(_: (bool, bool)), + | -error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:50:25 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:51:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), - | ^ expected one of `!`, `(`, `+`, `::`, or `<` + | ^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat3: impl Fn(Thing { a, b }: Thing), +LL + pat3: impl Fn(_: Thing), + | -error: expected one of `!`, `(`, `+`, `::`, or `<`, found `{` - --> $DIR/named-fn-trait-parameters.rs:52:27 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:53:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), - | ^ expected one of `!`, `(`, `+`, `::`, or `<` + | ^^^^^^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat4: impl Fn(NoThing { a, b }: NoThing), +LL + pat4: impl Fn(_: NoThing), + | -error: unexpected token: `:` - --> $DIR/named-fn-trait-parameters.rs:54:30 +error[E0642]: patterns aren't allowed in parenthesized argument list + --> $DIR/named-fn-trait-parameters.rs:55:19 | LL | pat5: impl Fn((((((x))))): bool), - | ^ unexpected token after this + | ^^^^^^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - pat5: impl Fn((((((x))))): bool), +LL + pat5: impl Fn(_: bool), + | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:58:26 + --> $DIR/named-fn-trait-parameters.rs:59:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:60:26 + --> $DIR/named-fn-trait-parameters.rs:61:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function -error: aborting due to 14 previous errors +error[E0425]: cannot find type `NoThing` in this scope + --> $DIR/named-fn-trait-parameters.rs:23:37 + | +LL | pat4: impl Fn(NoThing { a, b }: NoThing), + | ^^^^^^^ not found in this scope + | +note: similarly named struct `Thing` defined here + --> $DIR/named-fn-trait-parameters.rs:73:1 + | +LL | struct Thing { a: bool, b: bool } + | ^^^^^^^^^^^^ +help: a struct with a similar name exists + | +LL - pat4: impl Fn(NoThing { a, b }: NoThing), +LL + pat4: impl Fn(NoThing { a, b }: Thing), + | + +error: aborting due to 15 previous errors +Some errors have detailed explanations: E0425, E0642. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs index 60dd88e65400a..08997f8a6afd0 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs @@ -3,3 +3,4 @@ struct Apple((Apple, Option(Banana ? Citron))); //~^ ERROR invalid `?` in type //~| ERROR unexpected token: `Citron` +//~| ERROR expected a pattern, found an expression diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr index c92535c3906bc..fff09d19772f5 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr @@ -16,5 +16,13 @@ error: unexpected token: `Citron` LL | struct Apple((Apple, Option(Banana ? Citron))); | ^^^^^^ unexpected token after this -error: aborting due to 2 previous errors +error: expected a pattern, found an expression + --> $DIR/issue-103748-ICE-wrong-braces.rs:3:29 + | +LL | struct Apple((Apple, Option(Banana ? Citron))); + | ^^^^^^^^ not a pattern + | + = note: arbitrary expressions are not allowed in patterns: + +error: aborting due to 3 previous errors From f1e7b1ecca1cf1c57aead940365d9f09a50cf420 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 13:14:44 +0200 Subject: [PATCH 33/56] Semantically forbid `self` params in parenthesized argument lists --- .../rustc_ast_passes/src/ast_validation.rs | 13 +++++-- tests/ui/fn/named-fn-trait-parameters.rs | 4 +- tests/ui/fn/named-fn-trait-parameters.stderr | 38 +++++++++++++------ 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index fe5c604544448..234ba16daaade 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -397,7 +397,7 @@ impl<'a> AstValidator<'a> { let c_variadic_span = self.check_decl_cvariadic_pos(fn_decl); self.check_decl_splatting(fn_decl, c_variadic_span, splat_semantic); self.check_decl_attrs(fn_decl); - self.check_decl_self_param(fn_decl, self_semantic); + self.check_decl_self_param(&fn_decl.inputs, self_semantic); } /// Emits fatal error if function declaration has more than `u16::MAX` arguments @@ -544,8 +544,8 @@ impl<'a> AstValidator<'a> { }); } - fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { - if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { + fn check_decl_self_param(&self, fn_inputs: &[Param], self_semantic: SelfSemantic) { + if let (SelfSemantic::No, [param, ..]) = (self_semantic, fn_inputs) { if param.is_self() { self.dcx().emit_err(diagnostics::FnParamForbiddenSelf { span: param.span }); } @@ -2208,6 +2208,13 @@ impl Visitor<'_> for AstValidator<'_> { |this| visit::walk_anon_const(this, anon_const), ) } + + fn visit_path_segment(&mut self, seg: &PathSegment) -> Self::Result { + if let Some(Parenthesized(args)) = &seg.args { + self.check_decl_self_param(&args.inputs, SelfSemantic::No); + } + visit::walk_path_segment(self, seg); + } } pub fn check_crate( diff --git a/tests/ui/fn/named-fn-trait-parameters.rs b/tests/ui/fn/named-fn-trait-parameters.rs index 16dd8e8cf6d5a..0c9340221899b 100644 --- a/tests/ui/fn/named-fn-trait-parameters.rs +++ b/tests/ui/fn/named-fn-trait-parameters.rs @@ -27,8 +27,10 @@ fn semantics( //~^ ERROR patterns aren't allowed in parenthesized argument list self1: impl Fn(self), + //~^ ERROR `self` parameter is only allowed in associated functions self2: impl Fn(self, self), - //~^ ERROR unexpected `self` parameter in function + //~^ ERROR `self` parameter is only allowed in associated functions + //~| ERROR unexpected `self` parameter in function self3: impl Fn(bool, self), //~^ ERROR unexpected `self` parameter in function diff --git a/tests/ui/fn/named-fn-trait-parameters.stderr b/tests/ui/fn/named-fn-trait-parameters.stderr index 5f3a802e07372..3f3dced1907af 100644 --- a/tests/ui/fn/named-fn-trait-parameters.stderr +++ b/tests/ui/fn/named-fn-trait-parameters.stderr @@ -59,19 +59,19 @@ LL + pat5: impl Fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:30:26 + --> $DIR/named-fn-trait-parameters.rs:31:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:32:26 + --> $DIR/named-fn-trait-parameters.rs:34:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:47:19 + --> $DIR/named-fn-trait-parameters.rs:49:19 | LL | pat1: impl Fn(1..3: bool), | ^^^^ @@ -83,7 +83,7 @@ LL + pat1: impl Fn(_: bool), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:49:19 + --> $DIR/named-fn-trait-parameters.rs:51:19 | LL | pat2: impl Fn((x, y): (bool, bool)), | ^^^^^^ @@ -95,7 +95,7 @@ LL + pat2: impl Fn(_: (bool, bool)), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:51:19 + --> $DIR/named-fn-trait-parameters.rs:53:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), | ^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL + pat3: impl Fn(_: Thing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:53:19 + --> $DIR/named-fn-trait-parameters.rs:55:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL + pat4: impl Fn(_: NoThing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:55:19 + --> $DIR/named-fn-trait-parameters.rs:57:19 | LL | pat5: impl Fn((((((x))))): bool), | ^^^^^^^^^^^ @@ -131,17 +131,33 @@ LL + pat5: impl Fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:59:26 + --> $DIR/named-fn-trait-parameters.rs:61:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:61:26 + --> $DIR/named-fn-trait-parameters.rs:63:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function +error: `self` parameter is only allowed in associated functions + --> $DIR/named-fn-trait-parameters.rs:29:20 + | +LL | self1: impl Fn(self), + | ^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error: `self` parameter is only allowed in associated functions + --> $DIR/named-fn-trait-parameters.rs:31:20 + | +LL | self2: impl Fn(self, self), + | ^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + error[E0425]: cannot find type `NoThing` in this scope --> $DIR/named-fn-trait-parameters.rs:23:37 | @@ -149,7 +165,7 @@ LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^ not found in this scope | note: similarly named struct `Thing` defined here - --> $DIR/named-fn-trait-parameters.rs:73:1 + --> $DIR/named-fn-trait-parameters.rs:75:1 | LL | struct Thing { a: bool, b: bool } | ^^^^^^^^^^^^ @@ -159,7 +175,7 @@ LL - pat4: impl Fn(NoThing { a, b }: NoThing), LL + pat4: impl Fn(NoThing { a, b }: Thing), | -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors Some errors have detailed explanations: E0425, E0642. For more information about an error, try `rustc --explain E0425`. From 26ba932cb875261f96b5e89f6052c0ab88158d9b Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 13:21:43 +0200 Subject: [PATCH 34/56] Semantically forbid patterns in parenthesized argument lists --- .../rustc_ast_passes/src/ast_validation.rs | 14 +++-- compiler/rustc_ast_passes/src/diagnostics.rs | 7 +++ tests/ui/fn/named-fn-trait-parameters.rs | 7 ++- tests/ui/fn/named-fn-trait-parameters.stderr | 56 +++++++++++++++---- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 234ba16daaade..010afc6be5534 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -291,8 +291,11 @@ impl<'a> AstValidator<'a> { }); } - fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option, bool)) { - for Param { pat, .. } in &decl.inputs { + fn check_decl_no_pat( + fn_inputs: &[Param], + mut report_err: impl FnMut(Span, Option, bool), + ) { + for Param { pat, .. } in fn_inputs { match pat.kind { PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {} PatKind::Ident(BindingMode::MUT, ident, None) => { @@ -1200,7 +1203,7 @@ impl<'a> AstValidator<'a> { SelfSemantic::No, SplatSemantic::from_extern(bfty.ext), ); - Self::check_decl_no_pat(&bfty.decl, |span, _, _| { + Self::check_decl_no_pat(&bfty.decl.inputs, |span, _, _| { self.dcx().emit_err(diagnostics::PatternFnPointer { span }); }); if let Extern::Implicit(extern_span) = bfty.ext { @@ -2009,7 +2012,7 @@ impl Visitor<'_> for AstValidator<'_> { // Functions without bodies cannot have patterns. if let FnKind::Fn(ctxt, _, Fn { body: None, sig, .. }) = fk { - Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| { + Self::check_decl_no_pat(&sig.decl.inputs, |span, ident, mut_ident| { if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) { if let Some(ident) = ident { let is_foreign = matches!(ctxt, FnCtxt::Foreign); @@ -2212,6 +2215,9 @@ impl Visitor<'_> for AstValidator<'_> { fn visit_path_segment(&mut self, seg: &PathSegment) -> Self::Result { if let Some(Parenthesized(args)) = &seg.args { self.check_decl_self_param(&args.inputs, SelfSemantic::No); + Self::check_decl_no_pat(&args.inputs, |span, _, _| { + self.dcx().emit_err(diagnostics::PatternParenthesizedArgList { span }); + }); } visit::walk_path_segment(self, seg); } diff --git a/compiler/rustc_ast_passes/src/diagnostics.rs b/compiler/rustc_ast_passes/src/diagnostics.rs index 5ab905b5df52b..19516272ce166 100644 --- a/compiler/rustc_ast_passes/src/diagnostics.rs +++ b/compiler/rustc_ast_passes/src/diagnostics.rs @@ -675,6 +675,13 @@ pub(crate) struct PatternFnPointer { pub span: Span, } +#[derive(Diagnostic)] +#[diag("patterns aren't allowed in parenthesized argument lists", code = E0561)] +pub(crate) struct PatternParenthesizedArgList { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("only a single explicit lifetime bound is permitted", code = E0226)] pub(crate) struct TraitObjectBound { diff --git a/tests/ui/fn/named-fn-trait-parameters.rs b/tests/ui/fn/named-fn-trait-parameters.rs index 0c9340221899b..14f913c8bdd3d 100644 --- a/tests/ui/fn/named-fn-trait-parameters.rs +++ b/tests/ui/fn/named-fn-trait-parameters.rs @@ -34,13 +34,18 @@ fn semantics( self3: impl Fn(bool, self), //~^ ERROR unexpected `self` parameter in function - // FIXME should be rejected restricted_pat1: impl Fn(mut x: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat2: impl Fn(&x: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat3: impl Fn(&&x: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat4: impl Fn(false: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat5: impl Fn(&_: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat6: impl Fn(&true: ()), + //~^ ERROR patterns aren't allowed in parenthesized argument lists ) { } // Patterns are also syntactically rejected, but restricted patterns are not diff --git a/tests/ui/fn/named-fn-trait-parameters.stderr b/tests/ui/fn/named-fn-trait-parameters.stderr index 3f3dced1907af..43644fee0cb0c 100644 --- a/tests/ui/fn/named-fn-trait-parameters.stderr +++ b/tests/ui/fn/named-fn-trait-parameters.stderr @@ -71,7 +71,7 @@ LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:49:19 + --> $DIR/named-fn-trait-parameters.rs:54:19 | LL | pat1: impl Fn(1..3: bool), | ^^^^ @@ -83,7 +83,7 @@ LL + pat1: impl Fn(_: bool), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:51:19 + --> $DIR/named-fn-trait-parameters.rs:56:19 | LL | pat2: impl Fn((x, y): (bool, bool)), | ^^^^^^ @@ -95,7 +95,7 @@ LL + pat2: impl Fn(_: (bool, bool)), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:53:19 + --> $DIR/named-fn-trait-parameters.rs:58:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), | ^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL + pat3: impl Fn(_: Thing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:55:19 + --> $DIR/named-fn-trait-parameters.rs:60:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL + pat4: impl Fn(_: NoThing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:57:19 + --> $DIR/named-fn-trait-parameters.rs:62:19 | LL | pat5: impl Fn((((((x))))): bool), | ^^^^^^^^^^^ @@ -131,13 +131,13 @@ LL + pat5: impl Fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:61:26 + --> $DIR/named-fn-trait-parameters.rs:66:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:63:26 + --> $DIR/named-fn-trait-parameters.rs:68:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function @@ -158,6 +158,42 @@ LL | self2: impl Fn(self, self), | = note: associated functions are those in `impl` or `trait` definitions +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:37:30 + | +LL | restricted_pat1: impl Fn(mut x: ()), + | ^^^^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:39:30 + | +LL | restricted_pat2: impl Fn(&x: ()), + | ^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:41:30 + | +LL | restricted_pat3: impl Fn(&&x: ()), + | ^^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:43:30 + | +LL | restricted_pat4: impl Fn(false: ()), + | ^^^^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:45:30 + | +LL | restricted_pat5: impl Fn(&_: ()), + | ^^ + +error[E0561]: patterns aren't allowed in parenthesized argument lists + --> $DIR/named-fn-trait-parameters.rs:47:30 + | +LL | restricted_pat6: impl Fn(&true: ()), + | ^^^^^ + error[E0425]: cannot find type `NoThing` in this scope --> $DIR/named-fn-trait-parameters.rs:23:37 | @@ -165,7 +201,7 @@ LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^ not found in this scope | note: similarly named struct `Thing` defined here - --> $DIR/named-fn-trait-parameters.rs:75:1 + --> $DIR/named-fn-trait-parameters.rs:80:1 | LL | struct Thing { a: bool, b: bool } | ^^^^^^^^^^^^ @@ -175,7 +211,7 @@ LL - pat4: impl Fn(NoThing { a, b }: NoThing), LL + pat4: impl Fn(NoThing { a, b }: Thing), | -error: aborting due to 17 previous errors +error: aborting due to 23 previous errors -Some errors have detailed explanations: E0425, E0642. +Some errors have detailed explanations: E0425, E0561, E0642. For more information about an error, try `rustc --explain E0425`. From 930507ec764c9bb7cfc1756c5bb0458947586ef3 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 13:25:24 +0200 Subject: [PATCH 35/56] No longer mark `named_fn_trait_parameters` as incomplete --- compiler/rustc_feature/src/unstable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 7efa784bd8622..5bad528963987 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -642,7 +642,7 @@ declare_features! ( /// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions. (unstable, naked_functions_target_feature, "1.86.0", Some(138568)), /// Allows providing names to parameters of `impl Fn` etc - (incomplete, named_fn_trait_parameters, "1.99.0", Some(158499)), + (unstable, named_fn_trait_parameters, "1.99.0", Some(158499)), /// Allows specifying the as-needed link modifier (unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490)), /// Allow negative trait implementations. From 70339fc8f6dbab8fde0201390dfa5a21812e84b1 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Sep 2026 14:05:43 +0200 Subject: [PATCH 36/56] Test that duplicate names are semantically allowed --- tests/ui/fn/fn-ptr-pattern.rs | 2 ++ tests/ui/fn/fn-ptr-pattern.stderr | 16 ++++++++-------- tests/ui/fn/named-fn-trait-parameters.rs | 2 ++ tests/ui/fn/named-fn-trait-parameters.stderr | 16 ++++++++-------- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/tests/ui/fn/fn-ptr-pattern.rs b/tests/ui/fn/fn-ptr-pattern.rs index 9bf759af19af7..4260a5095048e 100644 --- a/tests/ui/fn/fn-ptr-pattern.rs +++ b/tests/ui/fn/fn-ptr-pattern.rs @@ -42,6 +42,8 @@ fn semantics( //~^ ERROR patterns aren't allowed in function pointer types restricted_pat6: fn(&true: ()), //~^ ERROR patterns aren't allowed in function pointer types + + duplicate_names: fn(x: usize, x: usize), ) { } // Patterns are also syntactically rejected, but restricted patterns are not diff --git a/tests/ui/fn/fn-ptr-pattern.stderr b/tests/ui/fn/fn-ptr-pattern.stderr index 4425caee39e3f..27982d26dbc54 100644 --- a/tests/ui/fn/fn-ptr-pattern.stderr +++ b/tests/ui/fn/fn-ptr-pattern.stderr @@ -71,7 +71,7 @@ LL | self3: fn(bool, self), | ^^^^ must be the first parameter of an associated function error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:50:14 + --> $DIR/fn-ptr-pattern.rs:52:14 | LL | pat1: fn(1..3: bool), | ^^^^ @@ -83,7 +83,7 @@ LL + pat1: fn(_: bool), | error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:52:14 + --> $DIR/fn-ptr-pattern.rs:54:14 | LL | pat2: fn((x, y): (bool, bool)), | ^^^^^^ @@ -95,7 +95,7 @@ LL + pat2: fn(_: (bool, bool)), | error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:54:14 + --> $DIR/fn-ptr-pattern.rs:56:14 | LL | pat3: fn(Thing { a, b }: Thing), | ^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL + pat3: fn(_: Thing), | error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:56:14 + --> $DIR/fn-ptr-pattern.rs:58:14 | LL | pat4: fn(NoThing { a, b }: NoThing), | ^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL + pat4: fn(_: NoThing), | error[E0642]: patterns aren't allowed in function pointer types - --> $DIR/fn-ptr-pattern.rs:58:14 + --> $DIR/fn-ptr-pattern.rs:60:14 | LL | pat5: fn((((((x))))): bool), | ^^^^^^^^^^^ @@ -131,13 +131,13 @@ LL + pat5: fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/fn-ptr-pattern.rs:62:21 + --> $DIR/fn-ptr-pattern.rs:64:21 | LL | self2: fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/fn-ptr-pattern.rs:64:21 + --> $DIR/fn-ptr-pattern.rs:66:21 | LL | self3: fn(bool, self), | ^^^^ must be the first parameter of an associated function @@ -201,7 +201,7 @@ LL | pat4: fn(NoThing { a, b }: NoThing), | ^^^^^^^ not found in this scope | note: similarly named struct `Thing` defined here - --> $DIR/fn-ptr-pattern.rs:75:1 + --> $DIR/fn-ptr-pattern.rs:77:1 | LL | struct Thing { a: bool, b: bool } | ^^^^^^^^^^^^ diff --git a/tests/ui/fn/named-fn-trait-parameters.rs b/tests/ui/fn/named-fn-trait-parameters.rs index 14f913c8bdd3d..103ce5902048e 100644 --- a/tests/ui/fn/named-fn-trait-parameters.rs +++ b/tests/ui/fn/named-fn-trait-parameters.rs @@ -46,6 +46,8 @@ fn semantics( //~^ ERROR patterns aren't allowed in parenthesized argument lists restricted_pat6: impl Fn(&true: ()), //~^ ERROR patterns aren't allowed in parenthesized argument lists + + duplicate_names: impl Fn(x: usize, x: usize), ) { } // Patterns are also syntactically rejected, but restricted patterns are not diff --git a/tests/ui/fn/named-fn-trait-parameters.stderr b/tests/ui/fn/named-fn-trait-parameters.stderr index 43644fee0cb0c..d675826ff8559 100644 --- a/tests/ui/fn/named-fn-trait-parameters.stderr +++ b/tests/ui/fn/named-fn-trait-parameters.stderr @@ -71,7 +71,7 @@ LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:54:19 + --> $DIR/named-fn-trait-parameters.rs:56:19 | LL | pat1: impl Fn(1..3: bool), | ^^^^ @@ -83,7 +83,7 @@ LL + pat1: impl Fn(_: bool), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:56:19 + --> $DIR/named-fn-trait-parameters.rs:58:19 | LL | pat2: impl Fn((x, y): (bool, bool)), | ^^^^^^ @@ -95,7 +95,7 @@ LL + pat2: impl Fn(_: (bool, bool)), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:58:19 + --> $DIR/named-fn-trait-parameters.rs:60:19 | LL | pat3: impl Fn(Thing { a, b }: Thing), | ^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL + pat3: impl Fn(_: Thing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:60:19 + --> $DIR/named-fn-trait-parameters.rs:62:19 | LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL + pat4: impl Fn(_: NoThing), | error[E0642]: patterns aren't allowed in parenthesized argument list - --> $DIR/named-fn-trait-parameters.rs:62:19 + --> $DIR/named-fn-trait-parameters.rs:64:19 | LL | pat5: impl Fn((((((x))))): bool), | ^^^^^^^^^^^ @@ -131,13 +131,13 @@ LL + pat5: impl Fn(_: bool), | error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:66:26 + --> $DIR/named-fn-trait-parameters.rs:68:26 | LL | self2: impl Fn(self, self), | ^^^^ must be the first parameter of an associated function error: unexpected `self` parameter in function - --> $DIR/named-fn-trait-parameters.rs:68:26 + --> $DIR/named-fn-trait-parameters.rs:70:26 | LL | self3: impl Fn(bool, self), | ^^^^ must be the first parameter of an associated function @@ -201,7 +201,7 @@ LL | pat4: impl Fn(NoThing { a, b }: NoThing), | ^^^^^^^ not found in this scope | note: similarly named struct `Thing` defined here - --> $DIR/named-fn-trait-parameters.rs:80:1 + --> $DIR/named-fn-trait-parameters.rs:82:1 | LL | struct Thing { a: bool, b: bool } | ^^^^^^^^^^^^ From fde670d43d088944a75703513535f75cdf348a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 11 Sep 2026 15:17:07 +0200 Subject: [PATCH 37/56] Initial josh-sync configuration --- compiler/rustc_codegen_cranelift/josh-sync.toml | 3 +++ compiler/rustc_codegen_cranelift/rust-version | 0 2 files changed, 3 insertions(+) create mode 100644 compiler/rustc_codegen_cranelift/josh-sync.toml create mode 100644 compiler/rustc_codegen_cranelift/rust-version diff --git a/compiler/rustc_codegen_cranelift/josh-sync.toml b/compiler/rustc_codegen_cranelift/josh-sync.toml new file mode 100644 index 0000000000000..2de9f9489cce3 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/josh-sync.toml @@ -0,0 +1,3 @@ +repo = "rustc_codegen_cranelift" +filter = ":~(history=\"keep-trivial-merges,no-splice\")[:rev(<=5e120485964f4857f1ad70f7d661fd244d087668:prefix=compiler/rustc_codegen_cranelift,<=7bd21608dfab11ea536f7be8936cc7dfac5864fb:SQUASH)]:/compiler/rustc_codegen_cranelift" +filter-version = 2 diff --git a/compiler/rustc_codegen_cranelift/rust-version b/compiler/rustc_codegen_cranelift/rust-version new file mode 100644 index 0000000000000..e69de29bb2d1d From a6fafea6f185ebcf2913bac500e127fe4787e998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 11 Sep 2026 15:17:10 +0200 Subject: [PATCH 38/56] Prepare for merging from rust-lang/rust This updates the rust-version file to ca0a6473ffde01deb7fce24cc04864cf723e14a0. --- compiler/rustc_codegen_cranelift/rust-version | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_cranelift/rust-version b/compiler/rustc_codegen_cranelift/rust-version index e69de29bb2d1d..4dce5836595b5 100644 --- a/compiler/rustc_codegen_cranelift/rust-version +++ b/compiler/rustc_codegen_cranelift/rust-version @@ -0,0 +1 @@ +ca0a6473ffde01deb7fce24cc04864cf723e14a0 From 8095ae701be39d0623388498e112e15215fa7551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 11 Sep 2026 17:09:03 +0200 Subject: [PATCH 39/56] Update nightly version --- compiler/rustc_codegen_cranelift/rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain.toml b/compiler/rustc_codegen_cranelift/rust-toolchain.toml index b83354ee49fb9..d7e313a7a33ed 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain.toml +++ b/compiler/rustc_codegen_cranelift/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2026-09-10" +channel = "nightly-2026-09-11" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" From f28bf11d5e60e0bc206b50cf3fda3d877de0687b Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Fri, 11 Sep 2026 12:12:55 -0300 Subject: [PATCH 40/56] Add regression test for previous overflow evaluating the requirement --- .../trait-method-requires-gat-impl-trait.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/ui/generic-associated-types/trait-method-requires-gat-impl-trait.rs diff --git a/tests/ui/generic-associated-types/trait-method-requires-gat-impl-trait.rs b/tests/ui/generic-associated-types/trait-method-requires-gat-impl-trait.rs new file mode 100644 index 0000000000000..3477f579cd0dd --- /dev/null +++ b/tests/ui/generic-associated-types/trait-method-requires-gat-impl-trait.rs @@ -0,0 +1,17 @@ +//! Regression test for . +//@compile-flags: -Znext-solver=globally +//@ check-pass + +trait Trait { + type Assoc; + fn foo() + where + Self::Assoc: Trait; +} + +impl Trait for T { + type Assoc = T; + fn foo() {} +} + +fn main() {} From b4361c91eab43264f000d7c6785ee7a541db521f Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 11 Sep 2026 12:45:15 -0400 Subject: [PATCH 41/56] Move guard into is_old_enough_to_be_collected branch --- compiler/rustc_incremental/src/persist/fs.rs | 52 ++++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index a62250139e36e..5254123b1ca11 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -702,33 +702,6 @@ pub(crate) fn garbage_collect_session_directories( lock_file_to_session_dir.items().filter_map(|(lock_file_name, directory_name)| { debug!("garbage_collect_session_directories() - inspecting: {}", directory_name); - if directory_name.as_str() == current_session_directory_name - && !is_finalized(directory_name) - { - // Skipping our own active directory is important for correctness. - // - // To summarize #147821: we will try to lock directories before deciding they can be - // garbage collected, but the ability of `flock::Lock` to detect a lock held *by the - // same process* varies across file locking APIs. Then, if our own session directory - // has become old enough to be eligible for GC, we are beholden to platform-specific - // details about detecting the our own lock on the session directory. - // - // POSIX `fcntl(F_SETLK)`-style file locks are maintained across a process. On - // systems where this is the mechanism for `flock::Lock`, there is no way to - // discover if an `flock::Lock` has been created in the same process on the same - // file. Attempting to set a lock on the lockfile again will succeed, even if the - // lock was set by another thread, on another file descriptor. Then we would - // garbage collect our own live directory, unable to tell it was locked perhaps by - // this same thread. - // - // It's not clear that `flock::Lock` can be fixed for this in general, and our own - // incremental session directory is the only one which this process may own, so skip - // it here and avoid the problem. We know it's not garbage anyway: we're using it. - // Once finalized, its lock is released. Include it in collection so we keep - // the newest completed session. - return None; - } - let Ok(timestamp) = extract_timestamp_from_session_dir(directory_name) else { debug!( "found session-dir with malformed timestamp: {}", @@ -772,6 +745,31 @@ pub(crate) fn garbage_collect_session_directories( } } } else if is_old_enough_to_be_collected(timestamp) { + if directory_name.as_str() == current_session_directory_name { + // Skipping our own active directory is important for correctness. + // + // To summarize #147821: we will try to lock directories before deciding they can be + // garbage collected, but the ability of `flock::Lock` to detect a lock held *by the + // same process* varies across file locking APIs. Then, if our own session directory + // has become old enough to be eligible for GC, we are beholden to platform-specific + // details about detecting the our own lock on the session directory. + // + // POSIX `fcntl(F_SETLK)`-style file locks are maintained across a process. On + // systems where this is the mechanism for `flock::Lock`, there is no way to + // discover if an `flock::Lock` has been created in the same process on the same + // file. Attempting to set a lock on the lockfile again will succeed, even if the + // lock was set by another thread, on another file descriptor. Then we would + // garbage collect our own live directory, unable to tell it was locked perhaps by + // this same thread. + // + // It's not clear that `flock::Lock` can be fixed for this in general, and our own + // incremental session directory is the only one which this process may own, so skip + // it here and avoid the problem. We know it's not garbage anyway: we're using it. + // Once finalized, its lock is released. Include it in collection so we keep + // the newest completed session. + return None; + } + // When cleaning out "-working" session directories, i.e. // session directories that might still be in use by another // compiler instance, we only look a directories that are From 603380ed39ef81d005e4ddf393ec951fbf5cf4ea Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Sep 2026 13:39:59 +1000 Subject: [PATCH 42/56] Avoid some `struct_foo(..).emit()` chains These can be replaced with `foo(..)`. Also make the return type of `report_unterminated_block_comment` more precise. --- compiler/rustc_ast_lowering/src/item.rs | 4 +--- compiler/rustc_ast_lowering/src/lib.rs | 13 ++++++------- compiler/rustc_hir_analysis/src/check/check.rs | 2 +- .../src/outlives/implicit_infer.rs | 10 ++++------ compiler/rustc_hir_typeck/src/intrinsicck.rs | 2 +- compiler/rustc_parse/src/lexer/mod.rs | 2 +- 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b5e28d21a2613..60bb6e62b64d6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -800,9 +800,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> { if v.ident.name == kw::Underscore && self.tcx.features().unnamed_enum_variants() { // FIXME(#156628): lower unnamed enum variants to HIR. - self.dcx() - .struct_span_fatal(v.span, "unnamed enum variants are not yet implemented") - .emit() + self.dcx().span_fatal(v.span, "unnamed enum variants are not yet implemented"); } let hir_id = self.lower_node_id(v.id); self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a27dc47bf27c3..b196e1de8e89d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1795,9 +1795,9 @@ impl<'hir> LoweringContext<'_, 'hir> { if expr::WillCreateDefIdsVisitor.visit_expr(expr).is_break() { // FIXME(mgca): make this non-fatal once we have a better way to handle // nested items in invalid `direct_const_arg!()` arguments. - self.dcx().struct_span_fatal(span, msg).emit() + self.dcx().span_fatal(span, msg) } else { - self.dcx().struct_span_err(span, msg).emit() + self.dcx().span_err(span, msg) } } @@ -2983,9 +2983,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let literal = self.lower_lit(literal, span); let kind = if !matches!(literal.node, LitKind::Int(..)) { - let err = - self.dcx().struct_span_err(expr.span, "negated literal must be an integer"); - hir::ConstArgKind::Error(err.emit()) + let err = self.dcx().span_err(expr.span, "negated literal must be an integer"); + hir::ConstArgKind::Error(err) } else { hir::ConstArgKind::Literal { lit: literal.node, negated: true } }; @@ -3389,9 +3388,9 @@ impl UnrepresentableConstArgError { // FIXME(mgca): make this non-fatal once we have a better way to handle // nested items in const args // Issue: https://github.com/rust-lang/rust/issues/154539 - lowering_context.dcx().struct_span_fatal(self.span, msg).emit() + lowering_context.dcx().span_fatal(self.span, msg) } else { - lowering_context.dcx().struct_span_err(self.span, msg).emit() + lowering_context.dcx().span_err(self.span, msg) }; ConstArg { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d5bc834b831c7..9f8cde7892fb0 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1554,7 +1554,7 @@ fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalab return; } ScalableElt::ElementCount(..) if fields.len() >= 2 => { - tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit(); + tcx.dcx().span_err(span, "scalable vectors cannot have multiple fields"); return; } ScalableElt::Container if fields.is_empty() => { diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index 131812a364ebd..ca7e246a9e05b 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -97,12 +97,10 @@ pub(super) fn infer_clauses( } else { "overflow computing implied lifetime bounds".to_string() }; - tcx.dcx() - .struct_span_fatal( - clauses_added.iter().map(|id| tcx.def_span(*id)).collect::>(), - msg, - ) - .emit(); + tcx.dcx().span_fatal( + clauses_added.iter().map(|id| tcx.def_span(*id)).collect::>(), + msg, + ); } } diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index d63bffab88221..989c63ac2f34b 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -78,7 +78,7 @@ fn check_transmute<'tcx>( let normalize = |ty: Unnormalized<'tcx, Ty<'tcx>>| -> Result, ErrorGuaranteed> { tcx.try_normalize_erasing_regions(typing_env, ty).map_err(|err| { let err = LayoutError::NormalizationFailure(ty.skip_normalization(), err); - tcx.dcx().struct_span_err(span, err.to_string()).emit() + tcx.dcx().span_err(span, err.to_string()) }) }; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 6ed61a9f4e01d..2afb55b02e2e6 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1007,7 +1007,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { err.emit() } - fn report_unterminated_block_comment(&self, start: BytePos, doc_style: Option) { + fn report_unterminated_block_comment(&self, start: BytePos, doc_style: Option) -> ! { let msg = match doc_style { Some(_) => "unterminated block doc-comment", None => "unterminated block comment", From 09bf6de39ebaab2af69ac0b656dd440282fa9ee7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 9 Sep 2026 17:54:15 +1000 Subject: [PATCH 43/56] Remove `EmissionGuarantee` It's a trait that is used to give `Diag::emit` different return types depending on the `G` in `Diag<'_, G>`. It works, but it's overkill. There are only four different `G` types in practice (`BugAbort`, `FatalAbort`, `ErrorGuaranteed`, and `()`) and having inherent `emit` methods for each of those four concrete `Diag<'_, G>` types is good enough. This commit makes that change. This removes `EmissionGuarantee` trait bounds from many places, which is nice. --- compiler/rustc_abi/src/lib.rs | 4 +- compiler/rustc_ast_passes/src/diagnostics.rs | 4 +- .../rustc_attr_parsing/src/diagnostics.rs | 18 +- .../src/diagnostics/explain_borrow.rs | 10 +- .../rustc_borrowck/src/diagnostics/mod.rs | 6 +- .../src/diagnostics/region_name.rs | 4 +- .../rustc_builtin_macros/src/diagnostics.rs | 9 +- .../rustc_codegen_llvm/src/diagnostics.rs | 8 +- compiler/rustc_codegen_ssa/src/diagnostics.rs | 11 +- compiler/rustc_const_eval/src/diagnostics.rs | 4 +- compiler/rustc_errors/src/diagnostic.rs | 177 ++++++++---------- compiler/rustc_errors/src/diagnostic_impls.rs | 4 +- compiler/rustc_errors/src/lib.rs | 30 ++- .../rustc_hir_analysis/src/check/check.rs | 4 +- .../rustc_hir_analysis/src/diagnostics.rs | 7 +- .../wrong_number_of_generic_args.rs | 33 ++-- .../src/hir_ty_lowering/dyn_trait.rs | 6 +- compiler/rustc_hir_typeck/src/diagnostics.rs | 16 +- compiler/rustc_lint/src/diagnostics.rs | 18 +- compiler/rustc_lint/src/if_let_rescope.rs | 4 +- .../src/diagnostics/diagnostic.rs | 4 +- .../src/diagnostics/subdiagnostic.rs | 4 +- compiler/rustc_metadata/src/diagnostics.rs | 8 +- compiler/rustc_middle/src/middle/stability.rs | 4 +- compiler/rustc_middle/src/traits/mod.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 4 +- compiler/rustc_middle/src/ty/layout.rs | 6 +- compiler/rustc_mir_build/src/diagnostics.rs | 12 +- .../src/thir/pattern/migration.rs | 4 +- .../rustc_mir_transform/src/diagnostics.rs | 7 +- .../src/lint_tail_expr_drop_order.rs | 2 +- compiler/rustc_parse/src/diagnostics.rs | 16 +- compiler/rustc_parse/src/lib.rs | 6 +- .../rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_passes/src/diagnostics.rs | 8 +- compiler/rustc_resolve/src/diagnostics/mod.rs | 6 +- compiler/rustc_session/src/diagnostics.rs | 13 +- .../rustc_trait_selection/src/diagnostics.rs | 24 +-- .../src/diagnostics/note_and_explain.rs | 4 +- .../src/error_reporting/traits/overflow.rs | 7 +- .../src/error_reporting/traits/suggestions.rs | 29 ++- .../src/traits/coherence.rs | 6 +- .../src/traits/select/mod.rs | 4 +- .../src/traits/specialize/mod.rs | 4 +- .../src/diagnostics/diagnostic-structs.md | 2 +- .../clippy/clippy_utils/src/diagnostics.rs | 4 +- 46 files changed, 256 insertions(+), 315 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 3ea7902d5712d..b056fdc73d40b 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -51,7 +51,7 @@ use rustc_data_structures::stable_hash::StableOrd; #[cfg(feature = "nightly")] use rustc_error_messages::{DiagArgValue, IntoDiagArg}; #[cfg(feature = "nightly")] -use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, msg}; use rustc_hashes::Hash64; use rustc_index::{Idx, IndexSlice, IndexVec}; #[cfg(feature = "nightly")] @@ -399,7 +399,7 @@ pub enum TargetDataLayoutError<'a> { } #[cfg(feature = "nightly")] -impl Diagnostic<'_, G> for TargetDataLayoutError<'_> { +impl Diagnostic<'_, G> for TargetDataLayoutError<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { match self { TargetDataLayoutError::InvalidAddressSpace { addr_space, err, cause } => { diff --git a/compiler/rustc_ast_passes/src/diagnostics.rs b/compiler/rustc_ast_passes/src/diagnostics.rs index 5ab905b5df52b..337ce7591900f 100644 --- a/compiler/rustc_ast_passes/src/diagnostics.rs +++ b/compiler/rustc_ast_passes/src/diagnostics.rs @@ -2,7 +2,7 @@ use rustc_abi::ExternAbi; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic}; +use rustc_errors::{Applicability, Diag, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -663,7 +663,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec); // The derive for `Vec` does multiple calls to `span_label`, adding commas between each impl Subdiagnostic for EmptyLabelManySpans { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.0, ""); } } diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 663915e39dccd..224014380f9ac 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -3,8 +3,7 @@ use std::num::IntErrorKind; use rustc_attr_ir::{AttrPath, MirDialect, MirPhase}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, E0264, EmissionGuarantee, Level, - MultiSpan, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, E0264, Level, MultiSpan, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -1473,9 +1472,7 @@ impl<'a> AttributeParseError<'a> { diag: &mut Diag<'_, G>, possibilities: &[Symbol], strings: bool, - ) where - G: EmissionGuarantee, - { + ) { let quote = if strings { '"' } else { '`' }; match possibilities { &[] => {} @@ -1508,9 +1505,7 @@ impl<'a> AttributeParseError<'a> { diag: &mut Diag<'_, G>, possibilities: &[Symbol], strings: bool, - ) where - G: EmissionGuarantee, - { + ) { let description = self.description(); let quote = if strings { '"' } else { '`' }; @@ -1539,10 +1534,7 @@ impl<'a> AttributeParseError<'a> { } } - fn render_suggestions(&self, diag: &mut Diag<'_, G>) - where - G: EmissionGuarantee, - { + fn render_suggestions(&self, diag: &mut Diag<'_, G>) { let description = self.description(); match &self.suggestions { @@ -1591,7 +1583,7 @@ impl AttributeParseErrorSuggestions { } } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { +impl<'a, G> Diagnostic<'a, G> for AttributeParseError<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let name = self.path.to_string(); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 1b633aefc22f8..429eb85ed9e11 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -2,7 +2,7 @@ use std::assert_matches; -use rustc_errors::{Applicability, Diag, EmissionGuarantee}; +use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_infer::infer::NllRegionVariableOrigin; @@ -55,7 +55,7 @@ impl<'tcx> BorrowExplanation<'tcx> { pub(crate) fn is_explained(&self) -> bool { !matches!(self, BorrowExplanation::Unexplained) } - pub(crate) fn add_explanation_to_diagnostic( + pub(crate) fn add_explanation_to_diagnostic( &self, cx: &MirBorrowckCtxt<'_, '_, 'tcx>, err: &mut Diag<'_, G>, @@ -437,7 +437,7 @@ impl<'tcx> BorrowExplanation<'tcx> { } } - fn add_object_lifetime_default_note( + fn add_object_lifetime_default_note( &self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, G>, @@ -494,7 +494,7 @@ impl<'tcx> BorrowExplanation<'tcx> { } } - fn add_lifetime_bound_suggestion_to_diagnostic( + fn add_lifetime_bound_suggestion_to_diagnostic( &self, err: &mut Diag<'_, G>, category: &ConstraintCategory<'tcx>, @@ -523,7 +523,7 @@ impl<'tcx> BorrowExplanation<'tcx> { } } -fn suggest_rewrite_if_let( +fn suggest_rewrite_if_let( tcx: TyCtxt<'_>, expr: &hir::Expr<'_>, pat: &str, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 0e5ab5c00bd76..c5cf8d36abf1f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::formatting::DiagMessageAddArg; -use rustc_errors::{Applicability, Diag, DiagMessage, EmissionGuarantee, MultiSpan, listify, msg}; +use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan, listify, msg}; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{ @@ -669,7 +669,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// /// This is very similar to `fn suggest_static_lifetime_for_gat_from_hrtb` which handles this /// note for failed type tests instead of outlives errors. - fn add_placeholder_from_predicate_note( + fn add_placeholder_from_predicate_note( &self, diag: &mut Diag<'_, G>, path: &[OutlivesConstraint<'tcx>], @@ -731,7 +731,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// Add a label to region errors and borrow explanations when outlives constraints arise from /// proving a type implements `Sized` or `Copy`. - fn add_sized_or_copy_bound_info( + fn add_sized_or_copy_bound_info( &self, err: &mut Diag<'_, G>, blamed_category: ConstraintCategory<'tcx>, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 4e8237178d0fc..3b457d10f51bd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display}; use std::iter; use rustc_data_structures::fx::IndexEntry; -use rustc_errors::{Diag, EmissionGuarantee}; +use rustc_errors::Diag; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_middle::ty::print::RegionHighlightMode; @@ -105,7 +105,7 @@ impl RegionName { } } - pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_, G>) { + pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_, G>) { match &self.source { RegionNameSource::NamedLateParamRegion(span) | RegionNameSource::NamedEarlyParamRegion(span) => { diff --git a/compiler/rustc_builtin_macros/src/diagnostics.rs b/compiler/rustc_builtin_macros/src/diagnostics.rs index 4ebc39f1976fb..604341c3e7bbf 100644 --- a/compiler/rustc_builtin_macros/src/diagnostics.rs +++ b/compiler/rustc_builtin_macros/src/diagnostics.rs @@ -1,8 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ - Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans, - Subdiagnostic, msg, + Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan, SingleLabelManySpans, Subdiagnostic, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; @@ -543,7 +542,7 @@ pub(crate) struct EnvNotDefinedWithUserMessage { } // Hand-written implementation to support custom user messages. -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage { +impl<'a, G> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, self.msg_from_user.to_string()); @@ -774,7 +773,7 @@ pub(crate) struct FormatUnusedArg { // Allow the singular form to be a subdiagnostic of the multiple-unused // form of diagnostic. impl Subdiagnostic for FormatUnusedArg { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label( self.span, msg!( @@ -958,7 +957,7 @@ pub(crate) struct AsmClobberNoReg { pub(crate) clobbers: Vec, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg { +impl<'a, G> Diagnostic<'a, G> for AsmClobberNoReg { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new( dcx, diff --git a/compiler/rustc_codegen_llvm/src/diagnostics.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs index 70a14288aec0c..86fa6fd46e570 100644 --- a/compiler/rustc_codegen_llvm/src/diagnostics.rs +++ b/compiler/rustc_codegen_llvm/src/diagnostics.rs @@ -2,9 +2,7 @@ use std::ffi::{CString, c_uint}; use std::path::Path; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_errors::{ - Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, format_diag_message, msg, -}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, format_diag_message, msg}; use rustc_macros::Diagnostic; use rustc_span::Span; @@ -22,7 +20,7 @@ pub(crate) struct SanitizerMemtagRequiresMte; pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); -impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { +impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { // Reuse the formatted primary message from `LlvmError` without emitting it. let diag: Diag<'_, ()> = self.0.into_diag(dcx, level); @@ -141,7 +139,7 @@ pub(crate) enum LlvmError<'a> { pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String); -impl Diagnostic<'_, G> for WithLlvmError<'_> { +impl Diagnostic<'_, G> for WithLlvmError<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { use LlvmError::*; let msg_with_llvm_err = match &self.0 { diff --git a/compiler/rustc_codegen_ssa/src/diagnostics.rs b/compiler/rustc_codegen_ssa/src/diagnostics.rs index 4c9c78f909230..8aa2da904bd07 100644 --- a/compiler/rustc_codegen_ssa/src/diagnostics.rs +++ b/compiler/rustc_codegen_ssa/src/diagnostics.rs @@ -9,8 +9,7 @@ use std::process::ExitStatus; use rustc_abi::NumScalableVectors; use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg, - Level, msg, + Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, IntoDiagArg, Level, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; @@ -203,7 +202,7 @@ pub enum LinkRlibError { pub(crate) struct ThorinErrorWrapper(pub thorin::Error); -impl Diagnostic<'_, G> for ThorinErrorWrapper { +impl Diagnostic<'_, G> for ThorinErrorWrapper { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let build = |msg| Diag::new(dcx, level, msg); match self.0 { @@ -335,7 +334,7 @@ pub(crate) struct LinkingFailed<'a> { pub sysroot_dir: PathBuf, } -impl Diagnostic<'_, G> for LinkingFailed<'_> { +impl Diagnostic<'_, G> for LinkingFailed<'_> { fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, msg!("linking with `{$linker_path}` failed: {$exit_status}")); @@ -464,7 +463,7 @@ pub(crate) struct LinkExeUnexpectedError; pub(crate) struct LinkExeStatusStackBufferOverrun; -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for LinkExeStatusStackBufferOverrun { +impl<'a, G> Diagnostic<'a, G> for LinkExeStatusStackBufferOverrun { fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, msg!("0xc0000409 is `STATUS_STACK_BUFFER_OVERRUN`")); diag.note(msg!( @@ -1266,7 +1265,7 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { #[help("add the missing features in a `target_feature` attribute")] pub(crate) struct MissingFeatures; -impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { +impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( dcx, diff --git a/compiler/rustc_const_eval/src/diagnostics.rs b/compiler/rustc_const_eval/src/diagnostics.rs index 9faf9a59fc22a..b4dd468d7c9ee 100644 --- a/compiler/rustc_const_eval/src/diagnostics.rs +++ b/compiler/rustc_const_eval/src/diagnostics.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; -use rustc_errors::{Diag, DiagArgValue, EmissionGuarantee, MultiSpan, Subdiagnostic, msg}; +use rustc_errors::{Diag, DiagArgValue, MultiSpan, Subdiagnostic, msg}; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{Mutability, Ty}; @@ -317,7 +317,7 @@ pub(crate) struct FrameNote { } impl Subdiagnostic for FrameNote { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut span: MultiSpan = self.span.into(); if self.has_label && !self.span.is_dummy() { span.push_span_label(self.span, msg!("the failure occurred here")); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index d935299769871..ae4bd0426545d 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -20,67 +20,23 @@ use crate::{ Suggestions, }; -/// Trait for types that `Diag::emit` can return as a "guarantee" (or "proof") -/// token that the emission happened. -pub trait EmissionGuarantee: Sized { - /// This exists so that bugs and fatal errors can both result in `!` (an - /// abort) when emitted, but have different aborting behaviour. - type EmitResult = Self; - - /// Implementation of `Diag::emit`, fully controlled by each `impl` of - /// `EmissionGuarantee`, to make it impossible to create a value of - /// `Self::EmitResult` without actually performing the emission. - #[track_caller] - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult; -} - -impl EmissionGuarantee for ErrorGuaranteed { - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_error_guaranteed() - } -} - -impl EmissionGuarantee for () { - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - } -} - /// Marker type which enables implementation of `create_bug` and `emit_bug` functions for /// bug diagnostics. #[derive(Copy, Clone)] pub struct BugAbort; -impl EmissionGuarantee for BugAbort { - type EmitResult = !; - - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - panic::panic_any(ExplicitBug); - } -} - /// Marker type which enables implementation of `create_fatal` and `emit_fatal` functions for /// fatal diagnostics. #[derive(Copy, Clone)] pub struct FatalAbort; -impl EmissionGuarantee for FatalAbort { - type EmitResult = !; - - fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult { - diag.emit_producing_nothing(); - crate::FatalError.raise() - } -} - /// Trait implemented by error types. This is rarely implemented manually. Instead, use /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. /// /// When implemented manually, it should be generic over the emission /// guarantee, i.e.: /// ```ignore (fragment) -/// impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for Foo { ... } +/// impl<'a, G> Diagnostic<'a, G> for Foo { ... } /// ``` /// rather than being specific: /// ```ignore (fragment) @@ -95,7 +51,7 @@ impl EmissionGuarantee for FatalAbort { /// rather than the `Diagnostic` impl. /// - Derived impls are always generic, and it's good for the hand-written /// impls to be consistent with them. -pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { +pub trait Diagnostic<'a, G = ErrorGuaranteed> { /// Write out as a diagnostic out of `DiagCtxt`. #[must_use] #[track_caller] @@ -105,7 +61,6 @@ pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { impl<'a, T, G> Diagnostic<'a, G> for Spanned where T: Diagnostic<'a, G>, - G: EmissionGuarantee, { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { self.node.into_diag(dcx, level).with_span(self.span) @@ -127,7 +82,7 @@ impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for DiagDecorator { /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic]. pub trait Subdiagnostic { /// Add a subdiagnostic to an existing diagnostic. - fn add_to_diag(self, diag: &mut Diag<'_, G>); + fn add_to_diag(self, diag: &mut Diag<'_, G>); } #[derive(Clone, Debug, Encodable, Decodable)] @@ -433,16 +388,16 @@ pub struct Subdiag { /// Wraps a `DiagInner`, adding some useful things. /// - The `dcx` field, allowing it to (a) emit itself, and (b) do a drop check /// that it has been emitted or cancelled. -/// - The `EmissionGuarantee`, which determines the type returned from `emit`. +/// - `G`, which determines the type returned from `emit`. /// /// Each constructed `Diag` must be consumed by a function such as `emit`, -/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurs if a `Diag` -/// is dropped without being consumed by one of these functions. +/// `cancel`, or `delay_as_bug`. A panic occurs if a `Diag` is dropped without +/// being consumed by one of these functions. /// /// If there is some state in a downstream crate you would like to access in /// the methods of `Diag` here, consider extending `DiagCtxtFlags`. #[must_use] -pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> { +pub struct Diag<'a, G = ErrorGuaranteed> { pub dcx: DiagCtxtHandle<'a>, /// Why the `Option`? It is always `Some` until the `Diag` is consumed via @@ -465,7 +420,7 @@ impl !Clone for Diag<'_, G> {} rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::()); -impl Deref for Diag<'_, G> { +impl Deref for Diag<'_, G> { type Target = DiagInner; fn deref(&self) -> &DiagInner { @@ -473,18 +428,80 @@ impl Deref for Diag<'_, G> { } } -impl DerefMut for Diag<'_, G> { +impl DerefMut for Diag<'_, G> { fn deref_mut(&mut self) -> &mut DiagInner { self.diag.as_mut().unwrap() } } -impl Debug for Diag<'_, G> { +impl Debug for Diag<'_, G> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.diag.fmt(f) } } +impl Diag<'_, BugAbort> { + #[track_caller] + pub fn emit(self) -> ! { + assert_eq!(self.level, Level::Bug); + self.emit_producing_nothing(); + panic::panic_any(ExplicitBug); + } +} + +impl Diag<'_, FatalAbort> { + #[track_caller] + pub fn emit(self) -> ! { + assert_eq!(self.level, Level::Fatal); + self.emit_producing_nothing(); + crate::FatalError.raise() + } +} + +impl Diag<'_, ErrorGuaranteed> { + #[track_caller] + pub fn emit(self) -> ErrorGuaranteed { + self.emit_producing_error_guaranteed() + } + + /// Emit the diagnostic unless `delay` is true, + /// in which case the emission will be delayed as a bug. + /// + /// See `emit` and `delay_as_bug` for details. + #[track_caller] + pub fn emit_unless_delay(mut self, delay: bool) -> ErrorGuaranteed { + if delay { + self.downgrade_to_delayed_bug(); + } + self.emit() + } + + /// Delay emission of this diagnostic as a bug. + /// + /// This can be useful in contexts where an error indicates a bug but + /// typically this only happens when other compilation errors have already + /// happened. In those cases this can be used to defer emission of this + /// diagnostic as a bug in the compiler only if no other errors have been + /// emitted. + /// + /// In the meantime, though, callsites are required to deal with the "bug" + /// locally in whichever way makes the most sense. + #[track_caller] + pub fn delay_as_bug(mut self) -> ErrorGuaranteed { + self.downgrade_to_delayed_bug(); + self.emit() + } +} + +impl Diag<'_, ()> { + #[track_caller] + pub fn emit(self) { + assert_ne!(self.level, Level::Bug); + assert_ne!(self.level, Level::Fatal); + self.emit_producing_nothing(); + } +} + /// `Diag` impls many `&mut self -> &mut Self` methods. Each one modifies an /// existing diagnostic, either in a standalone fashion, e.g. /// `err.code(code);`, or in a chained fashion to make multiple modifications, @@ -528,7 +545,7 @@ macro_rules! with_fn { }; } -impl<'a, G: EmissionGuarantee> Diag<'a, G> { +impl<'a, G> Diag<'a, G> { #[track_caller] pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into) -> Self { Self::new_diagnostic(dcx, DiagInner::new(level, message)) @@ -566,13 +583,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self.level = Level::DelayedBug; } - /// Make emitting this diagnostic fatal - /// - /// Changes the level of this diagnostic to Fatal, and importantly also changes the emission guarantee. - /// This is sound for errors that would otherwise be printed, but now simply exit the process instead. - /// This function still gives an emission guarantee, the guarantee is now just that it exits fatally. - /// For delayed bugs this is different, since those are buffered. If we upgrade one to fatal, another - /// might now be ignored. + /// Make emitting this diagnostic fatal. #[track_caller] pub fn upgrade_to_fatal(mut self) -> Diag<'a, FatalAbort> { assert!( @@ -1282,13 +1293,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self } - /// Most `emit_producing_guarantee` functions use this as a starting point. + /// Most `emit` methods use this as a starting point. fn emit_producing_nothing(mut self) { let diag = self.take_diag(); self.dcx.emit_diagnostic(diag); } - /// `ErrorGuaranteed::emit_producing_guarantee` uses this. + /// `Diag<'_, ErrorGuaranteed>::emit` uses this. fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed { let diag = self.take_diag(); @@ -1310,24 +1321,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { guar.unwrap() } - /// Emit and consume the diagnostic. - #[track_caller] - pub fn emit(self) -> G::EmitResult { - G::emit_producing_guarantee(self) - } - - /// Emit the diagnostic unless `delay` is true, - /// in which case the emission will be delayed as a bug. - /// - /// See `emit` and `delay_as_bug` for details. - #[track_caller] - pub fn emit_unless_delay(mut self, delay: bool) -> G::EmitResult { - if delay { - self.downgrade_to_delayed_bug(); - } - self.emit() - } - /// Cancel and consume the diagnostic. (A diagnostic must either be emitted or /// cancelled or it will panic when dropped). pub fn cancel(mut self) { @@ -1347,27 +1340,11 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { let diag = self.take_diag(); self.dcx.stash_diagnostic(span, key, diag) } - - /// Delay emission of this diagnostic as a bug. - /// - /// This can be useful in contexts where an error indicates a bug but - /// typically this only happens when other compilation errors have already - /// happened. In those cases this can be used to defer emission of this - /// diagnostic as a bug in the compiler only if no other errors have been - /// emitted. - /// - /// In the meantime, though, callsites are required to deal with the "bug" - /// locally in whichever way makes the most sense. - #[track_caller] - pub fn delay_as_bug(mut self) -> G::EmitResult { - self.downgrade_to_delayed_bug(); - self.emit() - } } /// Destructor bomb: every `Diag` must be consumed (emitted, cancelled, etc.) /// or we emit a bug. -impl Drop for Diag<'_, G> { +impl Drop for Diag<'_, G> { fn drop(&mut self) { match self.diag.take() { Some(diag) if !panicking() => { diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index ba7569c51a07b..b002b8932a239 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -5,7 +5,7 @@ use rustc_macros::Subdiagnostic; use rustc_span::{Span, Symbol}; use crate::diagnostic::DiagLocation; -use crate::{Diag, EmissionGuarantee, Subdiagnostic}; +use crate::{Diag, Subdiagnostic}; impl IntoDiagArg for DiagLocation { fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { @@ -42,7 +42,7 @@ pub struct SingleLabelManySpans { pub label: &'static str, } impl Subdiagnostic for SingleLabelManySpans { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_labels(self.spans, self.label); } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 3374d71461cfa..9ca0344058d7f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -3,8 +3,6 @@ //! This module contains the code for creating and emitting diagnostics. // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(never_type))] -#![feature(associated_type_defaults)] #![feature(default_field_values)] #![feature(macro_metavar_expr_concat)] #![feature(negative_impls)] @@ -35,7 +33,7 @@ pub use codes::*; pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; pub use diagnostic::{ BugAbort, Diag, DiagDecorator, DiagInner, DiagLocation, DiagStyledString, Diagnostic, - EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic, + FatalAbort, StringPart, Subdiag, Subdiagnostic, }; pub use diagnostic_impls::{ DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, @@ -1565,19 +1563,19 @@ impl DelayedDiagInner { } } -/// | Level | is_error | EmissionGuarantee | Top-level | Used in lints? -/// | ----- | -------- | ----------------- | --------- | -------------- -/// | Bug | yes | BugAbort | yes | - -/// | Fatal | yes | FatalAbort | yes | - -/// | Error | yes | ErrorGuaranteed | yes | yes -/// | DelayedBug | yes | ErrorGuaranteed | yes | - -/// | ForceWarning | - | () | yes | lint-only -/// | Warning | - | () | yes | yes -/// | Note | - | () | rare | - -/// | Help | - | () | rare | - -/// | FailureNote | - | () | rare | - -/// | Allow | - | () | yes | lint-only -/// | Expect | - | () | yes | lint-only +/// | Level | is_error | emit return type | Top-level | Used in lints? +/// | ----- | -------- | ---------------- | --------- | -------------- +/// | Bug | yes | BugAbort | yes | - +/// | Fatal | yes | FatalAbort | yes | - +/// | Error | yes | ErrorGuaranteed | yes | yes +/// | DelayedBug | yes | ErrorGuaranteed | yes | - +/// | ForceWarning | - | () | yes | lint-only +/// | Warning | - | () | yes | yes +/// | Note | - | () | rare | - +/// | Help | - | () | rare | - +/// | FailureNote | - | () | rare | - +/// | Allow | - | () | yes | lint-only +/// | Expect | - | () | yes | lint-only /// #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug, Encodable, Decodable)] pub enum Level { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 9f8cde7892fb0..85338b10dfa58 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -4,7 +4,7 @@ use std::ops::ControlFlow; use rustc_abi::{ExternAbi, FieldIdx, MAX_SIMD_LANES, ScalableElt}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; -use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; use rustc_hir as hir; use rustc_hir::attrs::ReprAttr::ReprPacked; use rustc_hir::attrs::lang_items::LangItem; @@ -41,7 +41,7 @@ use crate::check::wfcheck::{ use crate::collect::ItemCtxt; use crate::diagnostics; -fn add_abi_diag_help(abi: ExternAbi, diag: &mut Diag<'_, T>) { +fn add_abi_diag_help(abi: ExternAbi, diag: &mut Diag<'_, G>) { if let ExternAbi::Cdecl { unwind } = abi { let c_abi = ExternAbi::C { unwind }; diag.help(format!("use `extern {c_abi}` instead",)); diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index a50aefd016059..1f0c493b881f1 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -3,8 +3,7 @@ use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - MultiSpan, listify, msg, + Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, Level, MultiSpan, listify, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -468,7 +467,7 @@ pub(crate) struct MissingGenericParams { } // FIXME: This doesn't need to be a manual impl! -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingGenericParams { +impl<'a, G> Diagnostic<'a, G> for MissingGenericParams { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut err = Diag::new( @@ -2070,7 +2069,7 @@ pub(crate) struct UncoveredTyParam<'tcx> { pub(crate) local_ty: Option>, } -impl Diagnostic<'_, G> for UncoveredTyParam<'_> { +impl Diagnostic<'_, G> for UncoveredTyParam<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let Self { param, local_ty } = self; diff --git a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs index 8a38207884184..e995d4fdf697b 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics/wrong_number_of_generic_args.rs @@ -1,6 +1,6 @@ use GenericArgsInfo::*; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize}; +use rustc_errors::{Applicability, Diag, Diagnostic, MultiSpan, pluralize}; use rustc_hir as hir; use rustc_middle::ty::{self as ty, AssocItem, AssocItems, TyCtxt}; use rustc_span::def_id::DefId; @@ -543,7 +543,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Builds the `expected 1 type argument / supplied 2 type arguments` message. - fn notify(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn notify(&self, err: &mut Diag<'_, G>) { let (quantifier, bound) = self.get_quantifier_and_bound(); let provided_args = self.num_provided_args(); @@ -595,7 +595,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest(&self, err: &mut Diag<'_, G>) { debug!( "suggest(self.provided {:?}, self.gen_args.span(): {:?})", self.num_provided_args(), @@ -623,7 +623,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap; /// ``` - fn suggest_adding_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest_adding_args(&self, err: &mut Diag<'_, G>) { if self.gen_args.parenthesized != hir::GenericArgsParentheses::No { return; } @@ -650,7 +650,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest_adding_lifetime_args(&self, err: &mut Diag<'_, G>) { debug!("suggest_adding_lifetime_args(path_segment: {:?})", self.path_segment); let num_missing_args = self.num_missing_lifetime_args(); let num_params_to_take = num_missing_args; @@ -704,7 +704,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest_adding_type_and_const_args(&self, err: &mut Diag<'_, G>) { let num_missing_args = self.num_missing_type_or_const_args(); let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args)); @@ -764,10 +764,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```compile_fail /// Into::into::>(42) // suggests considering `Into::>::into(42)` /// ``` - fn suggest_moving_args_from_assoc_fn_to_trait( - &self, - err: &mut Diag<'_, impl EmissionGuarantee>, - ) { + fn suggest_moving_args_from_assoc_fn_to_trait(&self, err: &mut Diag<'_, G>) { let Some(trait_) = self.tcx.trait_of_assoc(self.def_id) else { return; }; @@ -820,9 +817,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( + fn suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( &self, - err: &mut Diag<'_, impl EmissionGuarantee>, + err: &mut Diag<'_, G>, qpath: &'tcx hir::QPath<'tcx>, msg: String, num_assoc_fn_excess_args: usize, @@ -851,9 +848,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } - fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( + fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( &self, - err: &mut Diag<'_, impl EmissionGuarantee>, + err: &mut Diag<'_, G>, trait_def_id: DefId, expr: &'tcx hir::Expr<'tcx>, msg: String, @@ -907,7 +904,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// ```text /// type Map = HashMap; /// ``` - fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn suggest_removing_args_or_generics(&self, err: &mut Diag<'_, G>) { let num_provided_lt_args = self.num_provided_lifetime_args(); let num_provided_type_const_args = self.num_provided_type_or_const_args(); let unbound_assoc_items = self.get_unbound_associated_item(); @@ -1099,7 +1096,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Builds the `type defined here` message. - fn show_definition(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn show_definition(&self, err: &mut Diag<'_, G>) { let Some(def_span) = self.tcx.def_ident_span(self.def_id) else { return }; if !self.tcx.sess.source_map().is_span_accessible(def_span) { return; @@ -1146,7 +1143,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } /// Add note if `impl Trait` is explicitly specified. - fn note_synth_provided(&self, err: &mut Diag<'_, impl EmissionGuarantee>) { + fn note_synth_provided(&self, err: &mut Diag<'_, G>) { if !self.is_synth_provided() { return; } @@ -1155,7 +1152,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for WrongNumberOfGenericArgs<'_, '_> { +impl<'a, G> Diagnostic<'a, G> for WrongNumberOfGenericArgs<'_, '_> { fn into_diag( self, dcx: rustc_errors::DiagCtxtHandle<'a>, 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 102a3013b38ad..beacb3f188cd9 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 @@ -2,8 +2,8 @@ use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, StashKey, - Suggestions, struct_span_code_err, + Applicability, Diag, DiagCtxtHandle, Diagnostic, Level, StashKey, Suggestions, + struct_span_code_err, }; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def::{DefKind, Res}; @@ -739,7 +739,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Make sure that we are in the condition to suggest the blanket implementation. - fn maybe_suggest_blanket_trait_impl( + fn maybe_suggest_blanket_trait_impl( &self, span: Span, hir_id: hir::HirId, diff --git a/compiler/rustc_hir_typeck/src/diagnostics.rs b/compiler/rustc_hir_typeck/src/diagnostics.rs index 2d4cf3d9b400d..3b7de7790ac02 100644 --- a/compiler/rustc_hir_typeck/src/diagnostics.rs +++ b/compiler/rustc_hir_typeck/src/diagnostics.rs @@ -6,8 +6,8 @@ use rustc_abi::ExternAbi; use rustc_ast::{AssignOpKind, Label}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, - EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, IntoDiagArg, + Level, MultiSpan, Subdiagnostic, msg, }; use rustc_hir as hir; use rustc_hir::ExprKind; @@ -275,7 +275,7 @@ pub(crate) struct SuggestAnnotations { pub suggestions: Vec, } impl Subdiagnostic for SuggestAnnotations { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { if self.suggestions.is_empty() { return; } @@ -338,7 +338,7 @@ pub(crate) struct TypeMismatchFruTypo { } impl Subdiagnostic for TypeMismatchFruTypo { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("expr", self.expr.as_deref().unwrap_or("NONE")); // Only explain that `a ..b` is a range if it's split up @@ -561,7 +561,7 @@ pub(crate) struct RemoveSemiForCoerce { } impl Subdiagnostic for RemoveSemiForCoerce { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multispan: MultiSpan = self.semi.into(); multispan.push_span_label( self.expr, @@ -704,7 +704,7 @@ pub(crate) struct BreakNonLoop<'a> { pub break_expr_span: Span, } -impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> { +impl<'a, G> Diagnostic<'_, G> for BreakNonLoop<'a> { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, msg!("`break` with value from a `{$kind}` loop")); @@ -906,7 +906,7 @@ pub(crate) enum CastUnknownPointerSub { } impl rustc_errors::Subdiagnostic for CastUnknownPointerSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { CastUnknownPointerSub::To(span) => { let msg = msg!("needs more type information"); @@ -1202,7 +1202,7 @@ pub(crate) struct NakedFunctionsAsmBlock { pub non_asms: Vec, } -impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { +impl Diagnostic<'_, G> for NakedFunctionsAsmBlock { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index cfae7afd8f4f3..d96cadaca87eb 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -5,8 +5,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, - EmissionGuarantee, Level, Subdiagnostic, SuggestionStyle, msg, + Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, Level, + Subdiagnostic, SuggestionStyle, msg, }; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -42,7 +42,7 @@ pub(crate) enum OverruledAttributeSub { } impl Subdiagnostic for OverruledAttributeSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { OverruledAttributeSub::DefaultSource { id } => { diag.note(msg!("`forbid` lint level is the default for {$id}")); @@ -638,7 +638,7 @@ pub(crate) struct BuiltinUnpermittedTypeInitSub { } impl Subdiagnostic for BuiltinUnpermittedTypeInitSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut err = self.err; loop { if let Some(span) = err.span { @@ -689,7 +689,7 @@ pub(crate) struct BuiltinClashingExternSub<'a> { } impl Subdiagnostic for BuiltinClashingExternSub<'_> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut expected_str = DiagStyledString::new(); expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); let mut found_str = DiagStyledString::new(); @@ -1363,7 +1363,7 @@ pub(crate) struct NonBindingLetSub { } impl Subdiagnostic for NonBindingLetSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar; if can_suggest_binding { @@ -1740,7 +1740,7 @@ pub(crate) enum NonSnakeCaseDiagSub { } impl Subdiagnostic for NonSnakeCaseDiagSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { NonSnakeCaseDiagSub::Label { span } => { diag.span_label(span, msg!("should have a snake_case name")); @@ -2924,7 +2924,7 @@ pub(crate) struct MismatchedLifetimeSyntaxes { pub suggestions: Vec, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MismatchedLifetimeSyntaxes { +impl<'a, G> Diagnostic<'a, G> for MismatchedLifetimeSyntaxes { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let counts = self.inputs.len() + self.outputs.len(); let message = match counts { @@ -3037,7 +3037,7 @@ impl MismatchedLifetimeSyntaxesSuggestion { } impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { use MismatchedLifetimeSyntaxesSuggestion::*; let style = |optional_alternative| { diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 47a3f528b9854..1cd701db7d10e 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use hir::intravisit::{self, Visitor}; use rustc_ast::Recovered; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle, msg}; +use rustc_errors::{Applicability, Diag, Subdiagnostic, SuggestionStyle, msg}; use rustc_hir::{self as hir, HirIdSet}; use rustc_lint_defs::{LintId, declare_lint, fcw, impl_lint_pass}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -324,7 +324,7 @@ struct IfLetRescopeRewrite { } impl Subdiagnostic for IfLetRescopeRewrite { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut suggestions = vec![]; for match_head in self.match_heads { match match_head { diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index ac777b37a4303..72e7423fc2d88 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -48,9 +48,7 @@ impl<'a> DiagnosticDerive<'a> { // A lifetime of `'a` causes conflicts, but `_sess` is fine. structure.gen_impl(quote! { - gen impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for @Self - where G: rustc_errors::EmissionGuarantee - { + gen impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for @Self { #[track_caller] fn into_diag( self, diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index c99575ff7431d..d6b101ca0addf 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -97,9 +97,7 @@ impl SubdiagnosticDerive { fn add_to_diag<__G>( self, #diag: &mut rustc_errors::Diag<'_, __G>, - ) where - __G: rustc_errors::EmissionGuarantee, - { + ) { #implementation } } diff --git a/compiler/rustc_metadata/src/diagnostics.rs b/compiler/rustc_metadata/src/diagnostics.rs index b98a0ce25af37..a093e7990ea28 100644 --- a/compiler/rustc_metadata/src/diagnostics.rs +++ b/compiler/rustc_metadata/src/diagnostics.rs @@ -2,7 +2,7 @@ use std::io::Error; use std::path::{Path, PathBuf}; use rustc_errors::codes::*; -use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, msg}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol, sym}; use rustc_target::spec::{PanicStrategy, TargetTuple}; @@ -305,7 +305,7 @@ pub(crate) struct MultipleCandidates { pub candidates: Vec, } -impl Diagnostic<'_, G> for MultipleCandidates { +impl Diagnostic<'_, G> for MultipleCandidates { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( dcx, @@ -418,7 +418,7 @@ pub(crate) struct InvalidMetadataFiles { pub crate_rejections: Vec, } -impl Diagnostic<'_, G> for InvalidMetadataFiles { +impl Diagnostic<'_, G> for InvalidMetadataFiles { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( @@ -450,7 +450,7 @@ pub(crate) struct CannotFindCrate { pub is_tier_3: bool, } -impl Diagnostic<'_, G> for CannotFindCrate { +impl Diagnostic<'_, G> for CannotFindCrate { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 8dafdc9cc7d33..2ad73c8894da5 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -7,7 +7,7 @@ use rustc_ast::NodeId; use rustc_attr_ir::{ ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, StabilityLevel, }; -use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, LintBuffer, msg}; +use rustc_errors::{Applicability, Diag, Diagnostic, LintBuffer, msg}; use rustc_feature::GateIssue; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, HirId}; @@ -114,7 +114,7 @@ pub(crate) struct Deprecated { pub since_kind: DeprecatedSinceKind, } -impl<'a, G: EmissionGuarantee> rustc_errors::Diagnostic<'a, G> for Deprecated { +impl<'a, G> rustc_errors::Diagnostic<'a, G> for Deprecated { fn into_diag( self, dcx: rustc_errors::DiagCtxtHandle<'a>, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 4dfc8d7c9705d..40905cd780ee8 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -13,7 +13,7 @@ use std::borrow::Cow; use std::hash::{Hash, Hasher}; use std::sync::Arc; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::HirId; use rustc_hir::def_id::DefId; @@ -914,7 +914,7 @@ pub enum DynCompatibilityViolationSolution { } impl DynCompatibilityViolationSolution { - pub fn add_to(self, err: &mut Diag<'_, G>) { + pub fn add_to(self, err: &mut Diag<'_, G>) { match self { DynCompatibilityViolationSolution::None => {} DynCompatibilityViolationSolution::AddSelfOrMakeSized { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0b580812572eb..c1ff755fedc22 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2637,9 +2637,9 @@ impl<'tcx> TyCtxt<'tcx> { m.spans.inject_use_span.shrink_to_lo() } - pub fn disabled_nightly_features( + pub fn disabled_nightly_features( self, - diag: &mut Diag<'_, E>, + diag: &mut Diag<'_, G>, features: impl IntoIterator, ) { if !self.sess.is_nightly_build() { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 85e1df8b057a0..7006568a2ef33 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -6,9 +6,7 @@ use rustc_abi::{ PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, TyAbiInterface, VariantIdx, Variants, }; -use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, -}; +use rustc_errors::{Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, IntoDiagArg, Level}; use rustc_hir as hir; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def_id::DefId; @@ -1344,7 +1342,7 @@ pub enum FnAbiError<'tcx> { Layout(LayoutError<'tcx>), } -impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> { +impl<'a, 'b, G> Diagnostic<'a, G> for FnAbiError<'b> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { match self { Self::Layout(e) => Diag::new(dcx, level, e.to_string()), diff --git a/compiler/rustc_mir_build/src/diagnostics.rs b/compiler/rustc_mir_build/src/diagnostics.rs index 154edfdf4a577..83bfd322d6444 100644 --- a/compiler/rustc_mir_build/src/diagnostics.rs +++ b/compiler/rustc_mir_build/src/diagnostics.rs @@ -1,7 +1,7 @@ use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - MultiSpan, Subdiagnostic, msg, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level, MultiSpan, Subdiagnostic, + msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -585,7 +585,7 @@ pub(crate) struct UnsafeNotInheritedLintNote { } impl Subdiagnostic for UnsafeNotInheritedLintNote { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_note( self.signature_span, msg!("an unsafe function restricts its caller, but its body is safe by default"), @@ -625,7 +625,7 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'a, 'tcx> { pub(crate) ty: Ty<'tcx>, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNotEmpty<'_, '_> { +impl<'a, G> Diagnostic<'a, G> for NonExhaustivePatternsTypeNotEmpty<'_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, msg!("non-exhaustive patterns: type `{$ty}` is non-empty")); @@ -730,7 +730,7 @@ pub(crate) struct UnreachablePattern<'tcx> { pub(crate) inner: UnreachablePatternInner<'tcx>, } -impl<'a, 'tcx, G: EmissionGuarantee> Diagnostic<'a, G> for UnreachablePattern<'tcx> { +impl<'a, 'tcx, G> Diagnostic<'a, G> for UnreachablePattern<'tcx> { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = self.inner.into_diag(dcx, level); @@ -1260,7 +1260,7 @@ pub(crate) struct Variant { } impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("ty", self.ty); let mut spans = MultiSpan::from(self.adt_def_span); diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs index 75e23c3a2ff16..e6db030557703 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs @@ -1,7 +1,7 @@ //! Automatic migration of Rust 2021 patterns to a form valid in both Editions 2021 and 2024. use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, pluralize}; +use rustc_errors::{Applicability, Diag, MultiSpan, pluralize}; use rustc_hir::{BindingMode, ByRef, HirId, Mutability}; use rustc_lint_defs::builtin::RUST_2024_INCOMPATIBLE_PAT; use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt}; @@ -90,7 +90,7 @@ impl<'a> PatMigration<'a> { format!("cannot {verb1}{or_verb2} within an implicitly-borrowing pattern{in_rust_2024}") } - fn format_subdiagnostics(self, diag: &mut Diag<'_, impl EmissionGuarantee>) { + fn format_subdiagnostics(self, diag: &mut Diag<'_, G>) { // Format and emit explanatory notes about default binding modes. Reversing the spans' order // means if we have nested spans, the innermost ones will be visited first. for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() { diff --git a/compiler/rustc_mir_transform/src/diagnostics.rs b/compiler/rustc_mir_transform/src/diagnostics.rs index e9150049c6741..c851b55f9623a 100644 --- a/compiler/rustc_mir_transform/src/diagnostics.rs +++ b/compiler/rustc_mir_transform/src/diagnostics.rs @@ -1,7 +1,6 @@ use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, - Subdiagnostic, msg, + Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, Level, Subdiagnostic, msg, }; use rustc_lint_defs::Lint; use rustc_lint_defs::builtin::{ARITHMETIC_OVERFLOW, UNCONDITIONAL_PANIC}; @@ -219,7 +218,7 @@ pub(crate) struct UnusedAssignOverwrite { } impl Subdiagnostic for UnusedAssignOverwrite { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.assigned_span, "this value is reassigned later and never used"); diag.span_label( self.overwrite_span, @@ -298,7 +297,7 @@ pub(crate) struct UnusedVariableStringInterp { } impl Subdiagnostic for UnusedVariableStringInterp { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label( self.lit, msg!("you might have meant to use string interpolation in this string literal"), 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 eb6921e438528..0b8cdbb2d2696 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 @@ -524,7 +524,7 @@ struct LocalLabel<'a> { /// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order impl Subdiagnostic for LocalLabel<'_> { - fn add_to_diag(self, diag: &mut rustc_errors::Diag<'_, G>) { + fn add_to_diag(self, diag: &mut rustc_errors::Diag<'_, G>) { diag.span_label( self.span, msg!( diff --git a/compiler/rustc_parse/src/diagnostics.rs b/compiler/rustc_parse/src/diagnostics.rs index 1dc2d625fe0e0..829fc5a600e8a 100644 --- a/compiler/rustc_parse/src/diagnostics.rs +++ b/compiler/rustc_parse/src/diagnostics.rs @@ -7,8 +7,8 @@ use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, Token}; use rustc_ast_pretty::pprust; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, - Level, Subdiagnostic, SuggestionStyle, msg, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, IntoDiagArg, Level, + Subdiagnostic, SuggestionStyle, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; @@ -1537,7 +1537,7 @@ pub(crate) struct ExpectedIdentifier { pub help_cannot_start_number: Option, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier { +impl<'a, G> Diagnostic<'a, G> for ExpectedIdentifier { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); @@ -1603,7 +1603,7 @@ pub(crate) struct ExpectedSemi { pub sugg: ExpectedSemiSugg, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { +impl<'a, G> Diagnostic<'a, G> for ExpectedSemi { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let token_descr = TokenDescription::from_token(&self.token); @@ -2010,7 +2010,7 @@ pub(crate) struct FnTraitMissingParen { } impl Subdiagnostic for FnTraitMissingParen { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.span_label(self.span, msg!("`Fn` bounds require arguments in parentheses")); diag.span_suggestion_short( self.span.shrink_to_hi(), @@ -3697,7 +3697,7 @@ pub(crate) struct UseDerefMacro { } impl Subdiagnostic for UseDerefMacro { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let Self { field, before, after } = self; let mut parts = Vec::new(); @@ -4355,7 +4355,7 @@ pub(crate) struct HiddenUnicodeCodepointsDiagLabels { } impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { for (c, span) in self.spans { diag.span_label(span, format!("{c:?}")); } @@ -4369,7 +4369,7 @@ pub(crate) enum HiddenUnicodeCodepointsDiagSub { // Used because of multiple multipart_suggestion and note impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { HiddenUnicodeCodepointsDiagSub::Escape { spans } => { diag.multipart_suggestion_with_style( diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 539c15f18a9a4..16a438b5387ee 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -17,7 +17,7 @@ use rustc_ast as ast; use rustc_ast::token; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; -use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize}; +use rustc_errors::{Diag, FatalError, PResult, pluralize}; pub use rustc_lexer::UNICODE_VERSION; use rustc_session::parse::ParseSess; use rustc_span::edit_distance::find_best_match_for_name; @@ -165,11 +165,11 @@ pub fn new_parser_from_file<'a>( new_parser_from_source_file(psess, source_file, strip_tokens) } -pub fn utf8_error( +pub fn utf8_error( sm: &SourceMap, path: &str, sp: Option, - err: &mut Diag<'_, E>, + err: &mut Diag<'_, G>, utf8err: Utf8Error, contents: &[u8], ) { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 6d4a0215eb7b3..8b8f3e862ae3b 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1720,7 +1720,7 @@ impl<'a> Parser<'a> { ); err.span_label(op_span, format!("not a valid {} operator", kind.fixity)); - let help_base_case = |mut err: Diag<'_, _>, base| { + let help_base_case = |mut err: Diag<'_, ErrorGuaranteed>, base| { err.help(format!("use `{}= 1` instead", kind.op.chr())); err.emit(); Ok(base) diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 5f99c4b133597..745444dd7943a 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -2,9 +2,7 @@ use std::io::Error; use std::path::{Path, PathBuf}; use rustc_errors::codes::*; -use rustc_errors::{ - Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, msg, -}; +use rustc_errors::{Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, Level, MultiSpan, msg}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::middle::resolve::MainDefinition; use rustc_middle::ty::Ty; @@ -423,7 +421,7 @@ pub(crate) struct NoMainErr { pub add_teach_note: bool, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NoMainErr { +impl<'a, G> Diagnostic<'a, G> for NoMainErr { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = @@ -489,7 +487,7 @@ pub(crate) struct DuplicateLangItem { pub(crate) duplicate: Duplicate, } -impl Diagnostic<'_, G> for DuplicateLangItem { +impl Diagnostic<'_, G> for DuplicateLangItem { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( diff --git a/compiler/rustc_resolve/src/diagnostics/mod.rs b/compiler/rustc_resolve/src/diagnostics/mod.rs index dfa58ab73778f..b581777901195 100644 --- a/compiler/rustc_resolve/src/diagnostics/mod.rs +++ b/compiler/rustc_resolve/src/diagnostics/mod.rs @@ -2,7 +2,7 @@ use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, ElidedLifetimeInPathSubdiag, - EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, + IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Spanned, Symbol}; @@ -1380,7 +1380,7 @@ pub(crate) enum ItemWas { } impl Subdiagnostic for FoundItemConfigureOut { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut multispan: MultiSpan = self.span.into(); match self.item_was { ItemWas::BehindFeature { feature, span } => { @@ -1522,7 +1522,7 @@ pub(crate) struct Ambiguity { pub is_error: bool, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for Ambiguity { +impl<'a, G> Diagnostic<'a, G> for Ambiguity { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let Self { ident, diff --git a/compiler/rustc_session/src/diagnostics.rs b/compiler/rustc_session/src/diagnostics.rs index e8f29d8a9ee77..5b3de78ef7809 100644 --- a/compiler/rustc_session/src/diagnostics.rs +++ b/compiler/rustc_session/src/diagnostics.rs @@ -4,8 +4,7 @@ use rustc_ast::token; use rustc_ast::util::literal::LitError; use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level, - MultiSpan, StashKey, + Diag, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, Level, MultiSpan, StashKey, }; use rustc_feature::{GateIssue, find_feature_issue}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -96,11 +95,7 @@ pub fn feature_warn_issue( /// Adds the diagnostics for a feature to an existing error. /// Must be a language feature! -pub fn add_feature_diagnostics( - err: &mut Diag<'_, G>, - sess: &Session, - feature: Symbol, -) { +pub fn add_feature_diagnostics(err: &mut Diag<'_, G>, sess: &Session, feature: Symbol) { add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None); } @@ -109,7 +104,7 @@ pub fn add_feature_diagnostics( /// This variant allows you to control whether it is a library or language feature. /// Almost always, you want to use this for a language feature. If so, prefer /// `add_feature_diagnostics`. -pub fn add_feature_diagnostics_for_issue( +pub fn add_feature_diagnostics_for_issue( err: &mut Diag<'_, G>, sess: &Session, feature: Symbol, @@ -197,7 +192,7 @@ pub(crate) struct FeatureGateError { pub(crate) explain: DiagMessage, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for FeatureGateError { +impl<'a, G> Diagnostic<'a, G> for FeatureGateError { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { Diag::new(dcx, level, self.explain).with_span(self.span).with_code(E0658) diff --git a/compiler/rustc_trait_selection/src/diagnostics.rs b/compiler/rustc_trait_selection/src/diagnostics.rs index 6e2a4f10fb458..02a181adfadb7 100644 --- a/compiler/rustc_trait_selection/src/diagnostics.rs +++ b/compiler/rustc_trait_selection/src/diagnostics.rs @@ -2,8 +2,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, - EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, msg, + Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, IntoDiagArg, + Level, MultiSpan, Subdiagnostic, msg, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -36,7 +36,7 @@ pub(crate) struct NegativePositiveConflict<'tcx> { pub positive_impl_span: Result, } -impl Diagnostic<'_, G> for NegativePositiveConflict<'_> { +impl Diagnostic<'_, G> for NegativePositiveConflict<'_> { #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new( @@ -89,7 +89,7 @@ pub(crate) enum AdjustSignatureBorrow { } impl Subdiagnostic for AdjustSignatureBorrow { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { AdjustSignatureBorrow::Borrow { to_borrow } => { diag.arg("borrow_len", to_borrow.len()); @@ -437,7 +437,7 @@ pub(crate) enum RegionOriginNote<'a> { } impl Subdiagnostic for RegionOriginNote<'_> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let label_or_note = |diag: &mut Diag<'_, G>, span, msg: DiagMessage| { let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); @@ -532,7 +532,7 @@ pub(crate) enum LifetimeMismatchLabels { } impl Subdiagnostic for LifetimeMismatchLabels { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { diag.span_label(param_span, msg!("this parameter and the return type are declared with different lifetimes...")); @@ -605,7 +605,7 @@ pub(crate) struct AddLifetimeParamsSuggestion<'a> { } impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut mk_suggestion = || { let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) else { @@ -789,7 +789,7 @@ pub(crate) struct IntroducesStaticBecauseUnmetLifetimeReq { } impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { + fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { self.unmet_requirements.push_span_label( self.binding_span, msg!("introduces a `'static` lifetime requirement"), @@ -1184,7 +1184,7 @@ pub(crate) struct ConsiderBorrowingParamHelp { } impl Subdiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { // Seems like we can't call f() here as Into is required @@ -1661,7 +1661,7 @@ pub(crate) struct SuggestTuplePatternMany { } impl Subdiagnostic for SuggestTuplePatternMany { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("path", self.path); let message = msg!("try wrapping the pattern in a variant of `{$path}`"); diag.multipart_suggestions( @@ -1907,7 +1907,7 @@ pub(crate) struct AddPreciseCapturingAndParams { } impl Subdiagnostic for AddPreciseCapturingAndParams { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("new_lifetime", self.new_lifetime); diag.multipart_suggestion( msg!("add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate"), @@ -2047,7 +2047,7 @@ pub struct AddPreciseCapturingForOvercapture { } impl Subdiagnostic for AddPreciseCapturingForOvercapture { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let applicability = if self.apit_spans.is_empty() { Applicability::MachineApplicable } else { diff --git a/compiler/rustc_trait_selection/src/diagnostics/note_and_explain.rs b/compiler/rustc_trait_selection/src/diagnostics/note_and_explain.rs index 07b8adb898aa6..32a35b58f3186 100644 --- a/compiler/rustc_trait_selection/src/diagnostics/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/diagnostics/note_and_explain.rs @@ -1,5 +1,5 @@ use rustc_errors::formatting::DiagMessageAddArg; -use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic, msg}; +use rustc_errors::{Diag, IntoDiagArg, Subdiagnostic, msg}; use rustc_hir::def_id::LocalDefId; use rustc_middle::bug; use rustc_middle::ty::{self, TyCtxt}; @@ -163,7 +163,7 @@ impl RegionExplanation<'_> { } impl Subdiagnostic for RegionExplanation<'_> { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { + fn add_to_diag(self, diag: &mut Diag<'_, G>) { let msg = msg!( "{$pref_kind -> *[should_not_happen] [{$pref_kind}] diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index 30a18a928e842..a2b782c183c0b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -1,6 +1,6 @@ use std::fmt; -use rustc_errors::{Diag, E0275, EmissionGuarantee, ErrorGuaranteed, struct_span_code_err}; +use rustc_errors::{Diag, E0275, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def::Namespace; use rustc_hir::def_id::LOCAL_CRATE; use rustc_infer::traits::{Obligation, PredicateObligation}; @@ -17,10 +17,7 @@ pub enum OverflowCause<'tcx> { TraitSolver(ty::Predicate<'tcx>), } -pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( - tcx: TyCtxt<'tcx>, - err: &mut Diag<'_, G>, -) { +pub fn suggest_new_overflow_limit<'tcx, G>(tcx: TyCtxt<'tcx>, err: &mut Diag<'_, G>) { let suggested_limit = match tcx.recursion_limit() { Limit(0) => Limit(2), limit => limit * 2, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 95bb2fd7e40c5..a93d947612fc4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -9,8 +9,7 @@ use rustc_abi::ExternAbi; use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, EmissionGuarantee, MultiSpan, Style, SuggestionStyle, pluralize, - struct_span_code_err, + Applicability, Diag, MultiSpan, Style, SuggestionStyle, pluralize, struct_span_code_err, }; use rustc_hir::attrs::lang_items::{self, LangItem}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -120,7 +119,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) - /// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but /// it can also be an `impl Trait` param that needs to be decomposed to a type /// param for cleaner code. -pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( +pub fn suggest_restriction<'tcx, G>( tcx: TyCtxt<'tcx>, item_id: LocalDefId, hir_generics: &hir::Generics<'tcx>, @@ -2751,7 +2750,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false } - pub(super) fn suggest_borrow_for_unsized_closure_return( + pub(super) fn suggest_borrow_for_unsized_closure_return( &self, body_def_id: LocalDefId, err: &mut Diag<'_, G>, @@ -3296,7 +3295,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// /// Returns `true` if an async-await specific note was added to the diagnostic. #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))] - pub fn maybe_note_obligation_cause_for_async_await( + pub fn maybe_note_obligation_cause_for_async_await( &self, err: &mut Diag<'_, G>, obligation: &PredicateObligation<'tcx>, @@ -3528,7 +3527,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Unconditionally adds the diagnostic note described in /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. #[instrument(level = "debug", skip_all)] - fn note_obligation_cause_for_async_await( + fn note_obligation_cause_for_async_await( &self, err: &mut Diag<'_, G>, interior_or_upvar_span: CoroutineInteriorOrUpvar, @@ -3762,7 +3761,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn note_closure_capture( + fn note_closure_capture( &self, err: &mut Diag<'_, G>, closure_def_id: DefId, @@ -3814,7 +3813,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true } - pub(super) fn note_obligation_cause_code( + pub(super) fn note_obligation_cause_code( &self, body_def_id: LocalDefId, err: &mut Diag<'_, G>, @@ -3843,7 +3842,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn note_obligation_cause_code_inner( + fn note_obligation_cause_code_inner( &self, body_def_id: LocalDefId, err: &mut Diag<'_, G>, @@ -5199,7 +5198,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn note_function_argument_obligation( + fn note_function_argument_obligation( &self, body_def_id: LocalDefId, err: &mut Diag<'_, G>, @@ -5438,7 +5437,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_option_method_if_applicable( + fn suggest_option_method_if_applicable( &self, failed_pred: ty::Predicate<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -5513,7 +5512,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn look_for_iterator_item_mistakes( + fn look_for_iterator_item_mistakes( &self, assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>], typeck_results: &TypeckResults<'tcx>, @@ -5662,7 +5661,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn point_at_chain( + fn point_at_chain( &self, expr: &hir::Expr<'_>, typeck_results: &TypeckResults<'tcx>, @@ -5911,7 +5910,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// | | `Iterator::Item` is `&mut Vec` here /// | this expression has type `Vec>` /// ``` - fn point_at_chain_in_return_position( + fn point_at_chain_in_return_position( &self, body_def_id: LocalDefId, expr: &hir::Expr<'_>, @@ -7099,7 +7098,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( /// On `impl` evaluation cycles, look for `Self::AssocTy` restrictions in `where` clauses, explain /// they are not allowed and if possible suggest alternatives. -fn point_at_assoc_type_restriction( +fn point_at_assoc_type_restriction( tcx: TyCtxt<'_>, err: &mut Diag<'_, G>, self_ty_str: &str, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 24217aaf75fe7..f06aed3ac3e10 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -7,7 +7,7 @@ use std::fmt::Debug; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_errors::{Diag, EmissionGuarantee}; +use rustc_errors::Diag; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{PredicateObligations, TraitErrors}; @@ -61,14 +61,14 @@ pub struct OverlapResult<'tcx> { pub overflowing_predicates: Vec>, } -pub fn add_placeholder_note(err: &mut Diag<'_, G>) { +pub fn add_placeholder_note(err: &mut Diag<'_, G>) { err.note( "this behavior recently changed as a result of a bug fix; \ see rust-lang/rust#56105 for details", ); } -pub(crate) fn suggest_increasing_recursion_limit<'tcx, G: EmissionGuarantee>( +pub(crate) fn suggest_increasing_recursion_limit<'tcx, G>( tcx: TyCtxt<'tcx>, err: &mut Diag<'_, G>, overflowing_predicates: &[ty::Predicate<'tcx>], diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 15dfd58d6b753..54d5d68c5bd95 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -9,7 +9,7 @@ use std::ops::ControlFlow; use hir::def::DefKind; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_errors::{Diag, EmissionGuarantee}; +use rustc_errors::Diag; use rustc_hir as hir; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def_id::DefId; @@ -63,7 +63,7 @@ pub enum IntercrateAmbiguityCause<'tcx> { impl<'tcx> IntercrateAmbiguityCause<'tcx> { /// Emits notes when the overlap is caused by complex intercrate ambiguities. /// See #23980 for details. - pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diag<'_, G>) { + pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diag<'_, G>) { err.note(self.intercrate_ambiguity_hint()); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index f7351a6b8ed36..246cd8c5345ee 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -12,8 +12,8 @@ pub mod specialization_graph; use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::Diag; use rustc_errors::codes::*; -use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::Obligation; use rustc_lint_defs::builtin::COHERENCE_LEAK_CHECK; @@ -528,7 +528,7 @@ fn report_conflicting_impls<'tcx>( // Work to be done after we've built the Diag. We have to define it now // because the lint emit methods don't return back the Diag that's passed // in. - fn decorate<'tcx, G: EmissionGuarantee>( + fn decorate<'tcx, G>( tcx: TyCtxt<'tcx>, overlap: &OverlapError<'tcx>, impl_span: Span, diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md index d5a218dfa87c0..7ca97b7b059e4 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md @@ -93,7 +93,7 @@ In the end, the `Diagnostic` derive will generate an implementation of `Diagnostic` that looks like the following: ```rust,ignore -impl<'a, G: EmissionGuarantee> Diagnostic<'a> for FieldAlreadyDeclared { +impl<'a, G> Diagnostic<'a> for FieldAlreadyDeclared { fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, "field `{$field_name}` is already declared"); diag.set_span(self.span); diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 39c0e424b6585..4cda9c4aeb568 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -10,7 +10,7 @@ use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, Level, MultiSpan}; #[cfg(debug_assertions)] -use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions}; +use rustc_errors::{SubstitutionPart, Suggestions}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; use rustc_span::Span; @@ -43,7 +43,7 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) { /// /// This function makes sure we also validate them in debug clippy builds. #[cfg(debug_assertions)] -fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) { +fn validate_diag(diag: &Diag<'_, G>) { let suggestions = match &diag.suggestions { Suggestions::Enabled(suggs) => &**suggs, Suggestions::Sealed(suggs) => &**suggs, From c06379bb2d8ed0130b234a78b8f0b17370dd2b83 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 5 Sep 2026 18:18:10 +1000 Subject: [PATCH 44/56] tidy: Sort multi-line types by treating `>` as a closing bracket --- src/tools/tidy/src/alphabetical.rs | 2 +- src/tools/tidy/src/alphabetical/tests.rs | 56 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs index d9714c85428ad..d6184dd718296 100644 --- a/src/tools/tidy/src/alphabetical.rs +++ b/src/tools/tidy/src/alphabetical.rs @@ -51,7 +51,7 @@ fn indentation(line: &str) -> usize { } fn is_close_bracket(c: char) -> bool { - matches!(c, ')' | ']' | '}') + matches!(c, ')' | ']' | '}' | '>') } fn is_empty_or_comment(line: &&str) -> bool { diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs index 96dad53fa359f..01baa786643ec 100644 --- a/src/tools/tidy/src/alphabetical/tests.rs +++ b/src/tools/tidy/src/alphabetical/tests.rs @@ -409,10 +409,31 @@ fn multiline() { bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); let lines = "\ + // tidy-alphabetical-start force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], 'force use of unwind tables'), incremental: Option = (None, parse_opt_string, [UNTRACKED], 'enable incremental compilation'), + // tidy-alphabetical-end + "; + good(lines); +} + +#[test] +fn multiline_types() { + let lines = "\ + // tidy-alphabetical-start + rustc_data_structures::steal::Steal< + rustc_index::IndexVec< + rustc_middle::mir::Promoted, + rustc_middle::mir::Body<'tcx> + > + >, + rustc_index::IndexVec< + rustc_middle::mir::Promoted, + rustc_middle::mir::Body<'tcx> + >, + // tidy-alphabetical-end "; good(lines); } @@ -481,6 +502,41 @@ fn bless_multiline() { bless_test(before, after); } +#[test] +fn bless_multiline_types() { + let before = "\ + // tidy-alphabetical-start + rustc_index::IndexVec< + rustc_middle::mir::Promoted, + rustc_middle::mir::Body<'tcx> + >, + rustc_data_structures::steal::Steal< + rustc_index::IndexVec< + rustc_middle::mir::Promoted, + rustc_middle::mir::Body<'tcx> + > + >, + // tidy-alphabetical-end + "; + + let after = "\ + // tidy-alphabetical-start + rustc_data_structures::steal::Steal< + rustc_index::IndexVec< + rustc_middle::mir::Promoted, + rustc_middle::mir::Body<'tcx> + > + >, + rustc_index::IndexVec< + rustc_middle::mir::Promoted, + rustc_middle::mir::Body<'tcx> + >, + // tidy-alphabetical-end + "; + + bless_test(before, after); +} + #[test] fn bless_funny_numbers() { // Because `2` is indented it gets merged into one entry with `1` and gets From 20ceed78331595f17b9753fe08585f738317a67f Mon Sep 17 00:00:00 2001 From: malezjaa Date: Sun, 13 Sep 2026 10:17:10 +0200 Subject: [PATCH 45/56] regression test for valtree leaf const --- tests/ui/const-generics/mgca/valtree-leaf-const.rs | 12 ++++++++++++ .../ui/const-generics/mgca/valtree-leaf-const.stderr | 9 +++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/ui/const-generics/mgca/valtree-leaf-const.rs create mode 100644 tests/ui/const-generics/mgca/valtree-leaf-const.stderr diff --git a/tests/ui/const-generics/mgca/valtree-leaf-const.rs b/tests/ui/const-generics/mgca/valtree-leaf-const.rs new file mode 100644 index 0000000000000..e372e89fe5e50 --- /dev/null +++ b/tests/ui/const-generics/mgca/valtree-leaf-const.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Znext-solver + +#![feature(macroless_generic_const_args)] +#![feature(generic_const_args)] +#![feature(min_generic_const_args)] + +const TUPLE: (&'static str, &'static str) = ("a", true); +//~^ ERROR mismatched type + +fn main() { + TUPLE; +} diff --git a/tests/ui/const-generics/mgca/valtree-leaf-const.stderr b/tests/ui/const-generics/mgca/valtree-leaf-const.stderr new file mode 100644 index 0000000000000..db45a82198752 --- /dev/null +++ b/tests/ui/const-generics/mgca/valtree-leaf-const.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/valtree-leaf-const.rs:7:51 + | +LL | const TUPLE: (&'static str, &'static str) = ("a", true); + | ^^^^ expected `&str`, found `bool` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From df4f90d6771fda3a3962a5f9f84d6ee76f5305bb Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Sun, 13 Sep 2026 19:38:44 +0900 Subject: [PATCH 46/56] panic when we call impls_trait for types associated with builtin derive impls --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 34b9ede4985a6..acf554d6457fb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -4846,14 +4846,13 @@ impl<'db> Type<'db> { } fn param_env(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { - let interner = DbInterner::new_no_crate(db); let krate = self.krate(db); match self.owner { TypeOwnerId::GenericDefId(def) => { ParamEnvAndCrate { param_env: db.trait_environment(def), krate } } TypeOwnerId::BuiltinDeriveImplId(def) => ParamEnvAndCrate { - param_env: hir_ty::builtin_derive::param_env(interner, def), + param_env: hir_ty::builtin_derive::param_env(DbInterner::new_with(db, krate), def), krate, }, TypeOwnerId::AnonConstId(def) => ParamEnvAndCrate { @@ -4861,7 +4860,7 @@ impl<'db> Type<'db> { krate, }, TypeOwnerId::NoParams(_) => { - ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate } + ParamEnvAndCrate { param_env: ParamEnv::empty(DbInterner::new_no_crate(db)), krate } } } } From 1be3e33d9552ac053a0b1a0158ccc6268c7c5009 Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Sun, 13 Sep 2026 09:56:44 -0300 Subject: [PATCH 47/56] Add regression test for unexpected type for constructor --- .../mgca/unexpected-type-for-constructor.rs | 18 +++++++++++ .../unexpected-type-for-constructor.stderr | 30 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/ui/const-generics/mgca/unexpected-type-for-constructor.rs create mode 100644 tests/ui/const-generics/mgca/unexpected-type-for-constructor.stderr diff --git a/tests/ui/const-generics/mgca/unexpected-type-for-constructor.rs b/tests/ui/const-generics/mgca/unexpected-type-for-constructor.rs new file mode 100644 index 0000000000000..2cf96ac5359dd --- /dev/null +++ b/tests/ui/const-generics/mgca/unexpected-type-for-constructor.rs @@ -0,0 +1,18 @@ +//! Regression test for . +//@ compile-flags: -Znext-solver=globally +//@ check-fail + +#![feature(macroless_generic_const_args)] +#![feature(generic_const_args, min_generic_const_args)] +const C_INNER: (*const u8, u8) = (None::, None::); +//~^ ERROR mismatched types +//~| ERROR mismatched types + +fn foo2(x: *const u8) { + match (x, 1) { + C_INNER => {} //~ ERROR could not evaluate constant pattern + _ => {} + } +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/unexpected-type-for-constructor.stderr b/tests/ui/const-generics/mgca/unexpected-type-for-constructor.stderr new file mode 100644 index 0000000000000..00cb04da529d3 --- /dev/null +++ b/tests/ui/const-generics/mgca/unexpected-type-for-constructor.stderr @@ -0,0 +1,30 @@ +error[E0308]: mismatched types + --> $DIR/unexpected-type-for-constructor.rs:7:35 + | +LL | const C_INNER: (*const u8, u8) = (None::, None::); + | ^^^^^^^^^^ expected `*const u8`, found `Option` + | + = note: expected raw pointer `*const u8` + found enum `Option` + +error[E0308]: mismatched types + --> $DIR/unexpected-type-for-constructor.rs:7:47 + | +LL | const C_INNER: (*const u8, u8) = (None::, None::); + | ^^^^^^^^^^ expected `u8`, found `Option` + | + = note: expected type `u8` + found enum `Option` + +error: could not evaluate constant pattern + --> $DIR/unexpected-type-for-constructor.rs:13:9 + | +LL | const C_INNER: (*const u8, u8) = (None::, None::); + | ------------------------------ constant defined here +... +LL | C_INNER => {} + | ^^^^^^^ could not evaluate constant + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. From bb6549342f370bba40f329320c86a30438bb368f Mon Sep 17 00:00:00 2001 From: malezjaa Date: Sun, 13 Sep 2026 21:08:28 +0200 Subject: [PATCH 48/56] fix tailcall indirect return --- compiler/rustc_target/src/callconv/mod.rs | 2 +- .../tailcc-no-signature-restriction.rs | 26 +++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 26fedbd8a5481..9fe22a3a174b6 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -845,7 +845,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { // an LLVM aggregate type for this leads to bad optimizations, // so we pick an appropriately sized integer type instead. arg.cast_to_maybe_noundef(Reg { kind: RegKind::Integer, size }, cx); - } else if self.conv == CanonAbi::RustTail { + } else if self.conv == CanonAbi::RustTail && arg_idx.is_some() { assert!(arg.layout.is_sized(), "extern \"tail\" arguments must be sized"); arg.pass_by_stack_offset(None); } diff --git a/tests/ui/explicit-tail-calls/tailcc-no-signature-restriction.rs b/tests/ui/explicit-tail-calls/tailcc-no-signature-restriction.rs index 64cea66c1d565..e32aaa6b6966e 100644 --- a/tests/ui/explicit-tail-calls/tailcc-no-signature-restriction.rs +++ b/tests/ui/explicit-tail-calls/tailcc-no-signature-restriction.rs @@ -40,10 +40,32 @@ pub extern "tail" fn pass_struct(a: u64, d: u64) -> u64 { become add(large); } +#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(windows)))] +#[inline(never)] +pub extern "tail" fn pass_vector(x: [f32; 4]) -> [f32; 4] { + #[derive(Clone, Copy)] + pub struct F32x4([f32; 4]); + + #[inline(never)] + extern "tail" fn identity(x: F32x4) -> F32x4 { + x + } + + #[inline(never)] + extern "tail" fn forward(x: F32x4) -> F32x4 { + become identity(x); + } + + forward(F32x4(x)).0 +} + fn main() { assert_eq!(add(), 3); - // Windows and Aarch64 in LLVM 23 does not support byval arguments. + // Windows and Aarch64 in LLVM 23 do not support byval arguments. #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(windows)))] - assert_eq!(pass_struct(5, 6), 5 + 6); + { + assert_eq!(pass_struct(5, 6), 5 + 6); + assert_eq!(pass_vector([1.0, 2.0, 3.0, 4.0]), [1.0, 2.0, 3.0, 4.0]); + } } From 9282e0a259ac49f3029ed6b34ad504f6e3d32a1f Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 9 Sep 2026 04:34:41 +0300 Subject: [PATCH 49/56] Remove the interner/db argument from `empty()` and `default_types()` Interning doesn't really need an interner since the types are global. Initially I wanted to remove *all* `DbInterner` arguments from constructors, however: 1. This is a *much* larger change. 2. We want to eventually move the types under rustc_type_ir. Then having our own constructors will need extension traits and not be comfortable, and the inherent constructors will require an interner (because rustc needs it). However empty lists do not need an interner even in rustc. Pre-interned types (`default_types()`) do, but this will likely remain under our control, and also the version without interner is a tiny bit more efficient, because the `OnceLock` closure doesn't have captures. --- .../crates/hir-ty/src/builtin_derive.rs | 2 +- .../crates/hir-ty/src/consteval.rs | 14 +++++----- .../crates/hir-ty/src/consteval/tests.rs | 5 ++-- .../crates/hir-ty/src/display.rs | 4 +-- .../rust-analyzer/crates/hir-ty/src/infer.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 8 +++--- .../crates/hir-ty/src/lower/path.rs | 3 +-- .../crates/hir-ty/src/mir/eval.rs | 3 +-- .../crates/hir-ty/src/mir/eval/shim.rs | 2 +- .../crates/hir-ty/src/mir/eval/tests.rs | 11 +++----- .../crates/hir-ty/src/mir/lower.rs | 9 +++---- .../hir-ty/src/mir/lower/pattern_matching.rs | 2 +- .../crates/hir-ty/src/next_solver.rs | 10 +++---- .../crates/hir-ty/src/next_solver/consts.rs | 9 ++++++- .../infer/canonical/canonicalizer.rs | 2 +- .../crates/hir-ty/src/next_solver/interner.rs | 14 +++++----- .../hir-ty/src/next_solver/predicate.rs | 20 +++++++++----- .../crates/hir-ty/src/next_solver/region.rs | 8 +++++- .../crates/hir-ty/src/next_solver/ty.rs | 11 ++++++-- .../crates/hir-ty/src/variance.rs | 6 ++--- src/tools/rust-analyzer/crates/hir/src/lib.rs | 22 +++++---------- .../crates/hir/src/source_analyzer.rs | 27 +++++++++---------- .../rust-analyzer/src/cli/analysis_stats.rs | 8 ++---- 23 files changed, 100 insertions(+), 102 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs index baa7b87e457f9..53a232adfc7ac 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs @@ -195,7 +195,7 @@ pub fn predicates(db: &dyn HirDatabase, impl_: BuiltinDeriveImplId) -> GenericPr else { // Malformed derive. return GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind( - Clauses::empty(interner).store(), + Clauses::empty().store(), )); }; let duplicated_bounds = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index d65f76cdf1ceb..a1ed1e71aecc3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -253,7 +253,7 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option { - if val.ty == default_types(db).types.usize { + if val.ty == default_types().types.usize { Some(val.value.inner().to_leaf().to_uint_unchecked()) } else { None @@ -291,7 +291,7 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option { - if val.ty == default_types(db).types.isize { + if val.ty == default_types().types.isize { Some(val.value.inner().to_leaf().to_int_unchecked()) } else { None @@ -347,7 +347,7 @@ pub(crate) fn path_to_const<'a, 'db>( | ValueNs::StructId(_) | ValueNs::EnumVariantId(_) => return Err(CreateConstError::ResolveToNonConst), }; - let args = GenericArgs::empty(interner); + let args = GenericArgs::empty(); Ok(Const::new_unevaluated(interner, UnevaluatedConst { def: konst.into(), args })) } @@ -411,7 +411,7 @@ pub(crate) fn create_anon_const<'a, 'db>( let args = if allow_using_generic_params { GenericArgs::identity_for_item(interner, owner.generic_def(interner.db).into()) } else { - GenericArgs::empty(interner) + GenericArgs::empty() }; Ok(Const::new_unevaluated( interner, @@ -426,7 +426,6 @@ pub(crate) fn const_eval_discriminant_variant<'db>( db: &'db dyn HirDatabase, variant_id: EnumVariantId, ) -> Result> { - let interner = DbInterner::new_no_crate(db); let def = variant_id.into(); let body = Body::of(db, def); let loc = variant_id.lookup(db); @@ -446,7 +445,7 @@ pub(crate) fn const_eval_discriminant_variant<'db>( let mir_body = db.monomorphized_mir_body( def.into(), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), ParamEnvAndCrate { param_env: db.trait_environment(def.generic_def(db)), krate: def.krate(db), @@ -561,10 +560,9 @@ pub(crate) fn const_eval_static<'db>( db: &'db dyn HirDatabase, def: StaticId, ) -> Result> { - let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( def.into(), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } .store(), )?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 6ea8376e48743..b17df991f7afe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -14,7 +14,7 @@ use crate::{ db::HirDatabase, display::DisplayTarget, mir::{IsSigned, pad16}, - next_solver::{Allocation, DbInterner, GenericArgs}, + next_solver::{Allocation, GenericArgs}, setup_tracing, test_db::TestDB, }; @@ -120,7 +120,6 @@ fn pretty_print_err(e: ConstEvalError<'_>, db: &TestDB) -> String { fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, ConstEvalError<'_>> { let _tracing = setup_tracing(); - let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); let def_map = module_id.def_map(db); let scope = &def_map[module_id].scope; @@ -143,7 +142,7 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result, Co _ => None, }) .expect("No const named GOAL found in the test"); - db.const_eval(const_id, GenericArgs::empty(interner), None) + db.const_eval(const_id, GenericArgs::empty(), None) } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index a87a55b3c8980..e83962ec25ec2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -811,7 +811,7 @@ fn render_const_scalar<'db>( memory_map: &MemoryMap<'db>, ty: Ty<'db>, ) -> Result { - let param_env = ParamEnv::empty(f.interner); + let param_env = ParamEnv::empty(); let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_inner(f, b, memory_map, ty, param_env) @@ -1086,7 +1086,7 @@ fn render_const_scalar_from_valtree<'db>( ty: Ty<'db>, valtree: ValTree<'db>, ) -> Result { - let param_env = ParamEnv::empty(f.interner); + let param_env = ParamEnv::empty(); let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_from_valtree_inner(f, ty, valtree, param_env) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index f93c5a2ebbff1..cbe5b671fe83a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -1424,7 +1424,7 @@ impl<'db> InferenceContext<'db> { ) -> Self { let trait_env = db.trait_environment(generic_def); let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), owner); - let types = crate::next_solver::default_types(db); + let types = crate::next_solver::default_types(); InferenceContext { result: InferenceResult::new(types.types.error), return_ty: types.types.error, // set in collect_* calls diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index b86585231cca1..04e453fde3b93 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -252,7 +252,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { db, // Can provide no block since we don't use it for trait solving. interner, - types: crate::next_solver::default_types(db), + types: crate::next_solver::default_types(), lang_items: interner.lang_items(), resolver, def, @@ -635,7 +635,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { // place even if we encounter more opaque types while // lowering the bounds let idx = self.impl_trait_mode.opaque_type_data.alloc(ImplTrait { - predicates: StoredEarlyBinder::bind(Clauses::empty(interner).store()), + predicates: StoredEarlyBinder::bind(Clauses::empty().store()), assoc_ty_bounds_start: 0, }); @@ -2372,12 +2372,12 @@ impl<'db> GenericPredicates { /// A cycle can occur from malformed code. fn generic_predicates_cycle_result<'db>( - db: &'db dyn HirDatabase, + _db: &'db dyn HirDatabase, _: salsa::Id, _def: GenericDefId, ) -> TyLoweringResult<'db, GenericPredicates> { TyLoweringResult::empty(GenericPredicates::from_explicit_own_predicates( - StoredEarlyBinder::bind(Clauses::empty(DbInterner::new_no_crate(db)).store()), + StoredEarlyBinder::bind(Clauses::empty().store()), )) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index c67c69520db10..7e55ef2963169 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -576,7 +576,6 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { lowering_assoc_type_generics: bool, span: Span, ) -> GenericArgs<'db> { - let interner = self.ctx.interner; let prev_current_segment_idx = self.current_segment_idx; let prev_current_segment = self.current_or_prev_segment; @@ -586,7 +585,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { ValueTyDefId::UnionId(it) => it.into(), ValueTyDefId::ConstId(it) => it.into(), ValueTyDefId::StaticId(_) => { - return GenericArgs::empty(interner); + return GenericArgs::empty(); } ValueTyDefId::EnumVariantId(var) => { // the generic args for an enum variant may be either specified diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 32866c12e23e1..37f3e27631810 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -1503,8 +1503,7 @@ impl<'a, 'db> Evaluator<'a, 'db> { )?) } AggregateKind::Union(it, f) => { - let layout = - self.layout_adt((*it).into(), GenericArgs::empty(self.interner()))?; + let layout = self.layout_adt((*it).into(), GenericArgs::empty())?; let offset = layout .fields .offset(u32::from(f.local_id.into_raw()) as usize) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 5a43696233079..ca7c5c7366803 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -1246,7 +1246,7 @@ impl<'a, 'db> Evaluator<'a, 'db> { def, &args, // FIXME: wrong for manual impls of `FnOnce` - GenericArgs::empty(self.interner()), + GenericArgs::empty(), locals, destination, None, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index f09ac6f20d271..2ac3811f1769a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -5,19 +5,14 @@ use syntax::{TextRange, TextSize}; use test_fixture::WithFixture; use crate::{ - db::HirDatabase, - display::DisplayTarget, - mir::MirLowerError, - next_solver::{DbInterner, GenericArgs}, - setup_tracing, - test_db::TestDB, + db::HirDatabase, display::DisplayTarget, mir::MirLowerError, next_solver::GenericArgs, + setup_tracing, test_db::TestDB, }; use super::{MirEvalError, interpret_mir}; fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), MirEvalError<'_>> { crate::attach_db(db, || { - let interner = DbInterner::new_no_crate(db); let module_id = db.module_for_file(file_id.file_id(db)); let def_map = module_id.def_map(db); let scope = &def_map[module_id].scope; @@ -39,7 +34,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), let body = db .monomorphized_mir_body( func_id.into(), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), crate::ParamEnvAndCrate { param_env: db.trait_environment(func_id.into()), krate: func_id.krate(db), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index da631c0d595ea..3b82ed6f798e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -324,7 +324,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { db, infer, store, - types: crate::next_solver::default_types(db), + types: crate::next_solver::default_types(), owner, store_owner, resolver, @@ -547,7 +547,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { const_id.into(), current, place, - GenericArgs::empty(self.interner()), + GenericArgs::empty(), expr_id.into(), )?; Ok(Some(current)) @@ -1377,10 +1377,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { match pr { ResolveValueResult::ValueNs(v) => { if let ValueNs::ConstId(c) = v { - self.lower_const_to_operand( - GenericArgs::empty(self.interner()), - c.into(), - ) + self.lower_const_to_operand(GenericArgs::empty(), c.into()) } else { not_supported!("bad path in range pattern"); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index a401990681911..ecc013506689d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -413,7 +413,7 @@ impl<'db> MirLowerCtx<'_, 'db> { break 'b (c, x.1); } if let ResolveValueResult::ValueNs(ValueNs::ConstId(c)) = pr { - break 'b (c, GenericArgs::empty(self.interner())); + break 'b (c, GenericArgs::empty()); } not_supported!("path in pattern position that is not const or variant") }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs index 42fd31f2594da..6263571286721 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs @@ -43,7 +43,6 @@ use rustc_type_ir::MayBeErased; pub use solver::*; pub use ty::*; -use crate::db::HirDatabase; pub use crate::lower::ImplTraitIdx; pub use rustc_ast_ir::Mutability; @@ -143,25 +142,24 @@ impl std::fmt::Debug for DefaultAny<'_> { } #[inline] -pub fn default_types<'db>(db: &'db dyn HirDatabase) -> &'db DefaultAny<'db> { +pub fn default_types<'db>() -> &'db DefaultAny<'db> { static TYPES: OnceLock> = OnceLock::new(); - let interner = DbInterner::new_no_crate(db); TYPES.get_or_init(|| { let create_ty = |kind| { - let ty = Ty::new(interner, kind); + let ty = Ty::new_without_interner(kind); // We need to increase the refcount (forever), so that the types won't be freed. let ty = ManuallyDrop::new(ty.store()); ty.as_ref() }; let create_const = |kind| { - let ty = Const::new(interner, kind); + let ty = Const::new_without_interner(kind); // We need to increase the refcount (forever), so that the types won't be freed. let ty = ManuallyDrop::new(ty.store()); ty.as_ref() }; let create_region = |kind| { - let ty = Region::new(interner, kind); + let ty = Region::new_without_interner(kind); // We need to increase the refcount (forever), so that the types won't be freed. let ty = ManuallyDrop::new(ty.store()); ty.as_ref() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs index 1cabafa89bc4e..a9cfafb2e4890 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/consts.rs @@ -48,7 +48,10 @@ const _: () = { }; impl<'db> Const<'db> { - pub fn new(_interner: DbInterner<'db>, kind: ConstKind<'db>) -> Self { + /// You should avoid using this if you can, since we want `Ty` to be defined in `rustc_type_ir` and then this method + /// will become more difficult to use. + #[inline] + pub fn new_without_interner(kind: ConstKind<'db>) -> Self { let kind = unsafe { std::mem::transmute::, ConstKind<'static>>(kind) }; let flags = FlagComputation::for_const_kind(&kind); let cached = WithCachedTypeInfo { @@ -59,6 +62,10 @@ impl<'db> Const<'db> { Self { interned: Interned::new_gc(ConstInterned(cached)) } } + pub fn new(_interner: DbInterner<'db>, kind: ConstKind<'db>) -> Self { + Self::new_without_interner(kind) + } + pub fn inner(&self) -> &WithCachedTypeInfo> { let inner = &self.interned.0; unsafe { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs index 33e4c175d0635..e6416eadc05ec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/canonical/canonicalizer.rs @@ -498,7 +498,7 @@ impl<'cx, 'db> Canonicalizer<'cx, 'db> { { let base = Canonical { max_universe: UniverseIndex::ROOT, - var_kinds: CanonicalVarKinds::empty(tcx), + var_kinds: CanonicalVarKinds::empty(), value: (), }; Canonicalizer::canonicalize_with_base( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs index 7b2a811a01afe..df7c9bfe1ec44 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs @@ -90,8 +90,8 @@ macro_rules! interned_slice { impl<'db> $name<'db> { #[inline] - pub fn empty(interner: DbInterner<'db>) -> Self { - interner.default_types().empty.$default_types_field + pub fn empty() -> Self { + $crate::next_solver::default_types().empty.$default_types_field } #[inline] @@ -168,7 +168,7 @@ macro_rules! interned_slice { impl<'db> Default for $name<'db> { #[inline] fn default() -> Self { - $name::empty(DbInterner::conjure()) + $name::empty() } } @@ -399,7 +399,7 @@ impl<'db> DbInterner<'db> { #[inline] pub fn default_types(&self) -> &'db crate::next_solver::DefaultAny<'db> { - crate::next_solver::default_types(self.db) + crate::next_solver::default_types() } #[inline] @@ -1092,7 +1092,7 @@ impl<'db> Interner for DbInterner<'db> { | SolverDefId::InternedCoroutineId(_) | SolverDefId::InternedCoroutineClosureId(_) | SolverDefId::AnonConstId(_) => { - return VariancesOf::empty(self); + return VariancesOf::empty(); } }; self.db.variances_of(generic_def) @@ -1345,7 +1345,7 @@ impl<'db> Interner for DbInterner<'db> { let own_bounds: FxHashSet<_> = self.item_self_bounds(def_id).skip_binder().into_iter().collect(); if all_bounds.len() == own_bounds.len() { - EarlyBinder::bind(Clauses::empty(self)) + EarlyBinder::bind(Clauses::empty()) } else { EarlyBinder::bind(Clauses::new_from_iter( self, @@ -2172,7 +2172,7 @@ impl<'db> Interner for DbInterner<'db> { }; EarlyBinder::bind(Const::new_unevaluated( self, - UnevaluatedConst { def: GeneralConstIdWrapper(id), args: GenericArgs::empty(self) }, + UnevaluatedConst { def: GeneralConstIdWrapper(id), args: GenericArgs::empty() }, )) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs index cf492e65c3ff3..a1e249eaf9517 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/predicate.rs @@ -16,8 +16,8 @@ use rustc_type_ir::{ }; use crate::next_solver::{ - GenericArg, TraitIdWrapper, impl_foldable_for_interned_slice, impl_stored_interned_slice, - interned_slice, + GenericArg, TraitIdWrapper, default_types, impl_foldable_for_interned_slice, + impl_stored_interned_slice, interned_slice, }; use super::{Binder, BoundVarKinds, DbInterner, Region, Ty}; @@ -274,8 +274,8 @@ impl<'db> std::fmt::Debug for Clauses<'db> { impl<'db> Clauses<'db> { #[inline] - pub fn empty(interner: DbInterner<'db>) -> Self { - interner.default_types().empty.clauses + pub fn empty() -> Self { + default_types().empty.clauses } #[inline] @@ -321,6 +321,13 @@ impl<'db> Clauses<'db> { } } +impl Default for Clauses<'_> { + #[inline] + fn default() -> Self { + Self::empty() + } +} + impl<'db> IntoIterator for Clauses<'db> { type IntoIter = ::std::iter::Copied<::std::slice::Iter<'db, Clause<'db>>>; type Item = Clause<'db>; @@ -437,8 +444,9 @@ pub struct ParamEnv<'db> { } impl<'db> ParamEnv<'db> { - pub fn empty(interner: DbInterner<'db>) -> Self { - ParamEnv { clauses: Clauses::empty(interner) } + #[inline] + pub fn empty() -> Self { + ParamEnv { clauses: Clauses::empty() } } pub fn clauses(self) -> Clauses<'db> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs index a6facff7623d8..53099f67fcd5a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs @@ -38,11 +38,17 @@ const _: () = { }; impl<'db> Region<'db> { - pub fn new(_interner: DbInterner<'db>, kind: RegionKind<'db>) -> Self { + /// You should avoid using this if you can, since we want `Region` to be defined in `rustc_type_ir` and then this method + /// will become more difficult to use. + pub fn new_without_interner(kind: RegionKind<'db>) -> Self { let kind = unsafe { std::mem::transmute::, RegionKind<'static>>(kind) }; Self { interned: Interned::new_gc(RegionInterned(kind)) } } + pub fn new(_interner: DbInterner<'db>, kind: RegionKind<'db>) -> Self { + Self::new_without_interner(kind) + } + pub fn inner(&self) -> &RegionKind<'db> { let inner = &self.interned.0; unsafe { std::mem::transmute::<&RegionKind<'static>, &RegionKind<'db>>(inner) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs index 6faf0357e3583..c1810bc659c01 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs @@ -70,8 +70,10 @@ const _: () = { }; impl<'db> Ty<'db> { + /// You should avoid using this if you can, since we want `Const` to be defined in `rustc_type_ir` and then this method + /// will become more difficult to use. #[inline] - pub fn new(_interner: DbInterner<'db>, kind: TyKind<'db>) -> Self { + pub fn new_without_interner(kind: TyKind<'db>) -> Self { let kind = unsafe { std::mem::transmute::, TyKind<'static>>(kind) }; let flags = FlagComputation::for_kind(&kind); let cached = WithCachedTypeInfo { @@ -82,6 +84,11 @@ impl<'db> Ty<'db> { Self { interned: Interned::new_gc(TyInterned(cached)) } } + #[inline] + pub fn new(_interner: DbInterner<'db>, kind: TyKind<'db>) -> Self { + Self::new_without_interner(kind) + } + #[inline] pub fn inner(&self) -> &WithCachedTypeInfo> { let inner = &self.interned.0; @@ -784,7 +791,7 @@ impl<'db> Ty<'db> { let impl_bound = TraitRef::new_from_args( interner, future_trait.into(), - GenericArgs::empty(interner), + GenericArgs::empty(), ) .upcast(interner); Some(vec![impl_bound]) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 2690297283988..cce1b4caf44a7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -46,7 +46,7 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance GenericDefId::AdtId(adt) => { if let AdtId::StructId(id) = adt { let flags = &StructSignature::of(db, id).flags; - let types = || crate::next_solver::default_types(db); + let types = || crate::next_solver::default_types(); if flags.contains(StructFlags::IS_UNSAFE_CELL) { return types().one_invariant.store(); } else if flags.intersects( @@ -56,13 +56,13 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance } } } - _ => return VariancesOf::empty(DbInterner::new_no_crate(db)).store(), + _ => return VariancesOf::empty().store(), } let generics = generics(db, def); let count = generics.len(true); if count == 0 { - return VariancesOf::empty(DbInterner::new_no_crate(db)).store(); + return VariancesOf::empty().store(); } let variances = Context { generics, variances: vec![Variance::Bivariant; count].into_boxed_slice(), db } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 43fc2bae26ee1..f9073138e32dd 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1306,9 +1306,8 @@ impl<'db> AnonConst<'db> { self, db: &'db dyn HirDatabase, ) -> Result, ConstEvalError<'db>> { - let interner = DbInterner::new_no_crate(db); let ty = self.id.loc(db).ty.get().instantiate_identity().skip_norm_wip(); - db.anon_const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { + db.anon_const_eval(self.id, GenericArgs::empty(), None).map(|it| EvaluatedConst { allocation: it, def: self.id.into(), ty, @@ -1827,10 +1826,9 @@ impl Function { "evaluation of builtin derive impl methods is not supported".to_owned(), ))); }; - let interner = DbInterner::new_no_crate(db); let body = db.monomorphized_mir_body( id.into(), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), ParamEnvAndCrate { param_env: db.trait_environment(id.into()), krate: id.module(db).krate(db), @@ -2109,9 +2107,8 @@ impl Const { /// Evaluate the constant. pub fn eval(self, db: &dyn HirDatabase) -> Result, ConstEvalError<'_>> { - let interner = DbInterner::new_no_crate(db); let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity().skip_norm_wip(); - db.const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { + db.const_eval(self.id, GenericArgs::empty(), None).map(|it| EvaluatedConst { allocation: it, def: self.id.into(), ty, @@ -4510,7 +4507,7 @@ impl<'db> Type<'db> { TypeOwnerId::BuiltinDeriveImplId(def) => { GenericArgs::error_for_item(interner, def.into()) } - TypeOwnerId::NoParams(_) => GenericArgs::empty(interner), + TypeOwnerId::NoParams(_) => GenericArgs::empty(), }; Type::no_params(krate, self.ty.instantiate(interner, args).skip_norm_wip()) } @@ -4523,9 +4520,7 @@ impl<'db> Type<'db> { TypeOwnerId::BuiltinDeriveImplId(def) => { generic_args_from_tys(interner, def.into(), args) } - TypeOwnerId::NoParams(krate) => { - (GenericArgs::empty(interner), TypeOwnerId::NoParams(krate)) - } + TypeOwnerId::NoParams(krate) => (GenericArgs::empty(), TypeOwnerId::NoParams(krate)), }; Type { owner, ty: EarlyBinder::bind(self.ty.instantiate(interner, args).skip_norm_wip()) } } @@ -4848,9 +4843,7 @@ impl<'db> Type<'db> { param_env: hir_ty::builtin_derive::param_env(DbInterner::new_with(db, krate), def), krate, }, - TypeOwnerId::NoParams(_) => { - ParamEnvAndCrate { param_env: ParamEnv::empty(DbInterner::new_no_crate(db)), krate } - } + TypeOwnerId::NoParams(_) => ParamEnvAndCrate { param_env: ParamEnv::empty(), krate }, } } @@ -4974,8 +4967,7 @@ impl<'db> Type<'db> { trait_: Trait, args: &[Type<'db>], ) -> bool { - let interner = DbInterner::new_no_crate(db); - let env = ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate: self.krate(db) }; + let env = ParamEnvAndCrate { param_env: ParamEnv::empty(), krate: self.krate(db) }; traits::implements_trait_unique_with_infcx(db, env, trait_.id, &mut |infcx| { let mut args = Self::instantiate_many_with_infer(iter::once(self).chain(args), infcx); GenericArgs::for_item(infcx.interner, trait_.id.into(), |_, param, _, _| { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 021b89677d283..368e5e3c147fd 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -350,21 +350,18 @@ impl<'db> SourceAnalyzer<'db> { } fn trait_environment(&self, db: &'db dyn HirDatabase) -> ParamEnvAndCrate<'db> { - self.param_and(self.body_or_sig.as_ref().map_or_else( - || ParamEnv::empty(DbInterner::new_no_crate(db)), - |body_or_sig| { - let def = match *body_or_sig { - BodyOrSig::Body { def, .. } => def.generic_def(db), - BodyOrSig::VariantFields { def, .. } => match def { - VariantId::EnumVariantId(def) => def.loc(db).parent.into(), - VariantId::StructId(def) => def.into(), - VariantId::UnionId(def) => def.into(), - }, - BodyOrSig::Sig { def, .. } => def, - }; - db.trait_environment(def) - }, - )) + self.param_and(self.body_or_sig.as_ref().map_or_else(ParamEnv::empty, |body_or_sig| { + let def = match *body_or_sig { + BodyOrSig::Body { def, .. } => def.generic_def(db), + BodyOrSig::VariantFields { def, .. } => match def { + VariantId::EnumVariantId(def) => def.loc(db).parent.into(), + VariantId::StructId(def) => def.into(), + VariantId::UnionId(def) => def.into(), + }, + BodyOrSig::Sig { def, .. } => def, + }; + db.trait_environment(def) + })) } pub(crate) fn evaluate_where_clause( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 6cbb0c718c3e6..8c8ad34f6c441 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -19,10 +19,7 @@ use hir_def::{ expr_store::{Body, BodySourceMap, ExpressionStore}, hir::{ExprId, PatId, generics::GenericParams}, }; -use hir_ty::{ - InferenceResult, - next_solver::{DbInterner, GenericArgs}, -}; +use hir_ty::{InferenceResult, next_solver::GenericArgs}; use ide::{ Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve, InlayHintsConfig, LineCol, RaFixtureConfig, RootDatabase, @@ -411,7 +408,6 @@ impl flags::AnalysisStats { let mut all = 0; let mut fail = 0; for &a in adts { - let interner = DbInterner::new_no_crate(db); let generic_params = GenericParams::of(db, a.into()); if generic_params.iter_type_or_consts().next().is_some() || generic_params.iter_lt().next().is_some() @@ -422,7 +418,7 @@ impl flags::AnalysisStats { all += 1; let Err(e) = db.layout_of_adt( hir_def::AdtId::from(a), - GenericArgs::empty(interner).store(), + GenericArgs::empty().store(), hir_ty::ParamEnvAndCrate { param_env: db.trait_environment(a.into()), krate: a.krate(db).into(), From 05c806d47c55458242355d0abb66907e299c8c8d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 8 Sep 2026 07:53:48 +0300 Subject: [PATCH 50/56] Do not fill unstable methods in "Implement default members" But do in "Implement missing members", or if the feature is enabled, or if the trait has the same feature, since it is likely to be enabled by the user. We could choose another way, to do what we do in completion: consider all non-internal features available on any nightly toolchain. However here I find this method better, since we implement many methods at once. --- .../src/handlers/add_missing_impl_members.rs | 95 +++++++++++++++++++ .../ide-assists/src/handlers/generate_impl.rs | 1 + .../replace_derive_with_manual_impl.rs | 1 + .../crates/ide-assists/src/utils.rs | 28 +++++- 4 files changed, 120 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index ebbde8ce3c37d..67fa68df1e9df 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -140,6 +140,7 @@ fn add_missing_impl_members_inner( let missing_items = filter_assoc_items( &ctx.sema, + trait_, &ide_db::traits::get_missing_assoc_items(&ctx.sema, &impl_def), mode, ign_item, @@ -3021,6 +3022,100 @@ impl Read for () { $0fn read() { Self::read_buf() } +} + "#, + ); + } + + #[test] + fn unstable_item() { + check_assist( + add_missing_impl_members, + r#" +trait Foo { + #[unstable(feature = "foobar")] + fn foobar(); +} + +impl Foo for () { + $0 +} + "#, + r#" +trait Foo { + #[unstable(feature = "foobar")] + fn foobar(); +} + +impl Foo for () { + fn foobar() { + ${0:todo!()} + } +} + "#, + ); + check_assist_not_applicable( + add_missing_default_members, + r#" +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0 +} + "#, + ); + check_assist( + add_missing_default_members, + r#" +#![feature(foobar)] + +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0 +} + "#, + r#" +#![feature(foobar)] + +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0fn foobar() {} +} + "#, + ); + check_assist( + add_missing_default_members, + r#" +#[unstable(feature = "foobar")] +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0 +} + "#, + r#" +#[unstable(feature = "foobar")] +trait Foo { + #[unstable(feature = "foobar")] + fn foobar() {} +} + +impl Foo for () { + $0fn foobar() {} } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs index 5813a92427cb1..9fa9a0461eaa2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs @@ -167,6 +167,7 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_, '_> let holder_arg = ast::GenericArg::TypeArg(make.type_arg(make.ty_placeholder())); let missing_items = utils::filter_assoc_items( &ctx.sema, + hir_trait, &ide_db::traits::trait_items_with_required(ctx.db(), hir_trait), DefaultMethods::No, IgnoreAssocItems::DocHiddenAttrPresent, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 1ca291c5775a7..3e98aadb695c3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -233,6 +233,7 @@ fn impl_def_from_trait( let trait_items = filter_assoc_items( sema, + trait_, &ide_db::traits::trait_items_with_required(sema.db, trait_), DefaultMethods::No, ignore_items, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 68e7544e7d76b..8acb887133e0f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -4,7 +4,7 @@ use std::slice; pub(crate) use gen_trait_fn_body::gen_trait_fn_body; use hir::{ - HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution, Semantics, + HasAttrs as HirHasAttrs, HasCrate, HirDisplay, InFile, ModuleDef, PathResolution, Semantics, db::HirDatabase, }; use ide_db::{ @@ -158,11 +158,12 @@ pub enum DefaultMethods { pub fn filter_assoc_items( sema: &Semantics<'_, RootDatabase>, + trait_: hir::Trait, items: &[(hir::AssocItem, IsRequiredAssocItem)], default_methods: DefaultMethods, ignore_items: IgnoreAssocItems, ) -> Vec> { - items + let mut result = items .iter() .copied() .filter(|(assoc_item, is_required)| { @@ -179,16 +180,33 @@ pub fn filter_assoc_items( is_required.0 == (default_methods == DefaultMethods::No) }) + .map(|(item, _)| (item, item.attrs(sema.db).unstable_feature(sema.db))) // Note: This throws away items with no source. - .filter_map(|(assoc_item, _)| { + .filter_map(|(assoc_item, unstable_feature)| { let item = match assoc_item { hir::AssocItem::Function(it) => sema.source(it)?.map(ast::AssocItem::Fn), hir::AssocItem::TypeAlias(it) => sema.source(it)?.map(ast::AssocItem::TypeAlias), hir::AssocItem::Const(it) => sema.source(it)?.map(ast::AssocItem::Const), }; - Some(item) + Some((item, unstable_feature)) }) - .collect() + .collect::>(); + + // Now, we want to filter unstable assoc items whose feature is not enabled, unless: + // - it's required, or + // - the trait has the same feature, so the user probably intends to enable it. + if default_methods == DefaultMethods::Only { + let trait_unstable_feature = trait_.attrs(sema.db).unstable_feature(sema.db); + let krate = trait_.krate(sema.db); + result.retain(|(_, item_unstable_feature)| { + *item_unstable_feature == trait_unstable_feature + || item_unstable_feature + .as_ref() + .is_none_or(|feature| krate.is_unstable_feature_enabled(sema.db, feature)) + }); + } + + result.into_iter().map(|(item, _)| item).collect() } /// Given `original_items` retrieved from the trait definition (usually by From f0eb4b571cbfbc92223f20a940ce99b2c25526e8 Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Sun, 13 Sep 2026 21:58:10 +0200 Subject: [PATCH 51/56] Remove pointless A: Allocator bounds in boxed.rs --- library/alloc/src/boxed.rs | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 07228664d65ef..07b40b90e0b70 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -448,10 +448,7 @@ impl Box { #[unstable(feature = "allocator_api", issue = "32838")] #[must_use] #[inline] - pub fn new_in(x: T, alloc: A) -> Self - where - A: Allocator, - { + pub fn new_in(x: T, alloc: A) -> Self { let mut boxed = Self::new_uninit_in(alloc); boxed.write(x); // SAFETY: Initialised by the above. @@ -475,10 +472,7 @@ impl Box { /// ``` #[unstable(feature = "allocator_api", issue = "32838")] #[inline] - pub fn try_new_in(x: T, alloc: A) -> Result - where - A: Allocator, - { + pub fn try_new_in(x: T, alloc: A) -> Result { let mut boxed = Self::try_new_uninit_in(alloc)?; boxed.write(x); // SAFETY: Initialised by the above. @@ -504,10 +498,7 @@ impl Box { #[unstable(feature = "allocator_api", issue = "32838")] #[cfg(not(no_global_oom_handling))] #[must_use] - pub fn new_uninit_in(alloc: A) -> Box, A> - where - A: Allocator, - { + pub fn new_uninit_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -536,10 +527,7 @@ impl Box { /// # Ok::<(), std::alloc::AllocError>(()) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] - pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> - where - A: Allocator, - { + pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> { let ptr = if T::IS_ZST { NonNull::dangling() } else { @@ -573,10 +561,7 @@ impl Box { #[unstable(feature = "allocator_api", issue = "32838")] #[cfg(not(no_global_oom_handling))] #[must_use] - pub fn new_zeroed_in(alloc: A) -> Box, A> - where - A: Allocator, - { + pub fn new_zeroed_in(alloc: A) -> Box, A> { let layout = Layout::new::>(); // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable. // That would make code size bigger. @@ -609,10 +594,7 @@ impl Box { /// /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] - pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> - where - A: Allocator, - { + pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> { let ptr = if T::IS_ZST { NonNull::dangling() } else { From a6aae86a235f0cff4e472b04a591ee2e43986426 Mon Sep 17 00:00:00 2001 From: sjwang05 <63834813+sjwang05@users.noreply.github.com> Date: Sun, 13 Sep 2026 13:18:21 -0700 Subject: [PATCH 52/56] cleanups --- .../src/solve/eval_ctxt/mod.rs | 151 ++++++++++-------- 1 file changed, 83 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index c5665246710a3..3a4875c1d0951 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1614,74 +1614,7 @@ where r.retain(|(outlives, _)| !outlives.is_trivial() && unique.insert(*outlives)); } - #[derive(Default)] - struct NonTrivialVars { - vars: HashSet, - } - impl TypeVisitor for NonTrivialVars - where - I: Interner, - { - type Result = (); - fn visit_ty(&mut self, t: I::Ty) { - // If a nested type doesn't have any `ReVar`s, then we won't insert - // anything into `vars` anyway, so skip for better perf. - if !t.has_infer_regions() { - return; - } - t.super_visit_with(self); - } - fn visit_const(&mut self, c: I::Const) { - // The same goes for consts. - if !c.has_infer_regions() { - return; - } - c.super_visit_with(self); - } - fn visit_region(&mut self, r: Region) { - if let ty::ReVar(vid) = r.kind() { - self.vars.insert(vid); - } - } - } - - // If we have a constraint like `'re: '?1`, where '?1 can name 're and '?1 appears - // only on the RHS of region constraints, then this kind of constraint is also trivial, - // since we're able to pick '?1 := 'empty, and 're: 'empty is always true for any 're. - if let ExternalRegionConstraints::Old(r) = &mut external_constraints.region_constraints - && !r.is_empty() - { - let mut vis = NonTrivialVars::default(); - var_values.visit_with(&mut vis); - // We have to visit each component of `external_constraints` individually here - // because we skip the RHS of outlives constraints, and `TypeVisitor` doesn't - // have a method we can easily override in order to do this. - external_constraints.opaque_types.visit_with(&mut vis); - external_constraints.normalization_nested_goals.visit_with(&mut vis); - for (constraint, _) in r.iter() { - match constraint { - ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, _)) => { - sup.visit_with(&mut vis) - } - ty::RegionConstraint::Eq(eq) => eq.visit_with(&mut vis), - } - } - - r.retain(|(outlives, _)| { - if let ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, re)) = *outlives - && let Some(sup_re) = sup.as_region() - && let ty::RegionKind::ReVar(vid) = re.kind() - // This is only safe if we call `eager_resolve_vars` beforehand, - // which we do. - && self.delegate.universe_of_region(vid).unwrap() - .can_name(max_universe(&**self.delegate, sup_re)) - { - vis.vars.contains(&vid) - } else { - true - } - }); - } + filter_irrelevant_region_constraints(self.delegate, &var_values, &mut external_constraints); let canonical = canonicalize_response( self.delegate, @@ -1802,6 +1735,88 @@ where } } +fn filter_irrelevant_region_constraints( + delegate: &D, + var_values: &CanonicalVarValues, + external_constraints: &mut ExternalConstraintsData, +) where + D: SolverDelegate, + I: Interner, +{ + #[derive(Default)] + struct NonTrivialVars { + vars: HashSet, + } + impl TypeVisitor for NonTrivialVars + where + I: Interner, + { + type Result = (); + fn visit_ty(&mut self, t: I::Ty) { + // If a nested type doesn't have any `ReVar`s, then we won't insert + // anything into `vars` anyway, so skip for better perf. + if !t.has_infer_regions() { + return; + } + t.super_visit_with(self); + } + fn visit_const(&mut self, c: I::Const) { + // The same goes for consts. + if !c.has_infer_regions() { + return; + } + c.super_visit_with(self); + } + fn visit_region(&mut self, r: Region) { + if let ty::ReVar(vid) = r.kind() { + self.vars.insert(vid); + } + } + } + + let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } = + external_constraints; + + // If we have a constraint like `'re: '?1`, where '?1 can name 're and '?1 appears + // only on the RHS of region constraints, then this kind of constraint is also trivial, + // since we're able to pick '?1 := glb('re, other_regions), and by definition of glb, + // `'re: glb`. + if let ExternalRegionConstraints::Old(r) = region_constraints + && !r.is_empty() + { + let mut vis = NonTrivialVars::default(); + var_values.visit_with(&mut vis); + // We have to visit each component of `external_constraints` individually here + // because we skip the RHS of outlives constraints, and `TypeVisitor` doesn't + // have a method we can easily override in order to do this. + opaque_types.visit_with(&mut vis); + normalization_nested_goals.visit_with(&mut vis); + for (constraint, _) in r.iter() { + match constraint { + ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, _)) => { + sup.visit_with(&mut vis) + } + ty::RegionConstraint::Eq(eq) => eq.visit_with(&mut vis), + } + } + + r.retain(|(outlives, _)| { + if let ty::RegionConstraint::Outlives(ty::OutlivesClause(sup, re)) = *outlives + && let Some(sup_re) = sup.as_region() + && let ty::RegionKind::ReVar(vid) = re.kind() + // This is only safe if we call `eager_resolve_vars` before calling, + // this function, which we do. + && delegate.universe_of_region(vid).unwrap() + .can_name(max_universe(&**delegate, sup_re)) + { + vis.vars.contains(&vid) + } else { + true + } + }); + } +} + #[derive(Debug)] enum RerunDecision { Yes, From 4e99638c7fb697db838c38669709c01bb7cc799a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Sep 2026 23:01:46 +0200 Subject: [PATCH 53/56] turn aligned-in-packed error into lint --- .../src/error_codes/E0588.md | 4 +- .../rustc_hir_analysis/src/check/check.rs | 87 +++++++++++-------- compiler/rustc_lint_defs/src/builtin.rs | 30 +++++++ ...cked-struct-contains-aligned-type-73112.rs | 2 +- ...-struct-contains-aligned-type-73112.stderr | 4 +- tests/ui/repr/repr-packed-contains-align.rs | 33 ++++--- .../ui/repr/repr-packed-contains-align.stderr | 58 ++++++------- 7 files changed, 139 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0588.md b/compiler/rustc_error_codes/src/error_codes/E0588.md index 995d945f1589e..6bb4cafc331a6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0588.md +++ b/compiler/rustc_error_codes/src/error_codes/E0588.md @@ -1,9 +1,11 @@ +#### Note: this error code is no longer emitted by the compiler. + A type with `packed` representation hint has a field with `align` representation hint. Erroneous code example: -```compile_fail,E0588 +```ignore (no longer emitted) #[repr(align(16))] struct Aligned(i32); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index fef10d297236f..be1d77194b937 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -12,7 +12,9 @@ use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::{Node, find_attr, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode, TraitErrors, WellFormedLoc}; -use rustc_lint_defs::builtin::{DEAD_CODE, UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; +use rustc_lint_defs::builtin::{ + ALIGNED_FIELDS_IN_PACKED, DEAD_CODE, UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS, +}; use rustc_macros::Diagnostic; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; @@ -105,7 +107,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuarante } check_transparent(tcx, def); - check_packed(tcx, span, def); + check_packed(tcx, span, def_id); check_type_defn(tcx, def_id, false) } @@ -115,7 +117,7 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuarantee def.destructor(tcx); // force the destructor to be evaluated check_transparent(tcx, def); check_union_fields(tcx, span, def_id); - check_packed(tcx, span, def); + check_packed(tcx, span, def_id); check_type_defn(tcx, def_id, true) } @@ -1644,7 +1646,8 @@ fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalab } } -pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { +pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { + let def = tcx.adt_def(def_id); let repr = def.repr(); if repr.packed() { // `#[pin_v2]` on a packed type is unsound: drop glue for a packed type moves an @@ -1673,6 +1676,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { } } } + if repr.align.is_some() { struct_span_code_err!( tcx.dcx(), @@ -1681,51 +1685,62 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { "type has conflicting packed and align representation hints" ) .emit(); - } else if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) { - let mut err = struct_span_code_err!( - tcx.dcx(), + } else if repr.c() + && let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) + { + tcx.emit_node_span_lint( + ALIGNED_FIELDS_IN_PACKED, + tcx.local_def_id_to_hir_id(def_id), sp, - E0588, - "packed type cannot transitively contain a `#[repr(align)]` type" - ); - - err.span_note( - tcx.def_span(def_spans[0].0), - format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)), - ); + rustc_errors::DiagDecorator(|diag| { + diag.primary_message( + "packed type cannot transitively contain a `#[repr(align)]` type", + ); - if def_spans.len() > 2 { - let mut first = true; - for (adt_def, span) in def_spans.iter().skip(1).rev() { - let ident = tcx.item_name(*adt_def); - err.span_note( - *span, - if first { - format!( - "`{}` contains a field of type `{}`", - tcx.type_of(def.did()).instantiate_identity().skip_norm_wip(), - ident - ) - } else { - format!("...which contains a field of type `{ident}`") - }, + diag.span_note( + tcx.def_span(def_spans[0].0), + format!( + "`{}` has a `#[repr(align)]` attribute", + tcx.item_name(def_spans[0].0) + ), ); - first = false; - } - } - err.emit(); + if def_spans.len() <= 2 { + // 2 spans means aligned type is directly inside packed type, no need to add + // extra notes. + return; + } + + let mut first = true; + for (adt_def, span) in def_spans.iter().skip(1).rev() { + let ident = tcx.item_name(*adt_def); + diag.span_note( + *span, + if first { + format!( + "`{}` contains a field of type `{}`", + tcx.type_of(def.did()).instantiate_identity().skip_norm_wip(), + ident + ) + } else { + format!("...which contains a field of type `{ident}`") + }, + ); + first = false; + } + }), + ); } } } -pub(super) fn check_packed_inner( +fn check_packed_inner( tcx: TyCtxt<'_>, def_id: DefId, stack: &mut Vec, ) -> Option> { if let ty::Adt(def, args) = tcx.type_of(def_id).instantiate_identity().skip_norm_wip().kind() { - if def.is_struct() || def.is_union() { + if def.repr().c() && (def.is_struct() || def.is_union()) { if def.repr().align.is_some() { return Some(vec![(def.did(), DUMMY_SP)]); } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9caba9c1b5fdb..d7152a6fbe4a0 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -17,6 +17,7 @@ pub mod hardwired { // tidy-alphabetical-start AARCH64_SOFTFLOAT_NEON, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + ALIGNED_FIELDS_IN_PACKED, AMBIGUOUS_ASSOCIATED_ITEMS, AMBIGUOUS_DERIVE_HELPERS, AMBIGUOUS_GLOB_IMPORTED_TRAITS, @@ -5790,3 +5791,32 @@ declare_lint! { "duplicate tools found in crate-level `#[register_tools]` directives", @feature_gate = register_tool; } + +declare_lint! { + /// The `aligned_fields_in_packed` lint detects fields with `align` representation hints + /// inside `repr(C)` types with `packed` representation hint. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[repr(C, align(16))] + /// struct Aligned(i32); + /// + /// #[repr(C, packed)] // error! + /// struct Packed(Aligned); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The behavior of this combination of hints is inconsistent across C compilers. The layout + /// computed for these types by Rust may thus not match the layout actually used by C. + /// Specifically, Rust always follows the GCC convention, which makes it incompatible with MSVC + /// for these types. This may change in the future for targets where GCC is not the default C + /// compiler. + pub ALIGNED_FIELDS_IN_PACKED, + Deny, + "`repr(C, align)` types nested inside `repr(C, packed)` types \ + do not always have a C-compatible layout", +} diff --git a/tests/ui/repr/packed-struct-contains-aligned-type-73112.rs b/tests/ui/repr/packed-struct-contains-aligned-type-73112.rs index baeb75beb0aa1..f8272e6f652e5 100644 --- a/tests/ui/repr/packed-struct-contains-aligned-type-73112.rs +++ b/tests/ui/repr/packed-struct-contains-aligned-type-73112.rs @@ -8,7 +8,7 @@ fn main() { #[repr(C, packed)] struct SomeStruct { - //~^ ERROR packed type cannot transitively contain a `#[repr(align)]` type [E0588] + //~^ ERROR packed type cannot transitively contain a `#[repr(align)]` type page_table: PageTable, } } diff --git a/tests/ui/repr/packed-struct-contains-aligned-type-73112.stderr b/tests/ui/repr/packed-struct-contains-aligned-type-73112.stderr index 237c357db22ba..8cba8bf75c437 100644 --- a/tests/ui/repr/packed-struct-contains-aligned-type-73112.stderr +++ b/tests/ui/repr/packed-struct-contains-aligned-type-73112.stderr @@ -1,4 +1,4 @@ -error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type +error: packed type cannot transitively contain a `#[repr(align)]` type --> $DIR/packed-struct-contains-aligned-type-73112.rs:10:5 | LL | struct SomeStruct { @@ -9,7 +9,7 @@ note: `PageTable` has a `#[repr(align)]` attribute | LL | pub struct PageTable { | ^^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(aligned_fields_in_packed)]` on by default error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0588`. diff --git a/tests/ui/repr/repr-packed-contains-align.rs b/tests/ui/repr/repr-packed-contains-align.rs index bef5c7d8c62fc..06c8e92249866 100644 --- a/tests/ui/repr/repr-packed-contains-align.rs +++ b/tests/ui/repr/repr-packed-contains-align.rs @@ -1,53 +1,66 @@ #![allow(dead_code)] -#[repr(align(16))] +#[repr(C, align(16))] #[derive(Clone, Copy)] struct SA(i32); +#[repr(align(16))] +#[derive(Clone, Copy)] +struct SARust(i32); + +#[repr(C)] #[derive(Clone, Copy)] struct SB(SA); -#[repr(align(16))] +#[repr(C, align(16))] #[derive(Clone, Copy)] union UA { i: i32 } +#[repr(C)] #[derive(Clone, Copy)] union UB { a: UA } -#[repr(packed)] +#[repr(C, packed)] struct SC(SA); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type -#[repr(packed)] +#[repr(C, packed)] struct SD(SB); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type -#[repr(packed)] +#[repr(C, packed)] struct SE(UA); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type -#[repr(packed)] +#[repr(C, packed)] struct SF(UB); //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type -#[repr(packed)] +#[repr(C, packed)] union UC { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type a: UA } -#[repr(packed)] +#[repr(C, packed)] union UD { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type n: UB } -#[repr(packed)] +#[repr(C, packed)] union UE { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type a: SA } -#[repr(packed)] +#[repr(C, packed)] union UF { //~ ERROR: packed type cannot transitively contain a `#[repr(align)]` type n: SB } +#[repr(packed)] +struct SG(SA); // outer type not `repr(C)`, no lint +#[repr(C, packed)] +struct SH(SARust); // inner type not `repr(C)`, no lint + + + fn main() {} diff --git a/tests/ui/repr/repr-packed-contains-align.stderr b/tests/ui/repr/repr-packed-contains-align.stderr index 4c3a960cad2a6..4c94cda745d2e 100644 --- a/tests/ui/repr/repr-packed-contains-align.stderr +++ b/tests/ui/repr/repr-packed-contains-align.stderr @@ -1,5 +1,5 @@ -error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:22:1 +error: packed type cannot transitively contain a `#[repr(align)]` type + --> $DIR/repr-packed-contains-align.rs:28:1 | LL | struct SC(SA); | ^^^^^^^^^ @@ -9,9 +9,10 @@ note: `SA` has a `#[repr(align)]` attribute | LL | struct SA(i32); | ^^^^^^^^^ + = note: `#[deny(aligned_fields_in_packed)]` on by default -error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:25:1 +error: packed type cannot transitively contain a `#[repr(align)]` type + --> $DIR/repr-packed-contains-align.rs:31:1 | LL | struct SD(SB); | ^^^^^^^^^ @@ -22,86 +23,86 @@ note: `SA` has a `#[repr(align)]` attribute LL | struct SA(i32); | ^^^^^^^^^ note: `SD` contains a field of type `SB` - --> $DIR/repr-packed-contains-align.rs:25:11 + --> $DIR/repr-packed-contains-align.rs:31:11 | LL | struct SD(SB); | ^^ note: ...which contains a field of type `SA` - --> $DIR/repr-packed-contains-align.rs:8:11 + --> $DIR/repr-packed-contains-align.rs:13:11 | LL | struct SB(SA); | ^^ -error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:28:1 +error: packed type cannot transitively contain a `#[repr(align)]` type + --> $DIR/repr-packed-contains-align.rs:34:1 | LL | struct SE(UA); | ^^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:12:1 + --> $DIR/repr-packed-contains-align.rs:17:1 | LL | union UA { | ^^^^^^^^ -error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:31:1 +error: packed type cannot transitively contain a `#[repr(align)]` type + --> $DIR/repr-packed-contains-align.rs:37:1 | LL | struct SF(UB); | ^^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:12:1 + --> $DIR/repr-packed-contains-align.rs:17:1 | LL | union UA { | ^^^^^^^^ note: `SF` contains a field of type `UB` - --> $DIR/repr-packed-contains-align.rs:31:11 + --> $DIR/repr-packed-contains-align.rs:37:11 | LL | struct SF(UB); | ^^ note: ...which contains a field of type `UA` - --> $DIR/repr-packed-contains-align.rs:18:5 + --> $DIR/repr-packed-contains-align.rs:24:5 | LL | a: UA | ^ -error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:34:1 +error: packed type cannot transitively contain a `#[repr(align)]` type + --> $DIR/repr-packed-contains-align.rs:40:1 | LL | union UC { | ^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:12:1 + --> $DIR/repr-packed-contains-align.rs:17:1 | LL | union UA { | ^^^^^^^^ -error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:39:1 +error: packed type cannot transitively contain a `#[repr(align)]` type + --> $DIR/repr-packed-contains-align.rs:45:1 | LL | union UD { | ^^^^^^^^ | note: `UA` has a `#[repr(align)]` attribute - --> $DIR/repr-packed-contains-align.rs:12:1 + --> $DIR/repr-packed-contains-align.rs:17:1 | LL | union UA { | ^^^^^^^^ note: `UD` contains a field of type `UB` - --> $DIR/repr-packed-contains-align.rs:40:5 + --> $DIR/repr-packed-contains-align.rs:46:5 | LL | n: UB | ^ note: ...which contains a field of type `UA` - --> $DIR/repr-packed-contains-align.rs:18:5 + --> $DIR/repr-packed-contains-align.rs:24:5 | LL | a: UA | ^ -error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:44:1 +error: packed type cannot transitively contain a `#[repr(align)]` type + --> $DIR/repr-packed-contains-align.rs:50:1 | LL | union UE { | ^^^^^^^^ @@ -112,8 +113,8 @@ note: `SA` has a `#[repr(align)]` attribute LL | struct SA(i32); | ^^^^^^^^^ -error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type - --> $DIR/repr-packed-contains-align.rs:49:1 +error: packed type cannot transitively contain a `#[repr(align)]` type + --> $DIR/repr-packed-contains-align.rs:55:1 | LL | union UF { | ^^^^^^^^ @@ -124,16 +125,15 @@ note: `SA` has a `#[repr(align)]` attribute LL | struct SA(i32); | ^^^^^^^^^ note: `UF` contains a field of type `SB` - --> $DIR/repr-packed-contains-align.rs:50:5 + --> $DIR/repr-packed-contains-align.rs:56:5 | LL | n: SB | ^ note: ...which contains a field of type `SA` - --> $DIR/repr-packed-contains-align.rs:8:11 + --> $DIR/repr-packed-contains-align.rs:13:11 | LL | struct SB(SA); | ^^ error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0588`. From d5e94f259e3a573e0fe4a327276525d672e57142 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 14 Sep 2026 10:27:06 +0200 Subject: [PATCH 54/56] Remove `parse_param_general` --- compiler/rustc_parse/src/parser/function.rs | 6 ++---- compiler/rustc_parse/src/parser/path.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/parser/function.rs b/compiler/rustc_parse/src/parser/function.rs index a042826c231a8..220cc5a3bc069 100644 --- a/compiler/rustc_parse/src/parser/function.rs +++ b/compiler/rustc_parse/src/parser/function.rs @@ -693,7 +693,7 @@ impl<'a> Parser<'a> { let (mut params, _) = self.parse_paren_comma_seq(|p| { p.recover_vcs_conflict_marker(); let snapshot = p.create_snapshot_for_diagnostic(); - let param = p.parse_param_general(fn_parse_mode, first_param, true).or_else(|e| { + let param = p.parse_param_general(fn_parse_mode, first_param).or_else(|e| { let guar = e.emit(); // When parsing a param failed, we should check to make the span of the param // not contain '(' before it. @@ -726,7 +726,6 @@ impl<'a> Parser<'a> { &mut self, fn_parse_mode: &FnParseMode, first_param: bool, - recover_arg_parse: bool, ) -> PResult<'a, Param> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; @@ -814,7 +813,7 @@ impl<'a> Parser<'a> { // If this is a C-variadic argument and we hit an error, return the error. Err(err) if this.token == token::DotDotDot => return Err(err), Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err), - Err(err) if recover_arg_parse => { + Err(err) => { // Recover from attempting to parse the argument as a type without pattern. this.restore_snapshot(parser_snapshot_before_ty); match this.recover_arg_parse(fn_parse_mode.context) { @@ -830,7 +829,6 @@ impl<'a> Parser<'a> { } } } - Err(err) => return Err(err), } }; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index e4ba1e7d18e51..6bc7195b8371c 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -405,7 +405,7 @@ impl<'a> Parser<'a> { req_name: |_, _| false, req_body: false, }; - let param = p.parse_param_general(&mode, first_param, true)?; + let param = p.parse_param_general(&mode, first_param)?; first_param = false; if !matches!(param.pat.kind, PatKind::Missing) { self.psess From 99bb4bb2573e40c90acd61a36f8fd0d2dcc1061a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 14 Sep 2026 10:29:28 +0200 Subject: [PATCH 55/56] Improve docs for `GenericArgs::Parenthesized` --- compiler/rustc_ast/src/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index c14ad62e9a60b..b7a9765d09273 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -255,7 +255,7 @@ impl PathSegment { pub enum GenericArgs { /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`. AngleBracketed(AngleBracketedArgs), - /// The `(A, B)` and `C` in `Foo(A, B) -> C`. + /// The `(A, B)` and `C` in `Foo(A, B) -> C`, used for the `Fn` trait among others. Parenthesized(ParenthesizedArgs), /// `(..)` in return type notation. ParenthesizedElided(Span), From ae76f4291392213062f08c8be18770d67b75f078 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Sep 2026 11:54:08 +0200 Subject: [PATCH 56/56] less pub --- compiler/rustc_hir_analysis/src/check/check.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index be1d77194b937..23fa09be6fec0 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -258,7 +258,7 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { } /// Checks that an opaque type does not contain cycles. -pub(super) fn check_opaque_for_cycles<'tcx>( +fn check_opaque_for_cycles<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed> { @@ -1209,7 +1209,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), }) } -pub(super) fn check_specialization_validity<'tcx>( +fn check_specialization_validity<'tcx>( tcx: TyCtxt<'tcx>, trait_def: &ty::TraitDef, trait_item: ty::AssocItem, @@ -1646,7 +1646,7 @@ fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalab } } -pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { +fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { let def = tcx.adt_def(def_id); let repr = def.repr(); if repr.packed() { @@ -1762,7 +1762,7 @@ fn check_packed_inner( None } -pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) { +fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) { if !adt.repr().transparent() { return; }