On Mon, 19 Jan 2026 at 14:31, Soumya AR <[email protected]> wrote:
>
> Hi Jonathan,
>
> I removed the changes from stdatomic.h.
> Putting an updated patch up.
> Should be OK to commit without the builtins for now?

Yes, this libstdc++ patch is OK for trunk now, thanks.


>
>
> > On 16 Jan 2026, at 6:51 PM, Jonathan Wakely <[email protected]> wrote:
> >
> > External email: Use caution opening links or attachments
> >
> >
> > On Fri, 16 Jan 2026 at 08:28, Soumya AR <[email protected]> wrote:
> >>>> +// 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.
> >>>> +
> >>>> +// Under Section 7 of GPL version 3, you are granted additional
> >>>> +// permissions described in the GCC Runtime Library Exception, version
> >>>> +// 3.1, as published by the Free Software Foundation.
> >>>> +
> >>>> +// You should have received a copy of the GNU General Public License and
> >>>> +// a copy of the GCC Runtime Library Exception along with this program;
> >>>> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> >>>> +// <http://www.gnu.org/licenses/>.
> >>>> +
> >>>> +// { dg-do run { target c++26 } }
> >>>
> >>> Do these new tests need { dg-add-options libatomic } ? I think they
> >>> probably do.
> >>>
> >>> What about { dg-require-atomic-cmpxchg-word "" } ?
> >>
> >> Yes, you're right, ideally should have both directives.
> >>
> >> However, on re-working this patch, I don't think these tests are needed in
> >> libstdc++ at all. I already have correctness tests for the builtins in the
> >> GCC testsuite.
> >>
> >> To test the API, I've created a C++26 version of nonmembers.cc for 
> >> fetch_min/max.
> >> And another fetch_min/max version for the correctness tests for atomic_ref.
> >
> > I missed this part, sorry.
> >
> > I think the new tests make sense in libstdc++. The builtins might be
> > thouroughly tested in the compiler tests, but having library tests
> > ensures we don't make a silly mistake like calling __atomic_fetch_min
> > from the fetch_max function (an easy copy*paste error to make when
> > refactoring).
> >
> > The tests in the new patch are adequate for that purpose: each
> > function is called at least once and the expected result is verified.
> >
> >> Or for both of these, should we just update the existing tests to C++26?
> >
> > I think it's better to have separate tests for the new members,
> > because the existing tests are typically only run for the default -std
> > mode (currently gnu++20) and so would not test any parts of the file
> > guarded by #if __cpp_lib_atomic_min_max. Having a separate test with {
> > target c++26 } means that everybody who runs the testsuite will run
> > that test.
> >
> > And we don't want to add { target c++26 } to the existing tests,
> > because then we would not test that the C++11 features still work in
> > C++11.
> >
>
> Oh right, that makes more sense. I was not sure why we don't add
> { target c++26 } to the existing tests earlier. Thanks for answering
> this.
>
> >> What about c_compat.cc?
> >
> > No changes to that file, because there should be no changes to <stdatomic.h>
> >
> >
> >>
> >> Thanks,
> >> Soumya
> >>
> >>>> +#include <atomic>
> >>>> +#include <limits>
> >>>> +#include <testsuite_hooks.h>
> >>>> +
> >>>> +template<typename T>
> >>>> +void test_signed()
> >>>> +{
> >>>> +  std::atomic<T> a;
> >>>> +  const std::memory_order mo = std::memory_order_relaxed;
> >>>> +  T expected = 0;
> >>>> +  T value = 0;
> >>>> +
> >>>> +  a.store(100);
> >>>> +  value = a.fetch_min(50);
> >>>> +  VERIFY( value == 100 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  value = a.fetch_min(75, mo);
> >>>> +  VERIFY( value == 50 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  value = a.fetch_min(25);
> >>>> +  VERIFY( value == 50 );
> >>>> +  VERIFY( a.load() == 25 );
> >>>> +
> >>>> +  a.store(-10);
> >>>> +  value = a.fetch_min(-20);
> >>>> +  VERIFY( value == -10 );
> >>>> +  VERIFY( a.load() == -20 );
> >>>> +
> >>>> +  value = a.fetch_min(-5, mo);
> >>>> +  VERIFY( value == -20 );
> >>>> +  VERIFY( a.load() == -20 );
> >>>> +
> >>>> +  a.store(10);
> >>>> +  value = a.fetch_min(-5);
> >>>> +  VERIFY( value == 10 );
> >>>> +  VERIFY( a.load() == -5 );
> >>>> +
> >>>> +  a.store(20);
> >>>> +  value = a.fetch_max(50);
> >>>> +  VERIFY( value == 20 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  value = a.fetch_max(30, mo);
> >>>> +  VERIFY( value == 50 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  value = a.fetch_max(100);
> >>>> +  VERIFY( value == 50 );
> >>>> +  VERIFY( a.load() == 100 );
> >>>> +
> >>>> +  a.store(-50);
> >>>> +  value = a.fetch_max(-20);
> >>>> +  VERIFY( value == -50 );
> >>>> +  VERIFY( a.load() == -20 );
> >>>> +
> >>>> +  value = a.fetch_max(-10, mo);
> >>>> +  VERIFY( value == -20 );
> >>>> +  VERIFY( a.load() == -10 );
> >>>> +
> >>>> +  a.store(-10);
> >>>> +  value = a.fetch_max(5);
> >>>> +  VERIFY( value == -10 );
> >>>> +  VERIFY( a.load() == 5 );
> >>>> +
> >>>> +  T min_val = std::numeric_limits<T>::min();
> >>>> +  T max_val = std::numeric_limits<T>::max();
> >>>> +
> >>>> +  a.store(0);
> >>>> +  value = a.fetch_min(min_val);
> >>>> +  VERIFY( value == 0 );
> >>>> +  VERIFY( a.load() == min_val );
> >>>> +
> >>>> +  a.store(0);
> >>>> +  value = a.fetch_max(max_val);
> >>>> +  VERIFY( value == 0 );
> >>>> +  VERIFY( a.load() == max_val );
> >>>> +}
> >>>> +
> >>>> +template<typename T>
> >>>> +void test_unsigned()
> >>>> +{
> >>>> +  std::atomic<T> a;
> >>>> +  const std::memory_order mo = std::memory_order_relaxed;
> >>>> +  T expected = 0;
> >>>> +  T value = 0;
> >>>> +
> >>>> +  a.store(100);
> >>>> +  value = a.fetch_min(50);
> >>>> +  VERIFY( value == 100 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  value = a.fetch_min(75, mo);
> >>>> +  VERIFY( value == 50 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  value = a.fetch_min(25);
> >>>> +  VERIFY( value == 50 );
> >>>> +  VERIFY( a.load() == 25 );
> >>>> +
> >>>> +  a.store(20);
> >>>> +  value = a.fetch_max(50);
> >>>> +  VERIFY( value == 20 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  value = a.fetch_max(30, mo);
> >>>> +  VERIFY( value == 50 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  value = a.fetch_max(100);
> >>>> +  VERIFY( value == 50 );
> >>>> +  VERIFY( a.load() == 100 );
> >>>> +
> >>>> +  T min_val = std::numeric_limits<T>::min();
> >>>> +  T max_val = std::numeric_limits<T>::max();
> >>>> +
> >>>> +  a.store(10);
> >>>> +  value = a.fetch_min(min_val);
> >>>> +  VERIFY( value == 10 );
> >>>> +  VERIFY( a.load() == min_val );
> >>>> +
> >>>> +  a.store(10);
> >>>> +  value = a.fetch_max(max_val);
> >>>> +  VERIFY( value == 10 );
> >>>> +  VERIFY( a.load() == max_val );
> >>>> +}
> >>>> +
> >>>> +int main()
> >>>> +{
> >>>> +  test_signed<signed char>();
> >>>> +  test_signed<short>();
> >>>> +  test_signed<int>();
> >>>> +  test_signed<long>();
> >>>> +  test_signed<long long>();
> >>>> +
> >>>> +  test_unsigned<unsigned char>();
> >>>> +  test_unsigned<unsigned short>();
> >>>> +  test_unsigned<unsigned int>();
> >>>> +  test_unsigned<unsigned long>();
> >>>> +  test_unsigned<unsigned long long>();
> >>>> +
> >>>> +  return 0;
> >>>> +}
> >>>> \ No newline at end of file
> >>>> diff --git 
> >>>> a/libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax_order.cc
> >>>>  
> >>>> b/libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax_order.cc
> >>>> new file mode 100644
> >>>> index 00000000000..3ed6f2e2e6f
> >>>> --- /dev/null
> >>>> +++ 
> >>>> b/libstdc++-v3/testsuite/29_atomics/atomic_integral/fetch_minmax_order.cc
> >>>> @@ -0,0 +1,116 @@
> >>>> +// Copyright The GNU Toolchain Authors.
> >>>> +//
> >>>> +// 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.
> >>>> +
> >>>> +// Under Section 7 of GPL version 3, you are granted additional
> >>>> +// permissions described in the GCC Runtime Library Exception, version
> >>>> +// 3.1, as published by the Free Software Foundation.
> >>>> +
> >>>> +// You should have received a copy of the GNU General Public License and
> >>>> +// a copy of the GCC Runtime Library Exception along with this program;
> >>>> +// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> >>>> +// <http://www.gnu.org/licenses/>.
> >>>> +
> >>>> +// { dg-do run { target c++26 } }
> >>>> +
> >>>> +#include <atomic>
> >>>> +#include <testsuite_hooks.h>
> >>>> +
> >>>> +void test_memory_orderings()
> >>>> +{
> >>>> +  std::atomic<int> a;
> >>>> +  int v;
> >>>> +
> >>>> +  a.store(100);
> >>>> +  v = a.fetch_min(50, std::memory_order_relaxed);
> >>>> +  VERIFY( v == 100 );
> >>>> +  VERIFY( a.load(std::memory_order_relaxed) == 50 );
> >>>> +
> >>>> +  a.store(100);
> >>>> +  v = a.fetch_min(50, std::memory_order_consume);
> >>>> +  VERIFY( v == 100 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  a.store(100);
> >>>> +  v = a.fetch_min(50, std::memory_order_acquire);
> >>>> +  VERIFY( v == 100 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  a.store(100);
> >>>> +  v = a.fetch_min(50, std::memory_order_release);
> >>>> +  VERIFY( v == 100 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  a.store(100);
> >>>> +  v = a.fetch_min(50, std::memory_order_acq_rel);
> >>>> +  VERIFY( v == 100 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  a.store(100);
> >>>> +  v = a.fetch_min(50, std::memory_order_seq_cst);
> >>>> +  VERIFY( v == 100 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  a.store(20);
> >>>> +  v = a.fetch_max(50, std::memory_order_relaxed);
> >>>> +  VERIFY( v == 20 );
> >>>> +  VERIFY( a.load(std::memory_order_relaxed) == 50 );
> >>>> +
> >>>> +  a.store(20);
> >>>> +  v = a.fetch_max(50, std::memory_order_consume);
> >>>> +  VERIFY( v == 20 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  a.store(20);
> >>>> +  v = a.fetch_max(50, std::memory_order_acquire);
> >>>> +  VERIFY( v == 20 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  a.store(20);
> >>>> +  v = a.fetch_max(50, std::memory_order_release);
> >>>> +  VERIFY( v == 20 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  a.store(20);
> >>>> +  v = a.fetch_max(50, std::memory_order_acq_rel);
> >>>> +  VERIFY( v == 20 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +
> >>>> +  a.store(20);
> >>>> +  v = a.fetch_max(50, std::memory_order_seq_cst);
> >>>> +  VERIFY( v == 20 );
> >>>> +  VERIFY( a.load() == 50 );
> >>>> +}
> >>>> +
> >>>> +// Test volatile atomic operations
> >>>> +void test_volatile()
> >>>> +{
> >>>> +  volatile std::atomic<int> va;
> >>>> +  int v;
> >>>> +
> >>>> +  va.store(100);
> >>>> +  v = va.fetch_min(50);
> >>>> +  VERIFY( v == 100 );
> >>>> +  VERIFY( va.load() == 50 );
> >>>> +
> >>>> +  va.store(20);
> >>>> +  v = va.fetch_max(50, std::memory_order_relaxed);
> >>>> +  VERIFY( v == 20 );
> >>>> +  VERIFY( va.load() == 50 );
> >>>> +}
> >>>> +
> >>>> +int main()
> >>>> +{
> >>>> +  test_memory_orderings();
> >>>> +  test_volatile();
> >>>> +  return 0;
> >>>> +}
> >>>> \ No newline at end of file
> >>>> diff --git 
> >>>> a/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc 
> >>>> b/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc
> >>>> index a07d9700ff4..3fb86db65b1 100644
> >>>> --- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc
> >>>> +++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/nonmembers.cc
> >>>> @@ -111,6 +111,22 @@ test01()
> >>>> 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, "" );
> >>>> +  auto r39 = atomic_fetch_min(&v, i);
> >>>> +  static_assert( std::is_same<decltype(r39), int>::value, "" );
> >>>> +  auto r40 = atomic_fetch_min(&a, l);
> >>>> +  static_assert( std::is_same<decltype(r40), long>::value, "" );
> >>>> +  auto r41 = atomic_fetch_min_explicit(&v, i, mo);
> >>>> +  static_assert( std::is_same<decltype(r41), int>::value, "" );
> >>>> +  auto r42 = atomic_fetch_min_explicit(&a, l, mo);
> >>>> +  static_assert( std::is_same<decltype(r42), long>::value, "" );
> >>>> +  auto r43 = atomic_fetch_max(&v, i);
> >>>> +  static_assert( std::is_same<decltype(r43), int>::value, "" );
> >>>> +  auto r44 = atomic_fetch_max(&a, l);
> >>>> +  static_assert( std::is_same<decltype(r44), long>::value, "" );
> >>>> +  auto r45 = atomic_fetch_max_explicit(&v, i, mo);
> >>>> +  static_assert( std::is_same<decltype(r45), int>::value, "" );
> >>>> +  auto r46 = atomic_fetch_max_explicit(&a, l, mo);
> >>>> +  static_assert( std::is_same<decltype(r46), long>::value, "" );
> >>>> }
> >>>>
> >>>> void
> >>>> @@ -160,4 +176,12 @@ test02()
> >>>> atomic_fetch_xor(&a, i);
> >>>> atomic_fetch_xor_explicit(&v, i, mo);
> >>>> atomic_fetch_xor_explicit(&a, i, mo);
> >>>> +  atomic_fetch_min(&v, i);
> >>>> +  atomic_fetch_min(&a, i);
> >>>> +  atomic_fetch_min_explicit(&v, i, mo);
> >>>> +  atomic_fetch_min_explicit(&a, i, mo);
> >>>> +  atomic_fetch_max(&v, i);
> >>>> +  atomic_fetch_max(&a, i);
> >>>> +  atomic_fetch_max_explicit(&v, i, mo);
> >>>> +  atomic_fetch_max_explicit(&a, i, mo);
> >>>> }
> >>>> diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc 
> >>>> b/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
> >>>> index 310434cefb5..5a282320bd7 100644
> >>>> --- a/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
> >>>> +++ b/libstdc++-v3/testsuite/29_atomics/atomic_ref/integral.cc
> >>>> @@ -155,9 +155,38 @@ test01()
> >>>>   v = a ^= 0x121;
> >>>>   VERIFY( v == 0x022 );
> >>>>   VERIFY( a == 0x022 );
> >>>> +
> >>>> +
> >>>> +    a = 100;
> >>>> +    v = a.fetch_min(50);
> >>>> +    VERIFY( v == 100 );
> >>>> +    VERIFY( a == 50 );
> >>>> +
> >>>> +    v = a.fetch_min(75, mo);
> >>>> +    VERIFY( v == 50 );
> >>>> +    VERIFY( a == 50 );
> >>>> +
> >>>> +    a = -10;
> >>>> +    v = a.fetch_min(-20);
> >>>> +    VERIFY( v == -10 );
> >>>> +    VERIFY( a == -20 );
> >>>> +
> >>>> +    a = 20;
> >>>> +    v = a.fetch_max(50);
> >>>> +    VERIFY( v == 20 );
> >>>> +    VERIFY( a == 50 );
> >>>> +
> >>>> +    v = a.fetch_max(30, mo);
> >>>> +    VERIFY( v == 50 );
> >>>> +    VERIFY( a == 50 );
> >>>> +
> >>>> +    a = -50;
> >>>> +    v = a.fetch_max(-20);
> >>>> +    VERIFY( v == -50 );
> >>>> +    VERIFY( a == -20 );
> >>>> }
> >>>>
> >>>> -  VERIFY( value == 0x022 );
> >>>> +  VERIFY( value == -20 );
> >>>> }
> >>>>
> >>>> void
> >>>> @@ -292,9 +321,27 @@ test02()
> >>>>   v = a ^= 0x12;
> >>>>   VERIFY( v == 0x24 );
> >>>>   VERIFY( a == 0x24 );
> >>>> +
> >>>> +    a = 100;
> >>>> +    v = a.fetch_min(50);
> >>>> +    VERIFY( v == 100 );
> >>>> +    VERIFY( a == 50 );
> >>>> +
> >>>> +    v = a.fetch_min(75, mo);
> >>>> +    VERIFY( v == 50 );
> >>>> +    VERIFY( a == 50 );
> >>>> +
> >>>> +    a = 20;
> >>>> +    v = a.fetch_max(50);
> >>>> +    VERIFY( v == 20 );
> >>>> +    VERIFY( a == 50 );
> >>>> +
> >>>> +    v = a.fetch_max(30, mo);
> >>>> +    VERIFY( v == 50 );
> >>>> +    VERIFY( a == 50 );
> >>>> }
> >>>>
> >>>> -  VERIFY( value == 0x24 );
> >>>> +  VERIFY( value == 50 );
> >>>> }
> >>>> void
> >>>> test03()
> >>>> diff --git 
> >>>> a/libstdc++-v3/testsuite/29_atomics/headers/stdatomic.h/c_compat.cc 
> >>>> b/libstdc++-v3/testsuite/29_atomics/headers/stdatomic.h/c_compat.cc
> >>>> index bcdb969b0c0..2e4c73c456c 100644
> >>>> --- a/libstdc++-v3/testsuite/29_atomics/headers/stdatomic.h/c_compat.cc
> >>>> +++ b/libstdc++-v3/testsuite/29_atomics/headers/stdatomic.h/c_compat.cc
> >>>> @@ -131,6 +131,10 @@ static_assert( requires (::atomic_int* i, int* e) {
> >>>> ::atomic_fetch_or_explicit(i, 1, memory_order_relaxed);
> >>>> ::atomic_fetch_xor(i, 1);
> >>>> ::atomic_fetch_xor_explicit(i, 1, memory_order_relaxed);
> >>>> +  ::atomic_fetch_min(i, 1);
> >>>> +  ::atomic_fetch_min_explicit(i, 1, memory_order_relaxed);
> >>>> +  ::atomic_fetch_max(i, 1);
> >>>> +  ::atomic_fetch_max_explicit(i, 1, memory_order_relaxed);
> >>>> } );
> >>>>
> >>>> static_assert( requires (::atomic_flag* f) {
> >>>> --
> >>>> 2.44.0
>
>

Reply via email to