From a197ebdb07e0908a6bbfc6faf6874ecb709c1e88 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 27 Aug 2025 16:15:08 +0300 Subject: [PATCH 01/36] {CStr,OsStr,Path}::as_$1 --- library/core/src/ffi/c_str.rs | 11 +++++++++++ library/std/src/ffi/os_str.rs | 11 +++++++++++ library/std/src/path.rs | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 09d9b160700ca..02e43b870cb70 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -648,6 +648,17 @@ impl CStr { pub fn display(&self) -> impl fmt::Display { crate::bstr::ByteStr::from_bytes(self.to_bytes()) } + + /// Returns the same string as a string slice `&CStr`. + /// + /// This method is redundant when used directly on `&CStr`, but + /// it helps dereferencing other string-like types to string slices, + /// for example references to `Box` or `Arc`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_c_str(&self) -> &CStr { + self + } } #[stable(feature = "c_string_eq_c_str", since = "1.90.0")] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 09bd911aa769a..5fdf745bc18dc 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -1278,6 +1278,17 @@ impl OsStr { pub fn display(&self) -> Display<'_> { Display { os_str: self } } + + /// Returns the same string as a string slice `&OsStr`. + /// + /// This method is redundant when used directly on `&OsStr`, but + /// it helps dereferencing other string-like types to string slices, + /// for example references to `Box` or `Arc`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_os_str(&self) -> &OsStr { + self + } } #[stable(feature = "box_from_os_str", since = "1.17.0")] diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 114fcc796c525..b6b899a67d5df 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3208,6 +3208,17 @@ impl Path { Display { inner: self.inner.display() } } + /// Returns the same path as `&Path`. + /// + /// This method is redundant when used directly on `&Path`, but + /// it helps dereferencing other `PathBuf`-like types to `Path`s, + /// for example references to `Box` or `Arc`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_path(&self) -> &Path { + self + } + /// Queries the file system to get information about a file, directory, etc. /// /// This function will traverse symbolic links to query information about the From 4e5ce74da2f36ebc760e24245bb02a9563a30c38 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 27 Aug 2025 17:27:05 +0300 Subject: [PATCH 02/36] `[T]::as_[mut_]slice` --- library/core/src/slice/mod.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index f03f2045444df..7b482c7510364 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4906,6 +4906,28 @@ impl [T] { if start <= self.len() && end <= self.len() { Some(start..end) } else { None } } + + /// Returns the same slice `&[T]`. + /// + /// This method is redundant when used directly on `&[T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `Arc<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_slice(&self) -> &[T] { + self + } + + /// Returns the same slice `&mut [T]`. + /// + /// This method is redundant when used directly on `&mut [T]`, but + /// it helps dereferencing other "container" types to slices, + /// for example `Box<[T]>` or `MutexGuard<[T]>`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_mut_slice(&mut self) -> &mut [T] { + self + } } impl [MaybeUninit] { From 48f7f312f12340591ab25d0679376f9d3b874d36 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 27 Aug 2025 17:27:05 +0300 Subject: [PATCH 03/36] `ByteStr::as_[mut_]byte_str` --- library/core/src/bstr/mod.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/core/src/bstr/mod.rs b/library/core/src/bstr/mod.rs index e13dc5cd44d5c..34e1ea66c99ad 100644 --- a/library/core/src/bstr/mod.rs +++ b/library/core/src/bstr/mod.rs @@ -68,6 +68,30 @@ impl ByteStr { ByteStr::from_bytes(bytes.as_ref()) } + /// Returns the same string as `&ByteStr`. + /// + /// This method is redundant when used directly on `&ByteStr`, but + /// it helps dereferencing other "container" types, + /// for example `Box` or `Arc`. + #[inline] + // #[unstable(feature = "str_as_str", issue = "130366")] + #[unstable(feature = "bstr", issue = "134915")] + pub const fn as_byte_str(&self) -> &ByteStr { + self + } + + /// Returns the same string as `&mut ByteStr`. + /// + /// This method is redundant when used directly on `&mut ByteStr`, but + /// it helps dereferencing other "container" types, + /// for example `Box` or `MutexGuard`. + #[inline] + // #[unstable(feature = "str_as_str", issue = "130366")] + #[unstable(feature = "bstr", issue = "134915")] + pub const fn as_mut_byte_str(&mut self) -> &mut ByteStr { + self + } + #[doc(hidden)] #[unstable(feature = "bstr_internals", issue = "none")] #[inline] From 519785671b6d56dea6b11c4ab41aacaebe4d252e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 11 Nov 2025 14:57:22 -0500 Subject: [PATCH 04/36] Set -Cpanic=abort in windows-msvc stack protector tests --- ...otector-heuristics-effect-windows-32bit.rs | 74 +++++++++++------- ...otector-heuristics-effect-windows-64bit.rs | 78 +++++++++++-------- .../stack-protector-target-support.rs | 2 +- 3 files changed, 93 insertions(+), 61 deletions(-) diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs index 3287e018b4044..5759c387e3b14 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs @@ -7,7 +7,7 @@ //@ [strong] compile-flags: -Z stack-protector=strong //@ [basic] compile-flags: -Z stack-protector=basic //@ [none] compile-flags: -Z stack-protector=none -//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort #![crate_type = "lib"] #![allow(internal_features)] @@ -26,6 +26,7 @@ pub fn emptyfn() { // CHECK-LABEL: array_char #[no_mangle] pub fn array_char(f: fn(*const char)) { + // CHECK-DAG: .cv_fpo_endprologue let a = ['c'; 1]; let b = ['d'; 3]; let c = ['e'; 15]; @@ -39,11 +40,14 @@ pub fn array_char(f: fn(*const char)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } // CHECK-LABEL: array_u8_1 #[no_mangle] pub fn array_u8_1(f: fn(*const u8)) { + // CHECK-DAG: .cv_fpo_endprologue let a = [0u8; 1]; f(&a as *const _); @@ -55,11 +59,14 @@ pub fn array_u8_1(f: fn(*const u8)) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } // CHECK-LABEL: array_u8_small: #[no_mangle] pub fn array_u8_small(f: fn(*const u8)) { + // CHECK-DAG: .cv_fpo_endprologue let a = [0u8; 2]; let b = [0u8; 7]; f(&a as *const _); @@ -72,11 +79,14 @@ pub fn array_u8_small(f: fn(*const u8)) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } // CHECK-LABEL: array_u8_large: #[no_mangle] pub fn array_u8_large(f: fn(*const u8)) { + // CHECK-DAG: .cv_fpo_endprologue let a = [0u8; 9]; f(&a as *const _); @@ -88,6 +98,8 @@ pub fn array_u8_large(f: fn(*const u8)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } #[derive(Copy, Clone)] @@ -96,6 +108,7 @@ pub struct ByteSizedNewtype(u8); // CHECK-LABEL: array_bytesizednewtype_9: #[no_mangle] pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { + // CHECK-DAG: .cv_fpo_endprologue let a = [ByteSizedNewtype(0); 9]; f(&a as *const _); @@ -107,11 +120,14 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } // CHECK-LABEL: local_var_addr_used_indirectly #[no_mangle] pub fn local_var_addr_used_indirectly(f: fn(bool)) { + // CHECK-DAG: .cv_fpo_endprologue let a = 5; let a_addr = &a as *const _ as usize; f(a_addr & 0x10 == 0); @@ -134,37 +150,27 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } // CHECK-LABEL: local_string_addr_taken #[no_mangle] pub fn local_string_addr_taken(f: fn(&String)) { + // CHECK-DAG: .cv_fpo_endprologue let x = String::new(); f(&x); // Taking the address of the local variable `x` leads to stack smash - // protection with the `strong` heuristic, but not with the `basic` - // heuristic. It does not matter that the reference is not mut. - // - // An interesting note is that a similar function in C++ *would* be - // protected by the `basic` heuristic, because `std::string` has a char - // array internally as a small object optimization: - // ``` - // cat < - // void f(void (*g)(const std::string&)) { - // std::string x; - // g(x); - // } - // EOF - // ``` - // + // protection. It does not matter that the reference is not mut. // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } pub trait SelfByRef { @@ -180,6 +186,7 @@ impl SelfByRef for i32 { // CHECK-LABEL: local_var_addr_taken_used_locally_only #[no_mangle] pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { + // CHECK-DAG: .cv_fpo_endprologue let x = factory(); let g = x.f(); sink(g); @@ -194,6 +201,8 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32 // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } pub struct Gigastruct { @@ -207,6 +216,7 @@ pub struct Gigastruct { // CHECK-LABEL: local_large_var_moved #[no_mangle] pub fn local_large_var_moved(f: fn(Gigastruct)) { + // CHECK-DAG: .cv_fpo_endprologue let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; f(x); @@ -231,11 +241,14 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } // CHECK-LABEL: local_large_var_cloned #[no_mangle] pub fn local_large_var_cloned(f: fn(Gigastruct)) { + // CHECK-DAG: .cv_fpo_endprologue f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); // A new instance of `Gigastruct` is passed to `f()`, without any apparent @@ -260,6 +273,8 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } extern "C" { @@ -293,6 +308,7 @@ extern "C" { // CHECK-LABEL: alloca_small_compile_time_constant_arg #[no_mangle] pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { + // CHECK-DAG: .cv_fpo_endprologue f(unsafe { alloca(8) }); // all: __security_check_cookie @@ -300,11 +316,14 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } // CHECK-LABEL: alloca_large_compile_time_constant_arg #[no_mangle] pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { + // CHECK-DAG: .cv_fpo_endprologue f(unsafe { alloca(9) }); // all: __security_check_cookie @@ -312,11 +331,14 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } // CHECK-LABEL: alloca_dynamic_arg #[no_mangle] pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { + // CHECK-DAG: .cv_fpo_endprologue f(unsafe { alloca(n) }); // all: __security_check_cookie @@ -324,18 +346,19 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } // The question then is: in what ways can Rust code generate array-`alloca` // LLVM instructions? This appears to only be generated by // rustc_codegen_ssa::traits::Builder::array_alloca() through -// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT -// this is support for the "unsized locals" unstable feature: -// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. +// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). // CHECK-LABEL: unsized_fn_param #[no_mangle] pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { + // CHECK-DAG: .cv_fpo_endprologue let n = if l { 1 } else { 2 }; f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from @@ -346,14 +369,11 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { // alloca, and is therefore not protected by the `strong` or `basic` // heuristics. - // We should have a __security_check_cookie call in `all` and `strong` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 // all-NOT: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .cv_fpo_endproc } diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs index 9a3dabc74dded..56a6f08da5877 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs @@ -7,7 +7,7 @@ //@ [strong] compile-flags: -Z stack-protector=strong //@ [basic] compile-flags: -Z stack-protector=basic //@ [none] compile-flags: -Z stack-protector=none -//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort #![crate_type = "lib"] #![feature(unsized_fn_params)] @@ -25,6 +25,7 @@ pub fn emptyfn() { // CHECK-LABEL: array_char #[no_mangle] pub fn array_char(f: fn(*const char)) { + // CHECK-DAG: .seh_endprologue let a = ['c'; 1]; let b = ['d'; 3]; let c = ['e'; 15]; @@ -38,11 +39,14 @@ pub fn array_char(f: fn(*const char)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } // CHECK-LABEL: array_u8_1 #[no_mangle] pub fn array_u8_1(f: fn(*const u8)) { + // CHECK-DAG: .seh_endprologue let a = [0u8; 1]; f(&a as *const _); @@ -54,11 +58,14 @@ pub fn array_u8_1(f: fn(*const u8)) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } // CHECK-LABEL: array_u8_small: #[no_mangle] pub fn array_u8_small(f: fn(*const u8)) { + // CHECK-DAG: .seh_endprologue let a = [0u8; 2]; let b = [0u8; 7]; f(&a as *const _); @@ -71,11 +78,14 @@ pub fn array_u8_small(f: fn(*const u8)) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } // CHECK-LABEL: array_u8_large: #[no_mangle] pub fn array_u8_large(f: fn(*const u8)) { + // CHECK-DAG: .seh_endprologue let a = [0u8; 9]; f(&a as *const _); @@ -87,6 +97,8 @@ pub fn array_u8_large(f: fn(*const u8)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } #[derive(Copy, Clone)] @@ -95,6 +107,7 @@ pub struct ByteSizedNewtype(u8); // CHECK-LABEL: array_bytesizednewtype_9: #[no_mangle] pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { + // CHECK-DAG: .seh_endprologue let a = [ByteSizedNewtype(0); 9]; f(&a as *const _); @@ -106,11 +119,14 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } // CHECK-LABEL: local_var_addr_used_indirectly #[no_mangle] pub fn local_var_addr_used_indirectly(f: fn(bool)) { + // CHECK-DAG: .seh_endprologue let a = 5; let a_addr = &a as *const _ as usize; f(a_addr & 0x10 == 0); @@ -133,6 +149,8 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } // CHECK-LABEL: local_string_addr_taken @@ -143,31 +161,11 @@ pub fn local_string_addr_taken(f: fn(&String)) { f(&x); // Taking the address of the local variable `x` leads to stack smash - // protection with the `strong` heuristic, but not with the `basic` - // heuristic. It does not matter that the reference is not mut. - // - // An interesting note is that a similar function in C++ *would* be - // protected by the `basic` heuristic, because `std::string` has a char - // array internally as a small object optimization: - // ``` - // cat < - // void f(void (*g)(const std::string&)) { - // std::string x; - // g(x); - // } - // EOF - // ``` - // - - // We should have a __security_check_cookie call in `all` and `strong` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 - // all-NOT: __security_check_cookie - // strong-NOT: __security_check_cookie + // protection. It does not matter that the reference is not mut. - // basic-NOT: __security_check_cookie + // all: __security_check_cookie + // strong: __security_check_cookie + // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie @@ -187,6 +185,7 @@ impl SelfByRef for i32 { // CHECK-LABEL: local_var_addr_taken_used_locally_only #[no_mangle] pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { + // CHECK-DAG: .seh_endprologue let x = factory(); let g = x.f(); sink(g); @@ -201,6 +200,8 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32 // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } pub struct Gigastruct { @@ -214,6 +215,7 @@ pub struct Gigastruct { // CHECK-LABEL: local_large_var_moved #[no_mangle] pub fn local_large_var_moved(f: fn(Gigastruct)) { + // CHECK-DAG: .seh_endprologue let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; f(x); @@ -238,11 +240,14 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } // CHECK-LABEL: local_large_var_cloned #[no_mangle] pub fn local_large_var_cloned(f: fn(Gigastruct)) { + // CHECK-DAG: .seh_endprologue f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); // A new instance of `Gigastruct` is passed to `f()`, without any apparent @@ -267,6 +272,8 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) { // basic: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } extern "C" { @@ -300,6 +307,7 @@ extern "C" { // CHECK-LABEL: alloca_small_compile_time_constant_arg #[no_mangle] pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { + // CHECK-DAG: .seh_endprologue f(unsafe { alloca(8) }); // all: __security_check_cookie @@ -307,11 +315,14 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } // CHECK-LABEL: alloca_large_compile_time_constant_arg #[no_mangle] pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { + // CHECK-DAG: .seh_endprologue f(unsafe { alloca(9) }); // all: __security_check_cookie @@ -319,11 +330,14 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } // CHECK-LABEL: alloca_dynamic_arg #[no_mangle] pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { + // CHECK-DAG: .seh_endprologue f(unsafe { alloca(n) }); // all: __security_check_cookie @@ -331,18 +345,19 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } // The question then is: in what ways can Rust code generate array-`alloca` // LLVM instructions? This appears to only be generated by // rustc_codegen_ssa::traits::Builder::array_alloca() through -// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT -// this is support for the "unsized locals" unstable feature: -// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. +// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). // CHECK-LABEL: unsized_fn_param #[no_mangle] pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { + // CHECK-DAG: .seh_endprologue let n = if l { 1 } else { 2 }; f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from @@ -353,14 +368,11 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { // alloca, and is therefore not protected by the `strong` or `basic` // heuristics. - // We should have a __security_check_cookie call in `all` and `strong` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 // all-NOT: __security_check_cookie // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie // none-NOT: __security_check_cookie // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc } diff --git a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs index 0218fe0a52f8a..9f182985d1573 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs @@ -173,7 +173,7 @@ //@ [r84] needs-llvm-components: x86 //@ [r85] compile-flags: --target x86_64-unknown-redox //@ [r85] needs-llvm-components: x86 -//@ compile-flags: -Z stack-protector=all +//@ compile-flags: -Z stack-protector=all -Cpanic=abort //@ compile-flags: -C opt-level=2 #![crate_type = "lib"] From a5f677b665961956f25e81818b1983687449135d Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 12 Nov 2025 23:40:47 -0500 Subject: [PATCH 05/36] Try to fix i686 --- ...-protector-heuristics-effect-windows-32bit.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs index 5759c387e3b14..d1b51068fce5a 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs @@ -7,7 +7,7 @@ //@ [strong] compile-flags: -Z stack-protector=strong //@ [basic] compile-flags: -Z stack-protector=basic //@ [none] compile-flags: -Z stack-protector=none -//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort -Cdebuginfo=1 #![crate_type = "lib"] #![allow(internal_features)] @@ -26,7 +26,6 @@ pub fn emptyfn() { // CHECK-LABEL: array_char #[no_mangle] pub fn array_char(f: fn(*const char)) { - // CHECK-DAG: .cv_fpo_endprologue let a = ['c'; 1]; let b = ['d'; 3]; let c = ['e'; 15]; @@ -47,7 +46,6 @@ pub fn array_char(f: fn(*const char)) { // CHECK-LABEL: array_u8_1 #[no_mangle] pub fn array_u8_1(f: fn(*const u8)) { - // CHECK-DAG: .cv_fpo_endprologue let a = [0u8; 1]; f(&a as *const _); @@ -66,7 +64,6 @@ pub fn array_u8_1(f: fn(*const u8)) { // CHECK-LABEL: array_u8_small: #[no_mangle] pub fn array_u8_small(f: fn(*const u8)) { - // CHECK-DAG: .cv_fpo_endprologue let a = [0u8; 2]; let b = [0u8; 7]; f(&a as *const _); @@ -86,7 +83,6 @@ pub fn array_u8_small(f: fn(*const u8)) { // CHECK-LABEL: array_u8_large: #[no_mangle] pub fn array_u8_large(f: fn(*const u8)) { - // CHECK-DAG: .cv_fpo_endprologue let a = [0u8; 9]; f(&a as *const _); @@ -108,7 +104,6 @@ pub struct ByteSizedNewtype(u8); // CHECK-LABEL: array_bytesizednewtype_9: #[no_mangle] pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { - // CHECK-DAG: .cv_fpo_endprologue let a = [ByteSizedNewtype(0); 9]; f(&a as *const _); @@ -127,7 +122,6 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { // CHECK-LABEL: local_var_addr_used_indirectly #[no_mangle] pub fn local_var_addr_used_indirectly(f: fn(bool)) { - // CHECK-DAG: .cv_fpo_endprologue let a = 5; let a_addr = &a as *const _ as usize; f(a_addr & 0x10 == 0); @@ -157,7 +151,6 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) { // CHECK-LABEL: local_string_addr_taken #[no_mangle] pub fn local_string_addr_taken(f: fn(&String)) { - // CHECK-DAG: .cv_fpo_endprologue let x = String::new(); f(&x); @@ -186,7 +179,6 @@ impl SelfByRef for i32 { // CHECK-LABEL: local_var_addr_taken_used_locally_only #[no_mangle] pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { - // CHECK-DAG: .cv_fpo_endprologue let x = factory(); let g = x.f(); sink(g); @@ -216,7 +208,6 @@ pub struct Gigastruct { // CHECK-LABEL: local_large_var_moved #[no_mangle] pub fn local_large_var_moved(f: fn(Gigastruct)) { - // CHECK-DAG: .cv_fpo_endprologue let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; f(x); @@ -248,7 +239,6 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) { // CHECK-LABEL: local_large_var_cloned #[no_mangle] pub fn local_large_var_cloned(f: fn(Gigastruct)) { - // CHECK-DAG: .cv_fpo_endprologue f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); // A new instance of `Gigastruct` is passed to `f()`, without any apparent @@ -308,7 +298,6 @@ extern "C" { // CHECK-LABEL: alloca_small_compile_time_constant_arg #[no_mangle] pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { - // CHECK-DAG: .cv_fpo_endprologue f(unsafe { alloca(8) }); // all: __security_check_cookie @@ -323,7 +312,6 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { // CHECK-LABEL: alloca_large_compile_time_constant_arg #[no_mangle] pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { - // CHECK-DAG: .cv_fpo_endprologue f(unsafe { alloca(9) }); // all: __security_check_cookie @@ -338,7 +326,6 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { // CHECK-LABEL: alloca_dynamic_arg #[no_mangle] pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { - // CHECK-DAG: .cv_fpo_endprologue f(unsafe { alloca(n) }); // all: __security_check_cookie @@ -358,7 +345,6 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { // CHECK-LABEL: unsized_fn_param #[no_mangle] pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { - // CHECK-DAG: .cv_fpo_endprologue let n = if l { 1 } else { 2 }; f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from From 4c29d61ec622f9081ee4f6bbe38ee5735d4cfb22 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 15 Oct 2025 09:55:38 +0000 Subject: [PATCH 06/36] Remove -Zoom=panic There are major questions remaining about the reentrancy that this allows. It doesn't have any users on github outside of a single project that uses it in a panic=abort project to show backtraces. It can still be emulated through #[alloc_error_handler] or set_alloc_error_hook depending on if you use the standard library or not. And finally it makes it harder to do various improvements to the allocator shim. --- src/allocator.rs | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 67b89114356b5..4a9b0c0952ff3 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -6,7 +6,6 @@ use rustc_ast::expand::allocator::{ AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name, }; use rustc_codegen_ssa::base::{allocator_kind_for_codegen, allocator_shim_contents}; -use rustc_session::config::OomStrategy; use rustc_symbol_mangling::mangle_internal_symbol; use crate::prelude::*; @@ -15,16 +14,11 @@ use crate::prelude::*; pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool { let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; let methods = allocator_shim_contents(tcx, kind); - codegen_inner(tcx, module, &methods, tcx.sess.opts.unstable_opts.oom); + codegen_inner(tcx, module, &methods); true } -fn codegen_inner( - tcx: TyCtxt<'_>, - module: &mut dyn Module, - methods: &[AllocatorMethod], - oom_strategy: OomStrategy, -) { +fn codegen_inner(tcx: TyCtxt<'_>, module: &mut dyn Module, methods: &[AllocatorMethod]) { let usize_ty = module.target_config().pointer_type(); for method in methods { @@ -65,35 +59,6 @@ fn codegen_inner( ); } - { - let sig = Signature { - call_conv: module.target_config().default_call_conv, - params: vec![], - returns: vec![AbiParam::new(types::I8)], - }; - let func_id = module - .declare_function( - &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - Linkage::Export, - &sig, - ) - .unwrap(); - let mut ctx = Context::new(); - ctx.func.signature = sig; - { - let mut func_ctx = FunctionBuilderContext::new(); - let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); - - let block = bcx.create_block(); - bcx.switch_to_block(block); - let value = bcx.ins().iconst(types::I8, oom_strategy.should_panic() as i64); - bcx.ins().return_(&[value]); - bcx.seal_all_blocks(); - bcx.finalize(); - } - module.define_function(func_id, &mut ctx).unwrap(); - } - { let sig = Signature { call_conv: module.target_config().default_call_conv, From 6693a568aff4d4f41007898d070c157f08a6d2db Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 16:20:48 +0000 Subject: [PATCH 07/36] Merge commit 'e24f0fa3c54951d1a5843b54ebe052faaa3a3cd2' into sync_cg_clif-2025-12-08 --- .cirrus.yml | 2 +- Cargo.lock | 159 ++++++++++-------- Cargo.toml | 26 +-- build_system/abi_cafe.rs | 2 +- build_system/bench.rs | 39 +++-- build_system/build_backend.rs | 7 +- build_system/build_sysroot.rs | 43 ++--- build_system/main.rs | 7 +- build_system/tests.rs | 8 +- build_system/utils.rs | 4 +- ...-simd-Disable-broken-reduce_sum-test.patch | 26 --- rust-toolchain | 2 +- scripts/rustup.sh | 4 +- src/common.rs | 20 ++- src/debuginfo/line_info.rs | 9 +- src/debuginfo/mod.rs | 59 ++++--- src/debuginfo/types.rs | 3 +- src/lib.rs | 12 +- 18 files changed, 224 insertions(+), 208 deletions(-) delete mode 100644 patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch diff --git a/.cirrus.yml b/.cirrus.yml index 3ed89beceb7fe..9be095dbf2d8f 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,7 +1,7 @@ task: name: freebsd freebsd_instance: - image_family: freebsd-14-2 + image_family: freebsd-15-0-amd64-ufs setup_rust_script: - pkg install -y git-tiny binutils - curl https://sh.rustup.rs -sSf --output rustup.sh diff --git a/Cargo.lock b/Cargo.lock index 09b6c6b87c300..617c7f0e34cd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,15 +10,15 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "bitflags" @@ -37,48 +37,48 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cranelift-assembler-x64" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f502c60b6af2025c312b37788c089943ef03156a2910da1aa046bb39eb8f61c7" +checksum = "bf7631e609c97f063f9777aae405e8492abf9bf92336d7aa3f875403dd4ffd7d" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b7e21a74bcf08443a4ef800a4a257063e5c51ee4d7a3bd58da5262d10340830" +checksum = "9c030edccdc4a5bbf28fbfe7701b5cd1f9854b4445184dd34af2a7e8f8db6f45" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f337d268865c292ad5df0669a9bbf6223ca41460292a20ad5b0a57b8e9f27f93" +checksum = "bb544c1242d0ca98baf01873ebba96c79d5df155d5108d9bb699aefc741f5e6d" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0e60319a8242c8d1c7b5a2444d140c416f903f75e0d84da3256fceb822bab85" +checksum = "f0325aecbafec053d3d3f082edfdca7937e2945e7f09c5ff9672e05198312282" [[package]] name = "cranelift-codegen" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78dee669e447a1c68760bf7acee33835e99d564f0137b067f74d4718dfc9970d" +checksum = "abb3236fd319ae897ba00c8a25105081de5c1348576def0e96c062ad259f87a7" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601f629d172b7230f41dd0e78ee797efaf7ec1a5e113c8f395f4027dff6a92ca" +checksum = "7b8791c911a361c539130ace34fb726b16aca4216470ec75d75264b1495c8a3a" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -114,33 +114,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15755c2660902c7d59d96f6551a66ef629650dc3fd405f9dad841e8c58c1a4a2" +checksum = "12ead718c2a10990870c19b2497b5a04b8aae6024485e33da25b5d02e35819e0" [[package]] name = "cranelift-control" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727bfca18705101a294ab9077ad214a8b762ea2bc9844389d0db233d7c61ec3b" +checksum = "c0a57fc972b5651047efddccb99440d103d9d8c13393ccebde15ddd5b6a1181b" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15564c6f0c72750ca4374f40b044857cbc8087571e46d4c7ccdbdcc29b1dec8b" +checksum = "5aae980b4a1678b601eab2f52e372ed0b3c9565a31c17f380008cb97b3a699c5" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c681f2731f1cf68eed9f3b6811571823a5ac498f59c52b73736b68599defb3" +checksum = "a78877016b607982ca1708c0dd4ce23bde04581a39854c9b43a1dca43625b54c" dependencies = [ "cranelift-codegen", "log", @@ -150,15 +150,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40cedc02f08307da019a3e06d3f20f772f829ff813aec975accb012f8930b688" +checksum = "5dc46a68b46d4f53f9f2f02ab8d3a34b00f03a21c124a7a965b8cbf5fdb6773b" [[package]] name = "cranelift-jit" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2864461448c72d15ae3311ea63df9c7e35f22f04683785f6715a0cf17e6577d" +checksum = "7df920009af919ad9df52eb7b47b1895145822e0c29da9b715a876fc8ecc6d82" dependencies = [ "anyhow", "cranelift-codegen", @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b31d249bbbccc4c1ae54701087d4d49d05951897691eef44f4a60e70252743b" +checksum = "ddcf313629071ce74de8e59f02092f5453d1a01047607fc4ad36886b8bd1486c" dependencies = [ "anyhow", "cranelift-codegen", @@ -187,9 +187,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db03ab51c60710eb83d0217725b77db4062aca83b35359f5e6aa99ed1c275977" +checksum = "03faa07ec8cf373250a8252eb773d098ff88259fa1c19ee1ecde8012839f4097" dependencies = [ "cranelift-codegen", "libc", @@ -198,9 +198,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7131e0eb45ee10b0bd6082d0c0114c2e9a670b034d46774b39d0fc5c0ed7cedf" +checksum = "7cca62c14f3c2e4f438192562bbf82d1a98a59543cc66ba04fb658ba99f515a6" dependencies = [ "anyhow", "cranelift-codegen", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.125.1" +version = "0.126.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7a06c330b7994a891ad5b622ebc9aefcd17beae832dd25f577cf60c13426bf" +checksum = "0484cb32c527a742e1bba09ef174acac0afb1dcf623ef1adda42849200edcd2e" [[package]] name = "crc32fast" @@ -246,9 +246,9 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "gimli" -version = "0.32.0" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" dependencies = [ "fallible-iterator", "indexmap", @@ -282,18 +282,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libloading" -version = "0.8.8" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-link 0.2.1", ] [[package]] @@ -304,9 +304,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "mach2" @@ -319,9 +319,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "object" @@ -337,27 +337,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] [[package]] name = "regalloc2" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd8138ce7c3d7c13be4f61893154b5d711bd798d2d7be3ecb8dcc7e7a06ca98" +checksum = "4e249c660440317032a71ddac302f25f1d5dff387667bcc3978d1f77aa31ac34" dependencies = [ "allocator-api2", "bumpalo", @@ -405,18 +405,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -431,15 +440,15 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -448,21 +457,21 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "38.0.1" +version = "39.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d0a76f1a6e887cc1b551b02dfd6e2ce5f6738e8cacd9ad7284f6ac1aac4698f" +checksum = "3f67986f5c499274ae5b2ba5b173bba0b95d1381f5ca70d8eec657f2392117d8" dependencies = [ "anyhow", "cfg-if", @@ -472,9 +481,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-math" -version = "38.0.1" +version = "39.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b900df4252ad86547e7f2b2c00201b006db4e864893bedfb3aca32b23d81868a" +checksum = "a681733e9b5d5d8804ee6cacd59f92c0d87ba2274f42ee1d4e5a943828d0075d" dependencies = [ "libm", ] @@ -485,6 +494,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.52.0" @@ -525,7 +540,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", diff --git a/Cargo.toml b/Cargo.toml index f2001123e579d..58e61cd0b9d7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,28 +8,28 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.125.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.125.0" } -cranelift-module = { version = "0.125.0" } -cranelift-native = { version = "0.125.0" } -cranelift-jit = { version = "0.125.0", optional = true } -cranelift-object = { version = "0.125.0" } +cranelift-codegen = { version = "0.126.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.126.0" } +cranelift-module = { version = "0.126.0" } +cranelift-native = { version = "0.126.0" } +cranelift-jit = { version = "0.126.0", optional = true } +cranelift-object = { version = "0.126.0" } target-lexicon = "0.13" gimli = { version = "0.32", default-features = false, features = ["write"] } object = { version = "0.37.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } indexmap = "2.0.0" -libloading = { version = "0.8.0", optional = true } +libloading = { version = "0.9.0", optional = true } smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-38.0.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } diff --git a/build_system/abi_cafe.rs b/build_system/abi_cafe.rs index 5a393a217c278..762b2be8f4405 100644 --- a/build_system/abi_cafe.rs +++ b/build_system/abi_cafe.rs @@ -11,7 +11,7 @@ static ABI_CAFE_REPO: GitRepo = GitRepo::github( "abi-cafe", ); -static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe_target"); +static ABI_CAFE: CargoProject = CargoProject::new(ABI_CAFE_REPO.source_dir(), "abi_cafe_target"); pub(crate) fn run( sysroot_kind: SysrootKind, diff --git a/build_system/bench.rs b/build_system/bench.rs index 192cb499536f1..91353ba8a874d 100644 --- a/build_system/bench.rs +++ b/build_system/bench.rs @@ -39,7 +39,26 @@ pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) { let rustc_clif = &compiler.rustc; let rustflags = &compiler.rustflags.join("\x1f"); let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml"); - let target_dir = dirs.build_dir.join("simple_raytracer"); + let target_dir = dirs.build_dir.join("simple-raytracer_target"); + + let raytracer_cg_llvm = dirs + .build_dir + .join(get_file_name(&compiler.rustc, "raytracer_cg_llvm", "bin")) + .to_str() + .unwrap() + .to_owned(); + let raytracer_cg_clif = dirs + .build_dir + .join(get_file_name(&compiler.rustc, "raytracer_cg_clif", "bin")) + .to_str() + .unwrap() + .to_owned(); + let raytracer_cg_clif_opt = dirs + .build_dir + .join(get_file_name(&compiler.rustc, "raytracer_cg_clif_opt", "bin")) + .to_str() + .unwrap() + .to_owned(); let clean_cmd = format!( "RUSTC=rustc cargo clean --manifest-path {manifest_path} --target-dir {target_dir}", @@ -47,19 +66,19 @@ pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) { target_dir = target_dir.display(), ); let llvm_build_cmd = format!( - "RUSTC=rustc cargo build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_llvm || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_llvm", + "RUSTC=rustc cargo build --manifest-path {manifest_path} --target-dir {target_dir} && (rm {raytracer_cg_llvm} || true) && ln {target_dir}/debug/main {raytracer_cg_llvm}", manifest_path = manifest_path.display(), target_dir = target_dir.display(), ); let clif_build_cmd = format!( - "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif", + "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm {raytracer_cg_clif} || true) && ln {target_dir}/debug/main {raytracer_cg_clif}", cargo_clif = cargo_clif.display(), rustc_clif = rustc_clif.display(), manifest_path = manifest_path.display(), target_dir = target_dir.display(), ); let clif_build_opt_cmd = format!( - "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt", + "RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" CARGO_BUILD_INCREMENTAL=true {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm {raytracer_cg_clif_opt} || true) && ln {target_dir}/release/main {raytracer_cg_clif_opt}", cargo_clif = cargo_clif.display(), rustc_clif = rustc_clif.display(), manifest_path = manifest_path.display(), @@ -92,20 +111,14 @@ pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) { let bench_run_markdown = dirs.build_dir.join("bench_run.md"); - let raytracer_cg_llvm = - Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_llvm", "bin")); - let raytracer_cg_clif = - Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif", "bin")); - let raytracer_cg_clif_opt = - Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif_opt", "bin")); let mut bench_run = hyperfine_command( 0, bench_runs, None, &[ - ("", raytracer_cg_llvm.to_str().unwrap()), - ("", raytracer_cg_clif.to_str().unwrap()), - ("", raytracer_cg_clif_opt.to_str().unwrap()), + ("build/raytracer_cg_llvm", &raytracer_cg_llvm), + ("build/raytracer_cg_clif", &raytracer_cg_clif), + ("build/raytracer_cg_clif_opt", &raytracer_cg_clif_opt), ], &bench_run_markdown, ); diff --git a/build_system/build_backend.rs b/build_system/build_backend.rs index b9fa0ff2d94c3..c0a8cc95614f6 100644 --- a/build_system/build_backend.rs +++ b/build_system/build_backend.rs @@ -6,7 +6,7 @@ use crate::rustc_info::get_file_name; use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env}; use crate::utils::{CargoProject, Compiler, LogGroup}; -static CG_CLIF: CargoProject = CargoProject::new(&RelPath::source("."), "cg_clif"); +static CG_CLIF: CargoProject = CargoProject::new(RelPath::source("."), "cg_clif"); pub(crate) fn build_backend( dirs: &Dirs, @@ -22,6 +22,11 @@ pub(crate) fn build_backend( rustflags.push("-Zallow-features=rustc_private,f16,f128".to_owned()); rustflags_to_cmd_env(&mut cmd, "RUSTFLAGS", &rustflags); + // Use incr comp despite release mode unless incremental builds are explicitly disabled + if env::var_os("CARGO_BUILD_INCREMENTAL").is_none() { + cmd.env("CARGO_BUILD_INCREMENTAL", "true"); + } + if env::var("CG_CLIF_EXPENSIVE_CHECKS").is_ok() { // Enabling debug assertions implicitly enables the clif ir verifier cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true"); diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index 70504ee8007d2..e7363e37a45d0 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -140,7 +140,7 @@ impl SysrootTarget { static STDLIB_SRC: RelPath = RelPath::build("stdlib"); static STANDARD_LIBRARY: CargoProject = - CargoProject::new(&RelPath::build("stdlib/library/sysroot"), "stdlib_target"); + CargoProject::new(RelPath::build("stdlib/library/sysroot"), "stdlib_target"); fn build_sysroot_for_triple( dirs: &Dirs, @@ -161,35 +161,18 @@ fn build_sysroot_for_triple( fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { let default_sysroot = crate::rustc_info::get_default_sysroot(&compiler.rustc); - let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] }; + let std_manifest_path = default_sysroot + .join("lib") + .join("rustlib") + .join(format!("manifest-rust-std-{}", compiler.triple)); - for entry in fs::read_dir( - default_sysroot.join("lib").join("rustlib").join(&target_libs.triple).join("lib"), - ) - .unwrap() - { - let entry = entry.unwrap(); - if entry.file_type().unwrap().is_dir() { - continue; - } - let file = entry.path(); - let file_name_str = file.file_name().unwrap().to_str().unwrap(); - if (file_name_str.contains("rustc_") - && !file_name_str.contains("rustc_std_workspace_") - && !file_name_str.contains("rustc_demangle") - && !file_name_str.contains("rustc_literal_escaper")) - || file_name_str.contains("chalk") - || file_name_str.contains("tracing") - || file_name_str.contains("regex") - { - // These are large crates that are part of the rustc-dev component and are not - // necessary to run regular programs. - continue; - } - target_libs.libs.push(file); - } + let libs = fs::read_to_string(std_manifest_path) + .unwrap() + .lines() + .map(|entry| default_sysroot.join(entry.strip_prefix("file:").unwrap())) + .collect(); - target_libs + SysrootTarget { triple: compiler.triple, libs } } fn build_clif_sysroot_for_triple( @@ -251,6 +234,10 @@ fn build_clif_sysroot_for_triple( if compiler.triple.contains("apple") { build_cmd.env("CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO", "packed"); } + // Use incr comp despite release mode unless incremental builds are explicitly disabled + if env::var_os("CARGO_BUILD_INCREMENTAL").is_none() { + build_cmd.env("CARGO_BUILD_INCREMENTAL", "true"); + } spawn_and_wait(build_cmd); for entry in fs::read_dir(build_dir.join("deps")).unwrap() { diff --git a/build_system/main.rs b/build_system/main.rs index fc00931283002..6251687babc67 100644 --- a/build_system/main.rs +++ b/build_system/main.rs @@ -59,11 +59,6 @@ fn main() { } env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1"); - // Force incr comp even in release mode unless in CI or incremental builds are explicitly disabled - if env::var_os("CARGO_BUILD_INCREMENTAL").is_none() { - env::set_var("CARGO_BUILD_INCREMENTAL", "true"); - } - let mut args = env::args().skip(1); let command = match args.next().as_deref() { Some("prepare") => Command::Prepare, @@ -79,7 +74,7 @@ fn main() { } }; - let mut out_dir = PathBuf::from("."); + let mut out_dir = std::env::current_dir().unwrap(); let mut download_dir = None; let mut sysroot_kind = SysrootKind::Clif; let mut use_unstable_features = true; diff --git a/build_system/tests.rs b/build_system/tests.rs index dd8cf929bc2f0..3b6a2e7a055cb 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -129,7 +129,7 @@ pub(crate) static RAND_REPO: GitRepo = GitRepo::github( "rand", ); -static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand_target"); +static RAND: CargoProject = CargoProject::new(RAND_REPO.source_dir(), "rand_target"); pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( "rust-lang", @@ -139,15 +139,15 @@ pub(crate) static REGEX_REPO: GitRepo = GitRepo::github( "regex", ); -static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target"); +static REGEX: CargoProject = CargoProject::new(REGEX_REPO.source_dir(), "regex_target"); static PORTABLE_SIMD_SRC: RelPath = RelPath::build("portable-simd"); -static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target"); +static PORTABLE_SIMD: CargoProject = CargoProject::new(PORTABLE_SIMD_SRC, "portable-simd_target"); static SYSROOT_TESTS_SRC: RelPath = RelPath::build("sysroot_tests"); -static SYSROOT_TESTS: CargoProject = CargoProject::new(&SYSROOT_TESTS_SRC, "sysroot_tests_target"); +static SYSROOT_TESTS: CargoProject = CargoProject::new(SYSROOT_TESTS_SRC, "sysroot_tests_target"); const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[ TestCase::custom("test.rust-random/rand", &|runner| { diff --git a/build_system/utils.rs b/build_system/utils.rs index 3266aa0ce8b64..5c7cefa120a7f 100644 --- a/build_system/utils.rs +++ b/build_system/utils.rs @@ -75,12 +75,12 @@ impl Compiler { } pub(crate) struct CargoProject { - source: &'static RelPath, + source: RelPath, target: &'static str, } impl CargoProject { - pub(crate) const fn new(path: &'static RelPath, target: &'static str) -> CargoProject { + pub(crate) const fn new(path: RelPath, target: &'static str) -> CargoProject { CargoProject { source: path, target } } diff --git a/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch b/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch deleted file mode 100644 index b1fd6224632be..0000000000000 --- a/patches/0001-portable-simd-Disable-broken-reduce_sum-test.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 5489384bc265e9e6fc2efaa63d93a4d51ebec2f5 Mon Sep 17 00:00:00 2001 -From: bjorn3 <17426603+bjorn3@users.noreply.github.com> -Date: Thu, 22 Aug 2024 19:22:58 +0000 -Subject: [PATCH] Disable broken reduce_sum test - -It was broken by an upstream change to the .sum() implementation on -float iterators. ---- - crates/core_simd/tests/ops_macros.rs | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs -index aa565a1..5e6ac41 100644 ---- a/crates/core_simd/tests/ops_macros.rs -+++ b/crates/core_simd/tests/ops_macros.rs -@@ -646,6 +646,7 @@ macro_rules! impl_float_tests { - } - - fn reduce_sum() { -+ return; - test_helpers::test_1(&|x| { - test_helpers::prop_assert_biteq! ( - Vector::::from_array(x).reduce_sum(), --- -2.34.1 - diff --git a/rust-toolchain b/rust-toolchain index 17c2cc5ac6609..461dbcdb0fb5d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-11-08" +channel = "nightly-2025-12-08" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/scripts/rustup.sh b/scripts/rustup.sh index fdfd03029b160..1a82193303e23 100755 --- a/scripts/rustup.sh +++ b/scripts/rustup.sh @@ -43,7 +43,7 @@ case $1 in cg_clif=$(pwd) pushd ../rust - git pull origin master + git pull origin main branch=sync_cg_clif-$(date +%Y-%m-%d) git checkout -b "$branch" "$cg_clif/git-fixed-subtree.sh" pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/rust-lang/rustc_codegen_cranelift.git main @@ -63,7 +63,7 @@ case $1 in cg_clif=$(pwd) pushd ../rust - git fetch origin master + git fetch origin main git -c advice.detachedHead=false checkout "$RUST_VERS" "$cg_clif/git-fixed-subtree.sh" push --prefix=compiler/rustc_codegen_cranelift/ "$cg_clif" sync_from_rust popd diff --git a/src/common.rs b/src/common.rs index 38676eaac3d56..b11f42408f58b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -377,26 +377,28 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { size.is_multiple_of(align), "size must be a multiple of alignment (size={size}, align={align})" ); + debug_assert!(align.is_power_of_two(), "alignment must be a power of two (align={align})"); let abi_align = if self.tcx.sess.target.arch == Arch::S390x { 8 } else { 16 }; + // Cranelift can only guarantee alignment up to the ABI alignment provided by the target. + // If the requested alignment is less than the abi_align it can be used directly. if align <= abi_align { let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, - // FIXME Don't force the size to a multiple of bytes once Cranelift gets - // a way to specify stack slot alignment. - size: size.div_ceil(abi_align) * abi_align, - align_shift: 4, + size, + // The maximum value of ilog2 is 31 which will always fit in a u8. + align_shift: align.ilog2().try_into().unwrap(), + key: None, }); Pointer::stack_slot(stack_slot) } else { - // Alignment is too big to handle using the above hack. Dynamically realign a stack slot + // Alignment is larger than the ABI alignment guaranteed. Dynamically realign a stack slot // instead. This wastes some space for the realignment. let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, - // FIXME Don't force the size to a multiple of bytes once Cranelift gets - // a way to specify stack slot alignment. - size: (size + align) / abi_align * abi_align, - align_shift: 4, + size: size + align, + align_shift: abi_align.ilog2().try_into().unwrap(), + key: None, }); let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0); let misalign_offset = self.bcx.ins().band_imm(base_ptr, i64::from(align - 1)); diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index 6fe22f5c6dd9b..db58ee8909113 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -5,7 +5,7 @@ use std::path::{Component, Path}; use cranelift_codegen::MachSrcLoc; use cranelift_codegen::binemit::CodeOffset; -use gimli::write::{AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable}; +use gimli::write::{FileId, FileInfo, LineProgram, LineString, LineStringTable}; use rustc_span::{FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHashAlgorithm, hygiene}; use crate::debuginfo::FunctionDebugContext; @@ -117,8 +117,7 @@ impl DebugContext { } filename => { // For anonymous sources, create an empty directory instead of using the default - let empty_dir = LineString::new(b"", line_program.encoding(), line_strings); - let dir_id = line_program.add_directory(empty_dir); + let dir_id = line_program.default_directory(); let dummy_file_name = LineString::new( filename.prefer_remapped_unconditionally().to_string().into_bytes(), @@ -176,10 +175,6 @@ impl FunctionDebugContext { assert_ne!(func_end, 0); - let entry = debug_context.dwarf.unit.get_mut(self.entry_id); - entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); - entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(func_end))); - func_end } } diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 494002f525c84..8c43db92fe05f 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -42,14 +42,14 @@ pub(crate) struct DebugContext { created_files: FxHashMap<(StableSourceFileId, SourceFileHash), FileId>, stack_pointer_register: Register, namespace_map: DefIdMap, - array_size_type: UnitEntryId, + array_size_type: Option, filename_display_preference: FileNameDisplayPreference, embed_source: bool, } pub(crate) struct FunctionDebugContext { - entry_id: UnitEntryId, + entry_id: Option, function_source_loc: (FileId, u64, u64), source_loc_set: IndexSet<(FileId, u64, u64)>, } @@ -154,18 +154,23 @@ impl DebugContext { root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0))); } - let array_size_type = dwarf.unit.add(dwarf.unit.root(), gimli::DW_TAG_base_type); - let array_size_type_entry = dwarf.unit.get_mut(array_size_type); - array_size_type_entry.set( - gimli::DW_AT_name, - AttributeValue::StringRef(dwarf.strings.add("__ARRAY_SIZE_TYPE__")), - ); - array_size_type_entry - .set(gimli::DW_AT_encoding, AttributeValue::Encoding(gimli::DW_ATE_unsigned)); - array_size_type_entry.set( - gimli::DW_AT_byte_size, - AttributeValue::Udata(isa.frontend_config().pointer_bytes().into()), - ); + let array_size_type = if tcx.sess.opts.debuginfo == DebugInfo::LineTablesOnly { + None + } else { + let array_size_type = dwarf.unit.add(dwarf.unit.root(), gimli::DW_TAG_base_type); + let array_size_type_entry = dwarf.unit.get_mut(array_size_type); + array_size_type_entry.set( + gimli::DW_AT_name, + AttributeValue::StringRef(dwarf.strings.add("__ARRAY_SIZE_TYPE__")), + ); + array_size_type_entry + .set(gimli::DW_AT_encoding, AttributeValue::Encoding(gimli::DW_ATE_unsigned)); + array_size_type_entry.set( + gimli::DW_AT_byte_size, + AttributeValue::Udata(isa.frontend_config().pointer_bytes().into()), + ); + Some(array_size_type) + }; Some(DebugContext { endian, @@ -217,6 +222,14 @@ impl DebugContext { ) -> FunctionDebugContext { let (file_id, line, column) = self.get_span_loc(tcx, function_span, function_span); + if tcx.sess.opts.debuginfo == DebugInfo::LineTablesOnly { + return FunctionDebugContext { + entry_id: None, + function_source_loc: (file_id, line, column), + source_loc_set: IndexSet::new(), + }; + } + let scope = self.item_namespace(tcx, tcx.parent(instance.def_id())); let mut name = String::new(); @@ -274,7 +287,7 @@ impl DebugContext { } FunctionDebugContext { - entry_id, + entry_id: Some(entry_id), function_source_loc: (file_id, line, column), source_loc_set: IndexSet::new(), } @@ -288,6 +301,10 @@ impl DebugContext { def_id: DefId, data_id: DataId, ) { + if tcx.sess.opts.debuginfo == DebugInfo::LineTablesOnly { + return; + } + let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() }; if nested { return; @@ -353,10 +370,12 @@ impl FunctionDebugContext { .0 .push(Range::StartLength { begin: address_for_func(func_id), length: u64::from(end) }); - let func_entry = debug_context.dwarf.unit.get_mut(self.entry_id); - // Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped. - func_entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); - // Using Udata for DW_AT_high_pc requires at least DWARF4 - func_entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(end))); + if let Some(entry_id) = self.entry_id { + let entry = debug_context.dwarf.unit.get_mut(entry_id); + // Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped. + entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); + // Using Udata for DW_AT_high_pc requires at least DWARF4 + entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(end))); + } } } diff --git a/src/debuginfo/types.rs b/src/debuginfo/types.rs index a292429cdfad9..18a0632a0939d 100644 --- a/src/debuginfo/types.rs +++ b/src/debuginfo/types.rs @@ -109,7 +109,8 @@ impl DebugContext { let subrange_id = self.dwarf.unit.add(array_type_id, gimli::DW_TAG_subrange_type); let subrange_entry = self.dwarf.unit.get_mut(subrange_id); - subrange_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(self.array_size_type)); + subrange_entry + .set(gimli::DW_AT_type, AttributeValue::UnitRef(self.array_size_type.unwrap())); subrange_entry.set(gimli::DW_AT_lower_bound, AttributeValue::Udata(0)); subrange_entry.set(gimli::DW_AT_count, AttributeValue::Udata(len)); diff --git a/src/lib.rs b/src/lib.rs index 5fdecd014ac05..b47b9afa4f073 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,7 @@ use rustc_codegen_ssa::{CodegenResults, TargetConfig}; use rustc_log::tracing::info; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; -use rustc_session::config::OutputFilenames; +use rustc_session::config::{OutputFilenames, PrintKind, PrintRequest}; use rustc_span::{Symbol, sym}; use rustc_target::spec::{Abi, Arch, Env, Os}; @@ -160,6 +160,16 @@ impl CodegenBackend for CraneliftCodegenBackend { } } + fn print(&self, req: &PrintRequest, out: &mut String, _sess: &Session) { + match req.kind { + // FIXME have a default impl that returns false + PrintKind::BackendHasZstd => { + out.push_str("false\n"); + } + _ => {} + } + } + fn target_config(&self, sess: &Session) -> TargetConfig { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = match sess.target.arch { From 66381e3d790c8a5ea8f3e736e561dacb88780fdc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:11:04 +0000 Subject: [PATCH 08/36] Revert build_llvm_sysroot_for_triple back from reading the manifest to filtering Reading the manifest doesn't work when running in the context of the rust build system. --- build_system/build_sysroot.rs | 41 +++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/build_system/build_sysroot.rs b/build_system/build_sysroot.rs index e7363e37a45d0..7b4c604580c11 100644 --- a/build_system/build_sysroot.rs +++ b/build_system/build_sysroot.rs @@ -161,18 +161,35 @@ fn build_sysroot_for_triple( fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget { let default_sysroot = crate::rustc_info::get_default_sysroot(&compiler.rustc); - let std_manifest_path = default_sysroot - .join("lib") - .join("rustlib") - .join(format!("manifest-rust-std-{}", compiler.triple)); - - let libs = fs::read_to_string(std_manifest_path) - .unwrap() - .lines() - .map(|entry| default_sysroot.join(entry.strip_prefix("file:").unwrap())) - .collect(); - - SysrootTarget { triple: compiler.triple, libs } + let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] }; + + for entry in fs::read_dir( + default_sysroot.join("lib").join("rustlib").join(&target_libs.triple).join("lib"), + ) + .unwrap() + { + let entry = entry.unwrap(); + if entry.file_type().unwrap().is_dir() { + continue; + } + let file = entry.path(); + let file_name_str = file.file_name().unwrap().to_str().unwrap(); + if (file_name_str.contains("rustc_") + && !file_name_str.contains("rustc_std_workspace_") + && !file_name_str.contains("rustc_demangle") + && !file_name_str.contains("rustc_literal_escaper")) + || file_name_str.contains("chalk") + || file_name_str.contains("tracing") + || file_name_str.contains("regex") + { + // These are large crates that are part of the rustc-dev component and are not + // necessary to run regular programs. + continue; + } + target_libs.libs.push(file); + } + + target_libs } fn build_clif_sysroot_for_triple( From d38a5a6d1d3a988d43ceb247d378317d2e157c9e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 8 Dec 2025 22:41:13 +1100 Subject: [PATCH 09/36] Make `--print=backend-has-zstd` work by default on any backend Using a defaulted `CodegenBackend` method that querying for zstd support should automatically print a safe value of `false` on any backend that doesn't specifically indicate the presence or absence of zstd. --- src/lib.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b47b9afa4f073..5fdecd014ac05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,7 @@ use rustc_codegen_ssa::{CodegenResults, TargetConfig}; use rustc_log::tracing::info; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; -use rustc_session::config::{OutputFilenames, PrintKind, PrintRequest}; +use rustc_session::config::OutputFilenames; use rustc_span::{Symbol, sym}; use rustc_target::spec::{Abi, Arch, Env, Os}; @@ -160,16 +160,6 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn print(&self, req: &PrintRequest, out: &mut String, _sess: &Session) { - match req.kind { - // FIXME have a default impl that returns false - PrintKind::BackendHasZstd => { - out.push_str("false\n"); - } - _ => {} - } - } - fn target_config(&self, sess: &Session) -> TargetConfig { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] let target_features = match sess.target.arch { From 932c939c9fa2c72c313172be4ea18b1fb1afcc7a Mon Sep 17 00:00:00 2001 From: Jamie Hill-Daniel Date: Wed, 10 Dec 2025 23:41:19 +0000 Subject: [PATCH 10/36] Remove uses of `cfg(any()/all())` --- src/base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base.rs b/src/base.rs index a0bee4e182147..ac5b3c2407851 100644 --- a/src/base.rs +++ b/src/base.rs @@ -167,7 +167,7 @@ pub(crate) fn compile_fn( context.clear(); context.func = codegened_func.func; - #[cfg(any())] // This is never true + #[cfg(false)] let _clif_guard = { use std::fmt::Write; From d55b61a684a8dd525883091f7ddbeb433e6cc30b Mon Sep 17 00:00:00 2001 From: Urgau Date: Sat, 6 Dec 2025 11:31:46 +0100 Subject: [PATCH 11/36] Adapt `cg_cranelift` to the overhauled filename handling --- src/debuginfo/line_info.rs | 7 +++++-- src/debuginfo/mod.rs | 22 ++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/debuginfo/line_info.rs b/src/debuginfo/line_info.rs index db58ee8909113..12b0d5ec4963b 100644 --- a/src/debuginfo/line_info.rs +++ b/src/debuginfo/line_info.rs @@ -6,7 +6,10 @@ use std::path::{Component, Path}; use cranelift_codegen::MachSrcLoc; use cranelift_codegen::binemit::CodeOffset; use gimli::write::{FileId, FileInfo, LineProgram, LineString, LineStringTable}; -use rustc_span::{FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHashAlgorithm, hygiene}; +use rustc_span::{ + FileName, Pos, RemapPathScopeComponents, SourceFile, SourceFileAndLine, + SourceFileHashAlgorithm, hygiene, +}; use crate::debuginfo::FunctionDebugContext; use crate::debuginfo::emit::address_for_func; @@ -95,7 +98,7 @@ impl DebugContext { match &source_file.name { FileName::Real(path) => { let (dir_path, file_name) = - split_path_dir_and_file(path.to_path(self.filename_display_preference)); + split_path_dir_and_file(path.path(RemapPathScopeComponents::DEBUGINFO)); let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str()); let file_name = osstr_as_utf8_bytes(file_name); diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 8c43db92fe05f..0cd510037293d 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -21,7 +21,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdMap; use rustc_session::Session; use rustc_session::config::DebugInfo; -use rustc_span::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId}; +use rustc_span::{RemapPathScopeComponents, SourceFileHash, StableSourceFileId}; use rustc_target::callconv::FnAbi; pub(crate) use self::emit::{DebugReloc, DebugRelocName}; @@ -44,7 +44,6 @@ pub(crate) struct DebugContext { namespace_map: DefIdMap, array_size_type: Option, - filename_display_preference: FileNameDisplayPreference, embed_source: bool, } @@ -102,18 +101,18 @@ impl DebugContext { let mut dwarf = DwarfUnit::new(encoding); - use rustc_session::config::RemapPathScopeComponents; - - let filename_display_preference = - tcx.sess.filename_display_preference(RemapPathScopeComponents::DEBUGINFO); - let producer = producer(tcx.sess); - let comp_dir = - tcx.sess.opts.working_dir.to_string_lossy(filename_display_preference).to_string(); + let comp_dir = tcx + .sess + .source_map() + .working_dir() + .path(RemapPathScopeComponents::DEBUGINFO) + .to_string_lossy(); let (name, file_info) = match tcx.sess.local_crate_source_file() { Some(path) => { - let name = path.to_string_lossy(filename_display_preference).to_string(); + let name = + path.path(RemapPathScopeComponents::DEBUGINFO).to_string_lossy().into_owned(); (name, None) } None => (tcx.crate_name(LOCAL_CRATE).to_string(), None), @@ -137,7 +136,7 @@ impl DebugContext { { let name = dwarf.strings.add(format!("{name}/@/{cgu_name}")); - let comp_dir = dwarf.strings.add(comp_dir); + let comp_dir = dwarf.strings.add(&*comp_dir); let root = dwarf.unit.root(); let root = dwarf.unit.get_mut(root); @@ -180,7 +179,6 @@ impl DebugContext { stack_pointer_register, namespace_map: DefIdMap::default(), array_size_type, - filename_display_preference, embed_source, }) } From 4d011efb8e418babc9337a24791462608a39d97e Mon Sep 17 00:00:00 2001 From: Urgau <3616612+Urgau@users.noreply.github.com> Date: Fri, 12 Dec 2025 18:13:08 +0100 Subject: [PATCH 12/36] Remove `[no-mentions]` handler in the triagebot config https://github.blog/changelog/2025-11-07-removing-notifications-for-mentions-in-commit-messages/ --- triagebot.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 13da0a87def3c..eb0c7b011f605 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -2,6 +2,3 @@ # Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust) [issue-links] - -# Prevents mentions in commits to avoid users being spammed -[no-mentions] From e3f9bcef746096612567eb200f0695eaee152fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 9 Dec 2025 00:43:46 +0000 Subject: [PATCH 13/36] Use `let...else` instead of `match foo { ... _ => return };` and `if let ... else return` --- src/debuginfo/unwind.rs | 6 ++---- src/optimize/peephole.rs | 6 +----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/debuginfo/unwind.rs b/src/debuginfo/unwind.rs index ecaf88a26259e..33ffe4cc4e9c8 100644 --- a/src/debuginfo/unwind.rs +++ b/src/debuginfo/unwind.rs @@ -130,11 +130,9 @@ impl UnwindContext { return; } - let unwind_info = if let Some(unwind_info) = + let Some(unwind_info) = context.compiled_code().unwrap().create_unwind_info(module.isa()).unwrap() - { - unwind_info - } else { + else { return; }; diff --git a/src/optimize/peephole.rs b/src/optimize/peephole.rs index c93fe93521033..f38c1f96e6ed5 100644 --- a/src/optimize/peephole.rs +++ b/src/optimize/peephole.rs @@ -29,11 +29,7 @@ pub(crate) fn maybe_known_branch_taken( arg: Value, test_zero: bool, ) -> Option { - let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) { - arg_inst - } else { - return None; - }; + let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) else { return None }; match bcx.func.dfg.insts[arg_inst] { InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => { From 6a821c5518a81145048faccf619b211eb7c23c2f Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 13 Dec 2025 15:18:07 +0100 Subject: [PATCH 14/36] simplify how inline asm handles `MaybeUninit` --- src/inline_asm.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 08cabe9d695c3..ac0da06cbb8e3 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -857,19 +857,9 @@ fn call_inline_asm<'tcx>( fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option { match ty.kind() { - // Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151 + // Adapted from https://github.com/rust-lang/rust/blob/df44a57fd29fca899ce473f85ed64efd0708dd7c/compiler/rustc_hir_typeck/src/inline_asm.rs#L180-L183 ty::Adt(adt, args) if fx.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => { - let fields = &adt.non_enum_variant().fields; - let ty = fields[FieldIdx::ONE].ty(fx.tcx, args); - let ty::Adt(ty, args) = ty.kind() else { - unreachable!("expected first field of `MaybeUninit` to be an ADT") - }; - assert!( - ty.is_manually_drop(), - "expected first field of `MaybeUninit` to be `ManuallyDrop`" - ); - let fields = &ty.non_enum_variant().fields; - let ty = fields[FieldIdx::ZERO].ty(fx.tcx, args); + let ty = args.type_at(0); fx.clif_type(ty) } _ => fx.clif_type(ty), From 4748c5372077eb7ce4fc080769f974a5ea222de9 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 14 Dec 2025 05:53:13 -0500 Subject: [PATCH 15/36] Add `llvm.x86.vcvtps2ph.128` (#1613) * Add `llvm.x86.vcvtps2ph.128` * `cargo fmt` * Test `_mm_cvtps_ph` --- example/std_example.rs | 18 ++++++++++++++++++ src/intrinsics/llvm_x86.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/example/std_example.rs b/example/std_example.rs index c569ef0ef8297..33db75f0943a9 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -259,6 +259,9 @@ unsafe fn test_simd() { test_mm_cvttps_epi32(); test_mm_cvtsi128_si64(); + #[cfg(not(jit))] + test_mm_cvtps_ph(); + test_mm_extract_epi8(); test_mm_insert_epi16(); test_mm_shuffle_epi8(); @@ -558,6 +561,21 @@ unsafe fn test_mm_cvttps_epi32() { } } +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "f16c")] +#[cfg(not(jit))] +unsafe fn test_mm_cvtps_ph() { + const F16_ONE: i16 = 0x3c00; + const F16_TWO: i16 = 0x4000; + const F16_THREE: i16 = 0x4200; + const F16_FOUR: i16 = 0x4400; + + let a = _mm_set_ps(1.0, 2.0, 3.0, 4.0); + let r = _mm_cvtps_ph::<_MM_FROUND_CUR_DIRECTION>(a); + let e = _mm_set_epi16(0, 0, 0, 0, F16_ONE, F16_TWO, F16_THREE, F16_FOUR); + assert_eq_m128i(r, e); +} + fn test_checked_mul() { let u: Option = u8::from_str_radix("1000", 10).ok(); assert_eq!(u, None); diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 37fbe4be1b0fe..61f48fa977435 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -1313,6 +1313,35 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( ret.write_cvalue_transmute(fx, res); } + "llvm.x86.vcvtps2ph.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_ph + intrinsic_args!(fx, args => (a, _imm8); intrinsic); + let a = a.load_scalar(fx); + + let imm8 = + if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[1].node) { + imm8 + } else { + fx.tcx + .dcx() + .span_fatal(span, "Index argument for `_mm_cvtps_ph` is not a constant"); + }; + + let imm8 = imm8.to_u32(); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(format!("vcvtps2ph xmm0, xmm0, {imm8}").into())], + &[CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + _ => { fx.tcx .dcx() From 8d37589f37cf435d66d4fa2b6aed3ac006063a9e Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Mon, 15 Dec 2025 22:08:00 -0800 Subject: [PATCH 16/36] std_detect: AArch64 Darwin: expose SME F16F16 and B16B16 features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This synchronizes the list with the current state of `sysctl` on macOS “Tahoe” 26.2. r? @Amanieu --- library/std_detect/src/detect/os/darwin/aarch64.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std_detect/src/detect/os/darwin/aarch64.rs b/library/std_detect/src/detect/os/darwin/aarch64.rs index 8c9fd9647b8a2..a23d65a23d811 100644 --- a/library/std_detect/src/detect/os/darwin/aarch64.rs +++ b/library/std_detect/src/detect/os/darwin/aarch64.rs @@ -76,6 +76,8 @@ pub(crate) fn detect_features() -> cache::Initializer { let sme = _sysctlbyname(c"hw.optional.arm.FEAT_SME"); let sme2 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2"); let sme2p1 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2p1"); + let sme_b16b16 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_B16B16"); + let sme_f16f16 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F16F16"); let sme_f64f64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F64F64"); let sme_i16i64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_I16I64"); let ssbs = _sysctlbyname(c"hw.optional.arm.FEAT_SSBS"); @@ -153,6 +155,8 @@ pub(crate) fn detect_features() -> cache::Initializer { enable_feature(Feature::sme, sme); enable_feature(Feature::sme2, sme2); enable_feature(Feature::sme2p1, sme2p1); + enable_feature(Feature::sme_b16b16, sme_b16b16); + enable_feature(Feature::sme_f16f16, sme_f16f16); enable_feature(Feature::sme_f64f64, sme_f64f64); enable_feature(Feature::sme_i16i64, sme_i16i64); enable_feature(Feature::ssbs, ssbs); From b9839eb105204f665e8675689c49b26a3d8fdcdd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 16 Dec 2025 16:13:22 +0000 Subject: [PATCH 17/36] Rustup to rustc 1.94.0-nightly (21ff67df1 2025-12-15) --- rust-toolchain | 2 +- src/driver/jit.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index 461dbcdb0fb5d..61ef39d75ffc0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-12-08" +channel = "nightly-2025-12-16" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 9dba46363936f..3a8ca25a5fc00 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -190,7 +190,7 @@ fn dep_symbol_lookup_fn( diag.emit(); } Linkage::Dynamic => { - dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); + dylib_paths.push(src.dylib.as_ref().unwrap().clone()); } } } From b73270f189cfe1f2c4bfbf9dda70f300ee8ed0bb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 16 Dec 2025 16:40:44 +0000 Subject: [PATCH 18/36] Fix rustc test suite --- scripts/test_rustc_tests.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index b5af585a732e3..570ac434b97e2 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -70,6 +70,7 @@ rm tests/ui/linking/no-gc-encapsulation-symbols.rs # same rm tests/ui/attributes/fn-align-dyn.rs # per-function alignment not supported rm -r tests/ui/explicit-tail-calls # tail calls rm -r tests/run-make/pointer-auth-link-with-c # pointer auth +rm -r tests/ui/eii # EII not yet implemented # requires LTO rm -r tests/run-make/cdylib @@ -143,6 +144,14 @@ rm tests/ui/errors/remap-path-prefix-sysroot.rs # different sysroot source path rm -r tests/run-make/export/extern-opt # something about rustc version mismatches rm -r tests/run-make/export # same rm -r tests/ui/compiletest-self-test/compile-flags-incremental.rs # needs compiletest compiled with panic=unwind +rm tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs # something going wrong with stdlib source remapping +rm tests/ui/consts/miri_unleashed/drop.rs # same +rm tests/ui/error-emitter/multiline-removal-suggestion.rs # same +rm tests/ui/lint/lint-const-item-mutation.rs # same +rm tests/ui/lint/use-redundant/use-redundant-issue-71450.rs # same +rm tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs # same +rm tests/ui/specialization/const_trait_impl.rs # same +rm tests/ui/thir-print/offset_of.rs # same # genuine bugs # ============ From 49f1fa5110846d1ffec4e5557961a4a9a1b4334e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 16 Dec 2025 16:42:17 +0000 Subject: [PATCH 19/36] Unconditionally install rustfmt Rustfmt used to be optional for nightlies long ago, but it is now always present. Also rename rust-toolchain to rust-toolchain.toml. --- .github/workflows/main.yml | 8 ++++---- .github/workflows/rustc.yml | 4 ++-- rust-toolchain | 4 ---- rust-toolchain.toml | 4 ++++ scripts/rustup.sh | 5 ++--- 5 files changed, 12 insertions(+), 13 deletions(-) delete mode 100644 rust-toolchain create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0930b924d1773..07d9af4a9b54a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,7 +28,7 @@ jobs: - name: Avoid installing rustc-dev run: | - sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain + sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain.toml rustfmt -v - name: Rustfmt @@ -88,7 +88,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} - name: Set MinGW as the default toolchain if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' @@ -158,7 +158,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} - name: Install hyperfine run: | @@ -207,7 +207,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} - name: Set MinGW as the default toolchain if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' diff --git a/.github/workflows/rustc.yml b/.github/workflows/rustc.yml index 9253ab96353c3..b22725fdc9d41 100644 --- a/.github/workflows/rustc.yml +++ b/.github/workflows/rustc.yml @@ -20,7 +20,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }} + key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }} - name: Test run: ./scripts/test_bootstrap.sh @@ -40,7 +40,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }} + key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }} - name: Install ripgrep run: | diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 61ef39d75ffc0..0000000000000 --- a/rust-toolchain +++ /dev/null @@ -1,4 +0,0 @@ -[toolchain] -channel = "nightly-2025-12-16" -components = ["rust-src", "rustc-dev", "llvm-tools"] -profile = "minimal" diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000000000..4d3fe30e7d47a --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2025-12-16" +components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] +profile = "minimal" diff --git a/scripts/rustup.sh b/scripts/rustup.sh index 1a82193303e23..e26be307328f0 100755 --- a/scripts/rustup.sh +++ b/scripts/rustup.sh @@ -22,8 +22,7 @@ case $1 in "prepare") echo "=> Installing new nightly" rustup toolchain install --profile minimal "nightly-${TOOLCHAIN}" # Sanity check to see if the nightly exists - sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain - rustup component add rustfmt || true + sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain.toml echo "=> Uninstalling all old nightlies" for nightly in $(rustup toolchain list | grep nightly | grep -v "$TOOLCHAIN" | grep -v nightly-x86_64); do @@ -35,7 +34,7 @@ case $1 in ./y.sh prepare ;; "commit") - git add rust-toolchain + git add rust-toolchain.toml git commit -m "Rustup to $(rustc -V)" ;; "push") From bb9dac5fe5889f6c4cfb373388ca0e54413429f9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 16 Dec 2025 16:49:44 +0000 Subject: [PATCH 20/36] Disable linker plugin lto rustc test --- scripts/test_rustc_tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 570ac434b97e2..09de603efa117 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -79,6 +79,7 @@ rm -r tests/run-make/lto-* rm -r tests/run-make/reproducible-build-2 rm -r tests/run-make/no-builtins-lto rm -r tests/run-make/reachable-extern-fn-available-lto +rm -r tests/run-make/no-builtins-linker-plugin-lto # coverage instrumentation rm tests/ui/consts/precise-drop-with-coverage.rs From 3822cf126bf004c9c9a5db6609f32e7758ea3427 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 16 Dec 2025 17:00:09 +0000 Subject: [PATCH 21/36] Disable a bunch of rustc tests that fail with --panic-unwind-support --- scripts/test_rustc_tests.sh | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 09de603efa117..69c6099c3ab86 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -53,17 +53,21 @@ rm tests/ui/sanitizer/kcfi-c-variadic.rs # same rm tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs # variadics for calling conventions other than C unsupported rm tests/ui/delegation/fn-header.rs +# inline assembly features +rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly +rm tests/ui/asm/global-asm-mono-sym-fn.rs # same +rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same +rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported +rm tests/ui/asm/label-operand.rs # same +rm tests/ui/asm/may_unwind.rs # asm unwinding not supported +rm tests/ui/asm/aarch64/may_unwind.rs # same + # misc unimplemented things rm tests/ui/target-feature/missing-plusminus.rs # error not implemented rm -r tests/run-make/repr128-dwarf # debuginfo test rm -r tests/run-make/split-debuginfo # same rm -r tests/run-make/target-specs # i686 not supported by Cranelift rm -r tests/run-make/mismatching-target-triples # same -rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly -rm tests/ui/asm/global-asm-mono-sym-fn.rs # same -rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same -rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported -rm tests/ui/asm/label-operand.rs # same rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes rm -r tests/run-make/used-proc-macro # used(linker) isn't supported yet rm tests/ui/linking/no-gc-encapsulation-symbols.rs # same @@ -71,6 +75,7 @@ rm tests/ui/attributes/fn-align-dyn.rs # per-function alignment not supported rm -r tests/ui/explicit-tail-calls # tail calls rm -r tests/run-make/pointer-auth-link-with-c # pointer auth rm -r tests/ui/eii # EII not yet implemented +rm -r tests/run-make/forced-unwind-terminate-pof # forced unwinding doesn't take precedence # requires LTO rm -r tests/run-make/cdylib @@ -89,6 +94,7 @@ rm -r tests/ui/instrument-coverage/ # ================== rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations rm tests/ui/codegen/init-large-type.rs # same +rm tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs # same rm tests/ui/statics/const_generics.rs # tests an optimization rm tests/ui/linking/executable-no-mangle-strip.rs # requires --gc-sections to work for statics @@ -167,6 +173,7 @@ rm tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs # same rm tests/ui/async-await/async-drop/async-drop-initial.rs # same (rust-lang/rust#140493) rm -r tests/ui/codegen/equal-pointers-unequal # make incorrect assumptions about the location of stack variables rm -r tests/run-make-cargo/rustdoc-scrape-examples-paths # FIXME(rust-lang/rust#145580) incr comp bug +rm -r tests/incremental/extern_static/issue-49153.rs # assumes reference to undefined static gets optimized away rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # really slow with unoptimized libstd rm tests/ui/process/process-panic-after-fork.rs # same From 60b616d3382b15b07c16db48edf5993254b7fc4d Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Wed, 17 Dec 2025 11:20:44 +0100 Subject: [PATCH 22/36] tests/run-make-cargo/same-crate-name-and-macro-name: New regression test --- .../consumer/Cargo.toml | 10 ++++++++++ .../consumer/src/main.rs | 7 +++++++ .../mylib_v1/Cargo.toml | 6 ++++++ .../mylib_v1/src/lib.rs | 6 ++++++ .../mylib_v2/Cargo.toml | 6 ++++++ .../mylib_v2/src/lib.rs | 6 ++++++ .../same-crate-name-and-macro-name/rmake.rs | 13 +++++++++++++ 7 files changed, 54 insertions(+) create mode 100644 tests/run-make-cargo/same-crate-name-and-macro-name/consumer/Cargo.toml create mode 100644 tests/run-make-cargo/same-crate-name-and-macro-name/consumer/src/main.rs create mode 100644 tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/Cargo.toml create mode 100644 tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/src/lib.rs create mode 100644 tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/Cargo.toml create mode 100644 tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/src/lib.rs create mode 100644 tests/run-make-cargo/same-crate-name-and-macro-name/rmake.rs diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/Cargo.toml b/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/Cargo.toml new file mode 100644 index 0000000000000..870d333da3a4f --- /dev/null +++ b/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "consumer" +version = "0.1.0" + +[dependencies] +mylib_v1 = { path = "../mylib_v1", package = "mylib" } +mylib_v2 = { path = "../mylib_v2", package = "mylib" } + +# Avoid interference with root workspace when casually testing +[workspace] diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/src/main.rs b/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/src/main.rs new file mode 100644 index 0000000000000..80e76ae281171 --- /dev/null +++ b/tests/run-make-cargo/same-crate-name-and-macro-name/consumer/src/main.rs @@ -0,0 +1,7 @@ +fn main() { + let v1 = mylib_v1::my_macro!(); + assert_eq!(v1, "version 1"); + + let v2 = mylib_v2::my_macro!(); + assert_eq!(v2, "version 2"); +} diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/Cargo.toml b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/Cargo.toml new file mode 100644 index 0000000000000..69f80bfc89ed6 --- /dev/null +++ b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "mylib" +version = "1.0.0" + +# Avoid interference with root workspace when casually testing +[workspace] diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/src/lib.rs b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/src/lib.rs new file mode 100644 index 0000000000000..0603b754ea82c --- /dev/null +++ b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v1/src/lib.rs @@ -0,0 +1,6 @@ +#[macro_export] +macro_rules! my_macro { + () => { + "version 1" + }; +} diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/Cargo.toml b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/Cargo.toml new file mode 100644 index 0000000000000..f164616393ba1 --- /dev/null +++ b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "mylib" +version = "2.0.0" + +# Avoid interference with root workspace when casually testing +[workspace] diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/src/lib.rs b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/src/lib.rs new file mode 100644 index 0000000000000..352c7c514f832 --- /dev/null +++ b/tests/run-make-cargo/same-crate-name-and-macro-name/mylib_v2/src/lib.rs @@ -0,0 +1,6 @@ +#[macro_export] +macro_rules! my_macro { + () => { + "version 2" + }; +} diff --git a/tests/run-make-cargo/same-crate-name-and-macro-name/rmake.rs b/tests/run-make-cargo/same-crate-name-and-macro-name/rmake.rs new file mode 100644 index 0000000000000..cce98cebb8044 --- /dev/null +++ b/tests/run-make-cargo/same-crate-name-and-macro-name/rmake.rs @@ -0,0 +1,13 @@ +//! Regression test for +//! +//! (that particular comment describes the issue well). +//! +//! We test that two library crates with the same name can export macros with +//! the same name without causing interference when both are used in another +//! crate. + +use run_make_support::cargo; + +fn main() { + cargo().current_dir("consumer").arg("run").run(); +} From cb301751b3ade3cf65f1d3eeb0c94ffce1a45561 Mon Sep 17 00:00:00 2001 From: delta17920 Date: Sat, 13 Dec 2025 15:18:34 +0000 Subject: [PATCH 23/36] Suggest struct pattern when destructuring Range with .. syntax --- .../rustc_resolve/src/late/diagnostics.rs | 36 ++++++++++ .../suggest-range-struct-destructuring.rs | 15 +++++ .../suggest-range-struct-destructuring.stderr | 66 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 tests/ui/resolve/suggest-range-struct-destructuring.rs create mode 100644 tests/ui/resolve/suggest-range-struct-destructuring.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 233a4c48862ac..0348764009b28 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -440,6 +440,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg); self.suggest_at_operator_in_slice_pat_with_range(&mut err, path); + self.suggest_range_struct_destructuring(&mut err, path, source); self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span); if let Some((span, label)) = base_error.span_label { @@ -1383,6 +1384,41 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + fn suggest_range_struct_destructuring( + &self, + err: &mut Diag<'_>, + path: &[Segment], + source: PathSource<'_, '_, '_>, + ) { + // We accept Expr here because range bounds (start..end) are parsed as expressions + if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) { + return; + } + + if let Some(pat) = self.diag_metadata.current_pat + && let ast::PatKind::Range(Some(start_expr), Some(end_expr), _) = &pat.kind + && let (ast::ExprKind::Path(None, start_path), ast::ExprKind::Path(None, end_path)) = + (&start_expr.kind, &end_expr.kind) + && path.len() == 1 + { + let ident = path[0].ident; + + if (start_path.segments.len() == 1 && start_path.segments[0].ident == ident) + || (end_path.segments.len() == 1 && end_path.segments[0].ident == ident) + { + let start_name = start_path.segments[0].ident; + let end_name = end_path.segments[0].ident; + + err.span_suggestion_verbose( + pat.span, + "if you meant to destructure a `Range`, use the struct pattern", + format!("std::ops::Range {{ start: {}, end: {} }}", start_name, end_name), + Applicability::MaybeIncorrect, + ); + } + } + } + fn suggest_swapping_misplaced_self_ty_and_trait( &mut self, err: &mut Diag<'_>, diff --git a/tests/ui/resolve/suggest-range-struct-destructuring.rs b/tests/ui/resolve/suggest-range-struct-destructuring.rs new file mode 100644 index 0000000000000..f690a7cad23f2 --- /dev/null +++ b/tests/ui/resolve/suggest-range-struct-destructuring.rs @@ -0,0 +1,15 @@ +use std::ops::Range; + +fn test_basic_range(r: Range) { + let start..end = r; + //~^ ERROR cannot find value `start` in this scope + //~| ERROR cannot find value `end` in this scope +} + +fn test_different_names(r: Range) { + let min..max = r; + //~^ ERROR cannot find value `min` in this scope + //~| ERROR cannot find value `max` in this scope +} + +fn main() {} diff --git a/tests/ui/resolve/suggest-range-struct-destructuring.stderr b/tests/ui/resolve/suggest-range-struct-destructuring.stderr new file mode 100644 index 0000000000000..291abf0d01d3f --- /dev/null +++ b/tests/ui/resolve/suggest-range-struct-destructuring.stderr @@ -0,0 +1,66 @@ +error[E0425]: cannot find value `start` in this scope + --> $DIR/suggest-range-struct-destructuring.rs:4:9 + | +LL | let start..end = r; + | ^^^^^ not found in this scope + | +help: if you meant to destructure a `Range`, use the struct pattern + | +LL - let start..end = r; +LL + let std::ops::Range { start: start, end: end } = r; + | + +error[E0425]: cannot find value `end` in this scope + --> $DIR/suggest-range-struct-destructuring.rs:4:16 + | +LL | let start..end = r; + | ^^^ not found in this scope + | +help: if you meant to destructure a `Range`, use the struct pattern + | +LL - let start..end = r; +LL + let std::ops::Range { start: start, end: end } = r; + | + +error[E0425]: cannot find value `min` in this scope + --> $DIR/suggest-range-struct-destructuring.rs:10:9 + | +LL | let min..max = r; + | ^^^ +... +LL | fn main() {} + | --------- similarly named function `main` defined here + | +help: if you meant to destructure a `Range`, use the struct pattern + | +LL - let min..max = r; +LL + let std::ops::Range { start: min, end: max } = r; + | +help: a function with a similar name exists + | +LL | let main..max = r; + | + +help: consider importing this function + | +LL + use std::cmp::min; + | + +error[E0425]: cannot find value `max` in this scope + --> $DIR/suggest-range-struct-destructuring.rs:10:14 + | +LL | let min..max = r; + | ^^^ not found in this scope + | +help: if you meant to destructure a `Range`, use the struct pattern + | +LL - let min..max = r; +LL + let std::ops::Range { start: min, end: max } = r; + | +help: consider importing this function + | +LL + use std::cmp::max; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0425`. From 3e78653ec32342708b70268e179dfcaad02f4d4e Mon Sep 17 00:00:00 2001 From: delta17920 Date: Sun, 14 Dec 2025 04:04:53 +0000 Subject: [PATCH 24/36] Fix grammar in suggestion message --- compiler/rustc_resolve/src/late/diagnostics.rs | 2 +- .../ui/resolve/suggest-range-struct-destructuring.stderr | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 0348764009b28..85e8917ae32e8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1411,7 +1411,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err.span_suggestion_verbose( pat.span, - "if you meant to destructure a `Range`, use the struct pattern", + "if you meant to destructure a `Range`, use a struct pattern", format!("std::ops::Range {{ start: {}, end: {} }}", start_name, end_name), Applicability::MaybeIncorrect, ); diff --git a/tests/ui/resolve/suggest-range-struct-destructuring.stderr b/tests/ui/resolve/suggest-range-struct-destructuring.stderr index 291abf0d01d3f..1a11e6ac84219 100644 --- a/tests/ui/resolve/suggest-range-struct-destructuring.stderr +++ b/tests/ui/resolve/suggest-range-struct-destructuring.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find value `start` in this scope LL | let start..end = r; | ^^^^^ not found in this scope | -help: if you meant to destructure a `Range`, use the struct pattern +help: if you meant to destructure a `Range`, use a struct pattern | LL - let start..end = r; LL + let std::ops::Range { start: start, end: end } = r; @@ -16,7 +16,7 @@ error[E0425]: cannot find value `end` in this scope LL | let start..end = r; | ^^^ not found in this scope | -help: if you meant to destructure a `Range`, use the struct pattern +help: if you meant to destructure a `Range`, use a struct pattern | LL - let start..end = r; LL + let std::ops::Range { start: start, end: end } = r; @@ -31,7 +31,7 @@ LL | let min..max = r; LL | fn main() {} | --------- similarly named function `main` defined here | -help: if you meant to destructure a `Range`, use the struct pattern +help: if you meant to destructure a `Range`, use a struct pattern | LL - let min..max = r; LL + let std::ops::Range { start: min, end: max } = r; @@ -51,7 +51,7 @@ error[E0425]: cannot find value `max` in this scope LL | let min..max = r; | ^^^ not found in this scope | -help: if you meant to destructure a `Range`, use the struct pattern +help: if you meant to destructure a `Range`, use a struct pattern | LL - let min..max = r; LL + let std::ops::Range { start: min, end: max } = r; From 6fac0fac9962962f77f46fe148bbca2ed6b60f59 Mon Sep 17 00:00:00 2001 From: delta17920 Date: Sun, 14 Dec 2025 15:08:01 +0000 Subject: [PATCH 25/36] Apply review suggestions --- .../rustc_resolve/src/late/diagnostics.rs | 85 +++++++++---- tests/ui/match/issue-92100.stderr | 6 + ...tern-meant-to-be-slice-rest-pattern.stderr | 18 +++ .../suggest-range-struct-destructuring.rs | 41 ++++-- .../suggest-range-struct-destructuring.stderr | 117 +++++++++++++----- tests/ui/typeck/issue-105946.stderr | 6 + 6 files changed, 216 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 85e8917ae32e8..f75ac400dc0ba 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1385,38 +1385,81 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_range_struct_destructuring( - &self, + &mut self, err: &mut Diag<'_>, path: &[Segment], source: PathSource<'_, '_, '_>, ) { - // We accept Expr here because range bounds (start..end) are parsed as expressions if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) { return; } - if let Some(pat) = self.diag_metadata.current_pat - && let ast::PatKind::Range(Some(start_expr), Some(end_expr), _) = &pat.kind - && let (ast::ExprKind::Path(None, start_path), ast::ExprKind::Path(None, end_path)) = - (&start_expr.kind, &end_expr.kind) - && path.len() == 1 - { - let ident = path[0].ident; + let Some(pat) = self.diag_metadata.current_pat else { return }; + let ast::PatKind::Range(start, end, end_kind) = &pat.kind else { return }; - if (start_path.segments.len() == 1 && start_path.segments[0].ident == ident) - || (end_path.segments.len() == 1 && end_path.segments[0].ident == ident) - { - let start_name = start_path.segments[0].ident; - let end_name = end_path.segments[0].ident; + let [segment] = path else { return }; + let failing_span = segment.ident.span; - err.span_suggestion_verbose( - pat.span, - "if you meant to destructure a `Range`, use a struct pattern", - format!("std::ops::Range {{ start: {}, end: {} }}", start_name, end_name), - Applicability::MaybeIncorrect, - ); - } + let in_start = start.as_ref().is_some_and(|e| e.span.contains(failing_span)); + let in_end = end.as_ref().is_some_and(|e| e.span.contains(failing_span)); + + if !in_start && !in_end { + return; } + + let start_snippet = + start.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok()); + let end_snippet = + end.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok()); + + let field = |name: &str, val: String| { + if val == name { val } else { format!("{name}: {val}") } + }; + + let mut resolve_short_name = |short: Symbol, full: &str| -> String { + let ident = Ident::with_dummy_span(short); + let path = Segment::from_path(&Path::from_ident(ident)); + + match self.resolve_path(&path, Some(TypeNS), None, PathSource::Type) { + PathResult::NonModule(..) => short.to_string(), + _ => full.to_string(), + } + }; + // FIXME(new_range): Also account for new range types + let (struct_path, fields) = match (start_snippet, end_snippet, &end_kind.node) { + (Some(start), Some(end), ast::RangeEnd::Excluded) => ( + resolve_short_name(sym::Range, "std::ops::Range"), + vec![field("start", start), field("end", end)], + ), + (Some(start), Some(end), ast::RangeEnd::Included(_)) => ( + resolve_short_name(sym::RangeInclusive, "std::ops::RangeInclusive"), + vec![field("start", start), field("end", end)], + ), + (Some(start), None, _) => ( + resolve_short_name(sym::RangeFrom, "std::ops::RangeFrom"), + vec![field("start", start)], + ), + (None, Some(end), ast::RangeEnd::Excluded) => { + (resolve_short_name(sym::RangeTo, "std::ops::RangeTo"), vec![field("end", end)]) + } + (None, Some(end), ast::RangeEnd::Included(_)) => ( + resolve_short_name(sym::RangeToInclusive, "std::ops::RangeToInclusive"), + vec![field("end", end)], + ), + _ => return, + }; + + err.span_suggestion_verbose( + pat.span, + format!("if you meant to destructure a range use a struct pattern"), + format!("{} {{ {} }}", struct_path, fields.join(", ")), + Applicability::MaybeIncorrect, + ); + + err.note( + "range patterns match against the start and end of a range; \ + to bind the components, use a struct pattern", + ); } fn suggest_swapping_misplaced_self_ty_and_trait( diff --git a/tests/ui/match/issue-92100.stderr b/tests/ui/match/issue-92100.stderr index eb9f4ba1ad698..13aacc4782af2 100644 --- a/tests/ui/match/issue-92100.stderr +++ b/tests/ui/match/issue-92100.stderr @@ -4,10 +4,16 @@ error[E0425]: cannot find value `a` in this scope LL | [a.., a] => {} | ^ not found in this scope | + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern help: if you meant to collect the rest of the slice in `a`, use the at operator | LL | [a @ .., a] => {} | + +help: if you meant to destructure a range use a struct pattern + | +LL - [a.., a] => {} +LL + [std::ops::RangeFrom { start: a }, a] => {} + | error: aborting due to 1 previous error diff --git a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr index 37b2d96bb0194..378ff04d3a1af 100644 --- a/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr +++ b/tests/ui/pattern/range-pattern-meant-to-be-slice-rest-pattern.stderr @@ -16,10 +16,16 @@ error[E0425]: cannot find value `rest` in this scope LL | [1, rest..] => println!("{rest}"), | ^^^^ not found in this scope | + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern help: if you meant to collect the rest of the slice in `rest`, use the at operator | LL | [1, rest @ ..] => println!("{rest}"), | + +help: if you meant to destructure a range use a struct pattern + | +LL - [1, rest..] => println!("{rest}"), +LL + [1, std::ops::RangeFrom { start: rest }] => println!("{rest}"), + | error[E0425]: cannot find value `rest` in this scope --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:35 @@ -33,11 +39,17 @@ error[E0425]: cannot find value `tail` in this scope LL | [_, ..tail] => println!("{tail}"), | ^^^^ not found in this scope | + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern help: if you meant to collect the rest of the slice in `tail`, use the at operator | LL - [_, ..tail] => println!("{tail}"), LL + [_, tail @ ..] => println!("{tail}"), | +help: if you meant to destructure a range use a struct pattern + | +LL - [_, ..tail] => println!("{tail}"), +LL + [_, std::ops::RangeTo { end: tail }] => println!("{tail}"), + | error[E0425]: cannot find value `tail` in this scope --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:35 @@ -51,11 +63,17 @@ error[E0425]: cannot find value `tail` in this scope LL | [_, ...tail] => println!("{tail}"), | ^^^^ not found in this scope | + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern help: if you meant to collect the rest of the slice in `tail`, use the at operator | LL - [_, ...tail] => println!("{tail}"), LL + [_, tail @ ..] => println!("{tail}"), | +help: if you meant to destructure a range use a struct pattern + | +LL - [_, ...tail] => println!("{tail}"), +LL + [_, std::ops::RangeToInclusive { end: tail }] => println!("{tail}"), + | error[E0425]: cannot find value `tail` in this scope --> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:17:36 diff --git a/tests/ui/resolve/suggest-range-struct-destructuring.rs b/tests/ui/resolve/suggest-range-struct-destructuring.rs index f690a7cad23f2..ee8a99ceaa1a3 100644 --- a/tests/ui/resolve/suggest-range-struct-destructuring.rs +++ b/tests/ui/resolve/suggest-range-struct-destructuring.rs @@ -1,15 +1,40 @@ -use std::ops::Range; +use std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive}; -fn test_basic_range(r: Range) { +fn test_range(r: Range) { let start..end = r; - //~^ ERROR cannot find value `start` in this scope - //~| ERROR cannot find value `end` in this scope + //~^ ERROR cannot find value `start` + //~| ERROR cannot find value `end` } -fn test_different_names(r: Range) { - let min..max = r; - //~^ ERROR cannot find value `min` in this scope - //~| ERROR cannot find value `max` in this scope +fn test_inclusive(r: RangeInclusive) { + let start..=end = r; + //~^ ERROR cannot find value `start` + //~| ERROR cannot find value `end` +} + +fn test_from(r: RangeFrom) { + let start.. = r; + //~^ ERROR cannot find value `start` +} + +fn test_to(r: RangeTo) { + let ..end = r; + //~^ ERROR cannot find value `end` +} + +fn test_to_inclusive(r: RangeToInclusive) { + let ..=end = r; + //~^ ERROR cannot find value `end` +} + +// Case 6: Complex Path (Keep this! It works!) +mod my { + // We don't define MISSING here to trigger the error +} +fn test_path(r: Range) { + let my::MISSING..end = r; + //~^ ERROR cannot find value `MISSING` + //~| ERROR cannot find value `end` } fn main() {} diff --git a/tests/ui/resolve/suggest-range-struct-destructuring.stderr b/tests/ui/resolve/suggest-range-struct-destructuring.stderr index 1a11e6ac84219..78a248ed777d1 100644 --- a/tests/ui/resolve/suggest-range-struct-destructuring.stderr +++ b/tests/ui/resolve/suggest-range-struct-destructuring.stderr @@ -4,10 +4,11 @@ error[E0425]: cannot find value `start` in this scope LL | let start..end = r; | ^^^^^ not found in this scope | -help: if you meant to destructure a `Range`, use a struct pattern + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern +help: if you meant to destructure a range use a struct pattern | LL - let start..end = r; -LL + let std::ops::Range { start: start, end: end } = r; +LL + let Range { start, end } = r; | error[E0425]: cannot find value `end` in this scope @@ -16,51 +17,111 @@ error[E0425]: cannot find value `end` in this scope LL | let start..end = r; | ^^^ not found in this scope | -help: if you meant to destructure a `Range`, use a struct pattern + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern +help: if you meant to destructure a range use a struct pattern | LL - let start..end = r; -LL + let std::ops::Range { start: start, end: end } = r; +LL + let Range { start, end } = r; | -error[E0425]: cannot find value `min` in this scope +error[E0425]: cannot find value `start` in this scope --> $DIR/suggest-range-struct-destructuring.rs:10:9 | -LL | let min..max = r; - | ^^^ -... -LL | fn main() {} - | --------- similarly named function `main` defined here +LL | let start..=end = r; + | ^^^^^ not found in this scope + | + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern +help: if you meant to destructure a range use a struct pattern + | +LL - let start..=end = r; +LL + let RangeInclusive { start, end } = r; + | + +error[E0425]: cannot find value `end` in this scope + --> $DIR/suggest-range-struct-destructuring.rs:10:17 + | +LL | let start..=end = r; + | ^^^ not found in this scope + | + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern +help: if you meant to destructure a range use a struct pattern + | +LL - let start..=end = r; +LL + let RangeInclusive { start, end } = r; + | + +error[E0425]: cannot find value `start` in this scope + --> $DIR/suggest-range-struct-destructuring.rs:16:9 + | +LL | let start.. = r; + | ^^^^^ not found in this scope + | + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern +help: if you meant to collect the rest of the slice in `start`, use the at operator + | +LL | let start @ .. = r; + | + +help: if you meant to destructure a range use a struct pattern + | +LL - let start.. = r; +LL + let RangeFrom { start } = r; + | + +error[E0425]: cannot find value `end` in this scope + --> $DIR/suggest-range-struct-destructuring.rs:21:11 | -help: if you meant to destructure a `Range`, use a struct pattern +LL | let ..end = r; + | ^^^ not found in this scope | -LL - let min..max = r; -LL + let std::ops::Range { start: min, end: max } = r; + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern +help: if you meant to collect the rest of the slice in `end`, use the at operator | -help: a function with a similar name exists +LL - let ..end = r; +LL + let end @ .. = r; | -LL | let main..max = r; - | + -help: consider importing this function +help: if you meant to destructure a range use a struct pattern | -LL + use std::cmp::min; +LL - let ..end = r; +LL + let RangeTo { end } = r; | -error[E0425]: cannot find value `max` in this scope - --> $DIR/suggest-range-struct-destructuring.rs:10:14 +error[E0425]: cannot find value `end` in this scope + --> $DIR/suggest-range-struct-destructuring.rs:26:12 + | +LL | let ..=end = r; + | ^^^ not found in this scope | -LL | let min..max = r; - | ^^^ not found in this scope + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern +help: if you meant to collect the rest of the slice in `end`, use the at operator | -help: if you meant to destructure a `Range`, use a struct pattern +LL - let ..=end = r; +LL + let end @ .. = r; + | +help: if you meant to destructure a range use a struct pattern + | +LL - let ..=end = r; +LL + let RangeToInclusive { end } = r; + | + +error[E0425]: cannot find value `MISSING` in module `my` + --> $DIR/suggest-range-struct-destructuring.rs:35:13 + | +LL | let my::MISSING..end = r; + | ^^^^^^^ not found in `my` + +error[E0425]: cannot find value `end` in this scope + --> $DIR/suggest-range-struct-destructuring.rs:35:22 | -LL - let min..max = r; -LL + let std::ops::Range { start: min, end: max } = r; +LL | let my::MISSING..end = r; + | ^^^ not found in this scope | -help: consider importing this function + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern +help: if you meant to destructure a range use a struct pattern | -LL + use std::cmp::max; +LL - let my::MISSING..end = r; +LL + let Range { start: my::MISSING, end } = r; | -error: aborting due to 4 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/typeck/issue-105946.stderr b/tests/ui/typeck/issue-105946.stderr index 30fe2000a4619..3f8733bda7631 100644 --- a/tests/ui/typeck/issue-105946.stderr +++ b/tests/ui/typeck/issue-105946.stderr @@ -4,10 +4,16 @@ error[E0425]: cannot find value `_y` in this scope LL | let [_y..] = [Box::new(1), Box::new(2)]; | ^^ not found in this scope | + = note: range patterns match against the start and end of a range; to bind the components, use a struct pattern help: if you meant to collect the rest of the slice in `_y`, use the at operator | LL | let [_y @ ..] = [Box::new(1), Box::new(2)]; | + +help: if you meant to destructure a range use a struct pattern + | +LL - let [_y..] = [Box::new(1), Box::new(2)]; +LL + let [std::ops::RangeFrom { start: _y }] = [Box::new(1), Box::new(2)]; + | error[E0658]: `X..` patterns in slices are experimental --> $DIR/issue-105946.rs:7:10 From bd137df64a4a9af48f7e107f4a488787fce3f51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 17 Dec 2025 14:23:13 +0100 Subject: [PATCH 26/36] test for duplicate default eii ICE 149985 Co-authored-by: SATVIKsynopsis --- tests/ui/eii/default/multiple-default-impls.rs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/ui/eii/default/multiple-default-impls.rs diff --git a/tests/ui/eii/default/multiple-default-impls.rs b/tests/ui/eii/default/multiple-default-impls.rs new file mode 100644 index 0000000000000..8a91feec382da --- /dev/null +++ b/tests/ui/eii/default/multiple-default-impls.rs @@ -0,0 +1,8 @@ +#![crate_type = "lib"] +#![feature(extern_item_impls)] + +#[eii(eii1)] +fn a() {} + +#[eii(eii1)] +fn b() {} From 1cd7cb1e8d5cfcf64942222091dae67725bb1951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 17 Dec 2025 17:53:07 +0100 Subject: [PATCH 27/36] turn panic into span_delayed_bug --- compiler/rustc_passes/src/eii.rs | 3 ++- tests/ui/eii/default/multiple-default-impls.rs | 10 ++++++++++ tests/ui/eii/default/multiple-default-impls.stderr | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/ui/eii/default/multiple-default-impls.stderr diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index 691576e6a05fc..ab3f9f0d21825 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -116,7 +116,8 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, (): } if default_impls.len() > 1 { - panic!("multiple not supported right now"); + let decl_span = tcx.def_ident_span(decl_did).unwrap(); + tcx.dcx().span_delayed_bug(decl_span, "multiple not supported right now"); } let (local_impl, is_default) = diff --git a/tests/ui/eii/default/multiple-default-impls.rs b/tests/ui/eii/default/multiple-default-impls.rs index 8a91feec382da..8d2ad0c1e1378 100644 --- a/tests/ui/eii/default/multiple-default-impls.rs +++ b/tests/ui/eii/default/multiple-default-impls.rs @@ -1,8 +1,18 @@ #![crate_type = "lib"] #![feature(extern_item_impls)] +// `eii` expands to, among other things, `macro eii() {}`. +// If we have two eiis named the same thing, we have a duplicate definition +// for that macro. The compiler happily continues compiling on duplicate +// definitions though, to emit as many diagnostics as possible. +// However, in the case of eiis, this can break the assumption that every +// eii has only one default implementation, since the default for both eiis will +// name resolve to the same eii definiton (since the other definition was duplicate) +// This test tests for the previously-ICE that occurred when this assumption +// (of 1 default) was broken which was reported in #149982. #[eii(eii1)] fn a() {} #[eii(eii1)] +//~^ ERROR the name `eii1` is defined multiple times fn b() {} diff --git a/tests/ui/eii/default/multiple-default-impls.stderr b/tests/ui/eii/default/multiple-default-impls.stderr new file mode 100644 index 0000000000000..b270b2346cd50 --- /dev/null +++ b/tests/ui/eii/default/multiple-default-impls.stderr @@ -0,0 +1,14 @@ +error[E0428]: the name `eii1` is defined multiple times + --> $DIR/multiple-default-impls.rs:16:1 + | +LL | #[eii(eii1)] + | ------------ previous definition of the macro `eii1` here +... +LL | #[eii(eii1)] + | ^^^^^^^^^^^^ `eii1` redefined here + | + = note: `eii1` must be defined only once in the macro namespace of this module + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0428`. From 08b7d34e06832250d3b1c8a4bf5ec78fbbae12a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 17 Dec 2025 17:57:04 +0100 Subject: [PATCH 28/36] another related case that deserved a test --- .../multiple-default-impls-same-name.rs | 19 ++++++++++++++ .../multiple-default-impls-same-name.stderr | 25 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/ui/eii/default/multiple-default-impls-same-name.rs create mode 100644 tests/ui/eii/default/multiple-default-impls-same-name.stderr diff --git a/tests/ui/eii/default/multiple-default-impls-same-name.rs b/tests/ui/eii/default/multiple-default-impls-same-name.rs new file mode 100644 index 0000000000000..080e0a46b7557 --- /dev/null +++ b/tests/ui/eii/default/multiple-default-impls-same-name.rs @@ -0,0 +1,19 @@ +#![crate_type = "lib"] +#![feature(extern_item_impls)] +// `eii` expands to, among other things, `macro eii() {}`. +// If we have two eiis named the same thing, we have a duplicate definition +// for that macro. The compiler happily continues compiling on duplicate +// definitions though, to emit as many diagnostics as possible. +// However, in the case of eiis, this can break the assumption that every +// eii has only one default implementation, since the default for both eiis will +// name resolve to the same eii definiton (since the other definition was duplicate) +// This test tests for the previously-ICE that occurred when this assumption +// (of 1 default) was broken which was reported in #149982. + +#[eii(eii1)] +fn a() {} + +#[eii(eii1)] +//~^ ERROR the name `eii1` is defined multiple times +fn a() {} +//~^ ERROR the name `a` is defined multiple times diff --git a/tests/ui/eii/default/multiple-default-impls-same-name.stderr b/tests/ui/eii/default/multiple-default-impls-same-name.stderr new file mode 100644 index 0000000000000..20544fcfeeba5 --- /dev/null +++ b/tests/ui/eii/default/multiple-default-impls-same-name.stderr @@ -0,0 +1,25 @@ +error[E0428]: the name `a` is defined multiple times + --> $DIR/multiple-default-impls-same-name.rs:18:1 + | +LL | fn a() {} + | ------ previous definition of the value `a` here +... +LL | fn a() {} + | ^^^^^^ `a` redefined here + | + = note: `a` must be defined only once in the value namespace of this module + +error[E0428]: the name `eii1` is defined multiple times + --> $DIR/multiple-default-impls-same-name.rs:16:1 + | +LL | #[eii(eii1)] + | ------------ previous definition of the macro `eii1` here +... +LL | #[eii(eii1)] + | ^^^^^^^^^^^^ `eii1` redefined here + | + = note: `eii1` must be defined only once in the macro namespace of this module + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0428`. From 82ee8b21cb66364792f4103616a2368847fb5421 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 12 Dec 2025 17:37:39 +0100 Subject: [PATCH 29/36] `cfg_select!`: emit parse errors in unused branches --- .../src/attributes/cfg_select.rs | 27 ++++++ .../rustc_builtin_macros/src/cfg_select.rs | 78 +++++++++++++---- tests/ui/macros/cfg_select.rs | 83 +++++++++++++++++++ tests/ui/macros/cfg_select.stderr | 24 +++--- tests/ui/macros/cfg_select_parse_error.rs | 18 ++++ tests/ui/macros/cfg_select_parse_error.stderr | 26 ++++++ 6 files changed, 228 insertions(+), 28 deletions(-) create mode 100644 tests/ui/macros/cfg_select_parse_error.rs create mode 100644 tests/ui/macros/cfg_select_parse_error.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index 0c0915558089e..00a2d12106e76 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -28,6 +28,33 @@ pub struct CfgSelectBranches { pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>, } +impl CfgSelectBranches { + /// Removes the top-most branch for which `predicate` returns `true`, + /// or the wildcard if none of the reachable branches satisfied the predicate. + pub fn pop_first_match(&mut self, predicate: F) -> Option<(TokenStream, Span)> + where + F: Fn(&CfgEntry) -> bool, + { + for (index, (cfg, _, _)) in self.reachable.iter().enumerate() { + if predicate(cfg) { + let matched = self.reachable.remove(index); + return Some((matched.1, matched.2)); + } + } + + self.wildcard.take().map(|(_, tts, span)| (tts, span)) + } + + /// Consume this value and iterate over all the `TokenStream`s that it stores. + pub fn into_iter_tts(self) -> impl Iterator { + let it1 = self.reachable.into_iter().map(|(_, tts, span)| (tts, span)); + let it2 = self.wildcard.into_iter().map(|(_, tts, span)| (tts, span)); + let it3 = self.unreachable.into_iter().map(|(_, tts, span)| (tts, span)); + + it1.chain(it2).chain(it3) + } +} + pub fn parse_cfg_select( p: &mut Parser<'_>, sess: &Session, diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index dc8077b2a1ffb..f11190b281053 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -1,22 +1,65 @@ use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{Expr, ast}; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select, }; -use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult}; use rustc_span::{Ident, Span, sym}; +use smallvec::SmallVec; use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; -/// Selects the first arm whose predicate evaluates to true. -fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> { - for (cfg, tt, arm_span) in branches.reachable { - if let EvalConfigResult::True = attr::eval_config_entry(&ecx.sess, &cfg) { - return Some((tt, arm_span)); - } +/// This intermediate structure is used to emit parse errors for the branches that are not chosen. +/// The `MacResult` instance below parses all branches, emitting any errors it encounters, but only +/// keeps the parse result for the selected branch. +struct CfgSelectResult<'cx, 'sess> { + ecx: &'cx mut ExtCtxt<'sess>, + site_span: Span, + selected_tts: TokenStream, + selected_span: Span, + other_branches: CfgSelectBranches, +} + +fn tts_to_mac_result<'cx, 'sess>( + ecx: &'cx mut ExtCtxt<'sess>, + site_span: Span, + tts: TokenStream, + span: Span, +) -> Box { + match ExpandResult::from_tts(ecx, tts, site_span, span, Ident::with_dummy_span(sym::cfg_select)) + { + ExpandResult::Ready(x) => x, + _ => unreachable!("from_tts always returns Ready"), } +} + +macro_rules! forward_to_parser_any_macro { + ($method_name:ident, $ret_ty:ty) => { + fn $method_name(self: Box) -> Option<$ret_ty> { + let CfgSelectResult { ecx, site_span, selected_tts, selected_span, .. } = *self; + + for (tts, span) in self.other_branches.into_iter_tts() { + let _ = tts_to_mac_result(ecx, site_span, tts, span).$method_name(); + } + + tts_to_mac_result(ecx, site_span, selected_tts, selected_span).$method_name() + } + }; +} + +impl<'cx, 'sess> MacResult for CfgSelectResult<'cx, 'sess> { + forward_to_parser_any_macro!(make_expr, Box); + forward_to_parser_any_macro!(make_stmts, SmallVec<[ast::Stmt; 1]>); + forward_to_parser_any_macro!(make_items, SmallVec<[Box; 1]>); + + forward_to_parser_any_macro!(make_impl_items, SmallVec<[Box; 1]>); + forward_to_parser_any_macro!(make_trait_impl_items, SmallVec<[Box; 1]>); + forward_to_parser_any_macro!(make_trait_items, SmallVec<[Box; 1]>); + forward_to_parser_any_macro!(make_foreign_items, SmallVec<[Box; 1]>); - branches.wildcard.map(|(_, tt, span)| (tt, span)) + forward_to_parser_any_macro!(make_ty, Box); + forward_to_parser_any_macro!(make_pat, Box); } pub(super) fn expand_cfg_select<'cx>( @@ -31,7 +74,7 @@ pub(super) fn expand_cfg_select<'cx>( Some(ecx.ecfg.features), ecx.current_expansion.lint_node_id, ) { - Ok(branches) => { + Ok(mut branches) => { if let Some((underscore, _, _)) = branches.wildcard { // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt. for (predicate, _, _) in &branches.unreachable { @@ -44,14 +87,17 @@ pub(super) fn expand_cfg_select<'cx>( } } - if let Some((tts, arm_span)) = select_arm(ecx, branches) { - return ExpandResult::from_tts( + if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| { + matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True) + }) { + let mac = CfgSelectResult { ecx, - tts, - sp, - arm_span, - Ident::with_dummy_span(sym::cfg_select), - ); + selected_tts, + selected_span, + other_branches: branches, + site_span: sp, + }; + return ExpandResult::Ready(Box::new(mac)); } else { // Emit a compiler error when none of the predicates matched. let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp }); diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index 9fc6803070258..2369158ba82a2 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -47,6 +47,89 @@ fn arm_rhs_expr_3() -> i32 { } } +fn expand_to_statements() -> i32 { + cfg_select! { + true => { + let a = 1; + a + 1 + } + false => { + let b = 2; + b + 1 + } + } +} + +type ExpandToType = cfg_select! { + unix => u32, + _ => i32, +}; + +fn expand_to_pattern(x: Option) -> bool { + match x { + (cfg_select! { + unix => Some(n), + _ => None, + }) => true, + _ => false, + } +} + +cfg_select! { + true => { + fn foo() {} + } + _ => { + fn bar() {} + } +} + +struct S; + +impl S { + cfg_select! { + true => { + fn foo() {} + } + _ => { + fn bar() {} + } + } +} + +trait T { + cfg_select! { + true => { + fn a(); + } + _ => { + fn b(); + } + } +} + +impl T for S { + cfg_select! { + true => { + fn a() {} + } + _ => { + fn b() {} + } + } +} + +extern "C" { + cfg_select! { + true => { + fn puts(s: *const i8) -> i32; + } + _ => { + fn printf(fmt: *const i8, ...) -> i32; + } + } +} + cfg_select! { _ => {} true => {} diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index 510fc33d6d113..ffd8540425ab0 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -1,5 +1,5 @@ warning: unreachable predicate - --> $DIR/cfg_select.rs:52:5 + --> $DIR/cfg_select.rs:135:5 | LL | _ => {} | - always matches @@ -7,7 +7,7 @@ LL | true => {} | ^^^^ this predicate is never reached error: none of the predicates in this `cfg_select` evaluated to true - --> $DIR/cfg_select.rs:56:1 + --> $DIR/cfg_select.rs:139:1 | LL | / cfg_select! { LL | | @@ -16,55 +16,55 @@ LL | | } | |_^ error: none of the predicates in this `cfg_select` evaluated to true - --> $DIR/cfg_select.rs:61:1 + --> $DIR/cfg_select.rs:144:1 | LL | cfg_select! {} | ^^^^^^^^^^^^^^ error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>` - --> $DIR/cfg_select.rs:65:5 + --> $DIR/cfg_select.rs:148:5 | LL | => {} | ^^ error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression - --> $DIR/cfg_select.rs:70:5 + --> $DIR/cfg_select.rs:153:5 | LL | () => {} | ^^ expressions are not allowed here error[E0539]: malformed `cfg_select` macro input - --> $DIR/cfg_select.rs:75:5 + --> $DIR/cfg_select.rs:158:5 | LL | "str" => {} | ^^^^^ expected a valid identifier here error[E0539]: malformed `cfg_select` macro input - --> $DIR/cfg_select.rs:80:5 + --> $DIR/cfg_select.rs:163:5 | LL | a::b => {} | ^^^^ expected a valid identifier here error[E0537]: invalid predicate `a` - --> $DIR/cfg_select.rs:85:5 + --> $DIR/cfg_select.rs:168:5 | LL | a() => {} | ^^^ error: expected one of `(`, `::`, `=>`, or `=`, found `+` - --> $DIR/cfg_select.rs:90:7 + --> $DIR/cfg_select.rs:173:7 | LL | a + 1 => {} | ^ expected one of `(`, `::`, `=>`, or `=` error: expected one of `(`, `::`, `=>`, or `=`, found `!` - --> $DIR/cfg_select.rs:96:8 + --> $DIR/cfg_select.rs:179:8 | LL | cfg!() => {} | ^ expected one of `(`, `::`, `=>`, or `=` warning: unexpected `cfg` condition name: `a` - --> $DIR/cfg_select.rs:90:5 + --> $DIR/cfg_select.rs:173:5 | LL | a + 1 => {} | ^ help: found config with similar value: `target_feature = "a"` @@ -75,7 +75,7 @@ LL | a + 1 => {} = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition name: `cfg` - --> $DIR/cfg_select.rs:96:5 + --> $DIR/cfg_select.rs:179:5 | LL | cfg!() => {} | ^^^ diff --git a/tests/ui/macros/cfg_select_parse_error.rs b/tests/ui/macros/cfg_select_parse_error.rs new file mode 100644 index 0000000000000..90fcb2309b348 --- /dev/null +++ b/tests/ui/macros/cfg_select_parse_error.rs @@ -0,0 +1,18 @@ +#![feature(cfg_select)] +#![crate_type = "lib"] + +// Check that parse errors in arms that are not selected are still reported. + +fn print() { + println!(cfg_select! { + false => { 1 ++ 2 } + //~^ ERROR Rust has no postfix increment operator + _ => { "not unix" } + }); +} + +cfg_select! { + false => { fn foo() { 1 +++ 2 } } + //~^ ERROR Rust has no postfix increment operator + _ => {} +} diff --git a/tests/ui/macros/cfg_select_parse_error.stderr b/tests/ui/macros/cfg_select_parse_error.stderr new file mode 100644 index 0000000000000..d4c86c3ceade1 --- /dev/null +++ b/tests/ui/macros/cfg_select_parse_error.stderr @@ -0,0 +1,26 @@ +error: Rust has no postfix increment operator + --> $DIR/cfg_select_parse_error.rs:8:22 + | +LL | false => { 1 ++ 2 } + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL - false => { 1 ++ 2 } +LL + false => { { let tmp = 1 ; 1 += 1; tmp } 2 } + | + +error: Rust has no postfix increment operator + --> $DIR/cfg_select_parse_error.rs:15:29 + | +LL | false => { fn foo() { 1 +++ 2 } } + | ^^ not a valid postfix operator + | +help: use `+= 1` instead + | +LL - false => { fn foo() { 1 +++ 2 } } +LL + false => { fn foo() { { let tmp = 1 ; 1 += 1; tmp }+ 2 } } + | + +error: aborting due to 2 previous errors + From c820f461228ba5d8d6bc6879e5a311a45673fb84 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 15 Dec 2025 14:42:01 +0100 Subject: [PATCH 30/36] Generate macro expansion for rust compiler crates docs --- src/bootstrap/src/core/build_steps/doc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index b86582807f722..fa36a6471cae5 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -932,6 +932,7 @@ impl Step for Rustc { // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222 // If there is any bug, please comment out the next line. cargo.rustdocflag("--generate-link-to-definition"); + cargo.rustdocflag("--generate-macro-expansion"); compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates); cargo.arg("-Zskip-rustdoc-fingerprint"); From ae5e0d5492b1106f8843ee2e00f6017bb0bf75b7 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Thu, 18 Dec 2025 10:42:47 +0300 Subject: [PATCH 31/36] Support recursive delegation --- compiler/rustc_ast_lowering/messages.ftl | 2 + compiler/rustc_ast_lowering/src/delegation.rs | 68 +++++++++---- compiler/rustc_ast_lowering/src/errors.rs | 14 +++ compiler/rustc_ast_lowering/src/item.rs | 6 +- compiler/rustc_hir_analysis/src/delegation.rs | 6 -- compiler/rustc_middle/src/ty/mod.rs | 3 + compiler/rustc_resolve/src/late.rs | 22 ++++- compiler/rustc_resolve/src/lib.rs | 3 + .../auxiliary/recursive-delegation-aux.rs | 7 ++ tests/ui/delegation/ice-issue-124347.rs | 4 +- tests/ui/delegation/ice-issue-124347.stderr | 17 ++-- .../delegation/recursive-delegation-errors.rs | 54 ++++++++++ .../recursive-delegation-errors.stderr | 98 +++++++++++++++++++ .../delegation/recursive-delegation-pass.rs | 68 +++++++++++++ .../ui/delegation/unsupported.current.stderr | 13 +-- tests/ui/delegation/unsupported.next.stderr | 13 +-- tests/ui/delegation/unsupported.rs | 1 - 17 files changed, 330 insertions(+), 69 deletions(-) create mode 100644 tests/ui/delegation/auxiliary/recursive-delegation-aux.rs create mode 100644 tests/ui/delegation/recursive-delegation-errors.rs create mode 100644 tests/ui/delegation/recursive-delegation-errors.stderr create mode 100644 tests/ui/delegation/recursive-delegation-pass.rs diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 370b15d2871a9..e1fccead4d21a 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -56,6 +56,8 @@ ast_lowering_coroutine_too_many_parameters = ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs .label = default fields are only supported on structs +ast_lowering_delegation_cycle_in_signature_resolution = encountered a cycle during delegation signature resolution +ast_lowering_delegation_unresolved_callee = failed to resolve delegation callee ast_lowering_does_not_support_modifiers = the `{$class_name}` register class does not support template modifiers diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 82bade8829a2f..532a0ce520cd6 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -44,6 +44,7 @@ use hir::{BodyId, HirId}; use rustc_abi::ExternAbi; use rustc_ast::*; use rustc_attr_parsing::{AttributeParser, ShouldEmit}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::ErrorGuaranteed; use rustc_hir::Target; use rustc_hir::attrs::{AttributeKind, InlineAttr}; @@ -55,6 +56,7 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol}; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; +use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee}; use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt}; pub(crate) struct DelegationResults<'hir> { @@ -119,10 +121,14 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, delegation: &Delegation, item_id: NodeId, - is_in_trait_impl: bool, ) -> DelegationResults<'hir> { let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); - let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl); + + let sig_id = self.get_delegation_sig_id( + self.resolver.delegation_sig_resolution_nodes[&self.local_def_id(item_id)], + span, + ); + match sig_id { Ok(sig_id) => { self.add_attributes_if_needed(span, sig_id); @@ -238,24 +244,48 @@ impl<'hir> LoweringContext<'_, 'hir> { fn get_delegation_sig_id( &self, - item_id: NodeId, - path_id: NodeId, + mut node_id: NodeId, span: Span, - is_in_trait_impl: bool, ) -> Result { - let sig_id = if is_in_trait_impl { item_id } else { path_id }; - self.get_resolution_id(sig_id, span) + let mut visited: FxHashSet = Default::default(); + + loop { + visited.insert(node_id); + + let Some(def_id) = self.get_resolution_id(node_id) else { + return Err(self.tcx.dcx().span_delayed_bug( + span, + format!( + "LoweringContext: couldn't resolve node {:?} in delegation item", + node_id + ), + )); + }; + + // If def_id is in local crate and it corresponds to another delegation + // it means that we refer to another delegation as a callee, so in order to obtain + // a signature DefId we obtain NodeId of the callee delegation and try to get signature from it. + if let Some(local_id) = def_id.as_local() + && let Some(next_node_id) = + self.resolver.delegation_sig_resolution_nodes.get(&local_id) + { + node_id = *next_node_id; + if visited.contains(&node_id) { + // We encountered a cycle in the resolution, or delegation callee refers to non-existent + // entity, in this case emit an error. + return Err(match visited.len() { + 1 => self.dcx().emit_err(UnresolvedDelegationCallee { span }), + _ => self.dcx().emit_err(CycleInDelegationSignatureResolution { span }), + }); + } + } else { + return Ok(def_id); + } + } } - fn get_resolution_id(&self, node_id: NodeId, span: Span) -> Result { - let def_id = - self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id()); - def_id.ok_or_else(|| { - self.tcx.dcx().span_delayed_bug( - span, - format!("LoweringContext: couldn't resolve node {:?} in delegation item", node_id), - ) - }) + fn get_resolution_id(&self, node_id: NodeId) -> Option { + self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id()) } fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> { @@ -271,8 +301,6 @@ impl<'hir> LoweringContext<'_, 'hir> { // Function parameter count, including C variadic `...` if present. fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) { if let Some(local_sig_id) = sig_id.as_local() { - // Map may be filled incorrectly due to recursive delegation. - // Error will be emitted later during HIR ty lowering. match self.resolver.delegation_fn_sigs.get(&local_sig_id) { Some(sig) => (sig.param_count, sig.c_variadic), None => (0, false), @@ -489,8 +517,8 @@ impl<'hir> LoweringContext<'_, 'hir> { delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some()); let call = if self - .get_resolution_id(delegation.id, span) - .and_then(|def_id| Ok(self.is_method(def_id, span))) + .get_resolution_id(delegation.id) + .map(|def_id| self.is_method(def_id, span)) .unwrap_or_default() && delegation.qself.is_none() && !has_generic_args diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 83f3a976e83f7..35c37fe91d494 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -475,3 +475,17 @@ pub(crate) struct UnionWithDefault { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_delegation_unresolved_callee)] +pub(crate) struct UnresolvedDelegationCallee { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_lowering_delegation_cycle_in_signature_resolution)] +pub(crate) struct CycleInDelegationSignatureResolution { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a68d63bf1464c..bfce7c25b75db 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -541,7 +541,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::Macro(ident, macro_def, macro_kinds) } ItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, id, false); + let delegation_results = self.lower_delegation(delegation, id); hir::ItemKind::Fn { sig: delegation_results.sig, ident: delegation_results.ident, @@ -1026,7 +1026,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (*ident, generics, kind, ty.is_some()) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, i.id, false); + let delegation_results = self.lower_delegation(delegation, i.id); let item_kind = hir::TraitItemKind::Fn( delegation_results.sig, hir::TraitFn::Provided(delegation_results.body_id), @@ -1196,7 +1196,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, i.id, is_in_trait_impl); + let delegation_results = self.lower_delegation(delegation, i.id); ( delegation.ident, ( diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 125fc21a5cc1c..4ab13140bf9c9 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -401,12 +401,6 @@ fn check_constraints<'tcx>( })); }; - if let Some(local_sig_id) = sig_id.as_local() - && tcx.hir_opt_delegation_sig_id(local_sig_id).is_some() - { - emit("recursive delegation is not supported yet"); - } - if tcx.fn_sig(sig_id).skip_binder().skip_binder().c_variadic { // See issue #127443 for explanation. emit("delegation to C-variadic functions is not allowed"); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b91176e3d4862..e918f7ba362d1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -220,6 +220,9 @@ pub struct ResolverAstLowering { /// Information about functions signatures for delegation items expansion pub delegation_fn_sigs: LocalDefIdMap, + // NodeIds (either delegation.id or item_id in case of a trait impl) for signature resolution, + // for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914 + pub delegation_sig_resolution_nodes: LocalDefIdMap, } bitflags::bitflags! { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5a4fbad6aaf88..d3428a4af348a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2928,7 +2928,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { item.id, LifetimeBinderKind::Function, span, - |this| this.resolve_delegation(delegation), + |this| this.resolve_delegation(delegation, item.id, false), ); } @@ -3257,7 +3257,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { item.id, LifetimeBinderKind::Function, delegation.path.segments.last().unwrap().ident.span, - |this| this.resolve_delegation(delegation), + |this| this.resolve_delegation(delegation, item.id, false), ); } AssocItemKind::Type(box TyAlias { generics, .. }) => self @@ -3550,7 +3550,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |i, s, c| MethodNotMemberOfTrait(i, s, c), ); - this.resolve_delegation(delegation) + this.resolve_delegation(delegation, item.id, trait_id.is_some()); }, ); } @@ -3699,17 +3699,30 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }) } - fn resolve_delegation(&mut self, delegation: &'ast Delegation) { + fn resolve_delegation( + &mut self, + delegation: &'ast Delegation, + item_id: NodeId, + is_in_trait_impl: bool, + ) { self.smart_resolve_path( delegation.id, &delegation.qself, &delegation.path, PathSource::Delegation, ); + if let Some(qself) = &delegation.qself { self.visit_ty(&qself.ty); } + self.visit_path(&delegation.path); + + self.r.delegation_sig_resolution_nodes.insert( + self.r.local_def_id(item_id), + if is_in_trait_impl { item_id } else { delegation.id }, + ); + let Some(body) = &delegation.body else { return }; self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { let span = delegation.path.segments.last().unwrap().ident.span; @@ -4294,7 +4307,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } - #[instrument(level = "debug", skip(self))] fn smart_resolve_path_fragment( &mut self, qself: &Option>, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b3141406e467e..646a1b8914133 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1276,6 +1276,7 @@ pub struct Resolver<'ra, 'tcx> { /// Amount of lifetime parameters for each item in the crate. item_generics_num_lifetimes: FxHashMap, delegation_fn_sigs: LocalDefIdMap, + delegation_sig_resolution_nodes: LocalDefIdMap, main_def: Option = None, trait_impls: FxIndexMap>, @@ -1694,6 +1695,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span, mods_with_parse_errors: Default::default(), impl_trait_names: Default::default(), + delegation_sig_resolution_nodes: Default::default(), .. }; @@ -1822,6 +1824,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), delegation_fn_sigs: self.delegation_fn_sigs, + delegation_sig_resolution_nodes: self.delegation_sig_resolution_nodes, }; ResolverOutputs { global_ctxt, ast_lowering } } diff --git a/tests/ui/delegation/auxiliary/recursive-delegation-aux.rs b/tests/ui/delegation/auxiliary/recursive-delegation-aux.rs new file mode 100644 index 0000000000000..5df644974f3ef --- /dev/null +++ b/tests/ui/delegation/auxiliary/recursive-delegation-aux.rs @@ -0,0 +1,7 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +fn foo() {} + +reuse foo as bar; +pub reuse bar as goo; diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs index 3e0a5b36ddcf3..6bf3a08ba5b49 100644 --- a/tests/ui/delegation/ice-issue-124347.rs +++ b/tests/ui/delegation/ice-issue-124347.rs @@ -1,12 +1,12 @@ #![feature(fn_delegation)] #![allow(incomplete_features)] -// FIXME(fn_delegation): `recursive delegation` error should be emitted here trait Trait { reuse Trait::foo { &self.0 } + //~^ ERROR failed to resolve delegation callee } reuse foo; -//~^ ERROR cycle detected when computing generics of `foo` +//~^ ERROR failed to resolve delegation callee fn main() {} diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr index 2955c04420348..40be6be4abfa1 100644 --- a/tests/ui/delegation/ice-issue-124347.stderr +++ b/tests/ui/delegation/ice-issue-124347.stderr @@ -1,17 +1,14 @@ -error[E0391]: cycle detected when computing generics of `foo` - --> $DIR/ice-issue-124347.rs:9:7 +error: failed to resolve delegation callee + --> $DIR/ice-issue-124347.rs:5:18 | -LL | reuse foo; - | ^^^ - | - = note: ...which immediately requires computing generics of `foo` again -note: cycle used when checking that `foo` is well-formed +LL | reuse Trait::foo { &self.0 } + | ^^^ + +error: failed to resolve delegation callee --> $DIR/ice-issue-124347.rs:9:7 | LL | reuse foo; | ^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/recursive-delegation-errors.rs b/tests/ui/delegation/recursive-delegation-errors.rs new file mode 100644 index 0000000000000..194182e20ed02 --- /dev/null +++ b/tests/ui/delegation/recursive-delegation-errors.rs @@ -0,0 +1,54 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + + +mod first_mod { + reuse foo; + //~^ ERROR failed to resolve delegation callee +} + +mod second_mod { + reuse foo as bar; + //~^ ERROR encountered a cycle during delegation signature resolution + reuse bar as foo; + //~^ ERROR encountered a cycle during delegation signature resolution +} + +mod third_mod { + reuse foo as foo1; + //~^ ERROR encountered a cycle during delegation signature resolution + reuse foo1 as foo2; + //~^ ERROR encountered a cycle during delegation signature resolution + reuse foo2 as foo3; + //~^ ERROR encountered a cycle during delegation signature resolution + reuse foo3 as foo4; + //~^ ERROR encountered a cycle during delegation signature resolution + reuse foo4 as foo5; + //~^ ERROR encountered a cycle during delegation signature resolution + reuse foo5 as foo; + //~^ ERROR encountered a cycle during delegation signature resolution +} + +mod fourth_mod { + trait Trait { + reuse Trait::foo as bar; + //~^ ERROR encountered a cycle during delegation signature resolution + reuse Trait::bar as foo; + //~^ ERROR encountered a cycle during delegation signature resolution + } +} + +mod fifth_mod { + reuse super::fifth_mod::{bar as foo, foo as bar}; + //~^ ERROR encountered a cycle during delegation signature resolution + //~| ERROR encountered a cycle during delegation signature resolution + + trait GlobReuse { + reuse GlobReuse::{foo as bar, bar as goo, goo as foo}; + //~^ ERROR encountered a cycle during delegation signature resolution + //~| ERROR encountered a cycle during delegation signature resolution + //~| ERROR encountered a cycle during delegation signature resolution + } +} + +fn main() {} diff --git a/tests/ui/delegation/recursive-delegation-errors.stderr b/tests/ui/delegation/recursive-delegation-errors.stderr new file mode 100644 index 0000000000000..9c4e316745aea --- /dev/null +++ b/tests/ui/delegation/recursive-delegation-errors.stderr @@ -0,0 +1,98 @@ +error: failed to resolve delegation callee + --> $DIR/recursive-delegation-errors.rs:6:11 + | +LL | reuse foo; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:11:11 + | +LL | reuse foo as bar; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:13:11 + | +LL | reuse bar as foo; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:18:11 + | +LL | reuse foo as foo1; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:20:11 + | +LL | reuse foo1 as foo2; + | ^^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:22:11 + | +LL | reuse foo2 as foo3; + | ^^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:24:11 + | +LL | reuse foo3 as foo4; + | ^^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:26:11 + | +LL | reuse foo4 as foo5; + | ^^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:28:11 + | +LL | reuse foo5 as foo; + | ^^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:34:22 + | +LL | reuse Trait::foo as bar; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:36:22 + | +LL | reuse Trait::bar as foo; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:42:30 + | +LL | reuse super::fifth_mod::{bar as foo, foo as bar}; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:42:42 + | +LL | reuse super::fifth_mod::{bar as foo, foo as bar}; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:47:27 + | +LL | reuse GlobReuse::{foo as bar, bar as goo, goo as foo}; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:47:39 + | +LL | reuse GlobReuse::{foo as bar, bar as goo, goo as foo}; + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/recursive-delegation-errors.rs:47:51 + | +LL | reuse GlobReuse::{foo as bar, bar as goo, goo as foo}; + | ^^^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/delegation/recursive-delegation-pass.rs b/tests/ui/delegation/recursive-delegation-pass.rs new file mode 100644 index 0000000000000..93f8fa401b555 --- /dev/null +++ b/tests/ui/delegation/recursive-delegation-pass.rs @@ -0,0 +1,68 @@ +//@ check-pass +//@ edition:2018 +//@ aux-crate:recursive_delegation_aux=recursive-delegation-aux.rs + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod first_mod { + pub mod to_reuse { + pub fn foo(x: usize) -> usize { + x + 1 + } + } + + mod single_reuse { + reuse crate::first_mod::to_reuse::foo; + reuse foo as bar; + reuse foo as bar1; + reuse bar as goo; + reuse goo as koo; + reuse koo as too; + } + + mod glob_reuse { + reuse super::to_reuse::{foo as bar, foo as bar1} { self } + reuse super::glob_reuse::{bar as goo, goo as koo, koo as too} { self } + } +} + +mod second_mod { + trait T { + fn foo(&self); + reuse T::foo as bar; + reuse T::bar as goo; + reuse T::goo as poo; + } + + trait TGlob { + fn xd(&self) -> &Self; + fn foo1(&self); + fn foo2(&self); + fn foo3(&self); + fn foo4(&self); + + reuse TGlob::{foo1 as bar1, foo3 as bar3, bar1 as bar11, bar11 as bar111} { self.xd() } + } +} + +mod third_mod { + reuse crate::first_mod::to_reuse::foo { + reuse foo as bar { + reuse bar as goo { + bar(123) + } + + goo(123) + } + + bar(123) + } +} + +mod fourth_mod { + reuse recursive_delegation_aux::goo as bar; + reuse bar as foo; +} + +fn main() {} diff --git a/tests/ui/delegation/unsupported.current.stderr b/tests/ui/delegation/unsupported.current.stderr index 5c4115630c002..2bb0633621f21 100644 --- a/tests/ui/delegation/unsupported.current.stderr +++ b/tests/ui/delegation/unsupported.current.stderr @@ -36,24 +36,15 @@ LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: recursive delegation is not supported yet - --> $DIR/unsupported.rs:46:22 - | -LL | pub reuse to_reuse2::foo; - | --- callee defined here -... -LL | reuse to_reuse1::foo; - | ^^^ - error[E0283]: type annotations needed - --> $DIR/unsupported.rs:55:18 + --> $DIR/unsupported.rs:54:18 | LL | reuse Trait::foo; | ^^^ cannot infer type | = note: cannot satisfy `_: effects::Trait` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0283, E0391. For more information about an error, try `rustc --explain E0283`. diff --git a/tests/ui/delegation/unsupported.next.stderr b/tests/ui/delegation/unsupported.next.stderr index a626da9a1442c..1665d1f39d6d0 100644 --- a/tests/ui/delegation/unsupported.next.stderr +++ b/tests/ui/delegation/unsupported.next.stderr @@ -28,24 +28,15 @@ LL | reuse ToReuse::opaque_ret; = note: cycle used when computing implied outlives bounds for `::opaque_ret::{anon_assoc#0}` (hack disabled = false) = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: recursive delegation is not supported yet - --> $DIR/unsupported.rs:46:22 - | -LL | pub reuse to_reuse2::foo; - | --- callee defined here -... -LL | reuse to_reuse1::foo; - | ^^^ - error[E0283]: type annotations needed - --> $DIR/unsupported.rs:55:18 + --> $DIR/unsupported.rs:54:18 | LL | reuse Trait::foo; | ^^^ cannot infer type | = note: cannot satisfy `_: effects::Trait` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0283, E0391. For more information about an error, try `rustc --explain E0283`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index 5e2bd832a4d84..1681888e34ea6 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -44,7 +44,6 @@ mod recursive { } reuse to_reuse1::foo; - //~^ ERROR recursive delegation is not supported yet } mod effects { From 957169399012bd3474b6b9b4c90048996f7c53b3 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Thu, 18 Dec 2025 01:32:49 -0800 Subject: [PATCH 32/36] unstable.rs: fix typos in comments (implementatble -> implementable) --- compiler/rustc_feature/src/unstable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index fe053935f9e64..f0a1f14168597 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -221,7 +221,7 @@ declare_features! ( (internal, compiler_builtins, "1.13.0", None), /// Allows writing custom MIR (internal, custom_mir, "1.65.0", None), - /// Implementation details of externally implementatble items + /// Implementation details of externally implementable items (internal, eii_internals, "CURRENT_RUSTC_VERSION", None), /// Outputs useful `assert!` messages (unstable, generic_assert, "1.63.0", None), @@ -503,7 +503,7 @@ declare_features! ( (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), /// Allows using `#[export_stable]` which indicates that an item is exportable. (incomplete, export_stable, "1.88.0", Some(139939)), - /// Externally implementatble items + /// Externally implementable items (unstable, extern_item_impls, "CURRENT_RUSTC_VERSION", Some(125418)), /// Allows defining `extern type`s. (unstable, extern_types, "1.23.0", Some(43467)), From 6396521fdbcda3c9e79dd7c6f698d6589eeaf5ce Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Dec 2025 10:52:32 +0000 Subject: [PATCH 33/36] Rustup to rustc 1.94.0-nightly (f794a0873 2025-12-17) --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 4d3fe30e7d47a..6ce49eb4ccf07 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-12-16" +channel = "nightly-2025-12-18" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" From 8de4afd39ba48f25be98684cdb7a96ec6da89d10 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Dec 2025 11:09:12 +0000 Subject: [PATCH 34/36] Fix rustc testsuite --- scripts/test_rustc_tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index 69c6099c3ab86..b25269d1430ae 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -35,6 +35,7 @@ git checkout -- tests/ui/entry-point/auxiliary/bad_main_functions.rs rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.round.ps rm tests/ui/simd/intrinsic/generic-arithmetic-pass.rs # unimplemented simd_funnel_{shl,shr} +rm -r tests/ui/scalable-vectors # scalable vectors are unsupported # exotic linkages rm tests/incremental/hashes/function_interfaces.rs @@ -159,6 +160,7 @@ rm tests/ui/lint/use-redundant/use-redundant-issue-71450.rs # same rm tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs # same rm tests/ui/specialization/const_trait_impl.rs # same rm tests/ui/thir-print/offset_of.rs # same +rm tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs # same # genuine bugs # ============ From fe34b17c2a626df957d26b6c2e0bbcf6e0565311 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Thu, 18 Dec 2025 11:39:40 +0100 Subject: [PATCH 35/36] Port `#[rustc_lint_opt_deny_field_access]` to attribute parser --- .../src/attributes/rustc_internal.rs | 24 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 7 +++--- .../rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_lint/src/internal.rs | 9 ++----- compiler/rustc_passes/messages.ftl | 3 --- compiler/rustc_passes/src/check_attr.rs | 16 +------------ compiler/rustc_passes/src/errors.rs | 9 ------- 8 files changed, 35 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 7910443787b4f..72c6d9e9851fb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -117,6 +117,30 @@ impl SingleAttributeParser for RustcLegacyConstGenericsParser { } } +pub(crate) struct RustcLintOptDenyFieldAccessParser; + +impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser { + const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]); + const TEMPLATE: AttributeTemplate = template!(Word); + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(arg) = args.list().and_then(MetaItemListParser::single) else { + cx.expected_single_argument(cx.attr_span); + return None; + }; + + let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg + else { + cx.expected_string_literal(arg.span(), arg.lit()); + return None; + }; + + Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message: *lint_message }) + } +} + pub(crate) struct RustcLintOptTyParser; impl NoArgsAttributeParser for RustcLintOptTyParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b4854c430cae0..e5448e7792a88 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -61,9 +61,9 @@ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, - RustcLegacyConstGenericsParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser, - RustcMainParser, RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, - RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, + RustcLegacyConstGenericsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, + RustcLintQueryInstabilityParser, RustcMainParser, RustcNeverReturnsNullPointerParser, + RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; @@ -213,6 +213,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 5e650fbb9bd0b..5991fb5ab24e6 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -931,6 +931,9 @@ pub enum AttributeKind { /// Represents `#[rustc_legacy_const_generics]` RustcLegacyConstGenerics { fn_indexes: ThinVec<(usize, Span)>, attr_span: Span }, + /// Represents `#[rustc_lint_opt_deny_field_access]` + RustcLintOptDenyFieldAccess { lint_message: Symbol }, + /// Represents `#[rustc_lint_opt_ty]` RustcLintOptTy, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index f99069e416bd2..64aa9c2a45bc3 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -94,6 +94,7 @@ impl AttributeKind { RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, RustcLegacyConstGenerics { .. } => Yes, + RustcLintOptDenyFieldAccess { .. } => Yes, RustcLintOptTy => Yes, RustcLintQueryInstability => Yes, RustcMain => No, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c32fed3674fcc..d6f20a4c85a4f 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -668,17 +668,12 @@ impl LateLintPass<'_> for BadOptAccess { for field in adt_def.all_fields() { if field.name == target.name - && let Some(attr) = - cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access) - && let Some(items) = attr.meta_item_list() - && let Some(item) = items.first() - && let Some(lit) = item.lit() - && let ast::LitKind::Str(val, _) = lit.kind + && let Some(lint_message) = find_attr!(cx.tcx.get_all_attrs(field.did), AttributeKind::RustcLintOptDenyFieldAccess { lint_message, } => lint_message) { cx.emit_span_lint( BAD_OPT_ACCESS, expr.span, - BadOptAccessDiag { msg: val.as_str() }, + BadOptAccessDiag { msg: lint_message.as_str() }, ); } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 5a9b759575172..7ebfca91d499d 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -473,9 +473,6 @@ passes_rustc_legacy_const_generics_only = #[rustc_legacy_const_generics] functions must only have const generics .label = non-const generic parameter -passes_rustc_lint_opt_deny_field_access = - `#[rustc_lint_opt_deny_field_access]` should be applied to a field - .label = not a field passes_rustc_pub_transparent = attribute should be applied to `#[repr(transparent)]` types diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d03da2e06cf13..33a3477bcf691 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -258,6 +258,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcNoImplicitAutorefs | AttributeKind::RustcLayoutScalarValidRangeStart(..) | AttributeKind::RustcLayoutScalarValidRangeEnd(..) + | AttributeKind::RustcLintOptDenyFieldAccess { .. } | AttributeKind::RustcLintOptTy | AttributeKind::RustcLintQueryInstability | AttributeKind::RustcNeverReturnsNullPointer @@ -314,9 +315,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_lint_diagnostics, ..] => { self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target) } - [sym::rustc_lint_opt_deny_field_access, ..] => { - self.check_rustc_lint_opt_deny_field_access(attr, span, target) - } [sym::rustc_clean, ..] | [sym::rustc_dirty, ..] | [sym::rustc_if_this_changed, ..] @@ -1251,18 +1249,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks that the `#[rustc_lint_opt_deny_field_access]` attribute is only applied to a field. - fn check_rustc_lint_opt_deny_field_access(&self, attr: &Attribute, span: Span, target: Target) { - match target { - Target::Field => {} - _ => { - self.tcx - .dcx() - .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span(), span }); - } - } - } - /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph /// option is passed to the compiler. fn check_rustc_dirty_clean(&self, attr: &Attribute) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f2b7d3740cb64..895cefe672baa 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -412,15 +412,6 @@ pub(crate) struct UnusedMultiple { pub name: Symbol, } -#[derive(Diagnostic)] -#[diag(passes_rustc_lint_opt_deny_field_access)] -pub(crate) struct RustcLintOptDenyFieldAccess { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_collapse_debuginfo)] pub(crate) struct CollapseDebuginfo { From cd4d899862bf23ce325c55310537b326d349bcd4 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Thu, 18 Dec 2025 12:30:05 +0100 Subject: [PATCH 36/36] make all parsed rustc attributes error on duplicate --- compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 72c6d9e9851fb..8005dd76b2a3d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -145,7 +145,7 @@ pub(crate) struct RustcLintOptTyParser; impl NoArgsAttributeParser for RustcLintOptTyParser { const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty]; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy; } @@ -154,7 +154,7 @@ pub(crate) struct RustcLintQueryInstabilityParser; impl NoArgsAttributeParser for RustcLintQueryInstabilityParser { const PATH: &[Symbol] = &[sym::rustc_lint_query_instability]; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)),