diff mbox

Implement std::experimental::variant

Message ID CAG4ZjNnY6iveWFYtVRwW_c0mB31JmRbdzyu8o98oOaWEVsp7uA@mail.gmail.com
State New
Headers show

Commit Message

Tim Shen Aug. 6, 2016, 5:45 a.m. UTC
On Fri, Aug 5, 2016 at 4:08 AM, Jonathan Wakely <jwakely@redhat.com> wrote:
>> --- a/libstdc++-v3/include/bits/uses_allocator.h
>> +++ b/libstdc++-v3/include/bits/uses_allocator.h
>> @@ -113,6 +113,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>     constexpr bool uses_allocator_v = uses_allocator<_Tp, _Alloc>::value;
>> #endif // C++17
>>
>> +  template<typename _Tp, typename _Alloc, typename... _Args>
>> +    struct __is_uses_allocator_constructible
>> +    : conditional<uses_allocator<_Tp, _Alloc>::value,
>> +      __or_<is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>,
>> +           is_constructible<_Tp, _Args..., _Alloc>>,
>> +      is_constructible<_Tp, _Args...>>::type { };
>> +
>> +  template<typename _Tp, typename _Alloc, typename... _Args>
>> +    static constexpr bool __is_uses_allocator_constructible_v =
>> +      __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
>
>
> This doesn't need to be 'static'

Done.

>
>
>> +  template<typename _Tp, typename _Alloc, typename... _Args>
>> +    struct __is_nothrow_uses_allocator_constructible
>> +    : conditional<uses_allocator<_Tp, _Alloc>::value,
>> +      __or_<is_nothrow_constructible<_Tp, allocator_arg_t, _Alloc,
>> _Args...>,
>> +           is_nothrow_constructible<_Tp, _Args..., _Alloc>>,
>> +      is_nothrow_constructible<_Tp, _Args...>>::type { };
>
>
> I wonder if there's any benefit to removing the duplication in the
> definitions of __is_nothrow_uses_allocator_constructible and
> __is_uses_allocator_constructible by defining a single template that
> can be instantation with either is_constructible or
> is_nothrow_constructible as needed:
>
>  template<template<typename, typename...> class _Trait, typename _Tp,
>           typename _Alloc, typename... _Args>
>    struct __is_uses_allocator_constructible_impl
>    : conditional<uses_allocator<_Tp, _Alloc>::value,
>      __or_<_Trait<_Tp, allocator_arg_t, _Alloc, _Args...>,
>          _Trait<_Tp, _Args..., _Alloc>>,
>      _Trait<_Tp, _Args...>>::type { };
>
>  template<typename _Tp, typename _Alloc, typename... _Args>
>    using __is_uses_allocator_constructible
>      = __is_uses_allocator_constructible_impl<is_constructible,
>                                               _Tp, _Alloc, _Args...>;
>
>  template<typename _Tp, typename _Alloc, typename... _Args>
>    using __is_nothrow_uses_allocator_constructible
>      = __is_uses_allocator_constructible_impl<is_nothrow_constructible,
>                                               _Tp, _Alloc, _Args...>;
>
> What do you think?
>
> (The variable templates would be unchanged).

Done. I don't have strong opinion on this.

>
>
>> +
>> +  template<typename _Tp, typename _Alloc, typename... _Args>
>> +    static constexpr bool __is_nothrow_uses_allocator_constructible_v =
>> +      __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
>
>
> This should be using __is_nothrow_uses_allocator_constructible
> (and doesn't need to be static)

Good catch. :)

>
>
>
>> +
>> +  template<typename _Tp, typename... _Args>
>> +    void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr,
>> +                                        _Args&&... __args)
>> +    { new (__ptr) _Tp(forward<_Args>(__args)...); }
>> +
>> +  template<typename _Tp, typename _Alloc, typename... _Args>
>> +    void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp*
>> __ptr,
>> +                                        _Args&&... __args)
>> +    { new (__ptr) _Tp(allocator_arg, *__a._M_a,
>> forward<_Args>(__args)...); }
>> +
>> +  template<typename _Tp, typename _Alloc, typename... _Args>
>> +    void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp*
>> __ptr,
>> +                                        _Args&&... __args)
>> +    { new (__ptr) _Tp(forward<_Args>(__args)..., *__a._M_a); }
>
>
> I think these all need to use ::new (__ptr) with qualification, see
> below.

Done. I didn't add a testcase for this. Do you think that we need one/some?

>
>
>> +/** @file variant
>> + *  This is a TS C++ Library header.
>
>
> This should be updated.

Done.

>
>> + */
>> +
>> +#ifndef _GLIBCXX_VARIANT
>> +#define _GLIBCXX_VARIANT 1
>> +
>> +#pragma GCC system_header
>> +
>> +#if __cplusplus <= 201103L
>
>
> This should be 201402L

Done.

>
>> +# include <bits/c++17_warning.h>
>> +#else
>> +
>> +#include <tuple>
>> +#include <type_traits>
>> +#include <utility>
>> +#include <bits/enable_special_members.h>
>> +#include <bits/uses_allocator.h>
>> +
>> +namespace std _GLIBCXX_VISIBILITY(default)
>> +{
>> +_GLIBCXX_BEGIN_NAMESPACE_VERSION
>> +
>> +  template<typename... _Types> class variant;
>> +
>> +  template<typename _Variant>
>> +    struct variant_size;
>> +
>> +  template<typename _Variant>
>> +    struct variant_size<const _Variant> : variant_size<_Variant> {};
>> +
>> +  template<typename _Variant>
>> +    struct variant_size<volatile _Variant> : variant_size<_Variant> {};
>> +
>> +  template<typename _Variant>
>> +    struct variant_size<const volatile _Variant> : variant_size<_Variant>
>> {};
>> +
>> +  template<typename... _Types>
>> +    struct variant_size<variant<_Types...>>
>> +    : std::integral_constant<size_t, sizeof...(_Types)> {};
>> +
>> +  template<typename _Variant>
>> +    static constexpr size_t variant_size_v =
>> variant_size<_Variant>::value;
>
>
> We don't need 'static' here.

Done.

>
>> +
>> +  template<size_t _Np, typename _Variant>
>> +    struct variant_alternative;
>> +
>> +  template<size_t _Np, typename _First, typename... _Rest>
>> +    struct variant_alternative<_Np, variant<_First, _Rest...>>
>> +    : variant_alternative<_Np-1, variant<_Rest...>> {};
>> +
>> +  template<typename _First, typename... _Rest>
>> +    struct variant_alternative<0, variant<_First, _Rest...>>
>> +    { using type = _First; };
>> +
>> +  template<size_t _Np, typename _Variant>
>> +    using variant_alternative_t =
>> +      typename variant_alternative<_Np, _Variant>::type;
>> +
>> +  static constexpr size_t variant_npos = -1;
>
>
> Or here.

Done.

>
>> +
>> +namespace __detail
>> +{
>> +namespace __variant
>> +{
>> +  // Returns the first apparence of _Tp in _Types.
>> +  // Returns sizeof...(_Types) if _Tp is not in _Types.
>> +  template<typename _Tp, typename... _Types>
>> +    struct __index_of : std::integral_constant<size_t, 0> {};
>> +
>> +  template<typename _Tp, typename... _Types>
>> +    static constexpr size_t __index_of_v = __index_of<_Tp,
>> _Types...>::value;
>
>
> Or here.

Done.

>
>> +  // Stores a void alternative, until void becomes a regular type.
>
>
> Personally I hope it won't become a regular type :-)

Sorry :)

Do you mind to share your insights?

> Let's say "because void is not a regault type" here. That avoids the
> comment becoming stale. If the language changes we'll need to update
> this bit of the code anyway. so the comment can be updated then too.

Done.

>
>> +      return __reserved_type_map<_Qualified_storage, _Alternative>(
>> +       *static_cast<_Storage*>(__ptr));
>> +    }
>> +
>> +  // Various functions as "vtable" entries, where those vtables are used
>> by
>> +  // polymorphic operations.
>> +  template<typename _Lhs, typename _Rhs>
>> +    constexpr void
>> +    __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));
>> +    }
>> +
>> +  template<typename _Tp>
>> +    constexpr void
>> +    __erased_dtor(void* __ptr)
>> +    {
>> +      using _Storage = decay_t<_Tp>;
>> +      static_cast<_Storage*>(__ptr)->~_Storage();
>> +    }
>
>
> This is almost the same as the __exception_ptr::__dest_thunk(void*)
> function we're about to add with Gleb's patch. I wonder if we should
> reuse the same function in both places. We can do that later though.

Added a TODO.

>
>
>> +  // For how many times does _Tp appear in _Tuple?
>> +  template<typename _Tp, typename _Tuple>
>> +    struct __tuple_count;
>> +
>> +  template<typename _Tp, typename _Tuple>
>> +    static constexpr size_t __tuple_count_v = __tuple_count<_Tp,
>> _Tuple>::value;
>> +
>> +  template<typename _Tp, typename... _Types>
>> +    struct __tuple_count<_Tp, tuple<_Types...>>
>> +    : integral_constant<size_t, 0> { };
>> +
>> +  template<typename _Tp, typename _First, typename... _Rest>
>> +    struct __tuple_count<_Tp, tuple<_First, _Rest...>>
>> +    : integral_constant<
>> +       size_t,
>> +       __tuple_count_v<_Tp, tuple<_Rest...>> + is_same_v<_Tp, _First>> {
>> };
>> +
>> +  template<typename _Tp, typename... _Types>
>> +    static constexpr bool __exactly_once =
>> +      __tuple_count_v<_Tp, tuple<_Types...>> == 1;
>
>
> I was going to say we could reuse this nice utility in <tuple> for
> std::get<T> but actually our implementation does need to count the
> types, it just works by an implicit conversion to the unique base
> class with that type (and is ambiguous otherwise). We could use your
> __exactly_once to give a nice static assertion for invalid calls to
> std::get<T>, but that would add unnecessary compile-time overhead to
> valid calls. Anyway, that's another tangent that isn't relevant to
> variant ...

These are good thoughts! Added a TODO.

Removed static.

>
>
>> +
>> +  // Takes _Types and create an overloaded _S_fun for each type.
>> +  // If a type appears for more than one times in _Types,
>
>
> s/for more than one times/more than once/

Done.

