public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors
@ 2020-08-05 21:31 gumby@henkel-wallace.org
  2020-08-05 21:43 ` [Bug c++/96489] " redi at gcc dot gnu.org
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: gumby@henkel-wallace.org @ 2020-08-05 21:31 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 96489
           Summary: Three way comparison operator failure to synthesize
                    traditional comparitors
           Product: gcc
           Version: 10.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gumby@henkel-wallace.org
  Target Milestone: ---

User-defined <=> doesn't generate == or != though user-defined operator== and
operator<=> = default do.

/usr/local/opt/gcc/bin/g++-10   -std=c++20 foo.cc && ./a.out
foo.cc: In function 'int main()':
foo.cc:21:9: error: no match for 'operator!=' (operand types are 'foo' and
'foo')
   21 |   if (a != b) std::cout << "not ";
      |       ~ ^~ ~
      |       |    |
      |       foo  foo
foo.cc:25:11: error: no match for 'operator==' (operand types are 'foo' and
'foo')
   25 |   if (!(a == c)) std::cout << "not ";
      |         ~ ^~ ~
      |         |    |
      |         foo  foo

#include <iostream>

struct foo {
    int content;
    foo(int x) : content { x } {}

  // works: auto operator <=> (foo const& rhs) const = default;
  // works: auto operator ==  (foo const& rhs) const { return content == 
rhs.content; }
  // fails: 
            auto operator <=> (foo const& rhs) const { return content <=>
rhs.content; }
};

int main() {
  foo a { 1 };
  foo b { 2 };
  foo c { 1 };

  if (a != b) std::cout << "not ";
  std::cout  << "equal" << std::endl;


  if (!(a == c)) std::cout << "not ";
  std::cout  << "equal" << std::endl;

  return 0;

Result:

/usr/local/opt/gcc/bin/g++-10   -std=c++20 foo.cc && ./a.out
foo.cc: In function 'int main()':
foo.cc:21:9: error: no match for 'operator!=' (operand types are 'foo' and
'foo')
   21 |   if (a != b) std::cout << "not ";
      |       ~ ^~ ~
      |       |    |
      |       foo  foo
foo.cc:25:11: error: no match for 'operator==' (operand types are 'foo' and
'foo')
   25 |   if (!(a == c)) std::cout << "not ";
      |         ~ ^~ ~
      |         |    |
      |         foo  foo

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/96489] Three way comparison operator failure to synthesize traditional comparitors
  2020-08-05 21:31 [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors gumby@henkel-wallace.org
@ 2020-08-05 21:43 ` redi at gcc dot gnu.org
  2020-08-05 22:33 ` gumby@henkel-wallace.org
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: redi at gcc dot gnu.org @ 2020-08-05 21:43 UTC (permalink / raw)
  To: gcc-bugs

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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|---                         |INVALID

--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
This is correct, [class.compare.default] p5 says:

If the member-specification does not explicitly declare any member or friend
named operator==, an == operator function is declared implicitly for each
three-way comparison operator function defined as defaulted in the
member-specification

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/96489] Three way comparison operator failure to synthesize traditional comparitors
  2020-08-05 21:31 [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors gumby@henkel-wallace.org
  2020-08-05 21:43 ` [Bug c++/96489] " redi at gcc dot gnu.org
@ 2020-08-05 22:33 ` gumby@henkel-wallace.org
  2020-08-05 23:06 ` redi at gcc dot gnu.org
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: gumby@henkel-wallace.org @ 2020-08-05 22:33 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #2 from DV Henkel-Wallace <gumby@henkel-wallace.org> ---
I don't think this should be marked as resolved.  The bug is not the case you
cited which indeed works properly as specified.

The bug is that comparators are not being synthesized when the a *user
supplied* operator<=> is defined.

I believe this case is [class.spaceship] case (1.1).  Although that case does
reference [class.compare.default], it talks about the spaceship operator being
"usable" which is defined, via clause (3), to have a defined binary operator of
appropriate types -- _not_ claiming that only the `= default` case applies.


