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.

Reply via email to