2019-04-17 Jonathan Wakely <jwakely@redhat.com>
+ * include/std/variant (__detail::__variant::_Traits::_S_copy_assign):
+ Do not depend on whether all alternative types are move constructible.
+ (__detail::__variant::_Copy_assign_base::operator=): Remove cv-quals
+ from the operand when deciding whether to perform the assignment.
+ * testsuite/20_util/variant/compile.cc (DeletedMoves): Define type
+ with deleted move constructor and deleted move assignment operator.
+ (default_ctor, copy_ctor, move_ctor, copy_assign, move_assign): Check
+ behaviour of variants with DeletedMoves as an alternative.
+ * testsuite/20_util/variant/run.cc (DeletedMoves): Define same type.
+ (move_ctor, move_assign): Check that moving a variant with a
+ DeletedMoves alternative falls back to copying instead of moving.
+
* testsuite/20_util/variant/compile.cc: Remove empty string literals
from static_assert declarations.
static constexpr bool _S_move_ctor =
(is_move_constructible_v<_Types> && ...);
static constexpr bool _S_copy_assign =
- _S_copy_ctor && _S_move_ctor
+ _S_copy_ctor
&& (is_copy_assignable_v<_Types> && ...);
static constexpr bool _S_move_assign =
_S_move_ctor
__variant::__get<__rhs_index>(*this);
if constexpr (is_same_v<
remove_reference_t<decltype(__this_mem)>,
- remove_reference_t<decltype(__rhs_mem)>>)
+ __remove_cvref_t<decltype(__rhs_mem)>>)
__this_mem = __rhs_mem;
}
}
struct MoveCtorAndSwapOnly : MoveCtorOnly { };
void swap(MoveCtorAndSwapOnly&, MoveCtorAndSwapOnly&) { }
+struct DeletedMoves
+{
+ DeletedMoves() = default;
+ DeletedMoves(const DeletedMoves&) = default;
+ DeletedMoves(DeletedMoves&&) = delete;
+ DeletedMoves& operator=(const DeletedMoves&) = default;
+ DeletedMoves& operator=(DeletedMoves&&) = delete;
+};
+
struct nonliteral
{
nonliteral() { }
static_assert(is_default_constructible_v<variant<string, string>>);
static_assert(!is_default_constructible_v<variant<AllDeleted, string>>);
static_assert(is_default_constructible_v<variant<string, AllDeleted>>);
+ static_assert(is_default_constructible_v<variant<DeletedMoves>>);
static_assert(noexcept(variant<int>()));
static_assert(!noexcept(variant<Empty>()));
static_assert(!is_copy_constructible_v<variant<AllDeleted, string>>);
static_assert(is_trivially_copy_constructible_v<variant<int>>);
static_assert(!is_trivially_copy_constructible_v<variant<std::string>>);
+ static_assert(is_trivially_copy_constructible_v<variant<DeletedMoves>>);
{
variant<int> a;
{
static_assert(is_move_constructible_v<variant<int, string>>);
static_assert(!is_move_constructible_v<variant<AllDeleted, string>>);
+ static_assert(is_move_constructible_v<variant<int, DeletedMoves>>); // uses copy ctor
static_assert(is_trivially_move_constructible_v<variant<int>>);
static_assert(!is_trivially_move_constructible_v<variant<std::string>>);
static_assert(!noexcept(variant<int, Empty>(declval<variant<int, Empty>>())));
static_assert(!is_copy_assignable_v<variant<AllDeleted, string>>);
static_assert(is_trivially_copy_assignable_v<variant<int>>);
static_assert(!is_trivially_copy_assignable_v<variant<string>>);
+ static_assert(is_trivially_copy_assignable_v<variant<DeletedMoves>>);
{
variant<Empty> a;
static_assert(!noexcept(a = a));
{
static_assert(is_move_assignable_v<variant<int, string>>);
static_assert(!is_move_assignable_v<variant<AllDeleted, string>>);
+ static_assert(is_move_assignable_v<variant<int, DeletedMoves>>); // uses copy assignment
static_assert(is_trivially_move_assignable_v<variant<int>>);
static_assert(!is_trivially_move_assignable_v<variant<string>>);
{
bool operator>(const AlwaysThrow&) const { VERIFY(false); }
};
+struct DeletedMoves
+{
+ DeletedMoves() = default;
+ DeletedMoves(const DeletedMoves&) = default;
+ DeletedMoves(DeletedMoves&&) = delete;
+ DeletedMoves& operator=(const DeletedMoves&) = default;
+ DeletedMoves& operator=(DeletedMoves&&) = delete;
+};
+
void default_ctor()
{
variant<monostate, string> v;
VERIFY(holds_alternative<string>(u));
VERIFY(get<string>(u) == "a");
VERIFY(holds_alternative<string>(v));
+
+ variant<vector<int>, DeletedMoves> d{std::in_place_index<0>, {1, 2, 3, 4}};
+ // DeletedMoves is not move constructible, so this uses copy ctor:
+ variant<vector<int>, DeletedMoves> e(std::move(d));
+ VERIFY(std::get<0>(d).size() == 4);
+ VERIFY(std::get<0>(e).size() == 4);
}
void arbitrary_ctor()
VERIFY(holds_alternative<string>(u));
VERIFY(get<string>(u) == "a");
VERIFY(holds_alternative<string>(v));
+
+ variant<vector<int>, DeletedMoves> d{std::in_place_index<0>, {1, 2, 3, 4}};
+ variant<vector<int>, DeletedMoves> e;
+ // DeletedMoves is not move assignable, so this uses copy assignment:
+ e = std::move(d);
+ VERIFY(std::get<0>(d).size() == 4);
+ VERIFY(std::get<0>(e).size() == 4);
}
void arbitrary_assign()