From d19a07b2a9d7f0a18409485451c12632b93ff674 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Wed, 4 Mar 2026 00:47:53 +0100 Subject: [PATCH 1/5] Fix LegacyKeyValueFormat report from docker build: x86_64-gnu --- .../docker/host-x86_64/x86_64-gnu-aux/Dockerfile | 4 ++-- .../docker/host-x86_64/x86_64-gnu-debug/Dockerfile | 14 ++++++-------- .../host-x86_64/x86_64-gnu-distcheck/Dockerfile | 6 +++--- .../docker/host-x86_64/x86_64-gnu-gcc/Dockerfile | 11 +++++------ .../host-x86_64/x86_64-gnu-llvm-21/Dockerfile | 11 +++++------ .../docker/host-x86_64/x86_64-gnu-miri/Dockerfile | 9 ++++----- .../docker/host-x86_64/x86_64-gnu-nopt/Dockerfile | 8 ++++---- .../docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 11 +++++------ src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile | 7 +++---- 9 files changed, 37 insertions(+), 44 deletions(-) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index d4113736b544b..95ddaab7f44b5 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -29,5 +29,5 @@ RUN sh /scripts/sccache.sh ENV NO_DEBUG_ASSERTIONS=1 ENV NO_OVERFLOW_CHECKS=1 -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu -ENV RUST_CHECK_TARGET check-aux +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu" +ENV RUST_CHECK_TARGET="check-aux" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index 54b13c4397f47..5287d6b8956ff 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -29,20 +29,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1 +ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS="1" # llvm.use-linker conflicts with downloading CI LLVM -ENV NO_DOWNLOAD_CI_LLVM 1 +ENV NO_DOWNLOAD_CI_LLVM="1" -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-debug \ --enable-lld \ --set rust.debuginfo-level-tests=2 \ --set llvm.use-linker=lld \ --set target.x86_64-unknown-linux-gnu.linker=clang \ --set target.x86_64-unknown-linux-gnu.cc=clang \ - --set target.x86_64-unknown-linux-gnu.cxx=clang++ + --set target.x86_64-unknown-linux-gnu.cxx=clang++" # This job checks: # - That ui tests can be built with `-Cdebuginfo=1` @@ -53,7 +52,6 @@ ENV RUST_CONFIGURE_ARGS \ # - That the tests with `//@ needs-force-clang-based-tests` pass, since they # don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set. -ENV SCRIPT \ - python3 ../x.py --stage 2 build && \ +ENV SCRIPT="python3 ../x.py --stage 2 build && \ python3 ../x.py --stage 2 test tests/ui && \ - python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo + python3 ../x.py --stage 2 test tests/run-make tests/run-make-cargo" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 5bafd89cfd91d..5ab44df7a8033 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -1,5 +1,5 @@ # Runs `distcheck`, which is a collection of smoke tests: -# +# # - Run `make check` from an unpacked dist tarball to make sure we can at the # minimum run check steps from those sources. # - Check that selected dist components at least have expected directory shape @@ -34,6 +34,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh # Make distcheck builds faster -ENV DISTCHECK_CONFIGURE_ARGS "--enable-sccache" +ENV DISTCHECK_CONFIGURE_ARGS="--enable-sccache" -ENV SCRIPT python3 ../x.py test distcheck +ENV SCRIPT="python3 ../x.py test distcheck" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile index f9c1ea531add5..2208ed3ffbe15 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-gcc/Dockerfile @@ -31,15 +31,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV NO_DEBUG_ASSERTIONS 1 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV NO_DEBUG_ASSERTIONS="1" +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs \ --set llvm.libzstd=true \ - --set 'rust.codegen-backends=[\"llvm\",\"gcc\"]' -ENV SCRIPT python3 ../x.py \ + --set rust.codegen-backends=[\\\"llvm\\\",\\\"gcc\\\"]" +ENV SCRIPT="python3 ../x.py \ --stage 2 \ test tests \ --test-codegen-backend gcc \ @@ -51,4 +50,4 @@ ENV SCRIPT python3 ../x.py \ --skip tests/rustdoc-js-std \ --skip tests/rustdoc-json \ --skip tests/rustdoc-ui \ - --set 'rust.codegen-backends=[\"llvm\",\"gcc\"]' + --set rust.codegen-backends=[\\\"llvm\\\",\\\"gcc\\\"]" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile index f0314854411f2..fc96735521077 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-21/Dockerfile @@ -44,16 +44,15 @@ RUN sh /scripts/sccache.sh # We are disabling CI LLVM since this builder is intentionally using a host # LLVM, rather than the typical src/llvm-project LLVM. -ENV NO_DOWNLOAD_CI_LLVM 1 -ENV EXTERNAL_LLVM 1 +ENV NO_DOWNLOAD_CI_LLVM="1" +ENV EXTERNAL_LLVM="1" # Using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --llvm-root=/usr/lib/llvm-21 \ --enable-llvm-link-shared \ --set rust.randomize-layout=true \ - --set rust.thin-lto-import-instr-limit=10 + --set rust.thin-lto-import-instr-limit=10" COPY scripts/shared.sh /scripts/ @@ -63,4 +62,4 @@ COPY scripts/x86_64-gnu-llvm3.sh /scripts/ COPY scripts/stage_2_test_set1.sh /scripts/ COPY scripts/stage_2_test_set2.sh /scripts/ -ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" +ENV SCRIPT="Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile index db4fca71d6376..e478b80044215 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-miri/Dockerfile @@ -34,11 +34,10 @@ ENV GCC_EXEC_PREFIX="/usr/lib/gcc/" COPY host-x86_64/x86_64-gnu-miri/check-miri.sh /tmp/ -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --enable-new-symbol-mangling +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ + --enable-new-symbol-mangling" -ENV HOST_TARGET x86_64-unknown-linux-gnu +ENV HOST_TARGET="x86_64-unknown-linux-gnu" # FIXME(#133381): currently rustc alt builds do *not* have rustc debug # assertions enabled! Therefore, we cannot force download CI rustc. @@ -46,4 +45,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -ENV SCRIPT /tmp/check-miri.sh ../x.py +ENV SCRIPT="/tmp/check-miri.sh ../x.py" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile index 854c36ee01c19..6020dc8877c16 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile @@ -22,8 +22,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --disable-optimize-tests \ - --set rust.test-compare-mode -ENV SCRIPT python3 ../x.py test --stage 1 --set rust.optimize=false library/std \ - && python3 ../x.py --stage 2 test + --set rust.test-compare-mode" +ENV SCRIPT="python3 ../x.py test --stage 1 --set rust.optimize=false library/std \ + && python3 ../x.py --stage 2 test" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 278e40eb71fac..3eb424ceef4a3 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -76,12 +76,11 @@ COPY scripts/nodejs.sh /scripts/ RUN sh /scripts/nodejs.sh /node ENV PATH="/node/bin:${PATH}" -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json \ - --enable-new-symbol-mangling + --enable-new-symbol-mangling" -ENV HOST_TARGET x86_64-unknown-linux-gnu +ENV HOST_TARGET="x86_64-unknown-linux-gnu" # FIXME(#133381): currently rustc alt builds do *not* have rustc debug # assertions enabled! Therefore, we cannot force download CI rustc. @@ -89,5 +88,5 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu COPY scripts/shared.sh /scripts/ -ENV SCRIPT /tmp/checktools.sh ../x.py && \ - python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" +ENV SCRIPT="/tmp/checktools.sh ../x.py && \ + python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args '--jobs 1'" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index 83c2aa8cfb3b7..7ca2dbb7d9f36 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -24,10 +24,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ +ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs \ - --set llvm.libzstd=true -ENV SCRIPT python3 ../x.py --stage 2 test + --set llvm.libzstd=true" +ENV SCRIPT="python3 ../x.py --stage 2 test" From c5c1d94e6ca8c695cd92d5f39c1c23d3d8338790 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 14 Mar 2026 22:09:13 -0400 Subject: [PATCH 2/5] Add `From` impls for wrapper types - `From for ThinBox` - `From for UniqueRc` - `From for UniqueArc` - `From for AssertUnwindSafe` - `From for LazyCell` - `From for LazyLock` --- library/alloc/src/boxed/thin.rs | 9 +++++++++ library/alloc/src/rc.rs | 9 +++++++++ library/alloc/src/sync.rs | 9 +++++++++ library/core/src/cell/lazy.rs | 10 ++++++++++ library/core/src/panic/unwind_safe.rs | 13 ++++++++++++ library/std/src/backtrace/tests.rs | 14 ++++++------- library/std/src/sync/lazy_lock.rs | 22 ++++++++++++--------- library/std/src/sync/once.rs | 7 +++++++ library/std/src/sys/sync/once/futex.rs | 5 +++++ library/std/src/sys/sync/once/no_threads.rs | 5 +++++ library/std/src/sys/sync/once/queue.rs | 5 +++++ 11 files changed, 91 insertions(+), 17 deletions(-) diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index b50810b8d923d..2a34537f58e31 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -430,3 +430,12 @@ impl Error for ThinBox { self.deref().source() } } + +#[cfg(not(no_global_oom_handling))] +#[unstable(feature = "thin_box", issue = "92791")] +impl From for ThinBox { + #[inline(always)] + fn from(value: T) -> Self { + Self::new(value) + } +} diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index cec41524325e0..8a651618ca83e 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -3980,6 +3980,15 @@ impl AsMut for UniqueRc { #[unstable(feature = "unique_rc_arc", issue = "112566")] impl Unpin for UniqueRc {} +#[cfg(not(no_global_oom_handling))] +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl From for UniqueRc { + #[inline(always)] + fn from(value: T) -> Self { + Self::new(value) + } +} + #[unstable(feature = "unique_rc_arc", issue = "112566")] impl PartialEq for UniqueRc { /// Equality for two `UniqueRc`s. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index dc82357dd146b..2c9fadbb8d9ef 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -4424,6 +4424,15 @@ impl AsMut for UniqueArc { } } +#[cfg(not(no_global_oom_handling))] +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl From for UniqueArc { + #[inline(always)] + fn from(value: T) -> Self { + Self::new(value) + } +} + #[unstable(feature = "unique_rc_arc", issue = "112566")] impl Unpin for UniqueArc {} diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 28a76569c1d03..ae559e599f481 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -366,6 +366,16 @@ impl fmt::Debug for LazyCell { } } +#[stable(feature = "from_wrapper_impls", since = "CURRENT_RUSTC_VERSION")] +impl From for LazyCell { + /// Constructs a `LazyCell` that starts already initialized + /// with the provided value. + #[inline] + fn from(value: T) -> Self { + Self { state: UnsafeCell::new(State::Init(value)) } + } +} + #[cold] #[inline(never)] const fn panic_poisoned() -> ! { diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 21dbd09f49606..ca2a4333eda52 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -313,3 +313,16 @@ impl AsyncIterator for AssertUnwindSafe { self.0.size_hint() } } + +/// If a value's type is already `UnwindSafe`, +/// wrapping it in `AssertUnwindSafe` is never incorrect. +#[stable(feature = "from_wrapper_impls", since = "CURRENT_RUSTC_VERSION")] +impl From for AssertUnwindSafe +where + T: UnwindSafe, +{ + #[inline(always)] + fn from(value: T) -> Self { + Self(value) + } +} diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs index 174d62813bd58..b68b528c18668 100644 --- a/library/std/src/backtrace/tests.rs +++ b/library/std/src/backtrace/tests.rs @@ -44,10 +44,9 @@ fn generate_fake_frames() -> Vec { #[test] fn test_debug() { let backtrace = Backtrace { - inner: Inner::Captured(LazyLock::preinit(Capture { - actual_start: 1, - frames: generate_fake_frames(), - })), + inner: Inner::Captured( + (Capture { actual_start: 1, frames: generate_fake_frames() }).into(), + ), }; #[rustfmt::skip] @@ -66,10 +65,9 @@ fn test_debug() { #[test] fn test_frames() { let backtrace = Backtrace { - inner: Inner::Captured(LazyLock::preinit(Capture { - actual_start: 1, - frames: generate_fake_frames(), - })), + inner: Inner::Captured( + (Capture { actual_start: 1, frames: generate_fake_frames() }).into(), + ), }; let frames = backtrace.frames(); diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 7274b5d10c75b..9bdde0ae4a537 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -105,15 +105,6 @@ impl T> LazyLock { LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) } } - /// Creates a new lazy value that is already initialized. - #[inline] - #[cfg(test)] - pub(crate) fn preinit(value: T) -> LazyLock { - let once = Once::new(); - once.call_once(|| {}); - LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) } - } - /// Consumes this `LazyLock` returning the stored value. /// /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. @@ -404,6 +395,19 @@ impl fmt::Debug for LazyLock { } } +#[stable(feature = "from_wrapper_impls", since = "CURRENT_RUSTC_VERSION")] +impl From for LazyLock { + /// Constructs a `LazyLock` that starts already initialized + /// with the provided value. + #[inline] + fn from(value: T) -> Self { + LazyLock { + once: Once::new_complete(), + data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }), + } + } +} + #[cold] #[inline(never)] fn panic_poisoned() -> ! { diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index bcfc9f581fd28..2556d1897b642 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -84,6 +84,13 @@ impl Once { Once { inner: sys::Once::new() } } + /// Creates a new `Once` value that starts already completed. + #[inline] + #[must_use] + pub(crate) const fn new_complete() -> Once { + Once { inner: sys::Once::new_complete() } + } + /// Performs an initialization routine once and only once. The given closure /// will be executed if this is the first time `call_once` has been called, /// and otherwise the routine will *not* be invoked. diff --git a/library/std/src/sys/sync/once/futex.rs b/library/std/src/sys/sync/once/futex.rs index 096f1d879ef26..236bc9ca4b7c7 100644 --- a/library/std/src/sys/sync/once/futex.rs +++ b/library/std/src/sys/sync/once/futex.rs @@ -75,6 +75,11 @@ impl Once { Once { state_and_queued: Futex::new(INCOMPLETE) } } + #[inline] + pub const fn new_complete() -> Once { + Once { state_and_queued: Futex::new(COMPLETE) } + } + #[inline] pub fn is_completed(&self) -> bool { // Use acquire ordering to make all initialization changes visible to the diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs index 576bbf644cbed..42fe2417307aa 100644 --- a/library/std/src/sys/sync/once/no_threads.rs +++ b/library/std/src/sys/sync/once/no_threads.rs @@ -39,6 +39,11 @@ impl Once { Once { state: Cell::new(State::Incomplete) } } + #[inline] + pub const fn new_complete() -> Once { + Once { state: Cell::new(State::Complete) } + } + #[inline] pub fn is_completed(&self) -> bool { self.state.get() == State::Complete diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index d7219a7361cff..f64f6523d1432 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -121,6 +121,11 @@ impl Once { Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(INCOMPLETE)) } } + #[inline] + pub const fn new_complete() -> Once { + Once { state_and_queue: AtomicPtr::new(ptr::without_provenance_mut(COMPLETE)) } + } + #[inline] pub fn is_completed(&self) -> bool { // An `Acquire` load is enough because that makes all the initialization From 4ecc78d637204bc3690ad0cd733671ce7b7e36ea Mon Sep 17 00:00:00 2001 From: arferreira Date: Sun, 15 Mar 2026 12:39:39 -0400 Subject: [PATCH 3/5] Suppress self-referential associated type constraint suggestion --- .../error_reporting/infer/note_and_explain.rs | 7 +++- ...ont-suggest-self-referential-constraint.rs | 20 +++++++++++ ...suggest-self-referential-constraint.stderr | 33 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/ui/associated-types/dont-suggest-self-referential-constraint.rs create mode 100644 tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 0fde0009debe7..7f53fdbc2c9f8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -263,8 +263,13 @@ impl Trait for X { cause.code(), ); } + // Don't suggest constraining a projection to something + // containing itself, e.g. `Item = &::Item`. (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) - if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => + if !tcx.is_impl_trait_in_trait(proj_ty.def_id) + && !tcx + .erase_and_anonymize_regions(values.expected) + .contains(tcx.erase_and_anonymize_regions(values.found)) => { let msg = || { format!( diff --git a/tests/ui/associated-types/dont-suggest-self-referential-constraint.rs b/tests/ui/associated-types/dont-suggest-self-referential-constraint.rs new file mode 100644 index 0000000000000..ad999a1c77356 --- /dev/null +++ b/tests/ui/associated-types/dont-suggest-self-referential-constraint.rs @@ -0,0 +1,20 @@ +// Regression test for #112104. +// +// Don't suggest `Item = &::Item` when +// the expected type wraps the found projection. + +fn option_of_ref_assoc(iter: &mut I) { + let _: Option<&I::Item> = iter.next(); + //~^ ERROR mismatched types +} + +// Valid constraint suggestions should still fire. +trait Foo { + type Assoc; +} + +fn assoc_to_concrete(x: T::Assoc) -> u32 { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr b/tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr new file mode 100644 index 0000000000000..e6e37cdf7e515 --- /dev/null +++ b/tests/ui/associated-types/dont-suggest-self-referential-constraint.stderr @@ -0,0 +1,33 @@ +error[E0308]: mismatched types + --> $DIR/dont-suggest-self-referential-constraint.rs:7:31 + | +LL | let _: Option<&I::Item> = iter.next(); + | ---------------- ^^^^^^^^^^^ expected `Option<&::Item>`, found `Option<::Item>` + | | + | expected due to this + | + = note: expected enum `Option<&_>` + found enum `Option<_>` +help: try using `.as_ref()` to convert `Option<::Item>` to `Option<&::Item>` + | +LL | let _: Option<&I::Item> = iter.next().as_ref(); + | +++++++++ + +error[E0308]: mismatched types + --> $DIR/dont-suggest-self-referential-constraint.rs:17:5 + | +LL | fn assoc_to_concrete(x: T::Assoc) -> u32 { + | --- expected `u32` because of return type +LL | x + | ^ expected `u32`, found associated type + | + = note: expected type `u32` + found associated type `::Assoc` +help: consider constraining the associated type `::Assoc` to `u32` + | +LL | fn assoc_to_concrete>(x: T::Assoc) -> u32 { + | +++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From cd4fd289cd60a56de47372cec0a260939cc93932 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 16 Mar 2026 17:36:53 +0100 Subject: [PATCH 4/5] suggest valid features when target feature is invalid --- compiler/rustc_codegen_ssa/src/errors.rs | 34 ++++++++++++------- .../rustc_codegen_ssa/src/target_features.rs | 32 +++++++++++------ tests/ui/target-feature/invalid-attribute.rs | 13 ++++--- .../target-feature/invalid-attribute.stderr | 20 ++++++++--- 4 files changed, 68 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 41337fc21a7b7..e0afcd51b7f41 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -8,7 +8,8 @@ use std::process::ExitStatus; use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, msg, + Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg, + Level, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::layout::LayoutError; @@ -1249,20 +1250,29 @@ pub(crate) struct FeatureNotValid<'a> { #[label("`{$feature}` is not valid for this target")] pub span: Span, #[subdiagnostic] - pub plus_hint: Option>, + pub hint: FeatureNotValidHint<'a>, } #[derive(Subdiagnostic)] -#[suggestion( - "consider removing the leading `+` in the feature name", - code = "enable = \"{stripped}\"", - applicability = "maybe-incorrect", - style = "verbose" -)] -pub struct RemovePlusFromFeatureName<'a> { - #[primary_span] - pub span: Span, - pub stripped: &'a str, +pub(crate) enum FeatureNotValidHint<'a> { + #[suggestion( + "consider removing the leading `+` in the feature name", + code = "enable = \"{stripped}\"", + applicability = "maybe-incorrect", + style = "verbose" + )] + RemovePlusFromFeatureName { + #[primary_span] + span: Span, + stripped: &'a str, + }, + #[help( + "valid names are: {$possibilities}{$and_more -> + [0] {\"\"} + *[other] {\" \"}and {$and_more} more + }" + )] + ValidFeatureNames { possibilities: DiagSymbolList<&'a str>, and_more: usize }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 08a02831312c7..8ac3f0555db27 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -9,12 +9,12 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol, edit_distance, sym}; use rustc_target::spec::Arch; use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability}; use smallvec::SmallVec; -use crate::errors::{FeatureNotValid, RemovePlusFromFeatureName}; +use crate::errors::{FeatureNotValid, FeatureNotValidHint}; use crate::{errors, target_features}; /// Compute the enabled target features from the `#[target_feature]` function attribute. @@ -32,15 +32,25 @@ pub(crate) fn from_target_feature_attr( for &(feature, feature_span) in features { let feature_str = feature.as_str(); let Some(stability) = rust_target_features.get(feature_str) else { - let plus_hint = feature_str - .strip_prefix('+') - .filter(|stripped| rust_target_features.contains_key(*stripped)) - .map(|stripped| RemovePlusFromFeatureName { span: feature_span, stripped }); - tcx.dcx().emit_err(FeatureNotValid { - feature: feature_str, - span: feature_span, - plus_hint, - }); + let hint = if let Some(stripped) = feature_str.strip_prefix('+') + && rust_target_features.contains_key(stripped) + { + FeatureNotValidHint::RemovePlusFromFeatureName { span: feature_span, stripped } + } else { + // Show the 5 feature names that are most similar to the input. + let mut valid_names: Vec<_> = + rust_target_features.keys().map(|name| name.as_str()).into_sorted_stable_ord(); + valid_names.sort_by_key(|name| { + edit_distance::edit_distance(name, feature.as_str(), 5).unwrap_or(usize::MAX) + }); + valid_names.truncate(5); + + FeatureNotValidHint::ValidFeatureNames { + possibilities: valid_names.into(), + and_more: rust_target_features.len().saturating_sub(5), + } + }; + tcx.dcx().emit_err(FeatureNotValid { feature: feature_str, span: feature_span, hint }); continue; }; diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index 47068fbb25d49..1022929118bd6 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -119,7 +119,12 @@ fn main() { //~| NOTE `+sse2` is not valid for this target unsafe fn hey() {} -#[target_feature(enable = "+sse5")] -//~^ ERROR `+sse5` is not valid for this target -//~| NOTE `+sse5` is not valid for this target -unsafe fn typo() {} +#[target_feature(enable = "sse5")] +//~^ ERROR `sse5` is not valid for this target +//~| NOTE `sse5` is not valid for this target +unsafe fn typo_sse() {} + +#[target_feature(enable = "avx512")] +//~^ ERROR `avx512` is not valid for this target +//~| NOTE `avx512` is not valid for this target +unsafe fn typo_avx512() {} diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index fbc35cfdc325e..8b91381a32b38 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -160,6 +160,8 @@ error: the feature named `foo` is not valid for this target | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ `foo` is not valid for this target + | + = help: valid names are: `fma`, `xop`, `adx`, `aes`, and `avx` and 74 more error[E0046]: not all trait items implemented, missing: `foo` --> $DIR/invalid-attribute.rs:81:1 @@ -205,13 +207,23 @@ LL - #[target_feature(enable = "+sse2")] LL + #[target_feature(enable = "sse2")] | -error: the feature named `+sse5` is not valid for this target +error: the feature named `sse5` is not valid for this target --> $DIR/invalid-attribute.rs:122:18 | -LL | #[target_feature(enable = "+sse5")] - | ^^^^^^^^^^^^^^^^ `+sse5` is not valid for this target +LL | #[target_feature(enable = "sse5")] + | ^^^^^^^^^^^^^^^ `sse5` is not valid for this target + | + = help: valid names are: `sse`, `sse2`, `sse3`, `sse4a`, and `ssse3` and 74 more + +error: the feature named `avx512` is not valid for this target + --> $DIR/invalid-attribute.rs:127:18 + | +LL | #[target_feature(enable = "avx512")] + | ^^^^^^^^^^^^^^^^^ `avx512` is not valid for this target + | + = help: valid names are: `avx512f`, `avx2`, `avx512bw`, `avx512cd`, and `avx512dq` and 74 more -error: aborting due to 25 previous errors +error: aborting due to 26 previous errors Some errors have detailed explanations: E0046, E0053, E0539, E0658. For more information about an error, try `rustc --explain E0046`. From f8bce56b3966c8784060ce875a51f65d18ac659b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 11 Mar 2026 19:39:47 +0100 Subject: [PATCH 5/5] Don't look for non-type-level assoc consts when checking trait object types --- .../src/hir_ty_lowering/dyn_trait.rs | 5 ++- compiler/rustc_middle/src/ty/assoc.rs | 4 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 2 +- .../associated-const-in-trait.rs | 2 + .../associated-const-in-trait.stderr | 38 +++++++++++++++++-- tests/ui/associated-item/issue-48027.stderr | 4 +- .../associated-consts.stderr | 4 +- tests/ui/type-alias/lack-of-wfcheck.rs | 27 +++++++++++++ tests/ui/wf/issue-87495.stderr | 9 ++++- 10 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 tests/ui/type-alias/lack-of-wfcheck.rs 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 7b8e09943df71..515cca6ac1c16 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 @@ -230,8 +230,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ordered_associated_items.extend( tcx.associated_items(pred.trait_ref.def_id) .in_definition_order() - // Only associated types & consts can possibly be constrained via a binding. - .filter(|item| item.is_type() || item.is_const()) + // Only associated types & type consts can possibly be + // constrained in a trait object type via a binding. + .filter(|item| item.is_type() || item.is_type_const()) // Traits with RPITITs are simply not dyn compatible (for now). .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| (item.def_id, trait_ref)), diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 4cc255cba6358..cabe8514ae4be 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -137,8 +137,8 @@ impl AssocItem { self.kind.as_def_kind() } - pub fn is_const(&self) -> bool { - matches!(self.kind, ty::AssocKind::Const { .. }) + pub fn is_type_const(&self) -> bool { + matches!(self.kind, ty::AssocKind::Const { is_type_const: true, .. }) } pub fn is_fn(&self) -> bool { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index b449b8f1a406c..780b57c470f36 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -753,7 +753,7 @@ impl<'tcx> Ty<'tcx> { .map(|principal| { tcx.associated_items(principal.def_id()) .in_definition_order() - .filter(|item| item.is_type() || item.is_const()) + .filter(|item| item.is_type() || item.is_type_const()) .filter(|item| !item.is_impl_trait_in_trait()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .count() diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 90b489258360f..5691ed1469276 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -239,7 +239,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc .flat_map(|super_poly_trait_ref| { tcx.associated_items(super_poly_trait_ref.def_id()) .in_definition_order() - .filter(|item| item.is_type() || item.is_const()) + .filter(|item| item.is_type() || item.is_type_const()) .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .map(move |assoc_item| { super_poly_trait_ref.map_bound(|super_trait_ref| { diff --git a/tests/ui/associated-consts/associated-const-in-trait.rs b/tests/ui/associated-consts/associated-const-in-trait.rs index 6b0b43feb109c..da68a0fa97c82 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.rs +++ b/tests/ui/associated-consts/associated-const-in-trait.rs @@ -7,6 +7,8 @@ trait Trait { impl dyn Trait { //~^ ERROR the trait `Trait` is not dyn compatible [E0038] const fn n() -> usize { Self::N } + //~^ ERROR the trait `Trait` is not dyn compatible [E0038] + //~| ERROR the trait `Trait` is not dyn compatible [E0038] } fn main() {} diff --git a/tests/ui/associated-consts/associated-const-in-trait.stderr b/tests/ui/associated-consts/associated-const-in-trait.stderr index fb4a55110b4e8..4085f8c990785 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.stderr +++ b/tests/ui/associated-consts/associated-const-in-trait.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/associated-const-in-trait.rs:7:10 + --> $DIR/associated-const-in-trait.rs:7:6 | LL | impl dyn Trait { - | ^^^^^ `Trait` is not dyn compatible + | ^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -14,6 +14,38 @@ LL | const N: usize; | ^ ...because it contains associated const `N` = help: consider moving `N` to another trait -error: aborting due to 1 previous error +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/associated-const-in-trait.rs:9:29 + | +LL | const fn n() -> usize { Self::N } + | ^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/associated-const-in-trait.rs:4:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const N: usize; + | ^ ...because it contains associated const `N` + = help: consider moving `N` to another trait + +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/associated-const-in-trait.rs:9:29 + | +LL | const fn n() -> usize { Self::N } + | ^^^^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/associated-const-in-trait.rs:4:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const N: usize; + | ^ ...because it contains associated const `N` + = help: consider moving `N` to another trait + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/associated-item/issue-48027.stderr b/tests/ui/associated-item/issue-48027.stderr index 7abcabc1c79d8..978c377d438ac 100644 --- a/tests/ui/associated-item/issue-48027.stderr +++ b/tests/ui/associated-item/issue-48027.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/issue-48027.rs:6:10 + --> $DIR/issue-48027.rs:6:6 | LL | impl dyn Bar {} - | ^^^ `Bar` is not dyn compatible + | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit diff --git a/tests/ui/dyn-compatibility/associated-consts.stderr b/tests/ui/dyn-compatibility/associated-consts.stderr index a92557ea7b8bd..11d02dd2904c8 100644 --- a/tests/ui/dyn-compatibility/associated-consts.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/associated-consts.rs:8:35 + --> $DIR/associated-consts.rs:8:31 | LL | fn make_bar(t: &T) -> &dyn Bar { - | ^^^ `Bar` is not dyn compatible + | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit diff --git a/tests/ui/type-alias/lack-of-wfcheck.rs b/tests/ui/type-alias/lack-of-wfcheck.rs new file mode 100644 index 0000000000000..91fbee8d3f198 --- /dev/null +++ b/tests/ui/type-alias/lack-of-wfcheck.rs @@ -0,0 +1,27 @@ +// Demonstrate that we don't check the definition site of (eager) type aliases for well-formedness. +// +// Listed below are ill-formed type system entities which we don't reject since they appear inside +// the definition of (eager) type aliases. These type aliases are intentionally not referenced from +// anywhere to prevent the eagerly expanded / instantiated aliased types from getting wfchecked +// since that's not what we're testing here. + +//@ check-pass + +type UnsatTraitBound0 = [str]; // `str: Sized` unsatisfied +type UnsatTraitBound1> = T; // `str: Sized` unsatisfied +type UnsatOutlivesBound<'a> = &'static &'a (); // `'a: 'static` unsatisfied + +type Diverging = [(); panic!()]; // `panic!()` diverging + +type DynIncompat0 = dyn Sized; // `Sized` axiomatically dyn incompatible +// issue: +type DynIncompat1 = dyn HasAssocConst; // dyn incompatible due to (non-type-level) assoc const + +// * dyn incompatible due to GAT +// * `'a: 'static`, `String: Copy` and `[u8]: Sized` unsatisfied, `loop {}` diverging +type Several<'a> = dyn HasGenericAssocType = [u8]>; + +trait HasAssocConst { const N: usize; } +trait HasGenericAssocType { type Type<'a: 'static, T: Copy, const N: usize>; } + +fn main() {} diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr index 49651e8d6c05c..42e3e2608d732 100644 --- a/tests/ui/wf/issue-87495.stderr +++ b/tests/ui/wf/issue-87495.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `T` is not dyn compatible - --> $DIR/issue-87495.rs:4:29 + --> $DIR/issue-87495.rs:4:25 | LL | const CONST: (bool, dyn T); - | ^ `T` is not dyn compatible + | ^^^^^ `T` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit @@ -13,6 +13,11 @@ LL | trait T { LL | const CONST: (bool, dyn T); | ^^^^^ ...because it contains associated const `CONST` = help: consider moving `CONST` to another trait +help: you might have meant to use `Self` to refer to the implementing type + | +LL - const CONST: (bool, dyn T); +LL + const CONST: (bool, Self); + | error: aborting due to 1 previous error