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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to