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