[libcxx-commits] [libcxx] [libc++] Make `constexpr std::variant`. Implement P2231R1 (PR #83335)
via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Feb 28 14:02:58 PST 2024
https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/83335
>From 9ba67d9e23cb4a1002cd703d4c0f516ca8bded07 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Wed, 28 Feb 2024 21:06:51 +0000
Subject: [PATCH 1/2] [libc++] Make `constexpr std::variant`. Implement P2231R1
---
libcxx/include/variant | 93 ++++++++--------
.../variant.ctor/copy.pass.cpp | 90 ++++++++++------
.../variant.ctor/move.pass.cpp | 97 +++++++++++------
.../variant.dtor/dtor.pass.cpp | 71 ++++++++-----
.../variant.mod/emplace_index_args.pass.cpp | 93 ++++------------
.../emplace_index_init_list_args.pass.cpp | 26 +++--
.../variant.mod/emplace_type_args.pass.cpp | 100 +++++-------------
.../emplace_type_init_list_args.pass.cpp | 34 +++---
8 files changed, 299 insertions(+), 305 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 6063739e52c86b..895f2350449e65 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -42,7 +42,7 @@ namespace std {
in_place_index_t<I>, initializer_list<U>, Args&&...);
// 20.7.2.2, destructor
- ~variant();
+ constexpr ~variant(); // constexpr since c++20
// 20.7.2.3, assignment
constexpr variant& operator=(const variant&);
@@ -52,16 +52,16 @@ namespace std {
// 20.7.2.4, modifiers
template <class T, class... Args>
- T& emplace(Args&&...);
+ constexpr T& emplace(Args&&...); // constexpr since c++20
template <class T, class U, class... Args>
- T& emplace(initializer_list<U>, Args&&...);
+ constexpr T& emplace(initializer_list<U>, Args&&...); // constexpr since c++20
template <size_t I, class... Args>
- variant_alternative_t<I, variant>& emplace(Args&&...);
+ constexpr variant_alternative_t<I, variant>& emplace(Args&&...); // constexpr since c++20
template <size_t I, class U, class... Args>
- variant_alternative_t<I, variant>& emplace(initializer_list<U>, Args&&...);
+ constexpr variant_alternative_t<I, variant>& emplace(initializer_list<U>, Args&&...); // constexpr since c++20
// 20.7.2.5, value status
constexpr bool valueless_by_exception() const noexcept;
@@ -222,6 +222,7 @@ namespace std {
#include <__functional/operations.h>
#include <__functional/unary_function.h>
#include <__memory/addressof.h>
+#include <__memory/construct_at.h>
#include <__type_traits/add_const.h>
#include <__type_traits/add_cv.h>
#include <__type_traits/add_pointer.h>
@@ -655,7 +656,8 @@ private:
template <size_t _Index, class _Tp>
struct _LIBCPP_TEMPLATE_VIS __alt {
- using __value_type = _Tp;
+ using __value_type = _Tp;
+ static constexpr size_t __index = _Index;
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI explicit constexpr __alt(in_place_t, _Args&&... __args)
@@ -701,9 +703,9 @@ union _LIBCPP_TEMPLATE_VIS __union<_DestructibleTrait, _Index> {};
friend struct __access::__union; \
}
-_LIBCPP_VARIANT_UNION(_Trait::_TriviallyAvailable, ~__union() = default;);
-_LIBCPP_VARIANT_UNION(_Trait::_Available, ~__union(){});
-_LIBCPP_VARIANT_UNION(_Trait::_Unavailable, ~__union() = delete;);
+_LIBCPP_VARIANT_UNION(_Trait::_TriviallyAvailable, _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__union() = default;);
+_LIBCPP_VARIANT_UNION(_Trait::_Available, _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__union(){});
+_LIBCPP_VARIANT_UNION(_Trait::_Unavailable, _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__union() = delete;);
# undef _LIBCPP_VARIANT_UNION
@@ -767,13 +769,13 @@ class _LIBCPP_TEMPLATE_VIS __dtor;
}
_LIBCPP_VARIANT_DESTRUCTOR(
- _Trait::_TriviallyAvailable, ~__dtor() = default;
- , void __destroy() noexcept { this->__index = __variant_npos<__index_t>; });
+ _Trait::_TriviallyAvailable, _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__dtor() = default;
+ , _LIBCPP_CONSTEXPR_SINCE_CXX20 void __destroy() noexcept { this->__index = __variant_npos<__index_t>; });
_LIBCPP_VARIANT_DESTRUCTOR(
_Trait::_Available,
- ~__dtor() { __destroy(); },
- void __destroy() noexcept {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__dtor() { __destroy(); },
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __destroy() noexcept {
if (!this->valueless_by_exception()) {
__visitation::__base::__visit_alt(
[](auto& __alt) noexcept {
@@ -785,7 +787,8 @@ _LIBCPP_VARIANT_DESTRUCTOR(
this->__index = __variant_npos<__index_t>;
});
-_LIBCPP_VARIANT_DESTRUCTOR(_Trait::_Unavailable, ~__dtor() = delete;, void __destroy() noexcept = delete;);
+_LIBCPP_VARIANT_DESTRUCTOR(_Trait::_Unavailable, _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__dtor() = delete;
+ , _LIBCPP_CONSTEXPR_SINCE_CXX20 void __destroy() noexcept = delete;);
# undef _LIBCPP_VARIANT_DESTRUCTOR
@@ -798,23 +801,22 @@ public:
using __base_type::operator=;
protected:
- template <size_t _Ip, class _Tp, class... _Args>
- _LIBCPP_HIDE_FROM_ABI static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) {
- ::new ((void*)std::addressof(__a)) __alt<_Ip, _Tp>(in_place, std::forward<_Args>(__args)...);
- return __a.__value;
- }
-
template <class _Rhs>
- _LIBCPP_HIDE_FROM_ABI static void __generic_construct(__ctor& __lhs, _Rhs&& __rhs) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI static void __generic_construct(__ctor& __lhs, _Rhs&& __rhs) {
__lhs.__destroy();
if (!__rhs.valueless_by_exception()) {
+ // We cannot directly construct at the target __alt because its direct enclosing union is not activated yet.
+ // We will get error if we did:
+ // construction of subobject of member '__tail' of union with active member '__dummy' is not allowed in a constant
+ // expression
auto __rhs_index = __rhs.index();
__visitation::__base::__visit_alt_at(
__rhs_index,
- [](auto& __lhs_alt, auto&& __rhs_alt) {
- __construct_alt(__lhs_alt, std::forward<decltype(__rhs_alt)>(__rhs_alt).__value);
+ [&__lhs](auto&& __rhs_alt) {
+ std::__construct_at(std::addressof(__lhs.__data),
+ in_place_index<__decay_t<decltype(__rhs_alt)>::__index>,
+ std::forward<decltype(__rhs_alt)>(__rhs_alt).__value);
},
- __lhs,
std::forward<_Rhs>(__rhs));
__lhs.__index = __rhs_index;
}
@@ -840,15 +842,18 @@ class _LIBCPP_TEMPLATE_VIS __move_constructor;
__move_constructor& operator=(__move_constructor&&) = default; \
}
-_LIBCPP_VARIANT_MOVE_CONSTRUCTOR(_Trait::_TriviallyAvailable,
- __move_constructor(__move_constructor&& __that) = default;);
+_LIBCPP_VARIANT_MOVE_CONSTRUCTOR(
+ _Trait::_TriviallyAvailable,
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 __move_constructor(__move_constructor&& __that) = default;);
_LIBCPP_VARIANT_MOVE_CONSTRUCTOR(
_Trait::_Available,
- __move_constructor(__move_constructor&& __that) noexcept(__all<is_nothrow_move_constructible_v<_Types>...>::value)
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 __move_constructor(__move_constructor&& __that) noexcept(
+ __all<is_nothrow_move_constructible_v<_Types>...>::value)
: __move_constructor(__valueless_t{}) { this->__generic_construct(*this, std::move(__that)); });
-_LIBCPP_VARIANT_MOVE_CONSTRUCTOR(_Trait::_Unavailable, __move_constructor(__move_constructor&&) = delete;);
+_LIBCPP_VARIANT_MOVE_CONSTRUCTOR(_Trait::_Unavailable,
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 __move_constructor(__move_constructor&&) = delete;);
# undef _LIBCPP_VARIANT_MOVE_CONSTRUCTOR
@@ -871,14 +876,16 @@ class _LIBCPP_TEMPLATE_VIS __copy_constructor;
__copy_constructor& operator=(__copy_constructor&&) = default; \
}
-_LIBCPP_VARIANT_COPY_CONSTRUCTOR(_Trait::_TriviallyAvailable,
- __copy_constructor(const __copy_constructor& __that) = default;);
+_LIBCPP_VARIANT_COPY_CONSTRUCTOR(
+ _Trait::_TriviallyAvailable,
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 __copy_constructor(const __copy_constructor& __that) = default;);
_LIBCPP_VARIANT_COPY_CONSTRUCTOR(
- _Trait::_Available, __copy_constructor(const __copy_constructor& __that)
+ _Trait::_Available, _LIBCPP_CONSTEXPR_SINCE_CXX20 __copy_constructor(const __copy_constructor& __that)
: __copy_constructor(__valueless_t{}) { this->__generic_construct(*this, __that); });
-_LIBCPP_VARIANT_COPY_CONSTRUCTOR(_Trait::_Unavailable, __copy_constructor(const __copy_constructor&) = delete;);
+_LIBCPP_VARIANT_COPY_CONSTRUCTOR(_Trait::_Unavailable,
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 __copy_constructor(const __copy_constructor&) = delete;);
# undef _LIBCPP_VARIANT_COPY_CONSTRUCTOR
@@ -891,22 +898,24 @@ public:
using __base_type::operator=;
template <size_t _Ip, class... _Args>
- _LIBCPP_HIDE_FROM_ABI auto& __emplace(_Args&&... __args) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI auto& __emplace(_Args&&... __args) {
this->__destroy();
- auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), std::forward<_Args>(__args)...);
+ std::__construct_at(std::addressof(this->__data), in_place_index<_Ip>, std::forward<_Args>(__args)...);
this->__index = _Ip;
- return __res;
+ return __access::__base::__get_alt<_Ip>(*this).__value;
}
protected:
template <size_t _Ip, class _Tp, class _Arg>
- _LIBCPP_HIDE_FROM_ABI void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) {
if (this->index() == _Ip) {
__a.__value = std::forward<_Arg>(__arg);
} else {
struct {
- _LIBCPP_HIDE_FROM_ABI void operator()(true_type) const { __this->__emplace<_Ip>(std::forward<_Arg>(__arg)); }
- _LIBCPP_HIDE_FROM_ABI void operator()(false_type) const {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()(true_type) const {
+ __this->__emplace<_Ip>(std::forward<_Arg>(__arg));
+ }
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()(false_type) const {
__this->__emplace<_Ip>(_Tp(std::forward<_Arg>(__arg)));
}
__assignment* __this;
@@ -1248,7 +1257,7 @@ public:
enable_if_t<(_Ip < sizeof...(_Types)), int> = 0,
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _Tp& emplace(_Args&&... __args) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _Tp& emplace(_Args&&... __args) {
return __impl_.template __emplace<_Ip>(std::forward<_Args>(__args)...);
}
@@ -1258,7 +1267,7 @@ public:
enable_if_t<(_Ip < sizeof...(_Types)), int> = 0,
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
return __impl_.template __emplace<_Ip>(__il, std::forward<_Args>(__args)...);
}
@@ -1266,7 +1275,7 @@ public:
class... _Args,
size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _Tp& emplace(_Args&&... __args) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _Tp& emplace(_Args&&... __args) {
return __impl_.template __emplace<_Ip>(std::forward<_Args>(__args)...);
}
@@ -1275,7 +1284,7 @@ public:
class... _Args,
size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
return __impl_.template __emplace<_Ip>(__il, std::forward<_Args>(__args)...);
}
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
index d1e5768f58d2b1..34626a4e25f355 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
@@ -23,29 +23,29 @@
struct NonT {
NonT(int v) : value(v) {}
- NonT(const NonT &o) : value(o.value) {}
+ NonT(const NonT& o) : value(o.value) {}
int value;
};
static_assert(!std::is_trivially_copy_constructible<NonT>::value, "");
struct NoCopy {
- NoCopy(const NoCopy &) = delete;
+ NoCopy(const NoCopy&) = delete;
};
struct MoveOnly {
- MoveOnly(const MoveOnly &) = delete;
- MoveOnly(MoveOnly &&) = default;
+ MoveOnly(const MoveOnly&) = delete;
+ MoveOnly(MoveOnly&&) = default;
};
struct MoveOnlyNT {
- MoveOnlyNT(const MoveOnlyNT &) = delete;
- MoveOnlyNT(MoveOnlyNT &&) {}
+ MoveOnlyNT(const MoveOnlyNT&) = delete;
+ MoveOnlyNT(MoveOnlyNT&&) {}
};
struct NTCopy {
constexpr NTCopy(int v) : value(v) {}
- NTCopy(const NTCopy &that) : value(that.value) {}
- NTCopy(NTCopy &&) = delete;
+ NTCopy(const NTCopy& that) : value(that.value) {}
+ NTCopy(NTCopy&&) = delete;
int value;
};
@@ -54,8 +54,8 @@ static_assert(std::is_copy_constructible<NTCopy>::value, "");
struct TCopy {
constexpr TCopy(int v) : value(v) {}
- TCopy(TCopy const &) = default;
- TCopy(TCopy &&) = delete;
+ TCopy(TCopy const&) = default;
+ TCopy(TCopy&&) = delete;
int value;
};
@@ -74,20 +74,21 @@ static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "");
struct MakeEmptyT {
static int alive;
MakeEmptyT() { ++alive; }
- MakeEmptyT(const MakeEmptyT &) {
+ MakeEmptyT(const MakeEmptyT&) {
++alive;
// Don't throw from the copy constructor since variant's assignment
// operator performs a copy before committing to the assignment.
}
- MakeEmptyT(MakeEmptyT &&) { throw 42; }
- MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
- MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
+ MakeEmptyT(MakeEmptyT&&) { throw 42; }
+ MakeEmptyT& operator=(const MakeEmptyT&) { throw 42; }
+ MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }
~MakeEmptyT() { --alive; }
};
int MakeEmptyT::alive = 0;
-template <class Variant> void makeEmpty(Variant &v) {
+template <class Variant>
+void makeEmpty(Variant& v) {
Variant v2(std::in_place_type<MakeEmptyT>);
try {
v = std::move(v2);
@@ -214,35 +215,58 @@ void test_copy_ctor_valueless_by_exception() {
using V = std::variant<int, MakeEmptyT>;
V v1;
makeEmpty(v1);
- const V &cv1 = v1;
+ const V& cv1 = v1;
V v(cv1);
assert(v.valueless_by_exception());
#endif // TEST_HAS_NO_EXCEPTIONS
}
-template <std::size_t Idx>
-constexpr bool test_constexpr_copy_ctor_imp(std::variant<long, void*, const int> const& v) {
+template <std::size_t Idx, class T>
+constexpr bool test_constexpr_copy_ctor_imp(const T& v) {
auto v2 = v;
- return v2.index() == v.index() &&
- v2.index() == Idx &&
- std::get<Idx>(v2) == std::get<Idx>(v);
+ return v2.index() == v.index() && v2.index() == Idx && std::get<Idx>(v2) == std::get<Idx>(v);
}
+#if TEST_STD_VER >= 20
+struct NonTrivialCopyCtor {
+ int i = 0;
+ constexpr NonTrivialCopyCtor(int ii) : i(ii) {}
+ constexpr NonTrivialCopyCtor(const NonTrivialCopyCtor& other) : i(other.i) {}
+ constexpr NonTrivialCopyCtor(NonTrivialCopyCtor&& other) = default;
+ constexpr ~NonTrivialCopyCtor() = default;
+ friend constexpr bool operator==(const NonTrivialCopyCtor&, const NonTrivialCopyCtor&) = default;
+};
+#endif
void test_constexpr_copy_ctor() {
- // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
- using V = std::variant<long, void*, const int>;
+ {
+ // Test is_trivially_copy_constructible
+ // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+ using V = std::variant<long, void*, const int>;
#ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
- static_assert(std::is_trivially_destructible<V>::value, "");
- static_assert(std::is_trivially_copy_constructible<V>::value, "");
- static_assert(std::is_trivially_move_constructible<V>::value, "");
- static_assert(!std::is_copy_assignable<V>::value, "");
- static_assert(!std::is_move_assignable<V>::value, "");
-#else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
- static_assert(std::is_trivially_copyable<V>::value, "");
+ static_assert(std::is_trivially_destructible<V>::value, "");
+ static_assert(std::is_trivially_copy_constructible<V>::value, "");
+ static_assert(std::is_trivially_move_constructible<V>::value, "");
+ static_assert(!std::is_copy_assignable<V>::value, "");
+ static_assert(!std::is_move_assignable<V>::value, "");
+#else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
+ static_assert(std::is_trivially_copyable<V>::value, "");
#endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
- static_assert(test_constexpr_copy_ctor_imp<0>(V(42l)), "");
- static_assert(test_constexpr_copy_ctor_imp<1>(V(nullptr)), "");
- static_assert(test_constexpr_copy_ctor_imp<2>(V(101)), "");
+ static_assert(std::is_trivially_copy_constructible<V>::value, "");
+ static_assert(test_constexpr_copy_ctor_imp<0>(V(42l)), "");
+ static_assert(test_constexpr_copy_ctor_imp<1>(V(nullptr)), "");
+ static_assert(test_constexpr_copy_ctor_imp<2>(V(101)), "");
+ }
+
+#if TEST_STD_VER >= 20
+ {
+ // Test !is_trivially_move_constructible
+ using V = std::variant<long, NonTrivialCopyCtor, void*>;
+ static_assert(!std::is_trivially_copy_constructible<V>::value, "");
+ static_assert(test_constexpr_copy_ctor_imp<0>(V(42l)), "");
+ static_assert(test_constexpr_copy_ctor_imp<1>(V(NonTrivialCopyCtor(5))), "");
+ static_assert(test_constexpr_copy_ctor_imp<2>(V(nullptr)), "");
+ }
+#endif
}
int main(int, char**) {
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
index e2518fe29caf7e..4bb6cf24b0f0e2 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
@@ -23,31 +23,31 @@
#include "test_workarounds.h"
struct ThrowsMove {
- ThrowsMove(ThrowsMove &&) noexcept(false) {}
+ ThrowsMove(ThrowsMove&&) noexcept(false) {}
};
struct NoCopy {
- NoCopy(const NoCopy &) = delete;
+ NoCopy(const NoCopy&) = delete;
};
struct MoveOnly {
int value;
MoveOnly(int v) : value(v) {}
- MoveOnly(const MoveOnly &) = delete;
- MoveOnly(MoveOnly &&) = default;
+ MoveOnly(const MoveOnly&) = delete;
+ MoveOnly(MoveOnly&&) = default;
};
struct MoveOnlyNT {
int value;
MoveOnlyNT(int v) : value(v) {}
- MoveOnlyNT(const MoveOnlyNT &) = delete;
- MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; }
+ MoveOnlyNT(const MoveOnlyNT&) = delete;
+ MoveOnlyNT(MoveOnlyNT&& other) : value(other.value) { other.value = -1; }
};
struct NTMove {
constexpr NTMove(int v) : value(v) {}
- NTMove(const NTMove &) = delete;
- NTMove(NTMove &&that) : value(that.value) { that.value = -1; }
+ NTMove(const NTMove&) = delete;
+ NTMove(NTMove&& that) : value(that.value) { that.value = -1; }
int value;
};
@@ -56,8 +56,8 @@ static_assert(std::is_move_constructible<NTMove>::value, "");
struct TMove {
constexpr TMove(int v) : value(v) {}
- TMove(const TMove &) = delete;
- TMove(TMove &&) = default;
+ TMove(const TMove&) = delete;
+ TMove(TMove&&) = default;
int value;
};
@@ -76,20 +76,21 @@ static_assert(std::is_trivially_move_constructible<TMoveNTCopy>::value, "");
struct MakeEmptyT {
static int alive;
MakeEmptyT() { ++alive; }
- MakeEmptyT(const MakeEmptyT &) {
+ MakeEmptyT(const MakeEmptyT&) {
++alive;
// Don't throw from the copy constructor since variant's assignment
// operator performs a copy before committing to the assignment.
}
- MakeEmptyT(MakeEmptyT &&) { throw 42; }
- MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
- MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
+ MakeEmptyT(MakeEmptyT&&) { throw 42; }
+ MakeEmptyT& operator=(const MakeEmptyT&) { throw 42; }
+ MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }
~MakeEmptyT() { --alive; }
};
int MakeEmptyT::alive = 0;
-template <class Variant> void makeEmpty(Variant &v) {
+template <class Variant>
+void makeEmpty(Variant& v) {
Variant v2(std::in_place_type<MakeEmptyT>);
try {
v = std::move(v2);
@@ -158,7 +159,10 @@ void test_move_ctor_sfinae() {
}
template <typename T>
-struct Result { std::size_t index; T value; };
+struct Result {
+ std::size_t index;
+ T value;
+};
void test_move_ctor_basic() {
{
@@ -289,31 +293,54 @@ void test_move_ctor_valueless_by_exception() {
#endif // TEST_HAS_NO_EXCEPTIONS
}
-template <std::size_t Idx>
-constexpr bool test_constexpr_ctor_imp(std::variant<long, void*, const int> const& v) {
+template <std::size_t Idx, class T>
+constexpr bool test_constexpr_ctor_imp(const T& v) {
auto copy = v;
- auto v2 = std::move(copy);
- return v2.index() == v.index() &&
- v2.index() == Idx &&
- std::get<Idx>(v2) == std::get<Idx>(v);
+ auto v2 = std::move(copy);
+ return v2.index() == v.index() && v2.index() == Idx && std::get<Idx>(v2) == std::get<Idx>(v);
}
+#if TEST_STD_VER >= 20
+struct NonTrivialMoveCtor {
+ int i = 0;
+ constexpr NonTrivialMoveCtor(int ii) : i(ii) {}
+ constexpr NonTrivialMoveCtor(const NonTrivialMoveCtor& other) = default;
+ constexpr NonTrivialMoveCtor(NonTrivialMoveCtor&& other) : i(other.i) {}
+ constexpr ~NonTrivialMoveCtor() = default;
+ friend constexpr bool operator==(const NonTrivialMoveCtor&, const NonTrivialMoveCtor&) = default;
+};
+#endif
+
void test_constexpr_move_ctor() {
- // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
- using V = std::variant<long, void*, const int>;
+ {
+ // Test is_trivially_move_constructible
+ // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+ using V = std::variant<long, void*, const int>;
#ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
- static_assert(std::is_trivially_destructible<V>::value, "");
- static_assert(std::is_trivially_copy_constructible<V>::value, "");
- static_assert(std::is_trivially_move_constructible<V>::value, "");
- static_assert(!std::is_copy_assignable<V>::value, "");
- static_assert(!std::is_move_assignable<V>::value, "");
-#else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
- static_assert(std::is_trivially_copyable<V>::value, "");
+ static_assert(std::is_trivially_destructible<V>::value, "");
+ static_assert(std::is_trivially_copy_constructible<V>::value, "");
+ static_assert(std::is_trivially_move_constructible<V>::value, "");
+ static_assert(!std::is_copy_assignable<V>::value, "");
+ static_assert(!std::is_move_assignable<V>::value, "");
+#else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
+ static_assert(std::is_trivially_copyable<V>::value, "");
#endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE
- static_assert(std::is_trivially_move_constructible<V>::value, "");
- static_assert(test_constexpr_ctor_imp<0>(V(42l)), "");
- static_assert(test_constexpr_ctor_imp<1>(V(nullptr)), "");
- static_assert(test_constexpr_ctor_imp<2>(V(101)), "");
+ static_assert(std::is_trivially_move_constructible<V>::value, "");
+ static_assert(test_constexpr_ctor_imp<0>(V(42l)), "");
+ static_assert(test_constexpr_ctor_imp<1>(V(nullptr)), "");
+ static_assert(test_constexpr_ctor_imp<2>(V(101)), "");
+ }
+
+#if TEST_STD_VER >= 20
+ {
+ // Test !is_trivially_move_constructible
+ using V = std::variant<long, NonTrivialMoveCtor, void*>;
+ static_assert(!std::is_trivially_move_constructible<V>::value, "");
+ static_assert(test_constexpr_ctor_imp<0>(V(42l)), "");
+ static_assert(test_constexpr_ctor_imp<1>(V(NonTrivialMoveCtor(5))), "");
+ static_assert(test_constexpr_ctor_imp<2>(V(nullptr)), "");
+ }
+#endif
}
int main(int, char**) {
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp
index 2e026038c97a3c..53c5283b2edc6f 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.dtor/dtor.pass.cpp
@@ -21,55 +21,76 @@
#include "test_macros.h"
struct NonTDtor {
- static int count;
- NonTDtor() = default;
- ~NonTDtor() { ++count; }
+ int* count;
+ constexpr NonTDtor(int* a, int*) : count(a) {}
+ TEST_CONSTEXPR_CXX20 ~NonTDtor() { ++*count; }
};
-int NonTDtor::count = 0;
static_assert(!std::is_trivially_destructible<NonTDtor>::value, "");
struct NonTDtor1 {
- static int count;
- NonTDtor1() = default;
- ~NonTDtor1() { ++count; }
+ int* count;
+ constexpr NonTDtor1(int*, int* b) : count(b) {}
+ TEST_CONSTEXPR_CXX20 ~NonTDtor1() { ++*count; }
};
-int NonTDtor1::count = 0;
static_assert(!std::is_trivially_destructible<NonTDtor1>::value, "");
struct TDtor {
- TDtor(const TDtor &) {} // non-trivial copy
- ~TDtor() = default;
+ constexpr TDtor() = default;
+ constexpr TDtor(const TDtor&) {} // non-trivial copy
+ TEST_CONSTEXPR_CXX20 ~TDtor() = default;
};
static_assert(!std::is_trivially_copy_constructible<TDtor>::value, "");
static_assert(std::is_trivially_destructible<TDtor>::value, "");
-int main(int, char**) {
+TEST_CONSTEXPR_CXX20 bool test() {
{
using V = std::variant<int, long, TDtor>;
static_assert(std::is_trivially_destructible<V>::value, "");
+ [[maybe_unused]] V v(std::in_place_index<2>);
}
{
using V = std::variant<NonTDtor, int, NonTDtor1>;
static_assert(!std::is_trivially_destructible<V>::value, "");
{
- V v(std::in_place_index<0>);
- assert(NonTDtor::count == 0);
- assert(NonTDtor1::count == 0);
+ int count0 = 0;
+ int count1 = 0;
+ {
+ V v(std::in_place_index<0>, &count0, &count1);
+ assert(count0 == 0);
+ assert(count1 == 0);
+ }
+ assert(count0 == 1);
+ assert(count1 == 0);
+ }
+ {
+ int count0 = 0;
+ int count1 = 0;
+ { V v(std::in_place_index<1>); }
+ assert(count0 == 0);
+ assert(count1 == 0);
}
- assert(NonTDtor::count == 1);
- assert(NonTDtor1::count == 0);
- NonTDtor::count = 0;
- { V v(std::in_place_index<1>); }
- assert(NonTDtor::count == 0);
- assert(NonTDtor1::count == 0);
{
- V v(std::in_place_index<2>);
- assert(NonTDtor::count == 0);
- assert(NonTDtor1::count == 0);
+ int count0 = 0;
+ int count1 = 0;
+ {
+ V v(std::in_place_index<2>, &count0, &count1);
+ assert(count0 == 0);
+ assert(count1 == 0);
+ }
+ assert(count0 == 0);
+ assert(count1 == 1);
}
- assert(NonTDtor::count == 0);
- assert(NonTDtor1::count == 1);
}
+ return true;
+}
+
+int main(int, char**) {
+ test();
+
+#if TEST_STD_VER >= 20
+ static_assert(test());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp
index 96fcd7e7bee481..36c78d1b22bd0c 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_args.pass.cpp
@@ -26,8 +26,8 @@
#include "variant_test_helpers.h"
template <class Var, std::size_t I, class... Args>
-constexpr auto test_emplace_exists_imp(int) -> decltype(
- std::declval<Var>().template emplace<I>(std::declval<Args>()...), true) {
+constexpr auto test_emplace_exists_imp(int)
+ -> decltype(std::declval<Var>().template emplace<I>(std::declval<Args>()...), true) {
return true;
}
@@ -36,51 +36,32 @@ constexpr auto test_emplace_exists_imp(long) -> bool {
return false;
}
-template <class Var, std::size_t I, class... Args> constexpr bool emplace_exists() {
+template <class Var, std::size_t I, class... Args>
+constexpr bool emplace_exists() {
return test_emplace_exists_imp<Var, I, Args...>(0);
}
void test_emplace_sfinae() {
{
- using V = std::variant<int, void *, const void *, TestTypes::NoCtors>;
+ using V = std::variant<int, void*, const void*, TestTypes::NoCtors>;
static_assert(emplace_exists<V, 0>(), "");
static_assert(emplace_exists<V, 0, int>(), "");
- static_assert(!emplace_exists<V, 0, decltype(nullptr)>(),
- "cannot construct");
+ static_assert(!emplace_exists<V, 0, decltype(nullptr)>(), "cannot construct");
static_assert(emplace_exists<V, 1, decltype(nullptr)>(), "");
- static_assert(emplace_exists<V, 1, int *>(), "");
- static_assert(!emplace_exists<V, 1, const int *>(), "");
+ static_assert(emplace_exists<V, 1, int*>(), "");
+ static_assert(!emplace_exists<V, 1, const int*>(), "");
static_assert(!emplace_exists<V, 1, int>(), "cannot construct");
- static_assert(emplace_exists<V, 2, const int *>(), "");
- static_assert(emplace_exists<V, 2, int *>(), "");
+ static_assert(emplace_exists<V, 2, const int*>(), "");
+ static_assert(emplace_exists<V, 2, int*>(), "");
static_assert(!emplace_exists<V, 3>(), "cannot construct");
}
-#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
- {
- using V = std::variant<int, int &, const int &, int &&, TestTypes::NoCtors>;
- static_assert(emplace_exists<V, 0>(), "");
- static_assert(emplace_exists<V, 0, int>(), "");
- static_assert(emplace_exists<V, 0, long long>(), "");
- static_assert(!emplace_exists<V, 0, int, int>(), "too many args");
- static_assert(emplace_exists<V, 1, int &>(), "");
- static_assert(!emplace_exists<V, 1>(), "cannot default construct ref");
- static_assert(!emplace_exists<V, 1, const int &>(), "cannot bind ref");
- static_assert(!emplace_exists<V, 1, int &&>(), "cannot bind ref");
- static_assert(emplace_exists<V, 2, int &>(), "");
- static_assert(emplace_exists<V, 2, const int &>(), "");
- static_assert(emplace_exists<V, 2, int &&>(), "");
- static_assert(!emplace_exists<V, 2, void *>(),
- "not constructible from void*");
- static_assert(emplace_exists<V, 3, int>(), "");
- static_assert(!emplace_exists<V, 3, int &>(), "cannot bind ref");
- static_assert(!emplace_exists<V, 3, const int &>(), "cannot bind ref");
- static_assert(!emplace_exists<V, 3, const int &&>(), "cannot bind ref");
- static_assert(!emplace_exists<V, 4>(), "no ctors");
- }
-#endif
}
-void test_basic() {
+struct NoCtor {
+ NoCtor() = delete;
+};
+
+TEST_CONSTEXPR_CXX20 bool test_basic() {
{
using V = std::variant<int>;
V v(42);
@@ -93,9 +74,9 @@ void test_basic() {
assert(std::get<0>(v) == 42);
assert(&ref2 == &std::get<0>(v));
}
+
{
- using V =
- std::variant<int, long, const void *, TestTypes::NoCtors, std::string>;
+ using V = std::variant<int, long, const void*, NoCtor, std::string>;
const int x = 100;
V v(std::in_place_index<0>, -1);
// default emplace a value
@@ -113,45 +94,15 @@ void test_basic() {
assert(std::get<4>(v) == "aaa");
assert(&ref3 == &std::get<4>(v));
}
-#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
- {
- using V = std::variant<int, long, const int &, int &&, TestTypes::NoCtors,
- std::string>;
- const int x = 100;
- int y = 42;
- int z = 43;
- V v(std::in_place_index<0>, -1);
- // default emplace a value
- auto& ref1 = v.emplace<1>();
- static_assert(std::is_same_v<long&, decltype(ref1)>, "");
- assert(std::get<1>(v) == 0);
- assert(&ref1 == &std::get<1>(v));
- // emplace a reference
- auto& ref2 = v.emplace<2>(x);
- static_assert(std::is_same_v<&, decltype(ref)>, "");
- assert(&std::get<2>(v) == &x);
- assert(&ref2 == &std::get<2>(v));
- // emplace an rvalue reference
- auto& ref3 = v.emplace<3>(std::move(y));
- static_assert(std::is_same_v<&, decltype(ref)>, "");
- assert(&std::get<3>(v) == &y);
- assert(&ref3 == &std::get<3>(v));
- // re-emplace a new reference over the active member
- auto& ref4 = v.emplace<3>(std::move(z));
- static_assert(std::is_same_v<&, decltype(ref)>, "");
- assert(&std::get<3>(v) == &z);
- assert(&ref4 == &std::get<3>(v));
- // emplace with multiple args
- auto& ref5 = v.emplace<5>(3u, 'a');
- static_assert(std::is_same_v<std::string&, decltype(ref5)>, "");
- assert(std::get<5>(v) == "aaa");
- assert(&ref5 == &std::get<5>(v));
- }
-#endif
+
+ return true;
}
int main(int, char**) {
test_basic();
+#if TEST_STD_VER >= 20
+ static_assert(test_basic());
+#endif
test_emplace_sfinae();
return 0;
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp
index 9068aacc435928..0bf279f41a8e52 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_index_init_list_args.pass.cpp
@@ -32,13 +32,12 @@ struct InitList {
struct InitListArg {
std::size_t size;
int value;
- constexpr InitListArg(std::initializer_list<int> il, int v)
- : size(il.size()), value(v) {}
+ constexpr InitListArg(std::initializer_list<int> il, int v) : size(il.size()), value(v) {}
};
template <class Var, std::size_t I, class... Args>
-constexpr auto test_emplace_exists_imp(int) -> decltype(
- std::declval<Var>().template emplace<I>(std::declval<Args>()...), true) {
+constexpr auto test_emplace_exists_imp(int)
+ -> decltype(std::declval<Var>().template emplace<I>(std::declval<Args>()...), true) {
return true;
}
@@ -47,13 +46,13 @@ constexpr auto test_emplace_exists_imp(long) -> bool {
return false;
}
-template <class Var, std::size_t I, class... Args> constexpr bool emplace_exists() {
+template <class Var, std::size_t I, class... Args>
+constexpr bool emplace_exists() {
return test_emplace_exists_imp<Var, I, Args...>(0);
}
void test_emplace_sfinae() {
- using V =
- std::variant<int, TestTypes::NoCtors, InitList, InitListArg, long, long>;
+ using V = std::variant<int, TestTypes::NoCtors, InitList, InitListArg, long, long>;
using IL = std::initializer_list<int>;
static_assert(!emplace_exists<V, 1, IL>(), "no such constructor");
static_assert(emplace_exists<V, 2, IL>(), "");
@@ -65,8 +64,12 @@ void test_emplace_sfinae() {
static_assert(!emplace_exists<V, 3, IL, int, int>(), "too many args");
}
-void test_basic() {
- using V = std::variant<int, InitList, InitListArg, TestTypes::NoCtors>;
+struct NoCtor {
+ NoCtor() = delete;
+};
+
+TEST_CONSTEXPR_CXX20 bool test_basic() {
+ using V = std::variant<int, InitList, InitListArg, NoCtor>;
V v;
auto& ref1 = v.emplace<1>({1, 2, 3});
static_assert(std::is_same_v<InitList&, decltype(ref1)>, "");
@@ -81,10 +84,15 @@ void test_basic() {
static_assert(std::is_same_v<InitList&, decltype(ref3)>, "");
assert(std::get<1>(v).size == 1);
assert(&ref3 == &std::get<1>(v));
+
+ return true;
}
int main(int, char**) {
test_basic();
+#if TEST_STD_VER >= 20
+ static_assert(test_basic());
+#endif
test_emplace_sfinae();
return 0;
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp
index 24305aa0a35dae..7712a8149aa116 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_args.pass.cpp
@@ -25,8 +25,8 @@
#include "variant_test_helpers.h"
template <class Var, class T, class... Args>
-constexpr auto test_emplace_exists_imp(int) -> decltype(
- std::declval<Var>().template emplace<T>(std::declval<Args>()...), true) {
+constexpr auto test_emplace_exists_imp(int)
+ -> decltype(std::declval<Var>().template emplace<T>(std::declval<Args>()...), true) {
return true;
}
@@ -35,52 +35,32 @@ constexpr auto test_emplace_exists_imp(long) -> bool {
return false;
}
-template <class... Args> constexpr bool emplace_exists() {
+template <class... Args>
+constexpr bool emplace_exists() {
return test_emplace_exists_imp<Args...>(0);
}
void test_emplace_sfinae() {
{
- using V = std::variant<int, void *, const void *, TestTypes::NoCtors>;
+ using V = std::variant<int, void*, const void*, TestTypes::NoCtors>;
static_assert(emplace_exists<V, int>(), "");
static_assert(emplace_exists<V, int, int>(), "");
- static_assert(!emplace_exists<V, int, decltype(nullptr)>(),
- "cannot construct");
- static_assert(emplace_exists<V, void *, decltype(nullptr)>(), "");
- static_assert(!emplace_exists<V, void *, int>(), "cannot construct");
- static_assert(emplace_exists<V, void *, int *>(), "");
- static_assert(!emplace_exists<V, void *, const int *>(), "");
- static_assert(emplace_exists<V, const void *, const int *>(), "");
- static_assert(emplace_exists<V, const void *, int *>(), "");
+ static_assert(!emplace_exists<V, int, decltype(nullptr)>(), "cannot construct");
+ static_assert(emplace_exists<V, void*, decltype(nullptr)>(), "");
+ static_assert(!emplace_exists<V, void*, int>(), "cannot construct");
+ static_assert(emplace_exists<V, void*, int*>(), "");
+ static_assert(!emplace_exists<V, void*, const int*>(), "");
+ static_assert(emplace_exists<V, const void*, const int*>(), "");
+ static_assert(emplace_exists<V, const void*, int*>(), "");
static_assert(!emplace_exists<V, TestTypes::NoCtors>(), "cannot construct");
}
-#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
- using V = std::variant<int, int &, const int &, int &&, long, long,
- TestTypes::NoCtors>;
- static_assert(emplace_exists<V, int>(), "");
- static_assert(emplace_exists<V, int, int>(), "");
- static_assert(emplace_exists<V, int, long long>(), "");
- static_assert(!emplace_exists<V, int, int, int>(), "too many args");
- static_assert(emplace_exists<V, int &, int &>(), "");
- static_assert(!emplace_exists<V, int &>(), "cannot default construct ref");
- static_assert(!emplace_exists<V, int &, const int &>(), "cannot bind ref");
- static_assert(!emplace_exists<V, int &, int &&>(), "cannot bind ref");
- static_assert(emplace_exists<V, const int &, int &>(), "");
- static_assert(emplace_exists<V, const int &, const int &>(), "");
- static_assert(emplace_exists<V, const int &, int &&>(), "");
- static_assert(!emplace_exists<V, const int &, void *>(),
- "not constructible from void*");
- static_assert(emplace_exists<V, int &&, int>(), "");
- static_assert(!emplace_exists<V, int &&, int &>(), "cannot bind ref");
- static_assert(!emplace_exists<V, int &&, const int &>(), "cannot bind ref");
- static_assert(!emplace_exists<V, int &&, const int &&>(), "cannot bind ref");
- static_assert(!emplace_exists<V, long, long>(), "ambiguous");
- static_assert(!emplace_exists<V, TestTypes::NoCtors>(),
- "cannot construct void");
-#endif
}
-void test_basic() {
+struct NoCtor {
+ NoCtor() = delete;
+};
+
+TEST_CONSTEXPR_CXX20 bool test_basic() {
{
using V = std::variant<int>;
V v(42);
@@ -94,8 +74,7 @@ void test_basic() {
assert(&ref2 == &std::get<0>(v));
}
{
- using V =
- std::variant<int, long, const void *, TestTypes::NoCtors, std::string>;
+ using V = std::variant<int, long, const void*, NoCtor, std::string>;
const int x = 100;
V v(std::in_place_type<int>, -1);
// default emplace a value
@@ -103,8 +82,8 @@ void test_basic() {
static_assert(std::is_same_v<long&, decltype(ref1)>, "");
assert(std::get<1>(v) == 0);
assert(&ref1 == &std::get<1>(v));
- auto& ref2 = v.emplace<const void *>(&x);
- static_assert(std::is_same_v<const void *&, decltype(ref2)>, "");
+ auto& ref2 = v.emplace<const void*>(&x);
+ static_assert(std::is_same_v<const void*&, decltype(ref2)>, "");
assert(std::get<2>(v) == &x);
assert(&ref2 == &std::get<2>(v));
// emplace with multiple args
@@ -113,45 +92,14 @@ void test_basic() {
assert(std::get<4>(v) == "aaa");
assert(&ref3 == &std::get<4>(v));
}
-#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
- {
- using V = std::variant<int, long, const int &, int &&, TestTypes::NoCtors,
- std::string>;
- const int x = 100;
- int y = 42;
- int z = 43;
- V v(std::in_place_index<0>, -1);
- // default emplace a value
- auto& ref1 = v.emplace<long>();
- static_assert(std::is_same_v<long&, decltype(ref1)>, "");
- assert(std::get<long>(v) == 0);
- assert(&ref1 == &std::get<long>(v));
- // emplace a reference
- auto& ref2 = v.emplace<const int &>(x);
- static_assert(std::is_same_v<const int&, decltype(ref2)>, "");
- assert(&std::get<const int &>(v) == &x);
- assert(&ref2 == &std::get<const int &>(v));
- // emplace an rvalue reference
- auto& ref3 = v.emplace<int &&>(std::move(y));
- static_assert(std::is_same_v<int &&, decltype(ref3)>, "");
- assert(&std::get<int &&>(v) == &y);
- assert(&ref3 == &std::get<int &&>(v));
- // re-emplace a new reference over the active member
- auto& ref4 = v.emplace<int &&>(std::move(z));
- static_assert(std::is_same_v<int &, decltype(ref4)>, "");
- assert(&std::get<int &&>(v) == &z);
- assert(&ref4 == &std::get<int &&>(v));
- // emplace with multiple args
- auto& ref5 = v.emplace<std::string>(3u, 'a');
- static_assert(std::is_same_v<std::string&, decltype(ref5)>, "");
- assert(std::get<std::string>(v) == "aaa");
- assert(&ref5 == &std::get<std::string>(v));
- }
-#endif
+ return true;
}
int main(int, char**) {
test_basic();
+#if TEST_STD_VER >= 20
+ static_assert(test_basic());
+#endif
test_emplace_sfinae();
return 0;
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp
index 74d834b9b34575..6cd862c7d8095b 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.mod/emplace_type_init_list_args.pass.cpp
@@ -32,13 +32,12 @@ struct InitList {
struct InitListArg {
std::size_t size;
int value;
- constexpr InitListArg(std::initializer_list<int> il, int v)
- : size(il.size()), value(v) {}
+ constexpr InitListArg(std::initializer_list<int> il, int v) : size(il.size()), value(v) {}
};
template <class Var, class T, class... Args>
-constexpr auto test_emplace_exists_imp(int) -> decltype(
- std::declval<Var>().template emplace<T>(std::declval<Args>()...), true) {
+constexpr auto test_emplace_exists_imp(int)
+ -> decltype(std::declval<Var>().template emplace<T>(std::declval<Args>()...), true) {
return true;
}
@@ -47,13 +46,13 @@ constexpr auto test_emplace_exists_imp(long) -> bool {
return false;
}
-template <class... Args> constexpr bool emplace_exists() {
+template <class... Args>
+constexpr bool emplace_exists() {
return test_emplace_exists_imp<Args...>(0);
}
void test_emplace_sfinae() {
- using V =
- std::variant<int, TestTypes::NoCtors, InitList, InitListArg, long, long>;
+ using V = std::variant<int, TestTypes::NoCtors, InitList, InitListArg, long, long>;
using IL = std::initializer_list<int>;
static_assert(emplace_exists<V, InitList, IL>(), "");
static_assert(!emplace_exists<V, InitList, int>(), "args don't match");
@@ -61,30 +60,37 @@ void test_emplace_sfinae() {
static_assert(emplace_exists<V, InitListArg, IL, int>(), "");
static_assert(!emplace_exists<V, InitListArg, int>(), "args don't match");
static_assert(!emplace_exists<V, InitListArg, IL>(), "too few args");
- static_assert(!emplace_exists<V, InitListArg, IL, int, int>(),
- "too many args");
+ static_assert(!emplace_exists<V, InitListArg, IL, int, int>(), "too many args");
}
-void test_basic() {
- using V = std::variant<int, InitList, InitListArg, TestTypes::NoCtors>;
+struct NoCtor {
+ NoCtor() = delete;
+};
+
+TEST_CONSTEXPR_CXX20 bool test_basic() {
+ using V = std::variant<int, InitList, InitListArg, NoCtor>;
V v;
auto& ref1 = v.emplace<InitList>({1, 2, 3});
- static_assert(std::is_same_v<InitList&,decltype(ref1)>, "");
+ static_assert(std::is_same_v<InitList&, decltype(ref1)>, "");
assert(std::get<InitList>(v).size == 3);
assert(&ref1 == &std::get<InitList>(v));
auto& ref2 = v.emplace<InitListArg>({1, 2, 3, 4}, 42);
- static_assert(std::is_same_v<InitListArg&,decltype(ref2)>, "");
+ static_assert(std::is_same_v<InitListArg&, decltype(ref2)>, "");
assert(std::get<InitListArg>(v).size == 4);
assert(std::get<InitListArg>(v).value == 42);
assert(&ref2 == &std::get<InitListArg>(v));
auto& ref3 = v.emplace<InitList>({1});
- static_assert(std::is_same_v<InitList&,decltype(ref3)>, "");
+ static_assert(std::is_same_v<InitList&, decltype(ref3)>, "");
assert(std::get<InitList>(v).size == 1);
assert(&ref3 == &std::get<InitList>(v));
+ return true;
}
int main(int, char**) {
test_basic();
+#if TEST_STD_VER >= 20
+ static_assert(test_basic());
+#endif
test_emplace_sfinae();
return 0;
>From 0c82ab4436223878a2eb5a5d37bab8ba15e00423 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Wed, 28 Feb 2024 22:02:47 +0000
Subject: [PATCH 2/2] assign
---
libcxx/include/variant | 35 +-
.../variant.variant/variant.assign/T.pass.cpp | 93 ++---
.../variant.assign/copy.pass.cpp | 367 ++++++++++--------
.../variant.assign/move.pass.cpp | 252 ++++++------
.../variant.ctor/copy.pass.cpp | 11 +-
.../variant.ctor/move.pass.cpp | 13 +-
6 files changed, 414 insertions(+), 357 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 895f2350449e65..dd0aa1fdeacb5c 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -926,7 +926,7 @@ protected:
}
template <class _That>
- _LIBCPP_HIDE_FROM_ABI void __generic_assign(_That&& __that) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __generic_assign(_That&& __that) {
if (this->valueless_by_exception() && __that.valueless_by_exception()) {
// do nothing.
} else if (__that.valueless_by_exception()) {
@@ -963,19 +963,21 @@ class _LIBCPP_TEMPLATE_VIS __move_assignment;
move_assignment \
}
-_LIBCPP_VARIANT_MOVE_ASSIGNMENT(_Trait::_TriviallyAvailable,
- __move_assignment& operator=(__move_assignment&& __that) = default;);
+_LIBCPP_VARIANT_MOVE_ASSIGNMENT(
+ _Trait::_TriviallyAvailable,
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 __move_assignment& operator=(__move_assignment&& __that) = default;);
_LIBCPP_VARIANT_MOVE_ASSIGNMENT(
_Trait::_Available,
- __move_assignment&
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 __move_assignment&
operator=(__move_assignment&& __that) noexcept(
__all<(is_nothrow_move_constructible_v<_Types> && is_nothrow_move_assignable_v<_Types>)...>::value) {
this->__generic_assign(std::move(__that));
return *this;
});
-_LIBCPP_VARIANT_MOVE_ASSIGNMENT(_Trait::_Unavailable, __move_assignment& operator=(__move_assignment&&) = delete;);
+_LIBCPP_VARIANT_MOVE_ASSIGNMENT(
+ _Trait::_Unavailable, _LIBCPP_CONSTEXPR_SINCE_CXX20 __move_assignment& operator=(__move_assignment&&) = delete;);
# undef _LIBCPP_VARIANT_MOVE_ASSIGNMENT
@@ -998,16 +1000,19 @@ class _LIBCPP_TEMPLATE_VIS __copy_assignment;
copy_assignment __copy_assignment& operator=(__copy_assignment&&) = default; \
}
-_LIBCPP_VARIANT_COPY_ASSIGNMENT(_Trait::_TriviallyAvailable,
- __copy_assignment& operator=(const __copy_assignment& __that) = default;);
+_LIBCPP_VARIANT_COPY_ASSIGNMENT(
+ _Trait::_TriviallyAvailable,
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 __copy_assignment& operator=(const __copy_assignment& __that) = default;);
_LIBCPP_VARIANT_COPY_ASSIGNMENT(
- _Trait::_Available, __copy_assignment& operator=(const __copy_assignment& __that) {
+ _Trait::_Available, _LIBCPP_CONSTEXPR_SINCE_CXX20 __copy_assignment& operator=(const __copy_assignment& __that) {
this->__generic_assign(__that);
return *this;
});
-_LIBCPP_VARIANT_COPY_ASSIGNMENT(_Trait::_Unavailable, __copy_assignment& operator=(const __copy_assignment&) = delete;);
+_LIBCPP_VARIANT_COPY_ASSIGNMENT(
+ _Trait::_Unavailable,
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 __copy_assignment& operator=(const __copy_assignment&) = delete;);
# undef _LIBCPP_VARIANT_COPY_ASSIGNMENT
@@ -1023,11 +1028,11 @@ public:
_LIBCPP_HIDE_FROM_ABI __impl& operator=(__impl&&) = default;
template <size_t _Ip, class _Arg>
- _LIBCPP_HIDE_FROM_ABI void __assign(_Arg&& __arg) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __assign(_Arg&& __arg) {
this->__assign_alt(__access::__base::__get_alt<_Ip>(*this), std::forward<_Arg>(__arg));
}
- inline _LIBCPP_HIDE_FROM_ABI void __swap(__impl& __that) {
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void __swap(__impl& __that) {
if (this->valueless_by_exception() && __that.valueless_by_exception()) {
// do nothing.
} else if (this->index() == __that.index()) {
@@ -1072,7 +1077,7 @@ public:
}
private:
- inline _LIBCPP_HIDE_FROM_ABI bool __move_nothrow() const {
+ constexpr inline _LIBCPP_HIDE_FROM_ABI bool __move_nothrow() const {
constexpr bool __results[] = {is_nothrow_move_constructible_v<_Types>...};
return this->valueless_by_exception() || __results[this->index()];
}
@@ -1236,7 +1241,7 @@ public:
_Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, initializer_list< _Up>&, _Args...>)
: __impl_(in_place_index<_Ip>, __il, std::forward<_Args>(__args)...) {}
- _LIBCPP_HIDE_FROM_ABI ~variant() = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr ~variant() = default;
_LIBCPP_HIDE_FROM_ABI constexpr variant& operator=(const variant&) = default;
_LIBCPP_HIDE_FROM_ABI constexpr variant& operator=(variant&&) = default;
@@ -1246,7 +1251,7 @@ public:
class _Tp = __variant_detail::__best_match_t<_Arg, _Types...>,
size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_assignable_v<_Tp&, _Arg> && is_constructible_v<_Tp, _Arg>, int> = 0>
- _LIBCPP_HIDE_FROM_ABI variant&
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI variant&
operator=(_Arg&& __arg) noexcept(is_nothrow_assignable_v<_Tp&, _Arg> && is_nothrow_constructible_v<_Tp, _Arg>) {
__impl_.template __assign<_Ip>(std::forward<_Arg>(__arg));
return *this;
@@ -1298,7 +1303,7 @@ public:
enable_if_t< __all<(__dependent_type<is_move_constructible<_Types>, _Dummy>::value &&
__dependent_type<is_swappable<_Types>, _Dummy>::value)...>::value,
int> = 0>
- _LIBCPP_HIDE_FROM_ABI void swap(variant& __that) noexcept(
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(variant& __that) noexcept(
__all<(is_nothrow_move_constructible_v<_Types> && is_nothrow_swappable_v<_Types>)...>::value) {
__impl_.__swap(__that.__impl_);
}
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
index b3fc2021a6b223..be9e38f893093c 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
@@ -33,17 +33,17 @@ struct Dummy {
struct ThrowsCtorT {
ThrowsCtorT(int) noexcept(false) {}
- ThrowsCtorT &operator=(int) noexcept { return *this; }
+ ThrowsCtorT& operator=(int) noexcept { return *this; }
};
struct ThrowsAssignT {
ThrowsAssignT(int) noexcept {}
- ThrowsAssignT &operator=(int) noexcept(false) { return *this; }
+ ThrowsAssignT& operator=(int) noexcept(false) { return *this; }
};
struct NoThrowT {
NoThrowT(int) noexcept {}
- NoThrowT &operator=(int) noexcept { return *this; }
+ NoThrowT& operator=(int) noexcept { return *this; }
};
} // namespace MetaHelpers
@@ -55,7 +55,7 @@ struct ThrowsCtorT {
int value;
ThrowsCtorT() : value(0) {}
ThrowsCtorT(int) noexcept(false) { throw 42; }
- ThrowsCtorT &operator=(int v) noexcept {
+ ThrowsCtorT& operator=(int v) noexcept {
value = v;
return *this;
}
@@ -64,9 +64,12 @@ struct ThrowsCtorT {
struct MoveCrashes {
int value;
MoveCrashes(int v = 0) noexcept : value{v} {}
- MoveCrashes(MoveCrashes &&) noexcept { assert(false); }
- MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; }
- MoveCrashes &operator=(int v) noexcept {
+ MoveCrashes(MoveCrashes&&) noexcept { assert(false); }
+ MoveCrashes& operator=(MoveCrashes&&) noexcept {
+ assert(false);
+ return *this;
+ }
+ MoveCrashes& operator=(int v) noexcept {
value = v;
return *this;
}
@@ -76,8 +79,8 @@ struct ThrowsCtorTandMove {
int value;
ThrowsCtorTandMove() : value(0) {}
ThrowsCtorTandMove(int) noexcept(false) { throw 42; }
- ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); }
- ThrowsCtorTandMove &operator=(int v) noexcept {
+ ThrowsCtorTandMove(ThrowsCtorTandMove&&) noexcept(false) { assert(false); }
+ ThrowsCtorTandMove& operator=(int v) noexcept {
value = v;
return *this;
}
@@ -87,14 +90,14 @@ struct ThrowsAssignT {
int value;
ThrowsAssignT() : value(0) {}
ThrowsAssignT(int v) noexcept : value(v) {}
- ThrowsAssignT &operator=(int) noexcept(false) { throw 42; }
+ ThrowsAssignT& operator=(int) noexcept(false) { throw 42; }
};
struct NoThrowT {
int value;
NoThrowT() : value(0) {}
NoThrowT(int v) noexcept : value(v) {}
- NoThrowT &operator=(int v) noexcept {
+ NoThrowT& operator=(int v) noexcept {
value = v;
return *this;
}
@@ -126,29 +129,25 @@ void test_T_assignment_sfinae() {
}
{
using V = std::variant<std::string, std::string>;
- static_assert(!std::is_assignable<V, const char *>::value, "ambiguous");
+ static_assert(!std::is_assignable<V, const char*>::value, "ambiguous");
}
{
- using V = std::variant<std::string, void *>;
+ using V = std::variant<std::string, void*>;
static_assert(!std::is_assignable<V, int>::value, "no matching operator=");
}
{
using V = std::variant<std::string, float>;
- static_assert(std::is_assignable<V, int>::value == VariantAllowsNarrowingConversions,
- "no matching operator=");
+ static_assert(std::is_assignable<V, int>::value == VariantAllowsNarrowingConversions, "no matching operator=");
}
{
using V = std::variant<std::unique_ptr<int>, bool>;
- static_assert(!std::is_assignable<V, std::unique_ptr<char>>::value,
- "no explicit bool in operator=");
+ static_assert(!std::is_assignable<V, std::unique_ptr<char>>::value, "no explicit bool in operator=");
struct X {
operator void*();
};
- static_assert(!std::is_assignable<V, X>::value,
- "no boolean conversion in operator=");
+ static_assert(!std::is_assignable<V, X>::value, "no boolean conversion in operator=");
#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
- static_assert(std::is_assignable<V, std::false_type>::value,
- "converted to bool in operator=");
+ static_assert(std::is_assignable<V, std::false_type>::value, "converted to bool in operator=");
#endif
}
{
@@ -157,22 +156,21 @@ void test_T_assignment_sfinae() {
operator X();
};
using V = std::variant<X>;
- static_assert(std::is_assignable<V, Y>::value,
- "regression on user-defined conversions in operator=");
+ static_assert(std::is_assignable<V, Y>::value, "regression on user-defined conversions in operator=");
}
#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
{
- using V = std::variant<int, int &&>;
+ using V = std::variant<int, int&&>;
static_assert(!std::is_assignable<V, int>::value, "ambiguous");
}
{
- using V = std::variant<int, const int &>;
+ using V = std::variant<int, const int&>;
static_assert(!std::is_assignable<V, int>::value, "ambiguous");
}
#endif // TEST_VARIANT_HAS_NO_REFERENCES
}
-void test_T_assignment_basic() {
+TEST_CONSTEXPR_CXX20 bool test_T_assignment_basic() {
{
std::variant<int> v(43);
v = 42;
@@ -201,35 +199,18 @@ void test_T_assignment_basic() {
#endif
{
std::variant<std::string, bool> v = true;
- v = "bar";
+ v = "bar";
assert(v.index() == 0);
assert(std::get<0>(v) == "bar");
}
- {
- std::variant<bool, std::unique_ptr<int>> v;
- v = nullptr;
- assert(v.index() == 1);
- assert(std::get<1>(v) == nullptr);
- }
-#if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
- {
- using V = std::variant<int &, int &&, long>;
- int x = 42;
- V v(43l);
- v = x;
- assert(v.index() == 0);
- assert(&std::get<0>(v) == &x);
- v = std::move(x);
- assert(v.index() == 1);
- assert(&std::get<1>(v) == &x);
- // 'long' is selected by FUN(const int &) since 'const int &' cannot bind
- // to 'int&'.
- const int &cx = x;
- v = cx;
- assert(v.index() == 2);
- assert(std::get<2>(v) == 42);
- }
-#endif // TEST_VARIANT_HAS_NO_REFERENCES
+ return true;
+}
+
+void test_T_assignment_basic_no_constexpr() {
+ std::variant<bool, std::unique_ptr<int>> v;
+ v = nullptr;
+ assert(v.index() == 1);
+ assert(std::get<1>(v) == nullptr);
}
void test_T_assignment_performs_construction() {
@@ -298,7 +279,7 @@ void test_T_assignment_performs_assignment() {
#endif // TEST_HAS_NO_EXCEPTIONS
}
-void test_T_assignment_vector_bool() {
+TEST_CONSTEXPR_CXX20 bool test_T_assignment_vector_bool() {
#ifndef _LIBCPP_ENABLE_NARROWING_CONVERSIONS_IN_VARIANT
std::vector<bool> vec = {true};
std::variant<bool, int> v;
@@ -306,15 +287,21 @@ void test_T_assignment_vector_bool() {
assert(v.index() == 0);
assert(std::get<0>(v) == true);
#endif
+ return true;
}
int main(int, char**) {
test_T_assignment_basic();
+ test_T_assignment_basic_no_constexpr();
test_T_assignment_performs_construction();
test_T_assignment_performs_assignment();
test_T_assignment_noexcept();
test_T_assignment_sfinae();
test_T_assignment_vector_bool();
+#if TEST_STD_VER >= 20
+ static_assert(test_T_assignment_basic());
+ static_assert(test_T_assignment_vector_bool());
+#endif
return 0;
}
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
index 096d365d2d7525..5a5d077e8c4ba0 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
@@ -22,88 +22,108 @@
#include "test_macros.h"
struct NoCopy {
- NoCopy(const NoCopy &) = delete;
- NoCopy &operator=(const NoCopy &) = default;
+ NoCopy(const NoCopy&) = delete;
+ NoCopy& operator=(const NoCopy&) = default;
};
struct CopyOnly {
- CopyOnly(const CopyOnly &) = default;
- CopyOnly(CopyOnly &&) = delete;
- CopyOnly &operator=(const CopyOnly &) = default;
- CopyOnly &operator=(CopyOnly &&) = delete;
+ CopyOnly(const CopyOnly&) = default;
+ CopyOnly(CopyOnly&&) = delete;
+ CopyOnly& operator=(const CopyOnly&) = default;
+ CopyOnly& operator=(CopyOnly&&) = delete;
};
struct MoveOnly {
- MoveOnly(const MoveOnly &) = delete;
- MoveOnly(MoveOnly &&) = default;
- MoveOnly &operator=(const MoveOnly &) = default;
+ MoveOnly(const MoveOnly&) = delete;
+ MoveOnly(MoveOnly&&) = default;
+ MoveOnly& operator=(const MoveOnly&) = default;
};
struct MoveOnlyNT {
- MoveOnlyNT(const MoveOnlyNT &) = delete;
- MoveOnlyNT(MoveOnlyNT &&) {}
- MoveOnlyNT &operator=(const MoveOnlyNT &) = default;
+ MoveOnlyNT(const MoveOnlyNT&) = delete;
+ MoveOnlyNT(MoveOnlyNT&&) {}
+ MoveOnlyNT& operator=(const MoveOnlyNT&) = default;
};
struct CopyAssign {
- static int alive;
- static int copy_construct;
- static int copy_assign;
- static int move_construct;
- static int move_assign;
- static void reset() {
- copy_construct = copy_assign = move_construct = move_assign = alive = 0;
- }
- CopyAssign(int v) : value(v) { ++alive; }
- CopyAssign(const CopyAssign &o) : value(o.value) {
- ++alive;
- ++copy_construct;
- }
- CopyAssign(CopyAssign &&o) noexcept : value(o.value) {
+ constexpr CopyAssign(int v, int* alv, int* cpy_ctr, int* cpy_assi, int* move_ctr, int* move_assi)
+ : value(v),
+ alive(alv),
+ copy_construct(cpy_ctr),
+ copy_assign(cpy_assi),
+ move_construct(move_ctr),
+ move_assign(move_assi) {
+ ++*alive;
+ }
+ constexpr CopyAssign(const CopyAssign& o)
+ : value(o.value),
+ alive(o.alive),
+ copy_construct(o.copy_construct),
+ copy_assign(o.copy_assign),
+ move_construct(o.move_construct),
+ move_assign(o.move_assign) {
+ ++*alive;
+ ++*copy_construct;
+ }
+ constexpr CopyAssign(CopyAssign&& o) noexcept
+ : value(o.value),
+ alive(o.alive),
+ copy_construct(o.copy_construct),
+ copy_assign(o.copy_assign),
+ move_construct(o.move_construct),
+ move_assign(o.move_assign) {
o.value = -1;
- ++alive;
- ++move_construct;
- }
- CopyAssign &operator=(const CopyAssign &o) {
- value = o.value;
- ++copy_assign;
+ ++*alive;
+ ++*move_construct;
+ }
+ constexpr CopyAssign& operator=(const CopyAssign& o) {
+ value = o.value;
+ alive = o.alive;
+ copy_construct = o.copy_construct;
+ copy_assign = o.copy_assign;
+ move_construct = o.move_construct;
+ move_assign = o.move_assign;
+ ++*copy_assign;
return *this;
}
- CopyAssign &operator=(CopyAssign &&o) noexcept {
- value = o.value;
- o.value = -1;
- ++move_assign;
+ constexpr CopyAssign& operator=(CopyAssign&& o) noexcept {
+ value = o.value;
+ alive = o.alive;
+ copy_construct = o.copy_construct;
+ copy_assign = o.copy_assign;
+ move_construct = o.move_construct;
+ move_assign = o.move_assign;
+ o.value = -1;
+ ++*move_assign;
return *this;
}
- ~CopyAssign() { --alive; }
+ TEST_CONSTEXPR_CXX20 ~CopyAssign() { --*alive; }
int value;
+ int* alive;
+ int* copy_construct;
+ int* copy_assign;
+ int* move_construct;
+ int* move_assign;
};
-int CopyAssign::alive = 0;
-int CopyAssign::copy_construct = 0;
-int CopyAssign::copy_assign = 0;
-int CopyAssign::move_construct = 0;
-int CopyAssign::move_assign = 0;
-
struct CopyMaybeThrows {
- CopyMaybeThrows(const CopyMaybeThrows &);
- CopyMaybeThrows &operator=(const CopyMaybeThrows &);
+ CopyMaybeThrows(const CopyMaybeThrows&);
+ CopyMaybeThrows& operator=(const CopyMaybeThrows&);
};
struct CopyDoesThrow {
- CopyDoesThrow(const CopyDoesThrow &) noexcept(false);
- CopyDoesThrow &operator=(const CopyDoesThrow &) noexcept(false);
+ CopyDoesThrow(const CopyDoesThrow&) noexcept(false);
+ CopyDoesThrow& operator=(const CopyDoesThrow&) noexcept(false);
};
-
struct NTCopyAssign {
constexpr NTCopyAssign(int v) : value(v) {}
- NTCopyAssign(const NTCopyAssign &) = default;
- NTCopyAssign(NTCopyAssign &&) = default;
- NTCopyAssign &operator=(const NTCopyAssign &that) {
+ NTCopyAssign(const NTCopyAssign&) = default;
+ NTCopyAssign(NTCopyAssign&&) = default;
+ NTCopyAssign& operator=(const NTCopyAssign& that) {
value = that.value;
return *this;
};
- NTCopyAssign &operator=(NTCopyAssign &&) = delete;
+ NTCopyAssign& operator=(NTCopyAssign&&) = delete;
int value;
};
@@ -112,10 +132,10 @@ static_assert(std::is_copy_assignable<NTCopyAssign>::value, "");
struct TCopyAssign {
constexpr TCopyAssign(int v) : value(v) {}
- TCopyAssign(const TCopyAssign &) = default;
- TCopyAssign(TCopyAssign &&) = default;
- TCopyAssign &operator=(const TCopyAssign &) = default;
- TCopyAssign &operator=(TCopyAssign &&) = delete;
+ TCopyAssign(const TCopyAssign&) = default;
+ TCopyAssign(TCopyAssign&&) = default;
+ TCopyAssign& operator=(const TCopyAssign&) = default;
+ TCopyAssign& operator=(TCopyAssign&&) = delete;
int value;
};
@@ -123,11 +143,11 @@ static_assert(std::is_trivially_copy_assignable<TCopyAssign>::value, "");
struct TCopyAssignNTMoveAssign {
constexpr TCopyAssignNTMoveAssign(int v) : value(v) {}
- TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign &) = default;
- TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign &&) = default;
- TCopyAssignNTMoveAssign &operator=(const TCopyAssignNTMoveAssign &) = default;
- TCopyAssignNTMoveAssign &operator=(TCopyAssignNTMoveAssign &&that) {
- value = that.value;
+ TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign&) = default;
+ TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign&&) = default;
+ TCopyAssignNTMoveAssign& operator=(const TCopyAssignNTMoveAssign&) = default;
+ TCopyAssignNTMoveAssign& operator=(TCopyAssignNTMoveAssign&& that) {
+ value = that.value;
that.value = -1;
return *this;
}
@@ -139,17 +159,20 @@ static_assert(std::is_trivially_copy_assignable_v<TCopyAssignNTMoveAssign>, "");
#ifndef TEST_HAS_NO_EXCEPTIONS
struct CopyThrows {
CopyThrows() = default;
- CopyThrows(const CopyThrows &) { throw 42; }
- CopyThrows &operator=(const CopyThrows &) { throw 42; }
+ CopyThrows(const CopyThrows&) { throw 42; }
+ CopyThrows& operator=(const CopyThrows&) { throw 42; }
};
struct CopyCannotThrow {
static int alive;
CopyCannotThrow() { ++alive; }
- CopyCannotThrow(const CopyCannotThrow &) noexcept { ++alive; }
- CopyCannotThrow(CopyCannotThrow &&) noexcept { assert(false); }
- CopyCannotThrow &operator=(const CopyCannotThrow &) noexcept = default;
- CopyCannotThrow &operator=(CopyCannotThrow &&) noexcept { assert(false); return *this; }
+ CopyCannotThrow(const CopyCannotThrow&) noexcept { ++alive; }
+ CopyCannotThrow(CopyCannotThrow&&) noexcept { assert(false); }
+ CopyCannotThrow& operator=(const CopyCannotThrow&) noexcept = default;
+ CopyCannotThrow& operator=(CopyCannotThrow&&) noexcept {
+ assert(false);
+ return *this;
+ }
};
int CopyCannotThrow::alive = 0;
@@ -157,10 +180,10 @@ int CopyCannotThrow::alive = 0;
struct MoveThrows {
static int alive;
MoveThrows() { ++alive; }
- MoveThrows(const MoveThrows &) { ++alive; }
- MoveThrows(MoveThrows &&) { throw 42; }
- MoveThrows &operator=(const MoveThrows &) { return *this; }
- MoveThrows &operator=(MoveThrows &&) { throw 42; }
+ MoveThrows(const MoveThrows&) { ++alive; }
+ MoveThrows(MoveThrows&&) { throw 42; }
+ MoveThrows& operator=(const MoveThrows&) { return *this; }
+ MoveThrows& operator=(MoveThrows&&) { throw 42; }
~MoveThrows() { --alive; }
};
@@ -169,20 +192,21 @@ int MoveThrows::alive = 0;
struct MakeEmptyT {
static int alive;
MakeEmptyT() { ++alive; }
- MakeEmptyT(const MakeEmptyT &) {
+ MakeEmptyT(const MakeEmptyT&) {
++alive;
// Don't throw from the copy constructor since variant's assignment
// operator performs a copy before committing to the assignment.
}
- MakeEmptyT(MakeEmptyT &&) { throw 42; }
- MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
- MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
+ MakeEmptyT(MakeEmptyT&&) { throw 42; }
+ MakeEmptyT& operator=(const MakeEmptyT&) { throw 42; }
+ MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; }
~MakeEmptyT() { --alive; }
};
int MakeEmptyT::alive = 0;
-template <class Variant> void makeEmpty(Variant &v) {
+template <class Variant>
+void makeEmpty(Variant& v) {
Variant v2(std::in_place_type<MakeEmptyT>);
try {
v = std::move(v2);
@@ -259,7 +283,7 @@ void test_copy_assignment_empty_empty() {
makeEmpty(v1);
V v2(std::in_place_index<0>);
makeEmpty(v2);
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
@@ -275,7 +299,7 @@ void test_copy_assignment_non_empty_empty() {
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<0>);
makeEmpty(v2);
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
@@ -285,7 +309,7 @@ void test_copy_assignment_non_empty_empty() {
V v1(std::in_place_index<2>, "hello");
V v2(std::in_place_index<0>);
makeEmpty(v2);
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
@@ -301,7 +325,7 @@ void test_copy_assignment_empty_non_empty() {
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_index<0>, 42);
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 0);
assert(std::get<0>(v1) == 42);
@@ -311,7 +335,7 @@ void test_copy_assignment_empty_non_empty() {
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_type<std::string>, "hello");
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
@@ -319,14 +343,18 @@ void test_copy_assignment_empty_non_empty() {
#endif // TEST_HAS_NO_EXCEPTIONS
}
-template <typename T> struct Result { std::size_t index; T value; };
+template <typename T>
+struct Result {
+ std::size_t index;
+ T value;
+};
-void test_copy_assignment_same_index() {
+TEST_CONSTEXPR_CXX20 bool test_copy_assignment_same_index() {
{
using V = std::variant<int>;
V v1(43);
V v2(42);
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 0);
assert(std::get<0>(v1) == 42);
@@ -335,40 +363,28 @@ void test_copy_assignment_same_index() {
using V = std::variant<int, long, unsigned>;
V v1(43l);
V v2(42l);
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1) == 42);
}
{
- using V = std::variant<int, CopyAssign, unsigned>;
- V v1(std::in_place_type<CopyAssign>, 43);
- V v2(std::in_place_type<CopyAssign>, 42);
- CopyAssign::reset();
- V &vref = (v1 = v2);
+ using V = std::variant<int, CopyAssign, unsigned>;
+ int alive = 0;
+ int copy_construct = 0;
+ int copy_assign = 0;
+ int move_construct = 0;
+ int move_assign = 0;
+ V v1(std::in_place_type<CopyAssign>, 43, &alive, ©_construct, ©_assign, &move_construct, &move_assign);
+ V v2(std::in_place_type<CopyAssign>, 42, &alive, ©_construct, ©_assign, &move_construct, &move_assign);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1).value == 42);
- assert(CopyAssign::copy_construct == 0);
- assert(CopyAssign::move_construct == 0);
- assert(CopyAssign::copy_assign == 1);
- }
-#ifndef TEST_HAS_NO_EXCEPTIONS
- using MET = MakeEmptyT;
- {
- using V = std::variant<int, MET, std::string>;
- V v1(std::in_place_type<MET>);
- MET &mref = std::get<1>(v1);
- V v2(std::in_place_type<MET>);
- try {
- v1 = v2;
- assert(false);
- } catch (...) {
- }
- assert(v1.index() == 1);
- assert(&std::get<1>(v1) == &mref);
+ assert(copy_construct == 0);
+ assert(move_construct == 0);
+ assert(copy_assign == 1);
}
-#endif // TEST_HAS_NO_EXCEPTIONS
// Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
{
@@ -427,36 +443,93 @@ void test_copy_assignment_same_index() {
static_assert(result.index == 1, "");
static_assert(result.value == 42, "");
}
+
+ return true;
}
-void test_copy_assignment_different_index() {
+TEST_CONSTEXPR_CXX20 bool test_copy_assignment_different_index() {
{
using V = std::variant<int, long, unsigned>;
V v1(43);
V v2(42l);
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1) == 42);
}
{
- using V = std::variant<int, CopyAssign, unsigned>;
- CopyAssign::reset();
+ using V = std::variant<int, CopyAssign, unsigned>;
+ int alive = 0;
+ int copy_construct = 0;
+ int copy_assign = 0;
+ int move_construct = 0;
+ int move_assign = 0;
V v1(std::in_place_type<unsigned>, 43u);
- V v2(std::in_place_type<CopyAssign>, 42);
- assert(CopyAssign::copy_construct == 0);
- assert(CopyAssign::move_construct == 0);
- assert(CopyAssign::alive == 1);
- V &vref = (v1 = v2);
+ V v2(std::in_place_type<CopyAssign>, 42, &alive, ©_construct, ©_assign, &move_construct, &move_assign);
+ assert(copy_construct == 0);
+ assert(move_construct == 0);
+ assert(alive == 1);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1).value == 42);
- assert(CopyAssign::alive == 2);
- assert(CopyAssign::copy_construct == 1);
- assert(CopyAssign::move_construct == 1);
- assert(CopyAssign::copy_assign == 0);
+ assert(alive == 2);
+ assert(copy_construct == 1);
+ assert(move_construct == 1);
+ assert(copy_assign == 0);
+ }
+
+ // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+ {
+ struct {
+ constexpr Result<long> operator()() const {
+ using V = std::variant<int, long, unsigned>;
+ V v(43);
+ V v2(42l);
+ v = v2;
+ return {v.index(), std::get<1>(v)};
+ }
+ } test;
+ constexpr auto result = test();
+ static_assert(result.index == 1, "");
+ static_assert(result.value == 42l, "");
+ }
+ {
+ struct {
+ constexpr Result<int> operator()() const {
+ using V = std::variant<int, TCopyAssign, unsigned>;
+ V v(std::in_place_type<unsigned>, 43u);
+ V v2(std::in_place_type<TCopyAssign>, 42);
+ v = v2;
+ return {v.index(), std::get<1>(v).value};
+ }
+ } test;
+ constexpr auto result = test();
+ static_assert(result.index == 1, "");
+ static_assert(result.value == 42, "");
}
+ return true;
+}
+
+void test_assignment_throw() {
#ifndef TEST_HAS_NO_EXCEPTIONS
+ using MET = MakeEmptyT;
+ // same index
+ {
+ using V = std::variant<int, MET, std::string>;
+ V v1(std::in_place_type<MET>);
+ MET& mref = std::get<1>(v1);
+ V v2(std::in_place_type<MET>);
+ try {
+ v1 = v2;
+ assert(false);
+ } catch (...) {
+ }
+ assert(v1.index() == 1);
+ assert(&std::get<1>(v1) == &mref);
+ }
+
+ // difference indices
{
using V = std::variant<int, CopyThrows, std::string>;
V v1(std::in_place_type<std::string>, "hello");
@@ -496,7 +569,7 @@ void test_copy_assignment_different_index() {
using V = std::variant<int, CopyThrows, std::string>;
V v1(std::in_place_type<CopyThrows>);
V v2(std::in_place_type<std::string>, "hello");
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
@@ -507,7 +580,7 @@ void test_copy_assignment_different_index() {
using V = std::variant<int, MoveThrows, std::string>;
V v1(std::in_place_type<MoveThrows>);
V v2(std::in_place_type<std::string>, "hello");
- V &vref = (v1 = v2);
+ V& vref = (v1 = v2);
assert(&vref == &v1);
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
@@ -515,47 +588,13 @@ void test_copy_assignment_different_index() {
assert(std::get<2>(v2) == "hello");
}
#endif // TEST_HAS_NO_EXCEPTIONS
-
- // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
- {
- struct {
- constexpr Result<long> operator()() const {
- using V = std::variant<int, long, unsigned>;
- V v(43);
- V v2(42l);
- v = v2;
- return {v.index(), std::get<1>(v)};
- }
- } test;
- constexpr auto result = test();
- static_assert(result.index == 1, "");
- static_assert(result.value == 42l, "");
- }
- {
- struct {
- constexpr Result<int> operator()() const {
- using V = std::variant<int, TCopyAssign, unsigned>;
- V v(std::in_place_type<unsigned>, 43u);
- V v2(std::in_place_type<TCopyAssign>, 42);
- v = v2;
- return {v.index(), std::get<1>(v).value};
- }
- } test;
- constexpr auto result = test();
- static_assert(result.index == 1, "");
- static_assert(result.value == 42, "");
- }
}
template <std::size_t NewIdx, class ValueType>
-constexpr bool test_constexpr_assign_imp(
- std::variant<long, void*, int>&& v, ValueType&& new_value)
-{
- const std::variant<long, void*, int> cp(
- std::forward<ValueType>(new_value));
+constexpr bool test_constexpr_assign_imp(std::variant<long, void*, int>&& v, ValueType&& new_value) {
+ const std::variant<long, void*, int> cp(std::forward<ValueType>(new_value));
v = cp;
- return v.index() == NewIdx &&
- std::get<NewIdx>(v) == std::get<NewIdx>(cp);
+ return v.index() == NewIdx && std::get<NewIdx>(v) == std::get<NewIdx>(cp);
}
void test_constexpr_copy_assignment() {
@@ -573,11 +612,17 @@ int main(int, char**) {
test_copy_assignment_empty_empty();
test_copy_assignment_non_empty_empty();
test_copy_assignment_empty_non_empty();
+ test_assignment_throw();
test_copy_assignment_same_index();
test_copy_assignment_different_index();
test_copy_assignment_sfinae();
test_copy_assignment_not_noexcept();
test_constexpr_copy_assignment();
+#if TEST_STD_VER >= 20
+ static_assert(test_copy_assignment_same_index());
+ static_assert(test_copy_assignment_different_index());
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
index 84094347aed3a7..d743c0130a22f3 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
@@ -24,71 +24,70 @@
#include "variant_test_helpers.h"
struct NoCopy {
- NoCopy(const NoCopy &) = delete;
- NoCopy &operator=(const NoCopy &) = default;
+ NoCopy(const NoCopy&) = delete;
+ NoCopy& operator=(const NoCopy&) = default;
};
struct CopyOnly {
- CopyOnly(const CopyOnly &) = default;
- CopyOnly(CopyOnly &&) = delete;
- CopyOnly &operator=(const CopyOnly &) = default;
- CopyOnly &operator=(CopyOnly &&) = delete;
+ CopyOnly(const CopyOnly&) = default;
+ CopyOnly(CopyOnly&&) = delete;
+ CopyOnly& operator=(const CopyOnly&) = default;
+ CopyOnly& operator=(CopyOnly&&) = delete;
};
struct MoveOnly {
- MoveOnly(const MoveOnly &) = delete;
- MoveOnly(MoveOnly &&) = default;
- MoveOnly &operator=(const MoveOnly &) = delete;
- MoveOnly &operator=(MoveOnly &&) = default;
+ MoveOnly(const MoveOnly&) = delete;
+ MoveOnly(MoveOnly&&) = default;
+ MoveOnly& operator=(const MoveOnly&) = delete;
+ MoveOnly& operator=(MoveOnly&&) = default;
};
struct MoveOnlyNT {
- MoveOnlyNT(const MoveOnlyNT &) = delete;
- MoveOnlyNT(MoveOnlyNT &&) {}
- MoveOnlyNT &operator=(const MoveOnlyNT &) = delete;
- MoveOnlyNT &operator=(MoveOnlyNT &&) = default;
+ MoveOnlyNT(const MoveOnlyNT&) = delete;
+ MoveOnlyNT(MoveOnlyNT&&) {}
+ MoveOnlyNT& operator=(const MoveOnlyNT&) = delete;
+ MoveOnlyNT& operator=(MoveOnlyNT&&) = default;
};
struct MoveOnlyOddNothrow {
- MoveOnlyOddNothrow(MoveOnlyOddNothrow &&) noexcept(false) {}
- MoveOnlyOddNothrow(const MoveOnlyOddNothrow &) = delete;
- MoveOnlyOddNothrow &operator=(MoveOnlyOddNothrow &&) noexcept = default;
- MoveOnlyOddNothrow &operator=(const MoveOnlyOddNothrow &) = delete;
+ MoveOnlyOddNothrow(MoveOnlyOddNothrow&&) noexcept(false) {}
+ MoveOnlyOddNothrow(const MoveOnlyOddNothrow&) = delete;
+ MoveOnlyOddNothrow& operator=(MoveOnlyOddNothrow&&) noexcept = default;
+ MoveOnlyOddNothrow& operator=(const MoveOnlyOddNothrow&) = delete;
};
struct MoveAssignOnly {
- MoveAssignOnly(MoveAssignOnly &&) = delete;
- MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
+ MoveAssignOnly(MoveAssignOnly&&) = delete;
+ MoveAssignOnly& operator=(MoveAssignOnly&&) = default;
};
struct MoveAssign {
- static int move_construct;
- static int move_assign;
- static void reset() { move_construct = move_assign = 0; }
- MoveAssign(int v) : value(v) {}
- MoveAssign(MoveAssign &&o) : value(o.value) {
- ++move_construct;
+ constexpr MoveAssign(int v, int* move_ctor, int* move_assi)
+ : value(v), move_construct(move_ctor), move_assign(move_assi) {}
+ constexpr MoveAssign(MoveAssign&& o) : value(o.value), move_construct(o.move_construct), move_assign(o.move_assign) {
+ ++*move_construct;
o.value = -1;
}
- MoveAssign &operator=(MoveAssign &&o) {
- value = o.value;
- ++move_assign;
+ constexpr MoveAssign& operator=(MoveAssign&& o) {
+ value = o.value;
+ move_construct = o.move_construct;
+ move_assign = o.move_assign;
+ ++*move_assign;
o.value = -1;
return *this;
}
int value;
+ int* move_construct;
+ int* move_assign;
};
-int MoveAssign::move_construct = 0;
-int MoveAssign::move_assign = 0;
-
struct NTMoveAssign {
constexpr NTMoveAssign(int v) : value(v) {}
- NTMoveAssign(const NTMoveAssign &) = default;
- NTMoveAssign(NTMoveAssign &&) = default;
- NTMoveAssign &operator=(const NTMoveAssign &that) = default;
- NTMoveAssign &operator=(NTMoveAssign &&that) {
- value = that.value;
+ NTMoveAssign(const NTMoveAssign&) = default;
+ NTMoveAssign(NTMoveAssign&&) = default;
+ NTMoveAssign& operator=(const NTMoveAssign& that) = default;
+ NTMoveAssign& operator=(NTMoveAssign&& that) {
+ value = that.value;
that.value = -1;
return *this;
};
@@ -100,10 +99,10 @@ static_assert(std::is_move_assignable<NTMoveAssign>::value, "");
struct TMoveAssign {
constexpr TMoveAssign(int v) : value(v) {}
- TMoveAssign(const TMoveAssign &) = delete;
- TMoveAssign(TMoveAssign &&) = default;
- TMoveAssign &operator=(const TMoveAssign &) = delete;
- TMoveAssign &operator=(TMoveAssign &&) = default;
+ TMoveAssign(const TMoveAssign&) = delete;
+ TMoveAssign(TMoveAssign&&) = default;
+ TMoveAssign& operator=(const TMoveAssign&) = delete;
+ TMoveAssign& operator=(TMoveAssign&&) = default;
int value;
};
@@ -111,13 +110,13 @@ static_assert(std::is_trivially_move_assignable<TMoveAssign>::value, "");
struct TMoveAssignNTCopyAssign {
constexpr TMoveAssignNTCopyAssign(int v) : value(v) {}
- TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default;
- TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default;
- TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) {
+ TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign&) = default;
+ TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign&&) = default;
+ TMoveAssignNTCopyAssign& operator=(const TMoveAssignNTCopyAssign& that) {
value = that.value;
return *this;
}
- TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default;
+ TMoveAssignNTCopyAssign& operator=(TMoveAssignNTCopyAssign&&) = default;
int value;
};
@@ -127,15 +126,12 @@ struct TrivialCopyNontrivialMove {
TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default;
TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {}
TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default;
- TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept {
- return *this;
- }
+ TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept { return *this; }
};
static_assert(std::is_trivially_copy_assignable_v<TrivialCopyNontrivialMove>, "");
static_assert(!std::is_trivially_move_assignable_v<TrivialCopyNontrivialMove>, "");
-
void test_move_assignment_noexcept() {
{
using V = std::variant<int>;
@@ -228,7 +224,7 @@ void test_move_assignment_empty_empty() {
makeEmpty(v1);
V v2(std::in_place_index<0>);
makeEmpty(v2);
- V &vref = (v1 = std::move(v2));
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
@@ -244,7 +240,7 @@ void test_move_assignment_non_empty_empty() {
V v1(std::in_place_index<0>, 42);
V v2(std::in_place_index<0>);
makeEmpty(v2);
- V &vref = (v1 = std::move(v2));
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
@@ -254,7 +250,7 @@ void test_move_assignment_non_empty_empty() {
V v1(std::in_place_index<2>, "hello");
V v2(std::in_place_index<0>);
makeEmpty(v2);
- V &vref = (v1 = std::move(v2));
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
@@ -270,7 +266,7 @@ void test_move_assignment_empty_non_empty() {
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_index<0>, 42);
- V &vref = (v1 = std::move(v2));
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 0);
assert(std::get<0>(v1) == 42);
@@ -280,7 +276,7 @@ void test_move_assignment_empty_non_empty() {
V v1(std::in_place_index<0>);
makeEmpty(v1);
V v2(std::in_place_type<std::string>, "hello");
- V &vref = (v1 = std::move(v2));
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
@@ -288,14 +284,18 @@ void test_move_assignment_empty_non_empty() {
#endif // TEST_HAS_NO_EXCEPTIONS
}
-template <typename T> struct Result { std::size_t index; T value; };
+template <typename T>
+struct Result {
+ std::size_t index;
+ T value;
+};
-void test_move_assignment_same_index() {
+TEST_CONSTEXPR_CXX20 bool test_move_assignment_same_index() {
{
using V = std::variant<int>;
V v1(43);
V v2(42);
- V &vref = (v1 = std::move(v2));
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 0);
assert(std::get<0>(v1) == 42);
@@ -304,39 +304,24 @@ void test_move_assignment_same_index() {
using V = std::variant<int, long, unsigned>;
V v1(43l);
V v2(42l);
- V &vref = (v1 = std::move(v2));
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1) == 42);
}
{
- using V = std::variant<int, MoveAssign, unsigned>;
- V v1(std::in_place_type<MoveAssign>, 43);
- V v2(std::in_place_type<MoveAssign>, 42);
- MoveAssign::reset();
- V &vref = (v1 = std::move(v2));
+ using V = std::variant<int, MoveAssign, unsigned>;
+ int move_construct = 0;
+ int move_assign = 0;
+ V v1(std::in_place_type<MoveAssign>, 43, &move_construct, &move_assign);
+ V v2(std::in_place_type<MoveAssign>, 42, &move_construct, &move_assign);
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1).value == 42);
- assert(MoveAssign::move_construct == 0);
- assert(MoveAssign::move_assign == 1);
+ assert(move_construct == 0);
+ assert(move_assign == 1);
}
-#ifndef TEST_HAS_NO_EXCEPTIONS
- using MET = MakeEmptyT;
- {
- using V = std::variant<int, MET, std::string>;
- V v1(std::in_place_type<MET>);
- MET &mref = std::get<1>(v1);
- V v2(std::in_place_type<MET>);
- try {
- v1 = std::move(v2);
- assert(false);
- } catch (...) {
- }
- assert(v1.index() == 1);
- assert(&std::get<1>(v1) == &mref);
- }
-#endif // TEST_HAS_NO_EXCEPTIONS
// Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
{
@@ -381,54 +366,33 @@ void test_move_assignment_same_index() {
static_assert(result.index == 1, "");
static_assert(result.value == 42, "");
}
+
+ return true;
}
-void test_move_assignment_different_index() {
+TEST_CONSTEXPR_CXX20 bool test_move_assignment_different_index() {
{
using V = std::variant<int, long, unsigned>;
V v1(43);
V v2(42l);
- V &vref = (v1 = std::move(v2));
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1) == 42);
}
{
- using V = std::variant<int, MoveAssign, unsigned>;
+ using V = std::variant<int, MoveAssign, unsigned>;
+ int move_construct = 0;
+ int move_assign = 0;
V v1(std::in_place_type<unsigned>, 43u);
- V v2(std::in_place_type<MoveAssign>, 42);
- MoveAssign::reset();
- V &vref = (v1 = std::move(v2));
+ V v2(std::in_place_type<MoveAssign>, 42, &move_construct, &move_assign);
+ V& vref = (v1 = std::move(v2));
assert(&vref == &v1);
assert(v1.index() == 1);
assert(std::get<1>(v1).value == 42);
- assert(MoveAssign::move_construct == 1);
- assert(MoveAssign::move_assign == 0);
- }
-#ifndef TEST_HAS_NO_EXCEPTIONS
- using MET = MakeEmptyT;
- {
- using V = std::variant<int, MET, std::string>;
- V v1(std::in_place_type<int>);
- V v2(std::in_place_type<MET>);
- try {
- v1 = std::move(v2);
- assert(false);
- } catch (...) {
- }
- assert(v1.valueless_by_exception());
- assert(v1.index() == std::variant_npos);
- }
- {
- using V = std::variant<int, MET, std::string>;
- V v1(std::in_place_type<MET>);
- V v2(std::in_place_type<std::string>, "hello");
- V &vref = (v1 = std::move(v2));
- assert(&vref == &v1);
- assert(v1.index() == 2);
- assert(std::get<2>(v1) == "hello");
+ assert(move_construct == 1);
+ assert(move_assign == 0);
}
-#endif // TEST_HAS_NO_EXCEPTIONS
// Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
{
@@ -459,18 +423,59 @@ void test_move_assignment_different_index() {
static_assert(result.index == 1, "");
static_assert(result.value == 42, "");
}
+
+ return true;
+}
+
+void test_assignment_throw() {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ using MET = MakeEmptyT;
+ // same index
+ {
+ using V = std::variant<int, MET, std::string>;
+ V v1(std::in_place_type<MET>);
+ MET& mref = std::get<1>(v1);
+ V v2(std::in_place_type<MET>);
+ try {
+ v1 = std::move(v2);
+ assert(false);
+ } catch (...) {
+ }
+ assert(v1.index() == 1);
+ assert(&std::get<1>(v1) == &mref);
+ }
+
+ // different indices
+ {
+ using V = std::variant<int, MET, std::string>;
+ V v1(std::in_place_type<int>);
+ V v2(std::in_place_type<MET>);
+ try {
+ v1 = std::move(v2);
+ assert(false);
+ } catch (...) {
+ }
+ assert(v1.valueless_by_exception());
+ assert(v1.index() == std::variant_npos);
+ }
+ {
+ using V = std::variant<int, MET, std::string>;
+ V v1(std::in_place_type<MET>);
+ V v2(std::in_place_type<std::string>, "hello");
+ V& vref = (v1 = std::move(v2));
+ assert(&vref == &v1);
+ assert(v1.index() == 2);
+ assert(std::get<2>(v1) == "hello");
+ }
+#endif // TEST_HAS_NO_EXCEPTIONS
}
template <std::size_t NewIdx, class ValueType>
-constexpr bool test_constexpr_assign_imp(
- std::variant<long, void*, int>&& v, ValueType&& new_value)
-{
- std::variant<long, void*, int> v2(
- std::forward<ValueType>(new_value));
+constexpr bool test_constexpr_assign_imp(std::variant<long, void*, int>&& v, ValueType&& new_value) {
+ std::variant<long, void*, int> v2(std::forward<ValueType>(new_value));
const auto cp = v2;
- v = std::move(v2);
- return v.index() == NewIdx &&
- std::get<NewIdx>(v) == std::get<NewIdx>(cp);
+ v = std::move(v2);
+ return v.index() == NewIdx && std::get<NewIdx>(v) == std::get<NewIdx>(cp);
}
void test_constexpr_move_assignment() {
@@ -488,11 +493,16 @@ int main(int, char**) {
test_move_assignment_empty_empty();
test_move_assignment_non_empty_empty();
test_move_assignment_empty_non_empty();
+ test_assignment_throw();
test_move_assignment_same_index();
test_move_assignment_different_index();
test_move_assignment_sfinae();
test_move_assignment_noexcept();
test_constexpr_move_assignment();
+#if TEST_STD_VER >= 20
+ static_assert(test_move_assignment_same_index());
+ static_assert(test_move_assignment_different_index());
+#endif
return 0;
}
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
index 34626a4e25f355..38e47e7bc9db18 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
@@ -22,8 +22,8 @@
#include "test_workarounds.h"
struct NonT {
- NonT(int v) : value(v) {}
- NonT(const NonT& o) : value(o.value) {}
+ constexpr NonT(int v) : value(v) {}
+ constexpr NonT(const NonT& o) : value(o.value) {}
int value;
};
static_assert(!std::is_trivially_copy_constructible<NonT>::value, "");
@@ -137,7 +137,7 @@ void test_copy_ctor_sfinae() {
}
}
-void test_copy_ctor_basic() {
+TEST_CONSTEXPR_CXX20 bool test_copy_ctor_basic() {
{
std::variant<int> v(std::in_place_index<0>, 42);
std::variant<int> v2 = v;
@@ -208,6 +208,7 @@ void test_copy_ctor_basic() {
static_assert(v2.index() == 1, "");
static_assert(std::get<1>(v2).value == 42, "");
}
+ return true;
}
void test_copy_ctor_valueless_by_exception() {
@@ -274,5 +275,9 @@ int main(int, char**) {
test_copy_ctor_valueless_by_exception();
test_copy_ctor_sfinae();
test_constexpr_copy_ctor();
+
+#if TEST_STD_VER >= 20
+ static_assert(test_copy_ctor_basic());
+#endif
return 0;
}
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
index 4bb6cf24b0f0e2..0c931be453741f 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
@@ -32,16 +32,16 @@ struct NoCopy {
struct MoveOnly {
int value;
- MoveOnly(int v) : value(v) {}
+ constexpr MoveOnly(int v) : value(v) {}
MoveOnly(const MoveOnly&) = delete;
MoveOnly(MoveOnly&&) = default;
};
struct MoveOnlyNT {
int value;
- MoveOnlyNT(int v) : value(v) {}
+ constexpr MoveOnlyNT(int v) : value(v) {}
MoveOnlyNT(const MoveOnlyNT&) = delete;
- MoveOnlyNT(MoveOnlyNT&& other) : value(other.value) { other.value = -1; }
+ constexpr MoveOnlyNT(MoveOnlyNT&& other) : value(other.value) { other.value = -1; }
};
struct NTMove {
@@ -164,7 +164,7 @@ struct Result {
T value;
};
-void test_move_ctor_basic() {
+TEST_CONSTEXPR_CXX20 bool test_move_ctor_basic() {
{
std::variant<int> v(std::in_place_index<0>, 42);
std::variant<int> v2 = std::move(v);
@@ -281,6 +281,7 @@ void test_move_ctor_basic() {
static_assert(result.index == 1, "");
static_assert(result.value.value == 42, "");
}
+ return true;
}
void test_move_ctor_valueless_by_exception() {
@@ -350,5 +351,9 @@ int main(int, char**) {
test_move_ctor_sfinae();
test_constexpr_move_ctor();
+#if TEST_STD_VER >= 20
+ static_assert(test_move_ctor_basic());
+#endif
+
return 0;
}
More information about the libcxx-commits
mailing list