CaseyCarter updated this revision to Diff 97204.
CaseyCarter added a comment.
Fix a weird corner case in variant's move assignment triviality test.
https://reviews.llvm.org/D32671
Files:
test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
test/support/msvc_stdlib_force_include.hpp
test/support/test.workarounds/c1xx_broken_is_trivially_copyable.pass.cpp
test/support/test_workarounds.h
Index: test/support/test_workarounds.h
===================================================================
--- test/support/test_workarounds.h
+++ test/support/test_workarounds.h
@@ -15,6 +15,7 @@
#if defined(TEST_COMPILER_C1XX)
# define TEST_WORKAROUND_C1XX_BROKEN_NULLPTR_CONVERSION_OPERATOR
+# define TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
#endif
#endif // SUPPORT_TEST_WORKAROUNDS_H
Index: test/support/test.workarounds/c1xx_broken_is_trivially_copyable.pass.cpp
===================================================================
--- /dev/null
+++ test/support/test.workarounds/c1xx_broken_is_trivially_copyable.pass.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// Verify TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE.
+
+#include <type_traits>
+
+#include "test_workarounds.h"
+
+struct S {
+ S(S const&) = default;
+ S(S&&) = default;
+ S& operator=(S const&) = delete;
+ S& operator=(S&&) = delete;
+};
+
+int main() {
+#if defined(TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE)
+ static_assert(!std::is_trivially_copyable<S>::value, "");
+#else
+ static_assert(std::is_trivially_copyable<S>::value, "");
+#endif
+}
Index: test/support/msvc_stdlib_force_include.hpp
===================================================================
--- test/support/msvc_stdlib_force_include.hpp
+++ test/support/msvc_stdlib_force_include.hpp
@@ -26,6 +26,11 @@
#error This header may not be used when targeting libc++
#endif
+// Indicates that we are using the MSVC standard library.
+#ifndef _MSVC_STL_VER
+#define _MSVC_STL_VER 42
+#endif
+
struct AssertionDialogAvoider {
AssertionDialogAvoider() {
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
Index: test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
===================================================================
--- test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
@@ -22,6 +22,7 @@
#include <variant>
#include "test_macros.h"
+#include "test_workarounds.h"
struct ThrowsMove {
ThrowsMove(ThrowsMove &&) noexcept(false) {}
@@ -178,20 +179,48 @@
}
void test_constexpr_move_ctor_extension() {
-#ifdef _LIBCPP_VERSION
+#if defined(_LIBCPP_VER) || defined(_MSVC_STL_VER)
using V = std::variant<long, void*, const int>;
+#ifdef TEST_WORKAROUND_C1XX_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
static_assert(std::is_trivially_copyable<V>::value, "");
+#endif
static_assert(std::is_trivially_move_constructible<V>::value, "");
static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), "");
static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), "");
static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), "");
#endif
}
+template<class...Ts>
+constexpr bool triviality_test =
+ std::is_trivially_move_constructible<std::variant<Ts...>>::value ==
+ std::conjunction<std::is_trivially_move_constructible<Ts>...>::value;
+
+void test_triviality_extension() {
+#if defined(_MSVC_STL_VER)
+ static_assert(triviality_test<int>, "");
+ static_assert(triviality_test<MoveOnly>, "");
+ static_assert(triviality_test<MoveOnlyNT>, "");
+ static_assert(triviality_test<int, long>, "");
+ static_assert(triviality_test<int, MoveOnly>, "");
+ static_assert(triviality_test<int, MoveOnlyNT>, "");
+ static_assert(triviality_test<int, ThrowsMove>, "");
+ static_assert(triviality_test<int, NoCopy>, "");
+ static_assert(triviality_test<int, MakeEmptyT>, "");
+#endif
+}
+
int main() {
test_move_ctor_basic();
test_move_ctor_valueless_by_exception();
test_move_noexcept();
test_move_ctor_sfinae();
test_constexpr_move_ctor_extension();
+ test_triviality_extension();
}
Index: test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
===================================================================
--- test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
@@ -21,6 +21,7 @@
#include <variant>
#include "test_macros.h"
+#include "test_workarounds.h"
struct NonT {
NonT(int v) : value(v) {}
@@ -137,23 +138,48 @@
auto v2 = v;
return v2.index() == v.index() &&
v2.index() == Idx &&
- std::get<Idx>(v2) == std::get<Idx>(v);
+ std::get<Idx>(v2) == std::get<Idx>(v);
}
void test_constexpr_copy_ctor_extension() {
-#ifdef _LIBCPP_VERSION
+#if defined(_LIBCPP_VER) || defined(_MSVC_STL_VER)
using V = std::variant<long, void*, const int>;
- static_assert(std::is_trivially_copyable<V>::value, "");
+#ifdef TEST_WORKAROUND_C1XX_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
+ static_assert(std::is_trivially_copyable<V>::value, "");
+#endif
static_assert(test_constexpr_copy_ctor_extension_imp<0>(V(42l)), "");
static_assert(test_constexpr_copy_ctor_extension_imp<1>(V(nullptr)), "");
static_assert(test_constexpr_copy_ctor_extension_imp<2>(V(101)), "");
#endif
}
+template<class...Ts>
+constexpr bool triviality_test =
+ std::is_trivially_copy_constructible<std::variant<Ts...>>::value ==
+ std::conjunction<std::is_trivially_copy_constructible<Ts>...>::value;
+
+void test_triviality_extension() {
+#if defined(_MSVC_STL_VER)
+ static_assert(triviality_test<int>, "");
+ static_assert(triviality_test<NonT>, "");
+ static_assert(triviality_test<int, long>, "");
+ static_assert(triviality_test<int, NoCopy>, "");
+ static_assert(triviality_test<int, MoveOnly>, "");
+ static_assert(triviality_test<int, MoveOnlyNT>, "");
+ static_assert(triviality_test<int, MakeEmptyT>, "");
+#endif
+}
+
int main() {
test_copy_ctor_basic();
test_copy_ctor_valueless_by_exception();
test_copy_ctor_sfinae();
test_constexpr_copy_ctor_extension();
+ test_triviality_extension();
}
Index: test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
===================================================================
--- test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
@@ -308,12 +308,63 @@
#endif
}
+template<class...Ts>
+constexpr bool triviality_test =
+ // move assignent of variant<Ts...> is trivial when
+ std::is_trivially_move_assignable<std::variant<Ts...>>::value ==
+ std::conjunction<
+ // All Ts are trivially destructible and
+ std::is_trivially_destructible<Ts>...,
+ // either
+ std::disjunction<
+ // All Ts are trivially move (constructible and assignable) so that
+ // variant's move assignment operator is non-deleted and trivial, or
+ std::conjunction<
+ std::is_trivially_move_constructible<Ts>...,
+ std::is_trivially_move_assignable<Ts>...>,
+ // At least one of the Ts is not move (constructible or assignable) so
+ // that variant's move assignment operator is *implicitly* deleted but
+ // all of the Ts are trivially *copy* (constructible and deletable) so
+ // that move assignment actually invokes the trivial copy assignment
+ // operator.
+ std::conjunction<
+ std::disjunction<
+ std::negation<std::is_move_constructible<Ts>>...,
+ std::negation<std::is_move_assignable<Ts>>...>,
+ std::is_trivially_copy_constructible<Ts>...,
+ std::is_trivially_copy_assignable<Ts>...>>>::value;
+
+void test_triviality_extension() {
+#if defined(_MSVC_STL_VER)
+ struct TrivialCopyNontrivialMove {
+ TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default;
+ TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {}
+ TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default;
+ TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept {
+ return *this;
+ }
+ };
+
+ static_assert(triviality_test<int>, "");
+ static_assert(triviality_test<std::string>, "");
+ static_assert(triviality_test<int, long>, "");
+ static_assert(triviality_test<int, std::string>, "");
+ static_assert(triviality_test<int, NoCopy>, "");
+ static_assert(triviality_test<int, CopyOnly>, "");
+ static_assert(triviality_test<int, MoveOnly>, "");
+ static_assert(triviality_test<int, MoveAssign>, "");
+ static_assert(triviality_test<int, MoveAssignOnly>, "");
+ static_assert(triviality_test<int, TrivialCopyNontrivialMove>, "");
+#endif
+}
+
int main() {
test_move_assignment_empty_empty();
test_move_assignment_non_empty_empty();
test_move_assignment_empty_non_empty();
test_move_assignment_same_index();
test_move_assignment_different_index();
test_move_assignment_sfinae();
test_move_assignment_noexcept();
+ test_triviality_extension();
}
Index: test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
===================================================================
--- test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
@@ -385,6 +385,27 @@
#endif
}
+template<class...Ts>
+constexpr bool triviality_test =
+ std::is_trivially_copy_assignable<std::variant<Ts...>>::value ==
+ std::conjunction<
+ std::is_trivially_destructible<Ts>...,
+ std::is_trivially_copy_constructible<Ts>...,
+ std::is_trivially_copy_assignable<Ts>...>::value;
+
+void test_triviality_extension() {
+#if defined(_MSVC_STL_VER)
+ static_assert(triviality_test<int>, "");
+ static_assert(triviality_test<std::string>, "");
+ static_assert(triviality_test<int, long>, "");
+ static_assert(triviality_test<int, std::string>, "");
+ static_assert(triviality_test<int, NoCopy>, "");
+ static_assert(triviality_test<int, NothrowCopy>, "");
+ static_assert(triviality_test<int, CopyOnly>, "");
+ static_assert(triviality_test<int, MoveOnly>, "");
+ static_assert(triviality_test<int, CopyAssign>, "");
+#endif
+}
int main() {
test_copy_assignment_empty_empty();
@@ -394,4 +415,5 @@
test_copy_assignment_different_index();
test_copy_assignment_sfinae();
test_copy_assignment_not_noexcept();
+ test_triviality_extension();
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits