I think all three compilers are wrong.
[dcl.fct.def.default]/3 says:
An explicitly-defaulted function that is not defined as deleted may be declared
constexprorconstevalonly if it would have been implicitly declared asconstexpr. If a function is explicitly defaulted on its first declaration, it is implicitly considered to beconstexprif the implicit declaration would be.
When is the copy assignment operator implicitly declared constexpr? [class.copy.assign]/10:
The implicitly-defined copy/move assignment operator is constexpr if
- X is a literal type, and
- […]
Where a literal type is, from [basic.types]/10:
A type is a literal type if it is:
- […]
a possibly cv-qualified class type that has all of the following properties:
- it has a trivial destructor,
- […]
A1 doesn’t have a trivial destructor, so its implicit copy assignment operator isn’t constexpr. Hence that copy assignment operator is ill-formed (gcc and msvc bug to accept).
The other two are fine, and it’s a clang bug to reject A2.
Note the last bit of [dcl.fct.def.default] that I quoted. You don’t actually have to add constexpr if you’re explicitly defaulting. It would be implicitly constexpr where that is possible.