http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58162
Bug ID: 58162 Summary: [C++11] bogus error: use of deleted function 'constexpr A::A(const A&)' Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: ppluzhnikov at google dot com Google ref b/10272620 /// --- cut --- struct A { A(); A(A&&); }; struct B { A const a = A(); }; B b; /// --- cut --- Using trunk: g++ (GCC) 4.9.0 20130814 (experimental) g++ -c -std=c++11 t.cc t.cc: In constructor ‘constexpr B::B()’: t.cc:6:8: error: use of deleted function ‘constexpr A::A(const A&)’ struct B { ^ t.cc:1:8: note: ‘constexpr A::A(const A&)’ is implicitly declared as deleted because ‘A’ declares a move constructor or move assignment operator struct A { ^ t.cc: At global scope: t.cc:10:3: note: synthesized method ‘constexpr B::B()’ first required here B b; ^ Analysys by jdennett This is under 8.5p17 (via other sections... 9.2[Class Members]p4 leads to 12.6.2, and 12.6.2p8 says "if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in 8.5"), and (I believe) should be the same initialization as for a local variable declared as A const a = A(); (All references above are in the C++14 CD.) 8.5p17 says: "If the destination type is a (possibly cv-qualified) class type: — If the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered." We're in the case of copy-initialization where the cv-unqualified version of the source type is A, and the destination type is "const A", but arguably "the class of the destination" is A (because const A isn't a class). So I believe that this should fall into the same case as direct-initialization, overload resolution should pick the A::A(A&&) move constructor, and all should be good. Wild guesses about how this might go wrong in the compiler: It might be that G++ is checking whether the cv-unqualified version of the source type is the same as the destination type (rather than the same as the cv-unqualified version of the destination type, which is the class here). If so, it would fall into the main case of copy-initialization, which creates a temporary of the target type. That should still work, but if the temporary were (incorrectly) considered to be a "const A" rather than an "A" then initializing from it would attempt to use the (deleted) copy constructor. Seeing if changing A(A&&) to A(A const&&) changes anything might be informative, or having both overloads present. Changing 'A(A&&);' to 'A(const AA&&);' or adding it as overload does fix the compilation problem. Further patch from jdennett: With the following hack, the testcase compiles. $ svn diff gcc Index: gcc/cp/parser.c =================================================================== --- gcc/cp/parser.c (revision 201651) +++ gcc/cp/parser.c (working copy) @@ -23002,7 +23002,10 @@ if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg) && CONSTRUCTOR_IS_DIRECT_INIT (parsed_arg)) flags = LOOKUP_NORMAL; - parsed_arg = digest_init_flags (TREE_TYPE (decl), parsed_arg, flags); + // TODO(jdennett): Something better than this, and work out how + // to test it. + parsed_arg = digest_init_flags (TYPE_MAIN_VARIANT (TREE_TYPE (decl)), + parsed_arg, flags); } }