Presumably because std::variant<int,char> is not trivially copy constructible, the ABI will be unable to pass it by value in a register in a call to a non-inlined function taking the variant by value, but will have to pass it by reference. Test case: #include <variant> struct TaggedUnion { union { int i; char c; }; int tag; }; void f1(std::variant<int,char>); void f2(TaggedUnion); int main () { f1(42); f2({42, 0}); return 0; } Result on Linux x86-64: f1 is called passing the argument by address, f2 is called passing by register. See the standard proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0602r0.html however I think this can be fixed in gcc regardless of when/whether the proposal is accepted.
Assign to myself. Implementation idea: https://godbolt.org/g/ulh4V7 The idea is to avoid multiple-layer hierarchy that libc++ uses, while remains easy to extend to fine-grained triviality (one for each of big five). It requires more or less a rewrite of the storage part. It's not hard for now, because we don't have ABI compatibility constraints.
(In reply to Tim Shen from comment #1) > Assign to myself. > > Implementation idea: > https://godbolt.org/g/ulh4V7 The experiment failed, therefore I posted a patch (see the list) to do the 4-layer inheritance (yikes) hierarchy. The experiment idea was to use CRTP (mixin) bases to dispatch on the triviality, e.g. template<typename... _Types> struct variant : _Variant_storage<_Types...>, _Copy_ctor_mixin<(is_trivially_copy_constructible<_Types> && ...), ... Such that: 1) _Variant_storage holds all memory, and is guaranteed to be trivial on all SMFs. 2) Mixins out-live _Variant_storage, and apply rich SMF semantics, if non-trivial; else forward the triviality. The triviality of variant is decided by the triviality of both the storage. However, the storage is always trivial, so the triviality is controlled by mixins, which is intended. The problem is that once storage is trivial, it has trivial behaviors, e.g. memcpy on copy ctor and copy assign. It's hard to get rid of the memcpys without getting rid of the storage triviality.
Hey, Does this idea help: https://godbolt.org/g/3Iqp2c ? The storage is an array of "special" byte classes which have empty constructors/assign when those would be implemented by one of the mixins.
Oh wait sorry, that doesn't solve it (yet), the variant_storage_byte would still have a default copy constructor that copies the byte member.
(In reply to Ambroz Bizjak from comment #4) > Oh wait sorry, that doesn't solve it (yet), the variant_storage_byte would > still have a default copy constructor that copies the byte member. Yeah, your solution seems to move the triviality forwarding down to the individual elements, not in the variant level. However, I'm not sure if it helps on the forwarding itself. You may still need the 4-layer inheritance on each byte.
Author: timshen Date: Tue Jun 27 18:19:03 2017 New Revision: 249706 URL: https://gcc.gnu.org/viewcvs?rev=249706&root=gcc&view=rev Log: PR libstdc++/80187 * include/std/variant (variant::variant, variant::~variant, variant::operator=): Implement triviality forwarding for four special member functions. * testsuite/20_util/variant/compile.cc: Tests. Modified: trunk/libstdc++-v3/ChangeLog trunk/libstdc++-v3/include/std/variant trunk/libstdc++-v3/testsuite/20_util/variant/compile.cc
Tim, can this be closed as fixed in GCC 8.1? Is there more to do?
*** Bug 80165 has been marked as a duplicate of this bug. ***
Fixed in GCC 8.1.