about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-05-09 08:48:58 -0700
committerbors <bors@rust-lang.org>2016-05-09 08:48:58 -0700
commitaf0a433865321ee9fc5287eef63227baf4cba109 (patch)
tree9bbb98039cceade0bed4ae51f46cefa0b603abc6
parent0cc90978e87c6681de18c265aaa1a324c064fc3d (diff)
parent03dd9b87cb00a3f11231c2c96f41c4c1ce6abe48 (diff)
downloadrust-af0a433865321ee9fc5287eef63227baf4cba109.tar.gz
rust-af0a433865321ee9fc5287eef63227baf4cba109.zip
Auto merge of #33048 - Amanieu:integer_atomics, r=alexcrichton
Add integer atomic types

Tracking issue: #32976
RFC: rust-lang/rfcs#1543

The changes to AtomicBool in the RFC are not included, they are in a separate PR (#32365).
-rw-r--r--src/doc/reference.md5
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/sync/atomic.rs1020
-rw-r--r--src/librustc/session/config.rs10
-rw-r--r--src/librustc_back/target/aarch64_apple_ios.rs1
-rw-r--r--src/librustc_back/target/aarch64_linux_android.rs4
-rw-r--r--src/librustc_back/target/aarch64_unknown_linux_gnu.rs3
-rw-r--r--src/librustc_back/target/arm_linux_androideabi.rs1
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabi.rs3
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabihf.rs3
-rw-r--r--src/librustc_back/target/armv7_apple_ios.rs1
-rw-r--r--src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs1
-rw-r--r--src/librustc_back/target/armv7s_apple_ios.rs1
-rw-r--r--src/librustc_back/target/asmjs_unknown_emscripten.rs1
-rw-r--r--src/librustc_back/target/i386_apple_ios.rs7
-rw-r--r--src/librustc_back/target/i686_apple_darwin.rs1
-rw-r--r--src/librustc_back/target/i686_linux_android.rs1
-rw-r--r--src/librustc_back/target/i686_pc_windows_gnu.rs1
-rw-r--r--src/librustc_back/target/i686_pc_windows_msvc.rs1
-rw-r--r--src/librustc_back/target/i686_unknown_dragonfly.rs1
-rw-r--r--src/librustc_back/target/i686_unknown_freebsd.rs1
-rw-r--r--src/librustc_back/target/i686_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/i686_unknown_linux_musl.rs1
-rw-r--r--src/librustc_back/target/le32_unknown_nacl.rs1
-rw-r--r--src/librustc_back/target/mips_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/mips_unknown_linux_musl.rs1
-rw-r--r--src/librustc_back/target/mipsel_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/mipsel_unknown_linux_musl.rs1
-rw-r--r--src/librustc_back/target/mod.rs15
-rw-r--r--src/librustc_back/target/powerpc64_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/powerpc_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/x86_64_apple_darwin.rs1
-rw-r--r--src/librustc_back/target/x86_64_apple_ios.rs7
-rw-r--r--src/librustc_back/target/x86_64_pc_windows_gnu.rs1
-rw-r--r--src/librustc_back/target/x86_64_pc_windows_msvc.rs1
-rw-r--r--src/librustc_back/target/x86_64_rumprun_netbsd.rs1
-rw-r--r--src/librustc_back/target/x86_64_sun_solaris.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_bitrig.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_dragonfly.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_freebsd.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_linux_gnu.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_linux_musl.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_netbsd.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_openbsd.rs1
-rw-r--r--src/libsyntax/feature_gate.rs8
-rw-r--r--src/test/run-make/atomic-lock-free/Makefile30
-rw-r--r--src/test/run-make/atomic-lock-free/atomic_lock_free.rs62
48 files changed, 600 insertions, 612 deletions
diff --git a/src/doc/reference.md b/src/doc/reference.md
index 397abfe563c..ebb111a2e2e 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -2091,6 +2091,8 @@ The following configurations must be defined by the implementation:
 * `target_pointer_width = "..."` - Target pointer width in bits. This is set
   to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for
   64-bit pointers.
+* `target_has_atomic = "..."` - Set of integer sizes on which the target can perform
+  atomic operations. Values are `"8"`, `"16"`, `"32"`, `"64"` and `"ptr"`.
 * `target_vendor = "..."` - Vendor of the target, for example `apple`, `pc`, or
   simply `"unknown"`.
 * `test` - Enabled when compiling the test harness (using the `--test` flag).
@@ -2295,6 +2297,9 @@ The currently implemented features of the reference compiler are:
 * `cfg_target_vendor` - Allows conditional compilation using the `target_vendor`
                         matcher which is subject to change.
 
+* `cfg_target_has_atomic` - Allows conditional compilation using the `target_has_atomic`
+                            matcher which is subject to change.
+
 * `concat_idents` - Allows use of the `concat_idents` macro, which is in many
                     ways insufficient for concatenating identifiers, and may be
                     removed entirely for something more wholesome.
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index fa5e90562d8..873059d3ccc 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -63,6 +63,7 @@
 #![feature(associated_type_defaults)]
 #![feature(concat_idents)]
 #![feature(const_fn)]
+#![feature(cfg_target_has_atomic)]
 #![feature(custom_attribute)]
 #![feature(fundamental)]
 #![feature(inclusive_range_syntax)]
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index e74dc08ea71..cf3e45cf3de 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -83,11 +83,13 @@ use default::Default;
 use fmt;
 
 /// A boolean type which can be safely shared between threads.
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct AtomicBool {
     v: UnsafeCell<usize>,
 }
 
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Default for AtomicBool {
     fn default() -> Self {
@@ -96,49 +98,18 @@ impl Default for AtomicBool {
 }
 
 // Send is implicitly implemented for AtomicBool.
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl Sync for AtomicBool {}
 
-/// A signed integer type which can be safely shared between threads.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct AtomicIsize {
-    v: UnsafeCell<isize>,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Default for AtomicIsize {
-    fn default() -> Self {
-        Self::new(Default::default())
-    }
-}
-
-// Send is implicitly implemented for AtomicIsize.
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl Sync for AtomicIsize {}
-
-/// An unsigned integer type which can be safely shared between threads.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct AtomicUsize {
-    v: UnsafeCell<usize>,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Default for AtomicUsize {
-    fn default() -> Self {
-        Self::new(Default::default())
-    }
-}
-
-// Send is implicitly implemented for AtomicUsize.
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl Sync for AtomicUsize {}
-
 /// A raw pointer type which can be safely shared between threads.
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct AtomicPtr<T> {
     p: UnsafeCell<*mut T>,
 }
 
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Default for AtomicPtr<T> {
     fn default() -> AtomicPtr<T> {
@@ -146,8 +117,10 @@ impl<T> Default for AtomicPtr<T> {
     }
 }
 
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<T> Send for AtomicPtr<T> {}
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<T> Sync for AtomicPtr<T> {}
 
@@ -189,18 +162,15 @@ pub enum Ordering {
 }
 
 /// An `AtomicBool` initialized to `false`.
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false);
-/// An `AtomicIsize` initialized to `0`.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub const ATOMIC_ISIZE_INIT: AtomicIsize = AtomicIsize::new(0);
-/// An `AtomicUsize` initialized to `0`.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub const ATOMIC_USIZE_INIT: AtomicUsize = AtomicUsize::new(0);
 
 // NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 const UINT_TRUE: usize = !0;
 
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 impl AtomicBool {
     /// Creates a new `AtomicBool`.
     ///
@@ -543,557 +513,7 @@ impl AtomicBool {
     }
 }
 
-impl AtomicIsize {
-    /// Creates a new `AtomicIsize`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::AtomicIsize;
-    ///
-    /// let atomic_forty_two  = AtomicIsize::new(42);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub const fn new(v: isize) -> AtomicIsize {
-        AtomicIsize {v: UnsafeCell::new(v)}
-    }
-
-    /// Loads a value from the isize.
-    ///
-    /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `order` is `Release` or `AcqRel`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let some_isize = AtomicIsize::new(5);
-    ///
-    /// assert_eq!(some_isize.load(Ordering::Relaxed), 5);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn load(&self, order: Ordering) -> isize {
-        unsafe { atomic_load(self.v.get(), order) }
-    }
-
-    /// Stores a value into the isize.
-    ///
-    /// `store` takes an `Ordering` argument which describes the memory ordering of this operation.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let some_isize = AtomicIsize::new(5);
-    ///
-    /// some_isize.store(10, Ordering::Relaxed);
-    /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics if `order` is `Acquire` or `AcqRel`.
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn store(&self, val: isize, order: Ordering) {
-        unsafe { atomic_store(self.v.get(), val, order); }
-    }
-
-    /// Stores a value into the isize, returning the old value.
-    ///
-    /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let some_isize = AtomicIsize::new(5);
-    ///
-    /// assert_eq!(some_isize.swap(10, Ordering::Relaxed), 5);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn swap(&self, val: isize, order: Ordering) -> isize {
-        unsafe { atomic_swap(self.v.get(), val, order) }
-    }
-
-    /// Stores a value into the `isize` if the current value is the same as the `current` value.
-    ///
-    /// The return value is always the previous value. If it is equal to `current`, then the value
-    /// was updated.
-    ///
-    /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
-    /// this operation.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let some_isize = AtomicIsize::new(5);
-    ///
-    /// assert_eq!(some_isize.compare_and_swap(5, 10, Ordering::Relaxed), 5);
-    /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
-    ///
-    /// assert_eq!(some_isize.compare_and_swap(6, 12, Ordering::Relaxed), 10);
-    /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn compare_and_swap(&self, current: isize, new: isize, order: Ordering) -> isize {
-        match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
-            Ok(x) => x,
-            Err(x) => x,
-        }
-    }
-
-    /// Stores a value into the `isize` if the current value is the same as the `current` value.
-    ///
-    /// The return value is a result indicating whether the new value was written and containing
-    /// the previous value. On success this value is guaranteed to be equal to `new`.
-    ///
-    /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this
-    /// operation. The first describes the required ordering if the operation succeeds while the
-    /// second describes the required ordering when the operation fails. The failure ordering can't
-    /// be `Release` or `AcqRel` and must be equivalent or weaker than the success ordering.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![feature(extended_compare_and_swap)]
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let some_isize = AtomicIsize::new(5);
-    ///
-    /// assert_eq!(some_isize.compare_exchange(5, 10,
-    ///                                        Ordering::Acquire,
-    ///                                        Ordering::Relaxed),
-    ///            Ok(5));
-    /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
-    ///
-    /// assert_eq!(some_isize.compare_exchange(6, 12,
-    ///                                        Ordering::SeqCst,
-    ///                                        Ordering::Acquire),
-    ///            Err(10));
-    /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
-    /// ```
-    #[inline]
-    #[unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767")]
-    pub fn compare_exchange(&self,
-                            current: isize,
-                            new: isize,
-                            success: Ordering,
-                            failure: Ordering) -> Result<isize, isize> {
-        unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
-    }
-
-    /// Stores a value into the `isize` if the current value is the same as the `current` value.
-    ///
-    /// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the
-    /// comparison succeeds, which can result in more efficient code on some platforms. The
-    /// return value is a result indicating whether the new value was written and containing the
-    /// previous value.
-    ///
-    /// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory
-    /// ordering of this operation. The first describes the required ordering if the operation
-    /// succeeds while the second describes the required ordering when the operation fails. The
-    /// failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker than the
-    /// success ordering.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![feature(extended_compare_and_swap)]
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let val = AtomicIsize::new(4);
-    ///
-    /// let mut old = val.load(Ordering::Relaxed);
-    /// loop {
-    ///     let new = old * 2;
-    ///     match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
-    ///         Ok(_) => break,
-    ///         Err(x) => old = x,
-    ///     }
-    /// }
-    /// ```
-    #[inline]
-    #[unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767")]
-    pub fn compare_exchange_weak(&self,
-                                 current: isize,
-                                 new: isize,
-                                 success: Ordering,
-                                 failure: Ordering) -> Result<isize, isize> {
-        unsafe { atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) }
-    }
-
-    /// Add an isize to the current value, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let foo = AtomicIsize::new(0);
-    /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
-    /// assert_eq!(foo.load(Ordering::SeqCst), 10);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_add(&self, val: isize, order: Ordering) -> isize {
-        unsafe { atomic_add(self.v.get(), val, order) }
-    }
-
-    /// Subtract an isize from the current value, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let foo = AtomicIsize::new(0);
-    /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 0);
-    /// assert_eq!(foo.load(Ordering::SeqCst), -10);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_sub(&self, val: isize, order: Ordering) -> isize {
-        unsafe { atomic_sub(self.v.get(), val, order) }
-    }
-
-    /// Bitwise and with the current isize, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let foo = AtomicIsize::new(0b101101);
-    /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
-    /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_and(&self, val: isize, order: Ordering) -> isize {
-        unsafe { atomic_and(self.v.get(), val, order) }
-    }
-
-    /// Bitwise or with the current isize, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let foo = AtomicIsize::new(0b101101);
-    /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
-    /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_or(&self, val: isize, order: Ordering) -> isize {
-        unsafe { atomic_or(self.v.get(), val, order) }
-    }
-
-    /// Bitwise xor with the current isize, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicIsize, Ordering};
-    ///
-    /// let foo = AtomicIsize::new(0b101101);
-    /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
-    /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_xor(&self, val: isize, order: Ordering) -> isize {
-        unsafe { atomic_xor(self.v.get(), val, order) }
-    }
-}
-
-impl AtomicUsize {
-    /// Creates a new `AtomicUsize`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::AtomicUsize;
-    ///
-    /// let atomic_forty_two = AtomicUsize::new(42);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub const fn new(v: usize) -> AtomicUsize {
-        AtomicUsize { v: UnsafeCell::new(v) }
-    }
-
-    /// Loads a value from the usize.
-    ///
-    /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
-    ///
-    /// # Panics
-    ///
-    /// Panics if `order` is `Release` or `AcqRel`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let some_usize = AtomicUsize::new(5);
-    ///
-    /// assert_eq!(some_usize.load(Ordering::Relaxed), 5);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn load(&self, order: Ordering) -> usize {
-        unsafe { atomic_load(self.v.get(), order) }
-    }
-
-    /// Stores a value into the usize.
-    ///
-    /// `store` takes an `Ordering` argument which describes the memory ordering of this operation.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let some_usize = AtomicUsize::new(5);
-    ///
-    /// some_usize.store(10, Ordering::Relaxed);
-    /// assert_eq!(some_usize.load(Ordering::Relaxed), 10);
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics if `order` is `Acquire` or `AcqRel`.
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn store(&self, val: usize, order: Ordering) {
-        unsafe { atomic_store(self.v.get(), val, order); }
-    }
-
-    /// Stores a value into the usize, returning the old value.
-    ///
-    /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let some_usize = AtomicUsize::new(5);
-    ///
-    /// assert_eq!(some_usize.swap(10, Ordering::Relaxed), 5);
-    /// assert_eq!(some_usize.load(Ordering::Relaxed), 10);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn swap(&self, val: usize, order: Ordering) -> usize {
-        unsafe { atomic_swap(self.v.get(), val, order) }
-    }
-
-    /// Stores a value into the `usize` if the current value is the same as the `current` value.
-    ///
-    /// The return value is always the previous value. If it is equal to `current`, then the value
-    /// was updated.
-    ///
-    /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
-    /// this operation.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let some_usize = AtomicUsize::new(5);
-    ///
-    /// assert_eq!(some_usize.compare_and_swap(5, 10, Ordering::Relaxed), 5);
-    /// assert_eq!(some_usize.load(Ordering::Relaxed), 10);
-    ///
-    /// assert_eq!(some_usize.compare_and_swap(6, 12, Ordering::Relaxed), 10);
-    /// assert_eq!(some_usize.load(Ordering::Relaxed), 10);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn compare_and_swap(&self, current: usize, new: usize, order: Ordering) -> usize {
-        match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
-            Ok(x) => x,
-            Err(x) => x,
-        }
-    }
-
-    /// Stores a value into the `usize` if the current value is the same as the `current` value.
-    ///
-    /// The return value is a result indicating whether the new value was written and containing
-    /// the previous value. On success this value is guaranteed to be equal to `new`.
-    ///
-    /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this
-    /// operation. The first describes the required ordering if the operation succeeds while the
-    /// second describes the required ordering when the operation fails. The failure ordering can't
-    /// be `Release` or `AcqRel` and must be equivalent or weaker than the success ordering.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![feature(extended_compare_and_swap)]
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let some_isize = AtomicUsize::new(5);
-    ///
-    /// assert_eq!(some_isize.compare_exchange(5, 10,
-    ///                                        Ordering::Acquire,
-    ///                                        Ordering::Relaxed),
-    ///            Ok(5));
-    /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
-    ///
-    /// assert_eq!(some_isize.compare_exchange(6, 12,
-    ///                                        Ordering::SeqCst,
-    ///                                        Ordering::Acquire),
-    ///            Err(10));
-    /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
-    /// ```
-    #[inline]
-    #[unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767")]
-    pub fn compare_exchange(&self,
-                            current: usize,
-                            new: usize,
-                            success: Ordering,
-                            failure: Ordering) -> Result<usize, usize> {
-        unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
-    }
-
-    /// Stores a value into the `usize` if the current value is the same as the `current` value.
-    ///
-    /// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the
-    /// comparison succeeds, which can result in more efficient code on some platforms. The
-    /// return value is a result indicating whether the new value was written and containing the
-    /// previous value.
-    ///
-    /// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory
-    /// ordering of this operation. The first describes the required ordering if the operation
-    /// succeeds while the second describes the required ordering when the operation fails. The
-    /// failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker than the
-    /// success ordering.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![feature(extended_compare_and_swap)]
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let val = AtomicUsize::new(4);
-    ///
-    /// let mut old = val.load(Ordering::Relaxed);
-    /// loop {
-    ///     let new = old * 2;
-    ///     match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
-    ///         Ok(_) => break,
-    ///         Err(x) => old = x,
-    ///     }
-    /// }
-    /// ```
-    #[inline]
-    #[unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767")]
-    pub fn compare_exchange_weak(&self,
-                                 current: usize,
-                                 new: usize,
-                                 success: Ordering,
-                                 failure: Ordering) -> Result<usize, usize> {
-        unsafe { atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) }
-    }
-
-    /// Add to the current usize, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let foo = AtomicUsize::new(0);
-    /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
-    /// assert_eq!(foo.load(Ordering::SeqCst), 10);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_add(&self, val: usize, order: Ordering) -> usize {
-        unsafe { atomic_add(self.v.get(), val, order) }
-    }
-
-    /// Subtract from the current usize, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let foo = AtomicUsize::new(10);
-    /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 10);
-    /// assert_eq!(foo.load(Ordering::SeqCst), 0);
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_sub(&self, val: usize, order: Ordering) -> usize {
-        unsafe { atomic_sub(self.v.get(), val, order) }
-    }
-
-    /// Bitwise and with the current usize, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let foo = AtomicUsize::new(0b101101);
-    /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
-    /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_and(&self, val: usize, order: Ordering) -> usize {
-        unsafe { atomic_and(self.v.get(), val, order) }
-    }
-
-    /// Bitwise or with the current usize, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let foo = AtomicUsize::new(0b101101);
-    /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
-    /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_or(&self, val: usize, order: Ordering) -> usize {
-        unsafe { atomic_or(self.v.get(), val, order) }
-    }
-
-    /// Bitwise xor with the current usize, returning the previous value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::sync::atomic::{AtomicUsize, Ordering};
-    ///
-    /// let foo = AtomicUsize::new(0b101101);
-    /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
-    /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn fetch_xor(&self, val: usize, order: Ordering) -> usize {
-        unsafe { atomic_xor(self.v.get(), val, order) }
-    }
-}
-
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 impl<T> AtomicPtr<T> {
     /// Creates a new `AtomicPtr`.
     ///
@@ -1311,6 +731,405 @@ impl<T> AtomicPtr<T> {
     }
 }
 
