https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87057
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> --- (In reply to Konstantin Kharlamov from comment #0) > When, in a code, a copy-constructor deleted but used, GCC issues an > absolutely unhelpful message that it couldn't convert the argument. "Why > can't it?". It's extremely difficult to diagnose — e.g. in my case I had to > go down from a project code to the minimal example below before I could > figure it out. There's really no other way, except as of magically guessing > that some of fields used in the struct being copied has its copy-constructor > deleted. > > FTR: to fix the code below you need to replace `return {ret}` with `return > {move(ret)}`. > > # Steps to reproduce: > > $ cat test.cpp > #include <memory> > #include <variant> > > struct PacketErr { > std::unique_ptr<char> failed_devices; > }; > > std::variant<std::monostate, PacketErr> deserialize(){ > PacketErr ret; > return {ret}; > } > > int main() {} > $ g++ test.cpp -std=c++17 > test.cpp: In function ‘std::variant<std::monostate, PacketErr> > deserialize()’: > test.cpp:10:16: error: could not convert ‘{ret}’ from ‘<brace-enclosed > initializer list>’ to ‘std::variant<std::monostate, PacketErr>’ > return {ret}; > > # Expected > > GCC should mention that a copy is not possible since there's a > copy-constructor deleted. I don't think that's really plausible. If fails because you cannot construct the variant type from a PacketErr lvalue, because it fails the SFINAE constraints. For the compiler to tell you why it fails them it would have to analyse those constraints and tell you that __is_accepted_index returns variant_npos, because none of the alternatives can be constructed from PacketErr&. It would then have to look at each alternative and see why each one fails, and then whether that is worth reporting to the user. So it would have to try to convert PacketErr& to monostate, and decide if any of the reasons for failure was useful to report. Then it would have to try to convert PacketErr& to PacketErr, and see if any of the reasons for failure was useful to report. That would require a lot of special-casing just for std::variant. Clang does print a lot more info, including this: /home/jwakely/gcc/latest/lib/gcc/x86_64-pc-linux-gnu/9.0.0/../../../../include/c++/9.0.0/variant:1093:2: note: candidate template ignored: substitution failure [with _Tp = PacketErr &, $1 = void, $2 = void]: implicit instantiation of undefined template 'std::variant<std::monostate, PacketErr>::__to_type_impl<18446744073709551615, false>' variant(_Tp&& __t) ^ But that still doesn't come close to telling you that the type is not copyable. N.B. If you just write "return ret;" it will compile fine. In general "return x;" is better than "return {x};" because it doesn't prevent NRVO.