diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2024-09-21 10:36:20 +0200 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2025-03-08 19:47:15 +0100 |
commit | 613f8ddbe3d7da63d827e588bf0333813c184b8a (patch) | |
tree | 8d09717835f04d0e8977a7dccd2a50aca5f4fede /libstdc++-v3/testsuite | |
parent | dff059294511b4f42a531d0a91bf185ee1bc7b0a (diff) | |
download | gcc-613f8ddbe3d7da63d827e588bf0333813c184b8a.zip gcc-613f8ddbe3d7da63d827e588bf0333813c184b8a.tar.gz gcc-613f8ddbe3d7da63d827e588bf0333813c184b8a.tar.bz2 |
libstdc++: constrain std::atomic's default constructor
This commit implements the proposed resolution to LWG4169, which is
to constrain std::atomic<T>'s default constructor based on whether
T itself is default constructible.
At the moment, std::atomic<T>'s primary template in libstdc++ has a
defaulted default constructor. Value-initialization of the T member
(since C++20 / P0883R2) is done via a NSDMI (= T()).
GCC already considers the defaulted constructor constrained/deleted,
however this behavior is non-standard (see the discussion in PR116769):
the presence of a NSDMI should not make the constructor unavailable to
overload resolution/deleted ([class.default.ctor]/2.5 does not apply).
When using libstdc++ on Clang, this causes build issues as the
constructor is *not* deleted there -- the interpretation of
[class.default.ctor]/4 seems to match Clang's behavior.
Therefore, although there would be "nothing to do" with GCC+libstdc++,
this commit changes the code as to stop relying on the GCC language
extension. In C++ >= 20 modes, std::atomic's defaulted default
constructor is changed to be a non-defaulted one, with a constraint
added as per LWG4169; value-initialization of the data member is moved
from the NSDMI to the member init list. The new signature matches the
one in the Standard as per [atomics.types.operations]/1.
In pre-C++20 modes, the constructor is left defaulted. This ensures
compatibility with C++11/14/17 behavior. In other words: we are not
backporting P0883R2 to earlier language modes here.
Amend an existing test to check that a std::atomic wrapping a
non-default constructible type is always non-default constructible:
from C++20, because of the constraint; before C++20, because we
are removing the NSDMI, and therefore [class.default.ctor]/2.5
applies.
Add another test that checks that std::atomic is trivially default
constructible in pre-C++20 modes, and it isn't afterwards.
libstdc++-v3/ChangeLog:
* include/bits/version.def (atomic_value_initialization):
Guard the FTM with the language concepts FTM.
* include/bits/version.h: Regenerate.
* include/std/atomic (atomic): When atomic value init is
defined, change the defaulted default constructor to
a non-defaulted one, constraining it as per LWG4169.
Otherwise, keep the existing constructor.
Remove the NSDMI for the _M_i member.
(_GLIBCXX20_INIT): Drop the macro, as it is not needed any more.
* testsuite/29_atomics/atomic/69301.cc: Test that
an atomic wrapping a non-default-constructible type is
always itself non-default-constructible (in all language
modes).
* testsuite/29_atomics/atomic/cons/trivial.cc: New test.
Diffstat (limited to 'libstdc++-v3/testsuite')
-rw-r--r-- | libstdc++-v3/testsuite/29_atomics/atomic/69301.cc | 2 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/29_atomics/atomic/cons/trivial.cc | 41 |
2 files changed, 43 insertions, 0 deletions
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/69301.cc b/libstdc++-v3/testsuite/29_atomics/atomic/69301.cc index da54b0e..72bf4af 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic/69301.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic/69301.cc @@ -29,6 +29,8 @@ struct NonDefaultConstructible template class std::atomic<NonDefaultConstructible>; +static_assert(!std::is_default_constructible<std::atomic<NonDefaultConstructible>>::value); + void test01() { diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/cons/trivial.cc b/libstdc++-v3/testsuite/29_atomics/atomic/cons/trivial.cc new file mode 100644 index 0000000..bb578db --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic/cons/trivial.cc @@ -0,0 +1,41 @@ +// { dg-do compile { target c++11 } } + +#include <atomic> +#include <type_traits> + +// C++20 / P0883R2 makes std::atomic value-initialize, so it's no +// longer going to be trivially default constructible; check that it +// still is in earlier language modes. +// (We are not applying that paper as a DR.) +#if __cpp_lib_atomic_value_initialization +constexpr bool atomic_default_ctor_is_trivial = false; +#else +constexpr bool atomic_default_ctor_is_trivial = true; +#endif + +template<typename T> +using isTDC = std::is_trivially_default_constructible<T>; + +static_assert(isTDC<std::atomic<bool>>::value == atomic_default_ctor_is_trivial); +static_assert(isTDC<std::atomic<char>>::value == atomic_default_ctor_is_trivial); +static_assert(isTDC<std::atomic<unsigned char>>::value == atomic_default_ctor_is_trivial); +static_assert(isTDC<std::atomic<int>>::value == atomic_default_ctor_is_trivial); +static_assert(isTDC<std::atomic<long>>::value == atomic_default_ctor_is_trivial); +static_assert(isTDC<std::atomic<unsigned long long>>::value == atomic_default_ctor_is_trivial); +static_assert(isTDC<std::atomic<int*>>::value == atomic_default_ctor_is_trivial); + +struct DefaultConstructible +{ + int a; + long long b; + char* p; +}; +static_assert(isTDC<std::atomic<DefaultConstructible>>::value == atomic_default_ctor_is_trivial); + +struct NonDefaultConstructible +{ + NonDefaultConstructible(int i) : val(i) { } + int val; +}; +// Not default constructible, therefore not trivially default constructible +static_assert(isTDC<std::atomic<NonDefaultConstructible>>::value == false); |