+macro_rules! atomic_int {
+    ($stable:meta,
+     $stable_cxchg:meta,
+     $stable_debug:meta,
+     $int_type:ident $atomic_type:ident $atomic_init:ident) => {
+        /// An integer type which can be safely shared between threads.
+        #[$stable]
+        pub struct $atomic_type {
+            v: UnsafeCell<$int_type>,
+        }
+
+        /// An atomic integer initialized to `0`.
+        #[$stable]
+        pub const $atomic_init: $atomic_type = $atomic_type::new(0);
+
+        #[$stable]
+        impl Default for $atomic_type {
+            fn default() -> Self {
+                Self::new(Default::default())
+            }
+        }
+
+        #[$stable_debug]
+        impl fmt::Debug for $atomic_type {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                f.debug_tuple(stringify!($atomic_type))
+                 .field(&self.load(Ordering::SeqCst))
+                 .finish()
+            }
+        }
+
+        // Send is implicitly implemented.
+        #[$stable]
+        unsafe impl Sync for $atomic_type {}
+
+        impl $atomic_type {
+            /// Creates a new atomic integer.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::AtomicIsize;
+            ///
+            /// let atomic_forty_two  = AtomicIsize::new(42);
+            /// ```
+            #[inline]
+            #[$stable]
+            pub const fn new(v: $int_type) -> Self {
+                $atomic_type {v: UnsafeCell::new(v)}
+            }
+
+            /// Loads a value from the atomic integer.
+            ///
+            /// `load` takes an `Ordering` argument which describes the memory ordering of this
+            /// operation.
+            ///
+            /// # Panics
+            ///
+            /// Panics if `order` is `Release` or `AcqRel`.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let some_isize = AtomicIsize::new(5);
+            ///
+            /// assert_eq!(some_isize.load(Ordering::Relaxed), 5);
+            /// ```
+            #[inline]
+            #[$stable]
+            pub fn load(&self, order: Ordering) -> $int_type {
+                unsafe { atomic_load(self.v.get(), order) }
+            }
+
+            /// Stores a value into the atomic integer.
+            ///
+            /// `store` takes an `Ordering` argument which describes the memory ordering of this
+            /// operation.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let some_isize = AtomicIsize::new(5);
+            ///
+            /// some_isize.store(10, Ordering::Relaxed);
+            /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
+            /// ```
+            ///
+            /// # Panics
+            ///
+            /// Panics if `order` is `Acquire` or `AcqRel`.
+            #[inline]
+            #[$stable]
+            pub fn store(&self, val: $int_type, order: Ordering) {
+                unsafe { atomic_store(self.v.get(), val, order); }
+            }
+
+            /// Stores a value into the atomic integer, returning the old value.
+            ///
+            /// `swap` takes an `Ordering` argument which describes the memory ordering of this
+            /// operation.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let some_isize = AtomicIsize::new(5);
+            ///
+            /// assert_eq!(some_isize.swap(10, Ordering::Relaxed), 5);
+            /// ```
+            #[inline]
+            #[$stable]
+            pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
+                unsafe { atomic_swap(self.v.get(), val, order) }
+            }
+
+            /// Stores a value into the atomic integer if the current value is the same as the
+            /// `current` value.
+            ///
+            /// The return value is always the previous value. If it is equal to `current`, then the
+            /// value was updated.
+            ///
+            /// `compare_and_swap` also takes an `Ordering` argument which describes the memory
+            /// ordering of this operation.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let some_isize = AtomicIsize::new(5);
+            ///
+            /// assert_eq!(some_isize.compare_and_swap(5, 10, Ordering::Relaxed), 5);
+            /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
+            ///
+            /// assert_eq!(some_isize.compare_and_swap(6, 12, Ordering::Relaxed), 10);
+            /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
+            /// ```
+            #[inline]
+            #[$stable]
+            pub fn compare_and_swap(&self,
+                                    current: $int_type,
+                                    new: $int_type,
+                                    order: Ordering) -> $int_type {
+                match self.compare_exchange(current,
+                                            new,
+                                            order,
+                                            strongest_failure_ordering(order)) {
+                    Ok(x) => x,
+                    Err(x) => x,
+                }
+            }
+
+            /// Stores a value into the atomic integer if the current value is the same as the
+            /// `current` value.
+            ///
+            /// The return value is a result indicating whether the new value was written and
+            /// containing the previous value. On success this value is guaranteed to be equal to
+            /// `new`.
+            ///
+            /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of
+            /// this operation. The first describes the required ordering if the operation succeeds
+            /// while the second describes the required ordering when the operation fails. The
+            /// failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker
+            /// than the success ordering.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// # #![feature(extended_compare_and_swap)]
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let some_isize = AtomicIsize::new(5);
+            ///
+            /// assert_eq!(some_isize.compare_exchange(5, 10,
+            ///                                        Ordering::Acquire,
+            ///                                        Ordering::Relaxed),
+            ///            Ok(5));
+            /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
+            ///
+            /// assert_eq!(some_isize.compare_exchange(6, 12,
+            ///                                        Ordering::SeqCst,
+            ///                                        Ordering::Acquire),
+            ///            Err(10));
+            /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
+            /// ```
+            #[inline]
+            #[$stable_cxchg]
+            pub fn compare_exchange(&self,
+                                    current: $int_type,
+                                    new: $int_type,
+                                    success: Ordering,
+                                    failure: Ordering) -> Result<$int_type, $int_type> {
+                unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
+            }
+
+            /// Stores a value into the atomic integer if the current value is the same as the
+            /// `current` value.
+            ///
+            /// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the
+            /// comparison succeeds, which can result in more efficient code on some platforms. The
+            /// return value is a result indicating whether the new value was written and containing
+            /// the previous value.
+            ///
+            /// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory
+            /// ordering of this operation. The first describes the required ordering if the
+            /// operation succeeds while the second describes the required ordering when the
+            /// operation fails. The failure ordering can't be `Release` or `AcqRel` and must be
+            /// equivalent or weaker than the success ordering.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// # #![feature(extended_compare_and_swap)]
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let val = AtomicIsize::new(4);
+            ///
+            /// let mut old = val.load(Ordering::Relaxed);
+            /// loop {
+            ///     let new = old * 2;
+            ///     match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
+            ///         Ok(_) => break,
+            ///         Err(x) => old = x,
+            ///     }
+            /// }
+            /// ```
+            #[inline]
+            #[$stable_cxchg]
+            pub fn compare_exchange_weak(&self,
+                                         current: $int_type,
+                                         new: $int_type,
+                                         success: Ordering,
+                                         failure: Ordering) -> Result<$int_type, $int_type> {
+                unsafe {
+                    atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
+                }
+            }
+
+            /// Add to the current value, returning the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let foo = AtomicIsize::new(0);
+            /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 10);
+            /// ```
+            #[inline]
+            #[$stable]
+            pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
+                unsafe { atomic_add(self.v.get(), val, order) }
+            }
+
+            /// Subtract from the current value, returning the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let foo = AtomicIsize::new(0);
+            /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 0);
+            /// assert_eq!(foo.load(Ordering::SeqCst), -10);
+            /// ```
+            #[inline]
+            #[$stable]
+            pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
+                unsafe { atomic_sub(self.v.get(), val, order) }
+            }
+
+            /// Bitwise and with the current value, returning the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let foo = AtomicIsize::new(0b101101);
+            /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
+            #[inline]
+            #[$stable]
+            pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
+                unsafe { atomic_and(self.v.get(), val, order) }
+            }
+
+            /// Bitwise or with the current value, returning the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let foo = AtomicIsize::new(0b101101);
+            /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
+            #[inline]
+            #[$stable]
+            pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
+                unsafe { atomic_or(self.v.get(), val, order) }
+            }
+
+            /// Bitwise xor with the current value, returning the previous value.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let foo = AtomicIsize::new(0b101101);
+            /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
+            /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
+            #[inline]
+            #[$stable]
+            pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
+                unsafe { atomic_xor(self.v.get(), val, order) }
+            }
+        }
+    }
+}
+
+#[cfg(target_has_atomic = "8")]
+atomic_int! {
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    i8 AtomicI8 ATOMIC_I8_INIT
+}
+#[cfg(target_has_atomic = "8")]
+atomic_int! {
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    u8 AtomicU8 ATOMIC_U8_INIT
+}
+#[cfg(target_has_atomic = "16")]
+atomic_int! {
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    i16 AtomicI16 ATOMIC_I16_INIT
+}
+#[cfg(target_has_atomic = "16")]
+atomic_int! {
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    u16 AtomicU16 ATOMIC_U16_INIT
+}
+#[cfg(target_has_atomic = "32")]
+atomic_int! {
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    i32 AtomicI32 ATOMIC_I32_INIT
+}
+#[cfg(target_has_atomic = "32")]
+atomic_int! {
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    u32 AtomicU32 ATOMIC_U32_INIT
+}
+#[cfg(target_has_atomic = "64")]
+atomic_int! {
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    i64 AtomicI64 ATOMIC_I64_INIT
+}
+#[cfg(target_has_atomic = "64")]
+atomic_int! {
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
+    u64 AtomicU64 ATOMIC_U64_INIT
+}
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
+atomic_int!{
+    stable(feature = "rust1", since = "1.0.0"),
+    unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767"),
+    stable(feature = "atomic_debug", since = "1.3.0"),
+    isize AtomicIsize ATOMIC_ISIZE_INIT
+}
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
+atomic_int!{
+    stable(feature = "rust1", since = "1.0.0"),
+    unstable(feature = "extended_compare_and_swap", reason = "recently added", issue = "31767"),
+    stable(feature = "atomic_debug", since = "1.3.0"),
+    usize AtomicUsize ATOMIC_USIZE_INIT
+}
+
 #[inline]
 fn strongest_failure_ordering(order: Ordering) -> Ordering {
     match order {
@@ -1514,19 +1333,16 @@ pub fn fence(order: Ordering) {
     }
 }
 
-macro_rules! impl_Debug {
-    ($($t:ident)*) => ($(
-        #[stable(feature = "atomic_debug", since = "1.3.0")]
-        impl fmt::Debug for $t {
-            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-                f.debug_tuple(stringify!($t)).field(&self.load(Ordering::SeqCst)).finish()
-            }
-        }
-    )*);
-}
 
