CaseyCarter updated this revision to Diff 101497.
CaseyCarter retitled this revision from "[libcxx] [test] variant: test coverage 
for P0602 extension" to "[libcxx] [test] variant: test coverage for LWG2904 and 
P0602".
CaseyCarter edited the summary of this revision.
CaseyCarter added a comment.

Massive update: Move the libcxx tree tests into std, merge my LWG2904 
differential.


https://reviews.llvm.org/D32671

Files:
  test/libcxx/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
  test/libcxx/utilities/variant/variant.variant/variant.assign/move.pass.cpp
  test/libcxx/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
  test/libcxx/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
  test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
  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/variant_test_helpers.hpp

Index: test/support/variant_test_helpers.hpp
===================================================================
--- test/support/variant_test_helpers.hpp
+++ test/support/variant_test_helpers.hpp
@@ -69,9 +69,9 @@
 void makeEmpty(Variant& v) {
     Variant v2(std::in_place_type<MakeEmptyT>);
     try {
-        v = v2;
+        v = std::move(v2);
         assert(false);
-    }  catch (...) {
+    } catch (...) {
         assert(v.valueless_by_exception());
     }
 }
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
@@ -53,6 +53,34 @@
   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; }
+  int value;
+};
+
+static_assert(!std::is_trivially_move_constructible<NTMove>::value, "");
+static_assert(std::is_move_constructible<NTMove>::value, "");
+
+struct TMove {
+  constexpr TMove(int v) : value(v) {}
+  TMove(const TMove &) = delete;
+  TMove(TMove &&) = default;
+  int value;
+};
+
+static_assert(std::is_trivially_move_constructible<TMove>::value, "");
+
+struct TMoveNTCopy {
+  constexpr TMoveNTCopy(int v) : value(v) {}
+  TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {}
+  TMoveNTCopy(TMoveNTCopy&&) = default;
+  int value;
+};
+
+static_assert(std::is_trivially_move_constructible<TMoveNTCopy>::value, "");
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
 struct MakeEmptyT {
   static int alive;
@@ -73,7 +101,7 @@
 template <class Variant> void makeEmpty(Variant &v) {
   Variant v2(std::in_place_type<MakeEmptyT>);
   try {
-    v = v2;
+    v = std::move(v2);
     assert(false);
   } catch (...) {
     assert(v.valueless_by_exception());
@@ -117,8 +145,30 @@
     using V = std::variant<int, NoCopy>;
     static_assert(!std::is_move_constructible<V>::value, "");
   }
+
+  // The following tests are for not-yet-standardized behavior (P0602):
+  {
+    using V = std::variant<int, long>;
+    static_assert(std::is_trivially_move_constructible<V>::value, "");
+  }
+  {
+    using V = std::variant<int, NTMove>;
+    static_assert(!std::is_trivially_move_constructible<V>::value, "");
+    static_assert(std::is_move_constructible<V>::value, "");
+  }
+  {
+    using V = std::variant<int, TMove>;
+    static_assert(std::is_trivially_move_constructible<V>::value, "");
+  }
+  {
+    using V = std::variant<int, TMoveNTCopy>;
+    static_assert(std::is_trivially_move_constructible<V>::value, "");
+  }
 }
 
+template <typename T>
+struct Result { size_t index; T value; };
+
 void test_move_ctor_basic() {
   {
     std::variant<int> v(std::in_place_index<0>, 42);
@@ -162,6 +212,80 @@
     assert(std::get<1>(v).value == -1);
     assert(std::get<1>(v2).value == 42);
   }
+
+  // The following tests are for not-yet-standardized behavior (P0602):
+  {
+    struct {
+      constexpr Result<int> operator()() const {
+        std::variant<int> v(std::in_place_index<0>, 42);
+        std::variant<int> v2 = std::move(v);
+        return {v2.index(), std::get<0>(std::move(v2))};
+      }
+    } test;
+    constexpr auto result = test();
+    static_assert(result.index == 0, "");
+    static_assert(result.value == 42, "");
+  }
+  {
+    struct {
+      constexpr Result<long> operator()() const {
+        std::variant<int, long> v(std::in_place_index<1>, 42);
+        std::variant<int, long> v2 = std::move(v);
+        return {v2.index(), std::get<1>(std::move(v2))};
+      }
+    } test;
+    constexpr auto result = test();
+    static_assert(result.index == 1, "");
+    static_assert(result.value == 42, "");
+  }
+  {
+    struct {
+      constexpr Result<TMove> operator()() const {
+        std::variant<TMove> v(std::in_place_index<0>, 42);
+        std::variant<TMove> v2(std::move(v));
+        return {v2.index(), std::get<0>(std::move(v2))};
+      }
+    } test;
+    constexpr auto result = test();
+    static_assert(result.index == 0, "");
+    static_assert(result.value.value == 42, "");
+  }
+  {
+    struct {
+      constexpr Result<TMove> operator()() const {
+        std::variant<int, TMove> v(std::in_place_index<1>, 42);
+        std::variant<int, TMove> v2(std::move(v));
+        return {v2.index(), std::get<1>(std::move(v2))};
+      }
+    } test;
+    constexpr auto result = test();
+    static_assert(result.index == 1, "");
+    static_assert(result.value.value == 42, "");
+  }
+  {
+    struct {
+      constexpr Result<TMoveNTCopy> operator()() const {
+        std::variant<TMoveNTCopy> v(std::in_place_index<0>, 42);
+        std::variant<TMoveNTCopy> v2(std::move(v));
+        return {v2.index(), std::get<0>(std::move(v2))};
+      }
+    } test;
+    constexpr auto result = test();
+    static_assert(result.index == 0, "");
+    static_assert(result.value.value == 42, "");
+  }
+  {
+    struct {
+      constexpr Result<TMoveNTCopy> operator()() const {
+        std::variant<int, TMoveNTCopy> v(std::in_place_index<1>, 42);
+        std::variant<int, TMoveNTCopy> v2(std::move(v));
+        return {v2.index(), std::get<1>(std::move(v2))};
+      }
+    } test;
+    constexpr auto result = test();
+    static_assert(result.index == 1, "");
+    static_assert(result.value.value == 42, "");
+  }
 }
 
 void test_move_ctor_valueless_by_exception() {
@@ -171,7 +295,7 @@
   makeEmpty(v1);
   V v(std::move(v1));
   assert(v.valueless_by_exception());
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
 }
 
 template <size_t Idx>
@@ -186,17 +310,17 @@
 }
 
 void test_constexpr_move_ctor_extension() {
-  // NOTE: This test is for not yet standardized behavior.
+  // NOTE: This test is for not yet standardized behavior. (P0602)
   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
+#else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
   static_assert(std::is_trivially_copyable<V>::value, "");
-#endif
+#endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
   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)), "");
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
@@ -51,6 +51,34 @@
   MoveOnlyNT(MoveOnlyNT &&) {}
 };
 
