From 6776af529a163d5830fea577cf00619940b27908 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 13 Mar 2023 16:31:48 +0100 Subject: [PATCH 1/5] std: use `LazyLock` to lazily resolve backtraces --- library/std/src/backtrace.rs | 63 ++++++------------------------ library/std/src/backtrace/tests.rs | 6 +-- library/std/src/lib.rs | 1 + library/std/src/sync/lazy_lock.rs | 9 +++++ library/std/tests/backtrace.rs | 10 +++++ 5 files changed, 35 insertions(+), 54 deletions(-) create mode 100644 library/std/tests/backtrace.rs diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 7543ffadd4140..18d5f3e910838 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -89,12 +89,11 @@ mod tests; // a backtrace or actually symbolizing it. use crate::backtrace_rs::{self, BytesOrWideString}; -use crate::cell::UnsafeCell; use crate::env; use crate::ffi::c_void; use crate::fmt; use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed}; -use crate::sync::Once; +use crate::sync::LazyLock; use crate::sys_common::backtrace::{lock, output_filename}; use crate::vec::Vec; @@ -133,20 +132,14 @@ pub enum BacktraceStatus { enum Inner { Unsupported, Disabled, - Captured(LazilyResolvedCapture), + Captured(LazyLock), } struct Capture { actual_start: usize, - resolved: bool, frames: Vec, } -fn _assert_send_sync() { - fn _assert() {} - _assert::(); -} - /// A single frame of a backtrace. #[unstable(feature = "backtrace_frames", issue = "79676")] pub struct BacktraceFrame { @@ -179,7 +172,7 @@ impl fmt::Debug for Backtrace { let capture = match &self.inner { Inner::Unsupported => return fmt.write_str(""), Inner::Disabled => return fmt.write_str(""), - Inner::Captured(c) => c.force(), + Inner::Captured(c) => &**c, }; let frames = &capture.frames[capture.actual_start..]; @@ -347,11 +340,10 @@ impl Backtrace { let inner = if frames.is_empty() { Inner::Unsupported } else { - Inner::Captured(LazilyResolvedCapture::new(Capture { + Inner::Captured(LazyLock::new(lazy_resolve(Capture { actual_start: actual_start.unwrap_or(0), frames, - resolved: false, - })) + }))) }; Backtrace { inner } @@ -376,7 +368,7 @@ impl<'a> Backtrace { #[must_use] #[unstable(feature = "backtrace_frames", issue = "79676")] pub fn frames(&'a self) -> &'a [BacktraceFrame] { - if let Inner::Captured(c) = &self.inner { &c.force().frames } else { &[] } + if let Inner::Captured(c) = &self.inner { &c.frames } else { &[] } } } @@ -386,7 +378,7 @@ impl fmt::Display for Backtrace { let capture = match &self.inner { Inner::Unsupported => return fmt.write_str("unsupported backtrace"), Inner::Disabled => return fmt.write_str("disabled backtrace"), - Inner::Captured(c) => c.force(), + Inner::Captured(c) => &**c, }; let full = fmt.alternate(); @@ -430,46 +422,15 @@ impl fmt::Display for Backtrace { } } -struct LazilyResolvedCapture { - sync: Once, - capture: UnsafeCell, -} - -impl LazilyResolvedCapture { - fn new(capture: Capture) -> Self { - LazilyResolvedCapture { sync: Once::new(), capture: UnsafeCell::new(capture) } - } - - fn force(&self) -> &Capture { - self.sync.call_once(|| { - // SAFETY: This exclusive reference can't overlap with any others - // `Once` guarantees callers will block until this closure returns - // `Once` also guarantees only a single caller will enter this closure - unsafe { &mut *self.capture.get() }.resolve(); - }); - - // SAFETY: This shared reference can't overlap with the exclusive reference above - unsafe { &*self.capture.get() } - } -} - -// SAFETY: Access to the inner value is synchronized using a thread-safe `Once` -// So long as `Capture` is `Sync`, `LazilyResolvedCapture` is too -unsafe impl Sync for LazilyResolvedCapture where Capture: Sync {} - -impl Capture { - fn resolve(&mut self) { - // If we're already resolved, nothing to do! - if self.resolved { - return; - } - self.resolved = true; +type LazyResolve = impl FnOnce() -> Capture; +fn lazy_resolve(mut capture: Capture) -> LazyResolve { + move || { // Use the global backtrace lock to synchronize this as it's a // requirement of the `backtrace` crate, and then actually resolve // everything. let _lock = lock(); - for frame in self.frames.iter_mut() { + for frame in capture.frames.iter_mut() { let symbols = &mut frame.symbols; let frame = match &frame.frame { RawFrame::Actual(frame) => frame, @@ -490,6 +451,8 @@ impl Capture { }); } } + + capture } } diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs index 4dfbf88e83ebc..ef419806dccbd 100644 --- a/library/std/src/backtrace/tests.rs +++ b/library/std/src/backtrace/tests.rs @@ -43,9 +43,8 @@ fn generate_fake_frames() -> Vec { #[test] fn test_debug() { let backtrace = Backtrace { - inner: Inner::Captured(LazilyResolvedCapture::new(Capture { + inner: Inner::Captured(LazyLock::preinit(Capture { actual_start: 1, - resolved: true, frames: generate_fake_frames(), })), }; @@ -66,9 +65,8 @@ fn test_debug() { #[test] fn test_frames() { let backtrace = Backtrace { - inner: Inner::Captured(LazilyResolvedCapture::new(Capture { + inner: Inner::Captured(LazyLock::preinit(Capture { actual_start: 1, - resolved: true, frames: generate_fake_frames(), })), }; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 318a46d1b637e..e3d6ce3a99613 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -271,6 +271,7 @@ #![feature(staged_api)] #![feature(thread_local)] #![feature(try_blocks)] +#![feature(type_alias_impl_trait)] #![feature(utf8_chunks)] // tidy-alphabetical-end // diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index a6bc468b09281..1fdb7e75c9c1e 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -69,6 +69,15 @@ impl T> LazyLock { LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) } } + /// Creates a new lazy value that is already initialized. + #[inline] + #[cfg(test)] + pub(crate) fn preinit(value: T) -> LazyLock { + let once = Once::new(); + once.call_once(|| {}); + LazyLock { once, data: UnsafeCell::new(Data { value: ManuallyDrop::new(value) }) } + } + /// Consumes this `LazyLock` returning the stored value. /// /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. diff --git a/library/std/tests/backtrace.rs b/library/std/tests/backtrace.rs new file mode 100644 index 0000000000000..531c5f89cf67f --- /dev/null +++ b/library/std/tests/backtrace.rs @@ -0,0 +1,10 @@ +use std::backtrace::Backtrace; + +// Unfortunately, this cannot be a unit test because that causes problems +// with type-alias-impl-trait (the assert counts as a defining use). +#[test] +fn assert_send_sync() { + fn assert() {} + + assert::(); +} From 29e3f8b793ec3b76fdba8075adfada21ce2a220a Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 26 Jul 2023 12:30:52 +0200 Subject: [PATCH 2/5] std: add auto traits to TAIT bound --- library/std/src/backtrace.rs | 7 ++++++- library/std/tests/backtrace.rs | 10 ---------- 2 files changed, 6 insertions(+), 11 deletions(-) delete mode 100644 library/std/tests/backtrace.rs diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 18d5f3e910838..f0e199fac737c 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -140,6 +140,11 @@ struct Capture { frames: Vec, } +fn _assert_send_sync() { + fn _assert() {} + _assert::(); +} + /// A single frame of a backtrace. #[unstable(feature = "backtrace_frames", issue = "79676")] pub struct BacktraceFrame { @@ -422,7 +427,7 @@ impl fmt::Display for Backtrace { } } -type LazyResolve = impl FnOnce() -> Capture; +type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync; fn lazy_resolve(mut capture: Capture) -> LazyResolve { move || { diff --git a/library/std/tests/backtrace.rs b/library/std/tests/backtrace.rs deleted file mode 100644 index 531c5f89cf67f..0000000000000 --- a/library/std/tests/backtrace.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::backtrace::Backtrace; - -// Unfortunately, this cannot be a unit test because that causes problems -// with type-alias-impl-trait (the assert counts as a defining use). -#[test] -fn assert_send_sync() { - fn assert() {} - - assert::(); -} From 0f0ab89feb4d668cb989aefe08f27af45cb10bed Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 16 Jul 2023 01:41:20 +0000 Subject: [PATCH 3/5] Don't install default projection bound for RPITITs --- compiler/rustc_metadata/src/rmeta/encoder.rs | 8 +------- compiler/rustc_ty_utils/src/ty.rs | 4 +++- .../in-trait/check-wf-on-non-defaulted-rpitit.rs | 10 ++++++++++ .../check-wf-on-non-defaulted-rpitit.stderr | 16 ++++++++++++++++ 4 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs create mode 100644 tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 0025dc9033c57..d72053ca98533 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1144,13 +1144,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> let assoc_item = tcx.associated_item(def_id); match assoc_item.container { ty::AssocItemContainer::ImplContainer => true, - // Always encode RPITITs, since we need to be able to project - // from an RPITIT associated item to an opaque when installing - // the default projection predicates in default trait methods - // with RPITITs. - ty::AssocItemContainer::TraitContainer => { - assoc_item.defaultness(tcx).has_value() || assoc_item.is_impl_trait_in_trait() - } + ty::AssocItemContainer::TraitContainer => assoc_item.defaultness(tcx).has_value(), } } DefKind::TyParam => { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2055852eda070..4c896712b1b92 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -129,7 +129,9 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // sure that this will succeed without errors anyway. if tcx.def_kind(def_id) == DefKind::AssocFn - && tcx.associated_item(def_id).container == ty::AssocItemContainer::TraitContainer + && let assoc_item = tcx.associated_item(def_id) + && assoc_item.container == ty::AssocItemContainer::TraitContainer + && assoc_item.defaultness(tcx).has_value() { let sig = tcx.fn_sig(def_id).instantiate_identity(); // We accounted for the binder of the fn sig, so skip the binder. diff --git a/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs new file mode 100644 index 0000000000000..742537ffcc43b --- /dev/null +++ b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs @@ -0,0 +1,10 @@ +#![feature(return_position_impl_trait_in_trait)] + +struct Wrapper(G); + +trait Foo { + fn bar() -> Wrapper; + //~^ ERROR `impl Sized` cannot be sent between threads safely +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr new file mode 100644 index 0000000000000..dee87d0823864 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr @@ -0,0 +1,16 @@ +error[E0277]: `impl Sized` cannot be sent between threads safely + --> $DIR/check-wf-on-non-defaulted-rpitit.rs:6:17 + | +LL | fn bar() -> Wrapper; + | ^^^^^^^^^^^^^^^^^^^ `impl Sized` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `impl Sized` +note: required by a bound in `Wrapper` + --> $DIR/check-wf-on-non-defaulted-rpitit.rs:3:19 + | +LL | struct Wrapper(G); + | ^^^^ required by this bound in `Wrapper` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 0b4a80f41710c6eb577970045c371f7765f6cadf Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sun, 30 Jul 2023 22:03:36 +0100 Subject: [PATCH 4/5] Fix empty_write since rust version attribute --- library/std/src/io/util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index 202c0a9a69cec..3840ffe7eecaa 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -100,7 +100,7 @@ impl SizeHint for Empty { } } -#[stable(feature = "empty_write", since = "1.64.0")] +#[stable(feature = "empty_write", since = "CURRENT_RUSTC_VERSION")] impl Write for Empty { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { @@ -124,7 +124,7 @@ impl Write for Empty { } } -#[stable(feature = "empty_write", since = "1.64.0")] +#[stable(feature = "empty_write", since = "CURRENT_RUSTC_VERSION")] impl Write for &Empty { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { From ee29d2fd0a0b53f3460a9ffe67db6473e5913385 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 12 Apr 2022 01:29:16 -0500 Subject: [PATCH 5/5] Stabilize const-weak-new Bump its stabilization version several times along the way to accommodate changes in release processes. Co-authored-by: Mara Bos Co-authored-by: Trevor Gross --- library/alloc/src/rc.rs | 2 +- library/alloc/src/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index d0d37c08d1306..a00174ceac694 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2112,7 +2112,7 @@ impl Weak { /// assert!(empty.upgrade().is_none()); /// ``` #[stable(feature = "downgraded_weak", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")] + #[rustc_const_stable(feature = "const_weak_new", since = "CURRENT_RUSTC_VERSION")] #[must_use] pub const fn new() -> Weak { Weak { ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::>(usize::MAX)) } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a19999cd72580..f6c7ab27ba7de 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1743,7 +1743,7 @@ impl Weak { /// assert!(empty.upgrade().is_none()); /// ``` #[stable(feature = "downgraded_weak", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")] + #[rustc_const_stable(feature = "const_weak_new", since = "CURRENT_RUSTC_VERSION")] #[must_use] pub const fn new() -> Weak { Weak { ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::>(usize::MAX)) } }