public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=>
       [not found] <bug-94061-4@http.gcc.gnu.org/bugzilla/>
@ 2022-01-08  1:06 ` f.heckenbach@fh-soft.de
  2022-01-08 16:35 ` ppalka at gcc dot gnu.org
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: f.heckenbach@fh-soft.de @ 2022-01-08  1:06 UTC (permalink / raw)
  To: gcc-bugs

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

Frank Heckenbach <f.heckenbach@fh-soft.de> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |f.heckenbach@fh-soft.de

--- Comment #1 from Frank Heckenbach <f.heckenbach@fh-soft.de> ---
I ran into the same problem.

Interestingly, clang also seems to reject it, so maybe it is wrong by the
letter of the standard? Though it would seem strange to me -- after all, when
manually implementing B::operator<=> a protected operator in A will do fine.

I hope someone who knows the standard more intimately can confirm whether
that's so and possibly open a defect report to the standard.

Fun fact: When I independently created a minimal test program, my result was
exactly identical to yours (modulo whitespace), including the names of the
structs. :)

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

* [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=>
       [not found] <bug-94061-4@http.gcc.gnu.org/bugzilla/>
  2022-01-08  1:06 ` [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=> f.heckenbach@fh-soft.de
@ 2022-01-08 16:35 ` ppalka at gcc dot gnu.org
  2022-01-08 21:59 ` f.heckenbach@fh-soft.de
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: ppalka at gcc dot gnu.org @ 2022-01-08 16:35 UTC (permalink / raw)
  To: gcc-bugs

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

Patrick Palka <ppalka at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ppalka at gcc dot gnu.org

--- Comment #2 from Patrick Palka <ppalka at gcc dot gnu.org> ---
(In reply to Frank Heckenbach from comment #1)
> I ran into the same problem.
> 
> Interestingly, clang also seems to reject it, so maybe it is wrong by the
> letter of the standard? Though it would seem strange to me -- after all,
> when manually implementing B::operator<=> a protected operator in A will do
> fine.

How do you define it?  It works if we define it as

  auto operator <=> (const B& b) const {
    return A::operator<=>(b);
  }

but not if it's defined as

  auto operator <=> (const B& b) const {
    return static_cast<const A&>(*this) <=> static_cast<const A&>(b);
  }

According to [class.spaceship], IIUC the synthesized operator<=> looks more
similar to the latter invalid definition (invoking <=> recursively as an
operator expression on each pair of corresponding subobjects), so GCC/Clang
might be right to define it as deleted.

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

* [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=>
       [not found] <bug-94061-4@http.gcc.gnu.org/bugzilla/>
  2022-01-08  1:06 ` [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=> f.heckenbach@fh-soft.de
  2022-01-08 16:35 ` ppalka at gcc dot gnu.org
@ 2022-01-08 21:59 ` f.heckenbach@fh-soft.de
  2022-04-12  9:07 ` feildel+gccbugzilla@corona-renderer.com
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: f.heckenbach@fh-soft.de @ 2022-01-08 21:59 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #3 from Frank Heckenbach <f.heckenbach@fh-soft.de> ---
(In reply to Patrick Palka from comment #2)
> How do you define it?  It works if we define it as
> 
>   auto operator <=> (const B& b) const {
>     return A::operator<=>(b);
>   }
> 
> but not if it's defined as
> 
>   auto operator <=> (const B& b) const {
>     return static_cast<const A&>(*this) <=> static_cast<const A&>(b);
>   }

I'd do the former. I don't know what the standard says exactly, but intuitively
it seems to me that "protected" should suffice, also by comparison with
constructors.

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

* [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=>
       [not found] <bug-94061-4@http.gcc.gnu.org/bugzilla/>
                   ` (2 preceding siblings ...)
  2022-01-08 21:59 ` f.heckenbach@fh-soft.de
@ 2022-04-12  9:07 ` feildel+gccbugzilla@corona-renderer.com
  2024-04-24  7:42 ` gcc-90 at tbilles dot hu
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 7+ messages in thread
From: feildel+gccbugzilla@corona-renderer.com @ 2022-04-12  9:07 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #4 from Baudouin Feildel <feildel+gccbugzilla@corona-renderer.com> ---
We also ran into this issue with operator==(). This behavior might be explained
by some implementation detail of the generated code for the operator, but we
believe it is wrong because it is inconsistent, see the following example
(https://godbolt.org/z/f4EjojExh):

struct Base {
  protected:
    Base() = default;
    bool operator==(const Base& other) const = default;
};

struct Child : Base {
    int         i = 0;
    Child() = default;
    bool operator==(const Child& other) const = default;
};

int main() 
{
    Child a1;
    Child b1;
    return a1 == b1;
}

Here calling protected constructor in defaulted ctor is totally fine. But
trying to do the same with comparison operator fails with the following
compiler error:

<source>: In function 'int main()':
<source>:17:18: error: use of deleted function 'constexpr bool
Child::operator==(const Child&) const'
   17 |     return a1 == b1;
      |                  ^~
<source>:10:10: note: 'constexpr bool Child::operator==(const Child&) const' is
implicitly deleted because the default definition would be ill-formed:
   10 |     bool operator==(const Child& other) const = default;
      |          ^~~~~~~~
<source>:10:10: error: 'bool Base::operator==(const Base&) const' is protected
within this context
<source>:4:10: note: declared protected here
    4 |     bool operator==(const Base& other) const = default;
      |          ^~~~~~~~




This behavior is unfortunate and make it very difficult to use defaulted
operator== when you have a common base class that should not be comparable. See
this other example: https://godbolt.org/z/v78r1nYr9.

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

* [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=>
       [not found] <bug-94061-4@http.gcc.gnu.org/bugzilla/>
                   ` (3 preceding siblings ...)
  2022-04-12  9:07 ` feildel+gccbugzilla@corona-renderer.com
@ 2024-04-24  7:42 ` gcc-90 at tbilles dot hu
  2024-04-24 21:31 ` ppalka at gcc dot gnu.org
  2024-04-24 21:32 ` ppalka at gcc dot gnu.org
  6 siblings, 0 replies; 7+ messages in thread
From: gcc-90 at tbilles dot hu @ 2024-04-24  7:42 UTC (permalink / raw)
  To: gcc-bugs

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

Tibor Billes <gcc-90 at tbilles dot hu> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |gcc-90 at tbilles dot hu

--- Comment #5 from Tibor Billes <gcc-90 at tbilles dot hu> ---
I ran into this problem, I found a detailed stackoverflow discussion that
explains that the standard mandate the derived to base conversion mentioned
earlier in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94061#c2

It says that the list of subobjects are "formed by a sequence of
derived-to-base conversions, class member access expressions, and array
subscript expressions applied to x".
(https://timsong-cpp.github.io/cppwp/n4868/class.compare.default#6.sentence-3)

I'm not a C++ language lawyer, just wanted to provide additional information
for anyone looking for this problem. And yeah, I also wish this would work..

Here is the stackoverflow discussion with all the good references to the
specific sections of the standard:
https://stackoverflow.com/questions/73055625/deriving-class-with-protected-equality-operator-results-in-deleted-default

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

* [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=>
       [not found] <bug-94061-4@http.gcc.gnu.org/bugzilla/>
                   ` (4 preceding siblings ...)
  2024-04-24  7:42 ` gcc-90 at tbilles dot hu
@ 2024-04-24 21:31 ` ppalka at gcc dot gnu.org
  2024-04-24 21:32 ` ppalka at gcc dot gnu.org
  6 siblings, 0 replies; 7+ messages in thread
From: ppalka at gcc dot gnu.org @ 2024-04-24 21:31 UTC (permalink / raw)
  To: gcc-bugs

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

Patrick Palka <ppalka at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jason at gcc dot gnu.org

--- Comment #6 from Patrick Palka <ppalka at gcc dot gnu.org> ---
It seems reasonable for this to work but there might be a defect, or at least
lack of clarity, in the standard in this situation.

http://eel.is/c++draft/class.spaceship#3 specifies how a defaulted <=> is
defined, in terms of <=> comparisons of corresponding subobjects.  But it's not
clear how each of these <=> comparisons is written.  If they're always written
like operator expressions, e.g. x_i <=> y_i then if x_i / y_i are base class
subobjects that have a protected <=>, then such a definition would indeed be
ill-formed due to the protected access: https://godbolt.org/z/5h4ednq9  The <=>
comparison would need to be written A::operator<=>(b) as mentioned in comment
#2 in order for the definition to be valid IIUC?

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

* [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=>
       [not found] <bug-94061-4@http.gcc.gnu.org/bugzilla/>
                   ` (5 preceding siblings ...)
  2024-04-24 21:31 ` ppalka at gcc dot gnu.org
@ 2024-04-24 21:32 ` ppalka at gcc dot gnu.org
  6 siblings, 0 replies; 7+ messages in thread
From: ppalka at gcc dot gnu.org @ 2024-04-24 21:32 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #7 from Patrick Palka <ppalka at gcc dot gnu.org> ---
(In reply to Patrick Palka from comment #6)
> It seems reasonable for this to work but there might be a defect, or at
> least lack of clarity, in the standard in this situation.
> 
> http://eel.is/c++draft/class.spaceship#3 specifies how a defaulted <=> is
> defined, in terms of <=> comparisons of corresponding subobjects.  But it's
> not clear how each of these <=> comparisons is written.  If they're always
> written like operator expressions, e.g. x_i <=> y_i then if x_i / y_i are
> base class subobjects that have a protected <=>, then such a definition
> would indeed be ill-formed due to the protected access:
> https://godbolt.org/z/5h4ednq9  The <=> comparison would need to be written
> A::operator<=>(b) as mentioned in comment #2 in order for the definition to
> be valid IIUC?
Oops, the full CE link is https://godbolt.org/z/5h4ednq9E

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

end of thread, other threads:[~2024-04-24 21:32 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <bug-94061-4@http.gcc.gnu.org/bugzilla/>
2022-01-08  1:06 ` [Bug c++/94061] defaulted member operator <=> defined as deleted if a base has protected member operator <=> f.heckenbach@fh-soft.de
2022-01-08 16:35 ` ppalka at gcc dot gnu.org
2022-01-08 21:59 ` f.heckenbach@fh-soft.de
2022-04-12  9:07 ` feildel+gccbugzilla@corona-renderer.com
2024-04-24  7:42 ` gcc-90 at tbilles dot hu
2024-04-24 21:31 ` ppalka at gcc dot gnu.org
2024-04-24 21:32 ` ppalka 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).