Skip to content

Commit 7164d1c

Browse files
Implement LWG-3746 optional's spaceship with U with a type derived from optional causes infinite constraint meta-recursion (#3265)
1 parent 66c528a commit 7164d1c

File tree

3 files changed

+23
-10
lines changed

3 files changed

+23
-10
lines changed

stl/inc/optional

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ _NODISCARD constexpr bool operator>=(const _Ty1& _Left, const optional<_Ty2>& _R
926926
#ifdef __cpp_lib_concepts
927927
// clang-format off
928928
_EXPORT_STD template <class _Ty1, class _Ty2>
929-
requires (!_Is_specialization_v<_Ty2, optional>)
929+
requires (!_Derived_from_specialization_of<_Ty2, optional>)
930930
&& three_way_comparable_with<_Ty1, _Ty2>
931931
_NODISCARD constexpr compare_three_way_result_t<_Ty1, _Ty2>
932932
operator<=>(const optional<_Ty1>& _Left, const _Ty2& _Right)

stl/inc/xutility

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,15 @@ using _Algorithm_int_t = conditional_t<is_integral_v<_Ty>, _Ty, ptrdiff_t>;
404404
template <class _Ty>
405405
concept _Destructible_object = is_object_v<_Ty> && destructible<_Ty>;
406406

407+
template <template <class...> class _Template, class... _Args>
408+
void _Derived_from_specialization_impl(const _Template<_Args...>&);
409+
410+
template <class _Ty, template <class...> class _Template>
411+
concept _Derived_from_specialization_of =
412+
requires(const _Ty& _Obj) {
413+
_STD _Derived_from_specialization_impl<_Template>(_Obj); // qualified: avoid ADL, handle incomplete types
414+
};
415+
407416
namespace ranges {
408417
namespace _Iter_move {
409418
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199
@@ -2932,23 +2941,17 @@ namespace ranges {
29322941

29332942
_EXPORT_STD struct view_base {};
29342943

2935-
template <template <class...> class _Template, class... _Args>
2936-
void _Derived_from_specialization_impl(const _Template<_Args...>&);
2937-
29382944
template <class _Ty, template <class...> class _Template>
2939-
concept _Derived_from_specialization_of =
2940-
is_object_v<_Ty> && requires(const _Ty& _Obj) {
2941-
_RANGES _Derived_from_specialization_impl<_Template>(
2942-
_Obj); // qualified: avoid ADL, handle incompletable types
2943-
};
2945+
concept _Strictly_derived_from_specialization_of =
2946+
is_object_v<_Ty> && _Derived_from_specialization_of<_Ty, _Template>;
29442947

29452948
_EXPORT_STD template <class _Derived>
29462949
requires is_class_v<_Derived> && same_as<_Derived, remove_cv_t<_Derived>>
29472950
class view_interface;
29482951

29492952
_EXPORT_STD template <class _Ty>
29502953
inline constexpr bool enable_view =
2951-
derived_from<_Ty, view_base> || _Derived_from_specialization_of<_Ty, view_interface>;
2954+
derived_from<_Ty, view_base> || _Strictly_derived_from_specialization_of<_Ty, view_interface>;
29522955

29532956
_EXPORT_STD template <class _Ty>
29542957
concept view = range<_Ty> && movable<_Ty> && enable_view<_Ty>;

tests/std/tests/P1614R2_spaceship/test.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,11 @@ constexpr bool tuple_like_test() {
290290
return true;
291291
}
292292

293+
template <class T>
294+
struct derived_optional : std::optional<T> {
295+
friend bool operator==(const derived_optional&, const derived_optional&) = default;
296+
};
297+
293298
template <auto SmallVal, decltype(SmallVal) EqualVal, decltype(EqualVal) LargeVal>
294299
constexpr bool optional_test() {
295300
using ReturnType = std::compare_three_way_result_t<decltype(SmallVal)>;
@@ -310,8 +315,13 @@ constexpr bool optional_test() {
310315
}
311316
{
312317
constexpr std::optional o1(SmallVal);
318+
constexpr derived_optional<decltype(SmallVal)> derived1{std::optional(SmallVal)};
319+
constexpr derived_optional<decltype(SmallVal)> derived2{std::optional(LargeVal)};
320+
321+
static_assert(!std::three_way_comparable<derived_optional<decltype(SmallVal)>>);
313322

314323
assert(spaceship_test<ReturnType>(o1, EqualVal, LargeVal));
324+
assert(spaceship_test<ReturnType>(o1, derived1, derived2));
315325
}
316326
{
317327
constexpr std::optional<decltype(SmallVal)> o1(std::nullopt);

0 commit comments

Comments
 (0)