Don't require relops on variant alternatives to all return the same
type.
Libc++ correctly asserts that a set of visitors for a variant all
return the same type. However, we use the visitation machinary to
perform relational operations. This causes a static assertion when
some of the alternatives relops return a UDT which is implicitly
convertible to bool instead of 'bool' exactly.
llvm-svn: 342560
diff --git a/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp b/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp
index 4337b4b..41a9535 100644
--- a/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp
@@ -85,43 +85,79 @@
}
#endif // TEST_HAS_NO_EXCEPTIONS
+struct MyBool {
+ bool value;
+ constexpr explicit MyBool(bool v) : value(v) {}
+ constexpr operator bool() const noexcept { return value; }
+};
+
+struct ComparesToMyBool {
+ int value = 0;
+};
+inline constexpr MyBool operator==(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
+ return MyBool(LHS.value == RHS.value);
+}
+inline constexpr MyBool operator!=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
+ return MyBool(LHS.value != RHS.value);
+}
+inline constexpr MyBool operator<(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
+ return MyBool(LHS.value < RHS.value);
+}
+inline constexpr MyBool operator<=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
+ return MyBool(LHS.value <= RHS.value);
+}
+inline constexpr MyBool operator>(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
+ return MyBool(LHS.value > RHS.value);
+}
+inline constexpr MyBool operator>=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept {
+ return MyBool(LHS.value >= RHS.value);
+}
+
+template <class T1, class T2>
+void test_equality_basic() {
+ {
+ using V = std::variant<T1, T2>;
+ constexpr V v1(std::in_place_index<0>, T1{42});
+ constexpr V v2(std::in_place_index<0>, T1{42});
+ static_assert(v1 == v2, "");
+ static_assert(v2 == v1, "");
+ static_assert(!(v1 != v2), "");
+ static_assert(!(v2 != v1), "");
+ }
+ {
+ using V = std::variant<T1, T2>;
+ constexpr V v1(std::in_place_index<0>, T1{42});
+ constexpr V v2(std::in_place_index<0>, T1{43});
+ static_assert(!(v1 == v2), "");
+ static_assert(!(v2 == v1), "");
+ static_assert(v1 != v2, "");
+ static_assert(v2 != v1, "");
+ }
+ {
+ using V = std::variant<T1, T2>;
+ constexpr V v1(std::in_place_index<0>, T1{42});
+ constexpr V v2(std::in_place_index<1>, T2{42});
+ static_assert(!(v1 == v2), "");
+ static_assert(!(v2 == v1), "");
+ static_assert(v1 != v2, "");
+ static_assert(v2 != v1, "");
+ }
+ {
+ using V = std::variant<T1, T2>;
+ constexpr V v1(std::in_place_index<1>, T2{42});
+ constexpr V v2(std::in_place_index<1>, T2{42});
+ static_assert(v1 == v2, "");
+ static_assert(v2 == v1, "");
+ static_assert(!(v1 != v2), "");
+ static_assert(!(v2 != v1), "");
+ }
+}
+
void test_equality() {
- {
- using V = std::variant<int, long>;
- constexpr V v1(42);
- constexpr V v2(42);
- static_assert(v1 == v2, "");
- static_assert(v2 == v1, "");
- static_assert(!(v1 != v2), "");
- static_assert(!(v2 != v1), "");
- }
- {
- using V = std::variant<int, long>;
- constexpr V v1(42);
- constexpr V v2(43);
- static_assert(!(v1 == v2), "");
- static_assert(!(v2 == v1), "");
- static_assert(v1 != v2, "");
- static_assert(v2 != v1, "");
- }
- {
- using V = std::variant<int, long>;
- constexpr V v1(42);
- constexpr V v2(42l);
- static_assert(!(v1 == v2), "");
- static_assert(!(v2 == v1), "");
- static_assert(v1 != v2, "");
- static_assert(v2 != v1, "");
- }
- {
- using V = std::variant<int, long>;
- constexpr V v1(42l);
- constexpr V v2(42l);
- static_assert(v1 == v2, "");
- static_assert(v2 == v1, "");
- static_assert(!(v1 != v2), "");
- static_assert(!(v2 != v1), "");
- }
+ test_equality_basic<int, long>();
+ test_equality_basic<ComparesToMyBool, int>();
+ test_equality_basic<int, ComparesToMyBool>();
+ test_equality_basic<ComparesToMyBool, ComparesToMyBool>();
#ifndef TEST_HAS_NO_EXCEPTIONS
{
using V = std::variant<int, MakeEmptyT>;
@@ -160,41 +196,54 @@
template <class Var>
constexpr bool test_less(const Var &l, const Var &r, bool expect_less,
bool expect_greater) {
+ static_assert(std::is_same_v<decltype(l < r), bool>, "");
+ static_assert(std::is_same_v<decltype(l <= r), bool>, "");
+ static_assert(std::is_same_v<decltype(l > r), bool>, "");
+ static_assert(std::is_same_v<decltype(l >= r), bool>, "");
+
return ((l < r) == expect_less) && (!(l >= r) == expect_less) &&
((l > r) == expect_greater) && (!(l <= r) == expect_greater);
}
-void test_relational() {
+template <class T1, class T2>
+void test_relational_basic() {
{ // same index, same value
- using V = std::variant<int, long>;
- constexpr V v1(1);
- constexpr V v2(1);
+ using V = std::variant<T1, T2>;
+ constexpr V v1(std::in_place_index<0>, T1{1});
+ constexpr V v2(std::in_place_index<0>, T1{1});
static_assert(test_less(v1, v2, false, false), "");
}
{ // same index, value < other_value
- using V = std::variant<int, long>;
- constexpr V v1(0);
- constexpr V v2(1);
+ using V = std::variant<T1, T2>;
+ constexpr V v1(std::in_place_index<0>, T1{0});
+ constexpr V v2(std::in_place_index<0>, T1{1});
static_assert(test_less(v1, v2, true, false), "");
}
{ // same index, value > other_value
- using V = std::variant<int, long>;
- constexpr V v1(1);
- constexpr V v2(0);
+ using V = std::variant<T1, T2>;
+ constexpr V v1(std::in_place_index<0>, T1{1});
+ constexpr V v2(std::in_place_index<0>, T1{0});
static_assert(test_less(v1, v2, false, true), "");
}
{ // LHS.index() < RHS.index()
- using V = std::variant<int, long>;
- constexpr V v1(0);
- constexpr V v2(0l);
+ using V = std::variant<T1, T2>;
+ constexpr V v1(std::in_place_index<0>, T1{0});
+ constexpr V v2(std::in_place_index<1>, T2{0});
static_assert(test_less(v1, v2, true, false), "");
}
{ // LHS.index() > RHS.index()
- using V = std::variant<int, long>;
- constexpr V v1(0l);
- constexpr V v2(0);
+ using V = std::variant<T1, T2>;
+ constexpr V v1(std::in_place_index<1>, T2{0});
+ constexpr V v2(std::in_place_index<0>, T1{0});
static_assert(test_less(v1, v2, false, true), "");
}
+}
+
+void test_relational() {
+ test_relational_basic<int, long>();
+ test_relational_basic<ComparesToMyBool, int>();
+ test_relational_basic<int, ComparesToMyBool>();
+ test_relational_basic<ComparesToMyBool, ComparesToMyBool>();
#ifndef TEST_HAS_NO_EXCEPTIONS
{ // LHS.index() < RHS.index(), RHS is empty
using V = std::variant<int, MakeEmptyT>;