GCC gives a -Wignored-attributes warning when a class template is
instantiated with a type that has an aligned(n) attribute. Specifically,
cris-elf uses 'typedef int __attribute_((__aligned(4))) _Atomic_word;'
and so compiling libstdc++ headers gives:
warning: ignoring attributes on template argument ‘int’ [-Wignored-attributes]
This commit reduces four occurrences of make_unsigned<_Atomic_word> into
two, one in bits/shared_ptr_base.h and one in ext/atomicity.h, and uses
diagnostic pragmas around the two remaining uses to avoid the warnings.
Because the unsigned type might have lost the alignment of _Atomic_word
that is needed for atomic ops (at least on cris-elf), the unsigned type
should only be used for plain non-atomic arithmetic. To prevent misuse,
it's defined as a private type in _Sp_counted_base, and is defined and
then undefined as a macro in ext/atomicity.h, so that it's not usable
after __exchange_and_add_single and __atomic_add_single have been
defined.
We also get a warning from instantiating __int_traits<_Atomic_word> in
shared_ptr_base.h which can be avoided by calculating the maximum signed
value from the maximum unsigned value.
libstdc++-v3/ChangeLog:
PR libstdc++/122172
* include/bits/shared_ptr_base.h (_Sp_counted_base): Define
_Unsigned_count_type for make_unsigned<_Atomic_word>.
Replace __int_traits<_Atomic_word> with equivalent expression.
* include/ext/atomicity.h (_GLIBCXX_UNSIGNED_ATOMIC_WORD):
Define macro for unsigned type to use for arithmetic.
(__exchange_and_add_single, __atomic_add_single): Use it.
---
Tested x86_64-linux, aarch64-linux, powerpc64le-linux.
libstdc++-v3/include/bits/shared_ptr_base.h | 24 ++++++++------
libstdc++-v3/include/ext/atomicity.h | 36 +++++++++++++--------
2 files changed, 38 insertions(+), 22 deletions(-)
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__))
--
2.51.0