More pragmatically the user will expect that their explicit definition of <=>
will result in unspecified comparisons being synthesized.  Else why define it
in the first place?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/96489] Three way comparison operator failure to synthesize traditional comparitors
  2020-08-05 21:31 [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors gumby@henkel-wallace.org
  2020-08-05 21:43 ` [Bug c++/96489] " redi at gcc dot gnu.org
  2020-08-05 22:33 ` gumby@henkel-wallace.org
@ 2020-08-05 23:06 ` redi at gcc dot gnu.org
  2020-08-05 23:12 ` redi at gcc dot gnu.org
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: redi at gcc dot gnu.org @ 2020-08-05 23:06 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to DV Henkel-Wallace from comment #2)
> I don't think this should be marked as resolved.  The bug is not the case
> you cited which indeed works properly as specified.
> 
> The bug is that comparators are not being synthesized when the a *user
> supplied* operator<=> is defined.

They're not supposed to be, because as I quoted above, the == operator is only
sythesized when <=> is defined as defaulted.

> I believe this case is [class.spaceship] case (1.1).  Although that case
> does reference [class.compare.default], it talks about the spaceship
> operator being "usable" which is defined, via clause (3), to have a defined
> binary operator of appropriate types -- _not_ claiming that only the `=
> default` case applies.
> 
> 
> More pragmatically the user will expect that their explicit definition of
> <=> will result in unspecified comparisons being synthesized.  Else why
> define it in the first place?

Because you get the < > <= >= operators for free.

But you only get == for free if <=> is defined as defaulted, and you only get
!= for free if == exists.

I think to get what you expect, you need to either define <=> as defaulted, or
define == as defaulted.

If you have a user-provided operator<=> and no operator== declared, then you
get no ==.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/96489] Three way comparison operator failure to synthesize traditional comparitors
  2020-08-05 21:31 [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors gumby@henkel-wallace.org
                   ` (2 preceding siblings ...)
  2020-08-05 23:06 ` redi at gcc dot gnu.org
@ 2020-08-05 23:12 ` redi at gcc dot gnu.org
  2020-08-05 23:35 ` gumby@henkel-wallace.org
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: redi at gcc dot gnu.org @ 2020-08-05 23:12 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> ---
I believe the rationale for this is that if your <=> can't be defaulted, then
it must be doing something special, and synthesizing == from it is not
necessarily safe.

If <=> is defaulted, then it does the "obvious" thing and so synthesizing == to
do the obvious thing is probably OK.

If <=> is user-provided but you know that an implicitly-defined operator==
would do the right thing, define operator== as defaulted.

Clang agrees with GCC FWIW.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/96489] Three way comparison operator failure to synthesize traditional comparitors
  2020-08-05 21:31 [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors gumby@henkel-wallace.org
                   ` (3 preceding siblings ...)
  2020-08-05 23:12 ` redi at gcc dot gnu.org
@ 2020-08-05 23:35 ` gumby@henkel-wallace.org
  2020-08-06  9:13 ` redi at gcc dot gnu.org
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: gumby@henkel-wallace.org @ 2020-08-05 23:35 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #5 from DV Henkel-Wallace <gumby@henkel-wallace.org> ---
(In reply to Jonathan Wakely from comment #4)
> I believe the rationale for this is that if your <=> can't be defaulted,
> then it must be doing something special, and synthesizing == from it is not
> necessarily safe.

The thing is: properly written user defined operator <=> is supposed to to be
"correct" (whatever that would mean!) for all of the < 0, = 0, and > 0 cases. 
It doesn't make sense to presume that a user defined <=> would only apply to
the < and > cases -- in fact how could it otherwise synthesize <= and => ?

(More jocularly it's not `operator <>` -- would we call that the submarine
operator?)

In fact I just changed my test case to use `((a <=> b) != 0)` and it did what I
expected.

> Clang agrees with GCC FWIW.

Yes, reported it to them too :-(

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/96489] Three way comparison operator failure to synthesize traditional comparitors
  2020-08-05 21:31 [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors gumby@henkel-wallace.org
                   ` (4 preceding siblings ...)
  2020-08-05 23:35 ` gumby@henkel-wallace.org
@ 2020-08-06  9:13 ` redi at gcc dot gnu.org
  2020-08-06 16:52 ` gumby@henkel-wallace.org
  2020-08-06 19:05 ` redi at gcc dot gnu.org
  7 siblings, 0 replies; 9+ messages in thread
From: redi at gcc dot gnu.org @ 2020-08-06  9:13 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #6 from Jonathan Wakely <redi at gcc dot gnu.org> ---
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1185r2.html

Your understanding of <=> is from 2018, that's not how C++20 works.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/96489] Three way comparison operator failure to synthesize traditional comparitors
  2020-08-05 21:31 [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors gumby@henkel-wallace.org
                   ` (5 preceding siblings ...)
  2020-08-06  9:13 ` redi at gcc dot gnu.org
@ 2020-08-06 16:52 ` gumby@henkel-wallace.org
  2020-08-06 19:05 ` redi at gcc dot gnu.org
  7 siblings, 0 replies; 9+ messages in thread
From: gumby@henkel-wallace.org @ 2020-08-06 16:52 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #7 from DV Henkel-Wallace <gumby@henkel-wallace.org> ---
Thanks.  That is clear.

BTW FWIW, defining <=> myself and then defining == default does appear to do
what I want (i.e. I don't have to use. = default with both operators).  I saw
that cppreference claims that `== default` will do `<=> < 0` -- though I know
that site isn't authoritative, merely close to authorotative.

Sorry about reporting a non-bug and thanks for your patience in your response.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Bug c++/96489] Three way comparison operator failure to synthesize traditional comparitors
  2020-08-05 21:31 [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors gumby@henkel-wallace.org
                   ` (6 preceding siblings ...)
  2020-08-06 16:52 ` gumby@henkel-wallace.org
@ 2020-08-06 19:05 ` redi at gcc dot gnu.org
  7 siblings, 0 replies; 9+ messages in thread
From: redi at gcc dot gnu.org @ 2020-08-06 19:05 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #8 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to DV Henkel-Wallace from comment #7)
> Thanks.  That is clear.
> 
> BTW FWIW, defining <=> myself and then defining == default does appear to do
> what I want (i.e. I don't have to use. = default with both operators).

Right, that's what I said (or tried to say) in comment 3:

  "I think to get what you expect, you need to either define <=> as defaulted,
   or define == as defaulted."

Either works fine, it doesn't need to be both.

> saw that cppreference claims that `== default` will do `<=> < 0` -- though I
> know that site isn't authoritative, merely close to authorotative.

https://en.cppreference.com/w/cpp/language/default_comparisons seems correct,
although it notes:

  This section is incomplete
  Reason: Defaulted equality comparisons

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2020-08-06 19:05 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-05 21:31 [Bug c++/96489] New: Three way comparison operator failure to synthesize traditional comparitors gumby@henkel-wallace.org
2020-08-05 21:43 ` [Bug c++/96489] " redi at gcc dot gnu.org
2020-08-05 22:33 ` gumby@henkel-wallace.org
2020-08-05 23:06 ` redi at gcc dot gnu.org
2020-08-05 23:12 ` redi at gcc dot gnu.org
2020-08-05 23:35 ` gumby@henkel-wallace.org
2020-08-06  9:13 ` redi at gcc dot gnu.org
2020-08-06 16:52 ` gumby@henkel-wallace.org
2020-08-06 19:05 ` redi at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).