From: "Tim Shen via gcc-patches" <gcc-patches@gcc.gnu.org>
To: "libstdc++" <libstdc++@gcc.gnu.org>,
gcc-patches <gcc-patches@gcc.gnu.org>
Subject: [Patch] Forward triviality in variant
Date: Tue, 30 May 2017 06:36:00 -0000 [thread overview]
Message-ID: <CAG4ZjNnp4DQXpBEs7yu-MCrfUGfk+3x=KkPZqJiQ5WWt3awnvg@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 802 bytes --]
This patch implements
<https://lichray.github.io/trivially_variant.html>, but with more
changes than the proposal's. It
1) Creates __detail::__variant::_Traits as a centralized place to hold
common (but not all yet) compile-time conditions.
2) Changes the noexcept conditions for the (copy|move) (ctor|assign)
SMFs, so that when one is trivial, one is also noexcept. It's not the
same as p0088r3, nor p0088r3 + D0602R1 anymore.
3) Creates 4 structs, namely (_Copy|_Move)_(ctor|assign)_(base|alias)
for dispatch on triviality. The code that were originally in
_Variant_base are moved into these four structs. There aren't
functional changes except for more triviality.
Sorry for having a large patch. Do tell me if you want me to split it.
Tested on x86_64-linux-gnu.
Thanks!
--
Regards,
Tim Shen
[-- Attachment #2: a.diff --]
[-- Type: text/x-patch, Size: 23828 bytes --]
commit a4db7d21c6e4223300861114931eb0ef78bef1a6
Author: Tim Shen <timshen@google.com>
Date: Mon May 29 22:44:42 2017 -0700
2017-05-30 Tim Shen <timshen@google.com>
PR libstdc++/80187
* include/std/variant (variant::variant, variant::~variant,
variant::operator=): Implement triviality forwarding for four
special member functions.
* testsuite/20_util/variant/compile.cc: Tests.
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index b9824a5182c..8736fcc75bc 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -290,6 +290,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__ref_cast<_Tp>(__t));
}
+ template<typename... _Types>
+ struct _Traits
+ {
+ static constexpr bool is_default_constructible_v =
+ is_default_constructible_v<typename _Nth_type<0, _Types...>::type>;
+ static constexpr bool is_copy_constructible_v =
+ __and_<is_copy_constructible<_Types>...>::value;
+ static constexpr bool is_move_constructible_v =
+ __and_<is_move_constructible<_Types>...>::value;
+ static constexpr bool is_copy_assignable_v =
+ is_copy_constructible_v && is_move_constructible_v
+ && __and_<is_copy_assignable<_Types>...>::value;
+ static constexpr bool is_move_assignable_v =
+ is_move_constructible_v
+ && __and_<is_move_assignable<_Types>...>::value;
+
+ static constexpr bool is_copy_ctor_trivial =
+ __and_<is_trivially_copy_constructible<_Types>...>::value;
+ static constexpr bool is_move_ctor_trivial =
+ __and_<is_trivially_move_constructible<_Types>...>::value;
+ static constexpr bool is_copy_assign_trivial =
+ __and_<is_trivially_copy_assignable<_Types>...>::value;
+ static constexpr bool is_move_assign_trivial =
+ __and_<is_trivially_move_assignable<_Types>...>::value;
+ static constexpr bool is_dtor_trivial =
+ __and_<is_trivially_destructible<_Types>...>::value;
+
+ static constexpr bool is_default_ctor_noexcept =
+ is_nothrow_default_constructible_v<
+ typename _Nth_type<0, _Types...>::type>;
+ static constexpr bool is_copy_ctor_noexcept =
+ is_copy_ctor_trivial;
+ static constexpr bool is_move_ctor_noexcept =
+ is_move_ctor_trivial
+ || __and_<is_nothrow_move_constructible<_Types>...>::value;
+ static constexpr bool is_copy_assign_noexcept =
+ is_copy_assign_trivial;
+ static constexpr bool is_move_assign_noexcept =
+ is_move_assign_trivial ||
+ (is_move_ctor_noexcept
+ && __and_<is_nothrow_move_assignable<_Types>...>::value);
+ };
+
// Defines members and ctors.
template<typename... _Types>
union _Variadic_union { };
@@ -355,6 +398,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
~_Variant_storage()
{ _M_reset(); }
+ void*
+ _M_storage() const
+ {
+ return const_cast<void*>(static_cast<const void*>(
+ std::addressof(_M_u)));
+ }
+
+ constexpr bool
+ _M_valid() const noexcept
+ {
+ return this->_M_index != __index_type(variant_npos);
+ }
+
_Variadic_union<_Types...> _M_u;
using __index_type = __select_index<_Types...>;
__index_type _M_index;
@@ -374,59 +430,114 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void _M_reset()
{ _M_index = variant_npos; }
+ void*
+ _M_storage() const
+ {
+ return const_cast<void*>(static_cast<const void*>(
+ std::addressof(_M_u)));
+ }
+
+ constexpr bool
+ _M_valid() const noexcept
+ {
+ return this->_M_index != __index_type(variant_npos);
+ }
+
_Variadic_union<_Types...> _M_u;
using __index_type = __select_index<_Types...>;
__index_type _M_index;
};
- // Helps SFINAE on special member functions. Otherwise it can live in variant
- // class.
template<typename... _Types>
- struct _Variant_base :
- _Variant_storage<(std::is_trivially_destructible_v<_Types> && ...),
- _Types...>
- {
- using _Storage =
- _Variant_storage<(std::is_trivially_destructible_v<_Types> && ...),
- _Types...>;
+ using _Variant_storage_alias =
+ _Variant_storage<_Traits<_Types...>::is_dtor_trivial, _Types...>;
- constexpr
- _Variant_base()
- noexcept(is_nothrow_default_constructible_v<
- variant_alternative_t<0, variant<_Types...>>>)
- : _Variant_base(in_place_index<0>) { }
+ // The following are (Copy|Move) (ctor|assign) layers for forwarding
+ // triviality and handling non-trivial SMF behaviors.
- _Variant_base(const _Variant_base& __rhs)
+ template<bool, typename... _Types>
+ struct _Copy_ctor_base : _Variant_storage_alias<_Types...>
+ {
+ using _Base = _Variant_storage_alias<_Types...>;
+ using _Base::_Base;
+
+ _Copy_ctor_base(const _Copy_ctor_base& __rhs)
+ noexcept(_Traits<_Types...>::is_copy_ctor_noexcept)
{
if (__rhs._M_valid())
{
static constexpr void (*_S_vtable[])(void*, void*) =
{ &__erased_ctor<_Types&, const _Types&>... };
- _S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
+ _S_vtable[__rhs._M_index](this->_M_storage(), __rhs._M_storage());
this->_M_index = __rhs._M_index;
}
}
- _Variant_base(_Variant_base&& __rhs)
- noexcept((is_nothrow_move_constructible_v<_Types> && ...))
+ _Copy_ctor_base(_Copy_ctor_base&&)
+ noexcept(_Traits<_Types...>::is_move_ctor_noexcept) = default;
+ _Copy_ctor_base& operator=(const _Copy_ctor_base&)
+ noexcept(_Traits<_Types...>::is_copy_assign_noexcept) = default;
+ _Copy_ctor_base& operator=(_Copy_ctor_base&&)
+ noexcept(_Traits<_Types...>::is_move_assign_noexcept) = default;
+ };
+
+ template<typename... _Types>
+ struct _Copy_ctor_base<true, _Types...> : _Variant_storage_alias<_Types...>
+ {
+ using _Base = _Variant_storage_alias<_Types...>;
+ using _Base::_Base;
+ };
+
+ template<typename... _Types>
+ using _Copy_ctor_alias =
+ _Copy_ctor_base<_Traits<_Types...>::is_copy_ctor_trivial, _Types...>;
+
+ template<bool, typename... _Types>
+ struct _Move_ctor_base : _Copy_ctor_alias<_Types...>
+ {
+ using _Base = _Copy_ctor_alias<_Types...>;
+ using _Base::_Base;
+
+ _Move_ctor_base(_Move_ctor_base&& __rhs)
+ noexcept(_Traits<_Types...>::is_move_ctor_noexcept)
{
if (__rhs._M_valid())
{
static constexpr void (*_S_vtable[])(void*, void*) =
{ &__erased_ctor<_Types&, _Types&&>... };
- _S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
+ _S_vtable[__rhs._M_index](this->_M_storage(), __rhs._M_storage());
this->_M_index = __rhs._M_index;
}
}
- template<size_t _Np, typename... _Args>
- constexpr explicit
- _Variant_base(in_place_index_t<_Np> __i, _Args&&... __args)
- : _Storage(__i, std::forward<_Args>(__args)...)
- { }
+ _Move_ctor_base(const _Move_ctor_base& __rhs)
+ noexcept(_Traits<_Types...>::is_copy_ctor_noexcept) = default;
+ _Move_ctor_base& operator=(const _Move_ctor_base&)
+ noexcept(_Traits<_Types...>::is_copy_assign_noexcept) = default;
+ _Move_ctor_base& operator=(_Move_ctor_base&&)
+ noexcept(_Traits<_Types...>::is_move_assign_noexcept) = default;
+ };
+
+ template<typename... _Types>
+ struct _Move_ctor_base<true, _Types...> : _Copy_ctor_alias<_Types...>
+ {
+ using _Base = _Copy_ctor_alias<_Types...>;
+ using _Base::_Base;
+ };
+
+ template<typename... _Types>
+ using _Move_ctor_alias =
+ _Move_ctor_base<_Traits<_Types...>::is_move_ctor_trivial, _Types...>;
+
+ template<bool, typename... _Types>
+ struct _Copy_assign_base : _Move_ctor_alias<_Types...>
+ {
+ using _Base = _Move_ctor_alias<_Types...>;
+ using _Base::_Base;
- _Variant_base&
- operator=(const _Variant_base& __rhs)
+ _Copy_assign_base&
+ operator=(const _Copy_assign_base& __rhs)
+ noexcept(_Traits<_Types...>::is_copy_assign_noexcept)
{
if (this->_M_index == __rhs._M_index)
{
@@ -434,16 +545,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
static constexpr void (*_S_vtable[])(void*, void*) =
{ &__erased_assign<_Types&, const _Types&>... };
- _S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
+ _S_vtable[__rhs._M_index](this->_M_storage(), __rhs._M_storage());
}
}
else
{
- _Variant_base __tmp(__rhs);
- this->~_Variant_base();
+ _Copy_assign_base __tmp(__rhs);
+ this->~_Copy_assign_base();
__try
{
- ::new (this) _Variant_base(std::move(__tmp));
+ ::new (this) _Copy_assign_base(std::move(__tmp));
}
__catch (...)
{
@@ -455,12 +566,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return *this;
}
- void _M_destructive_move(_Variant_base&& __rhs)
+ _Copy_assign_base(const _Copy_assign_base& __rhs)
+ noexcept(_Traits<_Types...>::is_copy_ctor_noexcept) = default;
+ _Copy_assign_base(_Copy_assign_base&&)
+ noexcept(_Traits<_Types...>::is_move_ctor_noexcept) = default;
+ _Copy_assign_base& operator=(_Copy_assign_base&&)
+ noexcept(_Traits<_Types...>::is_move_assign_noexcept) = default;
+ };
+
+ template<typename... _Types>
+ struct _Copy_assign_base<true, _Types...> : _Move_ctor_alias<_Types...>
+ {
+ using _Base = _Move_ctor_alias<_Types...>;
+ using _Base::_Base;
+ };
+
+ template<typename... _Types>
+ using _Copy_assign_alias =
+ _Copy_assign_base<_Traits<_Types...>::is_copy_assign_trivial,
+ _Types...>;
+
+ template<bool, typename... _Types>
+ struct _Move_assign_base : _Copy_assign_alias<_Types...>
+ {
+ using _Base = _Copy_assign_alias<_Types...>;
+ using _Base::_Base;
+
+ void _M_destructive_move(_Move_assign_base&& __rhs)
{
- this->~_Variant_base();
+ this->~_Move_assign_base();
__try
{
- ::new (this) _Variant_base(std::move(__rhs));
+ ::new (this) _Move_assign_base(std::move(__rhs));
}
__catch (...)
{
@@ -469,40 +606,81 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
}
- _Variant_base&
- operator=(_Variant_base&& __rhs)
- noexcept((is_nothrow_move_constructible_v<_Types> && ...)
- && (is_nothrow_move_assignable_v<_Types> && ...))
+ _Move_assign_base&
+ operator=(_Move_assign_base&& __rhs)
+ noexcept(_Traits<_Types...>::is_move_assign_noexcept)
{
if (this->_M_index == __rhs._M_index)
{
if (__rhs._M_valid())
{
static constexpr void (*_S_vtable[])(void*, void*) =
- { &__erased_assign<_Types&, _Types&&>... };
- _S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
+ { &__erased_assign<_Types&, const _Types&>... };
+ _S_vtable[__rhs._M_index](this->_M_storage(), __rhs._M_storage());
}
}
else
{
- _M_destructive_move(std::move(__rhs));
+ _Move_assign_base __tmp(__rhs);
+ this->~_Move_assign_base();
+ __try
+ {
+ ::new (this) _Move_assign_base(std::move(__tmp));
+ }
+ __catch (...)
+ {
+ this->_M_index = variant_npos;
+ __throw_exception_again;
+ }
}
+ __glibcxx_assert(this->_M_index == __rhs._M_index);
return *this;
}
- void*
- _M_storage() const
- {
- return const_cast<void*>(static_cast<const void*>(
- std::addressof(_Storage::_M_u)));
- }
+ _Move_assign_base(const _Move_assign_base& __rhs)
+ noexcept(_Traits<_Types...>::is_copy_ctor_noexcept) = default;
+ _Move_assign_base(_Move_assign_base&&)
+ noexcept(_Traits<_Types...>::is_move_ctor_noexcept) = default;
+ _Move_assign_base& operator=(const _Move_assign_base&)
+ noexcept(_Traits<_Types...>::is_copy_assign_noexcept) = default;
+ };
- constexpr bool
- _M_valid() const noexcept
- {
- return this->_M_index !=
- typename _Storage::__index_type(variant_npos);
- }
+ template<typename... _Types>
+ struct _Move_assign_base<true, _Types...> : _Copy_assign_alias<_Types...>
+ {
+ using _Base = _Copy_assign_alias<_Types...>;
+ using _Base::_Base;
+ };
+
+ template<typename... _Types>
+ using _Move_assign_alias =
+ _Move_assign_base<_Traits<_Types...>::is_move_assign_trivial,
+ _Types...>;
+
+ template<typename... _Types>
+ struct _Variant_base : _Move_assign_alias<_Types...>
+ {
+ using _Base = _Move_assign_alias<_Types...>;
+
+ constexpr
+ _Variant_base()
+ noexcept(_Traits<_Types...>::is_default_ctor_noexcept)
+ : _Variant_base(in_place_index<0>) { }
+
+ template<size_t _Np, typename... _Args>
+ constexpr explicit
+ _Variant_base(in_place_index_t<_Np> __i, _Args&&... __args)
+ : _Base(__i, std::forward<_Args>(__args)...)
+ { }
+
+ _Variant_base(const _Variant_base& __rhs)
+ noexcept(_Traits<_Types...>::is_copy_ctor_noexcept) = default;
+ _Variant_base(_Variant_base&&)
+ noexcept(_Traits<_Types...>::is_move_ctor_noexcept) = default;
+ _Variant_base& operator=(const _Variant_base&)
+ noexcept(_Traits<_Types...>::is_copy_assign_noexcept) = default;
+ _Variant_base& operator=(_Variant_base&&)
+ noexcept(_Traits<_Types...>::is_move_assign_noexcept) = default;
};
// For how many times does _Tp appear in _Tuple?
@@ -877,16 +1055,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
class variant
: private __detail::__variant::_Variant_base<_Types...>,
private _Enable_default_constructor<
- is_default_constructible_v<
- variant_alternative_t<0, variant<_Types...>>>, variant<_Types...>>,
+ __detail::__variant::_Traits<_Types...>::is_default_constructible_v,
+ variant<_Types...>>,
private _Enable_copy_move<
- (is_copy_constructible_v<_Types> && ...),
- (is_copy_constructible_v<_Types> && ...)
- && (is_move_constructible_v<_Types> && ...)
- && (is_copy_assignable_v<_Types> && ...),
- (is_move_constructible_v<_Types> && ...),
- (is_move_constructible_v<_Types> && ...)
- && (is_move_assignable_v<_Types> && ...),
+ __detail::__variant::_Traits<_Types...>::is_copy_constructible_v,
+ __detail::__variant::_Traits<_Types...>::is_copy_assignable_v,
+ __detail::__variant::_Traits<_Types...>::is_move_constructible_v,
+ __detail::__variant::_Traits<_Types...>::is_move_assignable_v,
variant<_Types...>>
{
private:
@@ -899,9 +1074,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
using _Base = __detail::__variant::_Variant_base<_Types...>;
using _Default_ctor_enabler =
- _Enable_default_constructor<
- is_default_constructible_v<
- variant_alternative_t<0, variant<_Types...>>>, variant<_Types...>>;
+ _Enable_default_constructor<
+ __detail::__variant::_Traits<_Types...>::is_default_constructible_v,
+ variant<_Types...>>;
template<typename _Tp>
static constexpr bool
@@ -928,12 +1103,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static constexpr size_t __index_of =
__detail::__variant::__index_of_v<_Tp, _Types...>;
+ using _Traits = __detail::__variant::_Traits<_Types...>;
+
public:
- constexpr variant()
- noexcept(is_nothrow_default_constructible_v<__to_type<0>>) = default;
- variant(const variant&) = default;
+ variant() noexcept(_Traits::is_default_ctor_noexcept) = default;
+ variant(const variant& __rhs)
+ noexcept(_Traits::is_copy_ctor_noexcept) = default;
variant(variant&&)
- noexcept((is_nothrow_move_constructible_v<_Types> && ...)) = default;
+ noexcept(_Traits::is_move_ctor_noexcept) = default;
+ variant& operator=(const variant&)
+ noexcept(_Traits::is_copy_assign_noexcept) = default;
+ variant& operator=(variant&&)
+ noexcept(_Traits::is_move_assign_noexcept) = default;
+ ~variant() = default;
template<typename _Tp,
typename = enable_if_t<!is_same_v<decay_t<_Tp>, variant>>,
@@ -942,7 +1124,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr
variant(_Tp&& __t)
noexcept(is_nothrow_constructible_v<__accepted_type<_Tp&&>, _Tp&&>)
- : variant(in_place_index<__accepted_index<_Tp&&>>, std::forward<_Tp>(__t))
+ : variant(in_place_index<__accepted_index<_Tp&&>>,
+ std::forward<_Tp>(__t))
{ __glibcxx_assert(holds_alternative<__accepted_type<_Tp&&>>(*this)); }
template<typename _Tp, typename... _Args,
@@ -950,7 +1133,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
&& is_constructible_v<_Tp, _Args&&...>>>
constexpr explicit
variant(in_place_type_t<_Tp>, _Args&&... __args)
- : variant(in_place_index<__index_of<_Tp>>, std::forward<_Args>(__args)...)
+ : variant(in_place_index<__index_of<_Tp>>,
+ std::forward<_Args>(__args)...)
{ __glibcxx_assert(holds_alternative<_Tp>(*this)); }
template<typename _Tp, typename _Up, typename... _Args,
@@ -983,13 +1167,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Default_ctor_enabler(_Enable_default_constructor_tag{})
{ __glibcxx_assert(index() == _Np); }
- ~variant() = default;
-
- variant& operator=(const variant&) = default;
- variant& operator=(variant&&)
- noexcept((is_nothrow_move_constructible_v<_Types> && ...)
- && (is_nothrow_move_assignable_v<_Types> && ...)) = default;
-
template<typename _Tp>
enable_if_t<__exactly_once<__accepted_type<_Tp&&>>
&& is_constructible_v<__accepted_type<_Tp&&>, _Tp&&>
@@ -1084,7 +1261,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr size_t index() const noexcept
{
if (this->_M_index ==
- typename _Base::_Storage::__index_type(variant_npos))
+ typename _Base::__index_type(variant_npos))
return variant_npos;
return this->_M_index;
}
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index 06e8eb31ee8..dbf5cffac57 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -88,10 +88,12 @@ void copy_ctor()
{
static_assert(is_copy_constructible_v<variant<int, string>>, "");
static_assert(!is_copy_constructible_v<variant<AllDeleted, string>>, "");
+ static_assert(is_trivially_copy_constructible_v<variant<int>>, "");
+ static_assert(!is_trivially_copy_constructible_v<variant<std::string>>, "");
{
variant<int> a;
- static_assert(!noexcept(variant<int>(a)), "");
+ static_assert(noexcept(variant<int>(a)), "");
}
{
variant<string> a;
@@ -103,7 +105,7 @@ void copy_ctor()
}
{
variant<int, char> a;
- static_assert(!noexcept(variant<int, char>(a)), "");
+ static_assert(noexcept(variant<int, char>(a)), "");
}
}
@@ -111,6 +113,8 @@ void move_ctor()
{
static_assert(is_move_constructible_v<variant<int, string>>, "");
static_assert(!is_move_constructible_v<variant<AllDeleted, string>>, "");
+ static_assert(is_trivially_move_constructible_v<variant<int>>, "");
+ static_assert(!is_trivially_move_constructible_v<variant<std::string>>, "");
static_assert(!noexcept(variant<int, Empty>(declval<variant<int, Empty>>())), "");
static_assert(noexcept(variant<int, DefaultNoexcept>(declval<variant<int, DefaultNoexcept>>())), "");
}
@@ -148,13 +152,15 @@ void copy_assign()
{
static_assert(is_copy_assignable_v<variant<int, string>>, "");
static_assert(!is_copy_assignable_v<variant<AllDeleted, string>>, "");
+ static_assert(is_trivially_copy_assignable_v<variant<int>>, "");
+ static_assert(!is_trivially_copy_assignable_v<variant<string>>, "");
{
variant<Empty> a;
static_assert(!noexcept(a = a), "");
}
{
variant<DefaultNoexcept> a;
- static_assert(!noexcept(a = a), "");
+ static_assert(noexcept(a = a), "");
}
}
@@ -162,6 +168,8 @@ void move_assign()
{
static_assert(is_move_assignable_v<variant<int, string>>, "");
static_assert(!is_move_assignable_v<variant<AllDeleted, string>>, "");
+ static_assert(is_trivially_move_assignable_v<variant<int>>, "");
+ static_assert(!is_trivially_move_assignable_v<variant<string>>, "");
{
variant<Empty> a;
static_assert(!noexcept(a = std::move(a)), "");
@@ -454,3 +462,75 @@ void test_emplace()
static_assert(!has_type_emplace<variant<AllDeleted>, AllDeleted>(0), "");
static_assert(!has_index_emplace<variant<AllDeleted>, 0>(0), "");
}
+
+void test_triviality()
+{
+#define TEST_TEMPLATE(CC, MC, CA, MA, CC_VAL, MC_VAL, CA_VAL, MA_VAL) \
+ { \
+ struct A \
+ { \
+ A(const A&) CC; \
+ A(A&&) MC; \
+ A& operator=(const A&) CA; \
+ A& operator=(A&&) MA; \
+ }; \
+ static_assert(CC_VAL is_trivially_copy_constructible_v<variant<A>>, ""); \
+ static_assert(MC_VAL is_trivially_move_constructible_v<variant<A>>, ""); \
+ static_assert(CA_VAL is_trivially_copy_assignable_v<variant<A>>, ""); \
+ static_assert(MA_VAL is_trivially_move_assignable_v<variant<A>>, ""); \
+ }
+ TEST_TEMPLATE(=default, =default, =default, =default, , , ,)
+ TEST_TEMPLATE(=default, =default, =default, {}, , , ,!)
+ TEST_TEMPLATE(=default, =default, {}, =default, , , !,)
+ TEST_TEMPLATE(=default, =default, {}, {}, , , !,!)
+ TEST_TEMPLATE(=default, {}, =default, =default, , !, ,)
+ TEST_TEMPLATE(=default, {}, =default, {}, , !, ,!)
+ TEST_TEMPLATE(=default, {}, {}, =default, , !, !,)
+ TEST_TEMPLATE(=default, {}, {}, {}, , !, !,!)
+ TEST_TEMPLATE({}, =default, =default, =default, !, , ,)
+ TEST_TEMPLATE({}, =default, =default, {}, !, , ,!)
+ TEST_TEMPLATE({}, =default, {}, =default, !, , !,)
+ TEST_TEMPLATE({}, =default, {}, {}, !, , !,!)
+ TEST_TEMPLATE({}, {}, =default, =default, !, !, ,)
+ TEST_TEMPLATE({}, {}, =default, {}, !, !, ,!)
+ TEST_TEMPLATE({}, {}, {}, =default, !, !, !,)
+ TEST_TEMPLATE({}, {}, {}, {}, !, !, !,!)
+#undef TEST_TEMPLATE
+
+#define TEST_TEMPLATE(CC, MC, CA, MA) \
+ { \
+ struct A \
+ { \
+ A(const A&) CC; \
+ A(A&&) MC; \
+ A& operator=(const A&) CA; \
+ A& operator=(A&&) MA; \
+ }; \
+ static_assert(!is_trivially_copy_constructible_v<variant<AllDeleted, A>>, ""); \
+ static_assert(!is_trivially_move_constructible_v<variant<AllDeleted, A>>, ""); \
+ static_assert(!is_trivially_copy_assignable_v<variant<AllDeleted, A>>, ""); \
+ static_assert(!is_trivially_move_assignable_v<variant<AllDeleted, A>>, ""); \
+ }
+ TEST_TEMPLATE(=default, =default, =default, =default)
+ TEST_TEMPLATE(=default, =default, =default, {})
+ TEST_TEMPLATE(=default, =default, {}, =default)
+ TEST_TEMPLATE(=default, =default, {}, {})
+ TEST_TEMPLATE(=default, {}, =default, =default)
+ TEST_TEMPLATE(=default, {}, =default, {})
+ TEST_TEMPLATE(=default, {}, {}, =default)
+ TEST_TEMPLATE(=default, {}, {}, {})
+ TEST_TEMPLATE({}, =default, =default, =default)
+ TEST_TEMPLATE({}, =default, =default, {})
+ TEST_TEMPLATE({}, =default, {}, =default)
+ TEST_TEMPLATE({}, =default, {}, {})
+ TEST_TEMPLATE({}, {}, =default, =default)
+ TEST_TEMPLATE({}, {}, =default, {})
+ TEST_TEMPLATE({}, {}, {}, =default)
+ TEST_TEMPLATE({}, {}, {}, {})
+#undef TEST_TEMPLATE
+
+ static_assert(is_trivially_copy_constructible_v<variant<DefaultNoexcept, int, char, float, double>>, "");
+ static_assert(is_trivially_move_constructible_v<variant<DefaultNoexcept, int, char, float, double>>, "");
+ static_assert(is_trivially_copy_assignable_v<variant<DefaultNoexcept, int, char, float, double>>, "");
+ static_assert(is_trivially_move_assignable_v<variant<DefaultNoexcept, int, char, float, double>>, "");
+}
next reply other threads:[~2017-05-30 6:29 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-05-30 6:36 Tim Shen via gcc-patches [this message]
2017-05-30 9:41 ` Tim Shen via gcc-patches
2017-06-01 15:13 ` Jonathan Wakely
2017-06-01 15:21 ` Ville Voutilainen
2017-06-01 15:29 ` Jonathan Wakely
2017-06-01 15:43 ` Ville Voutilainen
2017-06-01 16:03 ` Jonathan Wakely
2017-06-01 16:07 ` Ville Voutilainen
2017-06-01 16:13 ` Jonathan Wakely
2017-06-18 19:37 ` Tim Shen via gcc-patches
2017-06-27 15:43 ` Jonathan Wakely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAG4ZjNnp4DQXpBEs7yu-MCrfUGfk+3x=KkPZqJiQ5WWt3awnvg@mail.gmail.com' \
--to=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
--cc=timshen@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).