On Sat, 21 Sept 2024 at 10:43, Giuseppe D'Angelo <giuseppe.dang...@kdab.com> wrote: > > Hello, > > The attached patch modifies std::atomic's primary template. The goal is > to improve compatibility with Clang, while also possibly making it more > complaint with the changes introduced by P0883 / C++20. > > Simplifying, std::atomic has a `T t = T()` NDSMI and a defaulted default > constructor. The crux of the problem is that Clang seems to be stricter > than GCC when that constructor is considered / instantiated. > > Given a non-default constructible type NDC, doing something like > > constexpr bool b = std::is_default_constructible_v<std::atomic<NDC>>; > > causes a hard error on Clang because it will "see" the call to `NDC()` > in the NDSMI. The code is instead accepted by GCC. This hard error will > happen anywhere one "mentions" std::atomic<NDC>'s default constructor, > for instance in libstdc++'s C++20 std::pair implementation (uses them in > the explicit(bool) bits). You can play with this here: > > https://gcc.godbolt.org/z/xcr4zK8hx > > PR116769 argues that Clang's behavior is the correct one here, so this > patch improves compat with Clang by removing the defaulted default > constructor.
GCC's behaviour seems much more useful. > A related issue is: what's the value of `b` above? std::atomic's default > constructor is not constrained, so it should be `true`. Right now we're > reporting `false` instead. Good, that's the correct answer :-) I don't understand why anybody would want the NSDMI to be ignored and give the wrong answer, or be instantiated and give a hard error. > Thoughts? Your patch changes the value of is_trivially_default_constructible_v<std::atomic<int>> for C++11/14/17. Currently that is true for <= 17 and true for >= 20. You patch makes it always false. If we did this instead, I think all compilers would handle it correctly and we wouldn't change any behaviour for C++17 down: atomic() = default; #ifdef __cpp_concepts >= 202002 atomic() requires (!std::is_constructible_v<_Tp>) = delete; #endif For C++17 there's no NSDMI and the default constructor does the right thing (getting deleted if T is not default constructible). For C++20 the default constructor is deleted if the NSDMI would be ill-formed, which is consistent with the C++17 behaviour. The triviality of the constructor is unchanged.