diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index b8c0d2e67a37..9af706a6fde4 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -230,25 +230,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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(). @@ -266,8 +274,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 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(); @@ -300,8 +307,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION 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); } diff --git a/libstdc++-v3/include/ext/atomicity.h b/libstdc++-v3/include/ext/atomicity.h index 0b970f33f4b6..14670b5ecd15 100644 --- a/libstdc++-v3/include/ext/atomicity.h +++ b/libstdc++-v3/include/ext/atomicity.h @@ -90,20 +90,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _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; @@ -114,15 +126,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __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__))