This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patches] Add variant constexpr support for visit, comparisons and get


This 4-patch series contains the following in order:

a.diff: Remove uses-allocator ctors. They are going away, and removing
it reduces the maintenance burden from now on.

b.diff: Add constexpr support for get<> and comparisons. This patch
also involves small refactoring of _Variant_storage.

c.diff: Fix some libc++ test failures.

d.diff: Add constexpr support for visit. This patch also removes
__storage, __get_alternative, and __reserved_type_map, since we don't
need to support reference/void types for now.

The underlying design doesn't change - we still use the vtable
approach to achieve O(1) runtime cost even under -O0.

Bootstrapped and tested for each of them.

Thanks!


-- 
Regards,
Tim Shen
commit 638ecd4cf354d853bb12b089a356df99531f9afa
Author: Tim Shen <timshen@google.com>
Date:   Thu Nov 24 00:56:08 2016 -0800

    2016-11-26  Tim Shen  <timshen@google.com>
    
            * include/std/variant (__erased_use_alloc_ctor,
            _Variant_base::_Variant_base, variant::variant): Remove uses-allocator
            related functions.
            * testsuite/20_util/variant/compile.cc: Remove related tests.
            * testsuite/20_util/variant/run.cc: Remove related tests.

diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 34ad3fd..2d9303a 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -202,14 +202,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __erased_ctor(void* __lhs, void* __rhs)
     { ::new (__lhs) decay_t<_Lhs>(__get_alternative<_Rhs>(__rhs)); }
 
-  template<typename _Alloc, typename _Lhs, typename _Rhs>
-    constexpr void
-    __erased_use_alloc_ctor(const _Alloc& __a, void* __lhs, void* __rhs)
-    {
-      __uses_allocator_construct(__a, static_cast<decay_t<_Lhs>*>(__lhs),
-				 __get_alternative<_Rhs>(__rhs));
-    }
-
   // TODO: Find a potential chance to reuse this accross the project.
   template<typename _Tp>
     constexpr void
@@ -353,47 +345,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	: _Storage(__i, std::forward<_Args>(__args)...), _M_index(_Np)
 	{ }
 
-      template<typename _Alloc>
-	_Variant_base(const _Alloc& __a, const _Variant_base& __rhs)
-	: _Storage(), _M_index(__rhs._M_index)
-	{
-	  if (__rhs._M_valid())
-	    {
-	      static constexpr void
-	      (*_S_vtable[])(const _Alloc&, void*, void*) =
-		{ &__erased_use_alloc_ctor<_Alloc, __storage<_Types>&,
-					   const __storage<_Types>&>... };
-	      _S_vtable[__rhs._M_index](__a, _M_storage(), __rhs._M_storage());
-	    }
-	}
-
-      template<typename _Alloc>
-	_Variant_base(const _Alloc& __a, _Variant_base&& __rhs)
-	: _Storage(), _M_index(__rhs._M_index)
-	{
-	  if (__rhs._M_valid())
-	    {
-	      static constexpr void
-	      (*_S_vtable[])(const _Alloc&, void*, void*) =
-		{ &__erased_use_alloc_ctor<_Alloc, __storage<_Types>&,
-					   __storage<_Types>&&>... };
-	      _S_vtable[__rhs._M_index](__a, _M_storage(), __rhs._M_storage());
-	    }
-	}
-
-      template<typename _Alloc, size_t _Np, typename... _Args>
-	constexpr explicit
-	_Variant_base(const _Alloc& __a, in_place_index_t<_Np>,
-		      _Args&&... __args)
-	: _Storage(), _M_index(_Np)
-	{
-	  using _Storage =
-	    __storage<variant_alternative_t<_Np, variant<_Types...>>>;
-	  __uses_allocator_construct(__a, static_cast<_Storage*>(_M_storage()),
-				     std::forward<_Args>(__args)...);
-	  __glibcxx_assert(_M_index == _Np);
-	}
-
       _Variant_base&
       operator=(const _Variant_base& __rhs)
       {
@@ -1026,84 +977,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_Default_ctor_enabler(_Enable_default_constructor_tag{})
 	{ __glibcxx_assert(index() == _Np); }
 
-      template<typename _Alloc,
-	       typename = enable_if_t<
-		 __is_uses_allocator_constructible_v<__to_type<0>, _Alloc>>>
-	variant(allocator_arg_t, const _Alloc& __a)
-	: variant(allocator_arg, __a, in_place_index<0>)
-	{ }
-
-      template<typename _Alloc,
-	       typename = enable_if_t<__and_<__is_uses_allocator_constructible<
-		 _Types, _Alloc,
-		 add_lvalue_reference_t<add_const_t<_Types>>>...>::value>>
-	variant(allocator_arg_t, const _Alloc& __a, const variant& __rhs)
-	: _Base(__a, __rhs),
-	_Default_ctor_enabler(_Enable_default_constructor_tag{})
-	{ }
-
-      template<typename _Alloc,
-	       typename = enable_if_t<__and_<
-		 __is_uses_allocator_constructible<
-		   _Types, _Alloc, add_rvalue_reference_t<_Types>>...>::value>>
-	variant(allocator_arg_t, const _Alloc& __a, variant&& __rhs)
-	: _Base(__a, std::move(__rhs)),
-	_Default_ctor_enabler(_Enable_default_constructor_tag{})
-	{ }
-
-      template<typename _Alloc, typename _Tp,
-	       typename = enable_if_t<
-		 __exactly_once<__accepted_type<_Tp&&>>
-		 && __is_uses_allocator_constructible_v<
-		   __accepted_type<_Tp&&>, _Alloc, _Tp&&>
-		 && !is_same_v<decay_t<_Tp>, variant>, variant&>>
-	variant(allocator_arg_t, const _Alloc& __a, _Tp&& __t)
-	: variant(allocator_arg, __a, in_place_index<__accepted_index<_Tp&&>>,
-		  std::forward<_Tp>(__t))
-	{ __glibcxx_assert(holds_alternative<__accepted_type<_Tp&&>>(*this)); }
-
-      template<typename _Alloc, typename _Tp, typename... _Args,
-	       typename = enable_if_t<
-		 __exactly_once<_Tp>
-		 && __is_uses_allocator_constructible_v<
-		   _Tp, _Alloc, _Args&&...>>>
-	variant(allocator_arg_t, const _Alloc& __a, in_place_type_t<_Tp>,
-		_Args&&... __args)
-	: variant(allocator_arg, __a, in_place_index<__index_of<_Tp>>,
-		  std::forward<_Args>(__args)...)
-	{ __glibcxx_assert(holds_alternative<_Tp>(*this)); }
-
-      template<typename _Alloc, typename _Tp, typename _Up, typename... _Args,
-	       typename = enable_if_t<
-		 __exactly_once<_Tp>
-		 && __is_uses_allocator_constructible_v<
-		   _Tp, _Alloc, initializer_list<_Up>&, _Args&&...>>>
-	variant(allocator_arg_t, const _Alloc& __a, in_place_type_t<_Tp>,
-		initializer_list<_Up> __il, _Args&&... __args)
-	: variant(allocator_arg, __a, in_place_index<__index_of<_Tp>>, __il,
-		  std::forward<_Args>(__args)...)
-	{ __glibcxx_assert(holds_alternative<_Tp>(*this)); }
-
-      template<typename _Alloc, size_t _Np, typename... _Args,
-	       typename = enable_if_t<
-		 __is_uses_allocator_constructible_v<
-		   __to_type<_Np>, _Alloc, _Args&&...>>>
-	variant(allocator_arg_t, const _Alloc& __a, in_place_index_t<_Np>,
-		_Args&&... __args)
-	: _Base(__a, in_place_index<_Np>, std::forward<_Args>(__args)...),
-	_Default_ctor_enabler(_Enable_default_constructor_tag{})
-	{ __glibcxx_assert(index() == _Np); }
-
-      template<typename _Alloc, size_t _Np, typename _Up, typename... _Args,
-	       typename = enable_if_t<
-		 __is_uses_allocator_constructible_v<
-		   __to_type<_Np>, _Alloc, initializer_list<_Up>&, _Args&&...>>>
-	variant(allocator_arg_t, const _Alloc& __a, in_place_index_t<_Np>,
-		initializer_list<_Up> __il, _Args&&... __args)
-	: _Base(__a, in_place_index<_Np>, __il, std::forward<_Args>(__args)...),
-	_Default_ctor_enabler(_Enable_default_constructor_tag{})
-	{ __glibcxx_assert(index() == _Np); }
-
       ~variant() = default;
 
       variant& operator=(const variant&) = default;
@@ -1293,10 +1166,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 			   __detail::__variant::__get_storage(__variants)...);
     }
 