+struct NTCopy {
+  constexpr NTCopy(int v) : value(v) {}
+  NTCopy(const NTCopy &that) : value(that.value) {}
+  NTCopy(NTCopy &&) = delete;
+  int value;
+};
+
+static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, "");
+static_assert(std::is_copy_constructible<NTCopy>::value, "");
+
+struct TCopy {
+  constexpr TCopy(int v) : value(v) {}
+  TCopy(TCopy const &) = default;
+  TCopy(TCopy &&) = delete;
+  int value;
+};
+
+static_assert(std::is_trivially_copy_constructible<TCopy>::value, "");
+
+struct TCopyNTMove {
+  constexpr TCopyNTMove(int v) : value(v) {}
+  TCopyNTMove(const TCopyNTMove&) = default;
+  TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; }
+  int value;
+};
+
+static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "");
+
 #ifndef TEST_HAS_NO_EXCEPTIONS
 struct MakeEmptyT {
   static int alive;
@@ -71,7 +99,7 @@
 template <class Variant> void makeEmpty(Variant &v) {
   Variant v2(std::in_place_type<MakeEmptyT>);
   try {
-    v = v2;
+    v = std::move(v2);
     assert(false);
   } catch (...) {
     assert(v.valueless_by_exception());
@@ -96,6 +124,25 @@
     using V = std::variant<int, MoveOnlyNT>;
     static_assert(!std::is_copy_constructible<V>::value, "");
   }
+
+  // The following tests are for not-yet-standardized behavior (P0602):
+  {
+    using V = std::variant<int, long>;
+    static_assert(std::is_trivially_copy_constructible<V>::value, "");
+  }
+  {
+    using V = std::variant<int, NTCopy>;
+    static_assert(!std::is_trivially_copy_constructible<V>::value, "");
+    static_assert(std::is_copy_constructible<V>::value, "");
+  }
+  {
+    using V = std::variant<int, TCopy>;
+    static_assert(std::is_trivially_copy_constructible<V>::value, "");
+  }
+  {
+    using V = std::variant<int, TCopyNTMove>;
+    static_assert(std::is_trivially_copy_constructible<V>::value, "");
+  }
 }
 
 void test_copy_ctor_basic() {
@@ -125,6 +172,50 @@
     assert(v2.index() == 1);
     assert(std::get<1>(v2).value == 42);
   }
+
+  // The following tests are for not-yet-standardized behavior (P0602):
+  {
+    constexpr std::variant<int> v(std::in_place_index<0>, 42);
+    static_assert(v.index() == 0, "");
+    constexpr std::variant<int> v2 = v;
+    static_assert(v2.index() == 0, "");
+    static_assert(std::get<0>(v2) == 42, "");
+  }
+  {
+    constexpr std::variant<int, long> v(std::in_place_index<1>, 42);
+    static_assert(v.index() == 1, "");
+    constexpr std::variant<int, long> v2 = v;
+    static_assert(v2.index() == 1, "");
+    static_assert(std::get<1>(v2) == 42, "");
+  }
+  {
+    constexpr std::variant<TCopy> v(std::in_place_index<0>, 42);
+    static_assert(v.index() == 0, "");
+    constexpr std::variant<TCopy> v2(v);
+    static_assert(v2.index() == 0, "");
+    static_assert(std::get<0>(v2).value == 42, "");
+  }
+  {
+    constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42);
+    static_assert(v.index() == 1, "");
+    constexpr std::variant<int, TCopy> v2(v);
+    static_assert(v2.index() == 1, "");
+    static_assert(std::get<1>(v2).value == 42, "");
+  }
+  {
+    constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42);
+    static_assert(v.index() == 0, "");
+    constexpr std::variant<TCopyNTMove> v2(v);
+    static_assert(v2.index() == 0, "");
+    static_assert(std::get<0>(v2).value == 42, "");
+  }
+  {
+    constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42);
+    static_assert(v.index() == 1, "");
+    constexpr std::variant<int, TCopyNTMove> v2(v);
+    static_assert(v2.index() == 1, "");
+    static_assert(std::get<1>(v2).value == 42, "");
+  }
 }
 
 void test_copy_ctor_valueless_by_exception() {
@@ -135,7 +226,7 @@
   const V &cv1 = v1;
   V v(cv1);
   assert(v.valueless_by_exception());
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
 }
 
 template <size_t Idx>
