Skip to content

Commit

Permalink
<variant>: P0608R3 Improving variant's converting constructor/assignm…
Browse files Browse the repository at this point in the history
…ent (#1629)

Co-authored-by: Casey Carter <[email protected]>
Co-authored-by: Igor Zhukov <[email protected]>
Co-authored-by: S. B. Tam <[email protected]>
Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
5 people authored Feb 18, 2021
1 parent 8f79acf commit 87152f4
Show file tree
Hide file tree
Showing 7 changed files with 338 additions and 28 deletions.
30 changes: 24 additions & 6 deletions stl/inc/variant
Original file line number Diff line number Diff line change
Expand Up @@ -967,18 +967,35 @@ using _Variant_destroy_layer = conditional_t<conjunction_v<is_trivially_destruct
#pragma warning(disable : 4365) // '%s': conversion from '%s' to '%s', signed/unsigned mismatch
#pragma warning(disable : 5215) // '%s' a function parameter with volatile qualified type is deprecated in C++20
#endif // __clang__
template <size_t _Idx, class _Ty>

#if _HAS_CXX20
// build Ti x[] = {std::forward<T>(t)};
template <size_t _Idx, class _TargetType>
auto _Construct_array(_TargetType(&&)[1]) -> _Meta_list<integral_constant<size_t, _Idx>, _TargetType>;

template <size_t _Idx, class _TargetType, class _InitializerType>
using _Variant_type_resolver = decltype(_Construct_array<_Idx, _TargetType>({_STD declval<_InitializerType>()}));
#endif // _HAS_CXX20

template <size_t _Idx, class _TargetType>
struct _Variant_init_single_overload {
using _FTy = _Meta_list<integral_constant<size_t, _Idx>, _Ty> (*)(_Ty);
operator _FTy();
#if _HAS_CXX20
template <class _InitializerType>
auto operator()(_TargetType, _InitializerType&&) -> _Variant_type_resolver<_Idx, _TargetType, _InitializerType>;
#else // _HAS_CXX20
template <class _InitializerType>
auto operator()(_TargetType, _InitializerType&&) -> _Meta_list<integral_constant<size_t, _Idx>, _TargetType>;
#endif // _HAS_CXX20
};

template <class _Indices, class... _Types>
struct _Variant_init_overload_set_;

template <size_t... _Indices, class... _Types>
struct _Variant_init_overload_set_<index_sequence<_Indices...>, _Types...>
: _Variant_init_single_overload<_Indices, _Types>... {};
: _Variant_init_single_overload<_Indices, _Types>... {
using _Variant_init_single_overload<_Indices, _Types>::operator()...;
};

template <class... _Types>
using _Variant_init_overload_set = _Variant_init_overload_set_<index_sequence_for<_Types...>, _Types...>;
Expand All @@ -987,11 +1004,12 @@ template <class Enable, class _Ty, class... _Types>
struct _Variant_init_helper {}; // failure case (has no member "type")

template <class _Ty, class... _Types>
struct _Variant_init_helper<void_t<decltype(_Variant_init_overload_set<_Types...>{}(_STD declval<_Ty>()))>, _Ty,
struct _Variant_init_helper<
void_t<decltype(_Variant_init_overload_set<_Types...>{}(_STD declval<_Ty>(), _STD declval<_Ty>()))>, _Ty,
_Types...> {
// perform overload resolution to determine the unique alternative that should be initialized in
// variant<_Types...> from an argument expression with type and value category _Ty
using type = decltype(_Variant_init_overload_set<_Types...>{}(_STD declval<_Ty>()));
using type = decltype(_Variant_init_overload_set<_Types...>{}(_STD declval<_Ty>(), _STD declval<_Ty>()));
};

template <class _Ty, class... _Types> // extract the type from _Variant_init_helper
Expand Down
1 change: 1 addition & 0 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
// P0556R3 <bit> Integral Power-Of-2 Operations (renamed by P1956R1)
// P0586R2 Integer Comparison Functions
// P0595R2 is_constant_evaluated()
// P0608R3 Improving variant's Converting Constructor/Assignment
// P0616R0 Using move() In <numeric>
// P0631R8 <numbers> Math Constants
// P0646R1 list/forward_list remove()/remove_if()/unique() Return size_type
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ tests\P0556R3_bit_integral_power_of_two_operations
tests\P0586R2_integer_comparison
tests\P0595R2_is_constant_evaluated
tests\P0607R0_inline_variables
tests\P0608R3_improved_variant_converting_constructor
tests\P0616R0_using_move_in_numeric
tests\P0631R8_numbers_math_constants
tests\P0660R10_jthread_and_cv_any
Expand Down
10 changes: 5 additions & 5 deletions tests/std/tests/P0088R3_variant/env.lst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ RUNALL_CROSSLIST
PM_CL="/w14640 /Zc:threadSafeInit-"
RUNALL_CROSSLIST
PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /Zc:noexceptTypes-"
PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++17 /DCONSTEXPR_NOTHROW"
PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++17 /DCONSTEXPR_NOTHROW /DTEST_PERMISSIVE"
PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-"
PM_CL="/EHsc /MD /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /Zc:char8_t- /Zc:preprocessor"
PM_CL="/EHsc /MDd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /Zc:wchar_t-"
Expand All @@ -22,15 +22,15 @@ PM_CL="/EHsc /MT /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /analyze:
PM_CL="/EHsc /MT /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-"
PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=0 /std:c++latest /permissive- /fp:strict"
PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=1 /std:c++latest /permissive-"
PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive /DCONSTEXPR_NOTHROW"
PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive /DCONSTEXPR_NOTHROW /DTEST_PERMISSIVE"
PM_CL="/EHsc /MTd /D_ITERATOR_DEBUG_LEVEL=2 /std:c++latest /permissive- /analyze:only /analyze:autolog-"
PM_CL="/Za /EHsc /MD /std:c++latest /permissive-"
PM_CL="/Za /EHsc /MDd /std:c++latest /permissive-"
PM_CL="/clr /MD /std:c++17 /DCONSTEXPR_NOTHROW"
PM_CL="/clr /MDd /std:c++17 /DCONSTEXPR_NOTHROW"
PM_CL="/clr /MD /std:c++17 /DCONSTEXPR_NOTHROW /DTEST_PERMISSIVE"
PM_CL="/clr /MDd /std:c++17 /DCONSTEXPR_NOTHROW /DTEST_PERMISSIVE"
PM_CL="/BE /c /EHsc /MD /std:c++latest /permissive-"
PM_CL="/BE /c /EHsc /MDd /std:c++17 /permissive-"
PM_CL="/BE /c /EHsc /MTd /std:c++latest /permissive-"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /EHsc /MD /std:c++latest /permissive-"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /EHsc /MDd /std:c++17"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /EHsc /MDd /std:c++17 /DTEST_PERMISSIVE"
PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing /EHsc /MTd /std:c++latest /permissive- /fp:strict"
57 changes: 40 additions & 17 deletions tests/std/tests/P0088R3_variant/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1768,7 +1768,8 @@ int run_test()
{
static_assert(!std::is_assignable<std::variant<int, int>, int>::value, "");
static_assert(!std::is_assignable<std::variant<long, long long>, int>::value, "");
#if 0 // TRANSITION, P0608
#if _HAS_CXX20
#ifndef __EDG__ // TRANSITION, DevCom-1337958
static_assert(std::is_assignable<std::variant<char>, int>::value == VariantAllowsNarrowingConversions, "");

static_assert(std::is_assignable<std::variant<std::string, float>, int>::value
Expand All @@ -1778,13 +1779,16 @@ int run_test()
static_assert(!std::is_assignable<std::variant<std::string, bool>, int>::value, "");

static_assert(!std::is_assignable<std::variant<int, bool>, decltype("meow")>::value, "");
#endif // !__EDG__
static_assert(!std::is_assignable<std::variant<int, const bool>, decltype("meow")>::value, "");
static_assert(!std::is_assignable<std::variant<int, const volatile bool>, decltype("meow")>::value, "");

static_assert(!std::is_assignable<std::variant<bool>, std::true_type>::value, "");
static_assert(std::is_assignable<std::variant<bool>, std::true_type>::value, "");
static_assert(!std::is_assignable<std::variant<bool>, std::unique_ptr<char> >::value, "");
#ifndef TEST_PERMISSIVE
static_assert(!std::is_assignable<std::variant<bool>, decltype(nullptr)>::value, "");
#endif // TRANSITION, P0608
#endif // !TEST_PERMISSIVE
#endif // _HAS_CXX20

return 0;
}
Expand Down Expand Up @@ -3048,7 +3052,8 @@ void test_T_assignment_sfinae() {
using V = std::variant<std::string, void *>;
static_assert(!std::is_assignable<V, int>::value, "no matching operator=");
}
#if 0 // TRANSITION, P0608
#if _HAS_CXX20
#ifndef __EDG__ // TRANSITION, DevCom-1337958
{
using V = std::variant<std::string, float>;
static_assert(std::is_assignable<V, int>::value == VariantAllowsNarrowingConversions,
Expand All @@ -3063,10 +3068,11 @@ void test_T_assignment_sfinae() {
};
static_assert(!std::is_assignable<V, X>::value,
"no boolean conversion in operator=");
static_assert(!std::is_assignable<V, std::false_type>::value,
static_assert(std::is_assignable<V, std::false_type>::value,
"no converted to bool in operator=");
}
#endif // TRANSITION, P0608
#endif // !__EDG__
#endif // _HAS_CXX20
{
struct X {};
struct Y {
Expand Down Expand Up @@ -3104,7 +3110,8 @@ void test_T_assignment_basic() {
assert(v.index() == 1);
assert(std::get<1>(v) == 43);
}
#if 0 // TRANSITION, P0608
#if _HAS_CXX20
#ifndef __EDG__ // TRANSITION, DevCom-1337958
#ifndef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
{
std::variant<unsigned, long> v;
Expand All @@ -3116,19 +3123,22 @@ void test_T_assignment_basic() {
assert(std::get<0>(v) == 43);
}
#endif
#endif // !__EDG__
{
std::variant<std::string, bool> v = true;
v = "bar";
assert(v.index() == 0);
assert(std::get<0>(v) == "bar");
}
#ifndef TEST_PERMISSIVE
{
std::variant<bool, std::unique_ptr<int>> v;
v = nullptr;
assert(v.index() == 1);
assert(std::get<1>(v) == nullptr);
}
#endif // TRANSITION, P0608
#endif // !TEST_PERMISSIVE
#endif // _HAS_CXX20
{
std::variant<bool volatile, int> v = 42;
v = false;
Expand Down Expand Up @@ -3266,7 +3276,8 @@ int run_test()
{
static_assert(!std::is_constructible<std::variant<int, int>, int>::value, "");
static_assert(!std::is_constructible<std::variant<long, long long>, int>::value, "");
#if 0 // TRANSITION, P0608
#if _HAS_CXX20
#ifndef __EDG__ // TRANSITION, DevCom-1337958
static_assert(std::is_constructible<std::variant<char>, int>::value == VariantAllowsNarrowingConversions, "");

static_assert(std::is_constructible<std::variant<std::string, float>, int>::value
Expand All @@ -3278,11 +3289,13 @@ int run_test()
static_assert(!std::is_constructible<std::variant<int, bool>, decltype("meow")>::value, "");
static_assert(!std::is_constructible<std::variant<int, const bool>, decltype("meow")>::value, "");
static_assert(!std::is_constructible<std::variant<int, const volatile bool>, decltype("meow")>::value, "");

static_assert(!std::is_constructible<std::variant<bool>, std::true_type>::value, "");
#endif // !__EDG__
static_assert(std::is_constructible<std::variant<bool>, std::true_type>::value, "");
static_assert(!std::is_constructible<std::variant<bool>, std::unique_ptr<char> >::value, "");
#ifndef TEST_PERMISSIVE
static_assert(!std::is_constructible<std::variant<bool>, decltype(nullptr)>::value, "");
#endif // TRANSITION, P0608
#endif // !TEST_PERMISSIVE
#endif // _HAS_CXX20

return 0;
}
Expand Down Expand Up @@ -4567,7 +4580,8 @@ void test_T_ctor_sfinae() {
static_assert(!std::is_constructible<V, int>::value,
"no matching constructor");
}
#if 0 // TRANSITION, P0608
#if _HAS_CXX20
#ifndef __EDG__ // TRANSITION, DevCom-1337958
{
using V = std::variant<std::string, float>;
static_assert(std::is_constructible<V, int>::value == VariantAllowsNarrowingConversions,
Expand All @@ -4582,10 +4596,11 @@ void test_T_ctor_sfinae() {
};
static_assert(!std::is_constructible<V, X>::value,
"no boolean conversion in constructor");
static_assert(!std::is_constructible<V, std::false_type>::value,
static_assert(std::is_constructible<V, std::false_type>::value,
"no converted to bool in constructor");
}
#endif // TRANSITION, P0608
#endif // !__EDG__
#endif // _HAS_CXX20
{
struct X {};
struct Y {
Expand Down Expand Up @@ -4629,25 +4644,29 @@ void test_T_ctor_basic() {
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v) == 42, "");
}
#if 0 // TRANSITION, P0608
#if _HAS_CXX20
#ifndef __EDG__ // TRANSITION, DevCom-1337958
#ifndef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
{
constexpr std::variant<unsigned, long> v(42);
static_assert(v.index() == 1, "");
static_assert(std::get<1>(v) == 42, "");
}
#endif
#endif // !__EDG__
{
std::variant<std::string, bool const> v = "meow";
assert(v.index() == 0);
assert(std::get<0>(v) == "meow");
}
#ifndef TEST_PERMISSIVE
{
std::variant<bool volatile, std::unique_ptr<int>> v = nullptr;
assert(v.index() == 1);
assert(std::get<1>(v) == nullptr);
}
#endif // TRANSITION, P0608
#endif // !TEST_PERMISSIVE
#endif // _HAS_CXX20
{
std::variant<bool volatile const, int> v = true;
assert(v.index() == 0);
Expand Down Expand Up @@ -4681,6 +4700,7 @@ void test_T_ctor_basic() {
#endif
}

#if !_HAS_CXX20 // Narrowing check occurs with P0608R3
struct BoomOnAnything {
template <class T>
constexpr BoomOnAnything(T) { static_assert(!std::is_same<T, T>::value, ""); }
Expand All @@ -4692,6 +4712,7 @@ void test_no_narrowing_check_for_class_types() {
assert(v.index() == 0);
assert(std::get<0>(v) == 42);
}
#endif // Narrowing check occurs with P0608R3

struct Bar {};
struct Baz {};
Expand All @@ -4708,7 +4729,9 @@ int run_test() {
test_T_ctor_basic();
test_T_ctor_noexcept();
test_T_ctor_sfinae();
#if !_HAS_CXX20 // Narrowing check occurs with P0608R3
test_no_narrowing_check_for_class_types();
#endif // Narrowing check occurs with P0608R3
test_construction_with_repeated_types();
return 0;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_latest_matrix.lst
Loading

0 comments on commit 87152f4

Please sign in to comment.