-  template<typename... _Types, typename _Alloc>
-    struct uses_allocator<variant<_Types...>, _Alloc>
-    : true_type { };
-
   template<typename... _Types>
     struct hash<variant<_Types...>>
     : private __poison_hash<remove_const_t<_Types>>...
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index e3330be..5bd4e70 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -117,31 +117,6 @@ void in_place_type_ctor()
   static_assert(!is_constructible_v<variant<string, string>, in_place_type_t<string>, const char*>, "");
 }
 
-void uses_alloc_ctors()
-{
-  std::allocator<char> alloc;
-  variant<int> a(allocator_arg, alloc);
-  static_assert(!is_constructible_v<variant<AllDeleted>, allocator_arg_t, std::allocator<char>>, "");
-  {
-    variant<string, int> b(allocator_arg, alloc, "a");
-    static_assert(!is_constructible_v<variant<string, string>, allocator_arg_t, std::allocator<char>, const char*>, "");
-  }
-  {
-    variant<string, int> b(allocator_arg, alloc, in_place_index<0>, "a");
-    variant<string, string> c(allocator_arg, alloc, in_place_index<1>, "a");
-  }
-  {
-    variant<string, int> b(allocator_arg, alloc, in_place_index<0>, {'a'});
-    variant<string, string> c(allocator_arg, alloc, in_place_index<1>, {'a'});
-  }
-  {
-    variant<int, string, int> b(allocator_arg, alloc, in_place_type<string>, "a");
-  }
-  {
-    variant<int, string, int> b(allocator_arg, alloc, in_place_type<string>, {'a'});
-  }
-}
-
 void dtor()
 {
   static_assert(is_destructible_v<variant<int, string>>, "");
@@ -309,9 +284,7 @@ namespace adl_trap
 void test_adl()
 {
    using adl_trap::X;
-   using std::allocator_arg;
    X x;
-   std::allocator<int> a;
    std::initializer_list<int> il;
    adl_trap::Visitor vis;
 
@@ -324,11 +297,6 @@ void test_adl()
    variant<X> v2{in_place_type<X>, x};
    variant<X> v3{in_place_index<0>, il, x};
    variant<X> v4{in_place_type<X>, il, x};
-   variant<X> v5{allocator_arg, a, in_place_index<0>, x};
-   variant<X> v6{allocator_arg, a, in_place_type<X>, x};
-   variant<X> v7{allocator_arg, a, in_place_index<0>, il, x};
-   variant<X> v8{allocator_arg, a, in_place_type<X>, il, x};
-   variant<X> v9{allocator_arg, a, in_place_type<X>, 1};
 }
 
 void test_variant_alternative() {
diff --git a/libstdc++-v3/testsuite/20_util/variant/run.cc b/libstdc++-v3/testsuite/20_util/variant/run.cc
index 71e0176..fb5d7c4 100644
--- a/libstdc++-v3/testsuite/20_util/variant/run.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/run.cc
@@ -160,48 +160,6 @@ void in_place_type_ctor()
   }
 }
 
-struct UsesAllocatable
-{
-  template<typename Alloc>
-    UsesAllocatable(std::allocator_arg_t, const Alloc& a)
-    : d(0), a(static_cast<const void*>(&a)) { }
-
-  template<typename Alloc>
-    UsesAllocatable(std::allocator_arg_t, const Alloc& a, const UsesAllocatable&)
-    : d(1), a(static_cast<const void*>(&a)) { }
-
-  template<typename Alloc>
-    UsesAllocatable(std::allocator_arg_t, const Alloc& a, UsesAllocatable&&)
-    : d(2), a(static_cast<const void*>(&a)) { }
-
-  int d;
-  const void* a;
-};
-
-namespace std
-{
-  template<>
-    struct uses_allocator<UsesAllocatable, std::allocator<char>> : true_type { };
-}
-
-void uses_allocator_ctor()
-{
-  std::allocator<char> a;
-  variant<UsesAllocatable> v(std::allocator_arg, a);
-  VERIFY(get<0>(v).d == 0);
-  VERIFY(get<0>(v).a == &a);
-  {
-    variant<UsesAllocatable> u(std::allocator_arg, a, v);
-    VERIFY(get<0>(u).d == 1);
-    VERIFY(get<0>(u).a == &a);
-  }
-  {
-    variant<UsesAllocatable> u(std::allocator_arg, a, std::move(v));
-    VERIFY(get<0>(u).d == 2);
-    VERIFY(get<0>(u).a == &a);
-  }
-}
-
 void emplace()
 {
   variant<int, string> v;
@@ -450,7 +408,6 @@ int main()
   arbitrary_ctor();
   in_place_index_ctor();
   in_place_type_ctor();
-  uses_allocator_ctor();
   copy_assign();
   move_assign();
   arbitrary_assign();
commit 7c510c3d9ac56684a966ae818a2b0d64d63463c2
Author: Tim Shen <timshen@google.com>
Date:   Thu Nov 24 12:00:48 2016 -0800

    2016-11-26  Tim Shen  <timshen@google.com>
    
            * include/std/variant: Implement constexpr comparison and get<>.
            * testsuite/20_util/variant/compile.cc: Tests.

diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 2d9303a..a913074 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -154,31 +154,63 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Alternative>
     using __storage = _Alternative;
 
-  template<typename _Type, bool __is_literal = std::is_literal_type_v<_Type>>
+  // _Uninitialized nullify the destructor calls.
+  // This is necessary, since we define _Variadic_union as a recursive union,
+  // and we don't want to inspect the union members one by one in its dtor,
+  // it's slow.
+  template<typename _Type, bool = std::is_literal_type_v<_Type>>
     struct _Uninitialized;
 
   template<typename _Type>
     struct _Uninitialized<_Type, true>
     {
-      constexpr _Uninitialized() = default;
-
       template<typename... _Args>
       constexpr _Uninitialized(in_place_index_t<0>, _Args&&... __args)
       : _M_storage(std::forward<_Args>(__args)...)
       { }
 
+      constexpr const _Type& _M_get() const &
+      { return _M_storage; }
+
+      constexpr _Type& _M_get() &
+      { return _M_storage; }
+
+      constexpr const _Type&& _M_get() const &&
+      { return std::move(_M_storage); }
+
+      constexpr _Type&& _M_get() &&
+      { return std::move(_M_storage); }
+
       _Type _M_storage;
     };
 
   template<typename _Type>
     struct _Uninitialized<_Type, false>
     {
-      constexpr _Uninitialized() = default;
-
       template<typename... _Args>
       constexpr _Uninitialized(in_place_index_t<0>, _Args&&... __args)
       { ::new (&_M_storage) _Type(std::forward<_Args>(__args)...); }
 
+      const _Type& _M_get() const &
+      {
+	return *static_cast<const _Type*>(
+	    static_cast<const void*>(&_M_storage));
+      }
+
+      _Type& _M_get() &
+      { return *static_cast<_Type*>(static_cast<void*>(&_M_storage)); }
+
+      const _Type&& _M_get() const &&
+      {
+	return std::move(*static_cast<const _Type*>(
+	    static_cast<const void*>(&_M_storage)));
+      }
+
+      _Type&& _M_get() &&
+      {
+	return std::move(*static_cast<_Type*>(static_cast<void*>(&_M_storage)));
+      }
+
       typename std::aligned_storage<sizeof(_Type), alignof(_Type)>::type
 	  _M_storage;
     };
@@ -195,6 +227,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	*static_cast<_Storage*>(__ptr));
     }
 
