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