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

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
     Ever confirmed|0                           |1
             Status|UNCONFIRMED                 |NEW
           Keywords|                            |diagnostic
   Last reconfirmed|                            |2024-02-26

--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Frank Heckenbach from comment #0)
> The actual problem here is that the move-constructor was deleted because a

No, the move constructor is simply *not declared*. If it had been deleted then
it would have been selected by overload resolution as a better match and you'd
get an error telling you the move constructor was deleted.

The distinction is important (and frequently misunderstood).

> destructor was declared, but gcc does not mention this at all (instead of,
> or at least in addition to, why the copy-constructor was deleted).

That would be better.

If move construction fails, it's unlikely that the type is
copyable-but-not-movable, because such types are stupid and should not exist.
So then the question is whether it's supposed to be completely non-copyable and
non-movable, or whether the class has a bug that we can help to diagnose.

The right heuristic is probably:

If initializing T from a T rvalue is ill-formed, check whether an implicit move
constructor was suppressed. If it was, print a fix-it suggesting:

  S(S&&) = default;

Reduced:

struct MO {
  MO(MO&&) { }
};
struct S {
  ~S() = default;
  MO m;
};
S&& f();
S s = f();

This prints:

mo.cc:7:9: error: use of deleted function ‘S::S(const S&)’
    7 | S s = f();
      |         ^
mo.cc:2:8: note: ‘S::S(const S&)’ is implicitly deleted because the default
definition would be ill-formed:
    2 | struct S {
      |        ^
mo.cc:2:8: error: use of deleted function ‘constexpr MO::MO(const MO&)’
mo.cc:1:8: note: ‘constexpr MO::MO(const MO&)’ is implicitly declared as
deleted because ‘MO’ declares a move constructor or move assignment operator
    1 | struct MO {
      |        ^~


I think it would be better to print:

mo.cc:7:9: error: use of deleted function ‘S::S(const S&)’
    7 | S s = f();
      |         ^
mo.cc:5:4: note: ‘S::S(S&&)’ is not implicitly declared 'S' declares a
destructor:
    2 |   ~S() = default;
      |   ^~
mo.cc:5:4: note: add a user-declared move constructor to fix this:
   ~S() = default;
   ^
   S(S&&) = default;

mo.cc:2:8: note: ‘S::S(const S&)’ is implicitly deleted because the default
definition would be ill-formed:
    2 | struct S {
      |        ^
mo.cc:2:8: error: use of deleted function ‘constexpr MO::MO(const MO&)’
mo.cc:1:8: note: ‘constexpr MO::MO(const MO&)’ is implicitly declared as
deleted because ‘MO’ declares a move constructor or move assignment operator
    1 | struct MO {
      |        ^~


N.B. I don't think showing the locations "struct S {" and "struct MO {" for the
implicitly deleted copy constructors is useful, but I think I've said that in
another bug report somewhere.

Reply via email to