Bug 100644 - [11/12 regression] Deleted move constructor prevents templated constructor from being used
Summary: [11/12 regression] Deleted move constructor prevents templated constructor fr...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 11.1.0
: P3 normal
Target Milestone: 11.2
Assignee: Jason Merrill
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2021-05-18 00:55 UTC by Botond Ballo
Modified: 2022-07-19 22:23 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work: 10.3.0
Known to fail:
Last reconfirmed: 2021-05-18 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Botond Ballo 2021-05-18 00:55:24 UTC
GCC 11 gives an error for the following code which GCC 10 and Clang accept:


struct NonMovable {
  NonMovable(NonMovable&&) = delete;
};

template <class T>
struct Maybe {
  NonMovable mMember;

  template <typename U>
  Maybe(Maybe<U>&&);
};

void foo(Maybe<int>);

void unlucky(Maybe<int>&& x) {
  Maybe<int> var{(Maybe<int>&&)x};
}


The error is:


main.cpp: In function ‘void unlucky(Maybe<int>&&)’:
main.cpp:16:33: error: use of deleted function ‘Maybe<int>::Maybe(Maybe<int>&&)’
   16 |   Maybe<int> var{(Maybe<int>&&)x};
      |                                 ^
main.cpp:6:8: note: ‘Maybe<int>::Maybe(Maybe<int>&&)’ is implicitly deleted because the default definition would be ill-formed:
    6 | struct Maybe {
      |        ^~~~~
main.cpp:6:8: error: use of deleted function ‘NonMovable::NonMovable(NonMovable&&)’
main.cpp:2:3: note: declared here
    2 |   NonMovable(NonMovable &&) = delete;
      |   ^~~~~~~~~~


I believe the code should be accepted, with the deleted move constructor ignored during overload resolution and the templated constructor used instead.

I explain my reasoning, with links to the standard, in more detail here: https://bugzilla.mozilla.org/show_bug.cgi?id=1710235#c22

Please let me know if I've overlooked something and the code really is invalid.
Comment 1 Jonathan Wakely 2021-05-18 08:54:03 UTC
Rejected since r11-7287

    c++: Tuple of self-dependent classes [PR96926]
    
    When compiling this testcase, trying to resolve the initialization for the
    tuple member ends up recursively considering the same set of tuple
    constructor overloads, and since two of them separately depend on
    is_constructible, the one we try second fails to instantiate
    is_constructible because we're still in the middle of instantiating it the
    first time.
    
    Fixed by implementing an optimization that someone suggested we were already
    doing: if we see a non-template candidate that is a perfect match for all
    arguments, we can skip considering template candidates at all.  It would be
    enough to do this only when LOOKUP_DEFAULTED, but it shouldn't hurt in other
    cases.
    
    gcc/cp/ChangeLog:
    
            PR c++/96926
            * call.c (perfect_conversion_p): New.
            (perfect_candidate_p): New.
            (add_candidates): Ignore templates after a perfect non-template.
Comment 2 GCC Commits 2021-05-18 19:44:25 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:f71ca97def69b8aeb046d716eaea2367736f505e

commit r12-885-gf71ca97def69b8aeb046d716eaea2367736f505e
Author: Jason Merrill <jason@redhat.com>
Date:   Tue May 18 12:06:36 2021 -0400

    c++: "perfect" implicitly deleted move [PR100644]
    
    Here we were ignoring the template constructor because the implicit move
    constructor had all perfect conversions.  But CWG1402 says that an
    implicitly deleted move constructor is ignored by overload resolution; we
    implement that instead by preferring any other candidate in joust, to get
    better diagnostics, but that means we need to handle that case here as well.
    
    gcc/cp/ChangeLog:
    
            PR c++/100644
            * call.c (perfect_candidate_p): An implicitly deleted move
            is not perfect.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/implicit-delete1.C: New test.
Comment 3 GCC Commits 2021-05-18 21:19:22 UTC
The releases/gcc-11 branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:6384e940a6db379b0524465cf6cbbd0996b48485

commit r11-8431-g6384e940a6db379b0524465cf6cbbd0996b48485
Author: Jason Merrill <jason@redhat.com>
Date:   Tue May 18 12:06:36 2021 -0400

    c++: "perfect" implicitly deleted move [PR100644]
    
    Here we were ignoring the template constructor because the implicit move
    constructor had all perfect conversions.  But CWG1402 says that an
    implicitly deleted move constructor is ignored by overload resolution; we
    implement that instead by preferring any other candidate in joust, to get
    better diagnostics, but that means we need to handle that case here as well.
    
    gcc/cp/ChangeLog:
    
            PR c++/100644
            * call.c (perfect_candidate_p): An implicitly deleted move
            is not perfect.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/implicit-delete1.C: New test.
Comment 4 Jason Merrill 2021-05-19 20:19:39 UTC
Fixed for 11.2/12.