enable_special_members.h: Make _Enable_default_constructor constexpr.
authorTim Shen <timshen@google.com>
Tue, 6 Dec 2016 11:26:48 +0000 (11:26 +0000)
committerTim Shen <timshen@gcc.gnu.org>
Tue, 6 Dec 2016 11:26:48 +0000 (11:26 +0000)
* 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

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/enable_special_members.h
libstdc++-v3/include/std/variant
libstdc++-v3/testsuite/20_util/variant/compile.cc
libstdc++-v3/testsuite/20_util/variant/hash.cc

index 8a3ab43d665b5f2ca12a131fe8b70620515c2f02..cdad9728b41ac4cc0804d1507edd1127a0c9a3a1 100644 (file)
@@ -1,3 +1,11 @@
+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
index 07c6c99ef854da92014116254779706896551179..4f4477bfb33ffb9866101a29efa7fd4f4b3fb9a5 100644 (file)
@@ -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>
index a961a058a5693ad81bb2b54ddca0bcd7b56f58f4..fa1e6548e49183f91e2472ce9c406f7f4fa99fc4 100644 (file)
@@ -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())
          {
index ab8ada2e9191816d78027e359785e6252b507da4..087a17cb9525e81ea31fe4de65220e93079f3b67 100644 (file)
@@ -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), "");
+}
index 38991ae1f83e72c747cf9664caed9205f788bd0b..64d053f712e7a4c8d1143f2b1fc4223f76b72be8 100644 (file)
@@ -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()
 {