[PATCH] D44865: [libc++] Implement P0608R2 - A sane variant converting constructor
lichray updated this revision to Diff 172514. lichray added a comment. Herald added subscribers: libcxx-commits, ldionne. Updated implementation for https://reviews.llvm.org/source/clang/ Repository: rCXX libc++ https://reviews.llvm.org/D44865 Files: include/variant test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp Index: test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp === --- test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp +++ 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 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_sfinae() { { -using V = std::variant; +using V = std::variant; static_assert(!std::is_constructible::value, "ambiguous"); } { @@ -66,6 +68,32 @@ "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( !std::is_constructible>::value, @@ -99,6 +127,34 @@ 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; Index: test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp === --- test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "test_macros.h" #include "variant_test_helpers.hpp" @@ -128,7 +129,7 @@ void test_T_assignment_sfinae() { { -using V = std::variant; +using V = std::variant; static_assert(!std::is_assignable::value, "ambiguous"); } { @@ -139,6 +140,31 @@ 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; @@ -167,6 +193,37 @@ 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");
[PATCH] D44865: [libc++] Implement P0608R2 - A sane variant converting constructor
lichray updated this revision to Diff 149825. lichray added a comment. Refine coding style Repository: rCXX libc++ https://reviews.llvm.org/D44865 Files: include/variant test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp Index: test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp === --- test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "test_convertible.hpp" #include "test_macros.h" @@ -39,6 +40,8 @@ struct AnyConstructible { template AnyConstructible(T&&) {} }; struct NoConstructible { NoConstructible() = delete; }; +template +struct RValueConvertibleFrom { RValueConvertibleFrom(T&&) {} }; void test_T_ctor_noexcept() { { @@ -53,7 +56,7 @@ void test_T_ctor_sfinae() { { -using V = std::variant; +using V = std::variant; static_assert(!std::is_constructible::value, "ambiguous"); } { @@ -66,6 +69,16 @@ "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"); + } + { using V = std::variant; static_assert( !std::is_constructible>::value, @@ -99,6 +112,34 @@ 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; Index: test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp === --- test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "test_macros.h" #include "variant_test_helpers.hpp" @@ -128,7 +129,7 @@ void test_T_assignment_sfinae() { { -using V = std::variant; +using V = std::variant; static_assert(!std::is_assignable::value, "ambiguous"); } { @@ -139,6 +140,15 @@ 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="); + } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant; @@ -167,6 +177,44 @@ 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 = std::false_type(); +assert(v.index() == 1); +assert(std::get<1>(v) == false); +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); +v = std::true_type(); +assert(v.index() == 0); +assert(std::get<0>(v)); + } + { +std::variant v = 42; +assert(v.index() == 1); +assert(std::get<1>(v) == 42); +v = std::false_type(); +assert(v.index() == 0); +assert(!std::get<0>(v)); +v = true; +assert(v.index() == 0); +assert(std::get<0>(v)); + } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant; Index: include/variant === --- include/variant +++ include/variant @@ -1097,11 +1097,40 @@ template struct __overload<_Tp, _Types...> : __overload<_Types...> { using __overload<_Types...>::operator(); - __identity<_Tp> operator()(_Tp) const; + + template + auto operator()(_Tp, _Up&& __t) const + -> decltype(_Tp{_VSTD::forward<_Up>(__t)}, __identity<_Tp>()); +}; + +template +struct __ov
[PATCH] D44865: [libc++] Implement P0608R2 - A sane variant converting constructor
lichray updated this revision to Diff 149824. lichray added a comment. Preserve value category in narrowing test. Repository: rCXX libc++ https://reviews.llvm.org/D44865 Files: include/variant test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp Index: test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp === --- test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "test_convertible.hpp" #include "test_macros.h" @@ -40,6 +41,11 @@ struct AnyConstructible { template AnyConstructible(T&&) {} }; struct NoConstructible { NoConstructible() = delete; }; +template +struct RValueConvertibleFrom { +RValueConvertibleFrom(T&&) {} +}; + void test_T_ctor_noexcept() { { using V = std::variant; @@ -53,7 +59,7 @@ void test_T_ctor_sfinae() { { -using V = std::variant; +using V = std::variant; static_assert(!std::is_constructible::value, "ambiguous"); } { @@ -66,6 +72,16 @@ "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"); + } + { using V = std::variant; static_assert( !std::is_constructible>::value, @@ -99,6 +115,34 @@ 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; Index: test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp === --- test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "test_macros.h" #include "variant_test_helpers.hpp" @@ -128,7 +129,7 @@ void test_T_assignment_sfinae() { { -using V = std::variant; +using V = std::variant; static_assert(!std::is_assignable::value, "ambiguous"); } { @@ -139,6 +140,15 @@ 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="); + } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant; @@ -167,6 +177,44 @@ 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 = std::false_type(); +assert(v.index() == 1); +assert(std::get<1>(v) == false); +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); +v = std::true_type(); +assert(v.index() == 0); +assert(std::get<0>(v)); + } + { +std::variant v = 42; +assert(v.index() == 1); +assert(std::get<1>(v) == 42); +v = std::false_type(); +assert(v.index() == 0); +assert(!std::get<0>(v)); +v = true; +assert(v.index() == 0); +assert(std::get<0>(v)); + } #if !defined(TEST_VARIANT_HAS_NO_REFERENCES) { using V = std::variant; Index: include/variant === --- include/variant +++ include/variant @@ -1097,11 +1097,40 @@ template struct __overload<_Tp, _Types...> : __overload<_Types...> { using __overload<_Types...>::operator(); - __identity<_Tp> operator()(_Tp) const; + + template + auto operator()(_Tp, _Up&& __t) const + -> decltype(_Tp{_VSTD::forward<_U