diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 56cfbf138af00..5322b451fc6e8 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2450,12 +2450,22 @@ pub enum AbiFromStrErr { NoExplicitUnwind, } +/// The layout information for a variant. +/// +/// For items with multiple variants ([`Variants::Multiple`]), the layout information of each +/// variant largely matches that of the overall item. So, instead of giving each one a new [`LayoutData`], +/// we use this struct, which stores only the information that differs between the variants. +/// +/// See for more context. // NOTE: This struct is generic over the FieldIdx for rust-analyzer usage. #[derive(PartialEq, Eq, Hash, Clone, Debug)] #[cfg_attr(feature = "nightly", derive(StableHash))] pub struct VariantLayout { + // FIXME: ideally we'd remove these as variants should not have their own + // size or backend_repr. pub size: Size, pub backend_repr: BackendRepr, + pub field_offsets: IndexVec, fields_in_memory_order: IndexVec, largest_niche: Option, diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 0443d48c597f1..cf0194c9613a6 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -30,7 +30,7 @@ //! then mean that all later passes would have to check for these figments //! and report an error, and it just seems like more mess in the end.) -use std::iter; +use std::{cmp, iter}; use rustc_abi::FIRST_VARIANT; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -2608,56 +2608,18 @@ fn determine_capture_info( capture_info_a: ty::CaptureInfo, capture_info_b: ty::CaptureInfo, ) -> ty::CaptureInfo { - // If the capture kind is equivalent then, we don't need to escalate and can compare the - // expressions. - let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) { - (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true, - (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) => true, - (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b, - (ty::UpvarCapture::ByValue, _) - | (ty::UpvarCapture::ByUse, _) - | (ty::UpvarCapture::ByRef(_), _) => false, - }; - - if eq_capture_kind { - match (capture_info_a.capture_kind_expr_id, capture_info_b.capture_kind_expr_id) { - (Some(_), _) | (None, None) => capture_info_a, - (None, Some(_)) => capture_info_b, - } - } else { - // We select the CaptureKind which ranks higher based the following priority order: - // (ByUse | ByValue) > MutBorrow > UniqueImmBorrow > ImmBorrow - match (capture_info_a.capture_kind, capture_info_b.capture_kind) { - (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByValue) - | (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByUse) => { - bug!("Same capture can't be ByUse and ByValue at the same time") - } - (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) - | (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) - | (ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse, ty::UpvarCapture::ByRef(_)) => { - capture_info_a - } - (ty::UpvarCapture::ByRef(_), ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse) => { - capture_info_b - } - (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { - match (ref_a, ref_b) { - // Take LHS: - (BorrowKind::UniqueImmutable | BorrowKind::Mutable, BorrowKind::Immutable) - | (BorrowKind::Mutable, BorrowKind::UniqueImmutable) => capture_info_a, - - // Take RHS: - (BorrowKind::Immutable, BorrowKind::UniqueImmutable | BorrowKind::Mutable) - | (BorrowKind::UniqueImmutable, BorrowKind::Mutable) => capture_info_b, - - (BorrowKind::Immutable, BorrowKind::Immutable) - | (BorrowKind::UniqueImmutable, BorrowKind::UniqueImmutable) - | (BorrowKind::Mutable, BorrowKind::Mutable) => { - bug!("Expected unequal capture kinds"); - } - } + // We select the CaptureKind which ranks higher based the following priority order: + // (ByUse | ByValue) > MutBorrow > UniqueImmBorrow > ImmBorrow + match capture_info_a.capture_kind.partial_cmp(&capture_info_b.capture_kind) { + Some(cmp::Ordering::Equal) => { + match (capture_info_a.capture_kind_expr_id, capture_info_b.capture_kind_expr_id) { + (Some(_), _) | (None, None) => capture_info_a, + (None, Some(_)) => capture_info_b, } } + Some(cmp::Ordering::Greater) => capture_info_a, + Some(cmp::Ordering::Less) => capture_info_b, + None => bug!("Same capture can't be ByUse and ByValue at the same time"), } } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 652c353d418c2..4b410b3259bff 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -1,3 +1,4 @@ +use std::cmp; use std::fmt::Write; use rustc_data_structures::fx::FxIndexMap; @@ -46,16 +47,32 @@ impl UpvarId { #[derive(Eq, PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, StableHash, Hash)] #[derive(TypeFoldable, TypeVisitable)] pub enum UpvarCapture { + /// Upvar is captured by reference. + ByRef(BorrowKind), + + /// Upvar is captured by use. This is true when the closure is labeled `use`. + ByUse, + /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases /// depending on inference. ByValue, +} - /// Upvar is captured by use. This is true when the closure is labeled `use`. - ByUse, - - /// Upvar is captured by reference. - ByRef(BorrowKind), +// Used in rustc_hir_typeck::upvar::determine_capture_info +impl PartialOrd for UpvarCapture { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + match (self, other) { + (Self::ByValue, Self::ByValue) | (Self::ByUse, Self::ByUse) => { + Some(cmp::Ordering::Equal) + } + (Self::ByValue | Self::ByUse, Self::ByRef(_)) => Some(cmp::Ordering::Greater), + (Self::ByRef(_), Self::ByValue | Self::ByUse) => Some(cmp::Ordering::Less), + (Self::ByRef(left), Self::ByRef(right)) => Some(left.cmp(&right)), + (Self::ByUse, Self::ByValue) | (Self::ByValue, Self::ByUse) => None, + } + } } /// Given the closure DefId this map provides a map of root variables to minimum @@ -339,8 +356,21 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc curr_string } -#[derive(Eq, Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, StableHash, Hash)] -#[derive(TypeFoldable, TypeVisitable)] +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, // Order of variants is load-bearing + Ord, + TyEncodable, + TyDecodable, + StableHash, + TypeFoldable, + TypeVisitable +)] pub enum BorrowKind { /// Data must be immutable and is aliasable. Immutable, diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 2fe7c8c305afe..f53eb4a294194 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1202,9 +1202,9 @@ impl Option { /// Returns the provided default result (if none), /// or applies a function to the contained value (if any). /// - /// Arguments passed to `map_or` are eagerly evaluated; if you are passing + /// The `default` argument passed to `map_or` is eagerly evaluated; if you are passing /// the result of a function call, it is recommended to use [`map_or_else`], - /// which is lazily evaluated. + /// which lazily evaluates `default`. /// /// [`map_or_else`]: Option::map_or_else /// diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 472d568c5cf66..f1d412eeefcf3 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -842,9 +842,9 @@ impl Result { /// Returns the provided default (if [`Err`]), or /// applies a function to the contained value (if [`Ok`]). /// - /// Arguments passed to `map_or` are eagerly evaluated; if you are passing + /// The `default` argument passed to `map_or` is eagerly evaluated; if you are passing /// the result of a function call, it is recommended to use [`map_or_else`], - /// which is lazily evaluated. + /// which lazily evaluates `default`. /// /// [`map_or_else`]: Result::map_or_else /// diff --git a/library/core/src/sync/mod.rs b/library/core/src/sync/mod.rs index 6c2660263a705..bd85bffcf192a 100644 --- a/library/core/src/sync/mod.rs +++ b/library/core/src/sync/mod.rs @@ -4,5 +4,5 @@ pub mod atomic; mod sync_view; -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] pub use sync_view::SyncView; diff --git a/library/core/src/sync/sync_view.rs b/library/core/src/sync/sync_view.rs index f4822048d2153..5c1e24125cf74 100644 --- a/library/core/src/sync/sync_view.rs +++ b/library/core/src/sync/sync_view.rs @@ -47,8 +47,6 @@ use core::task::{Context, Poll}; /// functionality: /// /// ```ignore-wasm -/// #![feature(exclusive_wrapper)] -/// /// use std::sync::SyncView; /// use std::sync::mpsc::{self, Receiver}; /// use std::thread; @@ -91,7 +89,7 @@ use core::task::{Context, Poll}; /// for any value. This is a parallel with the fact that /// `&` and `&mut` references together can be thought of as a _compile-time_ /// version of a read-write lock. -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[doc(alias = "SyncWrapper")] #[doc(alias = "SyncCell")] #[doc(alias = "Unique")] @@ -105,10 +103,10 @@ pub struct SyncView { } // See `SyncView`'s docs for justification. -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] unsafe impl Sync for SyncView {} -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_default", issue = "143894")] const impl Default for SyncView where @@ -120,7 +118,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for SyncView { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { f.debug_struct("SyncView").finish_non_exhaustive() @@ -129,8 +127,8 @@ impl fmt::Debug for SyncView { impl SyncView { /// Wrap a value in an `SyncView` - #[unstable(feature = "exclusive_wrapper", issue = "98407")] - #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] + #[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn new(t: T) -> Self { @@ -138,8 +136,9 @@ impl SyncView { } /// Unwrap the value contained in the `SyncView` - #[unstable(feature = "exclusive_wrapper", issue = "98407")] - #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] + #[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] #[must_use] #[inline] pub const fn into_inner(self) -> T { @@ -154,8 +153,8 @@ impl SyncView { /// value, which means _unpinned_ `SyncView`s can produce _unpinned_ /// access to the underlying value, but _pinned_ `SyncView`s only /// produce _pinned_ access to the underlying value. - #[unstable(feature = "exclusive_wrapper", issue = "98407")] - #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] + #[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { @@ -167,8 +166,8 @@ impl SyncView { /// Build a _mutable_ reference to an `SyncView` from /// a _mutable_ reference to a `T`. This allows you to skip /// building an `SyncView` with [`SyncView::new`]. - #[unstable(feature = "exclusive_wrapper", issue = "98407")] - #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] + #[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_mut(r: &'_ mut T) -> &'_ mut SyncView { @@ -179,8 +178,8 @@ impl SyncView { /// Build a _pinned mutable_ reference to an `SyncView` from /// a _pinned mutable_ reference to a `T`. This allows you to skip /// building an `SyncView` with [`SyncView::new`]. - #[unstable(feature = "exclusive_wrapper", issue = "98407")] - #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] + #[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut SyncView> { @@ -197,8 +196,8 @@ impl SyncView { /// value, which means _unpinned_ `SyncView`s can produce _unpinned_ /// access to the underlying value, but _pinned_ `SyncView`s only /// produce _pinned_ access to the underlying value. - #[unstable(feature = "exclusive_wrapper", issue = "98407")] - #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] + #[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn as_pin_ref(self: Pin<&Self>) -> Pin<&T> { @@ -208,7 +207,7 @@ impl SyncView { } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] const impl From for SyncView { #[inline] @@ -217,7 +216,7 @@ const impl From for SyncView { } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] const impl FnOnce for SyncView where @@ -231,7 +230,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] const impl FnMut for SyncView where @@ -243,7 +242,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] const impl Fn for SyncView where @@ -255,7 +254,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] impl AsyncFnOnce for SyncView where F: AsyncFnOnce, @@ -270,7 +269,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] impl AsyncFnMut for SyncView where F: AsyncFnMut, @@ -286,7 +285,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] impl AsyncFn for SyncView where F: Sync + AsyncFn, @@ -297,7 +296,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] impl Future for SyncView where T: Future + ?Sized, @@ -324,7 +323,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] const impl AsRef for SyncView where @@ -337,7 +336,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] const impl AsMut for SyncView where @@ -350,7 +349,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_clone", issue = "142757")] const impl Clone for SyncView where @@ -367,10 +366,10 @@ where #[rustc_const_unstable(feature = "const_clone", issue = "142757")] const unsafe impl TrivialClone for SyncView where T: Sync + [const] TrivialClone {} -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] impl Copy for SyncView where T: Sync + Copy {} -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] const impl PartialEq> for SyncView where @@ -383,14 +382,14 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] impl StructuralPartialEq for SyncView where T: Sync + StructuralPartialEq + ?Sized {} -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] const impl Eq for SyncView where T: Sync + [const] Eq + ?Sized {} -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] impl Hash for SyncView where T: Sync + Hash + ?Sized, @@ -401,7 +400,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] const impl PartialOrd> for SyncView where @@ -414,7 +413,7 @@ where } } -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] const impl Ord for SyncView where diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 07645debe82be..e5e443088f36e 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -717,6 +717,11 @@ pub fn temp_dir() -> PathBuf { /// If the executable is renamed while it is running, platforms may return the /// path at the time it was loaded instead of the new path. /// +/// On Linux, if the executable is deleted while it is running, this function +/// may return the path with the string `" (deleted)"` appended. +/// +/// Note that the platform-specific behavior [may change in the future][changes]. +/// /// # Errors /// /// Acquiring the path of the current executable is a platform-specific operation @@ -752,6 +757,8 @@ pub fn temp_dir() -> PathBuf { /// Err(e) => println!("failed to get current exe path: {e}"), /// }; /// ``` +/// +/// [changes]: crate::io#platform-specific-behavior #[stable(feature = "env", since = "1.0.0")] pub fn current_exe() -> io::Result { paths_imp::current_exe() diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index bfb28b62d2089..f716f49ffd60a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -341,7 +341,6 @@ #![feature(error_generic_member_access)] #![feature(error_iter)] #![feature(exact_size_is_empty)] -#![feature(exclusive_wrapper)] #![feature(extend_one)] #![feature(float_gamma)] #![feature(float_minimum_maximum)] diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 9426d9a684ef6..b138c1b946c92 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -179,7 +179,7 @@ #![cfg_attr(rustfmt, rustfmt::skip)] // These come from `core` & `alloc` and only in one flavor: no poisoning. -#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[stable(feature = "exclusive_wrapper", since = "CURRENT_RUSTC_VERSION")] pub use core::sync::SyncView; #[stable(feature = "rust1", since = "1.0.0")] pub use core::sync::atomic; diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs index 4dad81685a94e..209a8790def08 100644 --- a/library/std/src/sys/thread_local/native/mod.rs +++ b/library/std/src/sys/thread_local/native/mod.rs @@ -81,8 +81,12 @@ pub macro thread_local_inner { // used to generate the `LocalKey` value for `thread_local!` (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{ + // We intentionally have an argument-position `'static` lifetime so that elided lifetimes in `$t` + // become `'static` like they do for `const`s and `static`s, including in the other two + // `thread_local!` implementations. + #[allow(mismatched_lifetime_syntaxes)] #[inline] - fn __rust_std_internal_init_fn() -> $t { + fn __rust_std_internal_init_fn(_lifetime_elision: $crate::marker::PhantomData<&'static ()>) -> $t { $init } @@ -94,7 +98,7 @@ pub macro thread_local_inner { $(#[$align_attr])* static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::LazyStorage<$t, ()> = $crate::thread::local_impl::LazyStorage::new(); - __RUST_STD_INTERNAL_VAL.get_or_init(__rust_std_internal_init, __rust_std_internal_init_fn) + __RUST_STD_INTERNAL_VAL.get_or_init(__rust_std_internal_init, || __rust_std_internal_init_fn($crate::marker::PhantomData)) } } else { |__rust_std_internal_init| { @@ -102,7 +106,7 @@ pub macro thread_local_inner { $(#[$align_attr])* static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::LazyStorage<$t, !> = $crate::thread::local_impl::LazyStorage::new(); - __RUST_STD_INTERNAL_VAL.get_or_init(__rust_std_internal_init, __rust_std_internal_init_fn) + __RUST_STD_INTERNAL_VAL.get_or_init(__rust_std_internal_init, || __rust_std_internal_init_fn($crate::marker::PhantomData)) } } }) diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs index 9f4e7710dffb7..a3d50d05eeec8 100644 --- a/library/std/src/sys/thread_local/no_threads.rs +++ b/library/std/src/sys/thread_local/no_threads.rs @@ -31,14 +31,18 @@ pub macro thread_local_inner { // used to generate the `LocalKey` value for `thread_local!` (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{ + // We intentionally have an argument-position `'static` lifetime so that elided lifetimes in `$t` + // become `'static` like they do for `const`s and `static`s, including in the other two + // `thread_local!` implementations. + #[allow(mismatched_lifetime_syntaxes)] #[inline] - fn __rust_std_internal_init_fn() -> $t { $init } + fn __rust_std_internal_init_fn(_lifetime_elision: $crate::marker::PhantomData<&'static ()>) -> $t { $init } unsafe { $crate::thread::LocalKey::new(|__rust_std_internal_init| { $(#[$align_attr])* static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new(); - __RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, __rust_std_internal_init_fn) + __RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, || __rust_std_internal_init_fn($crate::marker::PhantomData)) }) } }}, diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index 428339a16f4ea..8588fc994350b 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -20,8 +20,12 @@ pub macro thread_local_inner { // used to generate the `LocalKey` value for `thread_local!`. (@key $t:ty, $($(#[$($align_attr:tt)*])+)?, $init:expr) => {{ + // We intentionally have an argument-position `'static` lifetime so that elided lifetimes in `$t` + // become `'static` like they do for `const`s and `static`s, including in the other two + // `thread_local!` implementations. + #[allow(mismatched_lifetime_syntaxes)] #[inline] - fn __rust_std_internal_init_fn() -> $t { $init } + fn __rust_std_internal_init_fn(_lifetime_elision: $crate::marker::PhantomData<&'static ()>) -> $t { $init } // NOTE: this cannot import `LocalKey` or `Storage` with a `use` because that can shadow // user provided type or type alias with a matching name. Please update the shadowing test @@ -43,7 +47,7 @@ pub macro thread_local_inner { final_align }> = $crate::thread::local_impl::Storage::new(); - __RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, __rust_std_internal_init_fn) + __RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, || __rust_std_internal_init_fn($crate::marker::PhantomData)) }) } }}, diff --git a/library/std/tests/sync_view.rs b/library/std/tests/sync_view.rs new file mode 100644 index 0000000000000..1a21130f73fa2 --- /dev/null +++ b/library/std/tests/sync_view.rs @@ -0,0 +1,93 @@ +use core::sync::SyncView; +use std::cell::Cell; +use std::future::Future; +use std::marker::PhantomPinned; +use std::pin::{Pin, pin}; +use std::task::{Context, Poll, Waker}; + +const EMPTY: Vec = SyncView::new(Vec::new()).into_inner(); +const PROJECTED: u32 = { + let mut value = 41; + let view = SyncView::from_mut(&mut value); + *Pin::into_inner(Pin::new(view).as_pin_mut()) += 1; + let view = SyncView::from_pin_mut(Pin::new(&mut value)).get_mut(); + *Pin::new(&*view).as_pin_ref().get_ref() +}; + +fn require_sync(_: &T) {} + +fn call_mut(mut f: impl FnMut() -> u32) -> u32 { + f() +} + +fn call_shared(f: &impl Fn() -> u32) -> u32 { + f() +} + +fn complete(future: impl Future) -> u32 { + let mut context = Context::from_waker(Waker::noop()); + match pin!(future).poll(&mut context) { + Poll::Ready(value) => value, + Poll::Pending => panic!("expected an immediately ready future"), + } +} + +async fn call_async_once(f: impl AsyncFnOnce() -> u32) -> u32 { + f().await +} + +struct Pinned { + value: Cell, + _pin: PhantomPinned, +} + +#[test] +fn sync_view_const() { + assert!(EMPTY.is_empty()); + assert_eq!(PROJECTED, 42); +} + +#[test] +fn sync_view_access() { + let mut value = std::sync::SyncView::new(Cell::new(1)); + require_sync(&value); + value.as_mut().set(2); + assert_eq!(value.into_inner().get(), 2); + + let mut values = [1, 2]; + let view = SyncView::from_mut(&mut values[..]); + view.as_mut()[0] = 3; + assert_eq!(view.as_ref(), &[3, 2]); +} + +#[test] +fn sync_view_pinned_projection() { + let mut pinned = pin!(Pinned { value: Cell::new(4), _pin: PhantomPinned }); + let address = std::ptr::from_ref(pinned.as_ref().get_ref()); + let view = SyncView::from_pin_mut(pinned.as_mut()); + require_sync(view.as_ref().get_ref()); + let inner = view.as_pin_mut(); + assert_eq!(std::ptr::from_ref(inner.as_ref().get_ref()), address); + inner.value.set(5); + assert_eq!(pinned.value.get(), 5); +} + +#[test] +fn sync_view_forwarding() { + let counter = Cell::new(0); + let increment = SyncView::new(|| { + counter.set(counter.get() + 1); + counter.get() + }); + require_sync(&increment); + assert_eq!(call_mut(increment), 1); + assert_eq!(call_shared(&SyncView::new(|| 7)), 7); + + let future = SyncView::new(async { + std::future::ready(()).await; + counter.get() + }); + require_sync(&future); + assert_eq!(complete(future), 1); + assert_eq!(complete(call_async_once(SyncView::new(async || counter.get()))), 1); +} diff --git a/tests/ui/explicit-tail-calls/callee_is_weird.rs b/tests/ui/explicit-tail-calls/callee_is_weird.rs index 9e2b1fb8d4b55..5b08808a9ca71 100644 --- a/tests/ui/explicit-tail-calls/callee_is_weird.rs +++ b/tests/ui/explicit-tail-calls/callee_is_weird.rs @@ -1,4 +1,4 @@ -#![feature(explicit_tail_calls, exclusive_wrapper, fn_traits, unboxed_closures)] +#![feature(explicit_tail_calls, fn_traits, unboxed_closures)] #![expect(incomplete_features)] fn f() {} diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs deleted file mode 100644 index 93416a9bc2ac7..0000000000000 --- a/tests/ui/suggestions/missing-lifetime-specifier.rs +++ /dev/null @@ -1,54 +0,0 @@ -// The specific errors produced depend the thread-local implementation. -// Run only on platforms with "fast" TLS. -//@ ignore-wasm globals are used instead of thread locals -//@ ignore-emscripten globals are used instead of thread locals -//@ ignore-android does not use #[thread_local] -//@ ignore-nto does not use #[thread_local] -//@ ignore-qnx does not use #[thread_local] -// Different number of duplicated diagnostics on different targets -//@ compile-flags: -Zdeduplicate-diagnostics=yes - -use std::cell::RefCell; -use std::collections::HashMap; - -pub union Foo<'t, 'k> { - i: &'t i64, - f: &'k f64, -} -trait Bar<'t, 'k> {} - -pub union Qux<'t, 'k, I> { - i: &'t I, - f: &'k I, -} -trait Tar<'t, 'k, I> {} - -thread_local! { - static a: RefCell>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers -} -thread_local! { - static b: RefCell>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers -} -thread_local! { - static c: RefCell>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers -} -thread_local! { - static d: RefCell>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers -} - -thread_local! { - static e: RefCell>>>> = RefCell::new(HashMap::new()); - //~^ ERROR union takes 2 lifetime arguments but 1 lifetime argument -} -thread_local! { - static f: RefCell>>>> = - RefCell::new(HashMap::new()); - //~^^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR missing lifetime specifier -} - -fn main() {} diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr deleted file mode 100644 index 4c50f2a43e270..0000000000000 --- a/tests/ui/suggestions/missing-lifetime-specifier.stderr +++ /dev/null @@ -1,109 +0,0 @@ -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:27:44 - | -LL | static a: RefCell>>> = RefCell::new(HashMap::new()); - | ^^^ expected 2 lifetime parameters - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values - | -LL | static a: RefCell>>>> = RefCell::new(HashMap::new()); - | ++++++++++++++++++ - -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:31:44 - | -LL | static b: RefCell>>> = RefCell::new(HashMap::new()); - | ^ ^^^ expected 2 lifetime parameters - | | - | expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` - | -LL | static b: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++ ++++++++++++++++++ - -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:35:47 - | -LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ expected 2 lifetime parameters - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values - | -LL | static c: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++++++++++ - -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:39:44 - | -LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | ^ ^ expected 2 lifetime parameters - | | - | expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` - | -LL | static d: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++ +++++++++++++++++ - -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:48:44 - | -LL | static f: RefCell>>>> = - | ^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` - | -LL | static f: RefCell>>>> = - | +++++++ -help: instead, you are more likely to want to return an owned value - | -LL - static f: RefCell>>>> = -LL + static f: RefCell>>>> = - | - -error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:44:44 - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:20:11 - | -LL | pub union Qux<'t, 'k, I> { - | ^^^ -- -- -help: add missing lifetime argument - | -LL | static e: RefCell>>>> = RefCell::new(HashMap::new()); - | +++++++++ - -error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:48:49 - | -LL | static f: RefCell>>>> = - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments - | -note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:24:7 - | -LL | trait Tar<'t, 'k, I> {} - | ^^^ -- -- -help: add missing lifetime argument - | -LL | static f: RefCell>>>> = - | +++++++++ - -error: aborting due to 7 previous errors - -Some errors have detailed explanations: E0106, E0107. -For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/thread-local/lifetime-elision.rs b/tests/ui/thread-local/lifetime-elision.rs new file mode 100644 index 0000000000000..3b960d18764cb --- /dev/null +++ b/tests/ui/thread-local/lifetime-elision.rs @@ -0,0 +1,14 @@ +// Test that `thread_local!` defaults elided lifetimes in the type to `'static`. +// Regression test for 159358. +// Ideally this should be tested at least one target using each `thread_local!` +// implementation (no-threads, native, os), but currently there are no Tier 1 `no-threads` +// targets. `x86_64-unknown-linux-gnu` is a `native` target and `x86_64-pc-windows-gnu` +// is a `os` target, so those are covered (as of 2026-07-21). +//@ check-pass + +// Const initializer +std::thread_local!(static A: &str = const { "" }); +// Non-const initializer +std::thread_local!(static B: &str = ""); + +fn main() {}