Trivial copy assignment operator not considered such GCC stops considering a trivial copy assignment operator to be trivial when a non-trivial copy assignment operator is added to the class. Works with Clang; fails with GCC. ### SOURCE (<stdin>): struct Q { Q &operator=(const Q &) = default; // defaulted on first declaration, not user-provided; trivial Q &operator=(Q &); // not a viable candidate at P1 }; static_assert(__is_trivially_assignable(Q &, const Q &), ""); // (P1) // Assertion succeeds with Clang and ICC, but fails with GCC. ### COMPILER INVOCATION: g++ -xc++ -std=c++2a -fsyntax-only - ### ACTUAL OUTPUT: <stdin>:8:15: error: static assertion failed ### EXPECTED OUTPUT: (Clean compile) ### COMPILER VERSION INFO (g++ -v): Using built-in specs. COLLECT_GCC=/opt/wandbox/gcc-head/bin/g++ COLLECT_LTO_WRAPPER=/opt/wandbox/gcc-head/libexec/gcc/x86_64-pc-linux-gnu/8.0.1/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../source/configure --prefix=/opt/wandbox/gcc-head --enable-languages=c,c++ --disable-multilib --without-ppl --without-cloog-ppl --enable-checking=release --disable-nls --enable-lto LDFLAGS=-Wl,-rpath,/opt/wandbox/gcc-head/lib,-rpath,/opt/wandbox/gcc-head/lib64,-rpath,/opt/wandbox/gcc-head/lib32 Thread model: posix gcc version 8.0.1 20180405 (experimental) (GCC)
This should probably compile too: struct S { S &operator=(const S &) & = default; // trivial S &operator=(const S &) && { return *this; } // non-trivial }; struct R { S foo; }; static_assert(__is_trivially_assignable (S &, const S &)); static_assert(__is_trivially_assignable (R &, const R &));
This breaks std::tuple<> due to new assignment operators in C++23: https://godbolt.org/z/9EdPrdjhW #include <type_traits> template <class...> struct tuple; template <> struct tuple<> { tuple() = default; ~tuple() = default; tuple(const tuple&) = default; tuple(tuple&&) = default; tuple& operator=(const tuple&) = default; tuple& operator=(tuple&&) = default; constexpr const tuple& operator=(const tuple&) const noexcept { return *this; } constexpr const tuple& operator=(tuple&&) const noexcept { return *this; } }; static_assert(std::is_trivially_destructible_v<tuple<>>); static_assert(std::is_trivially_default_constructible_v<tuple<>>); static_assert(std::is_trivially_copy_constructible_v<tuple<>>); static_assert(std::is_trivially_move_constructible_v<tuple<>>); static_assert(std::is_trivially_copy_assignable_v<tuple<>>); static_assert(std::is_trivially_move_assignable_v<tuple<>>); static_assert(!std::is_trivially_copyable_v<tuple<>>); <source>:23:20: error: static assertion failed 23 | static_assert(std::is_trivially_copy_assignable_v<tuple<>>); | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <source>:24:20: error: static assertion failed 24 | static_assert(std::is_trivially_move_assignable_v<tuple<>>); | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Compiler returned: 1