From da133533ed1d16275a523aa09b06b1c459691f6a Mon Sep 17 00:00:00 2001 From: Jaiden Magnan Date: Wed, 14 Jan 2026 10:50:32 -0500 Subject: [PATCH 01/28] fix: more descriptive error message for enum to integer --- compiler/rustc_hir_typeck/src/cast.rs | 30 +++++++++++++++---- .../ui/cast/cast-enum-to-int-issue-151116.rs | 11 +++++++ .../cast/cast-enum-to-int-issue-151116.stderr | 14 +++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 tests/ui/cast/cast-enum-to-int-issue-151116.rs create mode 100644 tests/ui/cast/cast-enum-to-int-issue-151116.stderr diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 93275f62dcc17..e1d9d7fe6e538 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -291,12 +291,32 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::NeedViaThinPtr | CastError::NeedViaPtr => { let mut err = make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx); + if self.cast_ty.is_integral() { - err.help(format!("cast through {} first", match e { - CastError::NeedViaPtr => "a raw pointer", - CastError::NeedViaThinPtr => "a thin pointer", - e => unreachable!("control flow means we should never encounter a {e:?}"), - })); + if !matches!(self.expr.kind, ExprKind::AddrOf(..)) + && let ty::Ref(_, inner_ty, _) = *self.expr_ty.kind() + && let ty::Adt(adt_def, _) = *inner_ty.kind() + && adt_def.is_enum() + && adt_def.is_payloadfree() + { + err.span_suggestion_verbose( + self.expr_span.shrink_to_lo(), + "dereference the expression", + "*", + Applicability::MachineApplicable, + ); + } else { + err.help(format!( + "cast through {} first", + match e { + CastError::NeedViaPtr => "a raw pointer", + CastError::NeedViaThinPtr => "a thin pointer", + e => unreachable!( + "control flow means we should never encounter a {e:?}" + ), + } + )); + } } self.try_suggest_collection_to_bool(fcx, &mut err); diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.rs b/tests/ui/cast/cast-enum-to-int-issue-151116.rs new file mode 100644 index 0000000000000..ac6ff7b806edf --- /dev/null +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.rs @@ -0,0 +1,11 @@ +#[repr(u8)] +enum Priority { + High = 255, + Normal = 127, + Low = 1, +} + +fn main() { + let priority = &Priority::Normal; + let priority = priority as u8; //~ ERROR casting `&Priority` as `u8` is invalid +} diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.stderr b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr new file mode 100644 index 0000000000000..f1bcf3f26ea57 --- /dev/null +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr @@ -0,0 +1,14 @@ +error[E0606]: casting `&Priority` as `u8` is invalid + --> $DIR/cast-enum-to-int-issue-151116.rs:10:20 + | +LL | let priority = priority as u8; + | ^^^^^^^^^^^^^^ + | +help: dereference the expression + | +LL | let priority = *priority as u8; + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0606`. From 53f0ce84b2723ef508db374cdfdfddd07bcf477d Mon Sep 17 00:00:00 2001 From: Jaiden Magnan Date: Wed, 14 Jan 2026 11:32:24 -0500 Subject: [PATCH 02/28] fix: add the HELP message --- tests/ui/cast/cast-enum-to-int-issue-151116.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.rs b/tests/ui/cast/cast-enum-to-int-issue-151116.rs index ac6ff7b806edf..2c278d61ec1c6 100644 --- a/tests/ui/cast/cast-enum-to-int-issue-151116.rs +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.rs @@ -8,4 +8,5 @@ enum Priority { fn main() { let priority = &Priority::Normal; let priority = priority as u8; //~ ERROR casting `&Priority` as `u8` is invalid + //~| HELP: dereference the expression } From 9f43e6dafa23368feed921a3c4126126aaa9728e Mon Sep 17 00:00:00 2001 From: Jaiden Magnan Date: Sun, 26 Apr 2026 15:07:48 -0400 Subject: [PATCH 03/28] feat: fixing PR feedback --- compiler/rustc_hir_typeck/src/cast.rs | 2 +- tests/ui/cast/cast-enum-to-int-issue-151116.rs | 3 +++ tests/ui/cast/cast-enum-to-int-issue-151116.stderr | 10 +++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index e1d9d7fe6e538..77d45b46f1d7b 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -303,7 +303,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr_span.shrink_to_lo(), "dereference the expression", "*", - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); } else { err.help(format!( diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.rs b/tests/ui/cast/cast-enum-to-int-issue-151116.rs index 2c278d61ec1c6..d254b6400f2d4 100644 --- a/tests/ui/cast/cast-enum-to-int-issue-151116.rs +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.rs @@ -9,4 +9,7 @@ fn main() { let priority = &Priority::Normal; let priority = priority as u8; //~ ERROR casting `&Priority` as `u8` is invalid //~| HELP: dereference the expression + + let priority = &Priority::Normal as u8; //~ ERROR casting `&Priority` as `u8` is invalid + //~| HELP: cast through a raw pointer first } diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.stderr b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr index f1bcf3f26ea57..63a4a0cb71881 100644 --- a/tests/ui/cast/cast-enum-to-int-issue-151116.stderr +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr @@ -9,6 +9,14 @@ help: dereference the expression LL | let priority = *priority as u8; | + -error: aborting due to 1 previous error +error[E0606]: casting `&Priority` as `u8` is invalid + --> $DIR/cast-enum-to-int-issue-151116.rs:13:20 + | +LL | let priority = &Priority::Normal as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: cast through a raw pointer first + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0606`. From a1c5893176e25a56cdbcd8f60f2513d387a85996 Mon Sep 17 00:00:00 2001 From: Arjun Ramesh Date: Fri, 1 May 2026 16:29:04 -0400 Subject: [PATCH 04/28] Added std library support for WALI command-line arguments. --- library/std/src/os/linux/raw.rs | 5 +-- library/std/src/sys/args/mod.rs | 6 +++- library/std/src/sys/args/wali.rs | 56 ++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 library/std/src/sys/args/wali.rs diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index 6483f0861139b..6f2da15a98d69 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -31,7 +31,6 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; target_arch = "powerpc", target_arch = "sparc", target_arch = "arm", - target_arch = "wasm32" ))] mod arch { use crate::os::raw::{c_long, c_short, c_uint}; @@ -311,7 +310,9 @@ mod arch { } } -#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))] +#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64", + // `wasm32-wali-linux-musl` uses ABI similar to x86_64 + target_arch = "wasm32"))] mod arch { use crate::os::raw::{c_int, c_long}; diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index fd5562a520b71..8bd835c08d7c1 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -15,7 +15,7 @@ mod common; cfg_select! { any( - all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))), + all(target_family = "unix", not(any(target_family = "wasm", target_os = "espidf", target_os = "vita"))), target_os = "hermit", ) => { mod unix; @@ -45,6 +45,10 @@ cfg_select! { mod wasi; pub use wasi::*; } + all(target_family = "wasm", target_os = "linux") => { + mod wali; + pub use wali::*; + } target_os = "xous" => { mod xous; pub use xous::*; diff --git a/library/std/src/sys/args/wali.rs b/library/std/src/sys/args/wali.rs new file mode 100644 index 0000000000000..36455d4821554 --- /dev/null +++ b/library/std/src/sys/args/wali.rs @@ -0,0 +1,56 @@ +pub use super::common::Args; + +/// One-time global initialization. +pub unsafe fn init(argc: isize, argv: *const *const u8) { + unsafe { imp::init(argc, argv) } +} + +/// Returns the command line arguments +pub fn args() -> Args { + imp::args() +} + +mod imp { + use super::Args; + use crate::ffi::{CString, OsString}; + use crate::os::raw::{c_uint as WaliArgIdx, c_uint}; + use crate::os::unix::prelude::*; + use crate::sync::OnceLock; + + #[link(wasm_import_module = "wali")] + unsafe extern "C" { + pub fn __cl_get_argc() -> WaliArgIdx; + pub fn __cl_get_argv_len(offset: WaliArgIdx) -> c_uint; + pub fn __cl_copy_argv(buf: *mut i8, offset: WaliArgIdx) -> c_uint; + } + + static ARGS: OnceLock> = OnceLock::new(); + + pub unsafe fn init(_argc: isize, _argv: *const *const u8) { + // Uses the WALI arguments API + ARGS.set(argc_argv()).ok(); + } + + unsafe fn load_arg(idx: c_uint) -> OsString { + let arg_len = unsafe { __cl_get_argv_len(idx) }; + let arg_buf = CString::new(vec![b'x'; arg_len as usize]).unwrap(); + let ptr = arg_buf.into_raw(); + let arg_buf = unsafe { + __cl_copy_argv(ptr, idx); + CString::from_raw(ptr) + }; + let mut arg_buf = arg_buf.into_bytes_with_nul(); + let _ = arg_buf.pop(); + OsStringExt::from_vec(arg_buf) + } + + fn argc_argv() -> Vec { + let argc = unsafe { __cl_get_argc() }; + (0..argc).map(|x| unsafe { load_arg(x) }).collect() + } + + pub fn args() -> Args { + let cached = ARGS.get().cloned().unwrap_or_default(); + Args::new(cached) + } +} From a6d6601b20e53322e9b69ad2bd1aad8154250134 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2026 13:52:01 +0200 Subject: [PATCH 05/28] interpret: correctly deal with repr(transparent) enums --- compiler/rustc_const_eval/src/interpret/call.rs | 2 +- src/tools/miri/tests/pass/function_calls/abi_compat.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 5ec0344592da5..edbb668024455 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -81,7 +81,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> TyAndLayout<'tcx> { match layout.ty.kind() { ty::Adt(adt_def, _) if adt_def.repr().transparent() && may_unfold(*adt_def) => { - assert!(!adt_def.is_enum()); + assert_matches!(layout.variants, rustc_abi::Variants::Single { .. }); // Find the non-1-ZST field, and recurse. let (_, field) = layout.non_1zst_field(self).unwrap(); self.unfold_transparent(field, may_unfold) diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index cd48bd2accb27..ca76897faea86 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -63,13 +63,20 @@ fn test_abi_newtype() { #[repr(transparent)] #[derive(Copy, Clone)] struct Wrapper3(Zst, T, [u8; 0]); + #[repr(transparent)] + #[derive(Copy, Clone)] + enum Wrapper4 { + V(Zst, T, [u8; 0]) + } let t = T::default(); test_abi_compat(t, Wrapper(t)); test_abi_compat(t, Wrapper2(t, ())); test_abi_compat(t, Wrapper2a((), t)); test_abi_compat(t, Wrapper3(Zst, t, [])); - test_abi_compat(t, mem::MaybeUninit::new(t)); // MaybeUninit is `repr(transparent)` + test_abi_compat(t, Wrapper4::V(Zst, t, [])); + // MaybeUninit is `repr(transparent)`; that covers the `union` case. + test_abi_compat(t, mem::MaybeUninit::new(t)); } fn main() { From f4e1b2f3e89b49bfd92a6c7c4d24a8ee35ff6a91 Mon Sep 17 00:00:00 2001 From: Arjun Ramesh Date: Mon, 4 May 2026 08:34:11 -0400 Subject: [PATCH 06/28] Use `into_bytes` directly --- library/std/src/sys/args/wali.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/std/src/sys/args/wali.rs b/library/std/src/sys/args/wali.rs index 36455d4821554..dc6295a483334 100644 --- a/library/std/src/sys/args/wali.rs +++ b/library/std/src/sys/args/wali.rs @@ -39,9 +39,7 @@ mod imp { __cl_copy_argv(ptr, idx); CString::from_raw(ptr) }; - let mut arg_buf = arg_buf.into_bytes_with_nul(); - let _ = arg_buf.pop(); - OsStringExt::from_vec(arg_buf) + OsStringExt::from_vec(arg_buf.into_bytes()) } fn argc_argv() -> Vec { From 9ef7541f7c7d377092d052ee19de0fda8f1504de Mon Sep 17 00:00:00 2001 From: Arjun Ramesh Date: Mon, 4 May 2026 13:43:56 -0400 Subject: [PATCH 07/28] Restrict cfg gating on unix to not interfere with emscripten target --- library/std/src/sys/args/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index 8bd835c08d7c1..2659750f49eff 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -15,7 +15,7 @@ mod common; cfg_select! { any( - all(target_family = "unix", not(any(target_family = "wasm", target_os = "espidf", target_os = "vita"))), + all(target_family = "unix", not(any(all(target_family = "wasm", target_os = "linux"), target_os = "espidf", target_os = "vita"))), target_os = "hermit", ) => { mod unix; From 596d9853bb6c44c3ae290a40f792ee4ec54d1ea0 Mon Sep 17 00:00:00 2001 From: Devon Loehr Date: Mon, 4 May 2026 17:41:27 +0000 Subject: [PATCH 08/28] Adjust getMCSubtargetInfo signature for LLVM 23+ --- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index c7e8f99465e18..643e4944bf784 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -91,8 +91,13 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char *FileName) { extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, const char *Feature) { TargetMachine *Target = unwrap(TM); +#if LLVM_VERSION_GE(23, 0) + const MCSubtargetInfo &MCInfo = Target->getMCSubtargetInfo(); + return MCInfo.checkFeatures(std::string("+") + Feature); +#else const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); return MCInfo->checkFeatures(std::string("+") + Feature); +#endif } /// Check whether the target has a specific assembly mnemonic like `ret` or @@ -274,7 +279,11 @@ static llvm::DebugCompressionType fromRust(LLVMRustCompressionKind Kind) { extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, RustStringRef OutStr) { ArrayRef CPUTable = +#if LLVM_VERSION_GE(23, 0) + unwrap(TM)->getMCSubtargetInfo().getAllProcessorDescriptions(); +#else unwrap(TM)->getMCSubtargetInfo()->getAllProcessorDescriptions(); +#endif auto OS = RawRustStringOstream(OutStr); // Just print a bare list of target CPU names, and let Rust-side code handle @@ -286,9 +295,15 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) { const TargetMachine *Target = unwrap(TM); +#if LLVM_VERSION_GE(23, 0) + const MCSubtargetInfo &MCInfo = Target->getMCSubtargetInfo(); + const ArrayRef FeatTable = + MCInfo.getAllProcessorFeatures(); +#else const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); const ArrayRef FeatTable = MCInfo->getAllProcessorFeatures(); +#endif return FeatTable.size(); } @@ -296,9 +311,15 @@ extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index, const char **Feature, const char **Desc) { const TargetMachine *Target = unwrap(TM); +#if LLVM_VERSION_GE(23, 0) + const MCSubtargetInfo &MCInfo = Target->getMCSubtargetInfo(); + const ArrayRef FeatTable = + MCInfo.getAllProcessorFeatures(); +#else const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); const ArrayRef FeatTable = MCInfo->getAllProcessorFeatures(); +#endif const SubtargetFeatureKV Feat = FeatTable[Index]; *Feature = Feat.Key; *Desc = Feat.Desc; From ad582a586550bf2c72e963939f61a71df1af7c0c Mon Sep 17 00:00:00 2001 From: David Tenty Date: Mon, 4 May 2026 17:13:10 -0400 Subject: [PATCH 09/28] [AIX] add -bdbg:namedsects:ss link arg On AIX, PGO runtimes and ifunc support requires the named section linker feature which collects the name sections together and generates start/stop symbols for them. This change adds the option to the default linker args for the target. --- .../rustc_target/src/spec/targets/powerpc64_ibm_aix.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs index 469f8272e1ccf..5ab81aa55787e 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs @@ -5,7 +5,13 @@ pub(crate) fn target() -> Target { base.max_atomic_width = Some(64); base.add_pre_link_args( LinkerFlavor::Unix(Cc::No), - &["-b64", "-bpT:0x100000000", "-bpD:0x110000000", "-bcdtors:mbr:0:s"], + &[ + "-b64", + "-bpT:0x100000000", + "-bpD:0x110000000", + "-bcdtors:mbr:0:s", + "-bdbg:namedsects:ss", // PGO and ifunc support depends on the named sections linker feature + ], ); Target { From fbb5809996f6014142d7ba35f2d77f144df8a9f8 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Tue, 5 May 2026 07:21:22 +0200 Subject: [PATCH 10/28] Wasm: remove implicit `__heap_base`/`__data_end` exports --- compiler/rustc_codegen_ssa/src/back/linker.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 76aecb3b9e54e..2155f94a7cfd3 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1464,14 +1464,6 @@ impl<'a> Linker for WasmLd<'a> { for (sym, _) in symbols { self.link_args(&["--export", sym]); } - - // LLD will hide these otherwise-internal symbols since it only exports - // symbols explicitly passed via the `--export` flags above and hides all - // others. Various bits and pieces of wasm32-unknown-unknown tooling use - // this, so be sure these symbols make their way out of the linker as well. - if matches!(self.sess.target.os, Os::Unknown | Os::None) { - self.link_args(&["--export=__heap_base", "--export=__data_end"]); - } } fn windows_subsystem(&mut self, _subsystem: WindowsSubsystemKind) {} From 227a289461ba629abd29ea1f8a6939cddf2312de Mon Sep 17 00:00:00 2001 From: inq Date: Tue, 5 May 2026 09:57:57 +0700 Subject: [PATCH 11/28] add known-bug test for coroutine 'static-yields-non-'static unsoundness Coroutine variant of the closure / impl Fn 'static unsoundness family. References in PR description. --- .../static-coroutine-with-nonstatic-yield.rs | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 tests/ui/coroutine/static-coroutine-with-nonstatic-yield.rs diff --git a/tests/ui/coroutine/static-coroutine-with-nonstatic-yield.rs b/tests/ui/coroutine/static-coroutine-with-nonstatic-yield.rs new file mode 100644 index 0000000000000..99b53fae8bce0 --- /dev/null +++ b/tests/ui/coroutine/static-coroutine-with-nonstatic-yield.rs @@ -0,0 +1,60 @@ +//@ check-pass +//@ known-bug: #144442 + +// Same family as #84366 / #112905: a coroutine that yields a non-`'static` +// reference is wrongly `: 'static`, allowing a `Box` downcast to +// transmute between distinct lifetime substitutions and produce a UAF. + +#![forbid(unsafe_code)] // No `unsafe!` +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] + +use std::any::Any; +use std::cell::RefCell; +use std::ops::{Coroutine, CoroutineState}; +use std::pin::Pin; +use std::rc::Rc; + +type Payload = Box; + +fn make_coro<'a>() +-> impl Coroutine>>, Return = ()> + 'static { + #[coroutine] + || { + let storage: Rc>> = Rc::new(RefCell::new(None)); + yield storage.clone(); + yield storage; + } +} + +pub fn expand<'a>(payload: &'a Payload) -> &'static Payload { + let mut coro1 = Box::pin(make_coro::<'a>()); + let coro2 = make_coro::<'static>(); + let CoroutineState::Yielded(storage) = coro1.as_mut().resume(()) else { + panic!() + }; + *storage.borrow_mut() = Some(payload); + extract(coro1, coro2) +} + +fn extract< + 'a, + F: Coroutine>>, Return = ()> + 'static, + G: Coroutine>>, Return = ()> + 'static, +>( + x: Pin>, + _: G, +) -> &'static Payload { + let mut g: Pin> = *(Box::new(x) as Box).downcast().unwrap(); + let CoroutineState::Yielded(storage) = g.as_mut().resume(()) else { + panic!() + }; + let payload = storage.borrow().unwrap(); + payload +} + +fn main() { + let x = Box::new(Box::new(1i32)); + let y = expand(&x); + drop(x); + println!("{y}"); // Segfaults — UAF without `unsafe`. +} From 4d6351dc40dc275f112dd122e780378739ee6da8 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 5 May 2026 12:11:02 +0000 Subject: [PATCH 12/28] use `deref_patterns` in `rustc_ast_passes` --- .../rustc_ast_passes/src/ast_validation.rs | 41 ++++++++----------- compiler/rustc_ast_passes/src/feature_gate.rs | 10 ++--- compiler/rustc_ast_passes/src/lib.rs | 2 +- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d9f03342e1047..5725c65518845 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -607,7 +607,7 @@ impl<'a> AstValidator<'a> { } fn check_final_has_body(&self, item: &Item, defaultness: Defaultness) { - if let AssocItemKind::Fn(box Fn { body: None, .. }) = &item.kind + if let AssocItemKind::Fn(Fn { body: None, .. }) = &item.kind && let Defaultness::Final(def_span) = defaultness { let span = self.sess.source_map().guess_head_span(item.span); @@ -1163,8 +1163,7 @@ impl Visitor<'_> for AstValidator<'_> { ItemKind::Impl(Impl { generics, constness, - of_trait: - Some(box TraitImplHeader { safety, polarity, defaultness: _, trait_ref: t }), + of_trait: Some(TraitImplHeader { safety, polarity, defaultness: _, trait_ref: t }), self_ty, items, }) => { @@ -1234,7 +1233,7 @@ impl Visitor<'_> for AstValidator<'_> { ); } ItemKind::Fn( - func @ box Fn { + func @ Fn { defaultness, ident, generics: _, @@ -1328,14 +1327,8 @@ impl Visitor<'_> for AstValidator<'_> { visit::walk_item(this, item) }); } - ItemKind::Trait(box Trait { - constness, - is_auto, - generics, - ident, - bounds, - items, - .. + ItemKind::Trait(Trait { + constness, is_auto, generics, ident, bounds, items, .. }) => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); if *is_auto == IsAuto::Yes { @@ -1360,7 +1353,7 @@ impl Visitor<'_> for AstValidator<'_> { walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); }); } - ItemKind::TraitAlias(box TraitAlias { constness, generics, bounds, .. }) => { + ItemKind::TraitAlias(TraitAlias { constness, generics, bounds, .. }) => { let disallowed = matches!(constness, ast::Const::No) .then(|| TildeConstReason::Trait { span: item.span }); self.with_tilde_const(disallowed, |this| { @@ -1422,7 +1415,7 @@ impl Visitor<'_> for AstValidator<'_> { } }); } - ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => { + ItemKind::Const(ConstItem { defaultness, ident, rhs_kind, .. }) => { self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No); if !rhs_kind.has_expr() { self.dcx().emit_err(errors::ConstWithoutBody { @@ -1444,7 +1437,7 @@ impl Visitor<'_> for AstValidator<'_> { visit::walk_item(self, item); } - ItemKind::Static(box StaticItem { expr, safety, .. }) => { + ItemKind::Static(StaticItem { expr, safety, .. }) => { self.check_item_safety(item.span, *safety); if matches!(safety, Safety::Unsafe(_)) { self.dcx().emit_err(errors::UnsafeStatic { span: item.span }); @@ -1459,7 +1452,7 @@ impl Visitor<'_> for AstValidator<'_> { visit::walk_item(self, item); } ItemKind::TyAlias( - ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. }, + ty_alias @ TyAlias { defaultness, bounds, after_where_clause, ty, .. }, ) => { self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No); if ty.is_none() { @@ -1490,7 +1483,7 @@ impl Visitor<'_> for AstValidator<'_> { fn visit_foreign_item(&mut self, fi: &ForeignItem) { match &fi.kind { - ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => { + ForeignItemKind::Fn(Fn { defaultness, ident, sig, body, .. }) => { self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No); self.check_foreign_fn_bodyless(*ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); @@ -1511,7 +1504,7 @@ impl Visitor<'_> for AstValidator<'_> { }); } } - ForeignItemKind::TyAlias(box TyAlias { + ForeignItemKind::TyAlias(TyAlias { defaultness, ident, generics, @@ -1526,7 +1519,7 @@ impl Visitor<'_> for AstValidator<'_> { self.check_foreign_ty_genericless(generics, after_where_clause); self.check_foreign_item_ascii_only(*ident); } - ForeignItemKind::Static(box StaticItem { ident, safety, expr, .. }) => { + ForeignItemKind::Static(StaticItem { ident, safety, expr, .. }) => { self.check_item_safety(fi.span, *safety); self.check_foreign_kind_bodyless(*ident, "static", expr.as_ref().map(|b| b.span)); self.check_foreign_item_ascii_only(*ident); @@ -1818,7 +1811,7 @@ impl Visitor<'_> for AstValidator<'_> { if let AssocCtxt::Impl { .. } = ctxt { match &item.kind { - AssocItemKind::Const(box ConstItem { rhs_kind, .. }) => { + AssocItemKind::Const(ConstItem { rhs_kind, .. }) => { if !rhs_kind.has_expr() { self.dcx().emit_err(errors::AssocConstWithoutBody { span: item.span, @@ -1826,7 +1819,7 @@ impl Visitor<'_> for AstValidator<'_> { }); } } - AssocItemKind::Fn(box Fn { body, .. }) => { + AssocItemKind::Fn(Fn { body, .. }) => { if body.is_none() && !self.is_sdylib_interface { self.dcx().emit_err(errors::AssocFnWithoutBody { span: item.span, @@ -1834,7 +1827,7 @@ impl Visitor<'_> for AstValidator<'_> { }); } } - AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => { + AssocItemKind::Type(TyAlias { bounds, ty, .. }) => { if ty.is_none() { self.dcx().emit_err(errors::AssocTypeWithoutBody { span: item.span, @@ -1889,13 +1882,13 @@ impl Visitor<'_> for AstValidator<'_> { &item.vis, errors::VisibilityNotPermittedNote::TraitImpl, ); - if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { + if let AssocItemKind::Fn(Fn { sig, .. }) = &item.kind { self.check_trait_fn_not_const(sig.header.constness, parent); self.check_async_fn_in_const_trait_or_impl(sig, parent); } } Some(parent @ TraitOrImpl::Impl { constness }) => { - if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { + if let AssocItemKind::Fn(Fn { sig, .. }) = &item.kind { self.check_impl_fn_not_const(sig.header.constness, *constness); self.check_async_fn_in_const_trait_or_impl(sig, parent); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2b08906a77434..1bee96be835f9 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -228,7 +228,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Trait(box ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => { + ast::ItemKind::Trait(ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => { gate!(self, auto_traits, i.span, "auto traits are experimental and possibly buggy"); } @@ -241,10 +241,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate!(self, decl_macro, i.span, msg); } - ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ty), .. }) => { + ast::ItemKind::TyAlias(ast::TyAlias { ty: Some(ty), .. }) => { self.check_impl_trait(ty, false) } - ast::ItemKind::Const(box ast::ConstItem { + ast::ItemKind::Const(ast::ConstItem { rhs_kind: ast::ConstItemRhsKind::TypeConst { .. }, .. }) => { @@ -407,7 +407,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { let is_fn = match &i.kind { ast::AssocItemKind::Fn(_) => true, - ast::AssocItemKind::Type(box ast::TyAlias { ty, .. }) => { + ast::AssocItemKind::Type(ast::TyAlias { ty, .. }) => { if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { gate!( self, @@ -421,7 +421,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } false } - ast::AssocItemKind::Const(box ast::ConstItem { + ast::AssocItemKind::Const(ast::ConstItem { rhs_kind: ast::ConstItemRhsKind::TypeConst { rhs }, .. }) => { diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 677e44a79ac4b..8bf51dd10a844 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -3,7 +3,7 @@ //! by `rustc_ast_lowering`. // tidy-alphabetical-start -#![feature(box_patterns)] +#![feature(deref_patterns)] #![feature(iter_intersperse)] #![feature(iter_is_partitioned)] // tidy-alphabetical-end From e291b07dd99b7825a8e0c7861a8f17a0387575cb Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 5 May 2026 12:12:02 +0000 Subject: [PATCH 13/28] use `deref_patterns` in `rustc_ast` --- compiler/rustc_ast/src/ast.rs | 44 +++++++++++++-------------- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_ast/src/util/parser.rs | 2 +- compiler/rustc_ast/src/visit.rs | 6 ++-- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b105a97cdf98d..0be00f4d00be7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -4087,18 +4087,18 @@ impl ItemKind { pub fn ident(&self) -> Option { match *self { ItemKind::ExternCrate(_, ident) - | ItemKind::Static(box StaticItem { ident, .. }) - | ItemKind::Const(box ConstItem { ident, .. }) - | ItemKind::Fn(box Fn { ident, .. }) + | ItemKind::Static(StaticItem { ident, .. }) + | ItemKind::Const(ConstItem { ident, .. }) + | ItemKind::Fn(Fn { ident, .. }) | ItemKind::Mod(_, ident, _) - | ItemKind::TyAlias(box TyAlias { ident, .. }) + | ItemKind::TyAlias(TyAlias { ident, .. }) | ItemKind::Enum(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Union(ident, ..) - | ItemKind::Trait(box Trait { ident, .. }) - | ItemKind::TraitAlias(box TraitAlias { ident, .. }) + | ItemKind::Trait(Trait { ident, .. }) + | ItemKind::TraitAlias(TraitAlias { ident, .. }) | ItemKind::MacroDef(ident, _) - | ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), + | ItemKind::Delegation(Delegation { ident, .. }) => Some(ident), ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT), @@ -4149,14 +4149,14 @@ impl ItemKind { pub fn generics(&self) -> Option<&Generics> { match self { - Self::Fn(box Fn { generics, .. }) - | Self::TyAlias(box TyAlias { generics, .. }) - | Self::Const(box ConstItem { generics, .. }) + Self::Fn(Fn { generics, .. }) + | Self::TyAlias(TyAlias { generics, .. }) + | Self::Const(ConstItem { generics, .. }) | Self::Enum(_, generics, _) | Self::Struct(_, generics, _) | Self::Union(_, generics, _) - | Self::Trait(box Trait { generics, .. }) - | Self::TraitAlias(box TraitAlias { generics, .. }) + | Self::Trait(Trait { generics, .. }) + | Self::TraitAlias(TraitAlias { generics, .. }) | Self::Impl(Impl { generics, .. }) => Some(generics), Self::ExternCrate(..) @@ -4205,10 +4205,10 @@ pub enum AssocItemKind { impl AssocItemKind { pub fn ident(&self) -> Option { match *self { - AssocItemKind::Const(box ConstItem { ident, .. }) - | AssocItemKind::Fn(box Fn { ident, .. }) - | AssocItemKind::Type(box TyAlias { ident, .. }) - | AssocItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), + AssocItemKind::Const(ConstItem { ident, .. }) + | AssocItemKind::Fn(Fn { ident, .. }) + | AssocItemKind::Type(TyAlias { ident, .. }) + | AssocItemKind::Delegation(Delegation { ident, .. }) => Some(ident), AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(_) => None, } @@ -4216,9 +4216,9 @@ impl AssocItemKind { pub fn defaultness(&self) -> Defaultness { match *self { - Self::Const(box ConstItem { defaultness, .. }) - | Self::Fn(box Fn { defaultness, .. }) - | Self::Type(box TyAlias { defaultness, .. }) => defaultness, + Self::Const(ConstItem { defaultness, .. }) + | Self::Fn(Fn { defaultness, .. }) + | Self::Type(TyAlias { defaultness, .. }) => defaultness, Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => { Defaultness::Implicit } @@ -4271,9 +4271,9 @@ pub enum ForeignItemKind { impl ForeignItemKind { pub fn ident(&self) -> Option { match *self { - ForeignItemKind::Static(box StaticItem { ident, .. }) - | ForeignItemKind::Fn(box Fn { ident, .. }) - | ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => Some(ident), + ForeignItemKind::Static(StaticItem { ident, .. }) + | ForeignItemKind::Fn(Fn { ident, .. }) + | ForeignItemKind::TyAlias(TyAlias { ident, .. }) => Some(ident), ForeignItemKind::MacCall(_) => None, } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 4178db1bfb09d..3b01eb6eefa7d 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -7,7 +7,7 @@ // tidy-alphabetical-start #![doc(test(attr(deny(warnings), allow(internal_features))))] #![feature(associated_type_defaults)] -#![feature(box_patterns)] +#![feature(deref_patterns)] #![feature(iter_order_by)] #![feature(macro_metavar_expr)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 1e5f414fae1c7..1430d04dcca6a 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -210,7 +210,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { contains_exterior_struct_lit(x) } - ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => { + ast::ExprKind::MethodCall(ast::MethodCall { receiver, .. }) => { // X { y: 1 }.bar(...) contains_exterior_struct_lit(receiver) } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ee4b1d1354300..cbd7cb3ee8c6f 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -851,7 +851,7 @@ macro_rules! common_visitor_and_walkers { visit_visitable!($($mut)? vis, impl_), ItemKind::Trait(trait_) => visit_visitable!($($mut)? vis, trait_), - ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds}) => { + ItemKind::TraitAlias(TraitAlias { constness, ident, generics, bounds}) => { visit_visitable!($($mut)? vis, constness, ident, generics); visit_visitable_with!($($mut)? vis, bounds, BoundKind::Bound) } @@ -949,7 +949,7 @@ macro_rules! common_visitor_and_walkers { impl_walkable!(|&$($mut)? $($lt)? self: Impl, vis: &mut V| { let Impl { generics, of_trait, self_ty, items, constness: _ } = self; try_visit!(vis.visit_generics(generics)); - if let Some(box of_trait) = of_trait { + if let Some(of_trait) = of_trait { let TraitImplHeader { defaultness, safety, polarity, trait_ref } = of_trait; visit_visitable!($($mut)? vis, defaultness, safety, polarity, trait_ref); } @@ -1004,7 +1004,7 @@ macro_rules! common_visitor_and_walkers { visit_visitable!($($mut)? vis, block, opt_label, span), ExprKind::Match(subexpression, arms, kind) => visit_visitable!($($mut)? vis, subexpression, arms, kind), - ExprKind::Closure(box Closure { + ExprKind::Closure(Closure { binder, capture_clause, coroutine_kind, From f7817c236088deb2542e1a1db52767ca9d97e655 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 5 May 2026 13:25:58 +0000 Subject: [PATCH 14/28] use `deref_patterns` in `rustc_ast_lowering` --- compiler/rustc_ast_lowering/src/delegation.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 4 +- compiler/rustc_ast_lowering/src/item.rs | 58 +++++++------------ compiler/rustc_ast_lowering/src/lib.rs | 2 +- 4 files changed, 26 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index d390934f3b172..adde518af0f41 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -626,7 +626,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let callee_path = this.arena.alloc(this.mk_expr(hir::ExprKind::Path(path), span)); - let args = if let Some(box block) = delegation.body.as_ref() { + let args = if let Some(block) = delegation.body.as_ref() { this.arena.alloc_slice(&[this.lower_target_expr(block)]) } else { &mut [] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index d017c29a22f7f..eaa22e071af4b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -118,7 +118,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Call(f, self.lower_exprs(args)) } } - ExprKind::MethodCall(box MethodCall { seg, receiver, args, span }) => { + ExprKind::MethodCall(MethodCall { seg, receiver, args, span }) => { let hir_seg = self.arena.alloc(self.lower_path_segment( e.span, seg, @@ -212,7 +212,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr), - ExprKind::Closure(box Closure { + ExprKind::Closure(Closure { binder, capture_clause, constness, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3e0bc072a8d04..249f8e579eee9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -211,14 +211,12 @@ impl<'hir> LoweringContext<'_, 'hir> { i: &ItemKind, ) -> Vec { match i { - ItemKind::Fn(box Fn { eii_impls, .. }) - | ItemKind::Static(box StaticItem { eii_impls, .. }) + ItemKind::Fn(Fn { eii_impls, .. }) | ItemKind::Static(StaticItem { eii_impls, .. }) if eii_impls.is_empty() => { Vec::new() } - ItemKind::Fn(box Fn { eii_impls, .. }) - | ItemKind::Static(box StaticItem { eii_impls, .. }) => { + ItemKind::Fn(Fn { eii_impls, .. }) | ItemKind::Static(StaticItem { eii_impls, .. }) => { vec![hir::Attribute::Parsed(AttributeKind::EiiImpls( eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(), ))] @@ -298,7 +296,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs) } - ItemKind::Static(box ast::StaticItem { + ItemKind::Static(ast::StaticItem { ident, ty, safety: _, @@ -314,7 +312,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(*m, ident, ty, body_id) } - ItemKind::Const(box ConstItem { + ItemKind::Const(ConstItem { defaultness: _, ident, generics, @@ -352,7 +350,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.record_body(&[], body) }), ), - ItemKind::Fn(box Fn { + ItemKind::Fn(Fn { sig: FnSig { decl, header, span: fn_sig_span }, ident, generics, @@ -419,7 +417,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm)))); hir::ItemKind::GlobalAsm { asm, fake_body } } - ItemKind::TyAlias(box TyAlias { ident, generics, after_where_clause, ty, .. }) => { + ItemKind::TyAlias(TyAlias { ident, generics, after_where_clause, ty, .. }) => { // We lower // // type Foo = impl Trait @@ -539,7 +537,7 @@ impl<'hir> LoweringContext<'_, 'hir> { constness, }) } - ItemKind::Trait(box Trait { + ItemKind::Trait(Trait { impl_restriction, constness, is_auto, @@ -580,7 +578,7 @@ impl<'hir> LoweringContext<'_, 'hir> { items, } } - ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds }) => { + ItemKind::TraitAlias(TraitAlias { constness, ident, generics, bounds }) => { let constness = self.lower_constness(*constness); let ident = self.lower_ident(*ident); let (generics, bounds) = self.lower_generics( @@ -615,7 +613,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }); hir::ItemKind::Macro(ident, macro_def, macro_kinds) } - ItemKind::Delegation(box delegation) => { + ItemKind::Delegation(delegation) => { let delegation_results = self.lower_delegation(delegation, id); hir::ItemKind::Fn { sig: delegation_results.sig, @@ -794,7 +792,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind)); let (ident, kind) = match &i.kind { - ForeignItemKind::Fn(box Fn { sig, ident, generics, define_opaque, .. }) => { + ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (decl, fn_args)) = @@ -822,7 +820,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), ) } - ForeignItemKind::Static(box StaticItem { + ForeignItemKind::Static(StaticItem { ident, ty, mutability, @@ -839,9 +837,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } (ident, hir::ForeignItemKind::Static(ty, *mutability, safety)) } - ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => { - (ident, hir::ForeignItemKind::Type) - } + ForeignItemKind::TyAlias(TyAlias { ident, .. }) => (ident, hir::ForeignItemKind::Type), ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), }; @@ -980,7 +976,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let trait_item_def_id = hir_id.expect_owner(); let (ident, generics, kind, has_value) = match &i.kind { - AssocItemKind::Const(box ConstItem { + AssocItemKind::Const(ConstItem { ident, generics, ty, @@ -1020,9 +1016,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (*ident, generics, kind, rhs_kind.has_expr()) } - AssocItemKind::Fn(box Fn { - sig, ident, generics, body: None, define_opaque, .. - }) => { + AssocItemKind::Fn(Fn { sig, ident, generics, body: None, define_opaque, .. }) => { // FIXME(contracts): Deny contract here since it won't apply to // any impl method or callees. let idents = self.lower_fn_params_to_idents(&sig.decl); @@ -1047,7 +1041,7 @@ impl<'hir> LoweringContext<'_, 'hir> { false, ) } - AssocItemKind::Fn(box Fn { + AssocItemKind::Fn(Fn { sig, ident, generics, @@ -1082,7 +1076,7 @@ impl<'hir> LoweringContext<'_, 'hir> { true, ) } - AssocItemKind::Type(box TyAlias { + AssocItemKind::Type(TyAlias { ident, generics, after_where_clause, @@ -1115,7 +1109,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); (*ident, generics, kind, ty.is_some()) } - AssocItemKind::Delegation(box delegation) => { + AssocItemKind::Delegation(delegation) => { let delegation_results = self.lower_delegation(delegation, i.id); let item_kind = hir::TraitItemKind::Fn( delegation_results.sig, @@ -1216,7 +1210,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let (ident, (generics, kind)) = match &i.kind { - AssocItemKind::Const(box ConstItem { + AssocItemKind::Const(ConstItem { ident, generics, ty, @@ -1240,14 +1234,8 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ), ), - AssocItemKind::Fn(box Fn { - sig, - ident, - generics, - body, - contract, - define_opaque, - .. + AssocItemKind::Fn(Fn { + sig, ident, generics, body, contract, define_opaque, .. }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, @@ -1271,9 +1259,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (*ident, (generics, hir::ImplItemKind::Fn(sig, body_id))) } - AssocItemKind::Type(box TyAlias { - ident, generics, after_where_clause, ty, .. - }) => { + AssocItemKind::Type(TyAlias { ident, generics, after_where_clause, ty, .. }) => { let mut generics = generics.clone(); add_ty_alias_where_clause(&mut generics, after_where_clause, false); ( @@ -1307,7 +1293,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), ) } - AssocItemKind::Delegation(box delegation) => { + AssocItemKind::Delegation(delegation) => { let delegation_results = self.lower_delegation(delegation, i.id); ( delegation.ident, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 75dab290d6031..fc88dfae15187 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -31,7 +31,7 @@ //! in the HIR, especially for multiple identifiers. // tidy-alphabetical-start -#![feature(box_patterns)] +#![feature(deref_patterns)] #![recursion_limit = "256"] // tidy-alphabetical-end From 46fac37e1b5548d538a845495114736ab28f694d Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 5 May 2026 13:26:07 +0000 Subject: [PATCH 15/28] use `deref_patterns` in `rustc_ast_pretty` --- compiler/rustc_ast_pretty/src/lib.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/expr.rs | 4 ++-- .../rustc_ast_pretty/src/pprust/state/item.rs | 20 +++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index bfc1d387b7009..694e2229830fe 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,5 +1,5 @@ // tidy-alphabetical-start -#![feature(box_patterns)] +#![feature(deref_patterns)] #![feature(negative_impls)] // tidy-alphabetical-end diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 701152e9f9529..a20ef210da973 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -464,7 +464,7 @@ impl<'a> State<'a> { ast::ExprKind::Call(func, args) => { self.print_expr_call(func, args, fixup); } - ast::ExprKind::MethodCall(box ast::MethodCall { seg, receiver, args, .. }) => { + ast::ExprKind::MethodCall(ast::MethodCall { seg, receiver, args, .. }) => { self.print_expr_method_call(seg, receiver, args, fixup); } ast::ExprKind::Binary(op, lhs, rhs) => { @@ -582,7 +582,7 @@ impl<'a> State<'a> { let empty = attrs.is_empty() && arms.is_empty(); self.bclose(expr.span, empty, cb); } - ast::ExprKind::Closure(box ast::Closure { + ast::ExprKind::Closure(ast::Closure { binder, capture_clause, constness, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 5154e5dc005cd..b3a8f5d8cac30 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -36,7 +36,7 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(func) => { self.print_fn_full(vis, attrs, &*func); } - ast::ForeignItemKind::Static(box ast::StaticItem { + ast::ForeignItemKind::Static(ast::StaticItem { ident, ty, mutability, @@ -56,7 +56,7 @@ impl<'a> State<'a> { define_opaque.as_deref(), eii_impls, ), - ast::ForeignItemKind::TyAlias(box ast::TyAlias { + ast::ForeignItemKind::TyAlias(ast::TyAlias { defaultness, ident, generics, @@ -190,7 +190,7 @@ impl<'a> State<'a> { self.print_use_tree(tree); self.word(";"); } - ast::ItemKind::Static(box StaticItem { + ast::ItemKind::Static(StaticItem { ident, ty, safety, @@ -224,7 +224,7 @@ impl<'a> State<'a> { } self.end(ib); } - ast::ItemKind::Const(box ast::ConstItem { + ast::ItemKind::Const(ast::ConstItem { defaultness, ident, generics, @@ -296,7 +296,7 @@ impl<'a> State<'a> { self.end(ib); self.end(cb); } - ast::ItemKind::TyAlias(box ast::TyAlias { + ast::ItemKind::TyAlias(ast::TyAlias { defaultness, ident, generics, @@ -340,7 +340,7 @@ impl<'a> State<'a> { } }; - if let Some(box of_trait) = of_trait { + if let Some(of_trait) = of_trait { let ast::TraitImplHeader { defaultness, safety, polarity, ref trait_ref } = *of_trait; self.print_defaultness(defaultness); @@ -370,7 +370,7 @@ impl<'a> State<'a> { let empty = item.attrs.is_empty() && items.is_empty(); self.bclose(item.span, empty, cb); } - ast::ItemKind::Trait(box ast::Trait { + ast::ItemKind::Trait(ast::Trait { impl_restriction, constness, safety, @@ -403,7 +403,7 @@ impl<'a> State<'a> { let empty = item.attrs.is_empty() && items.is_empty(); self.bclose(item.span, empty, cb); } - ast::ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds }) => { + ast::ItemKind::TraitAlias(TraitAlias { constness, ident, generics, bounds }) => { let (cb, ib) = self.head(""); self.print_visibility(&item.vis); self.print_constness(*constness); @@ -596,7 +596,7 @@ impl<'a> State<'a> { ast::AssocItemKind::Fn(func) => { self.print_fn_full(vis, attrs, &*func); } - ast::AssocItemKind::Const(box ast::ConstItem { + ast::AssocItemKind::Const(ast::ConstItem { defaultness, ident, generics, @@ -617,7 +617,7 @@ impl<'a> State<'a> { &[], ); } - ast::AssocItemKind::Type(box ast::TyAlias { + ast::AssocItemKind::Type(ast::TyAlias { defaultness, ident, generics, From 0e72a29c934c2d2ece2990c32b9bdc161a7b5161 Mon Sep 17 00:00:00 2001 From: lapla Date: Tue, 5 May 2026 22:43:54 +0900 Subject: [PATCH 16/28] Always use `ConstFn` context for `const` closures --- compiler/rustc_middle/src/hir/map.rs | 6 ++---- .../const-traits/call-const-closure.next.stderr | 2 +- .../const-traits/call-const-closure.old.stderr | 2 +- tests/ui/traits/const-traits/call-const-closure.rs | 2 +- .../const-traits/const-closure-fn-ptr-const-item.rs | 11 +++++++++++ .../const-traits/const-closure-link-dead-code.rs | 12 ++++++++++++ 6 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 tests/ui/traits/const-traits/const-closure-fn-ptr-const-item.rs create mode 100644 tests/ui/traits/const-traits/const-closure-link-dead-code.rs diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 37273928d7d1f..bda9b3a47849e 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -317,11 +317,9 @@ impl<'tcx> TyCtxt<'tcx> { BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability), BodyOwnerKind::Fn if self.is_constructor(def_id) => return None, - // Const closures use their parent's const context - BodyOwnerKind::Closure if self.is_const_fn(def_id) => { - return self.hir_body_const_context(self.local_parent(local_def_id)); + BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.is_const_fn(def_id) => { + ConstContext::ConstFn } - BodyOwnerKind::Fn if self.is_const_fn(def_id) => ConstContext::ConstFn, BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None, }; diff --git a/tests/ui/traits/const-traits/call-const-closure.next.stderr b/tests/ui/traits/const-traits/call-const-closure.next.stderr index 16b936d58aaf6..9a851a97f186a 100644 --- a/tests/ui/traits/const-traits/call-const-closure.next.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.next.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `(): const Bar` is not satisfied +error[E0277]: the trait bound `(): [const] Bar` is not satisfied --> $DIR/call-const-closure.rs:16:18 | LL | (const || ().foo())(); diff --git a/tests/ui/traits/const-traits/call-const-closure.old.stderr b/tests/ui/traits/const-traits/call-const-closure.old.stderr index 16b936d58aaf6..9a851a97f186a 100644 --- a/tests/ui/traits/const-traits/call-const-closure.old.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.old.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `(): const Bar` is not satisfied +error[E0277]: the trait bound `(): [const] Bar` is not satisfied --> $DIR/call-const-closure.rs:16:18 | LL | (const || ().foo())(); diff --git a/tests/ui/traits/const-traits/call-const-closure.rs b/tests/ui/traits/const-traits/call-const-closure.rs index 2cf561ae6db14..5a5369a075358 100644 --- a/tests/ui/traits/const-traits/call-const-closure.rs +++ b/tests/ui/traits/const-traits/call-const-closure.rs @@ -14,7 +14,7 @@ impl Bar for () { const FOO: () = { (const || ().foo())(); - //~^ ERROR the trait bound `(): const Bar` is not satisfied + //~^ ERROR the trait bound `(): [const] Bar` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/const-closure-fn-ptr-const-item.rs b/tests/ui/traits/const-traits/const-closure-fn-ptr-const-item.rs new file mode 100644 index 0000000000000..1c24112883708 --- /dev/null +++ b/tests/ui/traits/const-traits/const-closure-fn-ptr-const-item.rs @@ -0,0 +1,11 @@ +//@ run-pass + +// Regression test for https://github.com/rust-lang/rust/issues/155803 + +#![feature(const_closures, const_trait_impl)] + +const F: fn() -> i32 = const || 42; + +fn main() { + assert_eq!(F(), 42); +} diff --git a/tests/ui/traits/const-traits/const-closure-link-dead-code.rs b/tests/ui/traits/const-traits/const-closure-link-dead-code.rs new file mode 100644 index 0000000000000..b28234c355eec --- /dev/null +++ b/tests/ui/traits/const-traits/const-closure-link-dead-code.rs @@ -0,0 +1,12 @@ +//@ build-pass +//@ compile-flags: -Clink-dead-code=true + +// Regression test for https://github.com/rust-lang/rust/issues/155803 + +#![feature(const_closures, const_trait_impl)] + +const _: () = { + assert!((const || true)()); +}; + +fn main() {} From 6a1953465be958adbbda3b1923bbe52f34e8451b Mon Sep 17 00:00:00 2001 From: paradoxicalguy Date: Tue, 5 May 2026 11:03:59 +0000 Subject: [PATCH 17/28] fix: remap ci-llvm debug paths via `-fdebug-prefix-map` ci-llvm include paths were leaking into debuginfo of `librustc_driver` via C/C++ compilation in rustc_llvm, causing non-determinism across stage2 builds. extend debug path remapping to the C/C++ build in rustc_llvm by converting RUSTC_DEBUGINFO_MAP into corresponding -fdebug-prefix-map flags and passing them through cc::Build. --- compiler/rustc_llvm/build.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 38c16fb1cd6d5..2d248c6991a52 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -273,6 +273,15 @@ fn main() { cfg.flag(&*flag); } + // Remap ci-llvm include paths in debug info for reproducible builds. + if let Some(maps) = tracked_env_var_os("RUSTC_DEBUGINFO_MAP") + && let Some(maps_str) = maps.to_str() + { + for map in maps_str.split('\t') { + cfg.flag(&format!("-fdebug-prefix-map={map}")); + } + } + for component in &components { let mut flag = String::from("LLVM_COMPONENT_"); flag.push_str(&component.to_uppercase()); From 412090247cab2ce7c40f99d194f04d72c7315b3c Mon Sep 17 00:00:00 2001 From: Devon Loehr Date: Tue, 5 May 2026 14:14:24 +0000 Subject: [PATCH 18/28] Narrow definitions --- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 643e4944bf784..f9276cdfa1321 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -93,11 +93,11 @@ extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, TargetMachine *Target = unwrap(TM); #if LLVM_VERSION_GE(23, 0) const MCSubtargetInfo &MCInfo = Target->getMCSubtargetInfo(); - return MCInfo.checkFeatures(std::string("+") + Feature); #else - const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); - return MCInfo->checkFeatures(std::string("+") + Feature); + const MCSubtargetInfo &MCInfo = *Target->getMCSubtargetInfo(); #endif + return MCInfo.checkFeatures(std::string("+") + Feature); + } /// Check whether the target has a specific assembly mnemonic like `ret` or @@ -297,13 +297,11 @@ extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) { const TargetMachine *Target = unwrap(TM); #if LLVM_VERSION_GE(23, 0) const MCSubtargetInfo &MCInfo = Target->getMCSubtargetInfo(); - const ArrayRef FeatTable = - MCInfo.getAllProcessorFeatures(); #else - const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); - const ArrayRef FeatTable = - MCInfo->getAllProcessorFeatures(); + const MCSubtargetInfo &MCInfo = *Target->getMCSubtargetInfo(); #endif + const ArrayRef FeatTable = + MCInfo.getAllProcessorFeatures(); return FeatTable.size(); } @@ -313,13 +311,11 @@ extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index, const TargetMachine *Target = unwrap(TM); #if LLVM_VERSION_GE(23, 0) const MCSubtargetInfo &MCInfo = Target->getMCSubtargetInfo(); - const ArrayRef FeatTable = - MCInfo.getAllProcessorFeatures(); #else - const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); - const ArrayRef FeatTable = - MCInfo->getAllProcessorFeatures(); + const MCSubtargetInfo &MCInfo = *Target->getMCSubtargetInfo(); #endif + const ArrayRef FeatTable = + MCInfo.getAllProcessorFeatures(); const SubtargetFeatureKV Feat = FeatTable[Index]; *Feature = Feat.Key; *Desc = Feat.Desc; From 7f697083d697158ab1551b8d745910105e4afaaa Mon Sep 17 00:00:00 2001 From: Devon Loehr Date: Tue, 5 May 2026 14:34:16 +0000 Subject: [PATCH 19/28] Fix formatting --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index f9276cdfa1321..b03a07538ccd8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -97,7 +97,6 @@ extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, const MCSubtargetInfo &MCInfo = *Target->getMCSubtargetInfo(); #endif return MCInfo.checkFeatures(std::string("+") + Feature); - } /// Check whether the target has a specific assembly mnemonic like `ret` or From 3c45cc96e6388241903ccf64568c142b235ffbd6 Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Tue, 5 May 2026 15:36:17 +0100 Subject: [PATCH 20/28] move codegen tests into its folder --- .../arm-collect-into-vec-codegen-regression.rs} | 0 .../issue-36856.rs => codegen/bool-negation-with-debug-info.rs} | 0 .../codegen-binder-not-ignored-in-generic-fn.rs} | 0 .../no-codegen-blowup-in-deeply-nested-struct.rs} | 0 .../issue-50761.rs => codegen/no-divide-by-zero-in-llvm-type.rs} | 0 .../no-segfault-with-multiple-codegen-units.rs} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-34427.rs => codegen/arm-collect-into-vec-codegen-regression.rs} (100%) rename tests/ui/{issues/issue-36856.rs => codegen/bool-negation-with-debug-info.rs} (100%) rename tests/ui/{issues/issue-20644.rs => codegen/codegen-binder-not-ignored-in-generic-fn.rs} (100%) rename tests/ui/{issues/issue-41696.rs => codegen/no-codegen-blowup-in-deeply-nested-struct.rs} (100%) rename tests/ui/{issues/issue-50761.rs => codegen/no-divide-by-zero-in-llvm-type.rs} (100%) rename tests/ui/{issues/issue-47364.rs => codegen/no-segfault-with-multiple-codegen-units.rs} (100%) diff --git a/tests/ui/issues/issue-34427.rs b/tests/ui/codegen/arm-collect-into-vec-codegen-regression.rs similarity index 100% rename from tests/ui/issues/issue-34427.rs rename to tests/ui/codegen/arm-collect-into-vec-codegen-regression.rs diff --git a/tests/ui/issues/issue-36856.rs b/tests/ui/codegen/bool-negation-with-debug-info.rs similarity index 100% rename from tests/ui/issues/issue-36856.rs rename to tests/ui/codegen/bool-negation-with-debug-info.rs diff --git a/tests/ui/issues/issue-20644.rs b/tests/ui/codegen/codegen-binder-not-ignored-in-generic-fn.rs similarity index 100% rename from tests/ui/issues/issue-20644.rs rename to tests/ui/codegen/codegen-binder-not-ignored-in-generic-fn.rs diff --git a/tests/ui/issues/issue-41696.rs b/tests/ui/codegen/no-codegen-blowup-in-deeply-nested-struct.rs similarity index 100% rename from tests/ui/issues/issue-41696.rs rename to tests/ui/codegen/no-codegen-blowup-in-deeply-nested-struct.rs diff --git a/tests/ui/issues/issue-50761.rs b/tests/ui/codegen/no-divide-by-zero-in-llvm-type.rs similarity index 100% rename from tests/ui/issues/issue-50761.rs rename to tests/ui/codegen/no-divide-by-zero-in-llvm-type.rs diff --git a/tests/ui/issues/issue-47364.rs b/tests/ui/codegen/no-segfault-with-multiple-codegen-units.rs similarity index 100% rename from tests/ui/issues/issue-47364.rs rename to tests/ui/codegen/no-segfault-with-multiple-codegen-units.rs From 769c3a9a12a3a1f46f27e2517fc0f5fc4b6525fa Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Tue, 5 May 2026 16:01:33 +0100 Subject: [PATCH 21/28] add issue links and bless --- tests/ui/codegen/arm-collect-into-vec-codegen-regression.rs | 2 +- tests/ui/codegen/bool-negation-with-debug-info.rs | 2 +- tests/ui/codegen/codegen-binder-not-ignored-in-generic-fn.rs | 2 ++ tests/ui/codegen/no-codegen-blowup-in-deeply-nested-struct.rs | 2 ++ tests/ui/codegen/no-divide-by-zero-in-llvm-type.rs | 1 + tests/ui/codegen/no-segfault-with-multiple-codegen-units.rs | 2 ++ 6 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/ui/codegen/arm-collect-into-vec-codegen-regression.rs b/tests/ui/codegen/arm-collect-into-vec-codegen-regression.rs index 519e839ad5f41..e739dbf803429 100644 --- a/tests/ui/codegen/arm-collect-into-vec-codegen-regression.rs +++ b/tests/ui/codegen/arm-collect-into-vec-codegen-regression.rs @@ -1,5 +1,5 @@ //@ run-pass -// Issue #34427: On ARM, the code in `foo` at one time was generating +// Issue https://github.com/rust-lang/rust/issues/34427: On ARM, the code in `foo` at one time was generating // a machine code instruction of the form: `str r0, [r0, rN]!` (for // some N), which is not legal because the source register and base // register cannot be identical in the preindexed form signalled by diff --git a/tests/ui/codegen/bool-negation-with-debug-info.rs b/tests/ui/codegen/bool-negation-with-debug-info.rs index afeba012fa0d6..6c79da1ddf895 100644 --- a/tests/ui/codegen/bool-negation-with-debug-info.rs +++ b/tests/ui/codegen/bool-negation-with-debug-info.rs @@ -1,5 +1,5 @@ //@ run-pass -// Regression test for #36856. +// Regression test for https://github.com/rust-lang/rust/issues/36856 //@ compile-flags:-g diff --git a/tests/ui/codegen/codegen-binder-not-ignored-in-generic-fn.rs b/tests/ui/codegen/codegen-binder-not-ignored-in-generic-fn.rs index 09a2ee7217c3a..747217a18f283 100644 --- a/tests/ui/codegen/codegen-binder-not-ignored-in-generic-fn.rs +++ b/tests/ui/codegen/codegen-binder-not-ignored-in-generic-fn.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/20644 + //@ build-pass #![allow(dead_code)] #![allow(unused_imports)] diff --git a/tests/ui/codegen/no-codegen-blowup-in-deeply-nested-struct.rs b/tests/ui/codegen/no-codegen-blowup-in-deeply-nested-struct.rs index 0b01efe7a7b13..dcca59ef0229f 100644 --- a/tests/ui/codegen/no-codegen-blowup-in-deeply-nested-struct.rs +++ b/tests/ui/codegen/no-codegen-blowup-in-deeply-nested-struct.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/41696 + //@ run-pass #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/codegen/no-divide-by-zero-in-llvm-type.rs b/tests/ui/codegen/no-divide-by-zero-in-llvm-type.rs index 8f5a32e0a001d..99bbaddf3c723 100644 --- a/tests/ui/codegen/no-divide-by-zero-in-llvm-type.rs +++ b/tests/ui/codegen/no-divide-by-zero-in-llvm-type.rs @@ -1,3 +1,4 @@ +// Regression test for https://github.com/rust-lang/rust/issues/50761 // Confirm that we don't accidentally divide or mod by zero in llvm_type //@ build-pass diff --git a/tests/ui/codegen/no-segfault-with-multiple-codegen-units.rs b/tests/ui/codegen/no-segfault-with-multiple-codegen-units.rs index 79cd5ed92a883..a8f723158a13a 100644 --- a/tests/ui/codegen/no-segfault-with-multiple-codegen-units.rs +++ b/tests/ui/codegen/no-segfault-with-multiple-codegen-units.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/47364 + //@ run-pass #![allow(unused_variables)] //@ compile-flags: -C codegen-units=8 -O From 6865172e8c83dbad9d6795499a71ad0d832eaf3e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 May 2026 16:28:16 +0200 Subject: [PATCH 22/28] Use `all_impls` instead of handrolling it --- .../src/error_reporting/traits/suggestions.rs | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) 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 148f1471b1b66..b442faad70ef4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3642,27 +3642,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { already implement it", with_no_trimmed_paths!(tcx.def_path_str(def_id)), )); - let impls_of = tcx.trait_impls_of(def_id); - let impls = impls_of - .non_blanket_impls() - .values() - .flatten() - .chain(impls_of.blanket_impls().iter()) + let mut types = tcx + .all_impls(def_id) + .map(|t| { + with_no_trimmed_paths!(format!( + " {}", + tcx.type_of(t).instantiate_identity().skip_norm_wip(), + )) + }) .collect::>(); - if !impls.is_empty() { - let len = impls.len(); - let mut types = impls - .iter() - .map(|&&t| { - with_no_trimmed_paths!(format!( - " {}", - tcx.type_of(t) - .instantiate_identity() - .skip_norm_wip(), - )) - }) - .collect::>(); - let post = if types.len() > 9 { + if !types.is_empty() { + let len = types.len(); + let post = if len > 9 { types.truncate(8); format!("\nand {} others", len - 8) } else { From cb2c5fc540d7f7facb0f41fcda5fba0b6dd01e48 Mon Sep 17 00:00:00 2001 From: khyperia <953151+khyperia@users.noreply.github.com> Date: Tue, 5 May 2026 17:35:17 +0200 Subject: [PATCH 23/28] generic_const_args: allow paths to non type consts --- compiler/rustc_ast_passes/src/feature_gate.rs | 23 +++++++ .../src/hir_ty_lowering/mod.rs | 9 ++- compiler/rustc_middle/src/ty/context.rs | 4 ++ .../src/ty/context/impl_interner.rs | 3 + .../src/solve/eval_ctxt/mod.rs | 38 ++++++++++++ .../src/solve/normalizes_to/anon_const.rs | 16 +---- .../src/solve/normalizes_to/free_alias.rs | 21 ++++--- .../src/solve/normalizes_to/inherent.rs | 24 +++++--- .../src/solve/normalizes_to/mod.rs | 25 +++++--- .../rustc_trait_selection/src/traits/mod.rs | 5 +- .../rustc_trait_selection/src/traits/wf.rs | 2 +- compiler/rustc_type_ir/src/inherent.rs | 2 + compiler/rustc_type_ir/src/interner.rs | 1 + compiler/rustc_type_ir/src/predicate.rs | 22 ++++++- .../rustc-dev-guide/src/feature-gate-check.md | 2 + .../language-features/generic-const-args.md | 3 +- ...-on-failed-eval-with-vars-fail.next.stderr | 48 +++++++++++++++ ...s-on-failed-eval-with-vars-fail.old.stderr | 10 +++ ...ambiguous-on-failed-eval-with-vars-fail.rs | 61 +++++++++++++++++++ .../gca/ambiguous-on-failed-eval-with-vars.rs | 43 +++++++++++++ .../gca/basic-different-definitions.rs | 1 + tests/ui/const-generics/gca/basic.rs | 1 + tests/ui/const-generics/gca/coherence-fail.rs | 1 + .../const-generics/gca/coherence-fail.stderr | 6 +- tests/ui/const-generics/gca/coherence-ok.rs | 1 + .../const-generics/gca/generic-free-const.rs | 19 ++++++ .../const-generics/gca/generic-param-rhs.rs | 1 + .../gca/generic-param-rhs.stderr | 2 +- .../gca/non-type-equality-fail.rs | 44 +++++++++++++ .../gca/non-type-equality-fail.stderr | 25 ++++++++ .../gca/non-type-equality-ok.rs | 47 ++++++++++++++ .../gca/path-to-non-type-const.rs | 35 +++++++++++ ...h-to-non-type-inherent-associated-const.rs | 28 +++++++++ ...-non-type-inherent-associated-const.stderr | 24 ++++++++ .../const-generics/gca/require-next-solver.rs | 4 ++ .../gca/require-next-solver.stderr | 10 +++ .../ui/const-generics/gca/rhs-but-not-root.rs | 1 + .../gca/rhs-but-not-root.stderr | 2 +- 38 files changed, 568 insertions(+), 46 deletions(-) create mode 100644 tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr create mode 100644 tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr create mode 100644 tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs create mode 100644 tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars.rs create mode 100644 tests/ui/const-generics/gca/generic-free-const.rs create mode 100644 tests/ui/const-generics/gca/non-type-equality-fail.rs create mode 100644 tests/ui/const-generics/gca/non-type-equality-fail.stderr create mode 100644 tests/ui/const-generics/gca/non-type-equality-ok.rs create mode 100644 tests/ui/const-generics/gca/path-to-non-type-const.rs create mode 100644 tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs create mode 100644 tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.stderr create mode 100644 tests/ui/const-generics/gca/require-next-solver.rs create mode 100644 tests/ui/const-generics/gca/require-next-solver.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2b08906a77434..aa91f78fbb35d 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -464,6 +464,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { check_incompatible_features(sess, features); check_dependent_features(sess, features); check_new_solver_banned_features(sess, features); + check_features_requiring_new_solver(sess, features); let mut visitor = PostExpansionVisitor { sess, features }; @@ -739,3 +740,25 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) { }); } } + +fn check_features_requiring_new_solver(sess: &Session, features: &Features) { + if sess.opts.unstable_opts.next_solver.globally { + return; + } + + // Require the new solver with GCA, because the old solver can't implement GCA correctly as it + // does not support normalization obligations for free and inherent consts. + if let Some(gca_span) = features + .enabled_lang_features() + .iter() + .find(|feat| feat.gate_name == sym::generic_const_args) + .map(|feat| feat.attr_sp) + { + #[allow(rustc::symbol_intern_string_literal)] + sess.dcx().emit_err(errors::MissingDependentFeatures { + parent_span: gca_span, + parent: sym::generic_const_args, + missing: String::from("-Znext-solver=globally"), + }); + } +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 473a32bac03a9..5a86e8186a5aa 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -3064,7 +3064,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); - if tcx.is_type_const(def_id) { + // FIXME(gca): Intentionally disallowing paths to inherent associated non-type constants + // until a refactoring for how generic args for IACs are represented has been landed. + let is_inherent_assoc_const = tcx.def_kind(def_id) + == DefKind::AssocConst { is_type_const: false } + && tcx.def_kind(tcx.parent(def_id)) == DefKind::Impl { of_trait: false }; + if tcx.is_type_const(def_id) + || tcx.features().generic_const_args() && !is_inherent_assoc_const + { Ok(()) } else { let mut err = self.dcx().struct_span_err( diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c25f5b402eb0d..574df1a33977c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -106,6 +106,10 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu self.generic_const_exprs() } + fn generic_const_args(self) -> bool { + self.generic_const_args() + } + fn coroutine_clone(self) -> bool { self.coroutine_clone() } diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 6f6317d53d97b..bacddb6808290 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -172,6 +172,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of_opaque_hir_typeck(def_id) } + fn is_type_const(self, def_id: DefId) -> bool { + self.is_type_const(def_id) + } fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> { self.const_of_item(def_id) } 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 615cc9e8f81d2..a9d36e425195f 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 @@ -1196,6 +1196,44 @@ where self.delegate.evaluate_const(param_env, uv) } + pub(super) fn evaluate_const_and_instantiate_normalizes_to_term( + &mut self, + goal: Goal>, + uv: ty::UnevaluatedConst, + ) -> QueryResult { + match self.evaluate_const(goal.param_env, uv) { + Some(evaluated) => { + self.instantiate_normalizes_to_term(goal, evaluated.into()); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + None if self.cx().features().generic_const_args() => { + // HACK(khyperia): calling `resolve_vars_if_possible` here shouldn't be necessary, + // `try_evaluate_const` calls `resolve_vars_if_possible` already. However, we want + // to check `has_non_region_infer` against the type with vars resolved (i.e. check + // if there are vars we failed to resolve), so we need to call it again here. + // Perhaps we could split EvaluateConstErr::HasGenericsOrInfers into HasGenerics and + // HasInfers or something, make evaluate_const return that, and make this branch be + // based on that, rather than checking `has_non_region_infer`. + if self.resolve_vars_if_possible(uv).has_non_region_infer() { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } else { + // We do not instantiate to the `uv` passed in, but rather + // `goal.predicate.alias`. The `uv` passed in might correspond to the `impl` + // form of a constant (with generic arguments corresponding to the impl block), + // however, we want to structurally instantiate to the original, non-rebased, + // trait `Self` form of the constant (with generic arguments being the trait + // `Self` type). + self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + } + None => { + // Legacy behavior: always treat as ambiguous + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + } + } + pub(super) fn is_transmutable( &mut self, src: I::Ty, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index b3703639d99ef..72e8d1be5915e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -2,7 +2,7 @@ use rustc_type_ir::{self as ty, Interner}; use tracing::instrument; use crate::delegate::SolverDelegate; -use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult}; +use crate::solve::{EvalCtxt, Goal, QueryResult}; impl EvalCtxt<'_, D> where @@ -14,17 +14,7 @@ where &mut self, goal: Goal>, ) -> QueryResult { - if let Some(normalized_const) = self.evaluate_const( - goal.param_env, - ty::UnevaluatedConst::new( - goal.predicate.alias.def_id().try_into().unwrap(), - goal.predicate.alias.args, - ), - ) { - self.instantiate_normalizes_to_term(goal, normalized_const.into()); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } else { - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } + let uv = goal.predicate.alias.expect_ct(self.cx()); + self.evaluate_const_and_instantiate_normalizes_to_term(goal, uv) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index f3004e4c8105b..44fe2913b73de 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -30,13 +30,20 @@ where .map(|pred| goal.with(cx, pred)), ); - let actual = if free_alias.kind(cx).is_type() { - cx.type_of(free_alias.def_id()).instantiate(cx, free_alias.args).skip_norm_wip().into() - } else { - cx.const_of_item(free_alias.def_id()) - .instantiate(cx, free_alias.args) - .skip_norm_wip() - .into() + let actual = match free_alias.kind(cx) { + ty::AliasTermKind::FreeTy { def_id } => { + cx.type_of(def_id).instantiate(cx, free_alias.args).skip_norm_wip().into() + } + ty::AliasTermKind::FreeConst { def_id } if cx.is_type_const(def_id) => { + cx.const_of_item(def_id).instantiate(cx, free_alias.args).skip_norm_wip().into() + } + ty::AliasTermKind::FreeConst { .. } => { + return self.evaluate_const_and_instantiate_normalizes_to_term( + goal, + free_alias.expect_ct(cx), + ); + } + kind => panic!("expected free alias, found {kind:?}"), }; self.instantiate_normalizes_to_term(goal, actual); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 4d62407fe2995..00b5fd7fdcbce 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -52,13 +52,23 @@ where .map(|pred| goal.with(cx, pred)), ); - let normalized = if inherent.kind(cx).is_type() { - cx.type_of(inherent.def_id()).instantiate(cx, inherent_args).skip_norm_wip().into() - } else { - cx.const_of_item(inherent.def_id()) - .instantiate(cx, inherent_args) - .skip_norm_wip() - .into() + let normalized = match inherent.kind(cx) { + ty::AliasTermKind::InherentTy { def_id } => { + cx.type_of(def_id).instantiate(cx, inherent_args).skip_norm_wip().into() + } + ty::AliasTermKind::InherentConst { def_id } if cx.is_type_const(def_id) => { + cx.const_of_item(def_id).instantiate(cx, inherent_args).skip_norm_wip().into() + } + ty::AliasTermKind::InherentConst { .. } => { + // FIXME(gca): This is dead code at the moment. It should eventually call + // self.evaluate_const like projected consts do in consider_impl_candidate in + // normalizes_to/mod.rs. However, how generic args are represented for IACs is up in + // the air right now. + // Will self.evaluate_const eventually take the inherent_args or the impl_args form + // of args? It might be either. + panic!("References to inherent associated consts should have been blocked"); + } + kind => panic!("expected inherent alias, found {kind:?}"), }; self.instantiate_normalizes_to_term(goal, normalized); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index d93b7843b2251..688c7fb2c2370 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -383,19 +383,30 @@ where // Finally we construct the actual value of the associated type. let term = match goal.predicate.alias.kind(cx) { - ty::AliasTermKind::ProjectionTy { .. } => { - cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) + ty::AliasTermKind::ProjectionTy { .. } => cx + .type_of(target_item_def_id) + .instantiate(cx, target_args) + .skip_norm_wip() + .into(), + ty::AliasTermKind::ProjectionConst { .. } + if cx.is_type_const(target_item_def_id) => + { + cx.const_of_item(target_item_def_id) + .instantiate(cx, target_args) + .skip_norm_wip() + .into() } ty::AliasTermKind::ProjectionConst { .. } => { - cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into()) + let uv = ty::UnevaluatedConst::new( + target_item_def_id.try_into().unwrap(), + target_args, + ); + return ecx.evaluate_const_and_instantiate_normalizes_to_term(goal, uv); } kind => panic!("expected projection, found {kind:?}"), }; - ecx.instantiate_normalizes_to_term( - goal, - term.instantiate(cx, target_args).skip_norm_wip(), - ); + ecx.instantiate_normalizes_to_term(goal, term); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index e0eeca23c6d46..a834dbd1604f8 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -701,7 +701,10 @@ pub fn try_evaluate_const<'tcx>( // logic does not go through type system normalization. If it did this would // be a backwards compatibility problem as we do not enforce "syntactic" non- // usage of generic parameters like we do here. - if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { + if uv.args.has_non_region_param() + || uv.args.has_non_region_infer() + || uv.args.has_non_region_placeholders() + { return Err(EvaluateConstErr::HasGenericsOrInfers); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 51173500f4718..fdf32d32e9058 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1065,7 +1065,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { // Skip type consts as mGCA doesn't support evaluatable clauses - if !tcx.is_type_const(uv.def) { + if !tcx.is_type_const(uv.def) && !tcx.features().generic_const_args() { let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), )); diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 3539215072ad9..f63361f5968d2 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -629,6 +629,8 @@ pub trait ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable { pub trait Features: Copy { fn generic_const_exprs(self) -> bool; + fn generic_const_args(self) -> bool; + fn coroutine_clone(self) -> bool; fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index fba43b9cffbe2..03573012177d7 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -203,6 +203,7 @@ pub trait Interner: fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) -> ty::EarlyBinder; + fn is_type_const(self, def_id: Self::DefId) -> bool; fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder; fn anon_const_kind(self, def_id: Self::DefId) -> ty::AnonConstKind; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 90240e241bc90..7b815e61cf09e 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -726,16 +726,32 @@ impl AliasTerm { AliasTermKind::InherentTy { def_id } => AliasTyKind::Inherent { def_id }, AliasTermKind::OpaqueTy { def_id } => AliasTyKind::Opaque { def_id }, AliasTermKind::FreeTy { def_id } => AliasTyKind::Free { def_id }, - AliasTermKind::InherentConst { .. } + kind @ (AliasTermKind::InherentConst { .. } | AliasTermKind::FreeConst { .. } | AliasTermKind::UnevaluatedConst { .. } - | AliasTermKind::ProjectionConst { .. } => { - panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") + | AliasTermKind::ProjectionConst { .. }) => { + panic!("Cannot turn `{}` into `AliasTy`", kind.descr()) } }; ty::AliasTy { kind, args: self.args, _use_alias_ty_new_instead: () } } + pub fn expect_ct(self, interner: I) -> ty::UnevaluatedConst { + let def_id = match self.kind(interner) { + AliasTermKind::InherentConst { def_id } + | AliasTermKind::FreeConst { def_id } + | AliasTermKind::UnevaluatedConst { def_id } + | AliasTermKind::ProjectionConst { def_id } => def_id, + kind @ (AliasTermKind::ProjectionTy { .. } + | AliasTermKind::InherentTy { .. } + | AliasTermKind::OpaqueTy { .. } + | AliasTermKind::FreeTy { .. }) => { + panic!("Cannot turn `{}` into `UnevaluatedConst`", kind.descr()) + } + }; + ty::UnevaluatedConst { def: def_id.try_into().unwrap(), args: self.args } + } + // FIXME: remove this function (access the field instead) pub fn kind(self, _interner: I) -> AliasTermKind { self.kind diff --git a/src/doc/rustc-dev-guide/src/feature-gate-check.md b/src/doc/rustc-dev-guide/src/feature-gate-check.md index 038a14ac070e1..0b4fc0cd680c0 100644 --- a/src/doc/rustc-dev-guide/src/feature-gate-check.md +++ b/src/doc/rustc-dev-guide/src/feature-gate-check.md @@ -69,6 +69,8 @@ in `check_crate` and its AST visitor. (declared in `rustc_feature::INCOMPATIBLE_FEATURES`) are not used together. - `check_new_solver_banned_features`: Bans features incompatible with compiler mode for the next trait solver. +- `check_features_requiring_new_solver`: Requires the new trait solver for + features incompatible with the old solver. - **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing (see [Checking `GatedSpans`](#checking-gatedspans)). diff --git a/src/doc/unstable-book/src/language-features/generic-const-args.md b/src/doc/unstable-book/src/language-features/generic-const-args.md index b9870e60d0f91..c496c50bf0400 100644 --- a/src/doc/unstable-book/src/language-features/generic-const-args.md +++ b/src/doc/unstable-book/src/language-features/generic-const-args.md @@ -23,7 +23,8 @@ See also: [generic_const_items] ## Examples -```rust + +```rust,ignore (requires-Z-next-solver) #![feature(generic_const_items)] #![feature(min_generic_const_args)] #![feature(generic_const_args)] diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr new file mode 100644 index 0000000000000..f609dcab752af --- /dev/null +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr @@ -0,0 +1,48 @@ +error[E0284]: type annotations needed for `([(); _], [(); 10])` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:29:9 + | +LL | let (mut arr, mut arr_with_weird_len) = free(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ type must be known at this point + | +note: required by a const generic parameter in `free` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:24:9 + | +LL | fn free() -> ([(); N], [(); FREE::]) { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `free` +help: consider giving this pattern a type, where the value of const parameter `N` is specified + | +LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = free(); + | +++++++++++++ + +error[E0271]: type mismatch resolving `10 == 2` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:35:45 + | +LL | let (mut arr, mut arr_with_weird_len) = free(); + | ^^^^^^ types differ + +error[E0284]: type annotations needed for `([(); _], [(); 10])` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:46:9 + | +LL | let (mut arr, mut arr_with_weird_len) = proj(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ type must be known at this point + | +note: required by a const generic parameter in `proj` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:41:9 + | +LL | fn proj() -> ([(); N], [(); ::PROJ::]) { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `proj` +help: consider giving this pattern a type, where the value of const parameter `N` is specified + | +LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = proj(); + | +++++++++++++ + +error[E0271]: type mismatch resolving `10 == 2` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:52:45 + | +LL | let (mut arr, mut arr_with_weird_len) = proj(); + | ^^^^^^ types differ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0271, E0284. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr new file mode 100644 index 0000000000000..f27badafa2ca7 --- /dev/null +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr @@ -0,0 +1,10 @@ +error: `generic_const_args` requires -Znext-solver=globally to be enabled + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:9:12 + | +LL | #![feature(generic_const_args)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: enable all of these features + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs new file mode 100644 index 0000000000000..72952940b1c12 --- /dev/null +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs @@ -0,0 +1,61 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +// (`test_free_mismatch` is quite difficult to implement in the old solver, so make sure this test +// runs on the old solver, just in case someone attempts to implement GCA for the old solver and +// removes the restriction that -Znext-solver must be enabled) + +#![feature(generic_const_items)] +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +//[old]~^ ERROR next-solver +#![expect(incomplete_features)] + +const FREE: usize = 10; + +trait Trait { + const PROJ: usize; +} +struct S; + +impl Trait for S { + const PROJ: usize = 10; +} + +fn free() -> ([(); N], [(); FREE::]) { + loop {} +} + +fn test_free() { + let (mut arr, mut arr_with_weird_len) = free(); + //[next]~^ ERROR type annotations needed + arr_with_weird_len = [(); 10]; +} + +fn test_free_mismatch() { + let (mut arr, mut arr_with_weird_len) = free(); + //[next]~^ ERROR type mismatch resolving `10 == 2` + arr_with_weird_len = [(); 2]; + arr = [(); 10]; +} + +fn proj() -> ([(); N], [(); ::PROJ::]) { + loop {} +} + +fn test_proj() { + let (mut arr, mut arr_with_weird_len) = proj(); + //[next]~^ ERROR type annotations needed + arr_with_weird_len = [(); 10]; +} + +fn test_proj_mismatch() { + let (mut arr, mut arr_with_weird_len) = proj(); + //[next]~^ ERROR type mismatch resolving `10 == 2` + arr_with_weird_len = [(); 2]; + arr = [(); 10]; +} + +fn main() { + test_free(); + test_proj(); +} diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars.rs b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars.rs new file mode 100644 index 0000000000000..4be1b036d6946 --- /dev/null +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars.rs @@ -0,0 +1,43 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +#![feature(generic_const_items)] +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![expect(incomplete_features)] + +const FREE: usize = 10; + +trait Trait { + const PROJ: usize; +} +struct S; + +impl Trait for S { + const PROJ: usize = 10; +} + +fn free() -> ([(); N], [(); FREE::]) { + loop {} +} + +fn test_free() { + let (mut arr, mut arr_with_weird_len) = free(); + arr_with_weird_len = [(); 10]; + arr = [(); 10]; +} + +fn proj() -> ([(); N], [(); ::PROJ::]) { + loop {} +} + +fn test_proj() { + let (mut arr, mut arr_with_weird_len) = proj(); + arr_with_weird_len = [(); 10]; + arr = [(); 10]; +} + +fn main() { + test_free(); + test_proj(); +} diff --git a/tests/ui/const-generics/gca/basic-different-definitions.rs b/tests/ui/const-generics/gca/basic-different-definitions.rs index d96c718617d24..ec26f26630a57 100644 --- a/tests/ui/const-generics/gca/basic-different-definitions.rs +++ b/tests/ui/const-generics/gca/basic-different-definitions.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ compile-flags: -Znext-solver #![feature(generic_const_items)] #![feature(min_generic_const_args)] diff --git a/tests/ui/const-generics/gca/basic.rs b/tests/ui/const-generics/gca/basic.rs index e80540d621de5..40c28c3d38c0e 100644 --- a/tests/ui/const-generics/gca/basic.rs +++ b/tests/ui/const-generics/gca/basic.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ compile-flags: -Znext-solver #![feature(generic_const_items)] #![feature(min_generic_const_args)] diff --git a/tests/ui/const-generics/gca/coherence-fail.rs b/tests/ui/const-generics/gca/coherence-fail.rs index 1b181d792d362..079c8cf63e144 100644 --- a/tests/ui/const-generics/gca/coherence-fail.rs +++ b/tests/ui/const-generics/gca/coherence-fail.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Znext-solver #![feature(generic_const_items, min_generic_const_args, generic_const_args)] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/gca/coherence-fail.stderr b/tests/ui/const-generics/gca/coherence-fail.stderr index e8122c1b832f1..d180654cc84a6 100644 --- a/tests/ui/const-generics/gca/coherence-fail.stderr +++ b/tests/ui/const-generics/gca/coherence-fail.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait1` for type `[(); 2]` - --> $DIR/coherence-fail.rs:9:1 + --> $DIR/coherence-fail.rs:10:1 | LL | impl Trait1 for [(); FOO::<1>] {} | ------------------------------ first implementation here @@ -7,7 +7,7 @@ LL | impl Trait1 for [(); BAR::<1>] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); 2]` error[E0119]: conflicting implementations of trait `Trait2` for type `[(); 1]` - --> $DIR/coherence-fail.rs:16:1 + --> $DIR/coherence-fail.rs:17:1 | LL | impl Trait2 for [(); DIV2::<2>] {} | ------------------------------- first implementation here @@ -15,7 +15,7 @@ LL | impl Trait2 for [(); DIV2::<3>] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); 1]` error[E0119]: conflicting implementations of trait `Trait3` for type `[(); 2]` - --> $DIR/coherence-fail.rs:25:1 + --> $DIR/coherence-fail.rs:26:1 | LL | impl Trait3 for [(); ADD1::<1>] {} | ------------------------------- first implementation here diff --git a/tests/ui/const-generics/gca/coherence-ok.rs b/tests/ui/const-generics/gca/coherence-ok.rs index 447f25bfdc36b..38899badf5f03 100644 --- a/tests/ui/const-generics/gca/coherence-ok.rs +++ b/tests/ui/const-generics/gca/coherence-ok.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ compile-flags: -Znext-solver #![feature(generic_const_items, min_generic_const_args, generic_const_args)] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/gca/generic-free-const.rs b/tests/ui/const-generics/gca/generic-free-const.rs new file mode 100644 index 0000000000000..e7816728d461e --- /dev/null +++ b/tests/ui/const-generics/gca/generic-free-const.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![feature(generic_const_items)] +#![expect(incomplete_features)] + +const ADD1: usize = N + 1; + +fn a() -> [usize; ADD1::] { + [ADD1::; ADD1::] +} + +fn main() { + let _: [(); ADD1::<1>] = [(); ADD1::<1>]; + let _: [(); ADD1::<{ ADD1::<1> }>] = [(); ADD1::<2>]; + a::<2>(); +} diff --git a/tests/ui/const-generics/gca/generic-param-rhs.rs b/tests/ui/const-generics/gca/generic-param-rhs.rs index ed4467d6f0039..ea6e2d7398b57 100644 --- a/tests/ui/const-generics/gca/generic-param-rhs.rs +++ b/tests/ui/const-generics/gca/generic-param-rhs.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Znext-solver #![feature(min_generic_const_args, generic_const_args)] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/gca/generic-param-rhs.stderr b/tests/ui/const-generics/gca/generic-param-rhs.stderr index acf3a5b21a855..ca0ce899b8b0d 100644 --- a/tests/ui/const-generics/gca/generic-param-rhs.stderr +++ b/tests/ui/const-generics/gca/generic-param-rhs.stderr @@ -1,5 +1,5 @@ error: generic parameters in const blocks are only allowed as the direct value of a `type const` - --> $DIR/generic-param-rhs.rs:6:19 + --> $DIR/generic-param-rhs.rs:7:19 | LL | foo::(); | ^ diff --git a/tests/ui/const-generics/gca/non-type-equality-fail.rs b/tests/ui/const-generics/gca/non-type-equality-fail.rs new file mode 100644 index 0000000000000..235ab37f8b570 --- /dev/null +++ b/tests/ui/const-generics/gca/non-type-equality-fail.rs @@ -0,0 +1,44 @@ +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + const PROJECTED_A: usize; + const PROJECTED_B: usize; +} + +struct StructImpl; +struct GenericStructImpl; + +impl Trait for StructImpl { + const PROJECTED_A: usize = 1; + const PROJECTED_B: usize = 1; +} + +impl Trait for GenericStructImpl { + const PROJECTED_A: usize = N; + const PROJECTED_B: usize = N; +} + +const FREE_A: usize = 1; +const FREE_B: usize = 1; + +struct Struct; + +fn f() { + let _: Struct<{ as Trait>::PROJECTED_A }> = + Struct::<{ as Trait>::PROJECTED_B }>; + //~^ ERROR mismatched types +} + +fn g() { + let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_B }>; + //~^ ERROR mismatched types +} + +fn main() { + f::<2>(); + g::(); +} diff --git a/tests/ui/const-generics/gca/non-type-equality-fail.stderr b/tests/ui/const-generics/gca/non-type-equality-fail.stderr new file mode 100644 index 0000000000000..796efdcea93cc --- /dev/null +++ b/tests/ui/const-generics/gca/non-type-equality-fail.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/non-type-equality-fail.rs:32:9 + | +LL | let _: Struct<{ as Trait>::PROJECTED_A }> = + | -------------------------------------------------------- expected due to this +LL | Struct::<{ as Trait>::PROJECTED_B }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: expected struct `Struct< as Trait>::PROJECTED_A>` + found struct `Struct< as Trait>::PROJECTED_B>` + +error[E0308]: mismatched types + --> $DIR/non-type-equality-fail.rs:37:41 + | +LL | let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_B }>; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | | + | expected due to this + | + = note: expected struct `Struct<::PROJECTED_A>` + found struct `Struct<::PROJECTED_B>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/gca/non-type-equality-ok.rs b/tests/ui/const-generics/gca/non-type-equality-ok.rs new file mode 100644 index 0000000000000..443fbc46bd8a0 --- /dev/null +++ b/tests/ui/const-generics/gca/non-type-equality-ok.rs @@ -0,0 +1,47 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![feature(generic_const_items)] +#![expect(incomplete_features)] + +trait Trait { + const PROJECTED_A: usize; + const PROJECTED_B: usize; +} + +struct StructImpl; +struct GenericStructImpl; + +impl Trait for StructImpl { + const PROJECTED_A: usize = 1; + const PROJECTED_B: usize = 1; +} + +impl Trait for GenericStructImpl { + const PROJECTED_A: usize = N; + const PROJECTED_B: usize = N; +} + +const FREE_A: usize = 1; +const FREE_B: usize = 1; + +struct Struct; + +fn f() { + let _: Struct<{ as Trait>::PROJECTED_A }> = + Struct::<{ as Trait>::PROJECTED_A }>; +} + +fn g() { + let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_A }>; +} + +fn main() { + let _: Struct = Struct::; + let _: Struct<{ ::PROJECTED_A }> = + Struct::<{ ::PROJECTED_B }>; + let _: Struct<{ as Trait>::PROJECTED_A }> = + Struct::<{ as Trait>::PROJECTED_B }>; +} diff --git a/tests/ui/const-generics/gca/path-to-non-type-const.rs b/tests/ui/const-generics/gca/path-to-non-type-const.rs new file mode 100644 index 0000000000000..c36dbbcc578fa --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-const.rs @@ -0,0 +1,35 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + const PROJECTED: usize; +} + +struct StructImpl; +struct GenericStructImpl; + +const FREE: usize = 1; + +impl Trait for StructImpl { + const PROJECTED: usize = 1; +} + +impl Trait for GenericStructImpl { + const PROJECTED: usize = A; +} + +struct Struct; + +fn f() { + let _ = Struct::<{ T::PROJECTED }>; +} + +fn main() { + let _ = Struct::; + let _ = Struct::<{ ::PROJECTED }>; + let _ = Struct::<{ as Trait>::PROJECTED }>; +} diff --git a/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs new file mode 100644 index 0000000000000..1b9164d4a2300 --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs @@ -0,0 +1,28 @@ +//! This test should be part of path-to-non-type-const.rs, and should pass. However, we are holding +//! off on implementing paths to IACs until a refactoring of how IAC generics are represented. +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +struct StructImpl; +struct GenericStructImpl; + +impl StructImpl { + const INHERENT: usize = 1; +} + +impl GenericStructImpl { + const INHERENT: usize = A; +} + +struct Struct; + +fn main() { + let _ = Struct::<{ StructImpl::INHERENT }>; + //~^ ERROR use of `const` in the type system not defined as `type const` + let _ = Struct::<{ GenericStructImpl::<2>::INHERENT }>; + //~^ ERROR use of `const` in the type system not defined as `type const` +} diff --git a/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.stderr b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.stderr new file mode 100644 index 0000000000000..b5da53f0f1c8e --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.stderr @@ -0,0 +1,24 @@ +error: use of `const` in the type system not defined as `type const` + --> $DIR/path-to-non-type-inherent-associated-const.rs:24:24 + | +LL | let _ = Struct::<{ StructImpl::INHERENT }>; + | ^^^^^^^^^^^^^^^^^^^^ + | +help: add `type` before `const` for `StructImpl::INHERENT` + | +LL | type const INHERENT: usize = 1; + | ++++ + +error: use of `const` in the type system not defined as `type const` + --> $DIR/path-to-non-type-inherent-associated-const.rs:26:24 + | +LL | let _ = Struct::<{ GenericStructImpl::<2>::INHERENT }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `type` before `const` for `GenericStructImpl::::INHERENT` + | +LL | type const INHERENT: usize = A; + | ++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/gca/require-next-solver.rs b/tests/ui/const-generics/gca/require-next-solver.rs new file mode 100644 index 0000000000000..ffe3141b0f28a --- /dev/null +++ b/tests/ui/const-generics/gca/require-next-solver.rs @@ -0,0 +1,4 @@ +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +//~^ ERROR next-solver +fn main() {} diff --git a/tests/ui/const-generics/gca/require-next-solver.stderr b/tests/ui/const-generics/gca/require-next-solver.stderr new file mode 100644 index 0000000000000..677c37610d842 --- /dev/null +++ b/tests/ui/const-generics/gca/require-next-solver.stderr @@ -0,0 +1,10 @@ +error: `generic_const_args` requires -Znext-solver=globally to be enabled + --> $DIR/require-next-solver.rs:2:12 + | +LL | #![feature(generic_const_args)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: enable all of these features + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/gca/rhs-but-not-root.rs b/tests/ui/const-generics/gca/rhs-but-not-root.rs index 6c0337dbbd470..61762a2851356 100644 --- a/tests/ui/const-generics/gca/rhs-but-not-root.rs +++ b/tests/ui/const-generics/gca/rhs-but-not-root.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Znext-solver #![feature(generic_const_items)] #![feature(min_generic_const_args)] #![feature(generic_const_args)] diff --git a/tests/ui/const-generics/gca/rhs-but-not-root.stderr b/tests/ui/const-generics/gca/rhs-but-not-root.stderr index 6481407eedc42..06f5ae248ac14 100644 --- a/tests/ui/const-generics/gca/rhs-but-not-root.stderr +++ b/tests/ui/const-generics/gca/rhs-but-not-root.stderr @@ -1,5 +1,5 @@ error: generic parameters in const blocks are only allowed as the direct value of a `type const` - --> $DIR/rhs-but-not-root.rs:7:54 + --> $DIR/rhs-but-not-root.rs:8:54 | LL | type const FOO: usize = ID::; | ^ From fc6b9c862636794917d502d5f19c37dfe26a8847 Mon Sep 17 00:00:00 2001 From: abhinav srivastav <136164196+paradoxicalguy@users.noreply.github.com> Date: Tue, 5 May 2026 22:13:25 +0530 Subject: [PATCH 24/28] updating flag with `flag_if_supported` Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com> --- compiler/rustc_llvm/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 2d248c6991a52..ed1b75bea29d9 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -278,7 +278,7 @@ fn main() { && let Some(maps_str) = maps.to_str() { for map in maps_str.split('\t') { - cfg.flag(&format!("-fdebug-prefix-map={map}")); + cfg.flag_if_supported(&format!("-ffile-prefix-map={map}")); } } From 5d832f1324dc9b76718e8edeb75018c04cc3df4a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 5 May 2026 12:02:28 -0700 Subject: [PATCH 25/28] Don't run ui-fulldeps tests twice in stage 1 This removes a separate call in the x86_64-gnu-llvm-21-3 job which runs the ui-fulldeps a second time. ui-fulldeps is already running in the first call (`../x.py --stage 1 test`) as it is a default test suite. This was added in https://github.com/rust-lang/rust/pull/116009, but I think that was a misunderstanding of the problem. The actual problem was fixed in https://github.com/rust-lang/rust/pull/116932 where the actual problem was the use of `&&`. This doesn't really have much of an impact on CI time (only a couple seconds) because all the tests are skipped with `ignored, up-to-date`. I'm mainly doing this to clean up the script itself for clarity. --- src/ci/docker/scripts/x86_64-gnu-llvm3.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm3.sh b/src/ci/docker/scripts/x86_64-gnu-llvm3.sh index 17eb2cea59ac1..6ea6082b4ea0e 100755 --- a/src/ci/docker/scripts/x86_64-gnu-llvm3.sh +++ b/src/ci/docker/scripts/x86_64-gnu-llvm3.sh @@ -14,10 +14,6 @@ set -ex # despite having different output on 32-bit vs 64-bit targets. ../x.py --stage 1 test tests/mir-opt --host='' --target=i686-unknown-linux-gnu -# Run `ui-fulldeps` in `--stage=1`, which actually uses the stage0 -# compiler, and is sensitive to the addition of new flags. -../x.py --stage 1 test tests/ui-fulldeps - # Rebuild the stdlib with the size optimizations enabled and run tests again. RUSTFLAGS_NOT_BOOTSTRAP="--cfg feature=\"optimize_for_size\"" ../x.py --stage 1 test \ library/std library/alloc library/core From 61743bf3b0ae0f9ea00c16ba742899739be2e55a Mon Sep 17 00:00:00 2001 From: Jaiden Magnan Date: Tue, 5 May 2026 16:19:41 -0400 Subject: [PATCH 26/28] fix: adding more verbose error message --- compiler/rustc_hir_typeck/src/cast.rs | 10 +++++++++- tests/ui/cast/cast-enum-to-int-issue-151116.rs | 4 ++-- tests/ui/cast/cast-enum-to-int-issue-151116.stderr | 7 ++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 77d45b46f1d7b..40315e8270e12 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -301,10 +301,18 @@ impl<'a, 'tcx> CastCheck<'tcx> { { err.span_suggestion_verbose( self.expr_span.shrink_to_lo(), - "dereference the expression", + "try dereferencing before the cast", "*", Applicability::MaybeIncorrect, ); + if !fcx.type_is_copy_modulo_regions(fcx.param_env, inner_ty) { + err.span_suggestion_verbose( + fcx.tcx.def_span(adt_def.did()).shrink_to_lo(), + "add `#[derive(Copy, Clone)]` to the enum definition", + "#[derive(Copy, Clone)]\n", + Applicability::MaybeIncorrect, + ); + } } else { err.help(format!( "cast through {} first", diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.rs b/tests/ui/cast/cast-enum-to-int-issue-151116.rs index d254b6400f2d4..25a85e10a83e5 100644 --- a/tests/ui/cast/cast-enum-to-int-issue-151116.rs +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.rs @@ -1,5 +1,5 @@ #[repr(u8)] -enum Priority { +enum Priority { //~ HELP: add `#[derive(Copy, Clone)]` to the enum definition High = 255, Normal = 127, Low = 1, @@ -8,7 +8,7 @@ enum Priority { fn main() { let priority = &Priority::Normal; let priority = priority as u8; //~ ERROR casting `&Priority` as `u8` is invalid - //~| HELP: dereference the expression + //~| HELP: try dereferencing before the cast let priority = &Priority::Normal as u8; //~ ERROR casting `&Priority` as `u8` is invalid //~| HELP: cast through a raw pointer first diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.stderr b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr index 63a4a0cb71881..7eb0d357fb0de 100644 --- a/tests/ui/cast/cast-enum-to-int-issue-151116.stderr +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr @@ -4,10 +4,15 @@ error[E0606]: casting `&Priority` as `u8` is invalid LL | let priority = priority as u8; | ^^^^^^^^^^^^^^ | -help: dereference the expression +help: try dereferencing before the cast | LL | let priority = *priority as u8; | + +help: add `#[derive(Copy, Clone)]` to the enum definition + | +LL + #[derive(Copy, Clone)] +LL | enum Priority { + | error[E0606]: casting `&Priority` as `u8` is invalid --> $DIR/cast-enum-to-int-issue-151116.rs:13:20 From 8634d633211fab1d95ecb297be5d6c8fe98691d6 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 5 May 2026 22:31:00 +0200 Subject: [PATCH 27/28] move test --- .../alias-with-bound-vars-incomplete-generalization.rs} | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename tests/ui/traits/next-solver/{self-referential-closure-sig-4.rs => generalize/alias-with-bound-vars-incomplete-generalization.rs} (75%) diff --git a/tests/ui/traits/next-solver/self-referential-closure-sig-4.rs b/tests/ui/traits/next-solver/generalize/alias-with-bound-vars-incomplete-generalization.rs similarity index 75% rename from tests/ui/traits/next-solver/self-referential-closure-sig-4.rs rename to tests/ui/traits/next-solver/generalize/alias-with-bound-vars-incomplete-generalization.rs index fb6297869356c..bf2276e4967b0 100644 --- a/tests/ui/traits/next-solver/self-referential-closure-sig-4.rs +++ b/tests/ui/traits/next-solver/generalize/alias-with-bound-vars-incomplete-generalization.rs @@ -2,7 +2,9 @@ //@[next] compile-flags: -Znext-solver //@ check-pass -// Regression test for the fourth variant of trait-system-refactor-initiative#191 +// Regression test for the fourth variant of trait-system-refactor-initiative#191. +// We previously didn't normalize `<() as Trait>::Assoc<'a>` before generalizing +// here, resulting in an error. trait Trait { type Assoc<'a>; From 0f5d89fea1d8751a94e2e023959743da7516dc80 Mon Sep 17 00:00:00 2001 From: Jaiden Magnan Date: Tue, 5 May 2026 17:34:50 -0400 Subject: [PATCH 28/28] fix: CopyPriority addition --- tests/ui/cast/cast-enum-to-int-issue-151116.rs | 12 ++++++++++++ .../cast/cast-enum-to-int-issue-151116.stderr | 17 ++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.rs b/tests/ui/cast/cast-enum-to-int-issue-151116.rs index 25a85e10a83e5..26da80bcf2774 100644 --- a/tests/ui/cast/cast-enum-to-int-issue-151116.rs +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.rs @@ -5,6 +5,14 @@ enum Priority { //~ HELP: add `#[derive(Copy, Clone)]` to the enum definition Low = 1, } +#[repr(u8)] +#[derive(Copy, Clone)] +enum CopyPriority { + High = 255, + Normal = 127, + Low = 1, +} + fn main() { let priority = &Priority::Normal; let priority = priority as u8; //~ ERROR casting `&Priority` as `u8` is invalid @@ -12,4 +20,8 @@ fn main() { let priority = &Priority::Normal as u8; //~ ERROR casting `&Priority` as `u8` is invalid //~| HELP: cast through a raw pointer first + + let priority = &CopyPriority::Normal; + let priority = priority as u8; //~ ERROR casting `&CopyPriority` as `u8` is invalid + //~| HELP: try dereferencing before the cast } diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.stderr b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr index 7eb0d357fb0de..63baef70585de 100644 --- a/tests/ui/cast/cast-enum-to-int-issue-151116.stderr +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr @@ -1,5 +1,5 @@ error[E0606]: casting `&Priority` as `u8` is invalid - --> $DIR/cast-enum-to-int-issue-151116.rs:10:20 + --> $DIR/cast-enum-to-int-issue-151116.rs:18:20 | LL | let priority = priority as u8; | ^^^^^^^^^^^^^^ @@ -15,13 +15,24 @@ LL | enum Priority { | error[E0606]: casting `&Priority` as `u8` is invalid - --> $DIR/cast-enum-to-int-issue-151116.rs:13:20 + --> $DIR/cast-enum-to-int-issue-151116.rs:21:20 | LL | let priority = &Priority::Normal as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: cast through a raw pointer first -error: aborting due to 2 previous errors +error[E0606]: casting `&CopyPriority` as `u8` is invalid + --> $DIR/cast-enum-to-int-issue-151116.rs:25:20 + | +LL | let priority = priority as u8; + | ^^^^^^^^^^^^^^ + | +help: try dereferencing before the cast + | +LL | let priority = *priority as u8; + | + + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0606`.