+  template<typename _Union>
+    constexpr decltype(auto) __get(in_place_index_t<0>, _Union&& __u)
+    { return std::forward<_Union>(__u)._M_first._M_get(); }
+
+  template<size_t _Np, typename _Union>
+    constexpr decltype(auto) __get(in_place_index_t<_Np>, _Union&& __u)
+    { return __get(in_place_index<_Np-1>, std::forward<_Union>(__u)._M_rest); }
+
+  // Returns the typed storage for __v.
+  template<size_t _Np, typename _Variant>
+    constexpr decltype(auto) __get(_Variant&& __v)
+    {
+      return __get(std::in_place_index<_Np>, std::forward<_Variant>(__v)._M_u);
+    }
+
   // Various functions as "vtable" entries, where those vtables are used by
   // polymorphic operations.
   template<typename _Lhs, typename _Rhs>
@@ -202,13 +249,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __erased_ctor(void* __lhs, void* __rhs)
     { ::new (__lhs) decay_t<_Lhs>(__get_alternative<_Rhs>(__rhs)); }
 
-  // TODO: Find a potential chance to reuse this accross the project.
-  template<typename _Tp>
+  template<typename _Variant, size_t _Np>
     constexpr void
-    __erased_dtor(void* __ptr)
+    __erased_dtor(_Variant&& __v)
     {
-      using _Storage = decay_t<_Tp>;
-      static_cast<_Storage*>(__ptr)->~_Storage();
+      auto&& __element = __get<_Np>(std::forward<_Variant>(__v));
+      using _Type = std::remove_reference_t<decltype(__element)>;
+      __element.~_Type();
     }
 
   template<typename _Lhs, typename _Rhs>
@@ -224,90 +271,108 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       swap(__get_alternative<_Lhs>(__lhs), __get_alternative<_Rhs>(__rhs));
     }
 
-  template<typename _Lhs, typename _Rhs>
+  template<typename _Variant, size_t _Np>
     constexpr bool
-    __erased_equal_to(void* __lhs, void* __rhs)
-    { return __get_alternative<_Lhs>(__lhs) == __get_alternative<_Rhs>(__rhs); }
+    __erased_equal_to(_Variant&& __lhs, _Variant&& __rhs)
+    {
+      return __get<_Np>(std::forward<_Variant>(__lhs))
+	  == __get<_Np>(std::forward<_Variant>(__rhs));
+    }
 
-  template<typename _Lhs, typename _Rhs>
+  template<typename _Variant, size_t _Np>
     constexpr bool
-    __erased_less_than(void* __lhs, void* __rhs)
-    { return __get_alternative<_Lhs>(__lhs) < __get_alternative<_Rhs>(__rhs); }
+    __erased_less_than(const _Variant& __lhs, const _Variant& __rhs)
+    {
+      return __get<_Np>(std::forward<_Variant>(__lhs))
+	  < __get<_Np>(std::forward<_Variant>(__rhs));
+    }
 
   template<typename _Tp>
     constexpr size_t
     __erased_hash(void* __t)
     { return std::hash<decay_t<_Tp>>{}(__get_alternative<_Tp>(__t)); }
 
+  // Defines members and ctors.
   template<typename... _Types>
-    struct _Variant_base;
+    union _Variadic_union { };
 
-  template<typename... _Types>
-    struct _Variant_storage
-    { constexpr _Variant_storage() = default; };
-
-  // Use recursive unions to implement a trivially destructible variant.
   template<typename _First, typename... _Rest>
-    struct _Variant_storage<_First, _Rest...>
+    union _Variadic_union<_First, _Rest...>
     {
-      constexpr _Variant_storage() = default;
+      constexpr _Variadic_union() : _M_rest() { }
+
+      template<typename... _Args>
+	constexpr _Variadic_union(in_place_index_t<0>, _Args&&... __args)
+	: _M_first(in_place_index<0>, std::forward<_Args>(__args)...)
+	{ }
+
+      template<size_t _Np, typename... _Args>
+	constexpr _Variadic_union(in_place_index_t<_Np>, _Args&&... __args)
+	: _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...)
+	{ }
+
+      _Uninitialized<_First> _M_first;
+      _Variadic_union<_Rest...> _M_rest;
+    };
+
+  // Defines index and the dtor, possibly trivial.
+  template<bool __trivially_destructible, typename... _Types>
+    struct _Variant_storage;
+
+  template<typename... _Types>
+    struct _Variant_storage<false, _Types...>
+    {
+      template<size_t... __indices>
+	static constexpr void (*_S_vtable[])(const _Variant_storage&) =
+	    { &__erased_dtor<const _Variant_storage&, __indices>... };
+
+      constexpr _Variant_storage() : _M_index(variant_npos) { }
 
       template<size_t _Np, typename... _Args>
 	constexpr _Variant_storage(in_place_index_t<_Np>, _Args&&... __args)
-	: _M_union(in_place_index<_Np>, std::forward<_Args>(__args)...)
+	: _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...),
+	_M_index(_Np)
 	{ }
 
-      ~_Variant_storage() = default;
+      template<size_t... __indices>
+	constexpr void _M_destroy_impl(std::index_sequence<__indices...>)
+	{
+	  if (_M_index != variant_npos)
+	    _S_vtable<__indices...>[_M_index](*this);
+	}
 
-      constexpr void*
-      _M_storage() const
-      {
-	return const_cast<void*>(
-	  static_cast<const void*>(std::addressof(_M_union._M_first._M_storage)));
-      }
+      ~_Variant_storage()
+      { _M_destroy_impl(std::make_index_sequence<sizeof...(_Types)>{}); }
 
-      union _Union
-      {
-	constexpr _Union() {};
-
-	template<typename... _Args>
-	  constexpr _Union(in_place_index_t<0>, _Args&&... __args)
-	  : _M_first(in_place_index<0>, std::forward<_Args>(__args)...)
-	  { }
-
-	template<size_t _Np, typename... _Args,
-		 typename = enable_if_t<0 < _Np && _Np < sizeof...(_Rest) + 1>>
-	  constexpr _Union(in_place_index_t<_Np>, _Args&&... __args)
-	  : _M_rest(in_place_index<_Np - 1>, std::forward<_Args>(__args)...)
-	  { }
-
-	_Uninitialized<__storage<_First>> _M_first;
-	_Variant_storage<_Rest...> _M_rest;
-      } _M_union;
+      _Variadic_union<_Types...> _M_u;
+      size_t _M_index;
     };
 
-  template<typename _Derived, bool __is_trivially_destructible>
-    struct _Dtor_mixin
+  template<typename... _Types>
+    struct _Variant_storage<true, _Types...>
     {
-      ~_Dtor_mixin()
-      { static_cast<_Derived*>(this)->_M_destroy(); }
-    };
+      constexpr _Variant_storage() : _M_index(variant_npos) { }
 
-  template<typename _Derived>
-    struct _Dtor_mixin<_Derived, true>
-    {
-      ~_Dtor_mixin() = default;
+      template<size_t _Np, typename... _Args>
+	constexpr _Variant_storage(in_place_index_t<_Np>, _Args&&... __args)
+	: _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...),
+	_M_index(_Np)
+	{ }
+
+      _Variadic_union<_Types...> _M_u;
+      size_t _M_index;
     };
 
   // Helps SFINAE on special member functions. Otherwise it can live in variant
   // class.
   template<typename... _Types>
     struct _Variant_base :