@@ -149,17 +240,17 @@
 }
 
 void test_constexpr_copy_ctor_extension() {
-  // NOTE: This test is for not yet standardized behavior.
+  // NOTE: This test is for not yet standardized behavior. (P0602)
   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
+#else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
   static_assert(std::is_trivially_copyable<V>::value, "");
-#endif
+#endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
   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)), "");
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
@@ -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 @@
 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,14 @@
     static_assert(std::is_move_assignable<V>::value, "");
   }
   {
+    using V = std::variant<int, CopyOnly>;
+#ifdef _LIBCPP_VERSION // LWG2904
     // 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, "");
+#else // _LIBCPP_VERSION // LWG2904
+    static_assert(std::is_move_assignable<V>::value, "");
+#endif // _LIBCPP_VERSION // LWG2904
   }
   {
     using V = std::variant<int, NoCopy>;
@@ -147,6 +209,35 @@
     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, "");
+  }
+#ifndef _LIBCPP_VERSION // LWG2904
+  {
+    using V = std::variant<int, CopyOnly>;
+    static_assert(std::is_trivially_move_assignable<V>::value, "");
+  }
+#endif // _LIBCPP_VERSION // LWG2904
 }
 
 void test_move_assignment_empty_empty() {
@@ -163,7 +254,7 @@
     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 +280,7 @@
     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 +306,11 @@
     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 +357,51 @@
     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 +449,60 @@
     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 +513,5 @@
   test_move_assignment_different_index();
   test_move_assignment_sfinae();
   test_move_assignment_noexcept();
+  test_constexpr_move_assignment_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
@@ -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
@@ -35,11 +39,6 @@
   NoCopy &operator=(const NoCopy &) = default;
 };
 
-struct NothrowCopy {
-  NothrowCopy(const NothrowCopy &) noexcept = default;
-  NothrowCopy &operator=(const NothrowCopy &) noexcept = default;
-};
-
 struct CopyOnly {
   CopyOnly(const CopyOnly &) = default;
   CopyOnly(CopyOnly &&) = delete;
@@ -73,7 +72,7 @@
     ++alive;
     ++copy_construct;
   }
