[PATCH] Implement P0558R2 changes to std::atomic

Jonathan Wakely jwakely@redhat.com
Thu May 24 15:28:00 GMT 2018


The restrictions forbidding arithmetic on atomic pointer types are only
enabled for C++17 and later, retaining the GNU extension for older
standards. The new nested typedefs and changes to prevent scalar
parameters participating in template argument deduction are enabled
unconditionally.

	PR libstdc++/69769
	PR libstdc++/85886
	* include/bits/atomic_base.h (__atomic_base::value_type)
	(__atomic_base::difference_type): Add new typedefs.
	* include/std/atomic (atomic<bool>::value_type, atomic<T>::value_type)
	(atomic<T*>::value_type, atomic<T*>::difference_type): Likewise.
	(atomic<T*>::operator++, atomic<T*>::operator--)
	(atomic<T*>::operator+=, atomic<T*>::operator-=)
	(atomic<T*>::fetch_add, atomic<T*>::fetch_sub): Add static assertion
	to enforce C++17 requirement on pointer arithmetic.
	(__atomic_val_t, __atomic_diff_t): New alias templates.
	(atomic_init, atomic_store_explicit, atomic_exchange_explicit)
	(atomic_compare_exchange_weak_explicit)
	(atomic_compare_exchange_strong_explicit, atomic_store)
	(atomic_exchange, atomic_compare_exchange_weak)
	(atomic_compare_exchange_strong): Use __atomic_val_t to make
	scalar parameters be non-deduced contexts.
	(atomic_fetch_add_explicit, atomic_fetch_sub_explicit)
	(atomic_fetch_add, atomic_fetch_sub): Change first parameter to be
	atomic instead of __atomic_base, and use __atomic_diff_t for scalar
	parameters.
	(atomic_fetch_and_explicit, atomic_fetch_or_explicit)
	(atomic_fetch_xor_explicit, atomic_fetch_and, atomic_fetch_or)
	(atomic_fetch_xor): Use __atomic_val_t for scalar parameters.
	(atomic_fetch_add_explicit, atomic_fetch_sub_explicit)
	(atomic_fetch_add, atomic_fetch_sub): Remove overloads for atomic
	address types.
	* testsuite/29_atomics/atomic/60695.cc: Adjust dg-error lineno.
	* testsuite/29_atomics/atomic/69769.cc: New test.
	* testsuite/29_atomics/atomic/nonmembers.cc: New test.
	* testsuite/29_atomics/atomic/operators/pointer_partial_void.cc:
	Disable test for C++17 and later.
	* testsuite/29_atomics/atomic/requirements/typedefs.cc: New test.
	* testsuite/29_atomics/atomic_integral/nonmembers.cc: New test.
	* testsuite/29_atomics/atomic_integral/requirements/typedefs.cc: New
	test.

Tested powerpc64le-linux, committed to trunk.

-------------- next part --------------
commit cc606c3ce7a562750bbb1e7b1cca960a853f8daf
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu May 24 15:48:10 2018 +0100

    Implement P0558R2 changes to std::atomic
    
    The restrictions forbidding arithmetic on atomic pointer types are only
    enabled for C++17 and later, retaining the GNU extension for older
    standards. The new nested typedefs and changes to prevent scalar
    parameters participating in template argument deduction are enabled
    unconditionally.
    
            PR libstdc++/69769
            PR libstdc++/85886
            * include/bits/atomic_base.h (__atomic_base::value_type)
            (__atomic_base::difference_type): Add new typedefs.
            * include/std/atomic (atomic<bool>::value_type, atomic<T>::value_type)
            (atomic<T*>::value_type, atomic<T*>::difference_type): Likewise.
            (atomic<T*>::operator++, atomic<T*>::operator--)
            (atomic<T*>::operator+=, atomic<T*>::operator-=)
            (atomic<T*>::fetch_add, atomic<T*>::fetch_sub): Add static assertion
            to enforce C++17 requirement on pointer arithmetic.
            (__atomic_val_t, __atomic_diff_t): New alias templates.
            (atomic_init, atomic_store_explicit, atomic_exchange_explicit)
            (atomic_compare_exchange_weak_explicit)
            (atomic_compare_exchange_strong_explicit, atomic_store)
            (atomic_exchange, atomic_compare_exchange_weak)
            (atomic_compare_exchange_strong): Use __atomic_val_t to make
            scalar parameters be non-deduced contexts.
            (atomic_fetch_add_explicit, atomic_fetch_sub_explicit)
            (atomic_fetch_add, atomic_fetch_sub): Change first parameter to be
            atomic instead of __atomic_base, and use __atomic_diff_t for scalar
            parameters.
            (atomic_fetch_and_explicit, atomic_fetch_or_explicit)
            (atomic_fetch_xor_explicit, atomic_fetch_and, atomic_fetch_or)
            (atomic_fetch_xor): Use __atomic_val_t for scalar parameters.
            (atomic_fetch_add_explicit, atomic_fetch_sub_explicit)
            (atomic_fetch_add, atomic_fetch_sub): Remove overloads for atomic
            address types.
            * testsuite/29_atomics/atomic/60695.cc: Adjust dg-error lineno.
            * testsuite/29_atomics/atomic/69769.cc: New test.
            * testsuite/29_atomics/atomic/nonmembers.cc: New test.
            * testsuite/29_atomics/atomic/operators/pointer_partial_void.cc:
            Disable test for C++17 and later.
            * testsuite/29_atomics/atomic/requirements/typedefs.cc: New test.
            * testsuite/29_atomics/atomic_integral/nonmembers.cc: New test.
            * testsuite/29_atomics/atomic_integral/requirements/typedefs.cc: New
            test.

diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index a1fadcd8056..7a3354d9e6f 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -237,6 +237,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _ITp>
     struct __atomic_base
     {
+      using value_type = _ITp;
+      using difference_type = value_type;
+
     private:
       typedef _ITp 	__int_type;
 
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index c234af83c2e..002604676cd 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -50,7 +50,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * @{
    */
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
 # define __cpp_lib_atomic_is_always_lock_free 201603
 #endif
 
@@ -62,6 +62,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<>
   struct atomic<bool>
   {
+    using value_type = bool;
+
   private:
     __atomic_base<bool>	_M_base;
 
@@ -94,7 +96,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     bool
     is_lock_free() const volatile noexcept { return _M_base.is_lock_free(); }
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_BOOL_LOCK_FREE == 2;
 #endif
 
@@ -173,6 +175,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct atomic
     {
+      using value_type = _Tp;
+
     private:
       // Align 1/2/4/8/16-byte types to at least their size.
       static constexpr int _S_min_alignment
@@ -229,7 +233,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    reinterpret_cast<void *>(-__alignof(_M_i)));
       }
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
       static constexpr bool is_always_lock_free
 	= __atomic_always_lock_free(sizeof(_M_i), 0);
 #endif
@@ -351,6 +355,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     struct atomic<_Tp*>
     {
+      using value_type = _Tp*;
+      using difference_type = ptrdiff_t;
+
       typedef _Tp* 			__pointer_type;
       typedef __atomic_base<_Tp*>	__base_type;
       __base_type			_M_b;
@@ -379,51 +386,111 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       __pointer_type
       operator++(int) noexcept
-      { return _M_b++; }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b++;
+      }
 
       __pointer_type
       operator++(int) volatile noexcept
-      { return _M_b++; }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b++;
+      }
 
       __pointer_type
       operator--(int) noexcept
-      { return _M_b--; }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b--;
+      }
 
       __pointer_type
       operator--(int) volatile noexcept
-      { return _M_b--; }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b--;
+      }
 
       __pointer_type
       operator++() noexcept
-      { return ++_M_b; }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return ++_M_b;
+      }
 
       __pointer_type
       operator++() volatile noexcept
-      { return ++_M_b; }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return ++_M_b;
+      }
 
       __pointer_type
       operator--() noexcept
-      { return --_M_b; }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return --_M_b;
+      }
 
       __pointer_type
       operator--() volatile noexcept
-      { return --_M_b; }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return --_M_b;
+      }
 
       __pointer_type
       operator+=(ptrdiff_t __d) noexcept
-      { return _M_b.operator+=(__d); }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b.operator+=(__d);
+      }
 
       __pointer_type
       operator+=(ptrdiff_t __d) volatile noexcept
-      { return _M_b.operator+=(__d); }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b.operator+=(__d);
+      }
 
       __pointer_type
       operator-=(ptrdiff_t __d) noexcept
-      { return _M_b.operator-=(__d); }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b.operator-=(__d);
+      }
 
       __pointer_type
       operator-=(ptrdiff_t __d) volatile noexcept
-      { return _M_b.operator-=(__d); }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b.operator-=(__d);
+      }
 
       bool
       is_lock_free() const noexcept
@@ -433,7 +500,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       is_lock_free() const volatile noexcept
       { return _M_b.is_lock_free(); }
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_POINTER_LOCK_FREE == 2;
 #endif
 
@@ -522,22 +589,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
-      { return _M_b.fetch_add(__d, __m); }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b.fetch_add(__d, __m);
+      }
 
       __pointer_type
       fetch_add(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) volatile noexcept
-      { return _M_b.fetch_add(__d, __m); }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b.fetch_add(__d, __m);
+      }
 
       __pointer_type
       fetch_sub(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) noexcept
-      { return _M_b.fetch_sub(__d, __m); }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b.fetch_sub(__d, __m);
+      }
 
       __pointer_type
       fetch_sub(ptrdiff_t __d,
 		memory_order __m = memory_order_seq_cst) volatile noexcept
-      { return _M_b.fetch_sub(__d, __m); }
+      {
+#if __cplusplus >= 201703L
+	static_assert( is_object<_Tp>::value, "pointer to object type" );
+#endif
+	return _M_b.fetch_sub(__d, __m);
+      }
     };
 
 
@@ -559,7 +646,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2;
 #endif
     };
@@ -582,7 +669,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2;
 #endif
     };
@@ -605,7 +692,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_CHAR_LOCK_FREE == 2;
 #endif
     };
@@ -628,7 +715,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_SHORT_LOCK_FREE == 2;
 #endif
     };
@@ -651,7 +738,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_SHORT_LOCK_FREE == 2;
 #endif
     };
@@ -674,7 +761,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_INT_LOCK_FREE == 2;
 #endif
     };
@@ -697,7 +784,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_INT_LOCK_FREE == 2;
 #endif
     };
@@ -720,7 +807,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_LONG_LOCK_FREE == 2;
 #endif
     };
@@ -743,7 +830,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_LONG_LOCK_FREE == 2;
 #endif
     };
@@ -766,7 +853,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_LLONG_LOCK_FREE == 2;
 #endif
     };
@@ -789,7 +876,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_LLONG_LOCK_FREE == 2;
 #endif
     };
@@ -812,7 +899,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_WCHAR_T_LOCK_FREE == 2;
 #endif
     };
@@ -835,7 +922,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_CHAR16_T_LOCK_FREE == 2;
 #endif
     };
@@ -858,7 +945,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using __base_type::operator __integral_type;
       using __base_type::operator=;
 
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
     static constexpr bool is_always_lock_free = ATOMIC_CHAR32_T_LOCK_FREE == 2;
 #endif
     };
@@ -1046,6 +1133,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   { atomic_flag_clear_explicit(__a, memory_order_seq_cst); }
 
 
+  template<typename _Tp>
+    using __atomic_val_t = typename atomic<_Tp>::value_type;
+  template<typename _Tp>
+    using __atomic_diff_t = typename atomic<_Tp>::difference_type;
+
+  // [atomics.nonmembers] Non-member functions.
   // Function templates generally applicable to atomic types.
   template<typename _ITp>
     inline bool
@@ -1059,23 +1152,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _ITp>
     inline void