-      _Variant_storage<_Types...>,
-      _Dtor_mixin<_Variant_base<_Types...>,
-		  __and_<std::is_trivially_destructible<_Types>...>::value>
+      _Variant_storage<(std::is_trivially_destructible_v<_Types> && ...),
+			_Types...>
     {
-      using _Storage = _Variant_storage<_Types...>;
+      using _Storage =
+	  _Variant_storage<(std::is_trivially_destructible_v<_Types> && ...),
+			    _Types...>;
 
       constexpr
       _Variant_base()
@@ -316,7 +381,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       : _Variant_base(in_place_index<0>) { }
 
       _Variant_base(const _Variant_base& __rhs)
-      : _Storage(), _M_index(__rhs._M_index)
       {
 	if (__rhs._M_valid())
 	  {
@@ -324,31 +388,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      { &__erased_ctor<__storage<_Types>&,
 			       const __storage<_Types>&>... };
 	    _S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
+	    this->_M_index = __rhs._M_index;
 	  }
       }
 
       _Variant_base(_Variant_base&& __rhs)
       noexcept(__and_<is_nothrow_move_constructible<_Types>...>::value)
-      : _Storage(), _M_index(__rhs._M_index)
       {
 	if (__rhs._M_valid())
 	  {
 	    static constexpr void (*_S_vtable[])(void*, void*) =
 	      { &__erased_ctor<__storage<_Types>&, __storage<_Types>&&>... };
 	    _S_vtable[__rhs._M_index](_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)...), _M_index(_Np)
+	: _Storage(__i, std::forward<_Args>(__args)...)
 	{ }
 
       _Variant_base&
       operator=(const _Variant_base& __rhs)
       {
-	if (_M_index == __rhs._M_index)
+	if (this->_M_index == __rhs._M_index)
 	  {
 	    if (__rhs._M_valid())
 	      {
@@ -368,11 +433,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      }
 	    __catch (...)
 	      {
-		_M_index = variant_npos;
+		this->_M_index = variant_npos;
 		__throw_exception_again;
 	      }
 	  }
-	__glibcxx_assert(_M_index == __rhs._M_index);
+	__glibcxx_assert(this->_M_index == __rhs._M_index);
 	return *this;
       }
 
@@ -381,7 +446,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       noexcept(__and_<is_nothrow_move_constructible<_Types>...,
 		      is_nothrow_move_assignable<_Types>...>::value)
       {
-	if (_M_index == __rhs._M_index)
+	if (this->_M_index == __rhs._M_index)
 	  {
 	    if (__rhs._M_valid())
 	      {
@@ -400,32 +465,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      }
 	    __catch (...)
 	      {
-		_M_index = variant_npos;
+		this->_M_index = variant_npos;
 		__throw_exception_again;
 	      }
 	  }
 	return *this;
       }
 
-      void _M_destroy()
+      void*
+      _M_storage() const
       {
-	if (_M_valid())
-	  {
-	    static constexpr void (*_S_vtable[])(void*) =
-	      { &__erased_dtor<__storage<_Types>&>... };
-	    _S_vtable[this->_M_index](_M_storage());
-	  }
+	return const_cast<void*>(static_cast<const void*>(
+	    std::addressof(_Storage::_M_u)));
       }
 
-      constexpr void*
-      _M_storage() const
-      { return _Storage::_M_storage(); }
-
       constexpr bool
       _M_valid() const noexcept
-      { return _M_index != variant_npos; }
-
-      size_t _M_index;
+      { return this->_M_index != variant_npos; }
     };
 
   // For how many times does _Tp appear in _Tuple?
@@ -490,15 +546,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     void* __get_storage(_Variant&& __v)
     { return __v._M_storage(); }
 
-  // Returns the reference to the desired alternative.
-  // It is as unsafe as a reinterpret_cast.
-  template<typename _Tp, typename _Variant>
-    decltype(auto) __access(_Variant&& __v)
-    {
-      return __get_alternative<__reserved_type_map<_Variant&&, __storage<_Tp>>>(
-	__get_storage(std::forward<_Variant>(__v)));
-    }
-
   // A helper used to create variadic number of _To types.
   template<typename _From, typename _To>
     using _To_type = _To;
@@ -598,9 +645,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_S_apply_all_alts(_Array_type& __vtable, index_sequence<__indices...>)
 	{ (_S_apply_single_alt<__indices>(__vtable._M_arr[__indices]), ...); }
 
-      template<size_t __index>
+      template<size_t __index, typename T>
 	static constexpr void
-	_S_apply_single_alt(auto& __element)
+	_S_apply_single_alt(T& __element)
 	{
 	  using _Alternative = variant_alternative_t<__index, decay_t<_First>>;
 	  using _Qualified_storage = __reserved_type_map<
@@ -656,23 +703,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<size_t _Np, typename... _Types>
-    variant_alternative_t<_Np, variant<_Types...>>&
+    constexpr variant_alternative_t<_Np, variant<_Types...>>&
     get(variant<_Types...>&);
 
   template<size_t _Np, typename... _Types>
-    variant_alternative_t<_Np, variant<_Types...>>&&
+    constexpr variant_alternative_t<_Np, variant<_Types...>>&&
     get(variant<_Types...>&&);
 
   template<size_t _Np, typename... _Types>
-    variant_alternative_t<_Np, variant<_Types...>> const&
+    constexpr variant_alternative_t<_Np, variant<_Types...>> const&
     get(const variant<_Types...>&);
 
   template<size_t _Np, typename... _Types>
-    variant_alternative_t<_Np, variant<_Types...>> const&&
+    constexpr variant_alternative_t<_Np, variant<_Types...>> const&&
     get(const variant<_Types...>&&);
 
   template<typename _Tp, typename... _Types>
-    inline _Tp& get(variant<_Types...>& __v)
+    constexpr inline _Tp& get(variant<_Types...>& __v)
     {
       static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
 		    "T should occur for exactly once in alternatives");
@@ -681,7 +728,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp, typename... _Types>
-    inline _Tp&& get(variant<_Types...>&& __v)
+    constexpr inline _Tp&& get(variant<_Types...>&& __v)
     {
       static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
 		    "T should occur for exactly once in alternatives");
@@ -691,7 +738,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp, typename... _Types>
-    inline const _Tp& get(const variant<_Types...>& __v)
+    constexpr inline const _Tp& get(const variant<_Types...>& __v)
     {
       static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
 		    "T should occur for exactly once in alternatives");
@@ -700,7 +747,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp, typename... _Types>
-    inline const _Tp&& get(const variant<_Types...>&& __v)
+    constexpr inline const _Tp&& get(const variant<_Types...>&& __v)
     {
       static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
 		    "T should occur for exactly once in alternatives");
@@ -710,7 +757,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<size_t _Np, typename... _Types>
-    inline add_pointer_t<variant_alternative_t<_Np, variant<_Types...>>>
+    constexpr inline
+    add_pointer_t<variant_alternative_t<_Np, variant<_Types...>>>
     get_if(variant<_Types...>* __ptr) noexcept
     {
       using _Alternative_type = variant_alternative_t<_Np, variant<_Types...>>;
@@ -718,12 +766,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		    "The index should be in [0, number of alternatives)");
       static_assert(!is_void_v<_Alternative_type>, "_Tp should not be void");
       if (__ptr && __ptr->index() == _Np)
-	return &__detail::__variant::__access<_Alternative_type>(*__ptr);
+	return &__detail::__variant::__get<_Np>(*__ptr);
       return nullptr;
     }
 
   template<size_t _Np, typename... _Types>
-    inline add_pointer_t<const variant_alternative_t<_Np, variant<_Types...>>>
+    constexpr inline
+    add_pointer_t<const variant_alternative_t<_Np, variant<_Types...>>>
     get_if(const variant<_Types...>* __ptr) noexcept
     {
       using _Alternative_type = variant_alternative_t<_Np, variant<_Types...>>;
@@ -731,12 +780,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		    "The index should be in [0, number of alternatives)");
       static_assert(!is_void_v<_Alternative_type>, "_Tp should not be void");
       if (__ptr && __ptr->index() == _Np)
-	return &__detail::__variant::__access<_Alternative_type>(*__ptr);
+	return &__detail::__variant::__get<_Np>(*__ptr);
       return nullptr;
     }
 
   template<typename _Tp, typename... _Types>
-    inline add_pointer_t<_Tp> get_if(variant<_Types...>* __ptr) noexcept
+    constexpr inline add_pointer_t<_Tp>
+    get_if(variant<_Types...>* __ptr) noexcept
     {
       static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
 		    "T should occur for exactly once in alternatives");
