https://gcc.gnu.org/g:c429d509a86d61b21298b787948e24a9c97084e3
commit r15-3134-gc429d509a86d61b21298b787948e24a9c97084e3 Author: Jonathan Wakely <jwak...@redhat.com> Date: Tue Jun 25 21:58:34 2024 +0100 libstdc++: Implement LWG 3746 for std::optional This avoids constraint recursion in operator<=> for std::optional. The resolution was approved in Kona 2022. libstdc++-v3/ChangeLog: * include/std/optional (__is_derived_from_optional): New concept. (operator<=>): Use __is_derived_from_optional. * testsuite/20_util/optional/relops/lwg3746.cc: New test. Diff: --- libstdc++-v3/include/std/optional | 12 ++++++++++-- .../testsuite/20_util/optional/relops/lwg3746.cc | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index 6651686cd1d0..933a5b15e569 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -1581,9 +1581,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return !__rhs; } #endif // three-way-comparison +#if __cpp_lib_concepts // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4072. std::optional comparisons: constrain harder -#if __cpp_lib_concepts # define _REQUIRES_NOT_OPTIONAL(T) requires (!__is_optional_v<T>) #else # define _REQUIRES_NOT_OPTIONAL(T) @@ -1675,8 +1675,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return !__rhs || __lhs >= *__rhs; } #ifdef __cpp_lib_three_way_comparison + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3746. optional's spaceship with U with a type derived from optional + // causes infinite constraint meta-recursion + template<typename _Tp> + concept __is_derived_from_optional = requires (const _Tp& __t) { + []<typename _Up>(const optional<_Up>&){ }(__t); + }; + template<typename _Tp, typename _Up> - requires (!__is_optional_v<_Up>) + requires (!__is_derived_from_optional<_Up>) && three_way_comparable_with<_Up, _Tp> constexpr compare_three_way_result_t<_Tp, _Up> operator<=> [[nodiscard]] (const optional<_Tp>& __x, const _Up& __v) diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/lwg3746.cc b/libstdc++-v3/testsuite/20_util/optional/relops/lwg3746.cc new file mode 100644 index 000000000000..46065f8e901d --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/optional/relops/lwg3746.cc @@ -0,0 +1,20 @@ +// { dg-do compile { target c++20 } } + +// LWG 3746. optional's spaceship with U with a type derived from optional +// causes infinite constraint meta-recursion + +#include <optional> + +struct S : std::optional<char> +{ + bool operator==(const S&) const; + bool operator<(const S&) const; + bool operator>(const S&) const; + bool operator<=(const S&) const; + bool operator>=(const S&) const; +}; + +auto cmp(const S& s, const std::optional<char>& o) +{ + return s <=> o; +}