* [Bug libstdc++/96269] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
@ 2020-07-21 15:10 ` redi at gcc dot gnu.org
2020-07-21 16:17 ` sshannin at gmail dot com
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: redi at gcc dot gnu.org @ 2020-07-21 15:10 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Your operator== should be const-qualified.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
2020-07-21 15:10 ` [Bug libstdc++/96269] " redi at gcc dot gnu.org
@ 2020-07-21 16:17 ` sshannin at gmail dot com
2020-11-05 15:40 ` redi at gcc dot gnu.org
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: sshannin at gmail dot com @ 2020-07-21 16:17 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
--- Comment #2 from sshannin at gmail dot com ---
(In reply to Jonathan Wakely from comment #1)
> Your operator== should be const-qualified.
I don't disagree. I can also fully remove the operator== and it compiles as
well (why should the presence of the non-const operator== cause the comparison
with nullopt in one direction to instantiate it).
But yeah, I lost something in my reduction in there. I think the main point is
that one direction of the comparison instantiates the templated operator== and
the other doesn't.
Consider this version of X instead, which avoids the const issues:
struct X {
int y;
template <typename T>
bool operator==(const T&o) const {
return y == o.summary();
}
};
We again end up instantiating X's operator== (even though we wouldn't call it)
in the FLIP case (and thus fail to compile), but in the non-flip case
everything seems fine.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
2020-07-21 15:10 ` [Bug libstdc++/96269] " redi at gcc dot gnu.org
2020-07-21 16:17 ` sshannin at gmail dot com
@ 2020-11-05 15:40 ` redi at gcc dot gnu.org
2020-11-05 15:52 ` ville.voutilainen at gmail dot com
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: redi at gcc dot gnu.org @ 2020-11-05 15:40 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
I don't think this is a bug in std::optional, I think it's how C++20 works.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (2 preceding siblings ...)
2020-11-05 15:40 ` redi at gcc dot gnu.org
@ 2020-11-05 15:52 ` ville.voutilainen at gmail dot com
2020-11-05 16:07 ` ville.voutilainen at gmail dot com
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: ville.voutilainen at gmail dot com @ 2020-11-05 15:52 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
Ville Voutilainen <ville.voutilainen at gmail dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |ville.voutilainen at gmail dot com
--- Comment #4 from Ville Voutilainen <ville.voutilainen at gmail dot com> ---
Right; even gcc trunk is happy with that code in C++17 mode with both values of
FLIP, it's the C++20 spaceship rules that cause trouble here.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (3 preceding siblings ...)
2020-11-05 15:52 ` ville.voutilainen at gmail dot com
@ 2020-11-05 16:07 ` ville.voutilainen at gmail dot com
2020-11-05 16:51 ` sshannin at gmail dot com
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: ville.voutilainen at gmail dot com @ 2020-11-05 16:07 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
--- Comment #5 from Ville Voutilainen <ville.voutilainen at gmail dot com> ---
Oh, and if you define a spaceship operator for your type, then things work
again, with or without FLIP.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (4 preceding siblings ...)
2020-11-05 16:07 ` ville.voutilainen at gmail dot com
@ 2020-11-05 16:51 ` sshannin at gmail dot com
2020-11-05 17:41 ` redi at gcc dot gnu.org
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: sshannin at gmail dot com @ 2020-11-05 16:51 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
--- Comment #6 from sshannin at gmail dot com ---
Thanks to you both for your analysis. As I said, I wasn't sure if it was an
issue, so I'm certainly willing to accept that it's not.
The one point I wanted to emphasize though just to make sure we're talking
about the same thing is that it seems to odd to me that we're instantiating any
form of comparison function for type T. We're comparing optional<T> to
nullopt_t, so it would seem that it shouldn't matter whether T itself is even
comparable.
More specifically, header <optional> defines operator<=>(const optional<T> &x,
nullopt_t), with the very simple body of bool(x) <=> false, as expected (circa
line 1050, gated by #ifdef __cpp_lib_three_way_comparsion). This is why the
non-flip case works, it hits the spaceship overload for (optional, null_opt_t).
But there is no such operator in the other direction: (null_opt_t, optional).
So we end up hitting optional's plain templated operator==() at ~line 1120,
which of course ultimately instantiates the T's (broken/weird) operator.
I guess to rephrase, should there also be a specialized spaceship overload for
the (nullopt_t, optional) direction to complement the (optional, nullopt) one?
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (5 preceding siblings ...)
2020-11-05 16:51 ` sshannin at gmail dot com
@ 2020-11-05 17:41 ` redi at gcc dot gnu.org
2020-11-05 17:50 ` redi at gcc dot gnu.org
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: redi at gcc dot gnu.org @ 2020-11-05 17:41 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
--- Comment #7 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to sshannin from comment #6)
> I guess to rephrase, should there also be a specialized spaceship overload
> for the (nullopt_t, optional) direction to complement the (optional,
> nullopt) one?
No, the compiler synthesizes it from operator==(optional, nullopt_t) by
reversing the arguments. That's how comparisons work in C++20.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (6 preceding siblings ...)
2020-11-05 17:41 ` redi at gcc dot gnu.org
@ 2020-11-05 17:50 ` redi at gcc dot gnu.org
2020-11-05 17:54 ` ville.voutilainen at gmail dot com
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: redi at gcc dot gnu.org @ 2020-11-05 17:50 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Last reconfirmed| |2020-11-05
Keywords| |rejects-valid
Assignee|unassigned at gcc dot gnu.org |redi at gcc dot gnu.org
Ever confirmed|0 |1
Status|UNCONFIRMED |ASSIGNED
--- Comment #8 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Ah, but there is a library bug here after all. The declval expressions used to
constrain the comparison operators are using the wrong type.
They always use declval<_Tp>() == declval<_Up>() but it should be const _Tp&
and const _Up& instead. That would mean those aren't candidates for your
non-const operator== and so the synthesized operator==(nulloptr_t, optional<T>)
would get used.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (7 preceding siblings ...)
2020-11-05 17:50 ` redi at gcc dot gnu.org
@ 2020-11-05 17:54 ` ville.voutilainen at gmail dot com
2020-11-05 18:00 ` [Bug libstdc++/96269] [10/11 Regression] " redi at gcc dot gnu.org
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: ville.voutilainen at gmail dot com @ 2020-11-05 17:54 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
--- Comment #9 from Ville Voutilainen <ville.voutilainen at gmail dot com> ---
Ha, well spotted. In general, in a spaceship world, you do want to provide
comparisons symmetrically and const-correctly, and that also works in the
pre-spaceship world, thus:
#include <optional>
struct X {
template <typename T>
bool operator==(const T&) const {
return false;
}
template <typename T> friend bool operator==(const T&, const X&) {return
false;}
};
bool foo() {
std::optional<X> x;
#ifndef FLIP
return x == std::nullopt;
#else
return std::nullopt == x;
#endif
}
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] [10/11 Regression] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (8 preceding siblings ...)
2020-11-05 17:54 ` ville.voutilainen at gmail dot com
@ 2020-11-05 18:00 ` redi at gcc dot gnu.org
2020-11-05 19:09 ` cvs-commit at gcc dot gnu.org
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: redi at gcc dot gnu.org @ 2020-11-05 18:00 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Target Milestone|--- |10.3
Known to fail| |10.2.1, 11.0
Known to work| |9.3.0
Summary|optional comparison with |[10/11 Regression] optional
|nullopt fails |comparison with nullopt
| |fails
Priority|P3 |P2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] [10/11 Regression] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (9 preceding siblings ...)
2020-11-05 18:00 ` [Bug libstdc++/96269] [10/11 Regression] " redi at gcc dot gnu.org
@ 2020-11-05 19:09 ` cvs-commit at gcc dot gnu.org
2020-11-05 19:31 ` redi at gcc dot gnu.org
2020-11-05 19:38 ` redi at gcc dot gnu.org
12 siblings, 0 replies; 14+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2020-11-05 19:09 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
--- Comment #10 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:
https://gcc.gnu.org/g:cdd2d448d8200ed5ebcb232163954367b553291e
commit r11-4753-gcdd2d448d8200ed5ebcb232163954367b553291e
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Thu Nov 5 18:36:19 2020 +0000
libstdc++: Fix constraints on std::optional comparisons [PR 96269]
The relational operators for std::optional were using the wrong types
in the declval expressions used to constrain them. Instead of using
const lvalues they were using non-const rvalues, which meant that a type
might satisfy the constraints but then give an error when the function
body was instantiated.
libstdc++-v3/ChangeLog:
PR libstdc++/96269
* include/std/optional (operator==, operator!=, operator<)
(operator>, operator<=, operator>=): Fix types used in
SFINAE constraints.
* testsuite/20_util/optional/relops/96269.cc: New test.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] [10/11 Regression] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (10 preceding siblings ...)
2020-11-05 19:09 ` cvs-commit at gcc dot gnu.org
@ 2020-11-05 19:31 ` redi at gcc dot gnu.org
2020-11-05 19:38 ` redi at gcc dot gnu.org
12 siblings, 0 replies; 14+ messages in thread
From: redi at gcc dot gnu.org @ 2020-11-05 19:31 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Resolution|--- |FIXED
Status|ASSIGNED |RESOLVED
--- Comment #11 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Fixed for 10.3
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Bug libstdc++/96269] [10/11 Regression] optional comparison with nullopt fails
2020-07-21 14:44 [Bug libstdc++/96269] New: optional comparison with nullopt fails sshannin at gmail dot com
` (11 preceding siblings ...)
2020-11-05 19:31 ` redi at gcc dot gnu.org
@ 2020-11-05 19:38 ` redi at gcc dot gnu.org
12 siblings, 0 replies; 14+ messages in thread
From: redi at gcc dot gnu.org @ 2020-11-05 19:38 UTC (permalink / raw)
To: gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96269
--- Comment #12 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Fixed by r10-8983 for gcc-10
^ permalink raw reply [flat|nested] 14+ messages in thread