diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index fc122db8ac1b1..8b7fd59cd874a 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -26,6 +26,11 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + ( + sym::target_has_atomic_equal_alignment, + sym::cfg_target_has_atomic, + cfg_fn!(cfg_target_has_atomic), + ), (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), ]; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8d004675d7f4d..ab96b0333f43f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,6 +12,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::impl_stable_hash_via_hash; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_target::abi::{Align, TargetDataLayout}; use rustc_target::spec::{Target, TargetTriple}; use crate::parse::CrateConfig; @@ -748,6 +749,9 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { let min_atomic_width = sess.target.target.min_atomic_width(); let max_atomic_width = sess.target.target.max_atomic_width(); let atomic_cas = sess.target.target.options.atomic_cas; + let layout = TargetDataLayout::parse(&sess.target.target).unwrap_or_else(|err| { + sess.fatal(&err); + }); let mut ret = FxHashSet::default(); ret.reserve(6); // the minimum number of insertions @@ -769,18 +773,27 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { if sess.target.target.options.has_elf_tls { ret.insert((sym::target_thread_local, None)); } - for &i in &[8, 16, 32, 64, 128] { + for &(i, align) in &[ + (8, layout.i8_align.abi), + (16, layout.i16_align.abi), + (32, layout.i32_align.abi), + (64, layout.i64_align.abi), + (128, layout.i128_align.abi), + ] { if i >= min_atomic_width && i <= max_atomic_width { - let mut insert_atomic = |s| { + let mut insert_atomic = |s, align: Align| { ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s)))); if atomic_cas { ret.insert((sym::target_has_atomic, Some(Symbol::intern(s)))); } + if align.bits() == i { + ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s)))); + } }; let s = i.to_string(); - insert_atomic(&s); + insert_atomic(&s, align); if &s == wordsz { - insert_atomic("ptr"); + insert_atomic("ptr", layout.pointer_align.abi); } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6085eedf23694..60688d26d4ce0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1071,6 +1071,7 @@ symbols! { target_feature, target_feature_11, target_has_atomic, + target_has_atomic_equal_alignment, target_has_atomic_load_store, target_os, target_pointer_width, diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 7eec2c487fef4..5c9cfe27101f0 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -327,6 +327,28 @@ impl AtomicBool { unsafe { &mut *(self.v.get() as *mut bool) } } + /// Get atomic access to a `&mut bool`. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let mut some_bool = true; + /// let a = AtomicBool::from_mut(&mut some_bool); + /// a.store(false, Ordering::Relaxed); + /// assert_eq!(some_bool, false); + /// ``` + #[inline] + #[cfg(target_has_atomic_equal_alignment = "8")] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut bool) -> &Self { + // SAFETY: the mutable reference guarantees unique ownership, and + // alignment of both `bool` and `Self` is 1. + unsafe { &*(v as *mut bool as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -819,6 +841,32 @@ impl<T> AtomicPtr<T> { self.p.get_mut() } + /// Get atomic access to a pointer. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let mut some_ptr = &mut 123 as *mut i32; + /// let a = AtomicPtr::from_mut(&mut some_ptr); + /// a.store(&mut 456, Ordering::Relaxed); + /// assert_eq!(unsafe { *some_ptr }, 456); + /// ``` + #[inline] + #[cfg(target_has_atomic_equal_alignment = "ptr")] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut *mut T) -> &Self { + use crate::mem::align_of; + let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `*mut T` and `Self` is the same on all platforms + // supported by rust, as verified above. + unsafe { &*(v as *mut *mut T as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -1113,6 +1161,7 @@ macro_rules! if_not_8_bit { #[cfg(target_has_atomic_load_store = "8")] macro_rules! atomic_int { ($cfg_cas:meta, + $cfg_align:meta, $stable:meta, $stable_cxchg:meta, $stable_debug:meta, @@ -1231,6 +1280,45 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5); } } + doc_comment! { + concat!("Get atomic access to a `&mut ", stringify!($int_type), "`. + +", +if_not_8_bit! { + $int_type, + concat!( + "**Note:** This function is only available on targets where `", + stringify!($int_type), "` has an alignment of ", $align, " bytes." + ) +}, +" + +# Examples + +``` +#![feature(atomic_from_mut)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let mut some_int = 123; +let a = ", stringify!($atomic_type), "::from_mut(&mut some_int); +a.store(100, Ordering::Relaxed); +assert_eq!(some_int, 100); +``` + "), + #[inline] + #[$cfg_align] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut $int_type) -> &Self { + use crate::mem::align_of; + let [] = [(); align_of::<Self>() - align_of::<$int_type>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `$int_type` and `Self` is the + // same, as promised by $cfg_align and verified above. + unsafe { &*(v as *mut $int_type as *mut Self) } + } + } + doc_comment! { concat!("Consumes the atomic and returns the contained value. @@ -1873,6 +1961,7 @@ let mut atomic = ", stringify!($atomic_type), "::new(1); #[cfg(target_has_atomic_load_store = "8")] atomic_int! { cfg(target_has_atomic = "8"), + cfg(target_has_atomic_equal_alignment = "8"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -1891,6 +1980,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "8")] atomic_int! { cfg(target_has_atomic = "8"), + cfg(target_has_atomic_equal_alignment = "8"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -1909,6 +1999,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "16")] atomic_int! { cfg(target_has_atomic = "16"), + cfg(target_has_atomic_equal_alignment = "16"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -1927,6 +2018,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "16")] atomic_int! { cfg(target_has_atomic = "16"), + cfg(target_has_atomic_equal_alignment = "16"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -1945,6 +2037,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "32")] atomic_int! { cfg(target_has_atomic = "32"), + cfg(target_has_atomic_equal_alignment = "32"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -1963,6 +2056,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "32")] atomic_int! { cfg(target_has_atomic = "32"), + cfg(target_has_atomic_equal_alignment = "32"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -1981,6 +2075,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "64")] atomic_int! { cfg(target_has_atomic = "64"), + cfg(target_has_atomic_equal_alignment = "64"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -1999,6 +2094,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "64")] atomic_int! { cfg(target_has_atomic = "64"), + cfg(target_has_atomic_equal_alignment = "64"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2017,6 +2113,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "128")] atomic_int! { cfg(target_has_atomic = "128"), + cfg(target_has_atomic_equal_alignment = "128"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), @@ -2035,6 +2132,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "128")] atomic_int! { cfg(target_has_atomic = "128"), + cfg(target_has_atomic_equal_alignment = "128"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), @@ -2074,6 +2172,7 @@ macro_rules! ptr_width { #[cfg(target_has_atomic_load_store = "ptr")] atomic_int! { cfg(target_has_atomic = "ptr"), + cfg(target_has_atomic_equal_alignment = "ptr"), stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), @@ -2092,6 +2191,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "ptr")] atomic_int! { cfg(target_has_atomic = "ptr"), + cfg(target_has_atomic_equal_alignment = "ptr"), stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), diff --git a/src/test/ui/atomic-from-mut-not-available.rs b/src/test/ui/atomic-from-mut-not-available.rs new file mode 100644 index 0000000000000..bf94616007570 --- /dev/null +++ b/src/test/ui/atomic-from-mut-not-available.rs @@ -0,0 +1,7 @@ +// only-x86 +// only-linux + +fn main() { + core::sync::atomic::AtomicU64::from_mut(&mut 0u64); + //~^ ERROR: no function or associated item named `from_mut` found for struct `AtomicU64` +} diff --git a/src/test/ui/atomic-from-mut-not-available.stderr b/src/test/ui/atomic-from-mut-not-available.stderr new file mode 100644 index 0000000000000..d1ebca8a29e93 --- /dev/null +++ b/src/test/ui/atomic-from-mut-not-available.stderr @@ -0,0 +1,9 @@ +error[E0599]: no function or associated item named `from_mut` found for struct `AtomicU64` in the current scope + --> $DIR/atomic-from-mut-not-available.rs:5:36 + | +LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64); + | ^^^^^^^^ function or associated item not found in `AtomicU64` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs index 506b21dc7d544..049fdd84d8c22 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs @@ -87,6 +87,30 @@ fn main() { //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "ptr"); //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "8"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "16"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "32"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "64"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "128"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "ptr"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "8"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "16"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "32"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "64"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "128"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "ptr"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change } #[macro_export] diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr index 6132c53087879..16e1dc6440084 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr @@ -160,6 +160,114 @@ LL | cfg!(target_has_atomic = "ptr"); = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable -error: aborting due to 18 previous errors +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:90:10 + | +LL | cfg!(target_has_atomic_load_store = "8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:92:10 + | +LL | cfg!(target_has_atomic_load_store = "16"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:94:10 + | +LL | cfg!(target_has_atomic_load_store = "32"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:96:10 + | +LL | cfg!(target_has_atomic_load_store = "64"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:98:10 + | +LL | cfg!(target_has_atomic_load_store = "128"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:100:10 + | +LL | cfg!(target_has_atomic_load_store = "ptr"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:102:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:104:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "16"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:106:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "32"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:108:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "64"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:110:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "128"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:112:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "ptr"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error: aborting due to 30 previous errors For more information about this error, try `rustc --explain E0658`.