public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [Patch] Implement std::experimental::variant
       [not found]                   ` <20160805110808.GY4264@redhat.com>
@ 2016-08-06  5:46                     ` Tim Shen
  2016-08-07  1:04                       ` Ville Voutilainen
  2016-08-18 12:47                       ` Jonathan Wakely
  0 siblings, 2 replies; 9+ messages in thread
From: Tim Shen @ 2016-08-06  5:46 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Ville Voutilainen, libstdc++, Axel Naumann, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 19027 bytes --]

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!


-- 
Regards,
Tim Shen

[-- Attachment #2: c.diff --]
[-- Type: text/plain, Size: 81016 bytes --]

commit 68159483a1f0d7338d9de1771fd5c18d509ecf83
Author: Tim Shen <timshen@google.com>
Date:   Fri Aug 5 22:29:40 2016 -0700

    2016-08-05  Tim Shen  <timshen@google.com>
    
            Implement <variant>
    
            * include/Makefile.am: Add new file std/variant.
            * include/Makefile.in: Generated from Makefile.am.
            * include/bits/enable_special_members.h: Add a tag type to allow
            the construction in non-default constructor.
            * include/bits/uses_allocator.h: Add convenience traits to
            detect constructibility.
            * include/std/variant: Implement <variant>.
            * testsuite/20_util/variant/compile.cc: Compile-time tests.
            * testsuite/20_util/variant/run.cc: Runtime tests.

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();
+}

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] Implement std::experimental::variant
  2016-08-06  5:46                     ` [Patch] Implement std::experimental::variant Tim Shen
@ 2016-08-07  1:04                       ` Ville Voutilainen
  2016-08-08 10:14                         ` Ville Voutilainen
  2016-08-18 12:47                       ` Jonathan Wakely
  1 sibling, 1 reply; 9+ messages in thread
From: Ville Voutilainen @ 2016-08-07  1:04 UTC (permalink / raw)
  To: Tim Shen; +Cc: Jonathan Wakely, libstdc++, Axel Naumann, gcc-patches

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.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] Implement std::experimental::variant
  2016-08-07  1:04                       ` Ville Voutilainen
@ 2016-08-08 10:14                         ` Ville Voutilainen
  0 siblings, 0 replies; 9+ messages in thread
From: Ville Voutilainen @ 2016-08-08 10:14 UTC (permalink / raw)
  To: Tim Shen; +Cc: Jonathan Wakely, libstdc++, Axel Naumann, gcc-patches

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 :) )

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] Implement std::experimental::variant
  2016-08-06  5:46                     ` [Patch] Implement std::experimental::variant Tim Shen
  2016-08-07  1:04                       ` Ville Voutilainen
@ 2016-08-18 12:47                       ` Jonathan Wakely
  2016-08-18 20:32                         ` Tim Shen
  1 sibling, 1 reply; 9+ messages in thread
From: Jonathan Wakely @ 2016-08-18 12:47 UTC (permalink / raw)
  To: Tim Shen; +Cc: Ville Voutilainen, libstdc++, Axel Naumann, gcc-patches

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!


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] Implement std::experimental::variant
  2016-08-18 12:47                       ` Jonathan Wakely
@ 2016-08-18 20:32                         ` Tim Shen
  2016-08-19  8:18                           ` Jonathan Wakely
  0 siblings, 1 reply; 9+ messages in thread
From: Tim Shen @ 2016-08-18 20:32 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Ville Voutilainen, libstdc++, Axel Naumann, gcc-patches

Tested on x86_64-linux-gnu and checked in as r239590.

Thanks!


-- 
Regards,
Tim Shen

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] Implement std::experimental::variant
  2016-08-18 20:32                         ` Tim Shen
@ 2016-08-19  8:18                           ` Jonathan Wakely
  2016-08-26 14:43                             ` Andre Vieira (lists)
  0 siblings, 1 reply; 9+ messages in thread
From: Jonathan Wakely @ 2016-08-19  8:18 UTC (permalink / raw)
  To: Tim Shen; +Cc: Ville Voutilainen, libstdc++, Axel Naumann, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 223 bytes --]

On 18/08/16 13:32 -0700, Tim Shen wrote:
>Tested on x86_64-linux-gnu and checked in as r239590.

This updates the status at
https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.201z

Committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1714 bytes --]

