From a197ebdb07e0908a6bbfc6faf6874ecb709c1e88 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Wed, 27 Aug 2025 16:15:08 +0300 Subject: [PATCH 01/10] {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/10] `[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/10] `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/10] 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/10] 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 8d37589f37cf435d66d4fa2b6aed3ac006063a9e Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Mon, 15 Dec 2025 22:08:00 -0800 Subject: [PATCH 06/10] 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 60b616d3382b15b07c16db48edf5993254b7fc4d Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Wed, 17 Dec 2025 11:20:44 +0100 Subject: [PATCH 07/10] 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 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 08/10] 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 09/10] 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 10/10] 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`.