-    atomic_init(atomic<_ITp>* __a, _ITp __i) noexcept
+    atomic_init(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
     { __a->store(__i, memory_order_relaxed); }
 
   template<typename _ITp>
     inline void
-    atomic_init(volatile atomic<_ITp>* __a, _ITp __i) noexcept
+    atomic_init(volatile atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
     { __a->store(__i, memory_order_relaxed); }
 
   template<typename _ITp>
     inline void
-    atomic_store_explicit(atomic<_ITp>* __a, _ITp __i,
+    atomic_store_explicit(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i,
 			  memory_order __m) noexcept
     { __a->store(__i, __m); }
 
   template<typename _ITp>
     inline void
-    atomic_store_explicit(volatile atomic<_ITp>* __a, _ITp __i,
+    atomic_store_explicit(volatile atomic<_ITp>* __a, __atomic_val_t<_ITp> __i,
 			  memory_order __m) noexcept
     { __a->store(__i, __m); }
 
@@ -1092,20 +1185,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _ITp>
     inline _ITp
-    atomic_exchange_explicit(atomic<_ITp>* __a, _ITp __i,
+    atomic_exchange_explicit(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i,
 			     memory_order __m) noexcept
     { return __a->exchange(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_exchange_explicit(volatile atomic<_ITp>* __a, _ITp __i,
+    atomic_exchange_explicit(volatile atomic<_ITp>* __a,
+			     __atomic_val_t<_ITp> __i,
 			     memory_order __m) noexcept
     { return __a->exchange(__i, __m); }
 
   template<typename _ITp>
     inline bool
     atomic_compare_exchange_weak_explicit(atomic<_ITp>* __a,
-					  _ITp* __i1, _ITp __i2,
+					  __atomic_val_t<_ITp>* __i1,
+					  __atomic_val_t<_ITp> __i2,
 					  memory_order __m1,
 					  memory_order __m2) noexcept
     { return __a->compare_exchange_weak(*__i1, __i2, __m1, __m2); }
@@ -1113,7 +1208,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _ITp>
     inline bool
     atomic_compare_exchange_weak_explicit(volatile atomic<_ITp>* __a,
-					  _ITp* __i1, _ITp __i2,
+					  __atomic_val_t<_ITp>* __i1,
+					  __atomic_val_t<_ITp> __i2,
 					  memory_order __m1,
 					  memory_order __m2) noexcept
     { return __a->compare_exchange_weak(*__i1, __i2, __m1, __m2); }
@@ -1121,7 +1217,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _ITp>
     inline bool
     atomic_compare_exchange_strong_explicit(atomic<_ITp>* __a,
-					    _ITp* __i1, _ITp __i2,
+					    __atomic_val_t<_ITp>* __i1,
+					    __atomic_val_t<_ITp> __i2,
 					    memory_order __m1,
 					    memory_order __m2) noexcept
     { return __a->compare_exchange_strong(*__i1, __i2, __m1, __m2); }
@@ -1129,7 +1226,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _ITp>
     inline bool
     atomic_compare_exchange_strong_explicit(volatile atomic<_ITp>* __a,
-					    _ITp* __i1, _ITp __i2,
+					    __atomic_val_t<_ITp>* __i1,
+					    __atomic_val_t<_ITp> __i2,
 					    memory_order __m1,
 					    memory_order __m2) noexcept
     { return __a->compare_exchange_strong(*__i1, __i2, __m1, __m2); }
@@ -1137,12 +1235,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _ITp>
     inline void
-    atomic_store(atomic<_ITp>* __a, _ITp __i) noexcept
+    atomic_store(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
     { atomic_store_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline void
-    atomic_store(volatile atomic<_ITp>* __a, _ITp __i) noexcept
+    atomic_store(volatile atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
     { atomic_store_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
@@ -1157,18 +1255,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _ITp>
     inline _ITp
-    atomic_exchange(atomic<_ITp>* __a, _ITp __i) noexcept
+    atomic_exchange(atomic<_ITp>* __a, __atomic_val_t<_ITp> __i) noexcept
     { return atomic_exchange_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_exchange(volatile atomic<_ITp>* __a, _ITp __i) noexcept
+    atomic_exchange(volatile atomic<_ITp>* __a,
+		    __atomic_val_t<_ITp> __i) noexcept
     { return atomic_exchange_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline bool
     atomic_compare_exchange_weak(atomic<_ITp>* __a,
-				 _ITp* __i1, _ITp __i2) noexcept
+				 __atomic_val_t<_ITp>* __i1,
+				 __atomic_val_t<_ITp> __i2) noexcept
     {
       return atomic_compare_exchange_weak_explicit(__a, __i1, __i2,
 						   memory_order_seq_cst,
@@ -1178,7 +1278,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _ITp>
     inline bool
     atomic_compare_exchange_weak(volatile atomic<_ITp>* __a,
-				 _ITp* __i1, _ITp __i2) noexcept
+				 __atomic_val_t<_ITp>* __i1,
+				 __atomic_val_t<_ITp> __i2) noexcept
     {
       return atomic_compare_exchange_weak_explicit(__a, __i1, __i2,
 						   memory_order_seq_cst,
@@ -1188,7 +1289,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _ITp>
     inline bool
     atomic_compare_exchange_strong(atomic<_ITp>* __a,
-				   _ITp* __i1, _ITp __i2) noexcept
+				   __atomic_val_t<_ITp>* __i1,
+				   __atomic_val_t<_ITp> __i2) noexcept
     {
       return atomic_compare_exchange_strong_explicit(__a, __i1, __i2,
 						     memory_order_seq_cst,
@@ -1198,172 +1300,148 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _ITp>
     inline bool
     atomic_compare_exchange_strong(volatile atomic<_ITp>* __a,
-				   _ITp* __i1, _ITp __i2) noexcept
+				   __atomic_val_t<_ITp>* __i1,
+				   __atomic_val_t<_ITp> __i2) noexcept
     {
       return atomic_compare_exchange_strong_explicit(__a, __i1, __i2,
 						     memory_order_seq_cst,
 						     memory_order_seq_cst);
     }
 
-  // Function templates for atomic_integral operations only, using
-  // __atomic_base. Template argument should be constricted to
-  // intergral types as specified in the standard, excluding address
-  // types.
+  // Function templates for atomic_integral and atomic_pointer operations only.
+  // Some operations (and, or, xor) are only available for atomic integrals,
+  // which is implemented by taking a parameter of type __atomic_base<_ITp>*.
+
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_add_explicit(__atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_add_explicit(atomic<_ITp>* __a,
+			      __atomic_diff_t<_ITp> __i,
 			      memory_order __m) noexcept
     { return __a->fetch_add(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_add_explicit(volatile __atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_add_explicit(volatile atomic<_ITp>* __a,
+			      __atomic_diff_t<_ITp> __i,
 			      memory_order __m) noexcept
     { return __a->fetch_add(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_sub_explicit(__atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_sub_explicit(atomic<_ITp>* __a,
+			      __atomic_diff_t<_ITp> __i,
 			      memory_order __m) noexcept
     { return __a->fetch_sub(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_sub_explicit(volatile __atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_sub_explicit(volatile atomic<_ITp>* __a,
+			      __atomic_diff_t<_ITp> __i,
 			      memory_order __m) noexcept
     { return __a->fetch_sub(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_and_explicit(__atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_and_explicit(__atomic_base<_ITp>* __a,
+			      __atomic_val_t<_ITp> __i,
 			      memory_order __m) noexcept
     { return __a->fetch_and(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_and_explicit(volatile __atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_and_explicit(volatile __atomic_base<_ITp>* __a,
+			      __atomic_val_t<_ITp> __i,
 			      memory_order __m) noexcept
     { return __a->fetch_and(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_or_explicit(__atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_or_explicit(__atomic_base<_ITp>* __a,
+			     __atomic_val_t<_ITp> __i,
 			     memory_order __m) noexcept
     { return __a->fetch_or(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_or_explicit(volatile __atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_or_explicit(volatile __atomic_base<_ITp>* __a,
+			     __atomic_val_t<_ITp> __i,
 			     memory_order __m) noexcept
     { return __a->fetch_or(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_xor_explicit(__atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_xor_explicit(__atomic_base<_ITp>* __a,
+			      __atomic_val_t<_ITp> __i,
 			      memory_order __m) noexcept
     { return __a->fetch_xor(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_xor_explicit(volatile __atomic_base<_ITp>* __a, _ITp __i,
+    atomic_fetch_xor_explicit(volatile __atomic_base<_ITp>* __a,
+			      __atomic_val_t<_ITp> __i,
 			      memory_order __m) noexcept
     { return __a->fetch_xor(__i, __m); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_add(__atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_add(atomic<_ITp>* __a,
+		     __atomic_diff_t<_ITp> __i) noexcept
     { return atomic_fetch_add_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_add(volatile __atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_add(volatile atomic<_ITp>* __a,
+		     __atomic_diff_t<_ITp> __i) noexcept
     { return atomic_fetch_add_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_sub(__atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_sub(atomic<_ITp>* __a,
+		     __atomic_diff_t<_ITp> __i) noexcept
     { return atomic_fetch_sub_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_sub(volatile __atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_sub(volatile atomic<_ITp>* __a,
+		     __atomic_diff_t<_ITp> __i) noexcept
     { return atomic_fetch_sub_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_and(__atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_and(__atomic_base<_ITp>* __a,
+		     __atomic_val_t<_ITp> __i) noexcept
     { return atomic_fetch_and_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_and(volatile __atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_and(volatile __atomic_base<_ITp>* __a,
+		     __atomic_val_t<_ITp> __i) noexcept
     { return atomic_fetch_and_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_or(__atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_or(__atomic_base<_ITp>* __a,
+		    __atomic_val_t<_ITp> __i) noexcept
     { return atomic_fetch_or_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_or(volatile __atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_or(volatile __atomic_base<_ITp>* __a,
+		    __atomic_val_t<_ITp> __i) noexcept
     { return atomic_fetch_or_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_xor(__atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_xor(__atomic_base<_ITp>* __a,
+		     __atomic_val_t<_ITp> __i) noexcept
     { return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
 
   template<typename _ITp>
     inline _ITp
-    atomic_fetch_xor(volatile __atomic_base<_ITp>* __a, _ITp __i) noexcept
+    atomic_fetch_xor(volatile __atomic_base<_ITp>* __a,
+		     __atomic_val_t<_ITp> __i) noexcept
     { return atomic_fetch_xor_explicit(__a, __i, memory_order_seq_cst); }
 
-
-  // Partial specializations for pointers.
-  template<typename _ITp>
-    inline _ITp*
-    atomic_fetch_add_explicit(atomic<_ITp*>* __a, ptrdiff_t __d,
-			      memory_order __m) noexcept
-    { return __a->fetch_add(__d, __m); }
-
-  template<typename _ITp>
-    inline _ITp*
-    atomic_fetch_add_explicit(volatile atomic<_ITp*>* __a, ptrdiff_t __d,
-			      memory_order __m) noexcept
-    { return __a->fetch_add(__d, __m); }
-
-  template<typename _ITp>
-    inline _ITp*
-    atomic_fetch_add(volatile atomic<_ITp*>* __a, ptrdiff_t __d) noexcept
-    { return __a->fetch_add(__d); }
-
-  template<typename _ITp>
-    inline _ITp*
-    atomic_fetch_add(atomic<_ITp*>* __a, ptrdiff_t __d) noexcept
-    { return __a->fetch_add(__d); }
-
-  template<typename _ITp>
-    inline _ITp*
-    atomic_fetch_sub_explicit(volatile atomic<_ITp*>* __a,
-			      ptrdiff_t __d, memory_order __m) noexcept
-    { return __a->fetch_sub(__d, __m); }
-
-  template<typename _ITp>
-    inline _ITp*
-    atomic_fetch_sub_explicit(atomic<_ITp*>* __a, ptrdiff_t __d,
-			      memory_order __m) noexcept
-    { return __a->fetch_sub(__d, __m); }
-
-  template<typename _ITp>
-    inline _ITp*
-    atomic_fetch_sub(volatile atomic<_ITp*>* __a, ptrdiff_t __d) noexcept
-    { return __a->fetch_sub(__d); }
-
-  template<typename _ITp>
-    inline _ITp*
-    atomic_fetch_sub(atomic<_ITp*>* __a, ptrdiff_t __d) noexcept
-    { return __a->fetch_sub(__d); }
   // @} group atomics
 
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc b/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc
index 8411895eda5..cf2dfb2d28c 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc
@@ -27,4 +27,4 @@ struct X {
   char stuff[0]; // GNU extension, type has zero size
 };
 
-std::atomic<X> a;  // { dg-error "not supported" "" { target *-*-* } 190 }
+std::atomic<X> a;  // { dg-error "not supported" "" { target *-*-* } 194 }
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/69769.cc b/libstdc++-v3/testsuite/29_atomics/atomic/69769.cc
new file mode 100644
index 00000000000..38fc49d0f25
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/69769.cc
@@ -0,0 +1,80 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+// { dg-require-atomic-builtins "" }
+
+#include <atomic>
+
+void
+test01()
+{
+  std::atomic<void*> p;
+  p.fetch_add(1); // { dg-error "from here" }
+  p.fetch_sub(1); // { dg-error "from here" }
+  p += 1;	  // { dg-error "from here" }
+  p -= 1;	  // { dg-error "from here" }
+  ++p;		  // { dg-error "from here" }
+  p++;		  // { dg-error "from here" }
+  --p;		  // { dg-error "from here" }
+  p--;		  // { dg-error "from here" }
+}
+
+void
+test02()
+{
+  std::atomic<void(*)()> p;
+  p.fetch_add(1); // { dg-error "from here" }
+  p.fetch_sub(1); // { dg-error "from here" }
+  p += 1;	  // { dg-error "from here" }
+  p -= 1;	  // { dg-error "from here" }
+  ++p;		  // { dg-error "from here" }
+  p++;		  // { dg-error "from here" }
+  --p;		  // { dg-error "from here" }
+  p--;		  // { dg-error "from here" }
+}
+
+void
+test03()
+{
+  volatile std::atomic<void*> p;
+  p.fetch_add(1); // { dg-error "from here" }
+  p.fetch_sub(1); // { dg-error "from here" }
+  p += 1;	  // { dg-error "from here" }
+  p -= 1;	  // { dg-error "from here" }
+  ++p;		  // { dg-error "from here" }
+  p++;		  // { dg-error "from here" }
+  --p;		  // { dg-error "from here" }
+  p--;		  // { dg-error "from here" }
+}
+
+void
+test04()
+{
+  volatile std::atomic<void(*)()> p;
+  p.fetch_add(1); // { dg-error "from here" }
+  p.fetch_sub(1); // { dg-error "from here" }
+  p += 1;	  // { dg-error "from here" }
+  p -= 1;	  // { dg-error "from here" }
+  ++p;		  // { dg-error "from here" }
+  p++;		  // { dg-error "from here" }
+  --p;		  // { dg-error "from here" }
+  p--;		  // { dg-error "from here" }
+}
+
+// { dg-prune-output "static assertion failed" }
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/nonmembers.cc b/libstdc++-v3/testsuite/29_atomics/atomic/nonmembers.cc
new file mode 100644
index 00000000000..886ad7be863
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/nonmembers.cc
@@ -0,0 +1,230 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+// { dg-require-atomic-builtins "" }
+
+#include <atomic>
+
+void
+test01()
+{
+  struct X { };
+  struct Y { };
+  // Primary template
+  volatile std::atomic<X> v;
+  std::atomic<Y> a;
+  const std::memory_order mo = std::memory_order_seq_cst;
+  X x;
+  Y y;
+  auto r1 = atomic_is_lock_free(&v);
+  static_assert( std::is_same<decltype(r1), bool>::value, "" );
+  auto r2 = atomic_is_lock_free(&a);
+  static_assert( std::is_same<decltype(r2), bool>::value, "" );
+  atomic_init(&v, x);
+  atomic_init(&a, y);
+  atomic_store(&v, x);
+  atomic_store(&a, y);
+  atomic_store_explicit(&v, x, mo);
+  atomic_store_explicit(&a, y, mo);
+  auto r3 = atomic_load(&v);
+  static_assert( std::is_same<decltype(r3), X>::value, "" );
+  auto r4 = atomic_load(&a);
+  static_assert( std::is_same<decltype(r4), Y>::value, "" );
+  auto r5 = atomic_load_explicit(&v, mo);
+  static_assert( std::is_same<decltype(r5), X>::value, "" );
+  auto r6 = atomic_load_explicit(&a, mo);
+  static_assert( std::is_same<decltype(r6), Y>::value, "" );
+  auto r7 = atomic_exchange(&v, x);
+  static_assert( std::is_same<decltype(r7), X>::value, "" );
+  auto r8 = atomic_exchange(&a, y);
+  static_assert( std::is_same<decltype(r8), Y>::value, "" );
+  auto r9 = atomic_exchange_explicit(&v, x, mo);
+  static_assert( std::is_same<decltype(r9), X>::value, "" );
+  auto r10 = atomic_exchange_explicit(&a, y, mo);
+  static_assert( std::is_same<decltype(r10), Y>::value, "" );
+  auto r11 = atomic_compare_exchange_weak(&v, &x, x);
+  static_assert( std::is_same<decltype(r11), bool>::value, "" );
+  auto r12 = atomic_compare_exchange_weak(&a, &y, y);
+  static_assert( std::is_same<decltype(r12), bool>::value, "" );
+  auto r13 = atomic_compare_exchange_strong(&v, &x, x);
+  static_assert( std::is_same<decltype(r13), bool>::value, "" );
+  auto r14 = atomic_compare_exchange_strong(&a, &y, y);
+  static_assert( std::is_same<decltype(r14), bool>::value, "" );
+  auto r15 = atomic_compare_exchange_weak_explicit(&v, &x, x, mo, mo);
+  static_assert( std::is_same<decltype(r15), bool>::value, "" );
+  auto r16 = atomic_compare_exchange_weak_explicit(&a, &y, y, mo, mo);
+  static_assert( std::is_same<decltype(r16), bool>::value, "" );
+  auto r17 = atomic_compare_exchange_strong_explicit(&v, &x, x, mo, mo);
+  static_assert( std::is_same<decltype(r17), bool>::value, "" );
+  auto r18 = atomic_compare_exchange_strong_explicit(&a, &y, y, mo, mo);
+  static_assert( std::is_same<decltype(r18), bool>::value, "" );
+}
+
+void
+test02()
+{
+  // Specialization for bool
+  volatile std::atomic<bool> v;
+  std::atomic<bool> a;
+  const std::memory_order mo = std::memory_order_seq_cst;
+  bool b = false;
+  auto r1 = atomic_is_lock_free(&v);
+  static_assert( std::is_same<decltype(r1), bool>::value, "" );
+  auto r2 = atomic_is_lock_free(&a);
+  static_assert( std::is_same<decltype(r2), bool>::value, "" );
+  atomic_init(&v, b);
+  atomic_init(&a, b);
+  atomic_store(&v, b);
+  atomic_store(&a, b);
+  atomic_store_explicit(&v, b, mo);
+  atomic_store_explicit(&a, b, mo);
+  auto r3 = atomic_load(&v);
+  static_assert( std::is_same<decltype(r3), bool>::value, "" );
+  auto r4 = atomic_load(&a);
+  static_assert( std::is_same<decltype(r4), bool>::value, "" );
+  auto r5 = atomic_load_explicit(&v, mo);
+  static_assert( std::is_same<decltype(r5), bool>::value, "" );
+  auto r6 = atomic_load_explicit(&a, mo);
+  static_assert( std::is_same<decltype(r6), bool>::value, "" );
+  auto r7 = atomic_exchange(&v, b);
+  static_assert( std::is_same<decltype(r7), bool>::value, "" );
+  auto r8 = atomic_exchange(&a, b);
+  static_assert( std::is_same<decltype(r8), bool>::value, "" );
+  auto r9 = atomic_exchange_explicit(&v, b, mo);
+  static_assert( std::is_same<decltype(r9), bool>::value, "" );
+  auto r10 = atomic_exchange_explicit(&a, b, mo);
+  static_assert( std::is_same<decltype(r10), bool>::value, "" );
+  auto r11 = atomic_compare_exchange_weak(&v, &b, b);
+  static_assert( std::is_same<decltype(r11), bool>::value, "" );
+  auto r12 = atomic_compare_exchange_weak(&a, &b, b);
+  static_assert( std::is_same<decltype(r12), bool>::value, "" );
+  auto r13 = atomic_compare_exchange_strong(&v, &b, b);
+  static_assert( std::is_same<decltype(r13), bool>::value, "" );
+  auto r14 = atomic_compare_exchange_strong(&a, &b, b);
+  static_assert( std::is_same<decltype(r14), bool>::value, "" );
+  auto r15 = atomic_compare_exchange_weak_explicit(&v, &b, b, mo, mo);
+  static_assert( std::is_same<decltype(r15), bool>::value, "" );
+  auto r16 = atomic_compare_exchange_weak_explicit(&a, &b, b, mo, mo);
+  static_assert( std::is_same<decltype(r16), bool>::value, "" );
+  auto r17 = atomic_compare_exchange_strong_explicit(&v, &b, b, mo, mo);
+  static_assert( std::is_same<decltype(r17), bool>::value, "" );
+  auto r18 = atomic_compare_exchange_strong_explicit(&a, &b, b, mo, mo);
+  static_assert( std::is_same<decltype(r18), bool>::value, "" );
+}
+
+void
+test03()
+{
+  // Partial specialization for pointers
+  volatile std::atomic<int*> v;
+  std::atomic<long*> a;
+  const std::memory_order mo = std::memory_order_seq_cst;
+  int* i = nullptr;
+  long* l = nullptr;
+  auto r1 = atomic_is_lock_free(&v);
+  static_assert( std::is_same<decltype(r1), bool>::value, "" );
+  auto r2 = atomic_is_lock_free(&a);
+  static_assert( std::is_same<decltype(r2), bool>::value, "" );
+  atomic_init(&v, i);
+  atomic_init(&a, l);
+  atomic_store(&v, i);
+  atomic_store(&a, l);
+  atomic_store_explicit(&v, i, mo);
+  atomic_store_explicit(&a, l, mo);
+  auto r3 = atomic_load(&v);
+  static_assert( std::is_same<decltype(r3), int*>::value, "" );
+  auto r4 = atomic_load(&a);
+  static_assert( std::is_same<decltype(r4), long*>::value, "" );
+  auto r5 = atomic_load_explicit(&v, mo);
+  static_assert( std::is_same<decltype(r5), int*>::value, "" );
+  auto r6 = atomic_load_explicit(&a, mo);
+  static_assert( std::is_same<decltype(r6), long*>::value, "" );
+  auto r7 = atomic_exchange(&v, i);
+  static_assert( std::is_same<decltype(r7), int*>::value, "" );
+  auto r8 = atomic_exchange(&a, l);
+  static_assert( std::is_same<decltype(r8), long*>::value, "" );
+  auto r9 = atomic_exchange_explicit(&v, i, mo);
+  static_assert( std::is_same<decltype(r9), int*>::value, "" );
+  auto r10 = atomic_exchange_explicit(&a, l, mo);
+  static_assert( std::is_same<decltype(r10), long*>::value, "" );
+  auto r11 = atomic_compare_exchange_weak(&v, &i, i);
+  static_assert( std::is_same<decltype(r11), bool>::value, "" );
+  auto r12 = atomic_compare_exchange_weak(&a, &l, l);
+  static_assert( std::is_same<decltype(r12), bool>::value, "" );
+  auto r13 = atomic_compare_exchange_strong(&v, &i, i);
+  static_assert( std::is_same<decltype(r13), bool>::value, "" );
+  auto r14 = atomic_compare_exchange_strong(&a, &l, l);
+  static_assert( std::is_same<decltype(r14), bool>::value, "" );
+  auto r15 = atomic_compare_exchange_weak_explicit(&v, &i, i, mo, mo);
+  static_assert( std::is_same<decltype(r15), bool>::value, "" );
+  auto r16 = atomic_compare_exchange_weak_explicit(&a, &l, l, mo, mo);
+  static_assert( std::is_same<decltype(r16), bool>::value, "" );
+  auto r17 = atomic_compare_exchange_strong_explicit(&v, &i, i, mo, mo);
+  static_assert( std::is_same<decltype(r17), bool>::value, "" );
+  auto r18 = atomic_compare_exchange_strong_explicit(&a, &l, l, mo, mo);
+  static_assert( std::is_same<decltype(r18), bool>::value, "" );
+
+  auto r19 = atomic_fetch_add(&v, 1);
+  static_assert( std::is_same<decltype(r19), int*>::value, "" );
+  auto r20 = atomic_fetch_add(&a, 1);
+  static_assert( std::is_same<decltype(r20), long*>::value, "" );
+  auto r21 = atomic_fetch_add_explicit(&v, 1, mo);
+  static_assert( std::is_same<decltype(r21), int*>::value, "" );
+  auto r22 = atomic_fetch_add_explicit(&a, 1, mo);
+  static_assert( std::is_same<decltype(r22), long*>::value, "" );
+  auto r23 = atomic_fetch_sub(&v, 1);
+  static_assert( std::is_same<decltype(r23), int*>::value, "" );
+  auto r24 = atomic_fetch_sub(&a, 1);
+  static_assert( std::is_same<decltype(r24), long*>::value, "" );
+  auto r25 = atomic_fetch_sub_explicit(&v, 1, mo);
+  static_assert( std::is_same<decltype(r25), int*>::value, "" );
+  auto r26 = atomic_fetch_sub_explicit(&a, 1, mo);
+  static_assert( std::is_same<decltype(r26), long*>::value, "" );
+}
+
+void
+test04()
+{
+  struct base { };
+  struct derived : base { };
+  // Partial specialization for pointers
+  volatile std::atomic<base*> v;
+  std::atomic<base*> a;
+  const std::memory_order mo = std::memory_order_seq_cst;
+  // Repeat tests with arguments of type different to value_type.
+  derived* const p = nullptr;
+  base* b = nullptr;
+  atomic_init(&v, p);
+  atomic_init(&a, p);
+  atomic_store(&v, p);
+  atomic_store(&a, p);
+  atomic_store_explicit(&v, p, mo);
+  atomic_store_explicit(&a, p, mo);
+  atomic_exchange(&v, p);
+  atomic_exchange(&a, p);
+  atomic_exchange_explicit(&v, p, mo);
+  atomic_exchange_explicit(&a, p, mo);
+  atomic_compare_exchange_weak(&v, &b, p);
+  atomic_compare_exchange_weak(&a, &b, p);
+  atomic_compare_exchange_strong(&v, &b, p);
+  atomic_compare_exchange_strong(&a, &b, p);
+  atomic_compare_exchange_weak_explicit(&v, &b, p, mo, mo);
+  atomic_compare_exchange_weak_explicit(&a, &b, p, mo, mo);
+  atomic_compare_exchange_strong_explicit(&v, &b, p, mo, mo);
+  atomic_compare_exchange_strong_explicit(&a, &b, p, mo, mo);
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc
index e1865b7fb5b..f4668b3e259 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc
@@ -1,4 +1,4 @@
-// { dg-do run { target c++11 } }
+// { dg-do run { target { c++11_only || c++14_only } } }
 // { dg-require-atomic-builtins "" }
 
 // Copyright (C) 2012-2018 Free Software Foundation, Inc.
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/requirements/typedefs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/requirements/typedefs.cc
new file mode 100644
index 00000000000..96d263e8fbf
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/requirements/typedefs.cc
@@ -0,0 +1,36 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+// { dg-require-atomic-builtins "" }
+
+#include <atomic>
+
+template<typename T>
+constexpr bool check()
+{
+  typename std::atomic<T>::value_type* pv = (T*)nullptr;
+  typename std::atomic<T>::difference_type* pd = (std::ptrdiff_t*)nullptr;
+  return true;
+}
+
+static_assert( check<int*>(), "" );
+static_assert( check<void*>(), "" );
+static_assert( check<void(*)()>(), "" );
+struct X { };
+static_assert( check<X*>(), "" );
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc
new file mode 100644
index 00000000000..96a234d620a
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc
@@ -0,0 +1,163 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+// { dg-require-atomic-builtins "" }
+
+#include <atomic>
+
+void
+test01()
+{
+  volatile std::atomic<int> v;
+  std::atomic<long> a;
+  const std::memory_order mo = std::memory_order_seq_cst;
+  int i = 0;
+  long l = 0;
+  auto r1 = atomic_is_lock_free(&v);
+  static_assert( std::is_same<decltype(r1), bool>::value, "" );
+  auto r2 = atomic_is_lock_free(&a);
+  static_assert( std::is_same<decltype(r2), bool>::value, "" );
+  atomic_init(&v, i);
+  atomic_init(&a, l);
+  atomic_store(&v, i);
+  atomic_store(&a, l);
+  atomic_store_explicit(&v, i, mo);
+  atomic_store_explicit(&a, l, mo);
+  auto r3 = atomic_load(&v);
+  static_assert( std::is_same<decltype(r3), int>::value, "" );
+  auto r4 = atomic_load(&a);
+  static_assert( std::is_same<decltype(r4), long>::value, "" );
+  auto r5 = atomic_load_explicit(&v, mo);
+  static_assert( std::is_same<decltype(r5), int>::value, "" );
+  auto r6 = atomic_load_explicit(&a, mo);
+  static_assert( std::is_same<decltype(r6), long>::value, "" );
+  auto r7 = atomic_exchange(&v, i);
+  static_assert( std::is_same<decltype(r7), int>::value, "" );
+  auto r8 = atomic_exchange(&a, l);
+  static_assert( std::is_same<decltype(r8), long>::value, "" );
+  auto r9 = atomic_exchange_explicit(&v, i, mo);
+  static_assert( std::is_same<decltype(r9), int>::value, "" );
+  auto r10 = atomic_exchange_explicit(&a, l, mo);
+  static_assert( std::is_same<decltype(r10), long>::value, "" );
+  auto r11 = atomic_compare_exchange_weak(&v, &i, i);
+  static_assert( std::is_same<decltype(r11), bool>::value, "" );
+  auto r12 = atomic_compare_exchange_weak(&a, &l, l);
+  static_assert( std::is_same<decltype(r12), bool>::value, "" );
+  auto r13 = atomic_compare_exchange_strong(&v, &i, i);
+  static_assert( std::is_same<decltype(r13), bool>::value, "" );
+  auto r14 = atomic_compare_exchange_strong(&a, &l, l);
+  static_assert( std::is_same<decltype(r14), bool>::value, "" );
+  auto r15 = atomic_compare_exchange_weak_explicit(&v, &i, i, mo, mo);
+  static_assert( std::is_same<decltype(r15), bool>::value, "" );
+  auto r16 = atomic_compare_exchange_weak_explicit(&a, &l, l, mo, mo);
+  static_assert( std::is_same<decltype(r16), bool>::value, "" );
+  auto r17 = atomic_compare_exchange_strong_explicit(&v, &i, i, mo, mo);
+  static_assert( std::is_same<decltype(r17), bool>::value, "" );
+  auto r18 = atomic_compare_exchange_strong_explicit(&a, &l, l, mo, mo);
+  static_assert( std::is_same<decltype(r18), bool>::value, "" );
+
+  auto r19 = atomic_fetch_add(&v, i);
+  static_assert( std::is_same<decltype(r19), int>::value, "" );
+  auto r20 = atomic_fetch_add(&a, l);
+  static_assert( std::is_same<decltype(r20), long>::value, "" );
+  auto r21 = atomic_fetch_add_explicit(&v, i, mo);
+  static_assert( std::is_same<decltype(r21), int>::value, "" );
+  auto r22 = atomic_fetch_add_explicit(&a, l, mo);
+  static_assert( std::is_same<decltype(r22), long>::value, "" );
+  auto r23 = atomic_fetch_sub(&v, i);
+  static_assert( std::is_same<decltype(r23), int>::value, "" );
+  auto r24 = atomic_fetch_sub(&a, l);
+  static_assert( std::is_same<decltype(r24), long>::value, "" );
+  auto r25 = atomic_fetch_sub_explicit(&v, i, mo);
+  static_assert( std::is_same<decltype(r25), int>::value, "" );
+  auto r26 = atomic_fetch_sub_explicit(&a, l, mo);
+  static_assert( std::is_same<decltype(r26), long>::value, "" );
+  auto r27 = atomic_fetch_and(&v, i);
+  static_assert( std::is_same<decltype(r27), int>::value, "" );
+  auto r28 = atomic_fetch_and(&a, l);
+  static_assert( std::is_same<decltype(r28), long>::value, "" );
+  auto r29 = atomic_fetch_and_explicit(&v, i, mo);
+  static_assert( std::is_same<decltype(r29), int>::value, "" );
+  auto r30 = atomic_fetch_and_explicit(&a, l, mo);
+  static_assert( std::is_same<decltype(r30), long>::value, "" );
+  auto r31 = atomic_fetch_or(&v, i);
+  static_assert( std::is_same<decltype(r31), int>::value, "" );
+  auto r32 = atomic_fetch_or(&a, l);
+  static_assert( std::is_same<decltype(r32), long>::value, "" );
+  auto r33 = atomic_fetch_or_explicit(&v, i, mo);
+  static_assert( std::is_same<decltype(r33), int>::value, "" );
+  auto r34 = atomic_fetch_or_explicit(&a, l, mo);
+  static_assert( std::is_same<decltype(r34), long>::value, "" );
+  auto r35 = atomic_fetch_xor(&v, i);
+  static_assert( std::is_same<decltype(r35), int>::value, "" );
+  auto r36 = atomic_fetch_xor(&a, l);
+  static_assert( std::is_same<decltype(r36), long>::value, "" );
+  auto r37 = atomic_fetch_xor_explicit(&v, i, mo);
+  static_assert( std::is_same<decltype(r37), int>::value, "" );
+  auto r38 = atomic_fetch_xor_explicit(&a, l, mo);
+  static_assert( std::is_same<decltype(r38), long>::value, "" );
+}
+
+void
+test02()
+{
+  volatile std::atomic<long> v;
+  std::atomic<long> a;
+  std::memory_order mo = std::memory_order_seq_cst;
+  // Repeat tests with arguments of type different to value_type.
+  const int i = 0;
+  long l = 0;
+  atomic_init(&v, i);
+  atomic_init(&a, i);
+  atomic_store(&v, i);
+  atomic_store(&a, i);
+  atomic_store_explicit(&v, i, mo);
+  atomic_store_explicit(&a, i, mo);
+  atomic_exchange(&v, i);
+  atomic_exchange(&a, i);
+  atomic_exchange_explicit(&v, i, mo);
+  atomic_exchange_explicit(&a, i, mo);
+  atomic_compare_exchange_weak(&v, &l, i);
+  atomic_compare_exchange_weak(&a, &l, i);
+  atomic_compare_exchange_strong(&v, &l, i);
+  atomic_compare_exchange_strong(&a, &l, i);
+  atomic_compare_exchange_weak_explicit(&v, &l, i, mo, mo);
+  atomic_compare_exchange_weak_explicit(&a, &l, i, mo, mo);
+  atomic_compare_exchange_strong_explicit(&v, &l, i, mo, mo);
+  atomic_compare_exchange_strong_explicit(&a, &l, i, mo, mo);
+  atomic_fetch_add(&v, i);
+  atomic_fetch_add(&a, i);
+  atomic_fetch_add_explicit(&v, i, mo);
+  atomic_fetch_add_explicit(&a, i, mo);
+  atomic_fetch_sub(&v, i);
+  atomic_fetch_sub(&a, i);
+  atomic_fetch_sub_explicit(&v, i, mo);
+  atomic_fetch_sub_explicit(&a, i, mo);
+  atomic_fetch_and(&v, i);
+  atomic_fetch_and(&a, i);
+  atomic_fetch_and_explicit(&v, i, mo);
+  atomic_fetch_and_explicit(&a, i, mo);
+  atomic_fetch_or(&v, i);
+  atomic_fetch_or(&a, i);
+  atomic_fetch_or_explicit(&v, i, mo);
+  atomic_fetch_or_explicit(&a, i, mo);
+  atomic_fetch_xor(&v, i);
+  atomic_fetch_xor(&a, i);
+  atomic_fetch_xor_explicit(&v, i, mo);
+  atomic_fetch_xor_explicit(&a, i, mo);
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/typedefs.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/typedefs.cc
new file mode 100644
index 00000000000..2cd20844701
--- /dev/null
+++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/typedefs.cc
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+// { dg-require-atomic-builtins "" }
+
+#include <atomic>
+
+template<typename T>
+constexpr bool check()
+{
+  typename std::atomic<T>::value_type* pv = (T*)nullptr;
+  typename std::atomic<T>::difference_type* pd = (T*)nullptr;
+  return true;
+}
+
+static_assert( check<signed short>(), "" );
+static_assert( check<unsigned short>(), "" );
+static_assert( check<signed int>(), "" );
+static_assert( check<unsigned int>(), "" );
+static_assert( check<signed long>(), "" );
+static_assert( check<unsigned long>(), "" );
+static_assert( check<signed long long>(), "" );
+static_assert( check<unsigned long long>(), "" );


More information about the Libstdc++ mailing list