-  CopyAssign(CopyAssign &&o) : value(o.value) {
+  CopyAssign(CopyAssign &&o) noexcept : value(o.value) {
     o.value = -1;
     ++alive;
     ++move_construct;
@@ -83,7 +82,7 @@
     ++copy_assign;
     return *this;
   }
-  CopyAssign &operator=(CopyAssign &&o) {
+  CopyAssign &operator=(CopyAssign &&o) noexcept {
     value = o.value;
     o.value = -1;
     ++move_assign;
@@ -115,6 +114,17 @@
   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; }
+};
+
+int CopyCannotThrow::alive = 0;
+
 struct MoveThrows {
   static int alive;
   MoveThrows() { ++alive; }
@@ -127,6 +137,47 @@
 
 int MoveThrows::alive = 0;
 
+struct NTCopyAssign {
+  constexpr NTCopyAssign(int v) : value(v) {}
+  NTCopyAssign(const NTCopyAssign &) = default;
+  NTCopyAssign(NTCopyAssign &&) = default;
+  NTCopyAssign &operator=(const NTCopyAssign &that) {
+    value = that.value;
+    return *this;
+  };
+  NTCopyAssign &operator=(NTCopyAssign &&) = delete;
+  int value;
+};
+
+static_assert(!std::is_trivially_copy_assignable<NTCopyAssign>::value, "");
+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;
+  int value;
+};
+
+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;
+    that.value = -1;
+    return *this;
+  }
+  int value;
+};
+
+static_assert(std::is_trivially_copy_assignable_v<TCopyAssignNTMoveAssign>, "");
+
 struct MakeEmptyT {
   static int alive;
   MakeEmptyT() { ++alive; }
@@ -146,7 +197,7 @@
 template <class Variant> void makeEmpty(Variant &v) {
   Variant v2(std::in_place_type<MakeEmptyT>);
   try {
-    v = v2;
+    v = std::move(v2);
     assert(false);
   } catch (...) {
     assert(v.valueless_by_exception());
@@ -171,10 +222,14 @@
     static_assert(std::is_copy_assignable<V>::value, "");
   }
   {
+    using V = std::variant<int, CopyOnly>;
+#ifdef _LIBCPP_VERSION // LWG2904
     // variant only provides copy assignment when both the copy and move
     // constructors are well formed
-    using V = std::variant<int, CopyOnly>;
     static_assert(!std::is_copy_assignable<V>::value, "");
+#else // _LIBCPP_VERSION // LWG2904
+    static_assert(std::is_copy_assignable<V>::value, "");
+#endif // _LIBCPP_VERSION // LWG2904
   }
   {
     using V = std::variant<int, NoCopy>;
@@ -188,6 +243,31 @@
     using V = std::variant<int, MoveOnlyNT>;
     static_assert(!std::is_copy_assignable<V>::value, "");
   }
+
+  // The following tests are for not-yet-standardized behavior (P0602):
+  {
+    using V = std::variant<int, long>;
+    static_assert(std::is_trivially_copy_assignable<V>::value, "");
+  }
+  {
+    using V = std::variant<int, NTCopyAssign>;
+    static_assert(!std::is_trivially_copy_assignable<V>::value, "");
+    static_assert(std::is_copy_assignable<V>::value, "");
+  }
+  {
+    using V = std::variant<int, TCopyAssign>;
+    static_assert(std::is_trivially_copy_assignable<V>::value, "");
+  }
+  {
+    using V = std::variant<int, TCopyAssignNTMoveAssign>;
+    static_assert(std::is_trivially_copy_assignable<V>::value, "");
+  }
+#ifndef _LIBCPP_VERSION // LWG2904
+  {
+    using V = std::variant<int, CopyOnly>;
+    static_assert(std::is_trivially_copy_assignable<V>::value, "");
+  }
+#endif // _LIBCPP_VERSION
 }
 
 void test_copy_assignment_empty_empty() {
@@ -204,7 +284,7 @@
     assert(v1.valueless_by_exception());
     assert(v1.index() == std::variant_npos);
   }
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
 }
 
 void test_copy_assignment_non_empty_empty() {
@@ -230,7 +310,7 @@
     assert(v1.valueless_by_exception());
     assert(v1.index() == std::variant_npos);
   }
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
 }
 
 void test_copy_assignment_empty_non_empty() {
@@ -256,9 +336,11 @@
     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_copy_assignment_same_index() {
   {
     using V = std::variant<int>;
@@ -306,7 +388,65 @@
     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 = 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 = 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<TCopyAssign>, 43);
+        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, "");
+  }
+  {
+    struct {
+      constexpr Result<int> operator()() const {
+        using V = std::variant<int, TCopyAssignNTMoveAssign, unsigned>;
+        V v(std::in_place_type<TCopyAssignNTMoveAssign>, 43);
+        V v2(std::in_place_type<TCopyAssignNTMoveAssign>, 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, "");
+  }
 }
 
 void test_copy_assignment_different_index() {
@@ -338,35 +478,61 @@
   }
 #ifndef TEST_HAS_NO_EXCEPTIONS
   {
-    // Test that if copy construction throws then original value is
-    // unchanged.
     using V = std::variant<int, CopyThrows, std::string>;
     V v1(std::in_place_type<std::string>, "hello");
     V v2(std::in_place_type<CopyThrows>);
     try {
       v1 = v2;
       assert(false);
     } catch (...) { /* ... */
     }
+#ifdef _LIBCPP_VERSION // LWG2904
+    // Test that if copy construction throws then original value is unchanged.
     assert(v1.index() == 2);
     assert(std::get<2>(v1) == "hello");
+#else // _LIBCPP_VERSION // LWG2904
+    // Test that copy construction is used directly if move construction may throw,
+    // resulting in a valueless variant if copy throws.
+    assert(v1.valueless_by_exception());
+#endif // _LIBCPP_VERSION // LWG2904
   }
   {
-    // Test that if move construction throws then the variant is left
-    // valueless by exception.
     using V = std::variant<int, MoveThrows, std::string>;
     V v1(std::in_place_type<std::string>, "hello");
     V v2(std::in_place_type<MoveThrows>);
     assert(MoveThrows::alive == 1);
+#ifdef _LIBCPP_VERSION // LWG2904
+    // Test that if move construction throws then the variant is left
+    // valueless by exception.
     try {
       v1 = v2;
       assert(false);
     } catch (...) { /* ... */
     }
     assert(v1.valueless_by_exception());
     assert(v2.index() == 1);
     assert(MoveThrows::alive == 1);
+#else // _LIBCPP_VERSION // LWG2904
+    // Test that copy construction is used directly if move construction may throw.
+    v1 = v2;
+    assert(v1.index() == 1);
+    assert(v2.index() == 1);
+    assert(MoveThrows::alive == 2);
+#endif // _LIBCPP_VERSION // LWG2904
+  }
+#ifndef _LIBCPP_VERSION // LWG2904
+  {
+    // Test that direct copy construction is preferred when it cannot throw.
+    using V = std::variant<int, CopyCannotThrow, std::string>;
+    V v1(std::in_place_type<std::string>, "hello");
+    V v2(std::in_place_type<CopyCannotThrow>);
+    assert(CopyCannotThrow::alive == 1);
+    v1 = v2;
+    assert(v1.index() == 1);
+    assert(v2.index() == 1);
+    assert(CopyCannotThrow::alive == 2);
   }
+#endif // _LIBCPP_VERSION // LWG2904
   {
     using V = std::variant<int, CopyThrows, std::string>;
     V v1(std::in_place_type<CopyThrows>);
@@ -389,9 +555,60 @@
     assert(v2.index() == 2);
     assert(std::get<2>(v2) == "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 = 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>, 43);
+        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 <size_t NewIdx, class ValueType>
+constexpr bool test_constexpr_assign_extension_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);
 }
 
+void test_constexpr_copy_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_copy_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() {
   test_copy_assignment_empty_empty();
@@ -401,4 +618,5 @@
   test_copy_assignment_different_index();
   test_copy_assignment_sfinae();
   test_copy_assignment_not_noexcept();
+  test_constexpr_copy_assignment_extension();
 }
Index: test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
===================================================================
--- test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
+++ test/std/utilities/variant/variant.variant/variant.assign/T.pass.cpp
@@ -68,6 +68,28 @@
   }
 };
 
