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!

Reply via email to