>
>> +  // only create one overload for it.
>> +  template<typename... _Types>
>> +    struct __overload_set
>> +    { static void _S_fun(); };
>> +
>> +  template<typename _First, typename... _Rest>
>> +    struct __overload_set<_First, _Rest...> : __overload_set<_Rest...>
>> +    {
>> +      using __overload_set<_Rest...>::_S_fun;
>> +      static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First);
>> +    };
>> +
>> +  template<typename... _Rest>
>> +    struct __overload_set<void, _Rest...> : __overload_set<_Rest...>
>> +    {
>> +      using __overload_set<_Rest...>::_S_fun;
>> +    };
>> +
>> +  // Helper for variant(_Tp&&) and variant::operator=(_Tp&&).
>> +  // __accepted_index maps the arbitrary _Tp to an alternative type in
>> _Variant.
>> +  template<typename _Tp, typename _Variant, typename = void>
>> +    struct __accepted_index
>> +    { static constexpr size_t value = variant_npos; };
>> +
>> +  template<typename _Tp, typename... _Types>
>> +    struct __accepted_index<
>> +      _Tp, variant<_Types...>,
>> +      decltype(__overload_set<_Types...>::_S_fun(declval<_Tp>()),
>
>
> This I think all uses of declval<_Tp> need to be qualified with std::
>
>> +              declval<void>())>
>
>
> (The decval<void>() case is OK as that won't do ADL).

Done for all of them, for consistency.

>
>> +  template<typename _Array_type, typename _First, typename... _Rest,
>> +          typename... _Args>
>> +    struct __gen_vtable_impl<_Array_type, tuple<_First, _Rest...>,
>> +                            tuple<_Args...>>
>
>
> Do you actually need to use std::tuple here, or would something much
> more lightweight be OK too?

I actually just need a template to hold all alternatives. How about
forward declaring tuple, and not including the header?

I was totally unaware of the cost of <tuple>, and tried to use
tuple_cat() on a bunch of function calls:
(void)tuple_cat(foo<_Types>()...) where foo returns tuple<>.

But not we have fold expression \o/! So I can directly write:
(foo<_Types>, ...)

which is perfect.

>
> For example we have std::tr2::__reflection_typelist in
> <tr2/type_traits>. Or it looks like this could just use something even
> simpler:
>  template<typename... T> struct __type_list
>
> What we really need is to standardize Eric Niebler's metapgroamming
> library, or Peter Dimov's one, or *anything* that gives us a set of
> nice tools for doing this stuff. std::tuple is a very heavyweight type
> to use for simple type lists.

I don't need the whole pack of metaprogramming tools here, lucky me. ;)

>
> It doesn't look like you're using any members of std::tuple, so maybe
> it won't actually instantiate any of the base classes or member
> functions, which is what would be inefficient.
>
>> +  template<typename _Tp, typename... _Types>
>> +    _Tp& get(variant<_Types...>& __v)
>
>
> Please add 'inline' to these one-line functions. All the get and
> get_if overloads are tiny.

What's the difference between non-inline function templates and inline
function templates? At some point you may already explained that to
me, but I'm still confused.

>
>> +  template<typename... _Types>
>> +    bool operator!=(const variant<_Types...>& __lhs,
>> +                   const variant<_Types...>& __rhs)
>> +    { return !(__lhs == __rhs); }
>
>
> Inline.

Done.

>
>> +  template<typename... _Types>
>> +    bool operator>(const variant<_Types...>& __lhs,
>> +                  const variant<_Types...>& __rhs)
>> +    { return __rhs < __lhs; }
>
>
> Inline.

Done.

>
>> +  template<typename... _Types>
>> +    bool operator<=(const variant<_Types...>& __lhs,
>> +                   const variant<_Types...>& __rhs)
>> +    { return !(__lhs > __rhs); }
>
>
> etc. :-)

Done.

>
>> +  constexpr bool operator<(monostate, monostate) noexcept
>> +  { return false; }
>
>
> These are implicitly inline because of 'constexpr' so that's OK :-)
>
>> +      template<size_t _Np, typename... _Args>
>> +       void emplace(_Args&&... __args)
>> +       {
>> +         static_assert(_Np < sizeof...(_Types),
>> +                       "_Np should be in [0, number of alternatives)");
>> +         this->~variant();
>> +         __try
>> +           {
>> +             new (this) variant(in_place<_Np>,
>> +                                forward<_Args>(__args)...);
>
>
> I think this needs to be qualified:  ::new (this) ...
>
> Otherwise you can't emplace some types into a variant:
>
>  #include <cstddef>
>  #include <new>
>
>  struct foo {
>    static void* operator new(std::size_t, void* p);
>  };
>
>  template<typename T>
>  struct variant {
>    alignas(T) char buf[sizeof(T)];
>    void emplace(T t) {
>      new (this) T(t);
>    }
>  };
>
>  int main()
>  {
>    variant<foo> v;
>    v.emplace( {} );
>  }
>
> (We get this wrong in std::function too, which I'll fix).

Done.

>
>> +  // To hornor algebraic data type, variant<> should be a bottom type,
>> which
>
>
> s/hornor/honor/

...Oops. :)

>
>> +  // is 0 (as opposed to a void type, which is 1). Use incomplete type to
>> model
>> +  // bottom type.
>> +  template<> class variant<>;
>> +
>> +  template<size_t _Np, typename... _Types>
>> +    variant_alternative_t<_Np, variant<_Types...>>&
>> +    get(variant<_Types...>& __v)
>> +    {
>> +      static_assert(_Np < sizeof...(_Types),
>> +                   "_Np should be in [0, number of alternatives)");
>
>
> I wonder if this message would be more user-friendly if it said
> "index" instead of "_Np", since _Np isn't a symbol the user will
> recognize. What do you think?

Done. Sorry, I don't always have time to care about user-friendliness.
When I do, I don't. ;)

>
>> +      using argument_type = monostate;
>> +
>> +      size_t
>> +      operator()(const monostate& __t) const noexcept
>> +      {
>> +       constexpr size_t __magic_monostate_hash =
>> +         static_cast<size_t>(-7777);
>> +       return static_cast<size_t>(__magic_monostate_hash);
>
>
> Do we really need to static_cast<size_t> again when it's already a
> size_t? :-)
> Do we need either static_cast?
>
>         constexpr size_t __magic_monostate_hash = -7777;
>         return __magic_monostate_hash;

Done. I seriously have no idea why that will happen.

>
>> diff --git a/libstdc++-v3/testsuite/experimental/variant/compile.cc
>> b/libstdc++-v3/testsuite/experimental/variant/compile.cc
>> new file mode 100644
>> index 0000000..5cc7738
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/experimental/variant/compile.cc
>> @@ -0,0 +1,392 @@
>> +// { dg-options "-std=gnu++17" }
>> +// { dg-do compile }
>> +
>> +// Copyright (C) 2016 Free Software Foundation, Inc.
>> +//
>> +// This file is part of the GNU ISO C++ Library.  This library is free
>> +// software; you can redistribute it and/or modify it under the
>> +// terms of the GNU General Public License as published by the
>> +// Free Software Foundation; either version 3, or (at your option)
>> +// any later version.
>> +
>> +// This library is distributed in the hope that it will be useful,
>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +// GNU General Public License for more details.
>> +
>> +// You should have received a copy of the GNU General Public License
>> along
>> +// with this library; see the file COPYING3.  If not see
>> +// <http://www.gnu.org/licenses/>.
>> +
>> +#include <variant>
>> +#include <string>
>> +#include <vector>
>> +#include <testsuite_hooks.h>
>
>
> There's no need for testsuite_hooks.h in this { do-do compile } test.
>
> /endreview
>
>
> This is some truly impressive code, I'm not sure I understand all of
> it yet!
>
> As before, my only reservation is that this fails to compile, but
> should work (because the selected constructor for the chosen
> alternative is constexpr):
>
>  #include <variant>
>
>  struct literal {
>   constexpr literal() = default;
>  };
>
>  struct nonliteral {
>   nonliteral() { }
>  };
>
>  using namespace std;
>  constexpr variant<literal, nonliteral> v{};
>  constexpr variant<literal, nonliteral> v1{in_place_type<literal>};
>  constexpr variant<literal, nonliteral> v2{in_place_index<0>};

Good news! This compiles now! I learned the technique from Anthony
Williams's implementation, whose code also compiles, but it requires a
close-to-trunk gcc, which implements
"...for unions, at least one non-static data member is of non-volatile
literal type, ...".

Also added it as a test.

Please verify the implementation by looking at _Uninitialized and
_Variant_storage.

>
>
> However, I think we could commit this for now as it's 99% complete.
> What do you think?
>
> I am concerned that if we commit this implementation now, and *don't*
> get a 100% conforming rewrite before we want to declare C++17 support
> stable and non-experimental, then we'd have to introduce an
> incompatible change. That could be done by replacing std::variant with
> std::_V2::variant, so it would still be possible.
>
> If you want to propose this for trunk please make the fixes noted
> above and send a new patch, CCing gcc-patches.
>
> Thanks!
>
>

I also moved the tests from experiemntal/variant to 20_util/variant.

Bootstrapped and tested on x86_64-linux-gnu.

Thank you all for reviewing all of these!

Comments

Ville Voutilainen Aug. 7, 2016, 1:04 a.m. UTC | #1
On 6 August 2016 at 08:45, Tim Shen <timshen@google.com> wrote:
>>  using namespace std;
>>  constexpr variant<literal, nonliteral> v{};
>>  constexpr variant<literal, nonliteral> v1{in_place_type<literal>};
>>  constexpr variant<literal, nonliteral> v2{in_place_index<0>};
>
> Good news! This compiles now! I learned the technique from Anthony
> Williams's implementation, whose code also compiles, but it requires a
> close-to-trunk gcc, which implements
> "...for unions, at least one non-static data member is of non-volatile
> literal type, ...".
>
> Also added it as a test.
>
> Please verify the implementation by looking at _Uninitialized and
> _Variant_storage.


Sounds very promising, I'll try to play with it before the end of the
weekend. Jonathan will be on holiday
next week so we have time before this gets committed. We might want to
entertain the idea of running
the tests at https://github.com/efcs/libcxx/tree/variant although that
implementation isn't something we should
adopt things from.
Ville Voutilainen Aug. 8, 2016, 10:14 a.m. UTC | #2
On 7 August 2016 at 04:04, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
>> Good news! This compiles now! I learned the technique from Anthony
>> Williams's implementation, whose code also compiles, but it requires a
>> close-to-trunk gcc, which implements
>> "...for unions, at least one non-static data member is of non-volatile
>> literal type, ...".
>>
>> Also added it as a test.
>>
>> Please verify the implementation by looking at _Uninitialized and
>> _Variant_storage.
>
>
> Sounds very promising, I'll try to play with it before the end of the
> weekend. Jonathan will be on holiday
> next week so we have time before this gets committed. We might want to
> entertain the idea of running
> the tests at https://github.com/efcs/libcxx/tree/variant although that
> implementation isn't something we should
> adopt things from.

I did the playing, looks very good to me. Thanks for doing the work, Tim!
(Jonathan, ship it :) )
Jonathan Wakely Aug. 18, 2016, 12:47 p.m. UTC | #3
On 05/08/16 22:45 -0700, Tim Shen wrote:
>On Fri, Aug 5, 2016 at 4:08 AM, Jonathan Wakely <jwakely@redhat.com> wrote:
>> I think these all need to use ::new (__ptr) with qualification, see
>> below.
>
>Done. I didn't add a testcase for this. Do you think that we need one/some?

No, I don't think we need a test. I doubt anybody will try to remove
the qualification, and if they do somebody who understands the need
for it can explain it before the patch gets committed :-)

>>> +  // Stores a void alternative, until void becomes a regular type.
>>
>>
>> Personally I hope it won't become a regular type :-)
>
>Sorry :)
>
>Do you mind to share your insights?

My impression of the proposal was that making it regular solves a few
problems, but introduces some other incompatibilities. If we were
designing a new language it might be a reasonable approach, but I
wouldn't want to introduce such a different object model based on what
we have today.