@@ -745,7 +795,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Tp, typename... _Types>
-    inline add_pointer_t<const _Tp> get_if(const variant<_Types...>* __ptr)
+    constexpr inline add_pointer_t<const _Tp>
+    get_if(const variant<_Types...>* __ptr)
     noexcept
     {
       static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
@@ -755,64 +806,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename... _Types>
-    bool operator==(const variant<_Types...>& __lhs,
-		    const variant<_Types...>& __rhs)
+    constexpr bool operator==(const variant<_Types...>& __lhs,
+			      const variant<_Types...>& __rhs)
     {
-      if (__lhs.index() != __rhs.index())
-	return false;
-
-      if (__lhs.valueless_by_exception())
-	return true;
-
-      using __detail::__variant::__storage;
-      static constexpr bool (*_S_vtable[])(void*, void*) =
-	{ &__detail::__variant::__erased_equal_to<
-	  const __storage<_Types>&, const __storage<_Types>&>... };
-      return _S_vtable[__lhs.index()](
-	  __detail::__variant::__get_storage(__lhs),
-	  __detail::__variant::__get_storage(__rhs));
+      return __lhs._M_equal_to(__rhs,
+			       std::make_index_sequence<sizeof...(_Types)>{});
     }
 
   template<typename... _Types>
-    inline bool
+    constexpr inline bool
     operator!=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
     { return !(__lhs == __rhs); }
 
   template<typename... _Types>
-    inline bool
+    constexpr inline bool
     operator<(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
     {
-      if (__lhs.index() < __rhs.index())
-	return true;
-
-      if (__lhs.index() > __rhs.index())
-	return false;
-
-      if (__lhs.valueless_by_exception())
-	return false;
-
-      using __detail::__variant::__storage;
-      static constexpr bool (*_S_vtable[])(void*, void*) =
-	{ &__detail::__variant::__erased_less_than<
-	    const __storage<_Types>&,
-	    const __storage<_Types>&>... };
-      return _S_vtable[__lhs.index()](
-	  __detail::__variant::__get_storage(__lhs),
-	  __detail::__variant::__get_storage(__rhs));
+      return __lhs._M_less_than(__rhs,
+				std::make_index_sequence<sizeof...(_Types)>{});
     }
 
   template<typename... _Types>
-    inline bool
+    constexpr inline bool
     operator>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
     { return __rhs < __lhs; }
 
   template<typename... _Types>
-    inline bool
+    constexpr inline bool
     operator<=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
     { return !(__lhs > __rhs); }
 
   template<typename... _Types>
-    inline bool
+    constexpr inline bool
     operator>=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
     { return !(__lhs < __rhs); }
 
@@ -1096,60 +1121,120 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  }
       }
 
+    private:
+      template<size_t... __indices>
+	static constexpr bool
+	(*_S_equal_to_vtable[])(const variant&, const variant&) =
+	  { &__detail::__variant::__erased_equal_to<
+	    const variant&, __indices>... };
+
+      template<size_t... __indices>
+	static constexpr bool
+	(*_S_less_than_vtable[])(const variant&, const variant&) =
+	  { &__detail::__variant::__erased_less_than<
+	      const variant&, __indices>... };
+
+      template<size_t... __indices>
+	constexpr bool
+	_M_equal_to(const variant& __rhs,
+		    std::index_sequence<__indices...>) const
+	{
+	  if (this->index() != __rhs.index())
+	    return false;
+
+	  if (this->valueless_by_exception())
+	    return true;
+
+	  return _S_equal_to_vtable<__indices...>[this->index()](*this, __rhs);
+	}
+
+      template<size_t... __indices>
+	constexpr inline bool
+	_M_less_than(const variant& __rhs,
+		     std::index_sequence<__indices...>) const
+	{
+	  auto __lhs_index = this->index();
+	  auto __rhs_index = __rhs.index();
+
+	  if (__lhs_index < __rhs_index)
+	    return true;
+
+	  if (__lhs_index > __rhs_index)
+	    return false;
+
+	  if (this->valueless_by_exception())
+	    return false;
+
+	  return _S_less_than_vtable<__indices...>[__lhs_index](*this, __rhs);
+	}
+
+      template<size_t _Np, typename _Vp>
+	friend constexpr decltype(auto) __detail::__variant::
+#if _GLIBCXX_INLINE_VERSION
+        __7:: // Required due to PR c++/59256
+#endif
+	__get(_Vp&& __v);
+
       template<typename _Vp>
 	friend void* __detail::__variant::
 #if _GLIBCXX_INLINE_VERSION
         __7:: // Required due to PR c++/59256
 #endif
         __get_storage(_Vp&& __v);
+
+      template<typename... _Tp>
+	friend constexpr bool
+	operator==(const variant<_Tp...>& __lhs,
+		   const variant<_Tp...>& __rhs);
+
+      template<typename... _Tp>
+	friend constexpr bool
+	operator<(const variant<_Tp...>& __lhs,
+		  const variant<_Tp...>& __rhs);
     };
 
   template<size_t _Np, typename... _Types>
-    variant_alternative_t<_Np, variant<_Types...>>&
+    constexpr variant_alternative_t<_Np, variant<_Types...>>&
     get(variant<_Types...>& __v)
     {
       static_assert(_Np < sizeof...(_Types),
 		    "The index should be in [0, number of alternatives)");
       if (__v.index() != _Np)
 	__throw_bad_variant_access("Unexpected index");
-      return __detail::__variant::__access<
-	variant_alternative_t<_Np, variant<_Types...>>>(__v);
+      return __detail::__variant::__get<_Np>(__v);
     }
 
   template<size_t _Np, typename... _Types>
-    variant_alternative_t<_Np, variant<_Types...>>&&
+    constexpr variant_alternative_t<_Np, variant<_Types...>>&&
     get(variant<_Types...>&& __v)
     {
       static_assert(_Np < sizeof...(_Types),
 		    "The index should be in [0, number of alternatives)");
       if (__v.index() != _Np)
 	__throw_bad_variant_access("Unexpected index");
-      return __detail::__variant::__access<
-	variant_alternative_t<_Np, variant<_Types...>>>(std::move(__v));
+      return __detail::__variant::__get<_Np>(std::move(__v));
     }
 
   template<size_t _Np, typename... _Types>
-    const variant_alternative_t<_Np, variant<_Types...>>&
+    constexpr const variant_alternative_t<_Np, variant<_Types...>>&
     get(const variant<_Types...>& __v)
     {
       static_assert(_Np < sizeof...(_Types),
 		    "The index should be in [0, number of alternatives)");
       if (__v.index() != _Np)
 	__throw_bad_variant_access("Unexpected index");
-      return __detail::__variant::__access<
-	variant_alternative_t<_Np, variant<_Types...>>>(__v);
+      return __detail::__variant::__get<_Np>(__v);
     }
 
   template<size_t _Np, typename... _Types>
-    const variant_alternative_t<_Np, variant<_Types...>>&&
+    constexpr const variant_alternative_t<_Np, variant<_Types...>>&&
     get(const variant<_Types...>&& __v)
     {
       static_assert(_Np < sizeof...(_Types),
 		    "The index should be in [0, number of alternatives)");
       if (__v.index() != _Np)
 	__throw_bad_variant_access("Unexpected index");
-      return __detail::__variant::__access<
-	variant_alternative_t<_Np, variant<_Types...>>>(std::move(__v));
+      return __detail::__variant::__get<_Np>(std::move(__v));
     }
 
   template<typename _Visitor, typename... _Variants>
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index 5bd4e70..54acc93 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -51,6 +51,14 @@ struct DefaultNoexcept
   DefaultNoexcept& operator=(DefaultNoexcept&&) noexcept = default;
 };
 
+struct nonliteral
+{
+  nonliteral() { }
+
+  bool operator<(const nonliteral&) const;
+  bool operator==(const nonliteral&) const;
+};
+
 void default_ctor()
 {
   static_assert(is_default_constructible_v<variant<int, string>>, "");
@@ -175,22 +183,40 @@ void test_get()
 void test_relational()
 {
   {
-    const variant<int, string> a, b;
-    (void)(a < b);
-    (void)(a > b);
-    (void)(a <= b);
-    (void)(a == b);
-    (void)(a != b);
-    (void)(a >= b);
+    constexpr variant<int, nonliteral> a(42), b(43);
+    static_assert((a < b), "");
+    static_assert(!(a > b), "");
+    static_assert((a <= b), "");
+    static_assert(!(a == b), "");
+    static_assert((a != b), "");
+    static_assert(!(a >= b), "");
   }
   {
-    const monostate a, b;
-    (void)(a < b);
-    (void)(a > b);
-    (void)(a <= b);
-    (void)(a == b);
-    (void)(a != b);
-    (void)(a >= b);
+    constexpr variant<int, nonliteral> a(42), b(42);
+    static_assert(!(a < b), "");
+    static_assert(!(a > b), "");
+    static_assert((a <= b), "");
+    static_assert((a == b), "");
+    static_assert(!(a != b), "");
+    static_assert((a >= b), "");
+  }
+  {
+    constexpr variant<int, nonliteral> a(43), b(42);
+    static_assert(!(a < b), "");
+    static_assert((a > b), "");
+    static_assert(!(a <= b), "");
+    static_assert(!(a == b), "");
+    static_assert((a != b), "");
+    static_assert((a >= b), "");
+  }
+  {
+    constexpr monostate a, b;
+    static_assert(!(a < b), "");
+    static_assert(!(a > b), "");
+    static_assert((a <= b), "");
+    static_assert((a == b), "");
+    static_assert(!(a != b), "");
+    static_assert((a >= b), "");
   }
 }
 
@@ -247,14 +273,59 @@ void test_constexpr()
 	constexpr literal() = default;
     };
 
