summaryrefslogtreecommitdiff
path: root/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp')
-rw-r--r--test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp199
1 files changed, 191 insertions, 8 deletions
diff --git a/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp b/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
index c1ba87be76d1..c410b4b8f3ef 100644
--- a/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
+++ b/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
@@ -10,6 +10,10 @@
// UNSUPPORTED: c++98, c++03, c++11, c++14
+// The following compilers don't generate constexpr special members correctly.
+// XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8
+// XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0
+
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
@@ -91,6 +95,60 @@ struct MoveAssign {
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;
+ that.value = -1;
+ return *this;
+ };
+ int value;
+};
+
+static_assert(!std::is_trivially_move_assignable<NTMoveAssign>::value, "");
+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;
+ int value;
+};
+
+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) {
+ value = that.value;
+ return *this;
+ }
+ TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default;
+ int value;
+};
+
+static_assert(std::is_trivially_move_assignable_v<TMoveAssignNTCopyAssign>, "");
+
+struct TrivialCopyNontrivialMove {
+ TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default;
+ TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {}
+ TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default;
+ 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>;
@@ -124,10 +182,8 @@ void test_move_assignment_sfinae() {
static_assert(std::is_move_assignable<V>::value, "");
}
{
- // variant only provides move assignment when both the move constructor
- // and move assignment operator are well formed.
using V = std::variant<int, CopyOnly>;
- static_assert(!std::is_move_assignable<V>::value, "");
+ static_assert(std::is_move_assignable<V>::value, "");
}
{
using V = std::variant<int, NoCopy>;
@@ -147,6 +203,33 @@ void test_move_assignment_sfinae() {
using V = std::variant<int, MoveAssignOnly>;
static_assert(!std::is_move_assignable<V>::value, "");
}
+
+ // The following tests are for not-yet-standardized behavior (P0602):
+ {
+ using V = std::variant<int, long>;
+ static_assert(std::is_trivially_move_assignable<V>::value, "");
+ }
+ {
+ using V = std::variant<int, NTMoveAssign>;
+ static_assert(!std::is_trivially_move_assignable<V>::value, "");
+ static_assert(std::is_move_assignable<V>::value, "");
+ }
+ {
+ using V = std::variant<int, TMoveAssign>;
+ static_assert(std::is_trivially_move_assignable<V>::value, "");
+ }
+ {
+ using V = std::variant<int, TMoveAssignNTCopyAssign>;
+ static_assert(std::is_trivially_move_assignable<V>::value, "");
+ }
+ {
+ using V = std::variant<int, TrivialCopyNontrivialMove>;
+ static_assert(!std::is_trivially_move_assignable<V>::value, "");
+ }
+ {
+ using V = std::variant<int, CopyOnly>;
+ static_assert(std::is_trivially_move_assignable<V>::value, "");
+ }
}
void test_move_assignment_empty_empty() {
@@ -163,7 +246,7 @@ void test_move_assignment_empty_empty() {
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
}
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
}
void test_move_assignment_non_empty_empty() {
@@ -189,7 +272,7 @@ void test_move_assignment_non_empty_empty() {
assert(v1.valueless_by_exception());
assert(v1.index() == std::variant_npos);
}
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
}
void test_move_assignment_empty_non_empty() {
@@ -215,9 +298,11 @@ void test_move_assignment_empty_non_empty() {
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
}
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
}
+template <typename T> struct Result { size_t index; T value; };
+
void test_move_assignment_same_index() {
{
using V = std::variant<int>;
@@ -264,7 +349,51 @@ void test_move_assignment_same_index() {
assert(v1.index() == 1);
assert(&std::get<1>(v1) == &mref);
}
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+ // The following tests are for not-yet-standardized behavior (P0602):
+ {
+ struct {
+ constexpr Result<int> operator()() const {
+ using V = std::variant<int>;
+ V v(43);
+ V v2(42);
+ v = std::move(v2);
+ return {v.index(), std::get<0>(v)};
+ }
+ } test;
+ constexpr auto result = test();
+ static_assert(result.index == 0, "");
+ static_assert(result.value == 42, "");
+ }
+ {
+ struct {
+ constexpr Result<long> operator()() const {
+ using V = std::variant<int, long, unsigned>;
+ V v(43l);
+ V v2(42l);
+ v = std::move(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, TMoveAssign, unsigned>;
+ V v(std::in_place_type<TMoveAssign>, 43);
+ V v2(std::in_place_type<TMoveAssign>, 42);
+ v = std::move(v2);
+ return {v.index(), std::get<1>(v).value};
+ }
+ } test;
+ constexpr auto result = test();
+ static_assert(result.index == 1, "");
+ static_assert(result.value == 42, "");
+ }
}
void test_move_assignment_different_index() {
@@ -312,7 +441,60 @@ void test_move_assignment_different_index() {
assert(v1.index() == 2);
assert(std::get<2>(v1) == "hello");
}
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+ // The following tests are for not-yet-standardized behavior (P0602):
+ {
+ struct {
+ constexpr Result<long> operator()() const {
+ using V = std::variant<int, long, unsigned>;
+ V v(43);
+ V v2(42l);
+ v = std::move(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<long> operator()() const {
+ using V = std::variant<int, TMoveAssign, unsigned>;
+ V v(std::in_place_type<unsigned>, 43);
+ V v2(std::in_place_type<TMoveAssign>, 42);
+ v = std::move(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 <size_t NewIdx, class ValueType>
+constexpr bool test_constexpr_assign_extension_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);
+}
+
+void test_constexpr_move_assignment_extension() {
+ // The following tests are for not-yet-standardized behavior (P0602):
+ using V = std::variant<long, void*, int>;
+ static_assert(std::is_trivially_copyable<V>::value, "");
+ static_assert(std::is_trivially_move_assignable<V>::value, "");
+ static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), "");
+ static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), "");
+ static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), "");
+ static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), "");
}
int main() {
@@ -323,4 +505,5 @@ int main() {
test_move_assignment_different_index();
test_move_assignment_sfinae();
test_move_assignment_noexcept();
+ test_constexpr_move_assignment_extension();
}