+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 {
+    value = v;
+    return *this;
+  }
+};
+
+struct ThrowsCtorTandMove {
+  int value;
+  ThrowsCtorTandMove() : value(0) {}
+  ThrowsCtorTandMove(int) noexcept(false) { throw 42; }
+  ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); }
+  ThrowsCtorTandMove &operator=(int v) noexcept {
+    value = v;
+    return *this;
+  }
+};
+
 struct ThrowsAssignT {
   int value;
   ThrowsAssignT() : value(0) {}
@@ -126,7 +148,7 @@
     using V = std::variant<int, const int &>;
     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
   }
-#endif
+#endif // TEST_VARIANT_HAS_NO_REFERENCES
 }
 
 void test_T_assignment_basic() {
@@ -163,7 +185,7 @@
     assert(v.index() == 2);
     assert(std::get<2>(v) == 42);
   }
-#endif
+#endif // TEST_VARIANT_HAS_NO_REFERENCES
 }
 
 void test_T_assignment_performs_construction() {
@@ -174,18 +196,46 @@
     V v(std::in_place_type<std::string>, "hello");
     try {
       v = 42;
+      assert(false);
     } catch (...) { /* ... */
     }
+#ifdef _LIBCPP_VERSION // LWG2904
     assert(v.valueless_by_exception());
+#else // _LIBCPP_VERSION
+    assert(v.index() == 0);
+    assert(std::get<0>(v) == "hello");
+#endif // _LIBCPP_VERSION
   }
   {
     using V = std::variant<ThrowsAssignT, std::string>;
     V v(std::in_place_type<std::string>, "hello");
     v = 42;
     assert(v.index() == 0);
     assert(std::get<0>(v).value == 42);
   }
