Bug 81311 - [7 Regression] An std::ref argument calls copy constructor instead of template constructor in C++17 mode
Summary: [7 Regression] An std::ref argument calls copy constructor instead of templat...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.0
: P2 normal
Target Milestone: 8.0
Assignee: Jason Merrill
URL:
Keywords: link-failure, wrong-code
: 80804 (view as bug list)
Depends on:
Blocks:
 
Reported: 2017-07-04 13:39 UTC by Peter Dimov
Modified: 2022-05-13 23:46 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work: 6.4.0, 8.0.1
Known to fail: 7.3.0, 7.5.0
Last reconfirmed: 2018-03-17 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Dimov 2017-07-04 13:39:20 UTC
In the following code:

```
#include <functional>
#include <iostream>

struct function
{
    function()
    {
        std::cout << "function()\n";
    }

    template<class F> function( F )
    {
        std::cout << "function<F>(F)\n";
    }

    function( function const& )
    {
        std::cout << "function(function const&)\n";
    }
};

int main()
{
    function f1;
    function f2( std::ref(f1) );
}
```

g++ 7.1 and 8 with -std=c++1z/17 call the copy constructor, whereas with -std=c++14 they call the template constructor (as do other compilers in all language modes.)
Comment 1 Jonathan Wakely 2017-09-14 14:48:46 UTC
extern "C" int puts(const char*);

struct function
{
    function()
    {
        puts("function()");
    }

    template<class F> function( F )
    {
        puts("function<F>(F)");
    }

    function( function const& )
    {
        puts("function(function const&)");
    }
};

struct ref
{
  ref() = default;

  operator function&() const;
};

int main()
{
    function f2( ref{} );
}

Compiles OK with C++14, printing "function<F>(F)" but fails to link with C++17:

/tmp/ccB3mFFt.o: In function `main':
/tmp/ref.cc:30: undefined reference to `ref::operator function&() const'
collect2: error: ld returned 1 exit status

Presumably caused by the changes for guaranteed elision in C++17.

Interestingly if the conversion operator is defined as deleted then it compiles OK, choosing the function<F>(F) constructor instead.
Comment 2 Jason Merrill 2018-03-22 03:53:51 UTC
Author: jason
Date: Thu Mar 22 03:53:19 2018
New Revision: 258755

URL: https://gcc.gnu.org/viewcvs?rev=258755&root=gcc&view=rev
Log:
	PR c++/81311 - wrong C++17 overload resolution.

	* call.c (build_user_type_conversion_1): Remove C++17 code.
	(conv_binds_ref_to_prvalue): New.
	(build_over_call): Handle C++17 copy elision.
	(build_special_member_call): Only do C++17 copy elision here if the
	argument is already the right type.

Added:
    trunk/gcc/testsuite/g++.dg/overload/conv-op2.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
Comment 3 Alexandre Oliva 2018-03-30 08:51:58 UTC
bug 85101 and bug 85092 started with the patch in comment 2
Comment 4 Richard Biener 2019-11-14 10:00:39 UTC
Fixed in GCC 8.
Comment 5 Andrew Pinski 2021-08-17 07:01:42 UTC
*** Bug 80804 has been marked as a duplicate of this bug. ***
Comment 6 GCC Commits 2022-05-13 23:46:44 UTC
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:62ecd2b8d46aaf96caef5fa78953216629e49ebd

commit r13-460-g62ecd2b8d46aaf96caef5fa78953216629e49ebd
Author: Marek Polacek <polacek@redhat.com>
Date:   Fri May 13 19:45:03 2022 -0400

    c++: Add fixed test [PR81952]
    
    This was fixed by r258755:
    PR c++/81311 - wrong C++17 overload resolution.
    
            PR c++/81952
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/overload/conv-op4.C: New test.