diff options
author | Zhihao Yuan <zy@miator.net> | 2019-06-18 15:26:50 +0000 |
---|---|---|
committer | Zhihao Yuan <zy@miator.net> | 2019-06-18 15:26:50 +0000 |
commit | c74fc6d5f96f2eb918425a6b93587fcd9055878f (patch) | |
tree | 23f7bc17ac4b46607f250bb6c575339ad63264c1 /libcxx/test/std/utilities | |
parent | df9ee08b649afd5c1e8eb6e798b97011e8f78cc2 (diff) | |
download | bcm5719-llvm-c74fc6d5f96f2eb918425a6b93587fcd9055878f.tar.gz bcm5719-llvm-c74fc6d5f96f2eb918425a6b93587fcd9055878f.zip |
[libc++] Implement P0608R3 - A sane variant converting constructor
Summary:
Prefer user-defined conversions over narrowing conversions and conversions to bool.
References:
http://wg21.link/p0608
Reviewers: EricWF, mpark, mclow.lists
Reviewed By: mclow.lists
Subscribers: zoecarver, ldionne, libcxx-commits, cfe-commits, christof
Differential Revision: https://reviews.llvm.org/D44865
llvm-svn: 363692
Diffstat (limited to 'libcxx/test/std/utilities')
4 files changed, 207 insertions, 3 deletions
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp index 02498b1acde..b2b53d6c6ea 100644 --- a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -22,6 +22,7 @@ #include <string> #include <type_traits> #include <variant> +#include <memory> #include "test_macros.h" #include "variant_test_helpers.hpp" @@ -122,7 +123,7 @@ void test_T_assignment_noexcept() { void test_T_assignment_sfinae() { { - using V = std::variant<long, unsigned>; + using V = std::variant<long, long long>; static_assert(!std::is_assignable<V, int>::value, "ambiguous"); } { @@ -133,6 +134,31 @@ void test_T_assignment_sfinae() { using V = std::variant<std::string, void *>; static_assert(!std::is_assignable<V, int>::value, "no matching operator="); } + { + using V = std::variant<std::string, float>; + static_assert(!std::is_assignable<V, int>::value, "no matching operator="); + } + { + using V = std::variant<std::unique_ptr<int>, bool>; + static_assert(!std::is_assignable<V, std::unique_ptr<char>>::value, + "no explicit bool in operator="); + struct X { + operator void*(); + }; + static_assert(!std::is_assignable<V, X>::value, + "no boolean conversion in operator="); + static_assert(!std::is_assignable<V, std::false_type>::value, + "no converted to bool in operator="); + } + { + struct X {}; + struct Y { + operator X(); + }; + using V = std::variant<X>; + static_assert(std::is_assignable<V, Y>::value, + "regression on user-defined conversions in operator="); + } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant<int, int &&>; @@ -161,6 +187,37 @@ void test_T_assignment_basic() { assert(v.index() == 1); assert(std::get<1>(v) == 43); } + { + std::variant<unsigned, long> v; + v = 42; + assert(v.index() == 1); + assert(std::get<1>(v) == 42); + v = 43u; + assert(v.index() == 0); + assert(std::get<0>(v) == 43); + } + { + std::variant<std::string, bool> v = true; + v = "bar"; + assert(v.index() == 0); + assert(std::get<0>(v) == "bar"); + } + { + std::variant<bool, std::unique_ptr<int>> v; + v = nullptr; + assert(v.index() == 1); + assert(std::get<1>(v) == nullptr); + } + { + std::variant<bool volatile, int> v = 42; + v = false; + assert(v.index() == 0); + assert(!std::get<0>(v)); + bool lvt = true; + v = lvt; + assert(v.index() == 0); + assert(std::get<0>(v)); + } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant<int &, int &&, long>; diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.fail.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.fail.cpp new file mode 100644 index 00000000000..d5f370d2720 --- /dev/null +++ b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.fail.cpp @@ -0,0 +1,52 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <variant> + +// template <class ...Types> class variant; + +// template <class T> +// variant& operator=(T&&) noexcept(see below); + +#include <variant> +#include <string> +#include <memory> + +int main(int, char**) +{ + std::variant<int, int> v1; + std::variant<long, long long> v2; + std::variant<char> v3; + v1 = 1; // expected-error {{no viable overloaded '='}} + v2 = 1; // expected-error {{no viable overloaded '='}} + v3 = 1; // expected-error {{no viable overloaded '='}} + + std::variant<std::string, float> v4; + std::variant<std::string, double> v5; + std::variant<std::string, bool> v6; + v4 = 1; // expected-error {{no viable overloaded '='}} + v5 = 1; // expected-error {{no viable overloaded '='}} + v6 = 1; // expected-error {{no viable overloaded '='}} + + std::variant<int, bool> v7; + std::variant<int, bool const> v8; + std::variant<int, bool volatile> v9; + v7 = "meow"; // expected-error {{no viable overloaded '='}} + v8 = "meow"; // expected-error {{no viable overloaded '='}} + v9 = "meow"; // expected-error {{no viable overloaded '='}} + + std::variant<bool> v10; + std::variant<bool> v11; + std::variant<bool> v12; + v10 = std::true_type(); // expected-error {{no viable overloaded '='}} + v11 = std::unique_ptr<char>(); // expected-error {{no viable overloaded '='}} + v12 = nullptr; // expected-error {{no viable overloaded '='}} +} diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp index 73bd2c6283d..40fa20b4f5e 100644 --- a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp @@ -20,8 +20,8 @@ #include <string> #include <type_traits> #include <variant> +#include <memory> -#include "test_convertible.hpp" #include "test_macros.h" #include "variant_test_helpers.hpp" @@ -39,6 +39,8 @@ struct NoThrowT { struct AnyConstructible { template <typename T> AnyConstructible(T&&) {} }; struct NoConstructible { NoConstructible() = delete; }; +template <class T> +struct RValueConvertibleFrom { RValueConvertibleFrom(T&&) {} }; void test_T_ctor_noexcept() { { @@ -53,7 +55,7 @@ void test_T_ctor_noexcept() { void test_T_ctor_sfinae() { { - using V = std::variant<long, unsigned>; + using V = std::variant<long, long long>; static_assert(!std::is_constructible<V, int>::value, "ambiguous"); } { @@ -66,6 +68,32 @@ void test_T_ctor_sfinae() { "no matching constructor"); } { + using V = std::variant<std::string, float>; + static_assert(!std::is_constructible<V, int>::value, + "no matching constructor"); + } + { + using V = std::variant<std::unique_ptr<int>, bool>; + static_assert(!std::is_constructible<V, std::unique_ptr<char>>::value, + "no explicit bool in constructor"); + struct X { + operator void*(); + }; + static_assert(!std::is_constructible<V, X>::value, + "no boolean conversion in constructor"); + static_assert(!std::is_constructible<V, std::false_type>::value, + "no converted to bool in constructor"); + } + { + struct X {}; + struct Y { + operator X(); + }; + using V = std::variant<X>; + static_assert(std::is_constructible<V, Y>::value, + "regression on user-defined conversions in constructor"); + } + { using V = std::variant<AnyConstructible, NoConstructible>; static_assert( !std::is_constructible<V, std::in_place_type_t<NoConstructible>>::value, @@ -99,6 +127,34 @@ void test_T_ctor_basic() { static_assert(v.index() == 1, ""); static_assert(std::get<1>(v) == 42, ""); } + { + constexpr std::variant<unsigned, long> v(42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + std::variant<std::string, bool const> v = "foo"; + assert(v.index() == 0); + assert(std::get<0>(v) == "foo"); + } + { + std::variant<bool volatile, std::unique_ptr<int>> v = nullptr; + assert(v.index() == 1); + assert(std::get<1>(v) == nullptr); + } + { + std::variant<bool volatile const, int> v = true; + assert(v.index() == 0); + assert(std::get<0>(v)); + } + { + std::variant<RValueConvertibleFrom<int>> v1 = 42; + assert(v1.index() == 0); + + int x = 42; + std::variant<RValueConvertibleFrom<int>, AnyConstructible> v2 = x; + assert(v2.index() == 1); + } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant<const int &, int &&, long>; diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.fail.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.fail.cpp new file mode 100644 index 00000000000..76b42ac226d --- /dev/null +++ b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.fail.cpp @@ -0,0 +1,39 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// <variant> + +// template <class ...Types> class variant; + +// template <class T> constexpr variant(T&&) noexcept(see below); + +#include <variant> +#include <string> +#include <memory> + +int main(int, char**) +{ + std::variant<int, int> v1 = 1; // expected-error {{no viable conversion}} + std::variant<long, long long> v2 = 1; // expected-error {{no viable conversion}} + std::variant<char> v3 = 1; // expected-error {{no viable conversion}} + + std::variant<std::string, float> v4 = 1; // expected-error {{no viable conversion}} + std::variant<std::string, double> v5 = 1; // expected-error {{no viable conversion}} + std::variant<std::string, bool> v6 = 1; // expected-error {{no viable conversion}} + + std::variant<int, bool> v7 = "meow"; // expected-error {{no viable conversion}} + std::variant<int, bool const> v8 = "meow"; // expected-error {{no viable conversion}} + std::variant<int, bool volatile> v9 = "meow"; // expected-error {{no viable conversion}} + + std::variant<bool> v10 = std::true_type(); // expected-error {{no viable conversion}} + std::variant<bool> v11 = std::unique_ptr<char>(); // expected-error {{no viable conversion}} + std::variant<bool> v12 = nullptr; // expected-error {{no viable conversion}} +} |