Example code as below or on godbolt. clang 16/trunk believes S<int>
is not a trivially_copyable
class. clang 15, gcc trunk and MSVC believe otherwise.
#include <type_traits>
template<typename T>
struct S {
T m_t;
S(S const&) = default;
S(S&&) = default;
S& operator=(S const&) requires (!std::is_integral<T>::value) = default;
~S() = default;
};
// next five assertions pass for all compilers
static_assert(std::is_trivially_destructible<S<int>>::value);
static_assert(std::is_trivially_copy_constructible<S<int>>::value);
static_assert(std::is_trivially_move_constructible<S<int>>::value);
static_assert(!std::is_copy_assignable<S<int>>::value);
static_assert(!std::is_move_assignable<S<int>>::value);
// compiles with gcc trunk, MSVC and clang 15, fails with clang 16/trunk
static_assert(std::is_trivially_copyable<S<int>>::value);
According to the standard class.prop:
A trivially copyable class is a class:
that has at least one eligible copy constructor, move constructor, copy assignment operator, or move assignment operator ([special],
[class.copy.ctor], [class.copy.assign]),where each eligible copy constructor, move constructor, copy assignment operator, and move assignment operator is trivial, and
that has a trivial, non-deleted destructor ([class.dtor]).
S<int>
has trivial copy/move constructor and trivial destructor. Its copy/move assignment operators are not eligible. I would agree with gcc/MSVC/clang15 on this. Is clang 16/trunk wrong on this one or am I missing something?
Edit: This is a confirmed clang bug.