Given the type
Tp() = default;
Tp(const Tp&) = default;
Tp(Tp&&) = default;
The following static asserts fail
If the destructor is defaulted (or removed, such that it is implicitly generated), the asserts do not trigger.
I'm not entirely sure this is a bug, but as far as I can determine from the standard, it is. Relevant text (§12.8 [class.copy], paragraph 12):
"A copy/move constructor for class X is trivial if it is not user-provided, its parameter-type-list is equivalent to the parameter-type-list of an implicit declaration, and if
- class X has no virtual functions (10.3) and no virtual base classes (10.1), and
- class X has no non-static data members of volatile-qualified type, and
- the constructor selected to copy/move each direct base class subobject is trivial, and
- for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;
otherwise the copy/move constructor is non-trivial."
No mention that a user defined destructor should make either copy or move constructors non-trivial if they otherwise qualify. Additionally, using the old std::has_trivial_copy_constructor (and the built-in __has_trivial_copy it's based on) does not trigger the assert.
Your non-trivial destructor means that is_trivially_xxx_constructible is false, because that trait is based on an expression that creates and destroys an object.
That's by design, because simply asking whether the type *has* a trivial constructor doesn't actually help, in typical generic code you want to know if a particular operation is trivial.