1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14 10 11 // <variant> 12 13 // template <class ...Types> 14 // constexpr bool 15 // operator==(variant<Types...> const&, variant<Types...> const&) noexcept; 16 // 17 // template <class ...Types> 18 // constexpr bool 19 // operator!=(variant<Types...> const&, variant<Types...> const&) noexcept; 20 // 21 // template <class ...Types> 22 // constexpr bool 23 // operator<(variant<Types...> const&, variant<Types...> const&) noexcept; 24 // 25 // template <class ...Types> 26 // constexpr bool 27 // operator>(variant<Types...> const&, variant<Types...> const&) noexcept; 28 // 29 // template <class ...Types> 30 // constexpr bool 31 // operator<=(variant<Types...> const&, variant<Types...> const&) noexcept; 32 // 33 // template <class ...Types> 34 // constexpr bool 35 // operator>=(variant<Types...> const&, variant<Types...> const&) noexcept; 36 37 #include <cassert> 38 #include <type_traits> 39 #include <utility> 40 #include <variant> 41 42 #include "test_macros.h" 43 44 #ifndef TEST_HAS_NO_EXCEPTIONS 45 struct MakeEmptyT { 46 MakeEmptyT() = default; 47 MakeEmptyT(MakeEmptyT &&) { throw 42; } 48 MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } 49 }; 50 inline bool operator==(const MakeEmptyT &, const MakeEmptyT &) { 51 assert(false); 52 return false; 53 } 54 inline bool operator!=(const MakeEmptyT &, const MakeEmptyT &) { 55 assert(false); 56 return false; 57 } 58 inline bool operator<(const MakeEmptyT &, const MakeEmptyT &) { 59 assert(false); 60 return false; 61 } 62 inline bool operator<=(const MakeEmptyT &, const MakeEmptyT &) { 63 assert(false); 64 return false; 65 } 66 inline bool operator>(const MakeEmptyT &, const MakeEmptyT &) { 67 assert(false); 68 return false; 69 } 70 inline bool operator>=(const MakeEmptyT &, const MakeEmptyT &) { 71 assert(false); 72 return false; 73 } 74 75 template <class Variant> void makeEmpty(Variant &v) { 76 Variant v2(std::in_place_type<MakeEmptyT>); 77 try { 78 v = std::move(v2); 79 assert(false); 80 } catch (...) { 81 assert(v.valueless_by_exception()); 82 } 83 } 84 #endif // TEST_HAS_NO_EXCEPTIONS 85 86 struct MyBool { 87 bool value; 88 constexpr explicit MyBool(bool v) : value(v) {} 89 constexpr operator bool() const noexcept { return value; } 90 }; 91 92 struct ComparesToMyBool { 93 int value = 0; 94 }; 95 inline constexpr MyBool operator==(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { 96 return MyBool(LHS.value == RHS.value); 97 } 98 inline constexpr MyBool operator!=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { 99 return MyBool(LHS.value != RHS.value); 100 } 101 inline constexpr MyBool operator<(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { 102 return MyBool(LHS.value < RHS.value); 103 } 104 inline constexpr MyBool operator<=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { 105 return MyBool(LHS.value <= RHS.value); 106 } 107 inline constexpr MyBool operator>(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { 108 return MyBool(LHS.value > RHS.value); 109 } 110 inline constexpr MyBool operator>=(const ComparesToMyBool& LHS, const ComparesToMyBool& RHS) noexcept { 111 return MyBool(LHS.value >= RHS.value); 112 } 113 114 template <class T1, class T2> 115 void test_equality_basic() { 116 { 117 using V = std::variant<T1, T2>; 118 constexpr V v1(std::in_place_index<0>, T1{42}); 119 constexpr V v2(std::in_place_index<0>, T1{42}); 120 static_assert(v1 == v2, ""); 121 static_assert(v2 == v1, ""); 122 static_assert(!(v1 != v2), ""); 123 static_assert(!(v2 != v1), ""); 124 } 125 { 126 using V = std::variant<T1, T2>; 127 constexpr V v1(std::in_place_index<0>, T1{42}); 128 constexpr V v2(std::in_place_index<0>, T1{43}); 129 static_assert(!(v1 == v2), ""); 130 static_assert(!(v2 == v1), ""); 131 static_assert(v1 != v2, ""); 132 static_assert(v2 != v1, ""); 133 } 134 { 135 using V = std::variant<T1, T2>; 136 constexpr V v1(std::in_place_index<0>, T1{42}); 137 constexpr V v2(std::in_place_index<1>, T2{42}); 138 static_assert(!(v1 == v2), ""); 139 static_assert(!(v2 == v1), ""); 140 static_assert(v1 != v2, ""); 141 static_assert(v2 != v1, ""); 142 } 143 { 144 using V = std::variant<T1, T2>; 145 constexpr V v1(std::in_place_index<1>, T2{42}); 146 constexpr V v2(std::in_place_index<1>, T2{42}); 147 static_assert(v1 == v2, ""); 148 static_assert(v2 == v1, ""); 149 static_assert(!(v1 != v2), ""); 150 static_assert(!(v2 != v1), ""); 151 } 152 } 153 154 void test_equality() { 155 test_equality_basic<int, long>(); 156 test_equality_basic<ComparesToMyBool, int>(); 157 test_equality_basic<int, ComparesToMyBool>(); 158 test_equality_basic<ComparesToMyBool, ComparesToMyBool>(); 159 #ifndef TEST_HAS_NO_EXCEPTIONS 160 { 161 using V = std::variant<int, MakeEmptyT>; 162 V v1; 163 V v2; 164 makeEmpty(v2); 165 assert(!(v1 == v2)); 166 assert(!(v2 == v1)); 167 assert(v1 != v2); 168 assert(v2 != v1); 169 } 170 { 171 using V = std::variant<int, MakeEmptyT>; 172 V v1; 173 makeEmpty(v1); 174 V v2; 175 assert(!(v1 == v2)); 176 assert(!(v2 == v1)); 177 assert(v1 != v2); 178 assert(v2 != v1); 179 } 180 { 181 using V = std::variant<int, MakeEmptyT>; 182 V v1; 183 makeEmpty(v1); 184 V v2; 185 makeEmpty(v2); 186 assert(v1 == v2); 187 assert(v2 == v1); 188 assert(!(v1 != v2)); 189 assert(!(v2 != v1)); 190 } 191 #endif 192 } 193 194 template <class Var> 195 constexpr bool test_less(const Var &l, const Var &r, bool expect_less, 196 bool expect_greater) { 197 static_assert(std::is_same_v<decltype(l < r), bool>, ""); 198 static_assert(std::is_same_v<decltype(l <= r), bool>, ""); 199 static_assert(std::is_same_v<decltype(l > r), bool>, ""); 200 static_assert(std::is_same_v<decltype(l >= r), bool>, ""); 201 202 return ((l < r) == expect_less) && (!(l >= r) == expect_less) && 203 ((l > r) == expect_greater) && (!(l <= r) == expect_greater); 204 } 205 206 template <class T1, class T2> 207 void test_relational_basic() { 208 { // same index, same value 209 using V = std::variant<T1, T2>; 210 constexpr V v1(std::in_place_index<0>, T1{1}); 211 constexpr V v2(std::in_place_index<0>, T1{1}); 212 static_assert(test_less(v1, v2, false, false), ""); 213 } 214 { // same index, value < other_value 215 using V = std::variant<T1, T2>; 216 constexpr V v1(std::in_place_index<0>, T1{0}); 217 constexpr V v2(std::in_place_index<0>, T1{1}); 218 static_assert(test_less(v1, v2, true, false), ""); 219 } 220 { // same index, value > other_value 221 using V = std::variant<T1, T2>; 222 constexpr V v1(std::in_place_index<0>, T1{1}); 223 constexpr V v2(std::in_place_index<0>, T1{0}); 224 static_assert(test_less(v1, v2, false, true), ""); 225 } 226 { // LHS.index() < RHS.index() 227 using V = std::variant<T1, T2>; 228 constexpr V v1(std::in_place_index<0>, T1{0}); 229 constexpr V v2(std::in_place_index<1>, T2{0}); 230 static_assert(test_less(v1, v2, true, false), ""); 231 } 232 { // LHS.index() > RHS.index() 233 using V = std::variant<T1, T2>; 234 constexpr V v1(std::in_place_index<1>, T2{0}); 235 constexpr V v2(std::in_place_index<0>, T1{0}); 236 static_assert(test_less(v1, v2, false, true), ""); 237 } 238 } 239 240 void test_relational() { 241 test_relational_basic<int, long>(); 242 test_relational_basic<ComparesToMyBool, int>(); 243 test_relational_basic<int, ComparesToMyBool>(); 244 test_relational_basic<ComparesToMyBool, ComparesToMyBool>(); 245 #ifndef TEST_HAS_NO_EXCEPTIONS 246 { // LHS.index() < RHS.index(), RHS is empty 247 using V = std::variant<int, MakeEmptyT>; 248 V v1; 249 V v2; 250 makeEmpty(v2); 251 assert(test_less(v1, v2, false, true)); 252 } 253 { // LHS.index() > RHS.index(), LHS is empty 254 using V = std::variant<int, MakeEmptyT>; 255 V v1; 256 makeEmpty(v1); 257 V v2; 258 assert(test_less(v1, v2, true, false)); 259 } 260 { // LHS.index() == RHS.index(), LHS and RHS are empty 261 using V = std::variant<int, MakeEmptyT>; 262 V v1; 263 makeEmpty(v1); 264 V v2; 265 makeEmpty(v2); 266 assert(test_less(v1, v2, false, false)); 267 } 268 #endif 269 } 270 271 int main(int, char**) { 272 test_equality(); 273 test_relational(); 274 275 return 0; 276 } 277