https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93975
Bug ID: 93975 Summary: Wrong constexpr copy/move assignment operator allowed on non-literal type Product: gcc Version: 9.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: david.alvarez at bsc dot es Target Milestone: --- Created attachment 47932 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47932&action=edit Reproducer Hi, Note: I sent #93973 with the same title by mistake, sorry. I am attaching file "bug.cc", that contains a testcase for the issue I'm describing. GCC compiles the code correctly, but it _should not_ under -std=c++17 and beyond. Clang-9 correctly detects the error and displays: $ clang++ -std=c++17 -c bug.cc bug.cc:9:3: error: defaulted definition of copy assignment operator is not constexpr constexpr Test& operator=(const Test &) = default; ^ 1 error generated. The issue is that the constexpr operator= is illegal in that context, and it is not detected by GCC correctly. GCC 5.3 outputted the following error: <source>:11:19: error: explicitly defaulted function 'constexpr Test& Test::operator=(const Test&)' cannot be declared as constexpr because the implicit declaration is not constexpr: constexpr Test& operator=(const Test &) = default; ^ Which is correct. In the C++ 2017 standard, section 15.8.2 paragraph 10, it says: A copy/move assignment operator for a class X that is defaulted and not defined as deleted is implicitly defined when it is odr-used (6.2) (e.g., when it is selected by overload resolution to assign to an object of its class type) or when it is explicitly defaulted after its first declaration. The implicitly-defined copy/move assignment operator is constexpr if (10.1) — X is a literal type, and (10.2) — the assignment operator selected to copy/move each direct base class subobject is a constexpr function, and (10.3) — for each non-static data member of X that is of class type (or array thereof), the assignment operator selected to copy/move that member is a constexpr function. The class Test in the example is not a literal type (and can be checked through std::is_literal_type<Test>) because it has no constexpr constructors. GCC detects the non-literality correctly, but fails to then mark the implicit copy/move assginment operator as non-constexpr. The issue was introduced in GCC 5.4 by patch: r236405 (git id 7c7bf2f86e5b9de752530a778909c11a596ed40a), which implemented support for constexpr copy/move constructors but did not check for the restrictions defined in the standard (but it does include a comment there as well with all the conditions to check...). Thanks!