>>
>> (The decval<void>() case is OK as that won't do ADL).
>
>Done for all of them, for consistency.
>
>>
>>> +  template<typename _Array_type, typename _First, typename... _Rest,
>>> +          typename... _Args>
>>> +    struct __gen_vtable_impl<_Array_type, tuple<_First, _Rest...>,
>>> +                            tuple<_Args...>>
>>
>>
>> Do you actually need to use std::tuple here, or would something much
>> more lightweight be OK too?
>
>I actually just need a template to hold all alternatives. How about
>forward declaring tuple, and not including the header?
>
>I was totally unaware of the cost of <tuple>, and tried to use
>tuple_cat() on a bunch of function calls:
>(void)tuple_cat(foo<_Types>()...) where foo returns tuple<>.
>
>But not we have fold expression \o/! So I can directly write:
>(foo<_Types>, ...)
>
>which is perfect.

Nice.

>>
>> For example we have std::tr2::__reflection_typelist in
>> <tr2/type_traits>. Or it looks like this could just use something even
>> simpler:
>>  template<typename... T> struct __type_list
>>
>> What we really need is to standardize Eric Niebler's metapgroamming
>> library, or Peter Dimov's one, or *anything* that gives us a set of
>> nice tools for doing this stuff. std::tuple is a very heavyweight type
>> to use for simple type lists.
>
>I don't need the whole pack of metaprogramming tools here, lucky me. ;)
>
>>
>> It doesn't look like you're using any members of std::tuple, so maybe
>> it won't actually instantiate any of the base classes or member
>> functions, which is what would be inefficient.
>>
>>> +  template<typename _Tp, typename... _Types>
>>> +    _Tp& get(variant<_Types...>& __v)
>>
>>
>> Please add 'inline' to these one-line functions. All the get and
>> get_if overloads are tiny.
>
>What's the difference between non-inline function templates and inline
>function templates? At some point you may already explained that to
>me, but I'm still confused.

In practical terms, there's no difference. Function templates and
inline functions both get compiled to weak symbols, which are allowed
to have multiple definitions. Duplicate definitions will be discarded
by the linker.

That's an implementation detail related to how they are handled by the
compiler.  In formal C++ language terms they are still different
things. A function template is not an inline function unless it is
declared 'inline'. My preference is to add 'inline' if it's a small
function that would typically be marked inline if it wasn't a
template.

If the compiler ever uses the presence of the 'inline' keyword as a
hint for inlining (rather than just as the trigger for generating a
weak symbol) then putting it there would make a difference.

>Good news! This compiles now! I learned the technique from Anthony
>Williams's implementation, whose code also compiles, but it requires a
>close-to-trunk gcc, which implements
>"...for unions, at least one non-static data member is of non-volatile
>literal type, ...".
>
>Also added it as a test.

Great.

>Please verify the implementation by looking at _Uninitialized and
>_Variant_storage.
>
>>
>>
>> However, I think we could commit this for now as it's 99% complete.
>> What do you think?
>>
>> I am concerned that if we commit this implementation now, and *don't*
>> get a 100% conforming rewrite before we want to declare C++17 support
>> stable and non-experimental, then we'd have to introduce an
>> incompatible change. That could be done by replacing std::variant with
>> std::_V2::variant, so it would still be possible.
>>
>> If you want to propose this for trunk please make the fixes noted
>> above and send a new patch, CCing gcc-patches.
>>
>> Thanks!
>>
>>
>
>I also moved the tests from experiemntal/variant to 20_util/variant.
>
>Bootstrapped and tested on x86_64-linux-gnu.

OK for trunk, thanks!
Tim Shen Aug. 18, 2016, 8:32 p.m. UTC | #4
Tested on x86_64-linux-gnu and checked in as r239590.

Thanks!
diff mbox

Patch

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index e2c4f63..dda0253 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -77,6 +77,7 @@  std_headers = \
 	${std_srcdir}/unordered_set \
 	${std_srcdir}/utility \
 	${std_srcdir}/valarray \
+	${std_srcdir}/variant \
 	${std_srcdir}/vector
 
 bits_srcdir = ${glibcxx_srcdir}/include/bits
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 882ff14..828673b 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -367,6 +367,7 @@  std_headers = \
 	${std_srcdir}/unordered_set \
 	${std_srcdir}/utility \
 	${std_srcdir}/valarray \
+	${std_srcdir}/variant \
 	${std_srcdir}/vector
 
 bits_srcdir = ${glibcxx_srcdir}/include/bits
diff --git a/libstdc++-v3/include/bits/enable_special_members.h b/libstdc++-v3/include/bits/enable_special_members.h
index 1ac8f38..07c6c99 100644
--- a/libstdc++-v3/include/bits/enable_special_members.h
+++ b/libstdc++-v3/include/bits/enable_special_members.h
@@ -36,13 +36,33 @@  namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+  struct _Enable_default_constructor_tag
+  {
+    explicit _Enable_default_constructor_tag() = default;
+  };
+
 /**
   * @brief A mixin helper to conditionally enable or disable the default
   * constructor.
   * @sa _Enable_special_members
   */
 template<bool _Switch, typename _Tag = void>
-  struct _Enable_default_constructor { };
+  struct _Enable_default_constructor
+  {
+    constexpr _Enable_default_constructor() noexcept = default;
+    constexpr _Enable_default_constructor(_Enable_default_constructor const&)
+      noexcept  = default;
+    constexpr _Enable_default_constructor(_Enable_default_constructor&&)
+      noexcept = default;
+    _Enable_default_constructor&
+    operator=(_Enable_default_constructor const&) noexcept = default;
+    _Enable_default_constructor&
+    operator=(_Enable_default_constructor&&) noexcept = default;
+
+    // Can be used in other ctors.
+    constexpr explicit
+    _Enable_default_constructor(_Enable_default_constructor_tag) { }
+  };
 
 
 /**
@@ -86,7 +106,20 @@  template<bool _Default, bool _Destructor,
 
 template<typename _Tag>
   struct _Enable_default_constructor<false, _Tag>
-  { constexpr _Enable_default_constructor() noexcept = delete; };
+  {
+    constexpr _Enable_default_constructor() noexcept = delete;
+    constexpr _Enable_default_constructor(_Enable_default_constructor const&)
+      noexcept  = default;
+    constexpr _Enable_default_constructor(_Enable_default_constructor&&)
+      noexcept = default;
+    _Enable_default_constructor&
+    operator=(_Enable_default_constructor const&) noexcept = default;
+    _Enable_default_constructor&
+    operator=(_Enable_default_constructor&&) noexcept = default;
+
+    // Can be used in other ctors.
+    explicit _Enable_default_constructor(_Enable_default_constructor_tag) { }
+  };
 
 template<typename _Tag>
   struct _Enable_destructor<false, _Tag>
diff --git a/libstdc++-v3/include/bits/uses_allocator.h b/libstdc++-v3/include/bits/uses_allocator.h
index 46aea13..500bd90 100644
--- a/libstdc++-v3/include/bits/uses_allocator.h
+++ b/libstdc++-v3/include/bits/uses_allocator.h
@@ -113,6 +113,57 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr bool uses_allocator_v = uses_allocator<_Tp, _Alloc>::value;
 #endif // C++17
 
+  template<template<typename...> class _Predicate,
+	   typename _Tp, typename _Alloc, typename... _Args>
+    struct __is_uses_allocator_predicate
+    : conditional<uses_allocator<_Tp, _Alloc>::value,
+      __or_<_Predicate<_Tp, allocator_arg_t, _Alloc, _Args...>,
+	    _Predicate<_Tp, _Args..., _Alloc>>,
+      _Predicate<_Tp, _Args...>>::type { };
+
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    struct __is_uses_allocator_constructible
+    : __is_uses_allocator_predicate<is_constructible, _Tp, _Alloc, _Args...>
+    { };
+
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    constexpr bool __is_uses_allocator_constructible_v =
+      __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
+
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    struct __is_nothrow_uses_allocator_constructible
+    : __is_uses_allocator_predicate<is_nothrow_constructible,
+				    _Tp, _Alloc, _Args...>
+    { };
+
+
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    constexpr bool __is_nothrow_uses_allocator_constructible_v =
+      __is_nothrow_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value;
+
+  template<typename _Tp, typename... _Args>
+    void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr,
+					 _Args&&... __args)
+    { new (__ptr) _Tp(forward<_Args>(__args)...); }
+
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp* __ptr,
+					 _Args&&... __args)
+    { new (__ptr) _Tp(allocator_arg, *__a._M_a, forward<_Args>(__args)...); }
+
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp* __ptr,
+					 _Args&&... __args)
+    { new (__ptr) _Tp(forward<_Args>(__args)..., *__a._M_a); }
+
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr,
+				    _Args&&... __args)
+    {
+      __uses_allocator_construct_impl(__use_alloc<_Tp, _Alloc, _Args...>(__a),
+				      __ptr, forward<_Args>(__args)...);
+    }
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
new file mode 100644
index 0000000..a9b4394
--- /dev/null
+++ b/libstdc++-v3/include/std/variant
@@ -0,0 +1,1360 @@ 
+// <variant> -*- C++ -*-
+
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file variant
+ *  This is the <variant> C++ Library header.
+ */
+
+#ifndef _GLIBCXX_VARIANT
+#define _GLIBCXX_VARIANT 1
+
+#pragma GCC system_header
+
+#if __cplusplus <= 201402L
+# include <bits/c++17_warning.h>
+#else
+
+#include <type_traits>
+#include <utility>
+#include <bits/enable_special_members.h>
+#include <bits/uses_allocator.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename... _Types> class tuple;
+  template<typename... _Types> class variant;
+  template <typename> struct hash;
+
+  template<typename _Variant>
+    struct variant_size;
+
+  template<typename _Variant>
+    struct variant_size<const _Variant> : variant_size<_Variant> {};
+
+  template<typename _Variant>
+    struct variant_size<volatile _Variant> : variant_size<_Variant> {};
+
+  template<typename _Variant>
+    struct variant_size<const volatile _Variant> : variant_size<_Variant> {};
+
+  template<typename... _Types>
+    struct variant_size<variant<_Types...>>
+    : std::integral_constant<size_t, sizeof...(_Types)> {};
+
+  template<typename _Variant>
+    constexpr size_t variant_size_v = variant_size<_Variant>::value;
+
+  template<size_t _Np, typename _Variant>
+    struct variant_alternative;
+
+  template<size_t _Np, typename _First, typename... _Rest>
+    struct variant_alternative<_Np, variant<_First, _Rest...>>
+    : variant_alternative<_Np-1, variant<_Rest...>> {};
+
+  template<typename _First, typename... _Rest>
+    struct variant_alternative<0, variant<_First, _Rest...>>
+    { using type = _First; };
+
+  template<size_t _Np, typename _Variant>
+    using variant_alternative_t =
+      typename variant_alternative<_Np, _Variant>::type;
+
+  constexpr size_t variant_npos = -1;
+
+namespace __detail
+{
+namespace __variant
+{
+  // Returns the first apparence of _Tp in _Types.
+  // Returns sizeof...(_Types) if _Tp is not in _Types.
+  template<typename _Tp, typename... _Types>
+    struct __index_of : std::integral_constant<size_t, 0> {};
+
+  template<typename _Tp, typename... _Types>
+    constexpr size_t __index_of_v = __index_of<_Tp, _Types...>::value;
+
+  template<typename _Tp, typename _First, typename... _Rest>
+    struct __index_of<_Tp, _First, _Rest...> :
+      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>>; };
+
+  // Stores a reference alternative as a... well, reference.
+  template<typename _Reference>
+    struct _Reference_storage
+    {
+      static_assert(is_reference_v<_Reference>,
+		    "BUG: _Reference should be a reference");
+
+      _Reference_storage(_Reference __ref) noexcept : _M_storage(__ref) { }
+
+      operator _Reference() noexcept
+      { return static_cast<_Reference>(_M_storage); }
+
+      _Reference _M_storage;
+    };
+
+  // Stores a void alternative, because it is not a regular type.
+  template<typename _Void>
+    struct _Void_storage { };
+
+  // Map from the alternative type to a non-qualified storage type.
+  template<typename _Alternative, typename = void>
+    struct __storage_type
+    { using type = _Alternative; };
+
+  template<typename _Alternative>
+    struct __storage_type<_Alternative,
+			  enable_if_t<is_reference_v<_Alternative>>>
+    { using type = _Reference_storage<_Alternative>; };
+
+  template<typename _Alternative>
+    struct __storage_type<_Alternative, enable_if_t<is_void_v<_Alternative>>>
+    { using type = _Void_storage<_Alternative>; };
+
+  template<typename _Type>
+    using __storage = typename __storage_type<_Type>::type;
+
+  template<typename _Type, bool __is_literal = 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)...)
+      { }
+
+      _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)...); }
+
+      typename std::aligned_storage<sizeof(_Type), alignof(_Type)>::type
+	  _M_storage;
+    };
+
+  // Reverse mapping of __storage_type.
+  template<typename _Storage_type>
+    struct __alternative_type
+    {
+      static_assert(!is_reference_v<_Storage_type>,
+		    "BUG: _Storage_type should not be reference");
+      using type = _Storage_type;
+    };
+
+  template<typename _Reference>
+    struct __alternative_type<_Reference_storage<_Reference>>
+    { using type = _Reference; };
+
+  template<typename _Void>
+    struct __alternative_type<_Void_storage<_Void>>
+    { using type = _Void; };
+
+  // Given a qualified storage type, return the desired reference.
+  // The qualified storage type is supposed to carry the variant object's
+  // qualifications and reference information, and the designated alternative's
+  // storage type.
+  // Returns the qualification-collapsed alternative references.
+  //
+  // For example, __get_alternative<_Reference_storage<int&&>&> returns int&.
+  template<typename _Qualified_storage>
+    decltype(auto)
+    __get_alternative(void* __ptr)
+    {
+      using _Storage = decay_t<_Qualified_storage>;
+      using _Alternative = typename __alternative_type<_Storage>::type;
+      return __reserved_type_map<_Qualified_storage, _Alternative>(
+	*static_cast<_Storage*>(__ptr));
+    }
+
+  // Various functions as "vtable" entries, where those vtables are used by
+  // polymorphic operations.
+  template<typename _Lhs, typename _Rhs>
+    constexpr void
+    __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
+    __erased_dtor(void* __ptr)
+    {
+      using _Storage = decay_t<_Tp>;
+      static_cast<_Storage*>(__ptr)->~_Storage();
+    }
+
+  template<typename _Lhs, typename _Rhs>
+    constexpr void
+    __erased_assign(void* __lhs, void* __rhs)
+    { __get_alternative<_Lhs>(__lhs) = __get_alternative<_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));
+    }
+
+  template<typename _Lhs, typename _Rhs>
+    constexpr bool
+    __erased_equal_to(void* __lhs, void* __rhs)
+    { return __get_alternative<_Lhs>(__lhs) == __get_alternative<_Rhs>(__rhs); }
+
+  template<typename _Lhs, typename _Rhs>
+    constexpr bool
+    __erased_less_than(void* __lhs, void* __rhs)
+    { return __get_alternative<_Lhs>(__lhs) < __get_alternative<_Rhs>(__rhs); }
+
+  template<typename _Tp>
+    constexpr size_t
+    __erased_hash(void* __t)
+    { return std::hash<decay_t<_Tp>>{}(__get_alternative<_Tp>(__t)); }
+
+  template<typename... _Types>
+    struct _Variant_base;
+
+  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...>
+    {
+      constexpr _Variant_storage() = default;
+
+      template<typename... _Args>
+	constexpr _Variant_storage(in_place_index_t<0>, _Args&&... __args)
+	: _M_first(in_place<0>, forward<_Args>(__args)...)
+	{ }
+
+      template<size_t _Np, typename... _Args,
+	       typename = enable_if_t<0 < _Np && _Np < sizeof...(_Rest) + 1>>
+	constexpr _Variant_storage(in_place_index_t<_Np>, _Args&&... __args)
+	: _M_rest(in_place<_Np - 1>, forward<_Args>(__args)...)
+	{ }
+
+      ~_Variant_storage() = default;
+
+      constexpr void*
+      _M_storage() const
+      {
+	return const_cast<void*>(
+	  static_cast<const void*>(&_M_first._M_storage));
+      }
+
+      union
+      {
+	_Uninitialized<__storage<_First>> _M_first;
+	_Variant_storage<_Rest...> _M_rest;
+      };
+    };
+
+  template<typename _Derived, bool __is_trivially_destructible>
+    struct _Dtor_mixin
+    {
+      ~_Dtor_mixin()
+      { static_cast<_Derived*>(this)->_M_destroy(); }
+    };
+
+  template<typename _Derived>
+    struct _Dtor_mixin<_Derived, true>
+    {
+      ~_Dtor_mixin() = default;
+    };
+
+  // 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>
+    {
+      using _Storage = _Variant_storage<_Types...>;
+
+      constexpr
+      _Variant_base()
+      noexcept(is_nothrow_default_constructible_v<
+		 variant_alternative_t<0, variant<_Types...>>>)
+      : _Variant_base(in_place<0>) { }
+
+      _Variant_base(const _Variant_base& __rhs)
+      : _Storage(), _M_index(__rhs._M_index)
+      {
+	if (__rhs._M_valid())
+	  {
+	    static constexpr void (*_S_vtable[])(void*, void*) =
+	      { &__erased_ctor<__storage<_Types>&,
+			       const __storage<_Types>&>... };
+	    _S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
+	  }
+      }
+
+      _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());
+	  }
+      }
+
+      template<size_t _Np, typename... _Args>
+	constexpr explicit
+	_Variant_base(in_place_index_t<_Np> __i, _Args&&... __args)
+	: _Storage(__i, 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()),
+				     forward<_Args>(__args)...);
+	  __glibcxx_assert(_M_index == _Np);
+	}
+
+      _Variant_base&
+      operator=(const _Variant_base& __rhs)
+      {
+	if (_M_index == __rhs._M_index)
+	  {
+	    if (__rhs._M_valid())
+	      {
+		static constexpr void (*_S_vtable[])(void*, void*) =
+		  { &__erased_assign<__storage<_Types>&,
+				     const __storage<_Types>&>... };
+		_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
+	      }
+	  }
+	else
+	  {
+	    _Variant_base __tmp(__rhs);
+	    this->~_Variant_base();
+	    __try
+	      {
+		::new (this) _Variant_base(std::move(__tmp));
+	      }
+	    __catch (...)
+	      {
+		_M_index = variant_npos;
+		__throw_exception_again;
+	      }
+	  }
+	__glibcxx_assert(_M_index == __rhs._M_index);
+	return *this;
+      }
+
+      _Variant_base&
+      operator=(_Variant_base&& __rhs)
+      noexcept(__and_<is_nothrow_move_constructible<_Types>...,
+		      is_nothrow_move_assignable<_Types>...>::value)
+      {
+	if (_M_index == __rhs._M_index)
+	  {
+	    if (__rhs._M_valid())
+	      {
+		static constexpr void (*_S_vtable[])(void*, void*) =
+		  { &__erased_assign<__storage<_Types>&,
+				     __storage<_Types>&&>... };
+		_S_vtable[__rhs._M_index](_M_storage(), __rhs._M_storage());
+	      }
+	  }
+	else
+	  {
+	    this->~_Variant_base();
+	    __try
+	      {
+		::new (this) _Variant_base(std::move(__rhs));
+	      }
+	    __catch (...)
+	      {
+		_M_index = variant_npos;
+		__throw_exception_again;
+	      }
+	  }
+	return *this;
+      }
+
+      void _M_destroy()
+      {
+	if (_M_valid())
+	  {
+	    static constexpr void (*_S_vtable[])(void*) =
+	      { &__erased_dtor<__storage<_Types>&>... };
+	    _S_vtable[this->_M_index](_M_storage());
+	  }
+      }
+
+      constexpr void*
+      _M_storage() const
+      { return _Storage::_M_storage(); }
+
+      constexpr bool
+      _M_valid() const noexcept
+      { return _M_index != variant_npos; }
+
+      size_t _M_index;
+    };
+
+  // For how many times does _Tp appear in _Tuple?
+  template<typename _Tp, typename _Tuple>
+    struct __tuple_count;
+
+  template<typename _Tp, typename _Tuple>
+    constexpr size_t __tuple_count_v = __tuple_count<_Tp, _Tuple>::value;
+
+  template<typename _Tp, typename... _Types>
+    struct __tuple_count<_Tp, tuple<_Types...>>
+    : integral_constant<size_t, 0> { };
+
+  template<typename _Tp, typename _First, typename... _Rest>
+    struct __tuple_count<_Tp, tuple<_First, _Rest...>>
+    : integral_constant<
+	size_t,
+	__tuple_count_v<_Tp, tuple<_Rest...>> + is_same_v<_Tp, _First>> { };
+
+  // TODO: Reuse this in <tuple> ?
+  template<typename _Tp, typename... _Types>
+    constexpr bool __exactly_once = __tuple_count_v<_Tp, tuple<_Types...>> == 1;
+
+  // Takes _Types and create an overloaded _S_fun for each type.
+  // If a type appears more than once in _Types, create only one overload.
+  template<typename... _Types>
+    struct __overload_set
+    { static void _S_fun(); };
+
+  template<typename _First, typename... _Rest>
+    struct __overload_set<_First, _Rest...> : __overload_set<_Rest...>
+    {
+      using __overload_set<_Rest...>::_S_fun;
+      static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First);
+    };
+
+  template<typename... _Rest>
+    struct __overload_set<void, _Rest...> : __overload_set<_Rest...>
+    {
+      using __overload_set<_Rest...>::_S_fun;
+    };
+
+  // Helper for variant(_Tp&&) and variant::operator=(_Tp&&).
+  // __accepted_index maps the arbitrary _Tp to an alternative type in _Variant.
+  template<typename _Tp, typename _Variant, typename = void>
+    struct __accepted_index
+    { static constexpr size_t value = variant_npos; };
+
+  template<typename _Tp, typename... _Types>
+    struct __accepted_index<
+      _Tp, variant<_Types...>,
+      decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()),
+	       std::declval<void>())>
+    {
+      static constexpr size_t value = sizeof...(_Types) - 1
+	- decltype(__overload_set<_Types...>::
+		   _S_fun(std::declval<_Tp>()))::value;
+    };
+
+  // Returns the raw storage for __v.
+  template<typename _Variant>
+    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(forward<_Variant>(__v)));
+    }
+
+  // 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 forward<_Visitor>(__visitor)(__get_alternative<_Args>(__ptrs)...);
+    }
+
+  // Used for storing multi-dimensional vtable.
+  template<typename _Tp, size_t... _Dimensions>
+    struct _Multi_array
+    {
+      constexpr const _Tp&
+      _M_access() const
+      { return _M_data; }
+
+      _Tp _M_data;
+    };
+
+  template<typename _Tp, size_t __first, size_t... __rest>
+    struct _Multi_array<_Tp, __first, __rest...>
+    {
+      template<typename... _Args>
+	constexpr const _Tp&
+	_M_access(size_t __first_index, _Args... __rest_indices) const
+	{ return _M_arr[__first_index]._M_access(__rest_indices...); }
+
+      _Multi_array<_Tp, __rest...> _M_arr[__first];
+    };
+
+  // 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>())
+  // 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>>
+  // 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>
+    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...>>
+    {
+      static constexpr _Array_type
+      _S_apply()
+      {
+	_Array_type __vtable{};
+	_S_apply_all_alts(
+	  __vtable, make_index_sequence<variant_size_v<decay_t<_First>>>());
+	return __vtable;
+      }
+
+      template<size_t... __indices>
+	static constexpr void
+	_S_apply_all_alts(_Array_type& __vtable, index_sequence<__indices...>)
+	{ (_S_apply_single_alt<__indices>(__vtable._M_arr[__indices]), ...); }
+
+      template<size_t __index>
+	static constexpr void
+	_S_apply_single_alt(auto& __element)
+	{
+	  using _Alternative = variant_alternative_t<__index, decay_t<_First>>;
+	  using _Qualified_storage = __reserved_type_map<
+	    _First, __storage<_Alternative>>;
+	  __element = __gen_vtable_impl<
+	    decay_t<decltype(__element)>, tuple<_Rest...>,
+	    tuple<_Args..., _Qualified_storage>>::_S_apply();
+	}
+    };
+
+  template<typename _Result_type, typename _Visitor, typename... _Args>
+    struct __gen_vtable_impl<
+      _Multi_array<_Result_type (*)(_Visitor, _To_type<_Args, void*>...)>,
+		   tuple<>, tuple<_Args...>>
+    {
+      using _Array_type =
+	_Multi_array<_Result_type (*)(_Visitor&&, _To_type<_Args, void*>...)>;
+
+      static constexpr auto
+      _S_apply()
+      { return _Array_type{&__visit_invoke<_Visitor, _Args...>}; }
+    };
+
+  template<typename _Result_type, typename _Visitor, typename... _Variants>
+    struct __gen_vtable
+    {
+      using _Func_ptr =
+	_Result_type (*)(_Visitor&&, _To_type<_Variants, void*>...);
+      using _Array_type =
+	_Multi_array<_Func_ptr, variant_size_v<decay_t<_Variants>>...>;
+
+      static constexpr _Array_type
+      _S_apply()
+      {
+	return __gen_vtable_impl<
+	  _Array_type, tuple<_Variants...>, tuple<>>::_S_apply();
+      }
+    };
+
+} // namespace __variant
+} // namespace __detail
+
+  template<typename _Tp, typename... _Types>
+    inline constexpr bool holds_alternative(const variant<_Types...>& __v)
+    noexcept
+    {
+      static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
+		    "T should occur for exactly once in alternatives");
+      return __v.index() == __detail::__variant::__index_of_v<_Tp, _Types...>;
+    }
+
+  template<size_t _Np, typename... _Types>
+    variant_alternative_t<_Np, variant<_Types...>>&
+    get(variant<_Types...>&);
+
+  template<size_t _Np, typename... _Types>
+    variant_alternative_t<_Np, variant<_Types...>>&&
+    get(variant<_Types...>&&);
+
+  template<size_t _Np, typename... _Types>
+    variant_alternative_t<_Np, variant<_Types...>> const&
+    get(const variant<_Types...>&);
+
+  template<size_t _Np, typename... _Types>
+    variant_alternative_t<_Np, variant<_Types...>> const&&
+    get(const variant<_Types...>&&);
+
+  template<typename _Tp, typename... _Types>
+    inline _Tp& get(variant<_Types...>& __v)
+    {
+      static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
+		    "T should occur for exactly once in alternatives");
+      static_assert(!is_void_v<_Tp>, "_Tp should not be void");
+      return get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v);
+    }
+
+  template<typename _Tp, typename... _Types>
+    inline _Tp&& get(variant<_Types...>&& __v)
+    {
+      static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
+		    "T should occur for exactly once in alternatives");
+      static_assert(!is_void_v<_Tp>, "_Tp should not be void");
+      return get<__detail::__variant::__index_of_v<_Tp, _Types...>>(
+	std::move(__v));
+    }
+
+  template<typename _Tp, typename... _Types>
+    inline const _Tp& get(const variant<_Types...>& __v)
+    {
+      static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
+		    "T should occur for exactly once in alternatives");
+      static_assert(!is_void_v<_Tp>, "_Tp should not be void");
+      return get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v);
+    }
+
+  template<typename _Tp, typename... _Types>
+    inline const _Tp&& get(const variant<_Types...>&& __v)
+    {
+      static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
+		    "T should occur for exactly once in alternatives");
+      static_assert(!is_void_v<_Tp>, "_Tp should not be void");
+      return get<__detail::__variant::__index_of_v<_Tp, _Types...>>(
+	std::move(__v));
+    }
+
+  template<size_t _Np, typename... _Types>
+    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...>>;
+      static_assert(_Np < sizeof...(_Types),
+		    "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 nullptr;
+    }
+
+  template<size_t _Np, typename... _Types>
+    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...>>;
+      static_assert(_Np < sizeof...(_Types),
+		    "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 nullptr;
+    }
+
+  template<typename _Tp, typename... _Types>
+    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");
+      static_assert(!is_void_v<_Tp>, "_Tp should not be void");
+      return get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>(__ptr);
+    }
+
+  template<typename _Tp, typename... _Types>
+    inline add_pointer_t<const _Tp> get_if(const variant<_Types...>* __ptr)
+    noexcept
+    {
+      static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
+		    "T should occur for exactly once in alternatives");
+      static_assert(!is_void_v<_Tp>, "_Tp should not be void");
+      return get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>(__ptr);
+    }
+
+  template<typename... _Types>
+    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));
+    }
+
+  template<typename... _Types>
+    inline bool
+    operator!=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
+    { return !(__lhs == __rhs); }
+
+  template<typename... _Types>
+    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));
+    }
+
+  template<typename... _Types>
+    inline bool
+    operator>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
+    { return __rhs < __lhs; }
+
+  template<typename... _Types>
+    inline bool
+    operator<=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
+    { return !(__lhs > __rhs); }
+
+  template<typename... _Types>
+    inline bool
+    operator>=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs)
+    { return !(__lhs < __rhs); }
+
+  template<typename _Visitor, typename... _Variants>
+    decltype(auto) visit(_Visitor&&, _Variants&&...);
+
+  struct monostate { };
+
+  constexpr bool operator<(monostate, monostate) noexcept
+  { return false; }
+
+  constexpr bool operator>(monostate, monostate) noexcept
+  { return false; }
+
+  constexpr bool operator<=(monostate, monostate) noexcept
+  { return true; }
+
+  constexpr bool operator>=(monostate, monostate) noexcept
+  { return true; }
+
+  constexpr bool operator==(monostate, monostate) noexcept
+  { return true; }
+
+  constexpr bool operator!=(monostate, monostate) noexcept
+  { return false; }
+
+  template<typename... _Types>
+    inline auto swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
+    noexcept(noexcept(__lhs.swap(__rhs))) -> decltype(__lhs.swap(__rhs))
+    { __lhs.swap(__rhs); }
+
+  class bad_variant_access : public exception
+  {
+  public:
+    bad_variant_access() noexcept : _M_reason("Unknown reason") { }
+    const char* what() const noexcept override
+    { return _M_reason; }
+
+  private:
+    bad_variant_access(const char* __reason) : _M_reason(__reason) { }
+
+    const char* _M_reason;
+
+    friend void __throw_bad_variant_access(const char* __what);
+  };
+
+  inline void
+  __throw_bad_variant_access(const char* __what)
+  { _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__what)); }
+
+  template<typename... _Types>
+    class variant
+    : private __detail::__variant::_Variant_base<_Types...>,
+      private _Enable_default_constructor<
+	is_default_constructible_v<
+	  variant_alternative_t<0, variant<_Types...>>>, variant<_Types...>>,
+      private _Enable_copy_move<
+	__and_<is_copy_constructible<_Types>...>::value,
+	__and_<is_copy_constructible<_Types>...,
+	       is_move_constructible<_Types>...,
+	       is_copy_assignable<_Types>...>::value,
+	__and_<is_move_constructible<_Types>...>::value,
+	__and_<is_move_constructible<_Types>...,
+	       is_move_assignable<_Types>...>::value,
+	variant<_Types...>>
+    {
+    private:
+      using _Base = __detail::__variant::_Variant_base<_Types...>;
+      using _Default_ctor_enabler =
+	_Enable_default_constructor<
+	  is_default_constructible_v<
+	    variant_alternative_t<0, variant<_Types...>>>, variant<_Types...>>;
+
+      template<typename _Tp>
+	static constexpr bool
+	__exactly_once = __detail::__variant::__exactly_once<_Tp, _Types...>;
+
+      template<typename _Tp>
+	static constexpr size_t __accepted_index =
+	  __detail::__variant::__accepted_index<_Tp&&, variant>::value;
+
+      template<size_t _Np, bool = _Np < sizeof...(_Types)>
+	struct __to_type_impl;
+
+      template<size_t _Np>
+	struct __to_type_impl<_Np, true>
+	{ using type = variant_alternative_t<_Np, variant>; };
+
+      template<size_t _Np>
+	using __to_type = typename __to_type_impl<_Np>::type;
+
+      template<typename _Tp>
+	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...>;
+
+    public:
+      constexpr variant()
+      noexcept(is_nothrow_default_constructible_v<__to_type<0>>) = default;
+      variant(const variant&) = default;
+      variant(variant&&)
+      noexcept(__and_<
+	is_nothrow_move_constructible<_Types>...>::value) = default;
+
+      template<typename _Tp,
+	       typename = enable_if_t<__exactly_once<__accepted_type<_Tp&&>>
+			  && is_constructible_v<__accepted_type<_Tp&&>, _Tp&&>
+			  && !is_same_v<decay_t<_Tp>, variant>>>
+	constexpr
+	variant(_Tp&& __t)
+	noexcept(is_nothrow_constructible_v<__accepted_type<_Tp&&>, _Tp&&>)
+	: variant(in_place<__accepted_index<_Tp&&>>, forward<_Tp>(__t))
+	{ __glibcxx_assert(holds_alternative<__accepted_type<_Tp&&>>(*this)); }
+
+      template<typename _Tp, typename... _Args,
+	       typename = enable_if_t<__exactly_once<_Tp>
+			  && is_constructible_v<_Tp, _Args&&...>>>
+	constexpr explicit
+	variant(in_place_type_t<_Tp>, _Args&&... __args)
+	: variant(in_place<__index_of<_Tp>>, forward<_Args>(__args)...)
+	{ __glibcxx_assert(holds_alternative<_Tp>(*this)); }
+
+      template<typename _Tp, typename _Up, typename... _Args,
+	       typename = enable_if_t<__exactly_once<_Tp>
+			  && is_constructible_v<
+			    _Tp, initializer_list<_Up>&, _Args&&...>>>
+	constexpr explicit
+	variant(in_place_type_t<_Tp>, initializer_list<_Up> __il,
+		_Args&&... __args)
+	: variant(in_place<__index_of<_Tp>>, __il,
+		  forward<_Args>(__args)...)
+	{ __glibcxx_assert(holds_alternative<_Tp>(*this)); }
+
+      template<size_t _Np, typename... _Args,
+	       typename = enable_if_t<
+		 is_constructible_v<__to_type<_Np>, _Args&&...>>>
+	constexpr explicit
+	variant(in_place_index_t<_Np>, _Args&&... __args)
+	: _Base(in_place<_Np>, forward<_Args>(__args)...),
+	_Default_ctor_enabler(_Enable_default_constructor_tag{})
+	{ __glibcxx_assert(index() == _Np); }
+
+      template<size_t _Np, typename _Up, typename... _Args,
+	       typename = enable_if_t<is_constructible_v<__to_type<_Np>,
+				      initializer_list<_Up>&, _Args&&...>>>
+	constexpr explicit
+	variant(in_place_index_t<_Np>, initializer_list<_Up> __il,
+		_Args&&... __args)
+	: _Base(in_place<_Np>, __il, forward<_Args>(__args)...),
+	_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<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<__accepted_index<_Tp&&>>,
+		  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_of<_Tp>>,
+		  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_of<_Tp>>, __il,
+		  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<_Np>, 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<_Np>, __il, forward<_Args>(__args)...),
+	_Default_ctor_enabler(_Enable_default_constructor_tag{})
+	{ __glibcxx_assert(index() == _Np); }
+
+      ~variant() = default;
+
+      variant& operator=(const variant&) = default;
+      variant& operator=(variant&&)
+      noexcept(__and_<is_nothrow_move_constructible<_Types>...,
+		      is_nothrow_move_assignable<_Types>...>::value) = default;
+
+      template<typename _Tp>
+	enable_if_t<__exactly_once<__accepted_type<_Tp&&>>
+		    && is_constructible_v<__accepted_type<_Tp&&>, _Tp&&>
+		    && is_assignable_v<__accepted_type<_Tp&&>&, _Tp&&>
+		    && !is_same_v<decay_t<_Tp>, variant>, variant&>
+	operator=(_Tp&& __rhs)
+	noexcept(is_nothrow_assignable_v<__accepted_type<_Tp&&>&, _Tp&&>
+		 && is_nothrow_constructible_v<__accepted_type<_Tp&&>, _Tp&&>)
+	{
+	  constexpr auto __index = __accepted_index<_Tp&&>;
+	  if (index() == __index)
+	    *static_cast<__storage<__to_type<__index>>*>(this->_M_storage())
+	      = forward<_Tp>(__rhs);
+	  else
+	    this->emplace<__index>(forward<_Tp>(__rhs));
+	  __glibcxx_assert(holds_alternative<__accepted_type<_Tp&&>>(*this));
+	  return *this;
+	}
+
+      template<typename _Tp, typename... _Args>
+	void emplace(_Args&&... __args)
+	{
+	  static_assert(__exactly_once<_Tp>,
+			"T should occur for exactly once in alternatives");
+	  this->emplace<__index_of<_Tp>>(forward<_Args>(__args)...);
+	  __glibcxx_assert(holds_alternative<_Tp>(*this));
+	}
+
+      template<typename _Tp, typename _Up, typename... _Args>
+	void 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, forward<_Args>(__args)...);
+	  __glibcxx_assert(holds_alternative<_Tp>(*this));
+	}
+
+      template<size_t _Np, typename... _Args>
+	void emplace(_Args&&... __args)
+	{
+	  static_assert(_Np < sizeof...(_Types),
+			"The index should be in [0, number of alternatives)");
+	  this->~variant();
+	  __try
+	    {
+	      ::new (this) variant(in_place<_Np>,
+				   forward<_Args>(__args)...);
+	    }
+	  __catch (...)
+	    {
+	      this->_M_index = variant_npos;
+	      __throw_exception_again;
+	    }
+	  __glibcxx_assert(index() == _Np);
+	}
+
+      template<size_t _Np, typename _Up, typename... _Args>
+	void emplace(initializer_list<_Up> __il, _Args&&... __args)
+	{
+	  static_assert(_Np < sizeof...(_Types),
+			"The index should be in [0, number of alternatives)");
+	  this->~variant();
+	  __try
+	    {
+	      ::new (this) variant(in_place<_Np>, __il,
+				   forward<_Args>(__args)...);
+	    }
+	  __catch (...)
+	    {
+	      this->_M_index = variant_npos;
+	      __throw_exception_again;
+	    }
+	  __glibcxx_assert(index() == _Np);
+	}
+
+      constexpr bool valueless_by_exception() const noexcept
+      { return !this->_M_valid(); }
+
+      constexpr size_t index() const noexcept
+      { return this->_M_index; }
+
+      void
+      swap(variant& __rhs)
+      noexcept(__and_<__is_nothrow_swappable<_Types>...>::value
+	       && is_nothrow_move_assignable_v<variant>)
+      {
+	if (this->index() == __rhs.index())
+	  {
+	    if (this->_M_valid())
+	      {
+		static constexpr void (*_S_vtable[])(void*, void*) =
+		  { &__detail::__variant::__erased_swap<
+		      __storage<_Types>&, __storage<_Types>&>... };
+		_S_vtable[__rhs._M_index](this->_M_storage(),
+					  __rhs._M_storage());
+	      }
+	  }
+	else if (!this->_M_valid())
+	  {
+	    *this = std::move(__rhs);
+	  }
+	else if (!__rhs._M_valid())
+	  {
+	    __rhs = std::move(*this);
+	  }
+	else
+	  {
+	    auto __tmp = std::move(__rhs);
+	    __rhs = std::move(*this);
+	    *this = std::move(__tmp);
+	  }
+      }
+
+      template<typename _Vp>
+	friend void* __detail::__variant::__get_storage(_Vp&& __v);
+    };
+
+  // To honor algebraic data type, variant<> should be a bottom type, which
+  // is 0 (as opposed to a void type, which is 1). Use incomplete type to model
+  // bottom type.
+  template<> class variant<>;
+
+  template<size_t _Np, typename... _Types>
+    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);
+    }
+
+  template<size_t _Np, typename... _Types>
+    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));
+    }
+
+  template<size_t _Np, typename... _Types>
+    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);
+    }
+
+  template<size_t _Np, typename... _Types>
+    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));
+    }
+
+  template<typename _Visitor, typename... _Variants>
+    decltype(auto)
+    visit(_Visitor&& __visitor, _Variants&&... __variants)
+    {
+      using _Result_type =
+	decltype(forward<_Visitor>(__visitor)(get<0>(__variants)...));
+      static 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)(forward<_Visitor>(__visitor),
+			   __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...>>
+    {
+      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>()))))
+      {
+	if (!__t.valueless_by_exception())
+	  {
+	    namespace __edv = __detail::__variant;
+	    static constexpr size_t (*_S_vtable[])(void*) =
+	      { &__edv::__erased_hash<const __edv::__storage<_Types>&>... };
+	    return hash<size_t>{}(__t.index())
+	      + _S_vtable[__t.index()](__edv::__get_storage(__t));
+	  }
+	return hash<size_t>{}(__t.index());
+      }
+    };
+
+  template<>
+    struct hash<monostate>
+    {
+      using result_type = size_t;
+      using argument_type = monostate;
+
+      size_t
+      operator()(const monostate& __t) const noexcept
+      {
+	constexpr size_t __magic_monostate_hash = -7777;
+	return __magic_monostate_hash;
+      }
+    };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+
+#endif // _GLIBCXX_VARIANT
diff --git a/libstdc++-v3/testsuite/20_util/variant/compile.cc b/libstdc++-v3/testsuite/20_util/variant/compile.cc
new file mode 100644
index 0000000..b57d356
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/variant/compile.cc
@@ -0,0 +1,405 @@ 
+// { dg-options "-std=gnu++17" }
+// { dg-do compile }
+
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <variant>
+#include <string>
+#include <vector>
+
+using namespace std;
+
+struct AllDeleted
+{
+  AllDeleted() = delete;
+  AllDeleted(const AllDeleted&) = delete;
+  AllDeleted(AllDeleted&&) = delete;
+  AllDeleted& operator=(const AllDeleted&) = delete;
+  AllDeleted& operator=(AllDeleted&&) = delete;
+};
+
+struct Empty
+{
+  Empty() { };
+  Empty(const Empty&) { };
+  Empty(Empty&&) { };
+  Empty& operator=(const Empty&) { return *this; };
+  Empty& operator=(Empty&&) { return *this; };
+};
+
+struct DefaultNoexcept
+{
+  DefaultNoexcept() noexcept = default;
+  DefaultNoexcept(const DefaultNoexcept&) noexcept = default;
+  DefaultNoexcept(DefaultNoexcept&&) noexcept = default;
+  DefaultNoexcept& operator=(const DefaultNoexcept&) noexcept = default;
+  DefaultNoexcept& operator=(DefaultNoexcept&&) noexcept = default;
+};
+
+void default_ctor()
+{
+  static_assert(is_default_constructible_v<variant<int, string>>, "");
+  static_assert(is_default_constructible_v<variant<string, string>>, "");
+  static_assert(!is_default_constructible_v<variant<>>, "");
+  static_assert(!is_default_constructible_v<variant<AllDeleted, string>>, "");
+  static_assert(is_default_constructible_v<variant<string, AllDeleted>>, "");
+
+  static_assert(noexcept(variant<int>()), "");
+  static_assert(!noexcept(variant<Empty>()), "");
+  static_assert(noexcept(variant<DefaultNoexcept>()), "");
+}
+
+void copy_ctor()
+{
+  static_assert(is_copy_constructible_v<variant<int, string>>, "");
+  static_assert(!is_copy_constructible_v<variant<AllDeleted, string>>, "");
+
+  {
+    variant<int> a;
+    static_assert(!noexcept(variant<int>(a)), "");
+  }
+  {
+    variant<string> a;
+    static_assert(!noexcept(variant<string>(a)), "");
+  }
+  {
+    variant<int, string> a;
+    static_assert(!noexcept(variant<int, string>(a)), "");
+  }
+  {
+    variant<int, char> a;
+    static_assert(!noexcept(variant<int, char>(a)), "");
+  }
+}
+
+void move_ctor()
+{
+  static_assert(is_move_constructible_v<variant<int, string>>, "");
+  static_assert(!is_move_constructible_v<variant<AllDeleted, string>>, "");
+  static_assert(!noexcept(variant<int, Empty>(variant<int, Empty>())), "");
+  static_assert(noexcept(variant<int, DefaultNoexcept>(variant<int, DefaultNoexcept>())), "");
+}
+
+void arbitrary_ctor()
+{
+  static_assert(!is_constructible_v<variant<string, string>, const char*>, "");
+  static_assert(is_constructible_v<variant<int, string>, const char*>, "");
+  static_assert(noexcept(variant<int, Empty>(int{})), "");
+  static_assert(noexcept(variant<int, DefaultNoexcept>(int{})), "");
+  static_assert(!noexcept(variant<int, Empty>(Empty{})), "");
+  static_assert(noexcept(variant<int, DefaultNoexcept>(DefaultNoexcept{})), "");
+}
+
+void in_place_index_ctor()
+{
+  variant<string, string> a(in_place<0>, "a");
+  variant<string, string> b(in_place<1>, {'a'});
+}
+
+void in_place_type_ctor()
+{
+  variant<int, string, int> a(in_place<string>, "a");
+  variant<int, string, int> b(in_place<string>, {'a'});
+  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<int> b(allocator_arg, alloc, a);
+    static_assert(!is_constructible_v<variant<void>, allocator_arg_t, std::allocator<char>, const variant<void>&>, "");
+  }
+  {
+    variant<int> b(allocator_arg, alloc, std::move(a));
+    static_assert(!is_constructible_v<variant<void>, allocator_arg_t, std::allocator<char>, variant<void>&&>, "");
+  }
+  {
+    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<0>, "a");
+    variant<string, string> c(allocator_arg, alloc, in_place<1>, "a");
+  }
+  {
+    variant<string, int> b(allocator_arg, alloc, in_place<0>, {'a'});
+    variant<string, string> c(allocator_arg, alloc, in_place<1>, {'a'});
+  }
+  {
+    variant<int, string, int> b(allocator_arg, alloc, in_place<string>, "a");
+  }
+  {
+    variant<int, string, int> b(allocator_arg, alloc, in_place<string>, {'a'});
+  }
+}
+
+void dtor()
+{
+  static_assert(is_destructible_v<variant<int, string>>, "");
+  static_assert(is_destructible_v<variant<AllDeleted, string>>, "");
+}
+
+void copy_assign()
+{
+  static_assert(is_copy_assignable_v<variant<int, string>>, "");
+  static_assert(!is_copy_assignable_v<variant<AllDeleted, string>>, "");
+  {
+    variant<Empty> a;
+    static_assert(!noexcept(a = a), "");
+  }
+  {
+    variant<DefaultNoexcept> a;
+    static_assert(!noexcept(a = a), "");
+  }
+}
+
+void move_assign()
+{
+  static_assert(is_move_assignable_v<variant<int, string>>, "");
+  static_assert(!is_move_assignable_v<variant<AllDeleted, string>>, "");
+  {
+    variant<Empty> a;
+    static_assert(!noexcept(a = std::move(a)), "");
+  }
+  {
+    variant<DefaultNoexcept> a;
+    static_assert(noexcept(a = std::move(a)), "");
+  }
+}
+
+void arbitrary_assign()
+{
+  static_assert(!is_assignable_v<variant<string, string>, const char*>, "");
+  static_assert(is_assignable_v<variant<int, string>, const char*>, "");
+  static_assert(noexcept(variant<int, Empty>() = int{}), "");
+  static_assert(noexcept(variant<int, DefaultNoexcept>() = int{}), "");
+  static_assert(!noexcept(variant<int, Empty>() = Empty{}), "");
+  static_assert(noexcept(variant<int, DefaultNoexcept>() = DefaultNoexcept{}), "");
+}
+
+void test_get()
+{
+  {
+    static_assert(is_same<decltype(get<0>(variant<int, string>())), int&&>::value, "");
+    static_assert(is_same<decltype(get<1>(variant<int, string>())), string&&>::value, "");
+    static_assert(is_same<decltype(get<1>(variant<int, string&>())), string&>::value, "");
+    static_assert(is_same<decltype(get<1>(variant<int, string&&>())), string&&>::value, "");
+    static_assert(is_same<decltype(get<1>(variant<int, const string>())), const string&&>::value, "");
+    static_assert(is_same<decltype(get<1>(variant<int, const string&>())), const string&>::value, "");
+    static_assert(is_same<decltype(get<1>(variant<int, const string&&>())), const string&&>::value, "");
+
+    static_assert(is_same<decltype(get<int>(variant<int, string>())), int&&>::value, "");
+    static_assert(is_same<decltype(get<string>(variant<int, string>())), string&&>::value, "");
+    static_assert(is_same<decltype(get<string&>(variant<int, string&>())), string&>::value, "");
+    static_assert(is_same<decltype(get<string&&>(variant<int, string&&>())), string&&>::value, "");
+    static_assert(is_same<decltype(get<const string>(variant<int, const string>())), const string&&>::value, "");
+    static_assert(is_same<decltype(get<const string&>(variant<int, const string&>())), const string&>::value, "");
+    static_assert(is_same<decltype(get<const string&&>(variant<int, const string&&>())), const string&&>::value, "");
+  }
+  {
+    variant<int, string> a;
+    variant<int, string&> b;
+    variant<int, string&&> c;
+    variant<int, const string> d;
+    variant<int, const string&> e;
+    variant<int, const string&&> f;
+
+    static_assert(is_same<decltype(get<0>(a)), int&>::value, "");
+    static_assert(is_same<decltype(get<1>(a)), string&>::value, "");
+    static_assert(is_same<decltype(get<1>(b)), string&>::value, "");
+    static_assert(is_same<decltype(get<1>(c)), string&>::value, "");
+    static_assert(is_same<decltype(get<1>(e)), const string&>::value, "");
+    static_assert(is_same<decltype(get<1>(e)), const string&>::value, "");
+    static_assert(is_same<decltype(get<1>(f)), const string&>::value, "");
+
+    static_assert(is_same<decltype(get<int>(a)), int&>::value, "");
+    static_assert(is_same<decltype(get<string>(a)), string&>::value, "");
+    static_assert(is_same<decltype(get<string&>(b)), string&>::value, "");
+    static_assert(is_same<decltype(get<string&&>(c)), string&>::value, "");
+    static_assert(is_same<decltype(get<const string>(e)), const string&>::value, "");
+    static_assert(is_same<decltype(get<const string&>(e)), const string&>::value, "");
+    static_assert(is_same<decltype(get<const string&&>(f)), const string&>::value, "");
+
+    static_assert(is_same<decltype(get_if<0>(&a)), int*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&a)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&b)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&c)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&e)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&e)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&f)), const string*>::value, "");
+
+    static_assert(is_same<decltype(get_if<int>(&a)), int*>::value, "");
+    static_assert(is_same<decltype(get_if<string>(&a)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<string&>(&b)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<string&&>(&c)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<const string>(&e)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<const string&>(&e)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<const string&&>(&f)), const string*>::value, "");
+  }
+  {
+    const variant<int, string> a;
+    const variant<int, string&> b;
+    const variant<int, string&&> c;
+    const variant<int, const string> d;
+    const variant<int, const string&> e;
+    const variant<int, const string&&> f;
+
+    static_assert(is_same<decltype(get<0>(a)), const int&>::value, "");
+    static_assert(is_same<decltype(get<1>(a)), const string&>::value, "");
+    static_assert(is_same<decltype(get<1>(b)), string&>::value, "");
+    static_assert(is_same<decltype(get<1>(c)), string&>::value, "");
+    static_assert(is_same<decltype(get<1>(d)), const string&>::value, "");
+    static_assert(is_same<decltype(get<1>(e)), const string&>::value, "");
+    static_assert(is_same<decltype(get<1>(f)), const string&>::value, "");
+
+    static_assert(is_same<decltype(get<int>(a)), const int&>::value, "");
+    static_assert(is_same<decltype(get<string>(a)), const string&>::value, "");
+    static_assert(is_same<decltype(get<string&>(b)), string&>::value, "");
+    static_assert(is_same<decltype(get<string&&>(c)), string&>::value, "");
+    static_assert(is_same<decltype(get<const string>(d)), const string&>::value, "");
+    static_assert(is_same<decltype(get<const string&>(e)), const string&>::value, "");
+    static_assert(is_same<decltype(get<const string&&>(f)), const string&>::value, "");
+
+    static_assert(is_same<decltype(get_if<0>(&a)), const int*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&a)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&b)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&c)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&d)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&e)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<1>(&f)), const string*>::value, "");
+
+    static_assert(is_same<decltype(get_if<int>(&a)), const int*>::value, "");
+    static_assert(is_same<decltype(get_if<string>(&a)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<string&>(&b)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<string&&>(&c)), string*>::value, "");
+    static_assert(is_same<decltype(get_if<const string>(&d)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<const string&>(&e)), const string*>::value, "");
+    static_assert(is_same<decltype(get_if<const string&&>(&f)), const string*>::value, "");
+  }
+}
+
+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);
+  }
+  {
+    const monostate a, b;
+    (void)(a < b);
+    (void)(a > b);
+    (void)(a <= b);
+    (void)(a == b);
+    (void)(a != b);
+    (void)(a >= b);
+  }
+}
+
+void test_swap()
+{
+  variant<int, string> a, b;
+  a.swap(b);
+  swap(a, b);
+}
+
+void test_visit()
+{
+  {
+    struct Visitor
+    {
+      void operator()(monostate) {}
+      void operator()(const int&) {}
+    };
+    struct CVisitor
+    {
+      void operator()(monostate) const {}
+      void operator()(const int&) const {}
+    };
+    variant<monostate, int&, const int&, int&&, const int&&> a;
+    const variant<monostate, int&, const int&, int&&, const int&&> b;
+    Visitor v;
+    const CVisitor u;
+    static_assert(is_same<void, decltype(visit(Visitor(), a))>::value, "");
+    static_assert(is_same<void, decltype(visit(Visitor(), b))>::value, "");
+    static_assert(is_same<void, decltype(visit(v, a))>::value, "");
+    static_assert(is_same<void, decltype(visit(v, b))>::value, "");
+    static_assert(is_same<void, decltype(visit(u, a))>::value, "");
+    static_assert(is_same<void, decltype(visit(u, b))>::value, "");
+  }
+  {
+    struct Visitor
+    {
+      bool operator()(int, float) { return false; }
+      bool operator()(int, double) { return false; }
+      bool operator()(char, float) { return false; }
+      bool operator()(char, double) { return false; }
+    };
+    visit(Visitor(), variant<int, char>(), variant<float, double>());
+  }
+}
+
+void test_constexpr()
+{
+  constexpr variant<int> a;
+  static_assert(holds_alternative<int>(a), "");
+  constexpr variant<int, char> b(in_place<0>, int{});
+  static_assert(holds_alternative<int>(b), "");
+  constexpr variant<int, char> c(in_place<int>, int{});
+  static_assert(holds_alternative<int>(c), "");
+  constexpr variant<int, char> d(in_place<1>, char{});
+  static_assert(holds_alternative<char>(d), "");
+  constexpr variant<int, char> e(in_place<char>, char{});
+  static_assert(holds_alternative<char>(e), "");
+  constexpr variant<int, char> f(char{});
+  static_assert(holds_alternative<char>(f), "");
+
+  {
+    struct literal {
+	constexpr literal() = default;
+    };
+
+    struct nonliteral {
+	nonliteral() { }
+    };
+
+    constexpr variant<literal, nonliteral> v{};
+    constexpr variant<literal, nonliteral> v1{in_place<literal>};
+    constexpr variant<literal, nonliteral> v2{in_place<0>};
+  }
+}
+
+void test_void()
+{
+  static_assert(is_same<int&&, decltype(get<int>(variant<int, void>()))>::value, "");
+  static_assert(!is_default_constructible_v<variant<void, int>>, "");
+  static_assert(!is_copy_constructible_v<variant<int, void>>, "");
+  static_assert(!is_move_constructible_v<variant<int, void>>, "");
+  static_assert(!is_copy_assignable_v<variant<int, void>>, "");
+  static_assert(!is_move_assignable_v<variant<int, void>>, "");
+  variant<int, void, string> v;
+  v = 3;
+  v = "asdf";
+}
diff --git a/libstdc++-v3/testsuite/20_util/variant/run.cc b/libstdc++-v3/testsuite/20_util/variant/run.cc
new file mode 100644
index 0000000..cbe3b17
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/variant/run.cc
@@ -0,0 +1,501 @@ 
+// { dg-options "-std=gnu++17" }
+// { dg-do run }
+
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <variant>
+#include <string>
+#include <vector>
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+using namespace std;
+
+struct AlwaysThrow
+{
+  AlwaysThrow() = default;
+
+  AlwaysThrow(const AlwaysThrow&)
+  { throw nullptr; }
+
+  AlwaysThrow(AlwaysThrow&&)
+  { throw nullptr; }
+
+  AlwaysThrow& operator=(const AlwaysThrow&)
+  {
+    throw nullptr;
+    return *this;
+  }
+
+  AlwaysThrow& operator=(AlwaysThrow&&)
+  {
+    throw nullptr;
+    return *this;
+  }
+};
+
+void default_ctor()
+{
+  bool test [[gnu::unused]] = true;
+
+  variant<monostate, string> v;
+  VERIFY(holds_alternative<monostate>(v));
+}
+
+void copy_ctor()
+{
+  bool test [[gnu::unused]] = true;
+
+  variant<monostate, string> v("a");
+  VERIFY(holds_alternative<string>(v));
+  variant<monostate, string> u(v);
+  VERIFY(holds_alternative<string>(u));
+  VERIFY(get<string>(u) == "a");
+}
+
+void move_ctor()
+{
+  bool test [[gnu::unused]] = true;
+
+  variant<monostate, string> v("a");
+  VERIFY(holds_alternative<string>(v));
+  variant<monostate, string> u(std::move(v));
+  VERIFY(holds_alternative<string>(u));
+  VERIFY(get<string>(u) == "a");
+  VERIFY(holds_alternative<string>(v));
+}
+
+void arbitrary_ctor()
+{
+  bool test [[gnu::unused]] = true;
+
+  variant<int, string> v("a");
+  VERIFY(holds_alternative<string>(v));
+  VERIFY(get<1>(v) == "a");
+}
+
+void copy_assign()
+{
+  bool test [[gnu::unused]] = true;
+
+  variant<monostate, string> v("a");
+  VERIFY(holds_alternative<string>(v));
+  variant<monostate, string> u;
+  u = v;
+  VERIFY(holds_alternative<string>(u));
+  VERIFY(get<string>(u) == "a");
+}
+
+void move_assign()
+{
+  bool test [[gnu::unused]] = true;
+
+  variant<monostate, string> v("a");
+  VERIFY(holds_alternative<string>(v));
+  variant<monostate, string> u;
+  u = std::move(v);
+  VERIFY(holds_alternative<string>(u));
+  VERIFY(get<string>(u) == "a");
+  VERIFY(holds_alternative<string>(v));
+}
+
+void arbitrary_assign()
+{
+  bool test [[gnu::unused]] = true;
+
+  variant<int, string> v;
+  v = "a";
+
+  VERIFY(holds_alternative<string>(variant<int, string>("a")));
+  VERIFY(get<1>(v) == "a");
+}
+
+void dtor()
+{
+  bool test [[gnu::unused]] = true;
+
+  struct A {
+      A(int& called) : called(called) {}
+      ~A() {
+	  called++;
+      }
+      int& called;
+  };
+  {
+    int called = 0;
+    { variant<string, A> a(in_place<1>, called); }
+    VERIFY(called == 1);
+  }
+  {
+    int called = 0;
+    { variant<string, A> a(in_place<0>); }
+    VERIFY(called == 0);
+  }
+}
+
+void in_place_index_ctor()
+{
+  bool test [[gnu::unused]] = true;
+
+  {
+    variant<int, string> v(in_place<1>, "a");
+    VERIFY(holds_alternative<string>(v));
+    VERIFY(get<1>(v) == "a");
+  }
+  {
+    variant<int, string> v(in_place<1>, {'a', 'b'});
+    VERIFY(holds_alternative<string>(v));
+    VERIFY(get<1>(v) == "ab");
+  }
+}
+
+void in_place_type_ctor()
+{
+  bool test [[gnu::unused]] = true;
+
+  {
+    variant<int, string> v(in_place<string>, "a");
+    VERIFY(holds_alternative<string>(v));
+    VERIFY(get<1>(v) == "a");
+  }
+  {
+    variant<int, string> v(in_place<string>, {'a', 'b'});
+    VERIFY(holds_alternative<string>(v));
+    VERIFY(get<1>(v) == "ab");
+  }
+}
+
+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()
+{
+  bool test [[gnu::unused]] = true;
+
+  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()
+{
+  bool test [[gnu::unused]] = true;
+
+  variant<int, string> v;
+  v.emplace<0>(1);
+  VERIFY(get<0>(v) == 1);
+  v.emplace<string>("a");
+  VERIFY(get<string>(v) == "a");
+  v.emplace<1>({'a', 'b'});
+  VERIFY(get<1>(v) == "ab");
+  v.emplace<string>({'a', 'c'});
+  VERIFY(get<string>(v) == "ac");
+  {
+    variant<int, AlwaysThrow> v;
+    AlwaysThrow a;
+    try { v.emplace<1>(a); } catch (nullptr_t) { }
+    VERIFY(v.valueless_by_exception());
+  }
+  {
+    variant<int, AlwaysThrow> v;
+    try { v.emplace<1>(AlwaysThrow{}); } catch (nullptr_t) { }
+    VERIFY(v.valueless_by_exception());
+  }
+}
+
+void test_get()
+{
+  bool test [[gnu::unused]] = true;
+
+  VERIFY(get<1>(variant<int, string>("a")) == "a");
+  VERIFY(get<string>(variant<int, string>("a")) == "a");
+  {
+    bool caught = false;
+
+    try
+      {
+	get<0>(variant<int, string>("a"));
+      }
+    catch (const bad_variant_access&)
+      {
+	caught = true;
+      }
+    VERIFY(caught);
+  }
+  {
+    bool caught = false;
+
+    try
+      {
+	get<int>(variant<int, string>("a"));
+      }
+    catch (const bad_variant_access&)
+      {
+	caught = true;
+      }
+    VERIFY(caught);
+  }
+}
+
+void test_relational()
+{
+  bool test [[gnu::unused]] = true;
+
+  VERIFY((variant<int, string>(2) < variant<int, string>(3)));
+  VERIFY((variant<int, string>(3) == variant<int, string>(3)));
+  VERIFY((variant<int, string>(3) > variant<int, string>(2)));
+  VERIFY((variant<int, string>(3) <= variant<int, string>(3)));
+  VERIFY((variant<int, string>(2) <= variant<int, string>(3)));
+  VERIFY((variant<int, string>(3) >= variant<int, string>(3)));
+  VERIFY((variant<int, string>(3) >= variant<int, string>(2)));
+  VERIFY((variant<int, string>(2) != variant<int, string>(3)));
+
+  VERIFY((variant<int, string>(2) < variant<int, string>("a")));
+  VERIFY((variant<string, int>(2) > variant<string, int>("a")));
+}
+
+void test_swap()
+{
+  bool test [[gnu::unused]] = true;
+
+  variant<int, string> a("a"), b("b");
+  a.swap(b);
+  VERIFY(get<1>(a) == "b");
+  VERIFY(get<1>(b) == "a");
+  swap(a, b);
+  VERIFY(get<1>(a) == "a");
+  VERIFY(get<1>(b) == "b");
+}
+
+void test_visit()
+{
+  bool test [[gnu::unused]] = true;
+
+  {
+    struct Visitor
+    {
+      int operator()(int, float) {
+	  return 0;
+      }
+      int operator()(int, double) {
+	  return 1;
+      }
+      int operator()(char, float) {
+	  return 2;
+      }
+      int operator()(char, double) {
+	  return 3;
+      }
+      int operator()(int, float) const {
+	  return 5;
+      }
+      int operator()(int, double) const {
+	  return 6;
+      }
+      int operator()(char, float) const {
+	  return 7;
+      }
+      int operator()(char, double) const {
+	  return 8;
+      }
+    } visitor1;
+    VERIFY(visit(visitor1, variant<int, char>(1), variant<float, double>(1.0f)) == 0);
+    VERIFY(visit(visitor1, variant<int, char>(1), variant<float, double>(1.0)) == 1);
+    VERIFY(visit(visitor1, variant<int, char>('a'), variant<float, double>(1.0f)) == 2);
+    VERIFY(visit(visitor1, variant<int, char>('a'), variant<float, double>(1.0)) == 3);
+
+    const auto& visitor2 = visitor1;
+    VERIFY(visit(visitor2, variant<int, char>(1), variant<float, double>(1.0f)) == 5);
+    VERIFY(visit(visitor2, variant<int, char>(1), variant<float, double>(1.0)) == 6);
+    VERIFY(visit(visitor2, variant<int, char>('a'), variant<float, double>(1.0f)) == 7);
+    VERIFY(visit(visitor2, variant<int, char>('a'), variant<float, double>(1.0)) == 8);
+  }
+
+  {
+    struct Visitor
+    {
+      int operator()(int, float) && {
+	  return 0;
+      }
+      int operator()(int, double) && {
+	  return 1;
+      }
+      int operator()(char, float) && {
+	  return 2;
+      }
+      int operator()(char, double) && {
+	  return 3;
+      }
+    };
+    VERIFY(visit(Visitor{}, variant<int, char>(1), variant<float, double>(1.0f)) == 0);
+    VERIFY(visit(Visitor{}, variant<int, char>(1), variant<float, double>(1.0)) == 1);
+    VERIFY(visit(Visitor{}, variant<int, char>('a'), variant<float, double>(1.0f)) == 2);
+    VERIFY(visit(Visitor{}, variant<int, char>('a'), variant<float, double>(1.0)) == 3);
+  }
+}
+
+void test_hash()
+{
+  bool test [[gnu::unused]] = true;
+
+  unordered_set<variant<int, string>> s;
+  VERIFY(s.emplace(3).second);
+  VERIFY(s.emplace("asdf").second);
+  VERIFY(s.emplace().second);
+  VERIFY(s.size() == 3);
+  VERIFY(!s.emplace(3).second);
+  VERIFY(!s.emplace("asdf").second);
+  VERIFY(!s.emplace().second);
+  VERIFY(s.size() == 3);
+  {
+    struct A
+    {
+      operator int()
+      {
+        throw nullptr;
+      }
+    };
+    variant<int, string> v;
+    try
+      {
+        v.emplace<0>(A{});
+      }
+    catch (nullptr_t)
+      {
+      }
+    VERIFY(v.valueless_by_exception());
+    VERIFY(s.insert(v).second);
+    VERIFY(s.size() == 4);
+    VERIFY(!s.insert(v).second);
+  }
+}
+
+void test_valueless_by_exception()
+{
+  bool test [[gnu::unused]] = true;
+
+  {
+    AlwaysThrow a;
+    bool caught = false;
+    try
+      {
+	variant<int, AlwaysThrow> v(a);
+      }
+    catch (nullptr_t)
+      {
+	caught = true;
+      }
+    VERIFY(caught);
+  }
+  {
+    AlwaysThrow a;
+    bool caught = false;
+    try
+      {
+	variant<int, AlwaysThrow> v(a);
+      }
+    catch (nullptr_t)
+      {
+	caught = true;
+      }
+    VERIFY(caught);
+  }
+  {
+    variant<int, AlwaysThrow> v;
+    bool caught = false;
+    try
+      {
+	AlwaysThrow a;
+	v = a;
+      }
+    catch (nullptr_t)
+      {
+	caught = true;
+      }
+    VERIFY(caught);
+    VERIFY(v.valueless_by_exception());
+  }
+  {
+    variant<int, AlwaysThrow> v;
+    bool caught = false;
+    try
+      {
+	v = AlwaysThrow{};
+      }
+    catch (nullptr_t)
+      {
+	caught = true;
+      }
+    VERIFY(caught);
+    VERIFY(v.valueless_by_exception());
+  }
+}
+
+int main()
+{
+  default_ctor();
+  copy_ctor();
+  move_ctor();
+  arbitrary_ctor();
+  in_place_index_ctor();
+  in_place_type_ctor();
+  uses_allocator_ctor();
+  copy_assign();
+  move_assign();
+  arbitrary_assign();
+  dtor();
+  emplace();
+  test_get();
+  test_relational();
+  test_swap();
+  test_visit();
+  test_hash();
+  test_valueless_by_exception();
+}