-    struct nonliteral {
-	nonliteral() { }
-    };
-
     constexpr variant<literal, nonliteral> v{};
     constexpr variant<literal, nonliteral> v1{in_place_type<literal>};
     constexpr variant<literal, nonliteral> v2{in_place_index<0>};
   }
+
+  {
+    constexpr variant<int> a(42);
+    static_assert(get<0>(a) == 42, "");
+  }
+  {
+    constexpr variant<int, nonliteral> a(42);
+    static_assert(get<0>(a) == 42, "");
+  }
+  {
+    constexpr variant<nonliteral, int> a(42);
+    static_assert(get<1>(a) == 42, "");
+  }
+  {
+    constexpr variant<int> a(42);
+    static_assert(get<int>(a) == 42, "");
+  }
+  {
+    constexpr variant<int, nonliteral> a(42);
+    static_assert(get<int>(a) == 42, "");
+  }
+  {
+    constexpr variant<nonliteral, int> a(42);
+    static_assert(get<int>(a) == 42, "");
+  }
+  {
+    constexpr variant<int> a(42);
+    static_assert(get<0>(std::move(a)) == 42, "");
+  }
+  {
+    constexpr variant<int, nonliteral> a(42);
+    static_assert(get<0>(std::move(a)) == 42, "");
+  }
+  {
+    constexpr variant<nonliteral, int> a(42);
+    static_assert(get<1>(std::move(a)) == 42, "");
+  }
+  {
+    constexpr variant<int> a(42);
+    static_assert(get<int>(std::move(a)) == 42, "");
+  }
+  {
+    constexpr variant<int, nonliteral> a(42);
+    static_assert(get<int>(std::move(a)) == 42, "");
+  }
+  {
+    constexpr variant<nonliteral, int> a(42);
+    static_assert(get<int>(std::move(a)) == 42, "");
+  }
 }
 
 void test_pr77641()
commit e80deb97ce75f6a3057c1115c4511fa3dbfb08d9
Author: Tim Shen <timshen@google.com>
Date:   Thu Nov 24 13:35:00 2016 -0800

    2016-11-27  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.

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 a913074..7cc7402 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -335,14 +335,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::make_index_sequence<sizeof...(_Types)>{});
+	_M_index = variant_npos;
+      }
+
       ~_Variant_storage()
-      { _M_destroy_impl(std::make_index_sequence<sizeof...(_Types)>{}); }
+      { _M_reset(); }
 
       _Variadic_union<_Types...> _M_u;
       size_t _M_index;
@@ -359,6 +365,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	_M_index(_Np)
 	{ }
 
+      void _M_reset()
+      { _M_index = variant_npos; }
+
       _Variadic_union<_Types...> _M_u;
       size_t _M_index;
     };
@@ -441,6 +450,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>...,
@@ -458,16 +481,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;
       }
@@ -687,6 +701,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
@@ -865,8 +890,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   { return false; }
 
   template<typename... _Types>
-    inline auto swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
-    noexcept(noexcept(__lhs.swap(__rhs))) -> decltype(__lhs.swap(__rhs))
+    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); }
 
   class bad_variant_access : public exception
