This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c++/65869] New: Incorrect overload resolution in function return statement


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

            Bug ID: 65869
           Summary: Incorrect overload resolution in function return
                    statement
           Product: gcc
           Version: 4.9.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: botond at mozilla dot com

GCC accepts the following code:


struct Base {};

struct Derived : Base {
    Derived();
    explicit Derived(const Derived&);
    explicit Derived(Derived&&);
    explicit Derived(const Base&);
    Derived(Base&&);
};

Derived foo() {
  Derived result;
  return result;
}

int main() {
  Derived result = foo();
}


I believe this code is invalid. Here's why:

  - [class.copy] p32 specifies that overload resolution
    to select the constructor for the copy in the return
    statement is to be performed in two stages.

  - First, it's performed treating the object to be copied
    ('result' here) as an rvalue.

  - Here, the 'Derived(Base&&)' constructor is selected.
    (The explicit constructors are not candidates in this
    context.)

  - However, p32 says that "if the type of the first
    parameter of the selected constructor is not an rvalue
    reference to the object's type", then overload 
    resolution is performed again, treating the object as 
    an rvalue.

      - Here, the type of the first parameter of the
        selected constructor is 'Base&&'. This is an rvalue
        reference, but it's not "to the object's type"
        ("the object's type" being 'Derived'). Therefore,
        this provision is activated.

  - The second overload resolution fails, because the only
    candidate (again, the explicit constructors are not
    candidates) has an rvalue reference parameter, which
    cannot bind to the lvalue that we're not treating the
    object as being.

A more detailed and better-formatted explanation can be found here [1].

Clang rejects this code, showing the error from the failure
of the second overload resolution:

test.cpp:13:10: error: no matching constructor for initialization of 'Derived'
  return result;
         ^~~~~~
test.cpp:8:5: note: candidate constructor not viable: no known conversion from
'Derived' to 'Base &&' for 1st argument
    Derived(Base&&);
    ^
test.cpp:4:5: note: candidate constructor not viable: requires 0 arguments, but
1 was provided
    Derived();
    ^

[1] http://stackoverflow.com/a/29834426/141719


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]