-impl_Debug!{ AtomicUsize AtomicIsize AtomicBool }
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
+#[stable(feature = "atomic_debug", since = "1.3.0")]
+impl fmt::Debug for AtomicBool {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_tuple("AtomicBool").field(&self.load(Ordering::SeqCst)).finish()
+    }
+}
 
+#[cfg(any(stage0, target_has_atomic = "ptr"))]
 #[stable(feature = "atomic_debug", since = "1.3.0")]
 impl<T> fmt::Debug for AtomicPtr<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 1a2c1b9a095..82237e0abb7 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -695,6 +695,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
     let os = &sess.target.target.target_os;
     let env = &sess.target.target.target_env;
     let vendor = &sess.target.target.target_vendor;
+    let max_atomic_width = sess.target.target.options.max_atomic_width;
 
     let fam = if let Some(ref fam) = sess.target.target.options.target_family {
         intern(fam)
@@ -721,6 +722,15 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
     if sess.target.target.options.has_elf_tls {
         ret.push(attr::mk_word_item(InternedString::new("target_thread_local")));
     }
+    for &i in &[8, 16, 32, 64, 128] {
+        if i <= max_atomic_width {
+            let s = i.to_string();
+            ret.push(mk(InternedString::new("target_has_atomic"), intern(&s)));
+            if &s == wordsz {
+                ret.push(mk(InternedString::new("target_has_atomic"), intern("ptr")));
+            }
+        }
+    }
     if sess.opts.debug_assertions {
         ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
     }
diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs
index 2f0a043f9a7..481338d1cee 100644
--- a/src/librustc_back/target/aarch64_apple_ios.rs
+++ b/src/librustc_back/target/aarch64_apple_ios.rs
@@ -24,6 +24,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             features: "+neon,+fp-armv8,+cyclone".to_string(),
             eliminate_frame_pointer: false,
+            max_atomic_width: 128,
             .. opts(Arch::Arm64)
         },
     }
diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs
index c4212e70212..ed171822464 100644
--- a/src/librustc_back/target/aarch64_linux_android.rs
+++ b/src/librustc_back/target/aarch64_linux_android.rs
@@ -11,6 +11,8 @@
 use target::Target;
 
 pub fn target() -> Target {
+    let mut base = super::android_base::opts();
+    base.max_atomic_width = 128;
     Target {
         llvm_target: "aarch64-linux-android".to_string(),
         target_endian: "little".to_string(),
@@ -20,6 +22,6 @@ pub fn target() -> Target {
         target_os: "android".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
-        options: super::android_base::opts(),
+        options: base,
     }
 }
diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
index 3bf4e92fb6a..aec1bae60c8 100644
--- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
@@ -11,7 +11,8 @@
 use target::Target;
 
 pub fn target() -> Target {
-    let base = super::linux_base::opts();
+    let mut base = super::linux_base::opts();
+    base.max_atomic_width = 128;
     Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs
index 5be78595138..ab662a97dc2 100644
--- a/src/librustc_back/target/arm_linux_androideabi.rs
+++ b/src/librustc_back/target/arm_linux_androideabi.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.features = "+v7,+vfp3,+d16".to_string();
+    base.max_atomic_width = 64;
 
     Target {
         llvm_target: "arm-linux-androideabi".to_string(),
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
index 29ab7120389..60c4a7c3c90 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
@@ -11,7 +11,8 @@
 use target::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::linux_base::opts();
+    let mut base = super::linux_base::opts();
+    base.max_atomic_width = 64;
     Target {
         llvm_target: "arm-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
index 8ca7c23eb55..72128e30641 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
@@ -11,7 +11,8 @@
 use target::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::linux_base::opts();
+    let mut base = super::linux_base::opts();
+    base.max_atomic_width = 64;
     Target {
         llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs
index d131f8b2ef0..a2486a1330a 100644
--- a/src/librustc_back/target/armv7_apple_ios.rs
+++ b/src/librustc_back/target/armv7_apple_ios.rs
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         target_vendor: "apple".to_string(),
         options: TargetOptions {
             features: "+v7,+vfp3,+neon".to_string(),
+            max_atomic_width: 64,
             .. opts(Arch::Armv7)
         }
     }
diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
index 549da058d51..7bcca3a3934 100644
--- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
+++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
@@ -25,6 +25,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             features: "+v7,+vfp3,+neon".to_string(),
             cpu: "cortex-a8".to_string(),
+            max_atomic_width: 64,
             .. base
         }
     }
diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs
index d317589bf36..e5379aa1b42 100644
--- a/src/librustc_back/target/armv7s_apple_ios.rs
+++ b/src/librustc_back/target/armv7s_apple_ios.rs
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         target_vendor: "apple".to_string(),
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".to_string(),
+            max_atomic_width: 64,
             .. opts(Arch::Armv7s)
         }
     }
diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs
index 546f9df605b..e6200177944 100644
--- a/src/librustc_back/target/asmjs_unknown_emscripten.rs
+++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs
@@ -22,6 +22,7 @@ pub fn target() -> Target {
         linker_is_gnu: true,
         allow_asm: false,
         obj_is_bitcode: true,
+        max_atomic_width: 32,
         .. Default::default()
     };
     Target {
diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs
index d149d4bbdc2..cf4020eeb58 100644
--- a/src/librustc_back/target/i386_apple_ios.rs
+++ b/src/librustc_back/target/i386_apple_ios.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::Target;
+use target::{Target, TargetOptions};
 use super::apple_ios_base::{opts, Arch};
 
 pub fn target() -> Target {
@@ -21,6 +21,9 @@ pub fn target() -> Target {
         target_os: "ios".to_string(),
         target_env: "".to_string(),
         target_vendor: "apple".to_string(),
-        options: opts(Arch::I386)
+        options: TargetOptions {
+            max_atomic_width: 64,
+            .. opts(Arch::I386)
+        }
     }
 }
diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs
index b6e2f4d8e8a..302691e9a59 100644
--- a/src/librustc_back/target/i686_apple_darwin.rs
+++ b/src/librustc_back/target/i686_apple_darwin.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::apple_base::opts();
     base.cpu = "yonah".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m32".to_string());
 
     Target {
diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs
index b338a971ff7..426be63cf21 100644
--- a/src/librustc_back/target/i686_linux_android.rs
+++ b/src/librustc_back/target/i686_linux_android.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.cpu = "pentium4".to_string();
+    base.max_atomic_width = 64;
 
     Target {
         llvm_target: "i686-linux-android".to_string(),
diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs
index 48203cc74d6..c2cc624c9f9 100644
--- a/src/librustc_back/target/i686_pc_windows_gnu.rs
+++ b/src/librustc_back/target/i686_pc_windows_gnu.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::windows_base::opts();
     base.cpu = "pentium4".to_string();
+    base.max_atomic_width = 64;
 
     // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
     // space available to x86 Windows binaries on x86_64.
diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_back/target/i686_pc_windows_msvc.rs
index 501219ad607..8c1bacc2807 100644
--- a/src/librustc_back/target/i686_pc_windows_msvc.rs
+++ b/src/librustc_back/target/i686_pc_windows_msvc.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
     base.cpu = "pentium4".to_string();
+    base.max_atomic_width = 64;
 
     // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
     // space available to x86 Windows binaries on x86_64.
diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs
index cdbbd5eafdd..6446ac45f7d 100644
--- a/src/librustc_back/target/i686_unknown_dragonfly.rs
+++ b/src/librustc_back/target/i686_unknown_dragonfly.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::dragonfly_base::opts();
     base.cpu = "pentium4".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m32".to_string());
 
     Target {
diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs
index fadedc24149..a7903d5db64 100644
--- a/src/librustc_back/target/i686_unknown_freebsd.rs
+++ b/src/librustc_back/target/i686_unknown_freebsd.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "pentium4".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m32".to_string());
 
     Target {
diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs
index a1f3ab76907..7813d557076 100644
--- a/src/librustc_back/target/i686_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "pentium4".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m32".to_string());
 
     Target {
diff --git a/src/librustc_back/target/i686_unknown_linux_musl.rs b/src/librustc_back/target/i686_unknown_linux_musl.rs
index 95fc0abece0..52744295837 100644
--- a/src/librustc_back/target/i686_unknown_linux_musl.rs
+++ b/src/librustc_back/target/i686_unknown_linux_musl.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "pentium4".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m32".to_string());
     base.pre_link_args.push("-Wl,-melf_i386".to_string());
 
diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs
index 472b73302a3..f4f0262d476 100644
--- a/src/librustc_back/target/le32_unknown_nacl.rs
+++ b/src/librustc_back/target/le32_unknown_nacl.rs
@@ -25,6 +25,7 @@ pub fn target() -> Target {
         no_compiler_rt: false,
         linker_is_gnu: true,
         allow_asm: false,
+        max_atomic_width: 32,
         .. Default::default()
     };
     Target {
diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs
index 863f5ceab0a..794e4d4996c 100644
--- a/src/librustc_back/target/mips_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+soft-float".to_string(),
+            max_atomic_width: 32,
             ..super::linux_base::opts()
         },
     }
diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs
index ac0fde5449f..35366659d58 100644
--- a/src/librustc_back/target/mips_unknown_linux_musl.rs
+++ b/src/librustc_back/target/mips_unknown_linux_musl.rs
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+soft-float".to_string(),
+            max_atomic_width: 32,
             ..super::linux_base::opts()
         }
     }
diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
index ff33effa3e7..ac1536b3d00 100644
--- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs
@@ -24,6 +24,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             cpu: "mips32".to_string(),
             features: "+mips32".to_string(),
+            max_atomic_width: 32,
             ..super::linux_base::opts()
         },
     }
diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs
index d9fb1405036..a9ea52c4278 100644
--- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs
+++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs
@@ -23,6 +23,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             cpu: "mips32".to_string(),
             features: "+mips32".to_string(),
+            max_atomic_width: 32,
             ..super::linux_base::opts()
         }
     }
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 30d0b47029d..2163a8a1689 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -292,6 +292,10 @@ pub struct TargetOptions {
     // If we give emcc .o files that are actually .bc files it
     // will 'just work'.
     pub obj_is_bitcode: bool,
+
+    /// Maximum integer size in bits that this target can perform atomic
+    /// operations on.
+    pub max_atomic_width: u64,
 }
 
 impl Default for TargetOptions {
@@ -340,6 +344,7 @@ impl Default for TargetOptions {
             allow_asm: true,
             has_elf_tls: false,
             obj_is_bitcode: false,
+            max_atomic_width: 0,
         }
     }
 }
