From 4513f0f0224fd34bbebfdc7aa6bb78a995a6ac7b Mon Sep 17 00:00:00 2001 From: Zhihao Yuan Date: Thu, 20 Jun 2019 22:09:40 +0000 Subject: [PATCH] [libc++] Recommit r363692 to implement P0608R3 Re-apply the change which was reverted in r363764 as-is after breakages being resolved. Thanks Eric Fiselier for working hard on this. See also: https://bugs.llvm.org/show_bug.cgi?id=42330 Differential Revision: https://reviews.llvm.org/D44865 llvm-svn: 363993 --- libcxx/include/variant | 32 +++++++++- .../variant.variant/variant.assign/T.pass.cpp | 59 +++++++++++++++++- .../variant.assign/conv.fail.cpp | 52 ++++++++++++++++ .../variant.variant/variant.ctor/T.pass.cpp | 60 ++++++++++++++++++- .../variant.ctor/conv.fail.cpp | 39 ++++++++++++ libcxx/www/cxx2a_status.html | 2 +- 6 files changed, 238 insertions(+), 6 deletions(-) create mode 100644 libcxx/test/std/utilities/variant/variant.variant/variant.assign/conv.fail.cpp create mode 100644 libcxx/test/std/utilities/variant/variant.variant/variant.ctor/conv.fail.cpp diff --git a/libcxx/include/variant b/libcxx/include/variant index 5d0722b62960..baf163050dd8 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -1098,11 +1098,39 @@ struct __overload<> { void operator()() const; }; template struct __overload<_Tp, _Types...> : __overload<_Types...> { using __overload<_Types...>::operator(); - __identity<_Tp> operator()(_Tp) const; + + static auto __test(_Tp (&&)[1]) -> __identity<_Tp>; + + template + auto operator()(_Tp, _Up&& __t) const + -> decltype(__test({ _VSTD::forward<_Up>(__t) })); }; +template +struct __overload_bool : _Base { + using _Base::operator(); + + template > + auto operator()(bool, _Up&&) const + -> enable_if_t, __identity<_Tp>>; +}; + +template +struct __overload + : __overload_bool<__overload<_Types...>, bool> {}; +template +struct __overload + : __overload_bool<__overload<_Types...>, bool const> {}; +template +struct __overload + : __overload_bool<__overload<_Types...>, bool volatile> {}; +template +struct __overload + : __overload_bool<__overload<_Types...>, bool const volatile> {}; + template -using __best_match_t = typename result_of_t<__overload<_Types...>(_Tp&&)>::type; +using __best_match_t = + typename invoke_result_t<__overload<_Types...>, _Tp, _Tp>::type; } // __variant_detail 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 02498b1acdeb..b2b53d6c6eaf 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 #include #include +#include #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; + using V = std::variant; static_assert(!std::is_assignable::value, "ambiguous"); } { @@ -133,6 +134,31 @@ void test_T_assignment_sfinae() { using V = std::variant; static_assert(!std::is_assignable::value, "no matching operator="); } + { + using V = std::variant; + static_assert(!std::is_assignable::value, "no matching operator="); + } + { + using V = std::variant, bool>; + static_assert(!std::is_assignable>::value, + "no explicit bool in operator="); + struct X { + operator void*(); + }; + static_assert(!std::is_assignable::value, + "no boolean conversion in operator="); + static_assert(!std::is_assignable::value, + "no converted to bool in operator="); + } + { + struct X {}; + struct Y { + operator X(); + }; + using V = std::variant; + static_assert(std::is_assignable::value, + "regression on user-defined conversions in operator="); + } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant; @@ -161,6 +187,37 @@ void test_T_assignment_basic() { assert(v.index() == 1); assert(std::get<1>(v) == 43); } + { + std::variant 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 v = true; + v = "bar"; + assert(v.index() == 0); + assert(std::get<0>(v) == "bar"); + } + { + std::variant> v; + v = nullptr; + assert(v.index() == 1); + assert(std::get<1>(v) == nullptr); + } + { + std::variant 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; 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 000000000000..d5f370d2720b --- /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 + +// + +// template class variant; + +// template +// variant& operator=(T&&) noexcept(see below); + +#include +#include +#include + +int main(int, char**) +{ + std::variant v1; + std::variant v2; + std::variant v3; + v1 = 1; // expected-error {{no viable overloaded '='}} + v2 = 1; // expected-error {{no viable overloaded '='}} + v3 = 1; // expected-error {{no viable overloaded '='}} + + std::variant v4; + std::variant v5; + std::variant v6; + v4 = 1; // expected-error {{no viable overloaded '='}} + v5 = 1; // expected-error {{no viable overloaded '='}} + v6 = 1; // expected-error {{no viable overloaded '='}} + + std::variant v7; + std::variant v8; + std::variant v9; + v7 = "meow"; // expected-error {{no viable overloaded '='}} + v8 = "meow"; // expected-error {{no viable overloaded '='}} + v9 = "meow"; // expected-error {{no viable overloaded '='}} + + std::variant v10; + std::variant v11; + std::variant v12; + v10 = std::true_type(); // expected-error {{no viable overloaded '='}} + v11 = std::unique_ptr(); // 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 73bd2c6283d3..40fa20b4f5ee 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 #include #include +#include -#include "test_convertible.hpp" #include "test_macros.h" #include "variant_test_helpers.hpp" @@ -39,6 +39,8 @@ struct NoThrowT { struct AnyConstructible { template AnyConstructible(T&&) {} }; struct NoConstructible { NoConstructible() = delete; }; +template +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; + using V = std::variant; static_assert(!std::is_constructible::value, "ambiguous"); } { @@ -65,6 +67,32 @@ void test_T_ctor_sfinae() { static_assert(!std::is_constructible::value, "no matching constructor"); } + { + using V = std::variant; + static_assert(!std::is_constructible::value, + "no matching constructor"); + } + { + using V = std::variant, bool>; + static_assert(!std::is_constructible>::value, + "no explicit bool in constructor"); + struct X { + operator void*(); + }; + static_assert(!std::is_constructible::value, + "no boolean conversion in constructor"); + static_assert(!std::is_constructible::value, + "no converted to bool in constructor"); + } + { + struct X {}; + struct Y { + operator X(); + }; + using V = std::variant; + static_assert(std::is_constructible::value, + "regression on user-defined conversions in constructor"); + } { using V = std::variant; static_assert( @@ -99,6 +127,34 @@ void test_T_ctor_basic() { static_assert(v.index() == 1, ""); static_assert(std::get<1>(v) == 42, ""); } + { + constexpr std::variant v(42); + static_assert(v.index() == 1, ""); + static_assert(std::get<1>(v) == 42, ""); + } + { + std::variant v = "foo"; + assert(v.index() == 0); + assert(std::get<0>(v) == "foo"); + } + { + std::variant> v = nullptr; + assert(v.index() == 1); + assert(std::get<1>(v) == nullptr); + } + { + std::variant v = true; + assert(v.index() == 0); + assert(std::get<0>(v)); + } + { + std::variant> v1 = 42; + assert(v1.index() == 0); + + int x = 42; + std::variant, AnyConstructible> v2 = x; + assert(v2.index() == 1); + } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant; 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 000000000000..76b42ac226d9 --- /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 + +// + +// template class variant; + +// template constexpr variant(T&&) noexcept(see below); + +#include +#include +#include + +int main(int, char**) +{ + std::variant v1 = 1; // expected-error {{no viable conversion}} + std::variant v2 = 1; // expected-error {{no viable conversion}} + std::variant v3 = 1; // expected-error {{no viable conversion}} + + std::variant v4 = 1; // expected-error {{no viable conversion}} + std::variant v5 = 1; // expected-error {{no viable conversion}} + std::variant v6 = 1; // expected-error {{no viable conversion}} + + std::variant v7 = "meow"; // expected-error {{no viable conversion}} + std::variant v8 = "meow"; // expected-error {{no viable conversion}} + std::variant v9 = "meow"; // expected-error {{no viable conversion}} + + std::variant v10 = std::true_type(); // expected-error {{no viable conversion}} + std::variant v11 = std::unique_ptr(); // expected-error {{no viable conversion}} + std::variant v12 = nullptr; // expected-error {{no viable conversion}} +} diff --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html index 52993aaf7817..17f06aae76b8 100644 --- a/libcxx/www/cxx2a_status.html +++ b/libcxx/www/cxx2a_status.html @@ -115,7 +115,7 @@ P0591R4LWGUtility functions to implement uses-allocator constructionSan Diego P0595R2CWGP0595R2 std::is_constant_evaluated()San DiegoComplete9.0 P0602R4LWGvariant and optional should propagate copy/move trivialitySan DiegoComplete8.0 - P0608R3LWGA sane variant converting constructorSan Diego + P0608R3LWGA sane variant converting constructorSan DiegoComplete9.0 P0655R1LWGvisit<R>: Explicit Return Type for visitSan Diego P0771R1LWGstd::function move constructor should be noexceptSan DiegoComplete6.0 P0896R4LWGThe One Ranges ProposalSan Diego