commit 6c46b6c04ac234b6443208e922bb3177344e90a8
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Aug 19 09:15:36 2016 +0100

    Update C++17 library status table
    
    	* doc/xml/manual/status_cxx2017.xml: Update status of make_from_tuple
    	and variant.
    	* doc/html/*: Regenerate.

diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
index 99f2bbf..35d6b6b 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
@@ -92,14 +92,13 @@ Feature-testing recommendations for C++</link>.
     </row>
 
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry> Variant: a type-safe union for C++17 </entry>
       <entry>
 	<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0088r3.html">
 	P0088R3
 	</link>
       </entry>
-      <entry align="center"> No </entry>
+      <entry align="center"> 7 </entry>
       <entry> <code>__has_include(&lt;variant&gt;)</code> </entry>
     </row>
 
@@ -206,14 +205,13 @@ Feature-testing recommendations for C++</link>.
     </row>
 
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
-      <entry> make_from_tuple: apply for construction </entry>
+      <entry> <code>make_from_tuple</code>: apply for construction </entry>
       <entry>
 	<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0209r2.pdf">
 	P0209R2
 	</link>
       </entry>
-      <entry align="center"> No </entry>
+      <entry align="center"> 7 </entry>
       <entry><code> __cpp_lib_make_from_tuple >= 201606 </code></entry>
     </row>
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] Implement std::experimental::variant
  2016-08-19  8:18                           ` Jonathan Wakely
@ 2016-08-26 14:43                             ` Andre Vieira (lists)
  2016-08-26 17:56                               ` Tim Shen
  0 siblings, 1 reply; 9+ messages in thread
From: Andre Vieira (lists) @ 2016-08-26 14:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: timshen

On 19/08/16 09:18, Jonathan Wakely wrote:
> On 18/08/16 13:32 -0700, Tim Shen wrote:
>> Tested on x86_64-linux-gnu and checked in as r239590.
> 
> This updates the status at
> https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.201z
> 
> Committed to trunk.
> 
> 

Hi,

I am seeing failures on arm-none-eabi for Cortex-M0 for these two tests:
.../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant: In
member function 'std::__detail::__variant::_Variant_base<_Types>&
std::__detail::__variant::_Variant_base<_Types>::operator=(const
std::__detail::__variant::_Variant_base<_Types>&)':
.../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:442:
error: '__try' was not declared in this scope
.../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:442:
note: suggested alternative: '__try'
.../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:446:
error: expected primary-expression before '...' token
.../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:446:
error: there are no arguments to '__catch' that depend on a template
parameter, so a declaration of '__catch' must be available [-fpermissive]^M
.../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:446:
note: (if you use '-fpermissive', G++ will accept your code, but
allowing the use of an undeclared name is deprecated)^M
.../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:447:
error: expected ';' before '{' token^M

(and more of the same ...)

Adding '#include <bits/exception_defines.h>' to
'include/c++/7.0.0/variant' "fixes" that. Not sure its the right
approach though.

For Cortex-M3 it builds but run.cc fails at execution time. I will look
further into this. The reason it succeeds for Cortex-M3 is because
'<utility>' includes '<exception>' and exception has the following code:
#if (__cplusplus >= 201103L) && (ATOMIC_INT_LOCK_FREE > 1)
#include <bits/exception_ptr.h>
#include <bits/nested_exception.h>
#endif

Which includes bits/exception_ptr.h and thus bits/exception_defines.h
for targets with ATOMIC_INT_LOCK_FREE which is the case for Cortex-M3
but not Cortex-M0.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] Implement std::experimental::variant
  2016-08-26 14:43                             ` Andre Vieira (lists)
@ 2016-08-26 17:56                               ` Tim Shen
  2016-09-13  9:12                                 ` Andre Vieira (lists)
  0 siblings, 1 reply; 9+ messages in thread
From: Tim Shen @ 2016-08-26 17:56 UTC (permalink / raw)
  To: Andre Vieira (lists); +Cc: gcc-patches

Hi,

On Fri, Aug 26, 2016 at 7:43 AM, Andre Vieira (lists)
<Andre.SimoesDiasVieira@arm.com> wrote:
> I am seeing failures on arm-none-eabi for Cortex-M0 for these two tests:
> .../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant: In
> member function 'std::__detail::__variant::_Variant_base<_Types>&
> std::__detail::__variant::_Variant_base<_Types>::operator=(const
> std::__detail::__variant::_Variant_base<_Types>&)':
> .../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:442:
> error: '__try' was not declared in this scope
> .../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:442:
> note: suggested alternative: '__try'
> .../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:446:
> error: expected primary-expression before '...' token
> .../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:446:
> error: there are no arguments to '__catch' that depend on a template
> parameter, so a declaration of '__catch' must be available [-fpermissive]^M
> .../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:446:
> note: (if you use '-fpermissive', G++ will accept your code, but
> allowing the use of an undeclared name is deprecated)^M
> .../gcc-final/arm-none-eabi/armv6-m/libstdc++-v3/include/variant:447:
> error: expected ';' before '{' token^M
>
> (and more of the same ...)
>
> Adding '#include <bits/exception_defines.h>' to
> 'include/c++/7.0.0/variant' "fixes" that. Not sure its the right
> approach though.

Why not?

>
> For Cortex-M3 it builds but run.cc fails at execution time. I will look
> further into this.

Can you attach testsuite/libstdc++.log? I'll find an arm machine to
reproduce it.

> The reason it succeeds for Cortex-M3 is because
> '<utility>' includes '<exception>' and exception has the following code:
> #if (__cplusplus >= 201103L) && (ATOMIC_INT_LOCK_FREE > 1)
> #include <bits/exception_ptr.h>
> #include <bits/nested_exception.h>
> #endif
>
> Which includes bits/exception_ptr.h and thus bits/exception_defines.h
> for targets with ATOMIC_INT_LOCK_FREE which is the case for Cortex-M3
> but not Cortex-M0.



-- 
Regards,
Tim Shen

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Patch] Implement std::experimental::variant
  2016-08-26 17:56                               ` Tim Shen
@ 2016-09-13  9:12                                 ` Andre Vieira (lists)
  0 siblings, 0 replies; 9+ messages in thread
From: Andre Vieira (lists) @ 2016-09-13  9:12 UTC (permalink / raw)
  To: Tim Shen; +Cc: gcc-patches

On 26/08/16 18:56, Tim Shen wrote:
>>
>> Adding '#include <bits/exception_defines.h>' to
>> 'include/c++/7.0.0/variant' "fixes" that. Not sure its the right
>> approach though.
> 
> Why not?
> 
I'm not saying its the wrong approach, I'm just saying thats the first
thing I tried and it "seemed" to solve it but I didnt really look into
whether it was the right thing to do.

>>
>> For Cortex-M3 it builds but run.cc fails at execution time. I will look
>> further into this.
> 
I only now noticed this execution failure was for our newlib-nano test
run, which does not support exceptions, so ignore that.


> Can you attach testsuite/libstdc++.log? I'll find an arm machine to
> reproduce it.
> 

You can reproduce for the compile failure with:

$ arm-none-eabi-g++
src/gcc/libstdc++-v3/testsuite/20_util/variant/compile.cc -S
-std=gnu++17 -mcpu=cortex-m0 -mthumb

which fails and if you change -mcpu=cortex-m0 to -mcpu=cortex-m3 it builds.


Cheers,
Andre

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-09-13  8:58 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CAG4ZjNnKxAhg6nNjPFZjoFji50StG9LURa_Wt=OdejLJ=NkSUw@mail.gmail.com>
     [not found] ` <20160516130235.GX27545@redhat.com>
     [not found]   ` <CAG4ZjNmtU8d82oJzkxBapy8jQf2Y2re5YEjqwVFNp+4OAA3p4w@mail.gmail.com>
     [not found]     ` <20160609075308.GR2629@redhat.com>
     [not found]       ` <CAG4ZjNmpUmbjAYDQfVut+b=xsokJBp3maf3Vn3KZ5A0j4vO=Vg@mail.gmail.com>
     [not found]         ` <CAFk2RUbrb6VJAY0ujbXDPQ0y_p4JWN7HSJBKGn+bWbxBR1Vk8A@mail.gmail.com>
     [not found]           ` <CAFk2RUaeAR5H4x_z_ZNDdEbbV7+n=qC+Xm91_9SVvq3+kMTF1A@mail.gmail.com>
     [not found]             ` <CAG4ZjNn76ArgbX87kwTHZXgWnKSnjQ1fYpN5LLHhsLMpWF2+Nw@mail.gmail.com>
     [not found]               ` <CAFk2RUYgDWYStVgsiaP809LmK7Kk0J6iX1tv9xvTRUr2RXVcYg@mail.gmail.com>
     [not found]                 ` <CAG4ZjNkvdCuJMmXzvJ2FejJLAtLyUzKf6=JDRKBM2Sd2va_YFQ@mail.gmail.com>
     [not found]                   ` <20160805110808.GY4264@redhat.com>
2016-08-06  5:46                     ` [Patch] Implement std::experimental::variant Tim Shen
2016-08-07  1:04                       ` Ville Voutilainen
2016-08-08 10:14                         ` Ville Voutilainen
2016-08-18 12:47                       ` Jonathan Wakely
2016-08-18 20:32                         ` Tim Shen
2016-08-19  8:18                           ` Jonathan Wakely
2016-08-26 14:43                             ` Andre Vieira (lists)
2016-08-26 17:56                               ` Tim Shen
2016-09-13  9:12                                 ` Andre Vieira (lists)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).