* [committed] libstdc++: Add missing constexpr to std::variant (P2231R1)
@ 2021-10-15 17:29 Jonathan Wakely
0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2021-10-15 17:29 UTC (permalink / raw)
To: libstdc++, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2054 bytes --]
This implements the changes in P2231R1 which make std::variant fully
constexpr in C++20.
We need to replace placement new with std::construct_at, but that isn't
defined for C++17. Use std::_Construct instead, which forwards to
std::construct_at in C++20 mode (since the related changes to make
std::optional fully constexpr, in r12-4389).
We also need to replace the untyped char buffer in _Uninitialized with a
union, which can be accessed in constexpr functions. But the union needs
to have a non-trivial destructor if its variant type is non-trivial,
which means that the _Variadic_union also needs a non-trivial
destructor. This adds a constrained partial specialization of
_Variadic_union for the C++20-only case where a non-trivial destructor
is needed.
We can't use concepts to constrain the specialization (or the primary
template's destructor) in C++17, so retain the untyped char buffer
solution for C++17 mode.
libstdc++-v3/ChangeLog:
* include/std/variant (__cpp_lib_variant): Update value for
C++20.
(__variant_cast, __variant_construct): Add constexpr for C++20.
(__variant_construct_single, __construct_by_index) Likewise. Use
std::_Construct instead of placement new.
(_Uninitialized<T, false>) [__cplusplus >= 202002]: Replace
buffer with a union and define a destructor.
(_Variadic_union) [__cplusplus >= 202002]: Add a specialization
for non-trivial destruction.
(_Variant_storage::__index_of): New helper variable template.
(_Variant_storage::~_Variant_storage()): Add constexpr.
(_Variant_storage::_M_reset()): Likewise.
(_Copy_ctor_base, _Move_ctor_base): Likewise.
(_Copy_assign_base, _Move_assign_base): Likewise.
(variant, swap): Likewise.
* include/std/version (__cpp_lib_variant): Update value for
C++20.
* testsuite/20_util/optional/version.cc: Check for exact value
in C++17.
* testsuite/20_util/variant/87619.cc: Increase timeout for
C++20 mode.
* testsuite/20_util/variant/constexpr.cc: New test.
* testsuite/20_util/variant/version.cc: New test.
Tested powerpc64le-linux. Committed to trunk.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 21188 bytes --]
commit ad820b0bb5f8342a8db2831d1f15c103583a3ba0
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Thu Oct 14 13:27:03 2021
libstdc++: Add missing constexpr to std::variant (P2231R1)
This implements the changes in P2231R1 which make std::variant fully
constexpr in C++20.
We need to replace placement new with std::construct_at, but that isn't
defined for C++17. Use std::_Construct instead, which forwards to
std::construct_at in C++20 mode (since the related changes to make
std::optional fully constexpr, in r12-4389).
We also need to replace the untyped char buffer in _Uninitialized with a
union, which can be accessed in constexpr functions. But the union needs
to have a non-trivial destructor if its variant type is non-trivial,
which means that the _Variadic_union also needs a non-trivial
destructor. This adds a constrained partial specialization of
_Variadic_union for the C++20-only case where a non-trivial destructor
is needed.
We can't use concepts to constrain the specialization (or the primary
template's destructor) in C++17, so retain the untyped char buffer
solution for C++17 mode.
libstdc++-v3/ChangeLog:
* include/std/variant (__cpp_lib_variant): Update value for
C++20.
(__variant_cast, __variant_construct): Add constexpr for C++20.
(__variant_construct_single, __construct_by_index) Likewise. Use
std::_Construct instead of placement new.
(_Uninitialized<T, false>) [__cplusplus >= 202002]: Replace
buffer with a union and define a destructor.
(_Variadic_union) [__cplusplus >= 202002]: Add a specialization
for non-trivial destruction.
(_Variant_storage::__index_of): New helper variable template.
(_Variant_storage::~_Variant_storage()): Add constexpr.
(_Variant_storage::_M_reset()): Likewise.
(_Copy_ctor_base, _Move_ctor_base): Likewise.
(_Copy_assign_base, _Move_assign_base): Likewise.
(variant, swap): Likewise.
* include/std/version (__cpp_lib_variant): Update value for
C++20.
* testsuite/20_util/optional/version.cc: Check for exact value
in C++17.
* testsuite/20_util/variant/87619.cc: Increase timeout for
C++20 mode.
* testsuite/20_util/variant/constexpr.cc: New test.
* testsuite/20_util/variant/version.cc: New test.
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index f49094130ee..d18365fde22 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -39,13 +39,14 @@
#include <bits/exception_defines.h>
#include <bits/functional_hash.h>
#include <bits/invoke.h>
-#include <ext/aligned_buffer.h>
#include <bits/parse_numbers.h>
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_iterator_base_funcs.h>
#include <bits/stl_construct.h>
#include <bits/utility.h> // in_place_index_t
-#if __cplusplus > 201703L
+#if __cplusplus == 201703L
+# include <ext/aligned_buffer.h>
+#else
# include <compare>
#endif
@@ -71,7 +72,12 @@ namespace __variant
} // namespace __variant
} // namespace __detail
-#define __cpp_lib_variant 202102L
+#if __cplusplus >= 202002L && __cpp_concepts
+// P2231R1 constexpr needs constexpr unions and constrained destructors.
+# define __cpp_lib_variant 202106L
+#else
+# define __cpp_lib_variant 202102L
+#endif
template<typename... _Types> class tuple;
template<typename... _Types> class variant;
@@ -146,6 +152,7 @@ namespace __variant
__do_visit(_Visitor&& __visitor, _Variants&&... __variants);
template <typename... _Types, typename _Tp>
+ _GLIBCXX20_CONSTEXPR
decltype(auto)
__variant_cast(_Tp&& __rhs)
{
@@ -224,8 +231,12 @@ namespace __variant
__as(const std::variant<_Types...>&& __v) noexcept
{ return std::move(__v); }
+ // For C++17:
// _Uninitialized<T> is guaranteed to be a trivially destructible type,
// even if T is not.
+ // For C++20:
+ // _Uninitialized<T> is trivially destructible iff T is, so _Variant_union
+ // needs a constrained non-trivial destructor.
template<typename _Type, bool = std::is_trivially_destructible_v<_Type>>
struct _Uninitialized;
@@ -256,6 +267,37 @@ namespace __variant
template<typename _Type>
struct _Uninitialized<_Type, false>
{
+#if __cpp_lib_variant >= 202106L
+ template<typename... _Args>
+ constexpr
+ _Uninitialized(in_place_index_t<0>, _Args&&... __args)
+ : _M_storage(std::forward<_Args>(__args)...)
+ { }
+
+ constexpr ~_Uninitialized() { }
+
+ _Uninitialized(const _Uninitialized&) = default;
+ _Uninitialized(_Uninitialized&&) = default;
+ _Uninitialized& operator=(const _Uninitialized&) = default;
+ _Uninitialized& operator=(_Uninitialized&&) = default;
+
+ constexpr const _Type& _M_get() const & noexcept
+ { return _M_storage; }
+
+ constexpr _Type& _M_get() & noexcept
+ { return _M_storage; }
+
+ constexpr const _Type&& _M_get() const && noexcept
+ { return std::move(_M_storage); }
+
+ constexpr _Type&& _M_get() && noexcept
+ { return std::move(_M_storage); }
+
+ union {
+ char _M_nope;
+ _Type _M_storage;
+ };
+#else
template<typename... _Args>
constexpr
_Uninitialized(in_place_index_t<0>, _Args&&... __args)
@@ -277,6 +319,7 @@ namespace __variant
{ return std::move(*_M_storage._M_ptr()); }
__gnu_cxx::__aligned_membuf<_Type> _M_storage;
+#endif
};
template<size_t _Np, typename _Union>
@@ -353,15 +396,31 @@ namespace __variant
constexpr _Variadic_union() : _M_rest() { }
template<typename... _Args>
- constexpr _Variadic_union(in_place_index_t<0>, _Args&&... __args)
+ constexpr
+ _Variadic_union(in_place_index_t<0>, _Args&&... __args)
: _M_first(in_place_index<0>, std::forward<_Args>(__args)...)
{ }
template<size_t _Np, typename... _Args>
- constexpr _Variadic_union(in_place_index_t<_Np>, _Args&&... __args)
+ constexpr
+ _Variadic_union(in_place_index_t<_Np>, _Args&&... __args)
: _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...)
{ }
+#if __cpp_lib_variant >= 202106L
+ _Variadic_union(const _Variadic_union&) = default;
+ _Variadic_union(_Variadic_union&&) = default;
+ _Variadic_union& operator=(const _Variadic_union&) = default;
+ _Variadic_union& operator=(_Variadic_union&&) = default;
+
+ ~_Variadic_union() = default;
+
+ constexpr ~_Variadic_union()
+ requires (!__has_trivial_destructor(_First))
+ || (!__has_trivial_destructor(_Variadic_union<_Rest...>))
+ { }
+#endif
+
_Uninitialized<_First> _M_first;
_Variadic_union<_Rest...> _M_rest;
};
@@ -406,6 +465,10 @@ namespace __variant
template<typename... _Types>
struct _Variant_storage<false, _Types...>
{
+ template<typename _Tp>
+ static constexpr size_t __index_of
+ = __detail::__variant::__index_of_v<_Tp, _Types...>;
+
constexpr
_Variant_storage()
: _M_index(static_cast<__index_type>(variant_npos))
@@ -418,7 +481,8 @@ namespace __variant
_M_index{_Np}
{ }
- void _M_reset()
+ constexpr void
+ _M_reset()
{
if (!_M_valid()) [[unlikely]]
return;
@@ -431,6 +495,7 @@ namespace __variant
_M_index = static_cast<__index_type>(variant_npos);
}
+ _GLIBCXX20_CONSTEXPR
~_Variant_storage()
{ _M_reset(); }
@@ -450,6 +515,10 @@ namespace __variant
template<typename... _Types>
struct _Variant_storage<true, _Types...>
{
+ template<typename _Tp>
+ static constexpr size_t __index_of
+ = __detail::__variant::__index_of_v<_Tp, _Types...>;
+
constexpr
_Variant_storage()
: _M_index(static_cast<__index_type>(variant_npos))
@@ -462,7 +531,8 @@ namespace __variant
_M_index{_Np}
{ }
- void _M_reset() noexcept
+ constexpr void
+ _M_reset() noexcept
{ _M_index = static_cast<__index_type>(variant_npos); }
constexpr bool
@@ -489,17 +559,25 @@ namespace __variant
_Variant_storage<_Traits<_Types...>::_S_trivial_dtor, _Types...>;
template<typename _Tp, typename _Up>
- void __variant_construct_single(_Tp&& __lhs, _Up&& __rhs_mem)
+ _GLIBCXX20_CONSTEXPR
+ void
+ __variant_construct_single(_Tp&& __lhs, _Up&& __rhs_mem)
{
- void* __storage = std::addressof(__lhs._M_u);
- using _Type = remove_reference_t<decltype(__rhs_mem)>;
+ using _Type = __remove_cvref_t<_Up>;
+
if constexpr (!is_same_v<_Type, __variant_cookie>)
- ::new (__storage)
- _Type(std::forward<decltype(__rhs_mem)>(__rhs_mem));
+ {
+ using _Lhs = remove_reference_t<_Tp>;
+ std::_Construct(std::__addressof(__lhs._M_u),
+ in_place_index<_Lhs::template __index_of<_Type>>,
+ std::forward<_Up>(__rhs_mem));
+ }
}
template<typename... _Types, typename _Tp, typename _Up>
- void __variant_construct(_Tp&& __lhs, _Up&& __rhs)
+ _GLIBCXX20_CONSTEXPR
+ void
+ __variant_construct(_Tp&& __lhs, _Up&& __rhs)
{
__lhs._M_index = __rhs._M_index;
__variant::__raw_visit([&__lhs](auto&& __rhs_mem) mutable
@@ -518,6 +596,7 @@ namespace __variant
using _Base = _Variant_storage_alias<_Types...>;
using _Base::_Base;
+ _GLIBCXX20_CONSTEXPR
_Copy_ctor_base(const _Copy_ctor_base& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_copy_ctor)
{
@@ -546,6 +625,7 @@ namespace __variant
using _Base = _Copy_ctor_alias<_Types...>;
using _Base::_Base;
+ _GLIBCXX20_CONSTEXPR
_Move_ctor_base(_Move_ctor_base&& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_move_ctor)
{
@@ -553,6 +633,7 @@ namespace __variant
}
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs)
{
this->_M_reset();
@@ -561,6 +642,7 @@ namespace __variant
}
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs)
{
this->_M_reset();
@@ -580,6 +662,7 @@ namespace __variant
using _Base::_Base;
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs)
{
this->_M_reset();
@@ -588,6 +671,7 @@ namespace __variant
}
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs)
{
this->_M_reset();
@@ -606,6 +690,7 @@ namespace __variant
using _Base = _Move_ctor_alias<_Types...>;
using _Base::_Base;
+ _GLIBCXX20_CONSTEXPR
_Copy_assign_base&
operator=(const _Copy_assign_base& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_copy_assign)
@@ -664,6 +749,7 @@ namespace __variant
using _Base = _Copy_assign_alias<_Types...>;
using _Base::_Base;
+ _GLIBCXX20_CONSTEXPR
_Move_assign_base&
operator=(_Move_assign_base&& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_move_assign)
@@ -707,8 +793,7 @@ namespace __variant
using _Base = _Move_assign_alias<_Types...>;
constexpr
- _Variant_base()
- noexcept(_Traits<_Types...>::_S_nothrow_default_ctor)
+ _Variant_base() noexcept(_Traits<_Types...>::_S_nothrow_default_ctor)
: _Variant_base(in_place_index<0>) { }
template<size_t _Np, typename... _Args>
@@ -1095,13 +1180,12 @@ namespace __variant
}
template<size_t _Np, typename _Variant, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
inline void
__construct_by_index(_Variant& __v, _Args&&... __args)
{
- auto&& __storage = __detail::__variant::__get<_Np>(__v);
- ::new ((void*)std::addressof(__storage))
- remove_reference_t<decltype(__storage)>
- (std::forward<_Args>(__args)...);
+ std::_Construct(std::__addressof(__variant::__get<_Np>(__v)),
+ std::forward<_Args>(__args)...);
// Construction didn't throw, so can set the new index now:
__v._M_index = _Np;
}
@@ -1285,6 +1369,7 @@ namespace __variant
visit(_Visitor&&, _Variants&&...);
template<typename... _Types>
+ _GLIBCXX20_CONSTEXPR
inline enable_if_t<(is_move_constructible_v<_Types> && ...)
&& (is_swappable_v<_Types> && ...)>
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
@@ -1342,9 +1427,11 @@ namespace __variant
{
private:
template <typename... _UTypes, typename _Tp>
- friend decltype(auto) __variant_cast(_Tp&&);
+ friend _GLIBCXX20_CONSTEXPR decltype(auto)
+ __variant_cast(_Tp&&);
+
template<size_t _Np, typename _Variant, typename... _Args>
- friend void
+ friend _GLIBCXX20_CONSTEXPR void
__detail::__variant::__construct_by_index(_Variant& __v,
_Args&&... __args);
@@ -1402,7 +1489,7 @@ namespace __variant
variant(variant&&) = default;
variant& operator=(const variant&) = default;
variant& operator=(variant&&) = default;
- ~variant() = default;
+ _GLIBCXX20_CONSTEXPR ~variant() = default;
template<typename _Tp,
typename = enable_if_t<sizeof...(_Types) != 0>,
@@ -1459,6 +1546,7 @@ namespace __variant
{ }
template<typename _Tp>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<__exactly_once<__accepted_type<_Tp&&>>
&& is_constructible_v<__accepted_type<_Tp&&>, _Tp>
&& is_assignable_v<__accepted_type<_Tp&&>&, _Tp>,
@@ -1483,6 +1571,7 @@ namespace __variant
}
template<typename _Tp, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<_Tp, _Args...> && __exactly_once<_Tp>,
_Tp&>
emplace(_Args&&... __args)
@@ -1492,6 +1581,7 @@ namespace __variant
}
template<typename _Tp, typename _Up, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
&& __exactly_once<_Tp>,
_Tp&>
@@ -1502,6 +1592,7 @@ namespace __variant
}
template<size_t _Np, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
_Args...>,
variant_alternative_t<_Np, variant>&>
@@ -1548,6 +1639,7 @@ namespace __variant
}
template<size_t _Np, typename _Up, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
initializer_list<_Up>&, _Args...>,
variant_alternative_t<_Np, variant>&>
@@ -1601,6 +1693,7 @@ namespace __variant
return size_t(__index_type(this->_M_index + 1)) - 1;
}
+ _GLIBCXX20_CONSTEXPR
void
swap(variant& __rhs)
noexcept((__is_nothrow_swappable<_Types>::value && ...)
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index a395c05db2d..0d7ae3bf857 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -173,7 +173,9 @@
# define __cpp_lib_to_chars 201611L
#endif
#define __cpp_lib_unordered_map_try_emplace 201411
-#define __cpp_lib_variant 202102L
+#if __cplusplus == 201703L || ! __cpp_concepts // N.B. updated value in C++20
+# define __cpp_lib_variant 202102L
+#endif
#endif
#if __cplusplus >= 202002L
@@ -280,6 +282,9 @@
# endif
#define __cpp_lib_to_address 201711L
#define __cpp_lib_to_array 201907L
+#if __cpp_concepts
+# define __cpp_lib_variant 202106L
+#endif
#endif
#if __cplusplus > 202002L
diff --git a/libstdc++-v3/testsuite/20_util/optional/version.cc b/libstdc++-v3/testsuite/20_util/optional/version.cc
index d8c9851f28f..c18ecb8d48d 100644
--- a/libstdc++-v3/testsuite/20_util/optional/version.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/version.cc
@@ -4,8 +4,8 @@
#ifndef __cpp_lib_optional
# error "Feature test macro for optional is missing in <version>"
-#elif __cpp_lib_optional < 201606L
-# error "Feature test macro for optional has wrong value in <version>"
+#elif __cplusplus == 201703L && __cpp_lib_optional != 201606L
+# error "Feature test macro for optional has wrong value for C++17 in <version>"
#elif __cplusplus >= 202002L && __cpp_lib_optional < 202106L
# error "Feature test macro for optional has wrong value for C++20 in <version>"
#endif
diff --git a/libstdc++-v3/testsuite/20_util/variant/87619.cc b/libstdc++-v3/testsuite/20_util/variant/87619.cc
index e83fa0306b6..c87851007f2 100644
--- a/libstdc++-v3/testsuite/20_util/variant/87619.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/87619.cc
@@ -16,6 +16,8 @@
// <http://www.gnu.org/licenses/>.
// { dg-do compile { target c++17 } }
+// FIXME: Need increased timeout due to PR c++/102780
+// { dg-timeout-factor 2 { target c++20 } }
#include <variant>
#include <utility>
diff --git a/libstdc++-v3/testsuite/20_util/variant/constexpr.cc b/libstdc++-v3/testsuite/20_util/variant/constexpr.cc
new file mode 100644
index 00000000000..7af3d98fe5d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/variant/constexpr.cc
@@ -0,0 +1,138 @@
+// { dg-options "-std=gnu++20" }
+// { dg-do compile { target c++20 } }
+
+#include <variant>
+
+// P2231R1 Missing constexpr in std::optional and std::variant
+
+#ifndef __cpp_lib_variant
+#error "Feature test macro for variant is missing in <variant>"
+#elif __cpp_lib_variant < 202106L
+# error "Feature test macro for variant has wrong value for C++20 in <variant>"
+#endif
+
+#include <testsuite_hooks.h>
+
+
+constexpr bool
+test_assign()
+{
+ std::variant<int, double> v1(1);
+ v1 = 2.5;
+ VERIFY( std::get<double>(v1) == 2.5 );
+
+ v1 = 99;
+ VERIFY( std::get<int>(v1) == 99 );
+ v1 = 999;
+ VERIFY( std::get<int>(v1) == 999 );
+
+ struct S // non-trivial special members
+ {
+ constexpr S(int i) : i(i) { }
+ constexpr ~S() { }
+ constexpr S(const S& s) : i(s.i) { }
+
+ int i;
+ };
+
+ std::variant<int, S> v;
+ v = S(123);
+ VERIFY( std::get<1>(v).i == 123 );
+
+ const S s(456);
+ v = s;
+ VERIFY( std::get<1>(v).i == 456 );
+
+ v = 789;
+ VERIFY( std::get<0>(v) == 789 );
+
+ return true;
+}
+
+static_assert( test_assign() );
+
+constexpr bool
+test_emplace()
+{
+ struct S // non-trivial special members
+ {
+ constexpr S(std::initializer_list<int> l) : i(l.begin()[0]) { }
+ constexpr S(std::initializer_list<int> l, int n) : i(l.begin()[n]) { }
+ constexpr ~S() { }
+ constexpr S(const S& s) : i(s.i) { }
+
+ int i;
+ };
+
+ std::variant<int, double, S> v(1);
+
+ // template<class T, class... Args> constexpr T& emplace(Args&&... args);
+ v.emplace<double>(2.0);
+ VERIFY( std::get<1>(v) == 2.0 );
+ v.emplace<double>(2.5);
+ VERIFY( std::get<1>(v) == 2.5 );
+ v.emplace<int>(2.5);
+ VERIFY( std::get<0>(v) == 2 );
+
+ // template<class T, class U, class... Args>
+ // constexpr T& emplace(initializer_list<U>, Args&&... args);
+ v.emplace<S>({3, 2, 1});
+ VERIFY( std::get<2>(v).i == 3 );
+ v.emplace<S>({3, 2, 1}, 1);
+ VERIFY( std::get<2>(v).i == 2 );
+
+ // template<size_t I, class... Args>
+ // constexpr variant_alternative_t<I, ...>& emplace(Args&&... args);
+ v.emplace<1>(3.0);
+ VERIFY( std::get<1>(v) == 3.0 );
+ v.emplace<1>(0.5);
+ VERIFY( std::get<1>(v) == 0.5 );
+ v.emplace<0>(1.5);
+ VERIFY( std::get<0>(v) == 1 );
+
+ // template<size_t I, class U, class... Args>
+ // constexpr variant_alternative_t<I, ...>&
+ // emplace(initializer_list<U>, Args&&... args);
+ v.emplace<2>({7, 8, 9});
+ VERIFY( std::get<2>(v).i == 7 );
+ v.emplace<2>({13, 12, 11}, 1);
+ VERIFY( std::get<2>(v).i == 12 );
+
+ return true;
+}
+
+static_assert( test_emplace() );
+
+constexpr bool
+test_swap()
+{
+ std::variant<int, double> v1(1), v2(2.5);
+ v1.swap(v2);
+ VERIFY( std::get<double>(v1) == 2.5 );
+ VERIFY( std::get<int>(v2) == 1 );
+
+ swap(v1, v2);
+ VERIFY( std::get<int>(v1) == 1 );
+ VERIFY( std::get<double>(v2) == 2.5 );
+
+ struct S
+ {
+ constexpr S(int i) : i(i) { }
+ constexpr S(S&& s) : i(s.i) { }
+ constexpr S& operator=(S&& s) { i = s.i; s.i = -1; return *this; }
+
+ int i;
+ };
+
+ std::variant<int, S> v3(3), v4(S(4));
+ v3.swap(v4);
+ VERIFY( std::get<S>(v3).i == 4 );
+ VERIFY( std::get<int>(v4) == 3 );
+ v3.swap(v4);
+ VERIFY( std::get<int>(v3) == 3 );
+ VERIFY( std::get<S>(v4).i == 4 );
+
+ return true;
+}
+
+static_assert( test_swap() );
diff --git a/libstdc++-v3/testsuite/20_util/variant/version.cc b/libstdc++-v3/testsuite/20_util/variant/version.cc
new file mode 100644
index 00000000000..de04c5eb294
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/variant/version.cc
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++17 } }
+
+#include <version>
+
+#ifndef __cpp_lib_variant
+#error "Feature test macro for variant is missing in <version>"
+#elif __cplusplus == 201703L && __cpp_lib_variant != 202102L
+# error "Feature test macro for variant has wrong value for C++17 in <version>"
+#elif __cplusplus >= 202002L && __cpp_lib_variant < 202106L
+# error "Feature test macro for variant has wrong value for C++20 in <version>"
+#endif
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2021-10-15 17:29 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-15 17:29 [committed] libstdc++: Add missing constexpr to std::variant (P2231R1) Jonathan Wakely
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).