https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70972

            Bug ID: 70972
           Summary: [6/7 Regression] Inheriting constructors taking
                    parameters by value should move them, not copy
           Product: gcc
           Version: 6.1.0
            Status: UNCONFIRMED
          Keywords: rejects-valid, wrong-code
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: rs2740 at gmail dot com
  Target Milestone: ---

The following code, accepted by GCC 5.3, fails to compile in GCC 6.1 and 7:

struct moveonly {
    moveonly(moveonly&&) = default;
    moveonly() = default;
};

struct A {
    A(moveonly) {}
};
struct B : A {
    using A::A;
};

B b(moveonly{});

with a bogus error:

+ g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp
main.cpp: In constructor 'B::B(moveonly)':
main.cpp:10:14: error: use of deleted function 'constexpr
moveonly::moveonly(const moveonly&)'
     using A::A;
              ^
main.cpp:1:8: note: 'constexpr moveonly::moveonly(const moveonly&)' is
implicitly declared as deleted because 'moveonly' declares a move constructor
or move assignment operator
 struct moveonly {
        ^~~~~~~~
main.cpp: At global scope:
main.cpp:13:15: note: synthesized method 'B::B(moveonly)' first required here 
 B b(moveonly{});

Per N4140 [class.inhctor]/8, an implicitly defined inheriting constructor
should cast a passed-by-value parameter to an rvalue before forwarding it to
the base class constructor:

> Each expression in the expression-list [of the mem-initializer for the base 
> class] is of the form static_cast<T&&>(p), where p is the name of the 
> corresponding constructor parameter and T is the declared type of p.

(The code above remains valid under the new inheriting constructor semantics in
P0136R1.)

However, GCC 6.1 looks for a copy constructor instead, and would call them
instead of move:

struct abort_on_copy{
    abort_on_copy(abort_on_copy&&) = default;
    abort_on_copy(const abort_on_copy&) { __builtin_abort(); }
    abort_on_copy() = default;
};

struct A {
    A(abort_on_copy) {}
};
struct B : A {
    using A::A;
};

int main() {
    B b(abort_on_copy{}); // aborts
}

Reply via email to