Skip to content

Commit

Permalink
P2602R2 Poison Pills Are Too Toxic (#3215)
Browse files Browse the repository at this point in the history
  • Loading branch information
CaseyCarter authored Dec 6, 2022
1 parent be29af2 commit 214e014
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 127 deletions.
87 changes: 57 additions & 30 deletions stl/inc/compare
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,16 @@ using _Synth_three_way_result = decltype(_Synth_three_way{}(_STD declval<_Ty1&>(
// Note: The following CPOs are passing arguments as lvalues; see GH-1374.

namespace _Strong_order {
void strong_order(); // Block unqualified name lookup; see GH-1374.
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199
void strong_order() = delete; // Block unqualified name lookup
#else // ^^^ no workaround / workaround vvv
void strong_order();
#endif // ^^^ workaround ^^^

template <class _Ty1, class _Ty2>
concept _Has_ADL =
requires(_Ty1& _Left, _Ty2& _Right) { static_cast<strong_ordering>(/* ADL */ strong_order(_Left, _Right)); };
concept _Has_ADL = requires(_Ty1& _Left, _Ty2& _Right) {
static_cast<strong_ordering>(strong_order(_Left, _Right)); // intentional ADL
};

template <class _Ty1, class _Ty2>
concept _Can_compare_three_way =
Expand All @@ -380,7 +385,7 @@ namespace _Strong_order {
return {_St::_None};
} else if constexpr (_Has_ADL<_Ty1, _Ty2>) {
return {_St::_Adl, noexcept(static_cast<strong_ordering>(
/* ADL */ strong_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))};
strong_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; // intentional ADL
} else if constexpr (floating_point<decay_t<_Ty1>>) {
return {_St::_Floating, true};
} else if constexpr (_Can_compare_three_way<_Ty1, _Ty2>) {
Expand All @@ -401,7 +406,7 @@ namespace _Strong_order {
noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy;
if constexpr (_Strat == _St::_Adl) {
return static_cast<strong_ordering>(/* ADL */ strong_order(_Left, _Right));
return static_cast<strong_ordering>(strong_order(_Left, _Right)); // intentional ADL
} else if constexpr (_Strat == _St::_Floating) {
using _Floating_type = decay_t<_Ty1>;
using _Traits = _Floating_type_traits<_Floating_type>;
Expand Down Expand Up @@ -451,18 +456,27 @@ inline namespace _Cpos {
}

namespace _Weak_order {
void weak_order(); // Block unqualified name lookup; see GH-1374.
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199
void weak_order() = delete; // Block unqualified name lookup
#else // ^^^ no workaround / workaround vvv
void weak_order();
#endif // ^^^ workaround ^^^

template <class _Ty1, class _Ty2>
concept _Has_ADL =
requires(_Ty1& _Left, _Ty2& _Right) { static_cast<weak_ordering>(/* ADL */ weak_order(_Left, _Right)); };
concept _Has_ADL = requires(_Ty1& _Left, _Ty2& _Right) {
static_cast<weak_ordering>(weak_order(_Left, _Right)); // intentional ADL
};

template <class _Ty1, class _Ty2>
concept _Can_compare_three_way =
requires(_Ty1& _Left, _Ty2& _Right) { static_cast<weak_ordering>(compare_three_way{}(_Left, _Right)); };

// Throughput optimization: attempting to use _STD strong_order will always select ADL strong_order here.
void strong_order(); // Block unqualified name lookup; see GH-1374.
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199
void strong_order() = delete; // Block unqualified name lookup
#else // ^^^ no workaround / workaround vvv
void strong_order();
#endif // ^^^ workaround ^^^

class _Cpo {
private:
Expand All @@ -474,16 +488,16 @@ namespace _Weak_order {
return {_St::_None};
} else if constexpr (_Has_ADL<_Ty1, _Ty2>) {
return {_St::_Adl, noexcept(static_cast<weak_ordering>(
/* ADL */ weak_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))};
weak_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; // intentional ADL
} else if constexpr (floating_point<decay_t<_Ty1>>) {
return {_St::_Floating, true};
} else if constexpr (_Can_compare_three_way<_Ty1, _Ty2>) {
return {_St::_Three, noexcept(static_cast<weak_ordering>(
compare_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))};
} else if constexpr (_Strong_order::_Has_ADL<_Ty1, _Ty2>) {
return {_St::_Strong, noexcept(static_cast<weak_ordering>(static_cast<strong_ordering>(
/* ADL, throughput optimization */ strong_order(
_STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))};
// throughput optimization (see above):
return {_St::_Strong, noexcept(static_cast<weak_ordering>(static_cast<strong_ordering>(strong_order(
_STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; // intentional ADL
} else {
return {_St::_None};
}
Expand All @@ -499,7 +513,7 @@ namespace _Weak_order {
noexcept(_Choice<_Ty1&, _Ty2&>._No_throw) {
constexpr _St _Strat = _Choice<_Ty1&, _Ty2&>._Strategy;
if constexpr (_Strat == _St::_Adl) {
return static_cast<weak_ordering>(/* ADL */ weak_order(_Left, _Right));
return static_cast<weak_ordering>(weak_order(_Left, _Right)); // intentional ADL
} else if constexpr (_Strat == _St::_Floating) {
using _Floating_type = decay_t<_Ty1>;
using _Traits = _Floating_type_traits<_Floating_type>;
Expand Down Expand Up @@ -553,8 +567,9 @@ namespace _Weak_order {
} else if constexpr (_Strat == _St::_Three) {
return static_cast<weak_ordering>(compare_three_way{}(_Left, _Right));
} else if constexpr (_Strat == _St::_Strong) {
// throughput optimization (see above):
return static_cast<weak_ordering>(
static_cast<strong_ordering>(/* ADL, throughput optimization */ strong_order(_Left, _Right)));
static_cast<strong_ordering>(strong_order(_Left, _Right))); // intentional ADL
} else {
static_assert(_Always_false<_Ty1>, "should be unreachable");
}
Expand All @@ -567,20 +582,30 @@ inline namespace _Cpos {
}

namespace _Partial_order {
void partial_order(); // Block unqualified name lookup; see GH-1374.
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199
void partial_order() = delete; // Block unqualified name lookup
#else // ^^^ no workaround / workaround vvv
void partial_order();
#endif // ^^^ workaround ^^^

template <class _Ty1, class _Ty2>
concept _Has_ADL =
requires(_Ty1& _Left, _Ty2& _Right) { static_cast<partial_ordering>(/* ADL */ partial_order(_Left, _Right)); };
concept _Has_ADL = requires(_Ty1& _Left, _Ty2& _Right) {
static_cast<partial_ordering>(partial_order(_Left, _Right)); // intentional ADL
};

template <class _Ty1, class _Ty2>
concept _Can_compare_three_way =
requires(_Ty1& _Left, _Ty2& _Right) { static_cast<partial_ordering>(compare_three_way{}(_Left, _Right)); };

// Throughput optimization: attempting to use _STD weak_order
// will attempt to select ADL weak_order, followed by ADL strong_order, here.
void weak_order(); // Block unqualified name lookup; see GH-1374.
void strong_order(); // Block unqualified name lookup; see GH-1374.
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199
void weak_order() = delete; // Block unqualified name lookup
void strong_order() = delete; // Block unqualified name lookup
#else // ^^^ no workaround / workaround vvv
void weak_order();
void strong_order();
#endif // ^^^ workaround ^^^

class _Cpo {
private:
Expand All @@ -591,19 +616,19 @@ namespace _Partial_order {
if constexpr (!same_as<decay_t<_Ty1>, decay_t<_Ty2>>) {
return {_St::_None};
} else if constexpr (_Has_ADL<_Ty1, _Ty2>) {
return {_St::_Adl, noexcept(static_cast<partial_ordering>(
/* ADL */ partial_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))};
return {_St::_Adl, noexcept(static_cast<partial_ordering>(partial_order(
_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))}; // intentional ADL
} else if constexpr (_Can_compare_three_way<_Ty1, _Ty2>) {
return {_St::_Three, noexcept(static_cast<partial_ordering>(
compare_three_way{}(_STD declval<_Ty1&>(), _STD declval<_Ty2&>())))};
} else if constexpr (_Weak_order::_Has_ADL<_Ty1, _Ty2>) {
return {_St::_Weak,
noexcept(static_cast<partial_ordering>(static_cast<weak_ordering>(
/* ADL, throughput optimization */ weak_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))};
// throughput optimization (see above):
return {_St::_Weak, noexcept(static_cast<partial_ordering>(static_cast<weak_ordering>(
weak_order(_STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; // intentional ADL
} else if constexpr (_Strong_order::_Has_ADL<_Ty1, _Ty2>) {
return {_St::_Strong, noexcept(static_cast<partial_ordering>(static_cast<strong_ordering>(
/* ADL, throughput optimization */ strong_order(
_STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))};
// throughput optimization (see above):
return {_St::_Strong, noexcept(static_cast<partial_ordering>(static_cast<strong_ordering>(strong_order(
_STD declval<_Ty1&>(), _STD declval<_Ty2&>()))))}; // intentional ADL
} else {
return {_St::_None};
}
Expand All @@ -623,11 +648,13 @@ namespace _Partial_order {
} else if constexpr (_Strat == _St::_Three) {
return static_cast<partial_ordering>(compare_three_way{}(_Left, _Right));
} else if constexpr (_Strat == _St::_Weak) {
// throughput optimization (see above):
return static_cast<partial_ordering>(
static_cast<weak_ordering>(/* ADL, throughput optimization */ weak_order(_Left, _Right)));
static_cast<weak_ordering>(weak_order(_Left, _Right))); // intentional ADL
} else if constexpr (_Strat == _St::_Strong) {
// throughput optimization (see above):
return static_cast<partial_ordering>(
static_cast<strong_ordering>(/* ADL, throughput optimization */ strong_order(_Left, _Right)));
static_cast<strong_ordering>(strong_order(_Left, _Right))); // intentional ADL
} else {
static_assert(_Always_false<_Ty1>, "should be unreachable");
}
Expand Down
6 changes: 3 additions & 3 deletions stl/inc/concepts
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,15 @@ namespace ranges {
template <class _Ty1, class _Ty2>
concept _Use_ADL_swap = (_Has_class_or_enum_type<_Ty1> || _Has_class_or_enum_type<_Ty2>)
&& requires(_Ty1&& __t, _Ty2&& __u) {
swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u));
swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)); // intentional ADL
};

struct _Cpo {
template <class _Ty1, class _Ty2>
requires _Use_ADL_swap<_Ty1, _Ty2>
constexpr void operator()(_Ty1&& __t, _Ty2&& __u) const
noexcept(noexcept(swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)))) {
swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u));
noexcept(noexcept(swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)))) { // intentional ADL
swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)); // intentional ADL
}

template <class _Ty>
Expand Down
6 changes: 5 additions & 1 deletion stl/inc/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -2052,7 +2052,11 @@ inline constexpr bool is_nothrow_swappable_v = _Is_nothrow_swappable<_Ty>::value
#endif // _HAS_CXX17

namespace _Has_ADL_swap_detail {
void swap(); // undefined (deliberate shadowing)
#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199
void swap() = delete; // Block unqualified name lookup
#else // ^^^ no workaround / workaround vvv
void swap();
#endif // ^^^ workaround ^^^

template <class, class = void>
struct _Has_ADL_swap : false_type {};
Expand Down
Loading

0 comments on commit 214e014

Please sign in to comment.