@@ -1028,25 +1055,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 +1093,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 +1122,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 +1137,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 +1285,16 @@ _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::make_index_sequence<sizeof...(_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((noexcept(hash<decay_t<_Types>>{}(std::declval<_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 54acc93..b973143 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() { }
@@ -222,9 +231,9 @@ void test_relational()
 
 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()
@@ -370,7 +379,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>, "");
 
@@ -378,3 +388,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()
 {
commit 1503eff1772d0ad7638dad2507d860ea56039714
Author: Tim Shen <timshen@google.com>
Date:   Sat Nov 26 20:10:40 2016 -0800

    2016-11-27  Tim Shen  <timshen@google.com>
    
            * include/std/variant (visit): Make visit constexpr. Also cleanup
            __get_alternative and __storage, since we don't support reference/void
            alternatives any more.
            * testsuite/20_util/variant/compile.cc: Add tests.

diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 7cc7402..1159772 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -42,10 +42,33 @@
 #include <bits/move.h>
 #include <bits/uses_allocator.h>
 #include <bits/functional_hash.h>
+#include <bits/invoke.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace __detail
+{
+namespace __variant
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<size_t _Np, typename... _Types>
+    struct _Nth_type;
+
+  template<size_t _Np, typename _First, typename... _Rest>
+    struct _Nth_type<_Np, _First, _Rest...>
+    : _Nth_type<_Np-1, _Rest...> { };
+
+  template<typename _First, typename... _Rest>
+    struct _Nth_type<0, _First, _Rest...>
+    { using type = _First; };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace __variant
+} // namespace __detail
+
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename... _Types> class tuple;
   template<typename... _Types> class variant;
@@ -99,6 +122,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   constexpr size_t variant_npos = -1;
 
+  template<size_t _Np, typename... _Types>
+    constexpr variant_alternative_t<_Np, variant<_Types...>>&
+    get(variant<_Types...>&);
+
+  template<size_t _Np, typename... _Types>
+    constexpr variant_alternative_t<_Np, variant<_Types...>>&&
+    get(variant<_Types...>&&);
+
+  template<size_t _Np, typename... _Types>
+    constexpr variant_alternative_t<_Np, variant<_Types...>> const&
+    get(const variant<_Types...>&);
+
+  template<size_t _Np, typename... _Types>
+    constexpr variant_alternative_t<_Np, variant<_Types...>> const&&
+    get(const variant<_Types...>&&);
+
 _GLIBCXX_END_NAMESPACE_VERSION
 
 namespace __detail
@@ -119,41 +158,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       std::integral_constant<size_t, is_same_v<_Tp, _First>
 	? 0 : __index_of_v<_Tp, _Rest...> + 1> {};
 
-  // Extract _From's qualifiers and references and apply it to _To.
-  // __reserved_type_map<const int&, char> is const char&.
-  template<typename _From, typename _To>
-    struct __reserved_type_map_impl
-    { using type = _To; };
-
-  template<typename _From, typename _To>
-    using __reserved_type_map =
-      typename __reserved_type_map_impl<_From, _To>::type;
-
-  template<typename _From, typename _To>
-    struct __reserved_type_map_impl<_From&, _To>
-    { using type = add_lvalue_reference_t<__reserved_type_map<_From, _To>>; };
-
-  template<typename _From, typename _To>
-    struct __reserved_type_map_impl<_From&&, _To>
-    { using type = add_rvalue_reference_t<__reserved_type_map<_From, _To>>; };
-
-  template<typename _From, typename _To>
-    struct __reserved_type_map_impl<const _From, _To>
-    { using type = add_const_t<__reserved_type_map<_From, _To>>; };
-
-  template<typename _From, typename _To>
-    struct __reserved_type_map_impl<volatile _From, _To>
-    { using type = add_volatile_t<__reserved_type_map<_From, _To>>; };
-
-  template<typename _From, typename _To>
-    struct __reserved_type_map_impl<const volatile _From, _To>
-    { using type = add_cv_t<__reserved_type_map<_From, _To>>; };
-
-  // This abstraction might be useful for future features,
-  // e.g. boost::recursive_wrapper.
-  template<typename _Alternative>
-    using __storage = _Alternative;
-
   // _Uninitialized nullify the destructor calls.
   // This is necessary, since we define _Variadic_union as a recursive union,
   // and we don't want to inspect the union members one by one in its dtor,
@@ -215,16 +219,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  _M_storage;
     };
 
-  // Given a qualified storage type, return the desired reference.
-  // For example, variant<int>&& stores the int as __storage<int>, and
-  // _Qualified_storage will be __storage<int>&&.
-  template<typename _Qualified_storage>
-    decltype(auto)
-    __get_alternative(void* __ptr)
+  template<typename _Ref>
+    _Ref __ref_cast(void* __ptr)
     {
-      using _Storage = decay_t<_Qualified_storage>;
-      return __reserved_type_map<_Qualified_storage, _Storage>(
-	*static_cast<_Storage*>(__ptr));
+      return static_cast<_Ref>(*static_cast<remove_reference_t<_Ref>*>(__ptr));
     }
 
   template<typename _Union>
@@ -247,7 +245,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Lhs, typename _Rhs>
     constexpr void
     __erased_ctor(void* __lhs, void* __rhs)
-    { ::new (__lhs) decay_t<_Lhs>(__get_alternative<_Rhs>(__rhs)); }
+    { ::new (__lhs) remove_reference_t<_Lhs>(__ref_cast<_Rhs>(__rhs)); }
 
   template<typename _Variant, size_t _Np>
     constexpr void
@@ -261,14 +259,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Lhs, typename _Rhs>
     constexpr void
     __erased_assign(void* __lhs, void* __rhs)
-    { __get_alternative<_Lhs>(__lhs) = __get_alternative<_Rhs>(__rhs); }
+    { __ref_cast<_Lhs>(__lhs) = __ref_cast<_Rhs>(__rhs); }
 
   template<typename _Lhs, typename _Rhs>
     constexpr void
     __erased_swap(void* __lhs, void* __rhs)
     {
       using std::swap;
-      swap(__get_alternative<_Lhs>(__lhs), __get_alternative<_Rhs>(__rhs));
+      swap(__ref_cast<_Lhs>(__lhs), __ref_cast<_Rhs>(__rhs));
     }
 
   template<typename _Variant, size_t _Np>
@@ -290,7 +288,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp>
     constexpr size_t
     __erased_hash(void* __t)
-    { return std::hash<decay_t<_Tp>>{}(__get_alternative<_Tp>(__t)); }
+    {
+      return std::hash<remove_cv_t<remove_reference_t<_Tp>>>{}(
+	  __ref_cast<_Tp>(__t));
+    }
 
   // Defines members and ctors.
   template<typename... _Types>
@@ -394,8 +395,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	if (__rhs._M_valid())
 	  {
 	    static constexpr void (*_S_vtable[])(void*, void*) =
-	      { &__erased_ctor<__storage<_Types>&,
-			       const __storage<_Types>&>... };
+	      { &__erased_ctor<_Types&, const _Types&>... };
 	    _S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
 	    this->_M_index = __rhs._M_index;
 	  }
@@ -407,7 +407,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	if (__rhs._M_valid())
 	  {
 	    static constexpr void (*_S_vtable[])(void*, void*) =
-	      { &__erased_ctor<__storage<_Types>&, __storage<_Types>&&>... };
+	      { &__erased_ctor<_Types&, _Types&&>... };
 	    _S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
 	    this->_M_index = __rhs._M_index;
 	  }
@@ -427,8 +427,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    if (__rhs._M_valid())
 	      {
 		static constexpr void (*_S_vtable[])(void*, void*) =
-		  { &__erased_assign<__storage<_Types>&,
-				     const __storage<_Types>&>... };
+		  { &__erased_assign<_Types&, const _Types&>... };
 		_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
 	      }
 	  }
@@ -474,8 +473,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    if (__rhs._M_valid())
 	      {
 		static constexpr void (*_S_vtable[])(void*, void*) =
-		  { &__erased_assign<__storage<_Types>&,
-				     __storage<_Types>&&>... };
+		  { &__erased_assign<_Types&, _Types&&>... };
 		_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
 	      }
 	  }
@@ -560,20 +558,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     void* __get_storage(_Variant&& __v)
     { return __v._M_storage(); }
 
-  // A helper used to create variadic number of _To types.
-  template<typename _From, typename _To>
-    using _To_type = _To;
-
-  // Call the actual visitor.
-  // _Args are qualified storage types.
-  template<typename _Visitor, typename... _Args>
-    decltype(auto)
-    __visit_invoke(_Visitor&& __visitor, _To_type<_Args, void*>... __ptrs)
-    {
-      return std::forward<_Visitor>(__visitor)(
-	  __get_alternative<_Args>(__ptrs)...);
-    }
-
   // Used for storing multi-dimensional vtable.
   template<typename _Tp, size_t... _Dimensions>
     struct _Multi_array
@@ -597,107 +581,112 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
   // Creates a multi-dimensional vtable recursively.
-  // _Variant_tuple is initially the input from visit(), and gets gradually
-  // consumed.
-  // _Arg_tuple is enumerated alternative sequence, represented by a
-  // qualified storage.
   //
   // For example,
   // visit([](auto, auto){},
-  //       variant<int, char>(),
-  //       variant<float, double, long double>())
+  //       variant<int, char>(),  // typedef'ed as V1
+  //       variant<float, double, long double>())  // typedef'ed as V2
   // will trigger instantiations of:
-  // __gen_vtable_impl<_Multi_array<void(*)(void*, void*), 2, 3>,
-  //                   tuple<variant<int, char>,
-  //                         variant<float, double, long double>>,
-  //                   tuple<>>
-  //   __gen_vtable_impl<_Multi_array<void(*)(void*, void*), 3>,
-  //                     tuple<variant<float, double, long double>>,
-  //                     tuple<int>>
-  //     __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
-  //                       tuple<>,
-  //                       tuple<int, float>>
-  //     __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
-  //                       tuple<>,
-  //                       tuple<int, double>>
-  //     __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
-  //                       tuple<>,
-  //                       tuple<int, long double>>
-  //   __gen_vtable_impl<_Multi_array<void(*)(void*, void*), 3>,
-  //                     tuple<variant<float, double, long double>>,
-  //                     tuple<char>>
-  //     __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
-  //                       tuple<>,
-  //                       tuple<char, float>>
-  //     __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
-  //                       tuple<>,
-  //                       tuple<char, double>>
-  //     __gen_vtable_impl<_Multi_array<void(*)(void*, void*)>,
-  //                       tuple<>,
-  //                       tuple<char, long double>>
+  // __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 2, 3>,
+  //                   tuple<V1&&, V2&&>, std::index_sequence<>>
+  //   __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>,
+  //                     tuple<V1&&, V2&&>, std::index_sequence<0>>
+  //     __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+  //                       tuple<V1&&, V2&&>, std::index_sequence<0, 0>>
+  //     __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+  //                       tuple<V1&&, V2&&>, std::index_sequence<0, 1>>
+  //     __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+  //                       tuple<V1&&, V2&&>, std::index_sequence<0, 2>>
+  //   __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&), 3>,
+  //                     tuple<V1&&, V2&&>, std::index_sequence<1>>
+  //     __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+  //                       tuple<V1&&, V2&&>, std::index_sequence<1, 0>>
+  //     __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+  //                       tuple<V1&&, V2&&>, std::index_sequence<1, 1>>
+  //     __gen_vtable_impl<_Multi_array<void(*)(V1&&, V2&&)>,
+  //                       tuple<V1&&, V2&&>, std::index_sequence<1, 2>>
   // The returned multi-dimensional vtable can be fast accessed by the visitor
   // using index calculation.
-  template<typename _Array_type, typename _Variant_tuple, typename _Arg_tuple>
+  template<typename _Array_type, typename _Variant_tuple, typename _Index_seq>
     struct __gen_vtable_impl;
 
-  template<typename _Array_type, typename _First, typename... _Rest,
-	   typename... _Args>
-    struct __gen_vtable_impl<_Array_type, tuple<_First, _Rest...>,
-			     tuple<_Args...>>
+  template<typename _Result_type, typename _Visitor, size_t... __unused,
+	   typename... _Variants, size_t... __indices>
+    struct __gen_vtable_impl<
+	_Multi_array<_Result_type (*)(_Visitor, _Variants...), __unused...>,
+	tuple<_Variants...>, std::index_sequence<__indices...>>
     {
+      using _Next =
+	  remove_reference_t<typename _Nth_type<sizeof...(__indices),
+			     _Variants...>::type>;
+      using _Array_type =
+	  _Multi_array<_Result_type (*)(_Visitor, _Variants...), __unused...>;
+
       static constexpr _Array_type
       _S_apply()
       {
 	_Array_type __vtable{};
 	_S_apply_all_alts(
-	  __vtable, make_index_sequence<variant_size_v<decay_t<_First>>>());
+	  __vtable, make_index_sequence<variant_size_v<_Next>>());
 	return __vtable;
       }
 
-      template<size_t... __indices>
+      template<size_t... __var_indices>
 	static constexpr void
-	_S_apply_all_alts(_Array_type& __vtable, index_sequence<__indices...>)
-	{ (_S_apply_single_alt<__indices>(__vtable._M_arr[__indices]), ...); }
+	_S_apply_all_alts(_Array_type& __vtable,
+			  std::index_sequence<__var_indices...>)
+	{
+	  (_S_apply_single_alt<__var_indices>(
+	     __vtable._M_arr[__var_indices]), ...);
+	}
 
       template<size_t __index, typename T>
 	static constexpr void
 	_S_apply_single_alt(T& __element)
 	{
-	  using _Alternative = variant_alternative_t<__index, decay_t<_First>>;
-	  using _Qualified_storage = __reserved_type_map<
-	    _First, __storage<_Alternative>>;
+	  using _Alternative = variant_alternative_t<__index, _Next>;
 	  __element = __gen_vtable_impl<
-	    decay_t<decltype(__element)>, tuple<_Rest...>,
-	    tuple<_Args..., _Qualified_storage>>::_S_apply();
+	    remove_reference_t<
+	      decltype(__element)>, tuple<_Variants...>,
+	      std::index_sequence<__indices..., __index>>::_S_apply();
 	}
     };
 
-  template<typename _Result_type, typename _Visitor, typename... _Args>
+  template<typename _Result_type, typename _Visitor, typename... _Variants,
+	   size_t... __indices>
     struct __gen_vtable_impl<
-      _Multi_array<_Result_type (*)(_Visitor, _To_type<_Args, void*>...)>,
-		   tuple<>, tuple<_Args...>>
+      _Multi_array<_Result_type (*)(_Visitor, _Variants...)>,
+		   tuple<_Variants...>, std::index_sequence<__indices...>>
     {
       using _Array_type =
-	_Multi_array<_Result_type (*)(_Visitor&&, _To_type<_Args, void*>...)>;
+	  _Multi_array<_Result_type (*)(_Visitor&&, _Variants...)>;
+
+      decltype(auto)
+      static constexpr __visit_invoke(_Visitor&& __visitor, _Variants... __vars)
+      {
+	return __invoke(std::forward<_Visitor>(__visitor),
+			std::get<__indices>(
+			    std::forward<_Variants>(__vars))...);
+      }
 
       static constexpr auto
       _S_apply()
-      { return _Array_type{&__visit_invoke<_Visitor, _Args...>}; }
+      { return _Array_type{&__visit_invoke}; }
     };
 
   template<typename _Result_type, typename _Visitor, typename... _Variants>
     struct __gen_vtable
     {
-      using _Func_ptr =
-	_Result_type (*)(_Visitor&&, _To_type<_Variants, void*>...);
+      using _Func_ptr = _Result_type (*)(_Visitor&&, _Variants...);
       using _Array_type =
-	_Multi_array<_Func_ptr, variant_size_v<decay_t<_Variants>>...>;
+	  _Multi_array<_Func_ptr,
+		       variant_size_v<remove_reference_t<_Variants>>...>;
 
       static constexpr _Array_type
       _S_apply()
       {
-	return __gen_vtable_impl<
-	  _Array_type, tuple<_Variants...>, tuple<>>::_S_apply();
+	return __gen_vtable_impl<_Array_type, tuple<_Variants...>,
+				 std::index_sequence<>>::_S_apply();
       }
     };
 
@@ -727,22 +716,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __v.index() == __detail::__variant::__index_of_v<_Tp, _Types...>;
     }
 
