1
Fork 0

Rollup merge of #54280 - japaric:no-cas-for-thumbv6, r=alexcrichton

remove (more) CAS API from Atomic* types where not natively supported

closes #54276

In PR #51953 I made the Atomic* types available on targets like thumbv6m and
msp430 with the intention of *only* exposing the load and store API on those
types -- the rest of the API doesn't work on those targets because the are no
native instructions to implement CAS loops.

Unfortunately, it seems I didn't properly cfg away all the CAS API on those
targets, as evidenced in #54276. This PR amends the issue by removing the rest
of the CAS API.

This is technically a breaking change because *libraries* that were using this
API and were being compiled for e.g. thumbv6m-none-eabi will stop compiling.
However, using those libraries (before this change) in programs (binaries) would
lead to linking errors when compiled for e.g. thumbv6m so this change
effectively shifts a linker error in binaries to a compiler error in libraries.

On a side note: extending the Atomic API is a bit error prone because of these
non-cas targets. Unless the author of the change is aware of these targets and
properly uses `#[cfg(atomic = "cas")]` they could end up exposing new CAS API on
these targets. I can't think of a test to check that an API is not present on
some target, but we could extend the `tidy` tool to check that *all* newly added
atomic API has the `#[cfg(atomic = "cas")]` attribute unless it's whitelisted in
`tidy` then the author of the change would have to verify if the API can be used
on non-cas targets.

In any case, I'd like to plug this hole ASAP. We can revisit testing in a
follow-up issue / PR.

r? @alexcrichton
cc @mvirkkunen
This commit is contained in:
Pietro Albini 2018-09-22 09:56:28 +02:00 committed by GitHub
commit e3cc48a4ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -558,6 +558,7 @@ impl AtomicBool {
/// ```
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[cfg(target_has_atomic = "cas")]
pub fn compare_exchange_weak(&self,
current: bool,
new: bool,
@ -1041,6 +1042,7 @@ impl<T> AtomicPtr<T> {
/// ```
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[cfg(target_has_atomic = "cas")]
pub fn compare_exchange_weak(&self,
current: *mut T,
new: *mut T,
@ -1434,6 +1436,7 @@ loop {
```"),
#[inline]
#[$stable_cxchg]
#[cfg(target_has_atomic = "cas")]
pub fn compare_exchange_weak(&self,
current: $int_type,
new: $int_type,
@ -1471,6 +1474,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 10);
```"),
#[inline]
#[$stable]
#[cfg(target_has_atomic = "cas")]
pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { atomic_add(self.v.get(), val, order) }
}
@ -1502,6 +1506,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 10);
```"),
#[inline]
#[$stable]
#[cfg(target_has_atomic = "cas")]
pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { atomic_sub(self.v.get(), val, order) }
}
@ -1536,6 +1541,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
```"),
#[inline]
#[$stable]
#[cfg(target_has_atomic = "cas")]
pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { atomic_and(self.v.get(), val, order) }
}
@ -1571,6 +1577,7 @@ assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31));
```"),
#[inline]
#[$stable_nand]
#[cfg(target_has_atomic = "cas")]
pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { atomic_nand(self.v.get(), val, order) }
}
@ -1605,6 +1612,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
```"),
#[inline]
#[$stable]
#[cfg(target_has_atomic = "cas")]
pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { atomic_or(self.v.get(), val, order) }
}
@ -1639,6 +1647,7 @@ assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
```"),
#[inline]
#[$stable]
#[cfg(target_has_atomic = "cas")]
pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { atomic_xor(self.v.get(), val, order) }
}
@ -1688,6 +1697,7 @@ assert_eq!(x.load(Ordering::SeqCst), 9);
#[unstable(feature = "no_more_cas",
reason = "no more CAS loops in user code",
issue = "48655")]
#[cfg(target_has_atomic = "cas")]
pub fn fetch_update<F>(&self,
mut f: F,
fetch_order: Ordering,
@ -1748,6 +1758,7 @@ assert!(max_foo == 42);
#[unstable(feature = "atomic_min_max",
reason = "easier and faster min/max than writing manual CAS loop",
issue = "48655")]
#[cfg(target_has_atomic = "cas")]
pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { $max_fn(self.v.get(), val, order) }
}
@ -1799,6 +1810,7 @@ assert_eq!(min_foo, 12);
#[unstable(feature = "atomic_min_max",
reason = "easier and faster min/max than writing manual CAS loop",
issue = "48655")]
#[cfg(target_has_atomic = "cas")]
pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { $min_fn(self.v.get(), val, order) }
}
@ -1987,6 +1999,7 @@ unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
/// Returns the previous value (like __sync_fetch_and_add).
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_xadd_acq(dst, val),
@ -1999,6 +2012,7 @@ unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
/// Returns the previous value (like __sync_fetch_and_sub).
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_xsub_acq(dst, val),
@ -2035,6 +2049,7 @@ unsafe fn atomic_compare_exchange<T>(dst: *mut T,
}
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T,
old: T,
new: T,
@ -2059,6 +2074,7 @@ unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T,
}
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_and<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_and_acq(dst, val),
@ -2070,6 +2086,7 @@ unsafe fn atomic_and<T>(dst: *mut T, val: T, order: Ordering) -> T {
}
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_nand<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_nand_acq(dst, val),
@ -2081,6 +2098,7 @@ unsafe fn atomic_nand<T>(dst: *mut T, val: T, order: Ordering) -> T {
}
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_or<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_or_acq(dst, val),
@ -2092,6 +2110,7 @@ unsafe fn atomic_or<T>(dst: *mut T, val: T, order: Ordering) -> T {
}
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_xor_acq(dst, val),
@ -2104,6 +2123,7 @@ unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
/// returns the max value (signed comparison)
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_max<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_max_acq(dst, val),
@ -2116,6 +2136,7 @@ unsafe fn atomic_max<T>(dst: *mut T, val: T, order: Ordering) -> T {
/// returns the min value (signed comparison)
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_min<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_min_acq(dst, val),
@ -2128,6 +2149,7 @@ unsafe fn atomic_min<T>(dst: *mut T, val: T, order: Ordering) -> T {
/// returns the max value (signed comparison)
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_umax<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_umax_acq(dst, val),
@ -2140,6 +2162,7 @@ unsafe fn atomic_umax<T>(dst: *mut T, val: T, order: Ordering) -> T {
/// returns the min value (signed comparison)
#[inline]
#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_umin<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_umin_acq(dst, val),