diff options
author | Eric Fiselier <eric@efcs.ca> | 2018-09-19 17:53:21 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2018-09-19 17:53:21 +0000 |
commit | 7dca3127c2ad98c3f5a291d8f4878348772bb558 (patch) | |
tree | 140c2f2c236dd94d1e57d7a50c3a7819fb7d0055 /libcxx/test/std/utilities | |
parent | 6b8d75425eebee8c0c2b279ac2cf0c669d1846fe (diff) | |
download | bcm5719-llvm-7dca3127c2ad98c3f5a291d8f4878348772bb558.tar.gz bcm5719-llvm-7dca3127c2ad98c3f5a291d8f4878348772bb558.zip |
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
Diffstat (limited to 'libcxx/test/std/utilities')
-rw-r--r-- | libcxx/test/std/utilities/variant/variant.relops/relops.pass.cpp | 107 | ||||
-rw-r--r-- | libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp | 88 |
2 files changed, 166 insertions, 29 deletions
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 4337b4bdbbd..41a95355215 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 @@ template <class Variant> void makeEmpty(Variant &v) { } #endif // TEST_HAS_NO_EXCEPTIONS -void test_equality() { +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<int, long>; - constexpr V v1(42); - constexpr V v2(42); + 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<int, long>; - constexpr V v1(42); - constexpr V v2(43); + 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<int, long>; - constexpr V v1(42); - constexpr V v2(42l); + 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<int, long>; - constexpr V v1(42l); - constexpr V v2(42l); + 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() { + 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 @@ void test_equality() { 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>; diff --git a/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp b/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp new file mode 100644 index 00000000000..c0c296c11ff --- /dev/null +++ b/libcxx/test/std/utilities/variant/variant.relops/relops_bool_conv.fail.cpp @@ -0,0 +1,88 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <variant> + +// template <class ...Types> +// constexpr bool +// operator==(variant<Types...> const&, variant<Types...> const&) noexcept; +// +// template <class ...Types> +// constexpr bool +// operator!=(variant<Types...> const&, variant<Types...> const&) noexcept; +// +// template <class ...Types> +// constexpr bool +// operator<(variant<Types...> const&, variant<Types...> const&) noexcept; +// +// template <class ...Types> +// constexpr bool +// operator>(variant<Types...> const&, variant<Types...> const&) noexcept; +// +// template <class ...Types> +// constexpr bool +// operator<=(variant<Types...> const&, variant<Types...> const&) noexcept; +// +// template <class ...Types> +// constexpr bool +// operator>=(variant<Types...> const&, variant<Types...> const&) noexcept; + +#include <cassert> +#include <type_traits> +#include <utility> +#include <variant> + +#include "test_macros.h" + + +struct MyBoolExplicit { + bool value; + constexpr explicit MyBoolExplicit(bool v) : value(v) {} + constexpr explicit operator bool() const noexcept { return value; } +}; + +struct ComparesToMyBoolExplicit { + int value = 0; +}; +inline constexpr MyBoolExplicit operator==(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value == RHS.value); +} +inline constexpr MyBoolExplicit operator!=(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value != RHS.value); +} +inline constexpr MyBoolExplicit operator<(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value < RHS.value); +} +inline constexpr MyBoolExplicit operator<=(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value <= RHS.value); +} +inline constexpr MyBoolExplicit operator>(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value > RHS.value); +} +inline constexpr MyBoolExplicit operator>=(const ComparesToMyBoolExplicit& LHS, const ComparesToMyBoolExplicit& RHS) noexcept { + return MyBoolExplicit(LHS.value >= RHS.value); +} + + +int main() { + using V = std::variant<int, ComparesToMyBoolExplicit>; + V v1(42); + V v2(101); + // expected-error-re@variant:* 6 {{static_assert failed due to requirement 'std::is_convertible{{[^']+}}' "the relational operator does not return a type which is implicitly convertible to bool"}} + // expected-error@variant:* 6 {{no viable conversion}} + (void)(v1 == v2); // expected-note {{here}} + (void)(v1 != v2); // expected-note {{here}} + (void)(v1 < v2); // expected-note {{here}} + (void)(v1 <= v2); // expected-note {{here}} + (void)(v1 > v2); // expected-note {{here}} + (void)(v1 >= v2); // expected-note {{here}} +} |