@@ -392,6 +397,9 @@ impl Target {
             options: Default::default(),
         };
 
+        // Default max-atomic-width to target-pointer-width
+        base.options.max_atomic_width = base.target_pointer_width.parse().unwrap();
+
         macro_rules! key {
             ($key_name:ident) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
@@ -404,6 +412,12 @@ impl Target {
                     .map(|o| o.as_boolean()
                          .map(|s| base.options.$key_name = s));
             } );
+            ($key_name:ident, u64) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                obj.find(&name[..])
+                    .map(|o| o.as_u64()
+                         .map(|s| base.options.$key_name = s));
+            } );
             ($key_name:ident, list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).map(|o| o.as_array()
@@ -451,6 +465,7 @@ impl Target {
         key!(archive_format);
         key!(allow_asm, bool);
         key!(custom_unwind_resume, bool);
+        key!(max_atomic_width, u64);
 
         base
     }
diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
index fe7daaec1cd..be4be8e6fc9 100644
--- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
@@ -14,6 +14,7 @@ pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.push("-m64".to_string());
+    base.max_atomic_width = 64;
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
index 4aab2b1802c..b0a81ce7ec5 100644
--- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
@@ -14,6 +14,7 @@ pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "ppc64le".to_string();
     base.pre_link_args.push("-m64".to_string());
+    base.max_atomic_width = 64;
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
index 1df36442c06..aea57dc4b7f 100644
--- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.pre_link_args.push("-m32".to_string());
+    base.max_atomic_width = 32;
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".to_string(),
diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs
index c8b5dd0eccc..5542c9120a4 100644
--- a/src/librustc_back/target/x86_64_apple_darwin.rs
+++ b/src/librustc_back/target/x86_64_apple_darwin.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::apple_base::opts();
     base.cpu = "core2".to_string();
+    base.max_atomic_width = 128; // core2 support cmpxchg16b
     base.eliminate_frame_pointer = false;
     base.pre_link_args.push("-m64".to_string());
 
diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs
index d038e88f2b4..8638241f861 100644
--- a/src/librustc_back/target/x86_64_apple_ios.rs
+++ b/src/librustc_back/target/x86_64_apple_ios.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::Target;
+use target::{Target, TargetOptions};
 use super::apple_ios_base::{opts, Arch};
 
 pub fn target() -> Target {
@@ -21,6 +21,9 @@ pub fn target() -> Target {
         target_os: "ios".to_string(),
         target_env: "".to_string(),
         target_vendor: "apple".to_string(),
-        options: opts(Arch::X86_64)
+        options: TargetOptions {
+            max_atomic_width: 64,
+            .. opts(Arch::X86_64)
+        }
     }
 }
diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs
index f0a09ae71ef..e243054d023 100644
--- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs
+++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs
@@ -14,6 +14,7 @@ pub fn target() -> Target {
     let mut base = super::windows_base::opts();
     base.cpu = "x86-64".to_string();
     base.pre_link_args.push("-m64".to_string());
+    base.max_atomic_width = 64;
 
     Target {
         llvm_target: "x86_64-pc-windows-gnu".to_string(),
diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_back/target/x86_64_pc_windows_msvc.rs
index b3fbd6ef051..a23a807a025 100644
--- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs
+++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
     base.cpu = "x86-64".to_string();
+    base.max_atomic_width = 64;
 
     Target {
         llvm_target: "x86_64-pc-windows-msvc".to_string(),
diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
index 652159d10fd..af5d21c4d93 100644
--- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs
+++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
@@ -15,6 +15,7 @@ pub fn target() -> Target {
     base.pre_link_args.push("-m64".to_string());
     base.linker = "x86_64-rumprun-netbsd-gcc".to_string();
     base.ar = "x86_64-rumprun-netbsd-ar".to_string();
+    base.max_atomic_width = 64;
 
     base.dynamic_linking = false;
     base.has_rpath = false;
diff --git a/src/librustc_back/target/x86_64_sun_solaris.rs b/src/librustc_back/target/x86_64_sun_solaris.rs
index 5aa08ea9c8c..8f2c905cf2e 100644
--- a/src/librustc_back/target/x86_64_sun_solaris.rs
+++ b/src/librustc_back/target/x86_64_sun_solaris.rs
@@ -14,6 +14,7 @@ pub fn target() -> Target {
     let mut base = super::solaris_base::opts();
     base.pre_link_args.push("-m64".to_string());
     base.cpu = "x86-64".to_string();
+    base.max_atomic_width = 64;
 
     Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_back/target/x86_64_unknown_bitrig.rs
index e8b95ed80d9..87753da540a 100644
--- a/src/librustc_back/target/x86_64_unknown_bitrig.rs
+++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs
@@ -12,6 +12,7 @@ use target::Target;
 
 pub fn target() -> Target {
     let mut base = super::bitrig_base::opts();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m64".to_string());
 
     Target {
diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs
index 3fa46c31a5e..2535071f308 100644
--- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs
+++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::dragonfly_base::opts();
     base.cpu = "x86-64".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m64".to_string());
 
     Target {
diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs
index d345a321794..d3ad0578aeb 100644
--- a/src/librustc_back/target/x86_64_unknown_freebsd.rs
+++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "x86-64".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m64".to_string());
 
     Target {
diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs
index 69e333a1350..7908e0d581b 100644
--- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "x86-64".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m64".to_string());
 
     Target {
diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_back/target/x86_64_unknown_linux_musl.rs
index f8f85e5c066..3301e0e0dc9 100644
--- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs
+++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "x86-64".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m64".to_string());
 
     Target {
diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs
index 74bf7189119..7e6d1b78469 100644
--- a/src/librustc_back/target/x86_64_unknown_netbsd.rs
+++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs
@@ -12,6 +12,7 @@ use target::Target;
 
 pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m64".to_string());
 
     Target {
diff --git a/src/librustc_back/target/x86_64_unknown_openbsd.rs b/src/librustc_back/target/x86_64_unknown_openbsd.rs
index 521de5373d0..823b0994b0a 100644
--- a/src/librustc_back/target/x86_64_unknown_openbsd.rs
+++ b/src/librustc_back/target/x86_64_unknown_openbsd.rs
@@ -13,6 +13,7 @@ use target::Target;
 pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.cpu = "x86-64".to_string();
+    base.max_atomic_width = 64;
     base.pre_link_args.push("-m64".to_string());
 
     Target {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 7f01821b004..cf797b85f54 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -268,8 +268,11 @@ declare_features! (
     // pub(restricted) visibilities (RFC 1422)
     (active, pub_restricted, "1.9.0", Some(32409)),
 
-     // Allow Drop types in statics/const functions (RFC 1440)
-    (active, drop_types_in_const, "1.9.0", Some(33156))
+    // Allow Drop types in statics/const functions (RFC 1440)
+    (active, drop_types_in_const, "1.9.0", Some(33156)),
+
+    // Allows cfg(target_has_atomic = "...").
+    (active, cfg_target_has_atomic, "1.9.0", Some(32976))
 );
 
 declare_features! (
@@ -577,6 +580,7 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)]
     ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
+    ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
 ];
 
 #[derive(Debug, Eq, PartialEq)]
diff --git a/src/test/run-make/atomic-lock-free/Makefile b/src/test/run-make/atomic-lock-free/Makefile
new file mode 100644
index 00000000000..78e7bb23137
--- /dev/null
+++ b/src/test/run-make/atomic-lock-free/Makefile
@@ -0,0 +1,30 @@
+-include ../tools.mk
+
+# This tests ensure that atomic types are never lowered into runtime library calls that are not
+# guaranteed to be lock-free.
+
+all:
+ifeq ($(UNAME),Linux)
+	$(RUSTC) --target=i686-unknown-linux-gnu atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=x86_64-unknown-linux-gnu atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=arm-unknown-linux-gnueabi atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=arm-unknown-linux-gnueabihf atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=armv7-unknown-linux-gnueabihf atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=aarch64-unknown-linux-gnu atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=mips-unknown-linux-gnu atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=mipsel-unknown-linux-gnu atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=powerpc-unknown-linux-gnu atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=powerpc64-unknown-linux-gnu atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+	$(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs
+	nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add
+endif
diff --git a/src/test/run-make/atomic-lock-free/atomic_lock_free.rs b/src/test/run-make/atomic-lock-free/atomic_lock_free.rs
new file mode 100644
index 00000000000..8731cd960f3
--- /dev/null
+++ b/src/test/run-make/atomic-lock-free/atomic_lock_free.rs
@@ -0,0 +1,62 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(cfg_target_has_atomic, no_core, intrinsics, lang_items)]
+#![crate_type="rlib"]
+#![no_core]
+
+extern "rust-intrinsic" {
+    fn atomic_xadd<T>(dst: *mut T, src: T) -> T;
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+#[cfg(target_has_atomic = "8")]
+pub unsafe fn atomic_u8(x: *mut u8) {
+    atomic_xadd(x, 1);
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "8")]
+pub unsafe fn atomic_i8(x: *mut i8) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "16")]
+pub unsafe fn atomic_u16(x: *mut u16) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "16")]
+pub unsafe fn atomic_i16(x: *mut i16) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "32")]
+pub unsafe fn atomic_u32(x: *mut u32) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "32")]
+pub unsafe fn atomic_i32(x: *mut i32) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "64")]
+pub unsafe fn atomic_u64(x: *mut u64) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "64")]
+pub unsafe fn atomic_i64(x: *mut i64) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "ptr")]
+pub unsafe fn atomic_usize(x: *mut usize) {
+    atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "ptr")]
+pub unsafe fn atomic_isize(x: *mut isize) {
+    atomic_xadd(x, 1);
+}