-#endif
+#ifdef _LIBCPP_VERSION // LWG2904
+  {
+    // Test that nothrow direct construction is preferred to nothrow move.
+    using V = std::variant<MoveCrashes, std::string>;
+    V v(std::in_place_type<std::string>, "hello");
+    v = 42;
+    assert(v.index() == 0);
+    assert(std::get<0>(v).value == 42);
+  }
+  {
+    // Test that throwing direct construction is preferred to copy-and-move when
+    // move can throw.
+    using V = std::variant<ThrowsCtorTandMove, std::string>;
+    V v(std::in_place_type<std::string>, "hello");
+    try {
+      v = 42;
+      assert(false);
+    } catch(...) { /* ... */
+    }
+    assert(v.valueless_by_exception());
+  }
+#endif // _LIBCPP_VERSION // LWG2904
+#endif // TEST_HAS_NO_EXCEPTIONS
 }
 
 void test_T_assignment_performs_assignment() {
@@ -227,7 +277,7 @@
     assert(v.index() == 1);
     assert(std::get<1>(v).value == 100);
   }
-#endif
+#endif // TEST_HAS_NO_EXCEPTIONS
 }
 
 int main() {
Index: test/libcxx/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
===================================================================
--- test/libcxx/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-//                     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, c++11, c++14
-
-// <variant>
-
-// template <class ...Types> class variant;
-
-// variant(variant&&) noexcept(see below);
-
-#include <type_traits>
-#include <variant>
-
-#include "test_macros.h"
-
-struct NTMove {
-  constexpr NTMove(int v) : value(v) {}
-  NTMove(const NTMove &) = delete;
-  NTMove(NTMove &&that) : value(that.value) { that.value = -1; }
-  int value;
-};
-
-static_assert(!std::is_trivially_move_constructible<NTMove>::value, "");
-static_assert(std::is_move_constructible<NTMove>::value, "");
-
-struct TMove {
-  constexpr TMove(int v) : value(v) {}
-  TMove(const TMove &) = delete;
-  TMove(TMove &&) = default;
-  int value;
-};
-
-static_assert(std::is_trivially_move_constructible<TMove>::value, "");
-
-struct TMoveNTCopy {
-  constexpr TMoveNTCopy(int v) : value(v) {}
-  TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {}
-  TMoveNTCopy(TMoveNTCopy&&) = default;
-  int value;
-};
-
-static_assert(std::is_trivially_move_constructible<TMoveNTCopy>::value, "");
-
-void test_move_ctor_sfinae() {
-  {
-    using V = std::variant<int, long>;
-    static_assert(std::is_trivially_move_constructible<V>::value, "");
-  }
-  {
-    using V = std::variant<int, NTMove>;
-    static_assert(!std::is_trivially_move_constructible<V>::value, "");
-    static_assert(std::is_move_constructible<V>::value, "");
-  }
-  {
-    using V = std::variant<int, TMove>;
-    static_assert(std::is_trivially_move_constructible<V>::value, "");
-  }
-  {
-    using V = std::variant<int, TMoveNTCopy>;
-    static_assert(std::is_trivially_move_constructible<V>::value, "");
-  }
-}
-
-template <typename T>
-struct Result { size_t index; T value; };
-
-void test_move_ctor_basic() {
-  {
-    struct {
-      constexpr Result<int> operator()() const {
-        std::variant<int> v(std::in_place_index<0>, 42);
-        std::variant<int> v2 = std::move(v);
-        return {v2.index(), std::get<0>(std::move(v2))};
-      }
-    } test;
-    constexpr auto result = test();
-    static_assert(result.index == 0, "");
-    static_assert(result.value == 42, "");
-  }
-  {
-    struct {
-      constexpr Result<long> operator()() const {
-        std::variant<int, long> v(std::in_place_index<1>, 42);
-        std::variant<int, long> v2 = std::move(v);
-        return {v2.index(), std::get<1>(std::move(v2))};
-      }
-    } test;
-    constexpr auto result = test();
-    static_assert(result.index == 1, "");
-    static_assert(result.value == 42, "");
-  }
-  {
-    struct {
-      constexpr Result<TMove> operator()() const {
-        std::variant<TMove> v(std::in_place_index<0>, 42);
-        std::variant<TMove> v2(std::move(v));
-        return {v2.index(), std::get<0>(std::move(v2))};
-      }
-    } test;
-    constexpr auto result = test();
-    static_assert(result.index == 0, "");
-    static_assert(result.value.value == 42, "");
-  }
-  {
-    struct {
-      constexpr Result<TMove> operator()() const {
-        std::variant<int, TMove> v(std::in_place_index<1>, 42);
-        std::variant<int, TMove> v2(std::move(v));
-        return {v2.index(), std::get<1>(std::move(v2))};
-      }
-    } test;
-    constexpr auto result = test();
-    static_assert(result.index == 1, "");
-    static_assert(result.value.value == 42, "");
-  }
-  {
-    struct {
-      constexpr Result<TMoveNTCopy> operator()() const {
-        std::variant<TMoveNTCopy> v(std::in_place_index<0>, 42);
-        std::variant<TMoveNTCopy> v2(std::move(v));
-        return {v2.index(), std::get<0>(std::move(v2))};
-      }
-    } test;
-    constexpr auto result = test();
-    static_assert(result.index == 0, "");
-    static_assert(result.value.value == 42, "");
-  }
-  {
-    struct {
-      constexpr Result<TMoveNTCopy> operator()() const {
-        std::variant<int, TMoveNTCopy> v(std::in_place_index<1>, 42);
-        std::variant<int, TMoveNTCopy> v2(std::move(v));
-        return {v2.index(), std::get<1>(std::move(v2))};
-      }
-    } test;
-    constexpr auto result = test();
-    static_assert(result.index == 1, "");
-    static_assert(result.value.value == 42, "");
-  }
-}
-
-int main() {
-  test_move_ctor_basic();
-  test_move_ctor_sfinae();
-}
Index: test/libcxx/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
===================================================================
--- test/libcxx/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-//                     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, c++11, c++14
-
-// <variant>
-
-// template <class ...Types> class variant;
-
-// variant(variant const&);
-
-#include <type_traits>
-#include <variant>
-
-#include "test_macros.h"
-
-struct NTCopy {
-  constexpr NTCopy(int v) : value(v) {}
-  NTCopy(const NTCopy &that) : value(that.value) {}
-  NTCopy(NTCopy &&) = delete;
-  int value;
-};
-
-static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, "");
-static_assert(std::is_copy_constructible<NTCopy>::value, "");
-
-struct TCopy {
-  constexpr TCopy(int v) : value(v) {}
-  TCopy(TCopy const &) = default;
-  TCopy(TCopy &&) = delete;
-  int value;
-};
-
-static_assert(std::is_trivially_copy_constructible<TCopy>::value, "");
-
-struct TCopyNTMove {
-  constexpr TCopyNTMove(int v) : value(v) {}
-  TCopyNTMove(const TCopyNTMove&) = default;
-  TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; }
-  int value;
-};
-
-static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "");
-
-void test_copy_ctor_sfinae() {
-  {
-    using V = std::variant<int, long>;
-    static_assert(std::is_trivially_copy_constructible<V>::value, "");
-  }
-  {
-    using V = std::variant<int, NTCopy>;
-    static_assert(!std::is_trivially_copy_constructible<V>::value, "");
-    static_assert(std::is_copy_constructible<V>::value, "");
-  }
-  {
-    using V = std::variant<int, TCopy>;
-    static_assert(std::is_trivially_copy_constructible<V>::value, "");
-  }
-  {
-    using V = std::variant<int, TCopyNTMove>;
-    static_assert(std::is_trivially_copy_constructible<V>::value, "");
-  }
-}
-
-void test_copy_ctor_basic() {
-  {
-    constexpr std::variant<int> v(std::in_place_index<0>, 42);
-    static_assert(v.index() == 0, "");
-    constexpr std::variant<int> v2 = v;
-    static_assert(v2.index() == 0, "");
-    static_assert(std::get<0>(v2) == 42, "");
-  }
-  {
-    constexpr std::variant<int, long> v(std::in_place_index<1>, 42);
-    static_assert(v.index() == 1, "");
-    constexpr std::variant<int, long> v2 = v;
-    static_assert(v2.index() == 1, "");
-    static_assert(std::get<1>(v2) == 42, "");
-  }
-  {
-    constexpr std::variant<TCopy> v(std::in_place_index<0>, 42);
-    static_assert(v.index() == 0, "");
-    constexpr std::variant<TCopy> v2(v);
-    static_assert(v2.index() == 0, "");
-    static_assert(std::get<0>(v2).value == 42, "");
-  }
-  {
-    constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42);
-    static_assert(v.index() == 1, "");
-    constexpr std::variant<int, TCopy> v2(v);
-    static_assert(v2.index() == 1, "");
-    static_assert(std::get<1>(v2).value == 42, "");
-  }
-  {
-    constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42);
-    static_assert(v.index() == 0, "");
-    constexpr std::variant<TCopyNTMove> v2(v);
-    static_assert(v2.index() == 0, "");
-    static_assert(std::get<0>(v2).value == 42, "");
-  }
-  {
-    constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42);
-    static_assert(v.index() == 1, "");
-    constexpr std::variant<int, TCopyNTMove> v2(v);
-    static_assert(v2.index() == 1, "");
-    static_assert(std::get<1>(v2).value == 42, "");
-  }
-}
-
-int main() {
-  test_copy_ctor_basic();
-  test_copy_ctor_sfinae();
-}
Index: test/libcxx/utilities/variant/variant.variant/variant.assign/move.pass.cpp
===================================================================
--- test/libcxx/utilities/variant/variant.variant/variant.assign/move.pass.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-//                     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, 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
-
-// <variant>
-
-// template <class ...Types> class variant;
-
-// variant& operator=(variant&&) noexcept(see below);
-
-#include <type_traits>
-#include <variant>
-
-#include "test_macros.h"
-
-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>, "");
-
-void test_move_assignment_sfinae() {
-  {
-    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, "");
-  }
-}
-
-template <typename T> struct Result { size_t index; T value; };
-
-void test_move_assignment_same_index() {
-  {
-    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() {
-  {
-    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() {
-#ifdef _LIBCPP_VERSION
-  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), "");
-#endif
-}
-
-int main() {
-  test_move_assignment_same_index();
-  test_move_assignment_different_index();
-  test_move_assignment_sfinae();
-  test_constexpr_move_assignment_extension();
-}
Index: test/libcxx/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
===================================================================
--- test/libcxx/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-//                     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, 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
-
-// <variant>
-
-// template <class ...Types> class variant;
-
-// variant& operator=(variant const&);
-
-#include <type_traits>
-#include <variant>
-
-#include "test_macros.h"
-
-struct NTCopyAssign {
-  constexpr NTCopyAssign(int v) : value(v) {}
-  NTCopyAssign(const NTCopyAssign &) = default;
-  NTCopyAssign(NTCopyAssign &&) = default;
-  NTCopyAssign &operator=(const NTCopyAssign &that) {
-    value = that.value;
-    return *this;
-  };
-  NTCopyAssign &operator=(NTCopyAssign &&) = delete;
-  int value;
-};
-
-static_assert(!std::is_trivially_copy_assignable<NTCopyAssign>::value, "");
-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;
-  int value;
-};
-
-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;
-    that.value = -1;
-    return *this;
-  }
-  int value;
-};
-
-static_assert(std::is_trivially_copy_assignable_v<TCopyAssignNTMoveAssign>, "");
-
-void test_copy_assignment_sfinae() {
-  {
-    using V = std::variant<int, long>;
-    static_assert(std::is_trivially_copy_assignable<V>::value, "");
-  }
-  {
-    using V = std::variant<int, NTCopyAssign>;
-    static_assert(!std::is_trivially_copy_assignable<V>::value, "");
-    static_assert(std::is_copy_assignable<V>::value, "");
-  }
-  {
-    using V = std::variant<int, TCopyAssign>;
-    static_assert(std::is_trivially_copy_assignable<V>::value, "");
-  }
-  {
-    using V = std::variant<int, TCopyAssignNTMoveAssign>;
-    static_assert(std::is_trivially_copy_assignable<V>::value, "");
-  }
-}
-
-template <typename T> struct Result { size_t index; T value; };
-
-void test_copy_assignment_same_index() {
-  {
-    struct {
-      constexpr Result<int> operator()() const {
-        using V = std::variant<int>;
-        V v(43);
-        V v2(42);
-        v = 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 = 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<TCopyAssign>, 43);
-        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, "");
-  }
-  {
-    struct {
-      constexpr Result<int> operator()() const {
-        using V = std::variant<int, TCopyAssignNTMoveAssign, unsigned>;
-        V v(std::in_place_type<TCopyAssignNTMoveAssign>, 43);
-        V v2(std::in_place_type<TCopyAssignNTMoveAssign>, 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, "");
-  }
-}
-
-void test_copy_assignment_different_index() {
-  {
-    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>, 43);
-        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 <size_t NewIdx, class ValueType>
-constexpr bool test_constexpr_assign_extension_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);
-}
-
-void test_constexpr_copy_assignment_extension() {
-#ifdef _LIBCPP_VERSION
-  using V = std::variant<long, void*, int>;
-  static_assert(std::is_trivially_copyable<V>::value, "");
-  static_assert(std::is_trivially_copy_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), "");
-#endif
-}
-
-int main() {
-  test_copy_assignment_same_index();
-  test_copy_assignment_different_index();
-  test_copy_assignment_sfinae();
-  test_constexpr_copy_assignment_extension();
-}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to