-  template<size_t _Np, typename... _Types>
-    constexpr variant_alternative_t<_Np, variant<_Types...>>&
-    get(variant<_Types...>&);
-
-  template<size_t _Np, typename... _Types>
-    constexpr variant_alternative_t<_Np, variant<_Types...>>&&
-    get(variant<_Types...>&&);
-
-  template<size_t _Np, typename... _Types>
-    constexpr variant_alternative_t<_Np, variant<_Types...>> const&
-    get(const variant<_Types...>&);
-
-  template<size_t _Np, typename... _Types>
-    constexpr variant_alternative_t<_Np, variant<_Types...>> const&&
-    get(const variant<_Types...>&&);
-
   template<typename _Tp, typename... _Types>
     constexpr inline _Tp& get(variant<_Types...>& __v)
     {
@@ -867,7 +840,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return !(__lhs < __rhs); }
 
   template<typename _Visitor, typename... _Variants>
-    decltype(auto) visit(_Visitor&&, _Variants&&...);
+    constexpr decltype(auto) visit(_Visitor&&, _Variants&&...);
 
   struct monostate { };
 
@@ -967,9 +940,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	using __accepted_type = __to_type<__accepted_index<_Tp>>;
 
       template<typename _Tp>
-	using __storage = __detail::__variant::__storage<_Tp>;
-
-      template<typename _Tp>
 	static constexpr size_t __index_of =
 	  __detail::__variant::__index_of_v<_Tp, _Types...>;
 
@@ -1129,8 +1099,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    if (this->_M_valid())
 	      {
 		static constexpr void (*_S_vtable[])(void*, void*) =
-		  { &__detail::__variant::__erased_swap<
-		      __storage<_Types>&, __storage<_Types>&>... };
+		  { &__detail::__variant::__erased_swap<_Types&, _Types&>... };
 		_S_vtable[__rhs._M_index](this->_M_storage(),
 					  __rhs._M_storage());
 	      }
@@ -1270,17 +1239,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 
   template<typename _Visitor, typename... _Variants>
-    decltype(auto)
+    constexpr decltype(auto)
     visit(_Visitor&& __visitor, _Variants&&... __variants)
     {
+      if ((__variants.valueless_by_exception() || ...))
+	__throw_bad_variant_access("Unexpected index");
+
       using _Result_type =
 	decltype(std::forward<_Visitor>(__visitor)(get<0>(__variants)...));
-      static constexpr auto _S_vtable =
+      constexpr auto _S_vtable =
 	__detail::__variant::__gen_vtable<
 	  _Result_type, _Visitor&&, _Variants&&...>::_S_apply();
       auto __func_ptr = _S_vtable._M_access(__variants.index()...);
       return (*__func_ptr)(std::forward<_Visitor>(__visitor),
-			   __detail::__variant::__get_storage(__variants)...);
+			   std::forward<_Variants>(__variants)...);
     }
 
   template<typename... _Types>
@@ -1300,7 +1272,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  {
 	    namespace __edv = __detail::__variant;
 	    static constexpr size_t (*_S_vtable[])(void*) =
-	      { &__edv::__erased_hash<const __edv::__storage<_Types>&>... };
+	      { &__edv::__erased_hash<const _Types&>... };
 	    return hash<size_t>{}(__t.index())
 	      + _S_vtable[__t.index()](__edv::__get_storage(__t));
 	  }
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
index b973143..8f77ffb 100644
--- a/libstdc++-v3/testsuite/20_util/variant/compile.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -260,6 +260,22 @@ void test_visit()
     };
     visit(Visitor(), variant<int, char>(), variant<float, double>());
   }
+  {
+    struct Visitor
+    {
+      constexpr bool operator()(const int&) { return true; }
+      constexpr bool operator()(const nonliteral&) { return false; }
+    };
+    static_assert(visit(Visitor(), variant<int, nonliteral>(0)), "");
+  }
+  {
+    struct Visitor
+    {
+      constexpr bool operator()(const int&) { return true; }
+      constexpr bool operator()(const nonliteral&) { return false; }
+    };
+    static_assert(visit(Visitor(), variant<int, nonliteral>(0)), "");
+  }
 }
 
 void test_constexpr()

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]