long
_M_get_use_count() const noexcept
{
+ // No memory barrier is used here so there is no synchronization
+ // with other threads.
+ auto __count = __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED);
+
// If long is wider than _Atomic_word then we can treat _Atomic_word
// as unsigned, and so double its usable range. If the widths are the
// same then casting to unsigned and then to long is a no-op.
- using _Up = typename make_unsigned<_Atomic_word>::type;
-
- // No memory barrier is used here so there is no synchronization
- // with other threads.
- return (_Up) __atomic_load_n(&_M_use_count, __ATOMIC_RELAXED);
+ return static_cast<_Unsigned_count_type>(__count);
}
private:
_Sp_counted_base(_Sp_counted_base const&) = delete;
_Sp_counted_base& operator=(_Sp_counted_base const&) = delete;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-attributes"
+ // This is only to be used for arithmetic, not for atomic ops.
+ using _Unsigned_count_type = make_unsigned<_Atomic_word>::type;
+#pragma GCC diagnostic pop
+
// Called when incrementing _M_use_count to cause a trap on overflow.
// This should be passed the value of the counter before the increment.
static void
_S_chk(_Atomic_word __count)
{
+ constexpr _Atomic_word __max_atomic_word = _Unsigned_count_type(-1)/2;
+
// __max is the maximum allowed value for the shared reference count.
// All valid reference count values need to fit into [0,LONG_MAX)
// because users can observe the count via shared_ptr::use_count().
// would not fit in [0,LONG_MAX) after casting to an unsigned type,
// which would cause use_count() to return bogus values.
constexpr _Atomic_word __max
- = sizeof(long) > sizeof(_Atomic_word)
- ? -1 : __gnu_cxx::__int_traits<_Atomic_word>::__max;
+ = sizeof(long) > sizeof(_Atomic_word) ? -1 : __max_atomic_word;
if (__count == __max) [[__unlikely__]]
__builtin_trap();
inline long
_Sp_counted_base<_S_single>::_M_get_use_count() const noexcept
{
- using _Up = typename make_unsigned<_Atomic_word>::type;
- return (_Up) _M_use_count;
+ return static_cast<_Unsigned_count_type>(_M_use_count);
}
_Atomic_word_fits_in_long[sizeof(_Atomic_word) <= sizeof(long) ? 1 : -1];
#endif
+ // Targets where _Atomic_word uses __attribute__((__aligned__(n))) will get
+ // a warning for make_unsigned<_Atomic_word>. That warning can be ignored,
+ // because we only need an unsigned type, we don't care about its alignment.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-attributes"
+
+ // We need an unsigned type that can be used for the arithmetic below.
+ // This type must not be use for atomic ops because it might not be
+ // sufficiently aligned. Define it as a macro that we #undef below,
+ // to prevent misuse elsewhere in the library.
+#if __cplusplus >= 201103L
+# define _GLIBCXX_UNSIGNED_ATOMIC_WORD std::make_unsigned<_Atomic_word>::type
+#else
+ // For most targets make_unsigned_t<_Atomic_word> is unsigned int,
+ // but 64-bit sparc uses long for _Atomic_word, so needs unsigned long.
+ // Sign-extending to unsigned long works for both cases, so use that.
+# define _GLIBCXX_UNSIGNED_ATOMIC_WORD unsigned long
+#endif
+
inline _Atomic_word
__attribute__((__always_inline__))
__exchange_and_add_single(_Atomic_word* __mem, int __val)
{
_Atomic_word __result = *__mem;
// Do the addition with an unsigned type so that overflow is well defined.
-#if __cplusplus >= 201103L
- std::make_unsigned<_Atomic_word>::type __u;
-#else
- // For most targets make_unsigned_t<_Atomic_word> is unsigned int,
- // but 64-bit sparc uses long for _Atomic_word.
- // Sign-extending to unsigned long works for both cases.
- unsigned long __u;
-#endif
+ _GLIBCXX_UNSIGNED_ATOMIC_WORD __u;
__u = __result;
__u += __val;
*__mem = __u;
__attribute__((__always_inline__))
__atomic_add_single(_Atomic_word* __mem, int __val)
{
-#if __cplusplus >= 201103L
- std::make_unsigned<_Atomic_word>::type __u;
-#else
- unsigned long __u; // see above
-#endif
+ _GLIBCXX_UNSIGNED_ATOMIC_WORD __u;
__u = *__mem;
__u += __val;
*__mem = __u;
}
+#undef _GLIBCXX_UNSIGNED_ATOMIC_WORD
+#pragma GCC diagnostic pop
inline _Atomic_word
__attribute__ ((__always_inline__))