]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix warnings from std::make_unsigned<_Atomic_word> [PR122172]
authorJonathan Wakely <jwakely@redhat.com>
Mon, 6 Oct 2025 14:51:28 +0000 (15:51 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 10 Oct 2025 23:09:19 +0000 (00:09 +0100)
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.

Reviewed-by: Hans-Peter Nilsson <hp@axis.com>
libstdc++-v3/include/bits/shared_ptr_base.h
libstdc++-v3/include/ext/atomicity.h

index b8c0d2e67a370a87f642874a9c66f4320127dfe9..9af706a6fde45819815dcdd7e81cfae75eacd9d4 100644 (file)
@@ -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);
     }
 
 
index 0b970f33f4b68fea0fe289c9d880c80a07303efd..14670b5ecd159249b60519b29f684fbe81357e3a 100644 (file)
@@ -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__))