aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2024-09-21 10:36:20 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2025-03-08 19:47:15 +0100
commit613f8ddbe3d7da63d827e588bf0333813c184b8a (patch)
tree8d09717835f04d0e8977a7dccd2a50aca5f4fede /libstdc++-v3/testsuite
parentdff059294511b4f42a531d0a91bf185ee1bc7b0a (diff)
downloadgcc-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.cc2
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic/cons/trivial.cc41
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);