From 313eb8ff1354ed6b99c1b9a6a4ba7184747cf39d Mon Sep 17 00:00:00 2001 From: Andrew Wock Date: Sun, 18 Feb 2024 18:06:16 -0500 Subject: [PATCH 01/18] Implement MaybeUninit::fill{,_with,_from} ACP: rust-lang/libs-team#156 Signed-off-by: Andrew Wock --- library/core/src/mem/maybe_uninit.rs | 202 ++++++++++++++++++++++++--- library/core/tests/lib.rs | 1 + library/core/tests/mem.rs | 195 +++++++++++++++++++++++++- 3 files changed, 376 insertions(+), 22 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index c19b5791562ce..026e21586d403 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1125,22 +1125,6 @@ impl MaybeUninit { // unlike copy_from_slice this does not call clone_from_slice on the slice // this is because `MaybeUninit` does not implement Clone. - struct Guard<'a, T> { - slice: &'a mut [MaybeUninit], - initialized: usize, - } - - impl<'a, T> Drop for Guard<'a, T> { - fn drop(&mut self) { - let initialized_part = &mut self.slice[..self.initialized]; - // SAFETY: this raw slice will contain only initialized objects - // that's why, it is allowed to drop it. - unsafe { - crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part)); - } - } - } - assert_eq!(this.len(), src.len(), "destination and source slices have different lengths"); // NOTE: We need to explicitly slice them to the same length // for bounds checking to be elided, and the optimizer will @@ -1162,6 +1146,151 @@ impl MaybeUninit { unsafe { MaybeUninit::slice_assume_init_mut(this) } } + /// Fills `this` with elements by cloning `value`, returning a mutable reference to the now + /// initialized contents of `this`. + /// Any previously initialized elements will not be dropped. + /// + /// This is similar to [`slice::fill`]. + /// + /// # Panics + /// + /// This function will panic if any call to `Clone` panics. + /// + /// If such a panic occurs, any elements previously initialized during this operation will be + /// dropped. + /// + /// # Examples + /// + /// Fill an uninit vec with 1. + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = vec![MaybeUninit::uninit(); 10]; + /// let initialized = MaybeUninit::fill(buf.as_mut_slice(), 1); + /// assert_eq!(initialized, &mut [1; 10]); + /// ``` + #[doc(alias = "memset")] + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn fill<'a>(this: &'a mut [MaybeUninit], value: T) -> &'a mut [T] + where + T: Clone, + { + SpecFill::spec_fill(this, value); + // SAFETY: Valid elements have just been filled into `this` so it is initialized + unsafe { MaybeUninit::slice_assume_init_mut(this) } + } + + /// Fills `this` with elements returned by calling a closure repeatedly. + /// + /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use + /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can + /// pass [`Default::default`] as the argument. + /// + /// # Panics + /// + /// This function will panic if any call to the provided closure panics. + /// + /// If such a panic occurs, any elements previously initialized during this operation will be + /// dropped. + /// + /// # Examples + /// + /// Fill an uninit vec with the default value. + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = vec![MaybeUninit::::uninit(); 10]; + /// let initialized = MaybeUninit::fill_with(buf.as_mut_slice(), Default::default); + /// assert_eq!(initialized, &mut [0; 10]); + /// ``` + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit], mut f: F) -> &'a mut [T] + where + F: FnMut() -> T, + { + let mut guard = Guard { slice: this, initialized: 0 }; + + for element in guard.slice.iter_mut() { + element.write(f()); + guard.initialized += 1; + } + + super::forget(guard); + + // SAFETY: Valid elements have just been written into `this` so it is initialized + unsafe { MaybeUninit::slice_assume_init_mut(this) } + } + + /// Fills `this` with elements yielded by an iterator until either all elements have been + /// initialized or the iterator is empty. + /// + /// Returns two slices. The first slice contains the initialized portion of the original slice. + /// The second slice is the still-uninitialized remainder of the original slice. + /// + /// # Panics + /// + /// This function panics if the iterator's `next` function panics. + /// + /// If such a panic occurs, any elements previously initialized during this operation will be + /// dropped. + /// + /// # Examples + /// + /// Fill an uninit vec with a cycling iterator. + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = vec![MaybeUninit::uninit(); 5]; + /// + /// let iter = [1, 2, 3].into_iter().cycle(); + /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter); + /// + /// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]); + /// assert_eq!(0, remainder.len()); + /// ``` + /// + /// Fill an uninit vec, but not completely. + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = vec![MaybeUninit::uninit(); 5]; + /// let iter = [1, 2]; + /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter); + /// + /// assert_eq!(initialized, &mut [1, 2]); + /// assert_eq!(remainder.len(), 3); + /// ``` + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn fill_from<'a, I>( + this: &'a mut [MaybeUninit], + it: I, + ) -> (&'a mut [T], &'a mut [MaybeUninit]) + where + I: IntoIterator, + { + let iter = it.into_iter(); + let mut guard = Guard { slice: this, initialized: 0 }; + + for (element, val) in guard.slice.iter_mut().zip(iter) { + element.write(val); + guard.initialized += 1; + } + + let initialized_len = guard.initialized; + super::forget(guard); + + // SAFETY: guard.initialized <= this.len() + let (initted, remainder) = unsafe { this.split_at_mut_unchecked(initialized_len) }; + + // SAFETY: Valid elements have just been written into `init`, so that portion + // of `this` is initialized. + (unsafe { MaybeUninit::slice_assume_init_mut(initted) }, remainder) + } + /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes. /// /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still @@ -1315,3 +1444,44 @@ impl [MaybeUninit; N] { unsafe { intrinsics::transmute_unchecked(self) } } } + +struct Guard<'a, T> { + slice: &'a mut [MaybeUninit], + initialized: usize, +} + +impl<'a, T> Drop for Guard<'a, T> { + fn drop(&mut self) { + let initialized_part = &mut self.slice[..self.initialized]; + // SAFETY: this raw sub-slice will contain only initialized objects. + unsafe { + crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part)); + } + } +} + +trait SpecFill { + fn spec_fill(&mut self, value: T); +} + +impl SpecFill for [MaybeUninit] { + default fn spec_fill(&mut self, value: T) { + let mut guard = Guard { slice: self, initialized: 0 }; + + if let Some((last, elems)) = guard.slice.split_last_mut() { + for el in elems { + el.write(value.clone()); + guard.initialized += 1; + } + + last.write(value); + } + super::forget(guard); + } +} + +impl SpecFill for [MaybeUninit] { + fn spec_fill(&mut self, value: T) { + self.fill(MaybeUninit::new(value)); + } +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index fa0e9a979d060..c5a7e87c4aa4f 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -54,6 +54,7 @@ #![feature(slice_from_ptr_range)] #![feature(slice_split_once)] #![feature(split_as_slice)] +#![feature(maybe_uninit_fill)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] #![feature(maybe_uninit_uninit_array_transpose)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 0f7fde747690a..e1c342f0f3e89 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -308,21 +308,204 @@ fn uninit_write_slice_cloned_mid_panic() { } } +#[derive(Clone)] +struct Bomb; + +impl Drop for Bomb { + fn drop(&mut self) { + panic!("dropped a bomb! kaboom!") + } +} + #[test] fn uninit_write_slice_cloned_no_drop() { - #[derive(Clone)] - struct Bomb; + let mut dst = [MaybeUninit::uninit()]; + let src = [Bomb]; + + MaybeUninit::clone_from_slice(&mut dst, &src); + + forget(src); +} + +#[test] +fn uninit_fill() { + let mut dst = [MaybeUninit::new(255); 64]; + let expect = [0; 64]; + + assert_eq!(MaybeUninit::fill(&mut dst, 0), &expect); +} + +struct CloneUntilPanic { + limit: usize, + rc: Rc<()>, +} - impl Drop for Bomb { - fn drop(&mut self) { - panic!("dropped a bomb! kaboom") +impl Clone for CloneUntilPanic { + fn clone(&self) -> Self { + if Rc::strong_count(&self.rc) >= self.limit { + panic!("expected panic on clone"); } + Self { limit: self.limit, rc: self.rc.clone() } } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_clone_panic_drop() { + use std::panic; + + let rc = Rc::new(()); + + let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::fill(&mut dst, src); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_clone_no_drop_clones() { + let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + + MaybeUninit::fill(&mut dst, Bomb); +} + +#[test] +fn uninit_fill_with() { + let mut dst = [MaybeUninit::new(255); 64]; + let expect = [0; 64]; + + assert_eq!(MaybeUninit::fill_with(&mut dst, || 0), &expect); +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_with_mid_panic() { + use std::panic; + + let rc = Rc::new(()); + + let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + + let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::fill_with(&mut dst, || src.clone()); + })); + + drop(src); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_with_no_drop() { + let mut dst = [MaybeUninit::uninit()]; + let src = Bomb; + + MaybeUninit::fill_with(&mut dst, || src.clone()); + + forget(src); +} + +#[test] +fn uninit_fill_from() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 64]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src); + assert_eq!(remainder.len(), 0); +} + +#[test] +fn uninit_fill_from_partial() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 48]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src); + assert_eq!(remainder.len(), 16); +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_from_mid_panic() { + use std::panic; + + struct IterUntilPanic { + limit: usize, + rc: Rc<()>, + } + + impl Iterator for IterUntilPanic { + type Item = Rc<()>; + fn next(&mut self) -> Option { + if Rc::strong_count(&self.rc) >= self.limit { + panic!("expected panic on next"); + } + Some(self.rc.clone()) + } + } + + let rc = Rc::new(()); + + let mut dst = [ + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + ]; + + let src = IterUntilPanic { limit: 3, rc: rc.clone() }; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::fill_from(&mut dst, src); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on next" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_from_no_drop() { let mut dst = [MaybeUninit::uninit()]; let src = [Bomb]; - MaybeUninit::clone_from_slice(&mut dst, &src); + MaybeUninit::fill_from(&mut dst, src.iter()); forget(src); } From 3908a935ef821c2828a7d825eac859f8ff54702a Mon Sep 17 00:00:00 2001 From: Noa Date: Wed, 21 Feb 2024 17:32:58 -0600 Subject: [PATCH 02/18] std support for wasm32 panic=unwind --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 13 ++++++-- library/panic_unwind/src/lib.rs | 13 +++++++- library/panic_unwind/src/wasm.rs | 32 ++++++++++++++++++++ library/std/src/sys/personality/mod.rs | 8 ++--- 4 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 library/panic_unwind/src/wasm.rs diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 54e8ed85e3250..e383673e1d4f2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -5,6 +5,7 @@ use crate::errors::{ }; use crate::llvm; use libc::c_int; +use rustc_codegen_ssa::base::wants_wasm_eh; use rustc_codegen_ssa::traits::PrintBackendInfo; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; @@ -98,8 +99,12 @@ unsafe fn configure_llvm(sess: &Session) { } } - if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind { - add("-enable-emscripten-cxx-exceptions", false); + if sess.panic_strategy() == PanicStrategy::Unwind { + if sess.target.os == "emscripten" { + add("-enable-emscripten-cxx-exceptions", false); + } else if wants_wasm_eh(sess) { + add("-wasm-enable-eh", false); + } } // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes @@ -520,6 +525,10 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec>; + +extern "C" { + /// LLVM lowers this intrinsic to the `throw` instruction. + #[link_name = "llvm.wasm.throw"] + fn wasm_throw(tag: i32, ptr: *mut u8) -> !; +} + +pub unsafe fn panic(payload: Box) -> u32 { + // The payload we pass to `wasm_throw` will be exactly the argument we get + // in `cleanup` below. So we just box it up once, to get something pointer-sized. + let payload_box: Payload = Box::new(payload); + // The wasm `throw` instruction takes a "tag", which differentiates certain + // types of exceptions from others. LLVM currently just identifies these + // via integers, with 0 corresponding to C++ exceptions and 1 to C setjmp()/longjmp(). + // Ideally, we'd be able to choose something unique for Rust, such that we + // don't try to treat a C++ exception payload as a `Box>`, but + // otherwise, pretending to be C++ works for now. + wasm_throw(0, Box::into_raw(payload_box) as *mut u8) +} + +pub unsafe fn cleanup(payload_box: *mut u8) -> Box { + // Recover the underlying `Box`. + let payload_box: Payload = Box::from_raw(payload_box as *mut _); + *payload_box +} diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index d37b8ce634654..1a6ea1dafcb53 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -16,11 +16,12 @@ mod dwarf; cfg_if::cfg_if! { if #[cfg(target_os = "emscripten")] { mod emcc; - } else if #[cfg(target_env = "msvc")] { + } else if #[cfg(any(target_env = "msvc", target_family = "wasm"))] { // This is required by the compiler to exist (e.g., it's a lang item), // but it's never actually called by the compiler because - // _CxxFrameHandler3 is the personality function that is always used. - // Hence this is just an aborting stub. + // __CxxFrameHandler3 (msvc) / __gxx_wasm_personality_v0 (wasm) is the + // personality function that is always used. Hence this is just an + // aborting stub. #[lang = "eh_personality"] fn rust_eh_personality() { core::intrinsics::abort() @@ -36,7 +37,6 @@ cfg_if::cfg_if! { mod gcc; } else { // Targets that don't support unwinding. - // - family=wasm // - os=none ("bare metal" targets) // - os=uefi // - os=espidf From 861c7e74c8bbc49082dcd38ef7169d99c69cd104 Mon Sep 17 00:00:00 2001 From: Noa Date: Thu, 22 Feb 2024 00:34:54 -0600 Subject: [PATCH 03/18] Fix llvm hang --- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 75d413dedad3e..4a4ac60d59eff 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1539,7 +1539,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let funclet; let llbb; let mut bx; - if base::wants_msvc_seh(self.cx.sess()) { + if base::wants_new_eh_instructions(self.cx.sess()) { // This is a basic block that we're aborting the program for, // notably in an `extern` function. These basic blocks are inserted // so that we assert that `extern` functions do indeed not panic, From 658a0a20eac4341e31c57cf08e019b53f09b93b4 Mon Sep 17 00:00:00 2001 From: Noa Date: Thu, 22 Feb 2024 16:52:48 -0600 Subject: [PATCH 04/18] Unconditionally pass -wasm-enable-eh --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 12 ++++++------ library/panic_unwind/src/lib.rs | 7 +------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e383673e1d4f2..51e1f408a6996 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -99,12 +99,12 @@ unsafe fn configure_llvm(sess: &Session) { } } - if sess.panic_strategy() == PanicStrategy::Unwind { - if sess.target.os == "emscripten" { - add("-enable-emscripten-cxx-exceptions", false); - } else if wants_wasm_eh(sess) { - add("-wasm-enable-eh", false); - } + if wants_wasm_eh(sess) { + add("-wasm-enable-eh", false); + } + + if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind { + add("-enable-emscripten-cxx-exceptions", false); } // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index bc3c9363d8abb..37e1d2cf6d167 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -60,12 +60,7 @@ cfg_if::cfg_if! { ))] { #[path = "gcc.rs"] mod real_imp; - } else if #[cfg(all(target_family = "wasm", panic = "unwind"))] { - // for now, PanicStrategy::Unwind is not the default for wasm targets, - // so we need the panic = "unwind" in the cfg above. to use llvm.wasm.throw, - // we need to pass -wasm-enable-eh to LLVM, but that only happens if rustc - // is compiling with -C panic=unwind. So, this lets us -Zbuild-std with - // panic=unwind, while keeping the default panic=abort working. + } else if #[cfg(target_family = "wasm")] { #[path = "wasm.rs"] mod real_imp; } else { From 125b26acf6f3127ecdd344c372691cefe0e9243e Mon Sep 17 00:00:00 2001 From: Noa Date: Thu, 22 Feb 2024 17:32:06 -0600 Subject: [PATCH 05/18] Use Itanium ABI for thrown exceptions --- library/panic_unwind/src/gcc.rs | 2 +- library/panic_unwind/src/lib.rs | 8 +---- library/panic_unwind/src/wasm.rs | 32 ------------------ library/unwind/src/lib.rs | 8 ++++- library/unwind/src/libunwind.rs | 2 +- library/unwind/src/unwinding.rs | 2 +- library/unwind/src/wasm.rs | 56 ++++++++++++++++++++++++++++++++ 7 files changed, 67 insertions(+), 43 deletions(-) delete mode 100644 library/panic_unwind/src/wasm.rs create mode 100644 library/unwind/src/wasm.rs diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index 54eb6627c0129..589d3c1b4d2d0 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -62,7 +62,7 @@ pub unsafe fn panic(data: Box) -> u32 { let exception = Box::new(Exception { _uwe: uw::_Unwind_Exception { exception_class: rust_exception_class(), - exception_cleanup, + exception_cleanup: Some(exception_cleanup), private: [core::ptr::null(); uw::unwinder_private_data_size], }, canary: &CANARY, diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 37e1d2cf6d167..dde1c64c6f193 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -16,10 +16,6 @@ #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![feature(core_intrinsics)] #![feature(lang_items)] -#![cfg_attr( - all(target_family = "wasm", not(target_os = "emscripten")), - feature(link_llvm_intrinsics) -)] #![feature(panic_unwind)] #![feature(staged_api)] #![feature(std_internals)] @@ -57,12 +53,10 @@ cfg_if::cfg_if! { target_os = "solid_asp3", all(target_family = "unix", not(target_os = "espidf")), all(target_vendor = "fortanix", target_env = "sgx"), + target_family = "wasm", ))] { #[path = "gcc.rs"] mod real_imp; - } else if #[cfg(target_family = "wasm")] { - #[path = "wasm.rs"] - mod real_imp; } else { // Targets that don't support unwinding. // - os=none ("bare metal" targets) diff --git a/library/panic_unwind/src/wasm.rs b/library/panic_unwind/src/wasm.rs deleted file mode 100644 index b11fb912b6301..0000000000000 --- a/library/panic_unwind/src/wasm.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Unwinding panics for wasm32. -use alloc::boxed::Box; -use core::any::Any; - -// The type of the exception payload that the wasm engine propagates -// through unwinding for us. LLVM requires that it be a thin pointer. -type Payload = Box>; - -extern "C" { - /// LLVM lowers this intrinsic to the `throw` instruction. - #[link_name = "llvm.wasm.throw"] - fn wasm_throw(tag: i32, ptr: *mut u8) -> !; -} - -pub unsafe fn panic(payload: Box) -> u32 { - // The payload we pass to `wasm_throw` will be exactly the argument we get - // in `cleanup` below. So we just box it up once, to get something pointer-sized. - let payload_box: Payload = Box::new(payload); - // The wasm `throw` instruction takes a "tag", which differentiates certain - // types of exceptions from others. LLVM currently just identifies these - // via integers, with 0 corresponding to C++ exceptions and 1 to C setjmp()/longjmp(). - // Ideally, we'd be able to choose something unique for Rust, such that we - // don't try to treat a C++ exception payload as a `Box>`, but - // otherwise, pretending to be C++ works for now. - wasm_throw(0, Box::into_raw(payload_box) as *mut u8) -} - -pub unsafe fn cleanup(payload_box: *mut u8) -> Box { - // Recover the underlying `Box`. - let payload_box: Payload = Box::from_raw(payload_box as *mut _); - *payload_box -} diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index f5988a4df1364..c25c949b942f9 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -6,6 +6,10 @@ #![feature(cfg_target_abi)] #![feature(strict_provenance)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] +#![cfg_attr( + all(target_family = "wasm", not(target_os = "emscripten")), + feature(link_llvm_intrinsics) +)] #![allow(internal_features)] cfg_if::cfg_if! { @@ -29,9 +33,11 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "xous")] { mod unwinding; pub use unwinding::*; + } else if #[cfg(target_family = "wasm")] { + mod wasm; + pub use wasm::*; } else { // no unwinder on the system! - // - wasm32 (not emscripten, which is "unix" family) // - os=none ("bare metal" targets) // - os=hermit // - os=uefi diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 1b5f6f9dde36c..617a2ad7ebcf6 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -91,7 +91,7 @@ pub struct _Unwind_Exception { pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = - extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); + Option; // FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in // the block are reexported in dylib build of std. This is needed when build rustc with diff --git a/library/unwind/src/unwinding.rs b/library/unwind/src/unwinding.rs index 1a4187b22200d..95e2eb000ccbd 100644 --- a/library/unwind/src/unwinding.rs +++ b/library/unwind/src/unwinding.rs @@ -46,7 +46,7 @@ pub const unwinder_private_data_size: usize = core::mem::size_of::(); pub type _Unwind_Exception_Cleanup_Fn = - extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); + Option; #[repr(C)] pub struct _Unwind_Exception { diff --git a/library/unwind/src/wasm.rs b/library/unwind/src/wasm.rs new file mode 100644 index 0000000000000..1de12905f89e5 --- /dev/null +++ b/library/unwind/src/wasm.rs @@ -0,0 +1,56 @@ +//! A shim for libunwind implemented in terms of the native wasm `throw` instruction. + +#![allow(nonstandard_style)] + +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9, // used only by ARM EHABI +} +pub use _Unwind_Reason_Code::*; + +pub type _Unwind_Exception_Class = u64; +pub type _Unwind_Word = *const u8; + +pub const unwinder_private_data_size: usize = 2; + +#[repr(C)] +pub struct _Unwind_Exception { + pub exception_class: _Unwind_Exception_Class, + pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, + pub private: [_Unwind_Word; unwinder_private_data_size], +} + +pub type _Unwind_Exception_Cleanup_Fn = + Option; + +pub unsafe fn _Unwind_DeleteException(exception: *mut _Unwind_Exception) { + if let Some(exception_cleanup) = unsafe { (*exception).exception_cleanup } { + exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, exception); + } +} + +pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code { + extern "C" { + /// LLVM lowers this intrinsic to the `throw` instruction. + // FIXME(coolreader18): move to stdarch + #[link_name = "llvm.wasm.throw"] + fn wasm_throw(tag: i32, ptr: *mut u8) -> !; + } + + // The wasm `throw` instruction takes a "tag", which differentiates certain + // types of exceptions from others. LLVM currently just identifies these + // via integers, with 0 corresponding to C++ exceptions and 1 to C setjmp()/longjmp(). + // Ideally, we'd be able to choose something unique for Rust, but for now, + // we pretend to be C++ and implement the Itanium exception-handling ABI. + wasm_throw(0, exception.cast()) +} From c7fcf437f1cde4e7f45dcdaf57e80f178d47bd65 Mon Sep 17 00:00:00 2001 From: Noa Date: Mon, 26 Feb 2024 11:56:48 -0600 Subject: [PATCH 06/18] Don't codegen wasm.throw unless with -Zbuild-std --- library/unwind/src/wasm.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/library/unwind/src/wasm.rs b/library/unwind/src/wasm.rs index 1de12905f89e5..b06671bcb8309 100644 --- a/library/unwind/src/wasm.rs +++ b/library/unwind/src/wasm.rs @@ -40,6 +40,7 @@ pub unsafe fn _Unwind_DeleteException(exception: *mut _Unwind_Exception) { } pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code { + #[cfg(panic = "unwind")] extern "C" { /// LLVM lowers this intrinsic to the `throw` instruction. // FIXME(coolreader18): move to stdarch @@ -52,5 +53,13 @@ pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwi // via integers, with 0 corresponding to C++ exceptions and 1 to C setjmp()/longjmp(). // Ideally, we'd be able to choose something unique for Rust, but for now, // we pretend to be C++ and implement the Itanium exception-handling ABI. - wasm_throw(0, exception.cast()) + cfg_if::cfg_if! { + // for now, unless we're -Zbuild-std with panic=unwind, never codegen a throw. + if #[cfg(panic = "unwind")] { + wasm_throw(0, exception.cast()) + } else { + let _ = exception; + core::arch::wasm32::unreachable() + } + } } From a5245ef284f70e048e9a4f6bbe1678067d0a3bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Tue, 27 Feb 2024 01:13:14 +0000 Subject: [PATCH 07/18] Hint user to update nightly on ICEs produced from outdated nightly --- compiler/rustc_driver_impl/Cargo.toml | 2 +- compiler/rustc_driver_impl/messages.ftl | 8 ++++ compiler/rustc_driver_impl/src/lib.rs | 42 +++++++++++++++++-- .../src/session_diagnostics.rs | 21 ++++++++++ 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 242aa06fe3e3c..fcc0afd3488b0 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -50,7 +50,7 @@ rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } serde_json = "1.0.59" shlex = "1.0" -time = { version = "0.3", default-features = false, features = ["alloc", "formatting"] } +time = { version = "0.3", default-features = false, features = ["alloc", "formatting", "parsing", "macros"] } tracing = { version = "0.1.35" } # tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 39462112dc287..4b0efeba4c6d7 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -1,6 +1,14 @@ driver_impl_ice = the compiler unexpectedly panicked. this is a bug. driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url} driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly +driver_impl_ice_bug_report_internal_feature_outdated = + using internal features is not supported and expected to cause internal compiler errors when used incorrectly + .outdated = it seems this '{$version}' is outdated, a newer nightly should have been released in the mean time + .update = please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists +driver_impl_ice_bug_report_outdated = + it seems this '{$version}' is outdated, a newer nightly should have been released in the mean time + .update = please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists + .url = we would appreciate a bug report: {$bug_report_url} driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden driver_impl_ice_flags = compiler flags: {$flags} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 692c059beb0c4..fcf18b6749796 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -57,7 +57,7 @@ use std::str; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; use std::time::{Instant, SystemTime}; -use time::OffsetDateTime; +use time::{Date, OffsetDateTime, Time}; #[allow(unused_macros)] macro do_not_use_print($($t:tt)*) { @@ -1370,6 +1370,9 @@ pub fn install_ice_hook( using_internal_features } +const DATE_FORMAT: &[time::format_description::FormatItem<'static>] = + &time::macros::format_description!("[year]-[month]-[day]"); + /// Prints the ICE message, including query stack, but without backtrace. /// /// The message will point the user at `bug_report_url` to report the ICE. @@ -1398,10 +1401,41 @@ fn report_ice( dcx.emit_err(session_diagnostics::Ice); } - if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { - dcx.emit_note(session_diagnostics::IceBugReportInternalFeature); + use time::ext::NumericalDuration; + + // Try to hint user to update nightly if applicable when reporting an ICE. + // Attempt to calculate when current version was released, and add 12 hours + // as buffer. If the current version's release timestamp is older than + // the system's current time + 24 hours + 12 hours buffer if we're on + // nightly. + if let Some("nightly") = option_env!("CFG_RELEASE_CHANNEL") + && let Some(version) = option_env!("CFG_VERSION") + && let Some(ver_date_str) = option_env!("CFG_VER_DATE") + && let Ok(ver_date) = Date::parse(&ver_date_str, DATE_FORMAT) + && let ver_datetime = OffsetDateTime::new_utc(ver_date, Time::MIDNIGHT) + && let system_datetime = OffsetDateTime::from(SystemTime::now()) + && system_datetime.checked_sub(36.hours()).is_some_and(|d| d > ver_datetime) + { + if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { + dcx.emit_note(session_diagnostics::IceBugReportInternalFeatureOutdated { + version, + note_update: (), + note_outdated: (), + }); + } else { + dcx.emit_note(session_diagnostics::IceBugReportOutdated { + version, + bug_report_url, + note_update: (), + note_url: (), + }); + } } else { - dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url }); + if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { + dcx.emit_note(session_diagnostics::IceBugReportInternalFeature); + } else { + dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url }); + } } let version = util::version_str!().unwrap_or("unknown_version"); diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index 2b31fdd77cca3..0c3909e68ca8f 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -46,6 +46,27 @@ pub(crate) struct IceBugReport<'a> { #[diag(driver_impl_ice_bug_report_internal_feature)] pub(crate) struct IceBugReportInternalFeature; +#[derive(Diagnostic)] +#[diag(driver_impl_ice_bug_report_outdated)] +pub(crate) struct IceBugReportOutdated<'a> { + pub version: &'a str, + pub bug_report_url: &'a str, + #[note(driver_impl_update)] + pub note_update: (), + #[note(driver_impl_url)] + pub note_url: (), +} + +#[derive(Diagnostic)] +#[diag(driver_impl_ice_bug_report_internal_feature_outdated)] +pub(crate) struct IceBugReportInternalFeatureOutdated<'a> { + pub version: &'a str, + #[note(driver_impl_outdated)] + pub note_outdated: (), + #[note(driver_impl_update)] + pub note_update: (), +} + #[derive(Diagnostic)] #[diag(driver_impl_ice_version)] pub(crate) struct IceVersion<'a> { From a0ca9b16338be84a520dd842d351de0679d5e2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Tue, 27 Feb 2024 12:40:02 +0000 Subject: [PATCH 08/18] Don't suggest update nightly if using internal features --- compiler/rustc_driver_impl/messages.ftl | 4 ---- compiler/rustc_driver_impl/src/lib.rs | 21 +++++++------------ .../src/session_diagnostics.rs | 10 --------- 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 4b0efeba4c6d7..5dd0295897b92 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -1,10 +1,6 @@ driver_impl_ice = the compiler unexpectedly panicked. this is a bug. driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url} driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly -driver_impl_ice_bug_report_internal_feature_outdated = - using internal features is not supported and expected to cause internal compiler errors when used incorrectly - .outdated = it seems this '{$version}' is outdated, a newer nightly should have been released in the mean time - .update = please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists driver_impl_ice_bug_report_outdated = it seems this '{$version}' is outdated, a newer nightly should have been released in the mean time .update = please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index fcf18b6749796..95747ee6cd50c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1415,21 +1415,14 @@ fn report_ice( && let ver_datetime = OffsetDateTime::new_utc(ver_date, Time::MIDNIGHT) && let system_datetime = OffsetDateTime::from(SystemTime::now()) && system_datetime.checked_sub(36.hours()).is_some_and(|d| d > ver_datetime) + && !using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { - if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { - dcx.emit_note(session_diagnostics::IceBugReportInternalFeatureOutdated { - version, - note_update: (), - note_outdated: (), - }); - } else { - dcx.emit_note(session_diagnostics::IceBugReportOutdated { - version, - bug_report_url, - note_update: (), - note_url: (), - }); - } + dcx.emit_note(session_diagnostics::IceBugReportOutdated { + version, + bug_report_url, + note_update: (), + note_url: (), + }); } else { if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { dcx.emit_note(session_diagnostics::IceBugReportInternalFeature); diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index 0c3909e68ca8f..62d0da62d2a79 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -57,16 +57,6 @@ pub(crate) struct IceBugReportOutdated<'a> { pub note_url: (), } -#[derive(Diagnostic)] -#[diag(driver_impl_ice_bug_report_internal_feature_outdated)] -pub(crate) struct IceBugReportInternalFeatureOutdated<'a> { - pub version: &'a str, - #[note(driver_impl_outdated)] - pub note_outdated: (), - #[note(driver_impl_update)] - pub note_update: (), -} - #[derive(Diagnostic)] #[diag(driver_impl_ice_version)] pub(crate) struct IceVersion<'a> { From 9c963fc5bcc5915db1b3f01c60d08add08504968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Tue, 27 Feb 2024 12:53:41 +0000 Subject: [PATCH 09/18] Adjust wording --- compiler/rustc_driver_impl/messages.ftl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 5dd0295897b92..1b69a6e2fbecc 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -2,9 +2,9 @@ driver_impl_ice = the compiler unexpectedly panicked. this is a bug. driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url} driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly driver_impl_ice_bug_report_outdated = - it seems this '{$version}' is outdated, a newer nightly should have been released in the mean time + it seems that this compiler `{$version}` is outdated, a newer nightly should have been released in the mean time .update = please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists - .url = we would appreciate a bug report: {$bug_report_url} + .url = if the problem still persists, we would appreciate a bug report: {$bug_report_url} driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden driver_impl_ice_flags = compiler flags: {$flags} From a9a979839bbdfec48c75d618ab0dce8a953589b8 Mon Sep 17 00:00:00 2001 From: Sundeep KOKKONDA <56015745+sundeep-kokkonda@users.noreply.github.com> Date: Mon, 4 Mar 2024 08:18:54 +0530 Subject: [PATCH 10/18] Removing absolute path in proc-macro With rust 1.75 the absolute build path is embedding into '.rustc' section and which causes reproducibility issues. Detailed issue is here. https://github.com/rust-lang/rust/issues/120825#issuecomment-1964307219 With this change the 'absolute path' changed back to '/rust/$hash' format. --- compiler/rustc_session/src/session.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 09fb6aa5d8f98..6a76d78b33f3d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -898,19 +898,6 @@ impl Session { } pub fn should_prefer_remapped_for_codegen(&self) -> bool { - // bail out, if any of the requested crate types aren't: - // "compiled executables or libraries" - for crate_type in &self.opts.crate_types { - match crate_type { - CrateType::Executable - | CrateType::Dylib - | CrateType::Rlib - | CrateType::Staticlib - | CrateType::Cdylib => continue, - CrateType::ProcMacro => return false, - } - } - let has_split_debuginfo = match self.split_debuginfo() { SplitDebuginfo::Off => false, SplitDebuginfo::Packed => true, From 6e9f59f967f6d749f0a20f0c9042dd93b39e4651 Mon Sep 17 00:00:00 2001 From: surechen Date: Mon, 4 Mar 2024 12:28:59 +0800 Subject: [PATCH 11/18] add test for #78894 --- .../use-redundant/use-redundant-issue-78894.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/ui/lint/use-redundant/use-redundant-issue-78894.rs diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-78894.rs b/tests/ui/lint/use-redundant/use-redundant-issue-78894.rs new file mode 100644 index 0000000000000..1a81c16f954d8 --- /dev/null +++ b/tests/ui/lint/use-redundant/use-redundant-issue-78894.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ edition:2018 +#![warn(unused_imports)] + +fn main () +{ + bar!(); + + macro_rules! bar { + () => (); + } + + use bar; +} From 4e03c51f7d693258cdffc9d6b66e7930cbe8509f Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 4 Mar 2024 11:34:10 +0000 Subject: [PATCH 12/18] hir_analysis: enums return `None` in `find_field` Unnamed union fields with enums are checked for, but if `find_field` causes an ICE then the compiler won't get to that point. Signed-off-by: David Wood --- compiler/rustc_hir_analysis/src/collect.rs | 7 ++- .../unnamed-enum-field-issue-121757.rs | 25 +++++++++++ .../unnamed-enum-field-issue-121757.stderr | 45 +++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.rs create mode 100644 tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.stderr diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b6e2695590c13..2cc37651ef521 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -791,7 +791,12 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { } fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option { - tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| { + let adt = tcx.adt_def(def_id); + if adt.is_enum() { + return None; + } + + adt.non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| { if field.is_unnamed() { let field_ty = tcx.type_of(field.did).instantiate_identity(); let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); diff --git a/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.rs b/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.rs new file mode 100644 index 0000000000000..5d15ec4cffdb9 --- /dev/null +++ b/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.rs @@ -0,0 +1,25 @@ +type NodeId = u32; +struct Type<'a>(std::marker::PhantomData::<&'a ()>); + +type Ast<'ast> = &'ast AstStructure<'ast>; + +struct AstStructure<'ast> { +//~^ ERROR struct with unnamed fields must have `#[repr(C)]` representation + id: NodeId, + _: AstKind<'ast> +//~^ ERROR unnamed fields are not yet fully implemented [E0658] +//~^^ ERROR unnamed fields can only have struct or union types +} + +enum AstKind<'ast> { + ExprInt, + ExprLambda(Ast<'ast>), +} + +fn compute_types<'tcx,'ast>(ast: Ast<'ast>) -> Type<'tcx> +{ + match ast.kind {} +//~^ ERROR no field `kind` on type `&'ast AstStructure<'ast>` [E0609] +} + +fn main() {} diff --git a/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.stderr b/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.stderr new file mode 100644 index 0000000000000..4ea910202de98 --- /dev/null +++ b/tests/ui/union/unnamed-fields/unnamed-enum-field-issue-121757.stderr @@ -0,0 +1,45 @@ +error[E0658]: unnamed fields are not yet fully implemented + --> $DIR/unnamed-enum-field-issue-121757.rs:9:5 + | +LL | _: AstKind<'ast> + | ^ + | + = note: see issue #49804 for more information + = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: struct with unnamed fields must have `#[repr(C)]` representation + --> $DIR/unnamed-enum-field-issue-121757.rs:6:1 + | +LL | struct AstStructure<'ast> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ struct `AstStructure` defined here + | +note: unnamed field defined here + --> $DIR/unnamed-enum-field-issue-121757.rs:9:5 + | +LL | _: AstKind<'ast> + | ^^^^^^^^^^^^^^^^ +help: add `#[repr(C)]` to this struct + | +LL + #[repr(C)] +LL | struct AstStructure<'ast> { + | + +error: unnamed fields can only have struct or union types + --> $DIR/unnamed-enum-field-issue-121757.rs:9:5 + | +LL | _: AstKind<'ast> + | ^^^^^^^^^^^^^^^^ + +error[E0609]: no field `kind` on type `&'ast AstStructure<'ast>` + --> $DIR/unnamed-enum-field-issue-121757.rs:21:15 + | +LL | match ast.kind {} + | ^^^^ unknown field + | + = note: available fields are: `id`, `_` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0609, E0658. +For more information about an error, try `rustc --explain E0609`. From 640e99ccc982586352b1ad94c350af3cbeff3c2e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Mar 2024 14:30:46 +0100 Subject: [PATCH 13/18] Fix duplicated path in the "not found dylib" error --- compiler/rustc_metadata/src/creader.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f65fe1a29c7cc..564c35f881d60 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1132,7 +1132,13 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result { // Only try to recover from this specific error. if !matches!(err, libloading::Error::LoadLibraryExW { .. }) { - return Err(err.to_string()); + let err = format_dlopen_err(&err); + // We include the path of the dylib in the error ourselves, so + // if it's in the error, we strip it. + if let Some(err) = err.strip_prefix(&format!(": {}", path.display())) { + return Err(err.to_string()); + } + return Err(err); } last_error = Some(err); From 5e6e140b0cf44079cd0f42ba8bfcbf874859dd68 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Mar 2024 14:31:23 +0100 Subject: [PATCH 14/18] Add regression ui test for duplicated path in dylib error --- tests/ui/codegen/duplicated-path-in-error.rs | 7 +++++++ tests/ui/codegen/duplicated-path-in-error.stderr | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 tests/ui/codegen/duplicated-path-in-error.rs create mode 100644 tests/ui/codegen/duplicated-path-in-error.stderr diff --git a/tests/ui/codegen/duplicated-path-in-error.rs b/tests/ui/codegen/duplicated-path-in-error.rs new file mode 100644 index 0000000000000..cff20dd9bd639 --- /dev/null +++ b/tests/ui/codegen/duplicated-path-in-error.rs @@ -0,0 +1,7 @@ +//@ only-linux +//@ compile-flags: -Zcodegen-backend=/non-existing-one.so + +// This test ensures that the error of the "not found dylib" doesn't duplicate +// the path of the dylib. + +fn main() {} diff --git a/tests/ui/codegen/duplicated-path-in-error.stderr b/tests/ui/codegen/duplicated-path-in-error.stderr new file mode 100644 index 0000000000000..d0d34e2f93468 --- /dev/null +++ b/tests/ui/codegen/duplicated-path-in-error.stderr @@ -0,0 +1,2 @@ +error: couldn't load codegen backend /non-existing-one.so: cannot open shared object file: No such file or directory + From 523ab25418f5bf624bdb7752ec9d9ecba9b8aa4e Mon Sep 17 00:00:00 2001 From: surechen Date: Mon, 4 Mar 2024 14:25:51 +0800 Subject: [PATCH 15/18] add test for #71450 --- .../use-redundant-issue-71450.rs | 45 +++++++++++++++++++ .../use-redundant-issue-71450.stderr | 17 +++++++ .../use-redundant-issue-78894.rs | 34 ++++++++++++++ .../use-redundant-issue-78894.stderr | 14 ++++++ 4 files changed, 110 insertions(+) create mode 100644 tests/ui/lint/use-redundant/use-redundant-issue-71450.rs create mode 100644 tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr create mode 100644 tests/ui/lint/use-redundant/use-redundant-issue-78894.stderr diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs b/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs new file mode 100644 index 0000000000000..d0fb3454d3f2b --- /dev/null +++ b/tests/ui/lint/use-redundant/use-redundant-issue-71450.rs @@ -0,0 +1,45 @@ +//@ check-pass + +#![warn(unused_imports)] + +mod foo { + use std::fmt; + + pub struct String; + + impl String { + pub fn new() -> String { + String{} + } + } + + impl fmt::Display for String { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "String") + } + } +} + +fn main() { + + { + use std::string::String; //~ WARNING the item `String` is imported redundantly + // 'String' from 'std::string::String'. + let s = String::new(); + println!("{}", s); + } + + { + // 'String' from 'std::string::String'. + let s = String::new(); + println!("{}", s); + } + + { + use foo::*; + // 'String' from 'foo::String'. + let s = String::new(); + println!("{}", s); + } + +} diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr new file mode 100644 index 0000000000000..b8832a3178371 --- /dev/null +++ b/tests/ui/lint/use-redundant/use-redundant-issue-71450.stderr @@ -0,0 +1,17 @@ +warning: the item `String` is imported redundantly + --> $DIR/use-redundant-issue-71450.rs:26:13 + | +LL | use std::string::String; + | ^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/prelude/mod.rs:LL:COL + | + = note: the item `String` is already defined here + | +note: the lint level is defined here + --> $DIR/use-redundant-issue-71450.rs:3:9 + | +LL | #![warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-78894.rs b/tests/ui/lint/use-redundant/use-redundant-issue-78894.rs index 1a81c16f954d8..09c87bc37a630 100644 --- a/tests/ui/lint/use-redundant/use-redundant-issue-78894.rs +++ b/tests/ui/lint/use-redundant/use-redundant-issue-78894.rs @@ -1,7 +1,16 @@ //@ check-pass //@ edition:2018 + #![warn(unused_imports)] +mod foo { + macro_rules! foo1 { + () => (); + } + + pub(crate) use foo1; +} + fn main () { bar!(); @@ -11,4 +20,29 @@ fn main () } use bar; + + mod m { + bar1!(); + + macro_rules! bar1 { + () => (); + } + + use bar1; + } + + { + foo::foo1!(); + } + + { + use foo::foo1; + foo1!(); + } + + { + use foo::foo1; //~ WARNING unused import: `foo::foo1` + foo::foo1!(); + } + } diff --git a/tests/ui/lint/use-redundant/use-redundant-issue-78894.stderr b/tests/ui/lint/use-redundant/use-redundant-issue-78894.stderr new file mode 100644 index 0000000000000..78dfe364223d4 --- /dev/null +++ b/tests/ui/lint/use-redundant/use-redundant-issue-78894.stderr @@ -0,0 +1,14 @@ +warning: unused import: `foo::foo1` + --> $DIR/use-redundant-issue-78894.rs:44:13 + | +LL | use foo::foo1; + | ^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/use-redundant-issue-78894.rs:4:9 + | +LL | #![warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +warning: 1 warning emitted + From 960dd38abe18f7da6a08866736ba77aa8259de33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Mar 2024 09:33:55 +0100 Subject: [PATCH 16/18] will_wake tests fail on Miri and that is expected --- library/alloc/tests/task.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/alloc/tests/task.rs b/library/alloc/tests/task.rs index 0f8d9218980e9..034039a1eae9d 100644 --- a/library/alloc/tests/task.rs +++ b/library/alloc/tests/task.rs @@ -4,6 +4,7 @@ use alloc::task::{LocalWake, Wake}; use core::task::{LocalWaker, Waker}; #[test] +#[cfg_attr(miri, should_panic)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it fails fn test_waker_will_wake_clone() { struct NoopWaker; @@ -19,6 +20,7 @@ fn test_waker_will_wake_clone() { } #[test] +#[cfg_attr(miri, should_panic)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it fails fn test_local_waker_will_wake_clone() { struct NoopWaker; From f391c0793b443d30ef8c4d4228550439d4dbfead Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Mar 2024 11:32:03 +0100 Subject: [PATCH 17/18] only set noalias on Box with the global allocator --- compiler/rustc_abi/src/lib.rs | 7 +++++-- .../example/mini_core.rs | 7 +++++-- .../rustc_codegen_cranelift/src/unsize.rs | 4 ---- .../rustc_codegen_gcc/example/mini_core.rs | 1 + .../src/debuginfo/metadata.rs | 10 ++++++--- compiler/rustc_codegen_ssa/src/mir/operand.rs | 1 + .../rustc_const_eval/src/interpret/place.rs | 1 + .../src/interpret/terminator.rs | 10 ++------- compiler/rustc_hir/src/lang_items.rs | 2 ++ compiler/rustc_middle/src/ty/layout.rs | 20 +++++++++++------- compiler/rustc_middle/src/ty/sty.rs | 21 +++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_ty_utils/src/abi.rs | 2 +- library/alloc/src/alloc.rs | 2 ++ library/alloc/src/boxed.rs | 3 +++ tests/codegen/function-arguments.rs | 10 +++++++++ tests/ui/abi/compatibility.rs | 1 + 17 files changed, 75 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 34529e0a086f3..4f2b9d0ef50d9 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1612,8 +1612,9 @@ pub enum PointerKind { SharedRef { frozen: bool }, /// Mutable reference. `unpin` indicates the absence of any pinned data. MutableRef { unpin: bool }, - /// Box. `unpin` indicates the absence of any pinned data. - Box { unpin: bool }, + /// Box. `unpin` indicates the absence of any pinned data. `global` indicates whether this box + /// uses the global allocator or a custom one. + Box { unpin: bool, global: bool }, } /// Note that this information is advisory only, and backends are free to ignore it. @@ -1622,6 +1623,8 @@ pub enum PointerKind { pub struct PointeeInfo { pub size: Size, pub align: Align, + /// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to + /// be reliable. pub safe: Option, } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index a79909ce0c878..67a0d0dabea94 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -525,8 +525,11 @@ pub struct Unique { impl CoerceUnsized> for Unique where T: Unsize {} impl DispatchFromDyn> for Unique where T: Unsize {} +#[lang = "global_alloc_ty"] +pub struct Global; + #[lang = "owned_box"] -pub struct Box(Unique, A); +pub struct Box(Unique, A); impl, U: ?Sized> CoerceUnsized> for Box {} @@ -536,7 +539,7 @@ impl Box { let size = intrinsics::size_of::(); let ptr = libc::malloc(size); intrinsics::copy(&val as *const T as *const u8, ptr, size); - Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, ()) + Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global) } } } diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index acfa461a6f30b..7b61dc64cb1ae 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -74,10 +74,6 @@ fn unsize_ptr<'tcx>( | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { (src, unsized_info(fx, *a, *b, old_info)) } - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { - let (a, b) = (src_layout.ty.boxed_ty(), dst_layout.ty.boxed_ty()); - (src, unsized_info(fx, a, b, old_info)) - } (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { assert_eq!(def_a, def_b); diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 230009741dc41..cc3d647c8c82f 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -472,6 +472,7 @@ pub trait Allocator { impl Allocator for () {} +#[lang = "global_alloc_ty"] pub struct Global; impl Allocator for Global {} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1a5f9b4294754..660f164736775 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -454,9 +454,13 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => { build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id) } - // Box may have a non-1-ZST allocator A. In that case, we - // cannot treat Box as just an owned alias of `*mut T`. - ty::Adt(def, args) if def.is_box() && cx.layout_of(args.type_at(1)).is_1zst() => { + // Some `Box` are newtyped pointers, make debuginfo aware of that. + // Only works if the allocator argument is a 1-ZST and hence irrelevant for layout + // (or if there is no allocator argument). + ty::Adt(def, args) + if def.is_box() + && args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) => + { build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id) } ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id), diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 94eb37e78e07d..932926976b58d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -204,6 +204,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { pub fn deref>(self, cx: &Cx) -> PlaceRef<'tcx, V> { if self.layout.ty.is_box() { + // Derefer should have removed all Box derefs bug!("dereferencing {:?} in codegen", self.layout.ty); } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 6e987784ff9ee..672008edfd36f 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -437,6 +437,7 @@ where trace!("deref to {} on {:?}", val.layout.ty, *val); if val.layout.ty.is_box() { + // Derefer should have removed all Box derefs bug!("dereferencing {}", val.layout.ty); } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index e72ace8be3559..d29e69d753ebb 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -359,14 +359,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Some(match ty.kind() { ty::Ref(_, ty, _) => *ty, ty::RawPtr(mt) => mt.ty, - // We should only accept `Box` with the default allocator. - // It's hard to test for that though so we accept every 1-ZST allocator. - ty::Adt(def, args) - if def.is_box() - && self.layout_of(args[1].expect_ty()).is_ok_and(|l| l.is_1zst()) => - { - args[0].expect_ty() - } + // We only accept `Box` with the default allocator. + _ if ty.is_box_global(*self.tcx) => ty.boxed_ty(), _ => return Ok(None), })) }; diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 8a89a3b5faa5e..5118bf5c3b7ab 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -267,6 +267,8 @@ language_item_table! { EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None; OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1); + GlobalAlloc, sym::global_alloc_ty, global_alloc_ty, Target::Struct, GenericRequirement::None; + // Experimental language item for Miri PtrUnique, sym::ptr_unique, ptr_unique, Target::Struct, GenericRequirement::Exact(1); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 5a0e2aa691d58..dda41f70f067a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -969,6 +969,8 @@ where } } + /// Compute the information for the pointer stored at the given offset inside this type. + /// This will recurse into fields of ADTs to find the inner pointer. fn ty_and_layout_pointee_info_at( this: TyAndLayout<'tcx>, cx: &C, @@ -1068,15 +1070,17 @@ where } } - // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. + // Fixup info for the first field of a `Box`. Recursive traversal will have found + // the raw pointer, so size and align are set to the boxed type, but `pointee.safe` + // will still be `None`. if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = this.ty.kind() { - if def.is_box() && offset.bytes() == 0 { - let optimize = tcx.sess.opts.optimize != OptLevel::No; - pointee.safe = Some(PointerKind::Box { - unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()), - }); - } + if offset.bytes() == 0 && this.ty.is_box() { + debug_assert!(pointee.safe.is_none()); + let optimize = tcx.sess.opts.optimize != OptLevel::No; + pointee.safe = Some(PointerKind::Box { + unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()), + global: this.ty.is_box_global(tcx), + }); } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 17659ac23307c..1f68571cd376b 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1999,6 +1999,27 @@ impl<'tcx> Ty<'tcx> { } } + /// Tests whether this is a Box using the global allocator. + #[inline] + pub fn is_box_global(self, tcx: TyCtxt<'tcx>) -> bool { + match self.kind() { + Adt(def, args) if def.is_box() => { + let Some(alloc) = args.get(1) else { + // Single-argument Box is always global. (for "minicore" tests) + return true; + }; + if let Some(alloc_adt) = alloc.expect_ty().ty_adt_def() { + let global_alloc = tcx.require_lang_item(LangItem::GlobalAlloc, None); + alloc_adt.did() == global_alloc + } else { + // Allocator is not an ADT... + false + } + } + _ => false, + } + } + /// Panics if called on any type other than `Box`. pub fn boxed_ty(self) -> Ty<'tcx> { match self.kind() { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3784a08b1b720..9e628e4ef91cf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -896,6 +896,7 @@ symbols! { generic_const_items, generic_param_attrs, get_context, + global_alloc_ty, global_allocator, global_asm, globs, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 43042dbd36641..a5328baadb5fc 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -452,7 +452,7 @@ fn adjust_for_rust_scalar<'tcx>( let no_alias = match kind { PointerKind::SharedRef { frozen } => frozen, PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref, - PointerKind::Box { unpin } => unpin && noalias_for_box, + PointerKind::Box { unpin, global } => unpin && global && noalias_for_box, }; // We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics // (see ). diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 0b1429397559d..ed7b0618e9be2 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -50,6 +50,8 @@ extern "Rust" { #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] #[cfg(not(test))] +// the compiler needs to know when a Box uses the global allocator vs a custom one +#[cfg_attr(not(bootstrap), lang = "global_alloc_ty")] pub struct Global; #[cfg(test)] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index b202d9250d5e4..2736e5ee6c588 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2062,6 +2062,9 @@ impl + ?Sized, A: Allocator> AsyncFn for Box #[unstable(feature = "coerce_unsized", issue = "18598")] impl, U: ?Sized, A: Allocator> CoerceUnsized> for Box {} +// It is quite crucial that we only allow the `Global` allocator here. +// Handling arbitrary custom allocators (which can affect the `Box` layout heavily!) +// would need a lot of codegen and interpreter adjustments. #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U: ?Sized> DispatchFromDyn> for Box {} diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index b75c188f51a9b..e6e2f64571497 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -2,6 +2,7 @@ #![crate_type = "lib"] #![feature(dyn_star)] #![feature(generic_nonzero)] +#![feature(allocator_api)] use std::mem::MaybeUninit; use std::num::NonZero; @@ -182,6 +183,15 @@ pub fn _box(x: Box) -> Box { x } +// With a custom allocator, it should *not* have `noalias`. (See +// for why.) The second argument is the allocator, +// which is a reference here that still carries `noalias` as usual. +// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1 %x.1) +#[no_mangle] +pub fn _box_custom(x: Box) { + drop(x) +} + // CHECK: noundef nonnull align 4 ptr @notunpin_box(ptr noundef nonnull align 4 %x) #[no_mangle] pub fn notunpin_box(x: Box) -> Box { diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 2449e515f5f5f..a4f60ea268464 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -160,6 +160,7 @@ mod prelude { pub _marker: PhantomData, } + #[lang = "global_alloc_ty"] pub struct Global; #[lang = "owned_box"] From da357346e802b6898e1c151420ce3c481896b3ef Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 Mar 2024 19:23:30 +0000 Subject: [PATCH 18/18] Merge `impl_trait_in_assoc_types_defined_by` query back into `opaque_types_defined_by` Instead, when we're collecting opaques for associated items, we choose the right collection mode depending on whether we're collecting for an associated item of a trait impl or not. --- .../src/collect/type_of/opaque.rs | 28 ++++++------------- compiler/rustc_middle/src/query/mod.rs | 9 ------ compiler/rustc_ty_utils/src/opaque_types.rs | 21 +++++--------- .../hidden_behind_struct_field2.rs | 2 +- .../hidden_behind_struct_field2.stderr | 13 ++++++--- .../hidden_behind_struct_field3.rs | 2 +- .../hidden_behind_struct_field3.stderr | 13 ++++++--- 7 files changed, 35 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index f0e998b7a0032..dcb01a117b047 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -46,9 +46,7 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type( for &assoc_id in tcx.associated_item_def_ids(impl_def_id) { let assoc = tcx.associated_item(assoc_id); match assoc.kind { - ty::AssocKind::Const | ty::AssocKind::Fn => { - locator.check(assoc_id.expect_local(), ImplTraitSource::AssocTy) - } + ty::AssocKind::Const | ty::AssocKind::Fn => locator.check(assoc_id.expect_local()), // Associated types don't have bodies, so they can't constrain hidden types ty::AssocKind::Type => {} } @@ -182,15 +180,9 @@ struct TaitConstraintLocator<'tcx> { typeck_types: Vec>, } -#[derive(Debug)] -enum ImplTraitSource { - AssocTy, - TyAlias, -} - impl TaitConstraintLocator<'_> { #[instrument(skip(self), level = "debug")] - fn check(&mut self, item_def_id: LocalDefId, source: ImplTraitSource) { + fn check(&mut self, item_def_id: LocalDefId) { // Don't try to check items that cannot possibly constrain the type. if !self.tcx.has_typeck_results(item_def_id) { debug!("no constraint: no typeck results"); @@ -242,12 +234,8 @@ impl TaitConstraintLocator<'_> { continue; } constrained = true; - let opaque_types_defined_by = match source { - ImplTraitSource::AssocTy => { - self.tcx.impl_trait_in_assoc_types_defined_by(item_def_id) - } - ImplTraitSource::TyAlias => self.tcx.opaque_types_defined_by(item_def_id), - }; + let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id); + if !opaque_types_defined_by.contains(&self.def_id) { self.tcx.dcx().emit_err(TaitForwardCompat { span: hidden_type.span, @@ -308,7 +296,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { } fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { if let hir::ExprKind::Closure(closure) = ex.kind { - self.check(closure.def_id, ImplTraitSource::TyAlias); + self.check(closure.def_id); } intravisit::walk_expr(self, ex); } @@ -316,7 +304,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. if it.owner_id.def_id != self.def_id { - self.check(it.owner_id.def_id, ImplTraitSource::TyAlias); + self.check(it.owner_id.def_id); intravisit::walk_item(self, it); } } @@ -324,13 +312,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. if it.owner_id.def_id != self.def_id { - self.check(it.owner_id.def_id, ImplTraitSource::TyAlias); + self.check(it.owner_id.def_id); intravisit::walk_impl_item(self, it); } } fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { trace!(?it.owner_id); - self.check(it.owner_id.def_id, ImplTraitSource::TyAlias); + self.check(it.owner_id.def_id); intravisit::walk_trait_item(self, it); } fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8357c21a3c2be..b0431ae05d395 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -344,15 +344,6 @@ rustc_queries! { } } - query impl_trait_in_assoc_types_defined_by( - key: LocalDefId - ) -> &'tcx ty::List { - desc { - |tcx| "computing the opaque types defined by `{}`", - tcx.def_path_str(key.to_def_id()) - } - } - /// Returns the list of bounds that can be used for /// `SelectionCandidate::ProjectionCandidate(_)` and /// `ProjectionTyCandidate::TraitDef`. diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 282595169737d..0ac14b338ac12 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -34,7 +34,11 @@ enum CollectionMode { } impl<'tcx> OpaqueTypeCollector<'tcx> { - fn new(tcx: TyCtxt<'tcx>, item: LocalDefId, mode: CollectionMode) -> Self { + fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self { + let mode = match tcx.def_kind(tcx.local_parent(item)) { + DefKind::Impl { of_trait: true } => CollectionMode::ImplTraitInAssocTypes, + _ => CollectionMode::TypeAliasImplTraitTransition, + }; Self { tcx, opaques: Vec::new(), item, seen: Default::default(), span: None, mode } } @@ -287,23 +291,13 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { } } -fn impl_trait_in_assoc_types_defined_by<'tcx>( - tcx: TyCtxt<'tcx>, - item: LocalDefId, -) -> &'tcx ty::List { - let mut collector = OpaqueTypeCollector::new(tcx, item, CollectionMode::ImplTraitInAssocTypes); - super::sig_types::walk_types(tcx, item, &mut collector); - tcx.mk_local_def_ids(&collector.opaques) -} - fn opaque_types_defined_by<'tcx>( tcx: TyCtxt<'tcx>, item: LocalDefId, ) -> &'tcx ty::List { let kind = tcx.def_kind(item); trace!(?kind); - let mut collector = - OpaqueTypeCollector::new(tcx, item, CollectionMode::TypeAliasImplTraitTransition); + let mut collector = OpaqueTypeCollector::new(tcx, item); super::sig_types::walk_types(tcx, item, &mut collector); match kind { DefKind::AssocFn @@ -346,6 +340,5 @@ fn opaque_types_defined_by<'tcx>( } pub(super) fn provide(providers: &mut Providers) { - *providers = - Providers { opaque_types_defined_by, impl_trait_in_assoc_types_defined_by, ..*providers }; + *providers = Providers { opaque_types_defined_by, ..*providers }; } diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs index 4c881dd133086..3117060cef0d2 100644 --- a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.rs @@ -15,7 +15,7 @@ impl Trait for Bar { type Assoc = impl std::fmt::Debug; fn foo() -> Foo { Foo { field: () } - //~^ ERROR: item constrains opaque type that is not in its signature + //~^ ERROR: mismatched types } } diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.stderr b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.stderr index 5c53dfa3a7500..4910e794e8d6e 100644 --- a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.stderr +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field2.stderr @@ -1,11 +1,15 @@ -error: item constrains opaque type that is not in its signature +error[E0308]: mismatched types --> $DIR/hidden_behind_struct_field2.rs:17:22 | +LL | type Assoc = impl std::fmt::Debug; + | -------------------- the expected opaque type +LL | fn foo() -> Foo { LL | Foo { field: () } - | ^^ + | ^^ expected opaque type, found `()` | - = note: this item must mention the opaque type in its signature in order to be able to register hidden types -note: this item must mention the opaque type in its signature in order to be able to register hidden types + = note: expected opaque type `::Assoc` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types --> $DIR/hidden_behind_struct_field2.rs:16:8 | LL | fn foo() -> Foo { @@ -13,3 +17,4 @@ LL | fn foo() -> Foo { error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field3.rs b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field3.rs index 1278563a92c46..c1f135994121e 100644 --- a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field3.rs +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field3.rs @@ -17,7 +17,7 @@ impl Trait for Bar { type Assoc = impl Iterator; fn foo() -> Self::Assoc { vec![Foo { field: () }].into_iter() - //~^ ERROR item constrains opaque type that is not in its signature + //~^ ERROR mismatched types } } diff --git a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field3.stderr b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field3.stderr index 0570e0303c633..f10ccc0029973 100644 --- a/tests/ui/type-alias-impl-trait/hidden_behind_struct_field3.stderr +++ b/tests/ui/type-alias-impl-trait/hidden_behind_struct_field3.stderr @@ -1,11 +1,15 @@ -error: item constrains opaque type that is not in its signature +error[E0308]: mismatched types --> $DIR/hidden_behind_struct_field3.rs:19:27 | +LL | type Assoc2 = impl std::fmt::Debug; + | -------------------- the expected opaque type +... LL | vec![Foo { field: () }].into_iter() - | ^^ + | ^^ expected opaque type, found `()` | - = note: this item must mention the opaque type in its signature in order to be able to register hidden types -note: this item must mention the opaque type in its signature in order to be able to register hidden types + = note: expected opaque type `::Assoc2` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types --> $DIR/hidden_behind_struct_field3.rs:18:8 | LL | fn foo() -> Self::Assoc { @@ -13,3 +17,4 @@ LL | fn foo() -> Self::Assoc { error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0308`.