Committed: gcc.gnu.org/g:68a1218c189 <http://gcc.gnu.org/g:68a1218c189>
Thanks Jonathan! > On 27 Jan 2026, at 4:14 PM, Jonathan Wakely <[email protected]> wrote: > > External email: Use caution opening links or attachments > > > 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 >> >> >
