From b33f44ca6ce2dae7502ce138600e1631ffc9232c Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 21 May 2024 15:13:01 +0100 Subject: [PATCH] libstdc++: Ensure std::variant relops convert to bool [PR115145] Ensure that the result of comparing the variant alternatives is converted to bool immediately rather than copied. libstdc++-v3/ChangeLog: PR libstdc++/115145 * include/std/variant (operator==, operator!=, operator<) (operator<=, operator>, operator>=): Add trailing-return-type to lambda expressions to trigger conversion to bool. * testsuite/20_util/variant/relops/115145.cc: New test. --- libstdc++-v3/include/std/variant | 63 ++++++++++++---------- .../testsuite/20_util/variant/relops/115145.cc | 36 +++++++++++++ 2 files changed, 71 insertions(+), 28 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/variant/relops/115145.cc diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index cfb4bcdbcc9..371cbb90f54 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -1271,10 +1271,11 @@ namespace __detail::__variant operator== [[nodiscard]] (const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { - return __detail::__variant::__compare(true, __lhs, __rhs, - [](auto&& __l, auto&& __r) { - return __l == __r; - }); + namespace __variant = __detail::__variant; + return __variant::__compare(true, __lhs, __rhs, + [](auto&& __l, auto&& __r) -> bool { + return __l == __r; + }); } template @@ -1286,10 +1287,11 @@ namespace __detail::__variant operator!= [[nodiscard]] (const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { - return __detail::__variant::__compare(true, __lhs, __rhs, - [](auto&& __l, auto&& __r) { - return __l != __r; - }); + namespace __variant = __detail::__variant; + return __variant::__compare(true, __lhs, __rhs, + [](auto&& __l, auto&& __r) -> bool { + return __l != __r; + }); } template @@ -1301,10 +1303,11 @@ namespace __detail::__variant operator< [[nodiscard]] (const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { - return __detail::__variant::__compare(true, __lhs, __rhs, - [](auto&& __l, auto&& __r) { - return __l < __r; - }); + namespace __variant = __detail::__variant; + return __variant::__compare(true, __lhs, __rhs, + [](auto&& __l, auto&& __r) -> bool { + return __l < __r; + }); } template @@ -1316,10 +1319,11 @@ namespace __detail::__variant operator<= [[nodiscard]] (const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { - return __detail::__variant::__compare(true, __lhs, __rhs, - [](auto&& __l, auto&& __r) { - return __l <= __r; - }); + namespace __variant = __detail::__variant; + return __variant::__compare(true, __lhs, __rhs, + [](auto&& __l, auto&& __r) -> bool { + return __l <= __r; + }); } template @@ -1331,10 +1335,11 @@ namespace __detail::__variant operator> [[nodiscard]] (const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { - return __detail::__variant::__compare(true, __lhs, __rhs, - [](auto&& __l, auto&& __r) { - return __l > __r; - }); + namespace __variant = __detail::__variant; + return __variant::__compare(true, __lhs, __rhs, + [](auto&& __l, auto&& __r) -> bool { + return __l > __r; + }); } template @@ -1346,10 +1351,11 @@ namespace __detail::__variant operator>= [[nodiscard]] (const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { - return __detail::__variant::__compare(true, __lhs, __rhs, - [](auto&& __l, auto&& __r) { - return __l >= __r; - }); + namespace __variant = __detail::__variant; + return __variant::__compare(true, __lhs, __rhs, + [](auto&& __l, auto&& __r) -> bool { + return __l >= __r; + }); } constexpr bool operator==(monostate, monostate) noexcept { return true; } @@ -1363,10 +1369,11 @@ namespace __detail::__variant { common_comparison_category_t...> __ret = strong_ordering::equal; - return __detail::__variant::__compare(__ret, __v, __w, - [](auto&& __l, auto&& __r) { - return __l <=> __r; - }); + namespace __variant = __detail::__variant; + return __variant::__compare(__ret, __v, __w, + [](auto&& __l, auto&& __r) { + return __l <=> __r; + }); } constexpr strong_ordering diff --git a/libstdc++-v3/testsuite/20_util/variant/relops/115145.cc b/libstdc++-v3/testsuite/20_util/variant/relops/115145.cc new file mode 100644 index 00000000000..f3443cbbbcc --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/variant/relops/115145.cc @@ -0,0 +1,36 @@ +// { dg-do compile { target c++17 } } +// PR libstdc++/115145 +// lambda in rewritten std::variant comparisons does not specify return type + +#include + +struct Bool { + operator bool() & { return val; } + const bool val; +}; + +Bool t{true}, f{false}; + +struct A { + Bool& operator==(const A&) const { return t; } + Bool& operator!=(const A&) const { return f; } + Bool& operator<(const A&) const { return f; } + Bool& operator>(const A&) const { return f; } + Bool& operator<=(const A&) const { return t; } + Bool& operator>=(const A&) const { return t; } +}; + +bool check_bool(bool); +template void check_bool(T) = delete; + +void +test_pr115145() +{ + std::variant v; + check_bool( v == v ); + check_bool( !(v != v) ); + check_bool( !(v < v) ); + check_bool( !(v > v) ); + check_bool( v <= v ); + check_bool( v >= v ); +} -- 2.11.4.GIT