aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Shen <timshen@google.com>2016-12-06 11:26:48 +0000
committerTim Shen <timshen@gcc.gnu.org>2016-12-06 11:26:48 +0000
commit458ef69052224b5d3d2c78cfbe0a0e0ec85a4193 (patch)
treec652adea01f85d2e42973e02cf87c3dcb4147671
parent9189f55908d6655e63fff8d9b9f87ec83d4891e1 (diff)
downloadgcc-458ef69052224b5d3d2c78cfbe0a0e0ec85a4193.zip
gcc-458ef69052224b5d3d2c78cfbe0a0e0ec85a4193.tar.gz
gcc-458ef69052224b5d3d2c78cfbe0a0e0ec85a4193.tar.bz2
enable_special_members.h: Make _Enable_default_constructor constexpr.
* include/bits/enable_special_members.h: Make _Enable_default_constructor constexpr. * include/std/variant (variant::emplace, variant::swap, std::swap, std::hash): Sfinae on emplace and std::swap; handle __poison_hash bases of duplicated types. * testsuite/20_util/variant/compile.cc: Add tests. * testsuite/20_util/variant/hash.cc: Add tests. From-SVN: r243294
-rw-r--r--libstdc++-v3/ChangeLog8
-rw-r--r--libstdc++-v3/include/bits/enable_special_members.h5
-rw-r--r--libstdc++-v3/include/std/variant89
-rw-r--r--libstdc++-v3/testsuite/20_util/variant/compile.cc43
-rw-r--r--libstdc++-v3/testsuite/20_util/variant/hash.cc4
5 files changed, 114 insertions, 35 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 8a3ab43..cdad972 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,13 @@
2016-12-07 Tim Shen <timshen@google.com>
+ * include/bits/enable_special_members.h: Make
+ _Enable_default_constructor constexpr.
+ * include/std/variant (variant::emplace, variant::swap, std::swap,
+ std::hash): Sfinae on emplace and std::swap; handle __poison_hash bases
+ of duplicated types.
+
+2016-12-07 Tim Shen <timshen@google.com>
+
* include/std/variant (std::get, operator==): Implement constexpr
comparison and get<>.
* testsuite/20_util/variant/compile.cc: Tests.
diff --git a/libstdc++-v3/include/bits/enable_special_members.h b/libstdc++-v3/include/bits/enable_special_members.h
index 07c6c99..4f4477b 100644
--- a/libstdc++-v3/include/bits/enable_special_members.h
+++ b/libstdc++-v3/include/bits/enable_special_members.h
@@ -38,7 +38,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct _Enable_default_constructor_tag
{
- explicit _Enable_default_constructor_tag() = default;
+ explicit constexpr _Enable_default_constructor_tag() = default;
};
/**
@@ -118,7 +118,8 @@ template<typename _Tag>
operator=(_Enable_default_constructor&&) noexcept = default;
// Can be used in other ctors.
- explicit _Enable_default_constructor(_Enable_default_constructor_tag) { }
+ constexpr explicit
+ _Enable_default_constructor(_Enable_default_constructor_tag) { }
};
template<typename _Tag>
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index a961a05..fa1e654 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -330,14 +330,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ }
template<size_t... __indices>
- constexpr void _M_destroy_impl(std::index_sequence<__indices...>)
+ constexpr void _M_reset_impl(std::index_sequence<__indices...>)
{
if (_M_index != variant_npos)
_S_vtable<__indices...>[_M_index](*this);
}
+ void _M_reset()
+ {
+ _M_reset_impl(std::index_sequence_for<_Types...>{});
+ _M_index = variant_npos;
+ }
+
~_Variant_storage()
- { _M_destroy_impl(std::index_sequence_for<_Types...>{}); }
+ { _M_reset(); }
_Variadic_union<_Types...> _M_u;
size_t _M_index;
@@ -354,6 +360,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_index(_Np)
{ }
+ void _M_reset()
+ { _M_index = variant_npos; }
+
_Variadic_union<_Types...> _M_u;
size_t _M_index;
};
@@ -436,6 +445,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return *this;
}
+ void _M_destructive_move(_Variant_base&& __rhs)
+ {
+ this->~_Variant_base();
+ __try
+ {
+ ::new (this) _Variant_base(std::move(__rhs));
+ }
+ __catch (...)
+ {
+ this->_M_index = variant_npos;
+ __throw_exception_again;
+ }
+ }
+
_Variant_base&
operator=(_Variant_base&& __rhs)
noexcept(__and_<is_nothrow_move_constructible<_Types>...,
@@ -453,16 +476,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
else
{
- this->~_Variant_base();
- __try
- {
- ::new (this) _Variant_base(std::move(__rhs));
- }
- __catch (...)
- {
- this->_M_index = variant_npos;
- __throw_exception_again;
- }
+ _M_destructive_move(std::move(__rhs));
}
return *this;
}
@@ -682,6 +696,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};
+ template<size_t _Np, typename _Tp>
+ struct _Base_dedup : public _Tp { };
+
+ template<typename _Variant, typename __indices>
+ struct _Variant_hash_base;
+
+ template<typename... _Types, size_t... __indices>
+ struct _Variant_hash_base<variant<_Types...>,
+ std::index_sequence<__indices...>>
+ : _Base_dedup<__indices, __poison_hash<remove_const_t<_Types>>>... { };
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace __variant
} // namespace __detail
@@ -858,8 +883,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return false; }
template<typename... _Types>
- inline enable_if_t<__and_<is_move_constructible<_Types>...,
- is_swappable<_Types>...>::value>
+ inline enable_if_t<(is_move_constructible_v<_Types> && ...)
+ && (is_swappable_v<_Types> && ...)>
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
noexcept(noexcept(__lhs.swap(__rhs)))
{ __lhs.swap(__rhs); }
@@ -1028,25 +1053,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Tp, typename... _Args>
- void emplace(_Args&&... __args)
+ enable_if_t<is_constructible_v<_Tp, _Args...> && __exactly_once<_Tp>>
+ emplace(_Args&&... __args)
{
- static_assert(__exactly_once<_Tp>,
- "T should occur for exactly once in alternatives");
this->emplace<__index_of<_Tp>>(std::forward<_Args>(__args)...);
__glibcxx_assert(holds_alternative<_Tp>(*this));
}
template<typename _Tp, typename _Up, typename... _Args>
- void emplace(initializer_list<_Up> __il, _Args&&... __args)
+ enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
+ && __exactly_once<_Tp>>
+ emplace(initializer_list<_Up> __il, _Args&&... __args)
{
- static_assert(__exactly_once<_Tp>,
- "T should occur for exactly once in alternatives");
this->emplace<__index_of<_Tp>>(__il, std::forward<_Args>(__args)...);
__glibcxx_assert(holds_alternative<_Tp>(*this));
}
template<size_t _Np, typename... _Args>
- void emplace(_Args&&... __args)
+ enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
+ _Args...>>
+ emplace(_Args&&... __args)
{
static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)");
@@ -1065,7 +1091,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<size_t _Np, typename _Up, typename... _Args>
- void emplace(initializer_list<_Up> __il, _Args&&... __args)
+ enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
+ initializer_list<_Up>&, _Args...>>
+ emplace(initializer_list<_Up> __il, _Args&&... __args)
{
static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)");
@@ -1092,7 +1120,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void
swap(variant& __rhs)
noexcept(__and_<__is_nothrow_swappable<_Types>...>::value
- && is_nothrow_move_assignable_v<variant>)
+ && is_nothrow_move_constructible_v<variant>)
{
if (this->index() == __rhs.index())
{
@@ -1107,17 +1135,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
else if (!this->_M_valid())
{
- *this = std::move(__rhs);
+ this->_M_destructive_move(std::move(__rhs));
+ __rhs._M_reset();
}
else if (!__rhs._M_valid())
{
- __rhs = std::move(*this);
+ __rhs._M_destructive_move(std::move(*this));
+ this->_M_reset();
}
else
{
auto __tmp = std::move(__rhs);
- __rhs = std::move(*this);
- *this = std::move(__tmp);
+ __rhs._M_destructive_move(std::move(*this));
+ this->_M_destructive_move(std::move(__tmp));
}
}
@@ -1253,14 +1283,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename... _Types>
struct hash<variant<_Types...>>
- : private __poison_hash<remove_const_t<_Types>>...
+ : private __detail::__variant::_Variant_hash_base<
+ variant<_Types...>, std::index_sequence_for<_Types...>>
{
using result_type = size_t;
using argument_type = variant<_Types...>;
size_t
operator()(const variant<_Types...>& __t) const
- noexcept((... && noexcept(hash<decay_t<_Types>>{}(std::declval<_Types>()))))
+ noexcept((is_nothrow_callable_v<hash<decay_t<_Types>>(_Types)> && ...))
{
if (!__t.valueless_by_exception())
{
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index ab8ada2..087a17c 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -51,6 +51,15 @@ struct DefaultNoexcept
DefaultNoexcept& operator=(DefaultNoexcept&&) noexcept = default;
};
+struct MoveCtorOnly
+{
+ MoveCtorOnly() noexcept = delete;
+ MoveCtorOnly(const DefaultNoexcept&) noexcept = delete;
+ MoveCtorOnly(DefaultNoexcept&&) noexcept { }
+ MoveCtorOnly& operator=(const DefaultNoexcept&) noexcept = delete;
+ MoveCtorOnly& operator=(DefaultNoexcept&&) noexcept = delete;
+};
+
struct nonliteral
{
nonliteral() { }
@@ -237,9 +246,9 @@ static_assert( !std::is_swappable_v<variant<D, int>> );
void test_swap()
{
- variant<int, string> a, b;
- a.swap(b);
- swap(a, b);
+ static_assert(is_swappable_v<variant<int, string>>, "");
+ static_assert(is_swappable_v<variant<MoveCtorOnly>>, "");
+ static_assert(!is_swappable_v<variant<AllDeleted>>, "");
}
void test_visit()
@@ -385,7 +394,8 @@ void test_adl()
variant<X> v4{in_place_type<X>, il, x};
}
-void test_variant_alternative() {
+void test_variant_alternative()
+{
static_assert(is_same_v<variant_alternative_t<0, variant<int, string>>, int>, "");
static_assert(is_same_v<variant_alternative_t<1, variant<int, string>>, string>, "");
@@ -393,3 +403,28 @@ void test_variant_alternative() {
static_assert(is_same_v<variant_alternative_t<0, volatile variant<int>>, volatile int>, "");
static_assert(is_same_v<variant_alternative_t<0, const volatile variant<int>>, const volatile int>, "");
}
+
+template<typename V, typename T>
+ constexpr auto has_type_emplace(int) -> decltype((declval<V>().template emplace<T>(), true))
+ { return true; };
+
+template<typename V, typename T>
+ constexpr bool has_type_emplace(...)
+ { return false; };
+
+template<typename V, size_t N>
+ constexpr auto has_index_emplace(int) -> decltype((declval<V>().template emplace<N>(), true))
+ { return true; };
+
+template<typename V, size_t T>
+ constexpr bool has_index_emplace(...)
+ { return false; };
+
+void test_emplace()
+{
+ static_assert(has_type_emplace<variant<int>, int>(0), "");
+ static_assert(!has_type_emplace<variant<long>, int>(0), "");
+ static_assert(has_index_emplace<variant<int>, 0>(0), "");
+ static_assert(!has_type_emplace<variant<AllDeleted>, AllDeleted>(0), "");
+ static_assert(!has_index_emplace<variant<AllDeleted>, 0>(0), "");
+}
diff --git a/libstdc++-v3/testsuite/20_util/variant/hash.cc b/libstdc++-v3/testsuite/20_util/variant/hash.cc
index 38991ae..64d053f 100644
--- a/libstdc++-v3/testsuite/20_util/variant/hash.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/hash.cc
@@ -29,6 +29,10 @@ template<class T>
auto f(...) -> decltype(std::false_type());
static_assert(!decltype(f<S>(0))::value, "");
+static_assert(!decltype(f<std::variant<S>>(0))::value, "");
+static_assert(!decltype(f<std::variant<S, S>>(0))::value, "");
+static_assert(decltype(f<std::variant<int>>(0))::value, "");
+static_assert(decltype(f<std::variant<int, int>>(0))::value, "");
int main()
{