Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

P2602R2 Poison Pills Are Too Toxic #3215

Merged
merged 3 commits into from
Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -2041,7 +2041,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