[libcxx] r350884 - [libcxx] Reorganize tests since the application of P0602R4

Louis Dionne ldionne at apple.com
Thu Jan 10 12:06:12 PST 2019


Author: ldionne
Date: Thu Jan 10 12:06:11 2019
New Revision: 350884

URL: http://llvm.org/viewvc/llvm-project?rev=350884&view=rev
Log:
[libcxx] Reorganize tests since the application of P0602R4

Summary:
P0602R4 makes the special member functions of optional and variant
conditionally trivial based on the types in the optional/variant.
We already implemented that, but the tests were organized as if this
were a non-standard extension. This patch reorganizes the tests in a
way that makes more sense since this is not an extension anymore.

Reviewers: EricWF, mpark, mclow.lists

Subscribers: christof, jkorous, dexonsmith, libcxx-commits

Differential Revision: https://reviews.llvm.org/D54772

Added:
    libcxx/trunk/test/libcxx/utilities/optional/optional.object/triviality.abi.pass.cpp
    libcxx/trunk/test/std/utilities/optional/optional.object/special_members.pass.cpp
    libcxx/trunk/test/std/utilities/optional/optional.object/triviality.pass.cpp
Removed:
    libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.fail.cpp
    libcxx/trunk/test/std/utilities/optional/optional.object/special_member_gen.pass.cpp
Modified:
    libcxx/trunk/include/optional
    libcxx/trunk/include/variant
    libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp
    libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp
    libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
    libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
    libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
    libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
    libcxx/trunk/www/cxx2a_status.html

Modified: libcxx/trunk/include/optional
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/optional?rev=350884&r1=350883&r2=350884&view=diff
==============================================================================
--- libcxx/trunk/include/optional (original)
+++ libcxx/trunk/include/optional Thu Jan 10 12:06:11 2019
@@ -105,8 +105,8 @@ namespace std {
 
     // 23.6.3.3, assignment
     optional &operator=(nullopt_t) noexcept;
-    optional &operator=(const optional &);
-    optional &operator=(optional &&) noexcept(see below );
+    optional &operator=(const optional &);                // constexpr in C++20
+    optional &operator=(optional &&) noexcept(see below); // constexpr in C++20
     template <class U = T> optional &operator=(U &&);
     template <class U> optional &operator=(const optional<U> &);
     template <class U> optional &operator=(optional<U> &&);

Modified: libcxx/trunk/include/variant
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/variant?rev=350884&r1=350883&r2=350884&view=diff
==============================================================================
--- libcxx/trunk/include/variant (original)
+++ libcxx/trunk/include/variant Thu Jan 10 12:06:11 2019
@@ -23,8 +23,8 @@ namespace std {
 
     // 20.7.2.1, constructors
     constexpr variant() noexcept(see below);
-    variant(const variant&);
-    variant(variant&&) noexcept(see below);
+    variant(const variant&);                // constexpr in C++20
+    variant(variant&&) noexcept(see below); // constexpr in C++20
 
     template <class T> constexpr variant(T&&) noexcept(see below);
 
@@ -46,8 +46,8 @@ namespace std {
     ~variant();
 
     // 20.7.2.3, assignment
-    variant& operator=(const variant&);
-    variant& operator=(variant&&) noexcept(see below);
+    variant& operator=(const variant&);                // constexpr in C++20
+    variant& operator=(variant&&) noexcept(see below); // constexpr in C++20
 
     template <class T> variant& operator=(T&&) noexcept(see below);
 

Added: libcxx/trunk/test/libcxx/utilities/optional/optional.object/triviality.abi.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/optional/optional.object/triviality.abi.pass.cpp?rev=350884&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/utilities/optional/optional.object/triviality.abi.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/utilities/optional/optional.object/triviality.abi.pass.cpp Thu Jan 10 12:06:11 2019
@@ -0,0 +1,98 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <optional>
+
+// This test asserts the triviality of special member functions of optional<T>
+// whenever T has these special member functions trivial. The goal of this test
+// is to make sure that we do not change the triviality of those, since that
+// constitues an ABI break (small enough optionals would be passed by registers).
+//
+// constexpr optional(const optional& rhs);
+// constexpr optional(optional&& rhs) noexcept(see below);
+// constexpr optional<T>& operator=(const optional& rhs);
+// constexpr optional<T>& operator=(optional&& rhs) noexcept(see below);
+
+#include <optional>
+#include <type_traits>
+#include <cassert>
+
+#include "archetypes.hpp"
+
+template <class T>
+struct SpecialMemberTest {
+    using O = std::optional<T>;
+
+    static_assert(std::is_trivially_destructible_v<O> ==
+        std::is_trivially_destructible_v<T>,
+        "optional<T> is trivially destructible if and only if T is.");
+
+    static_assert(std::is_trivially_copy_constructible_v<O> ==
+        std::is_trivially_copy_constructible_v<T>,
+        "optional<T> is trivially copy constructible if and only if T is.");
+
+    static_assert(std::is_trivially_move_constructible_v<O> ==
+        std::is_trivially_move_constructible_v<T> ||
+        (!std::is_move_constructible_v<T> && std::is_trivially_copy_constructible_v<T>),
+        "optional<T> is trivially move constructible if T is trivially move constructible, "
+        "or if T is trivially copy constructible and is not move constructible.");
+
+    static_assert(std::is_trivially_copy_assignable_v<O> ==
+        (std::is_trivially_destructible_v<T> &&
+         std::is_trivially_copy_constructible_v<T> &&
+         std::is_trivially_copy_assignable_v<T>),
+        "optional<T> is trivially copy assignable if and only if T is trivially destructible, "
+        "trivially copy constructible, and trivially copy assignable.");
+
+    static_assert(std::is_trivially_move_assignable_v<O> ==
+        (std::is_trivially_destructible_v<T> &&
+         ((std::is_trivially_move_constructible_v<T> && std::is_trivially_move_assignable_v<T>) ||
+          ((!std::is_move_constructible_v<T> || !std::is_move_assignable_v<T>) &&
+           std::is_trivially_copy_constructible_v<T> && std::is_trivially_copy_assignable_v<T>))),
+        "optional<T> is trivially move assignable if T is trivially destructible, and either "
+        "(1) trivially move constructible and trivially move assignable, or "
+        "(2) not move constructible or not move assignable, and "
+        "trivially copy constructible and trivially copy assignable.");
+};
+
+template <class ...Args> static void sink(Args&&...) {}
+
+template <class ...TestTypes>
+struct DoTestsMetafunction {
+    DoTestsMetafunction() { sink(SpecialMemberTest<TestTypes>{}...); }
+};
+
+struct TrivialMoveNonTrivialCopy {
+    TrivialMoveNonTrivialCopy() = default;
+    TrivialMoveNonTrivialCopy(const TrivialMoveNonTrivialCopy&) {}
+    TrivialMoveNonTrivialCopy(TrivialMoveNonTrivialCopy&&) = default;
+    TrivialMoveNonTrivialCopy& operator=(const TrivialMoveNonTrivialCopy&) { return *this; }
+    TrivialMoveNonTrivialCopy& operator=(TrivialMoveNonTrivialCopy&&) = default;
+};
+
+struct TrivialCopyNonTrivialMove {
+    TrivialCopyNonTrivialMove() = default;
+    TrivialCopyNonTrivialMove(const TrivialCopyNonTrivialMove&) = default;
+    TrivialCopyNonTrivialMove(TrivialCopyNonTrivialMove&&) {}
+    TrivialCopyNonTrivialMove& operator=(const TrivialCopyNonTrivialMove&) = default;
+    TrivialCopyNonTrivialMove& operator=(TrivialCopyNonTrivialMove&&) { return *this; }
+};
+
+int main()
+{
+    sink(
+        ImplicitTypes::ApplyTypes<DoTestsMetafunction>{},
+        ExplicitTypes::ApplyTypes<DoTestsMetafunction>{},
+        NonLiteralTypes::ApplyTypes<DoTestsMetafunction>{},
+        NonTrivialTypes::ApplyTypes<DoTestsMetafunction>{},
+        DoTestsMetafunction<TrivialMoveNonTrivialCopy, TrivialCopyNonTrivialMove>{}
+    );
+}

Modified: libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp?rev=350884&r1=350883&r2=350884&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp Thu Jan 10 12:06:11 2019
@@ -10,7 +10,7 @@
 // UNSUPPORTED: c++98, c++03, c++11, c++14
 // <optional>
 
-// optional<T>& operator=(const optional<T>& rhs);
+// optional<T>& operator=(const optional<T>& rhs); // constexpr in C++20
 
 #include <optional>
 #include <type_traits>
@@ -53,15 +53,19 @@ int main()
 {
     {
         using O = optional<int>;
+#if TEST_STD_VER > 17
         LIBCPP_STATIC_ASSERT(assign_empty(O{42}), "");
         LIBCPP_STATIC_ASSERT(assign_value(O{42}), "");
+#endif
         assert(assign_empty(O{42}));
         assert(assign_value(O{42}));
     }
     {
         using O = optional<TrivialTestTypes::TestType>;
+#if TEST_STD_VER > 17
         LIBCPP_STATIC_ASSERT(assign_empty(O{42}), "");
         LIBCPP_STATIC_ASSERT(assign_value(O{42}), "");
+#endif
         assert(assign_empty(O{42}));
         assert(assign_value(O{42}));
     }

Modified: libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp?rev=350884&r1=350883&r2=350884&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp Thu Jan 10 12:06:11 2019
@@ -12,11 +12,12 @@
 
 // optional<T>& operator=(optional<T>&& rhs)
 //     noexcept(is_nothrow_move_assignable<T>::value &&
-//              is_nothrow_move_constructible<T>::value);
+//              is_nothrow_move_constructible<T>::value); // constexpr in C++20
 
 #include <optional>
-#include <type_traits>
 #include <cassert>
+#include <type_traits>
+#include <utility>
 
 #include "test_macros.h"
 #include "archetypes.hpp"
@@ -51,6 +52,21 @@ struct Y {};
 bool X::throw_now = false;
 int X::alive = 0;
 
+
+template <class Tp>
+constexpr bool assign_empty(optional<Tp>&& lhs) {
+    optional<Tp> rhs;
+    lhs = std::move(rhs);
+    return !lhs.has_value() && !rhs.has_value();
+}
+
+template <class Tp>
+constexpr bool assign_value(optional<Tp>&& lhs) {
+    optional<Tp> rhs(101);
+    lhs = std::move(rhs);
+    return lhs.has_value() && rhs.has_value() && *lhs == Tp{101};
+}
+
 int main()
 {
     {
@@ -97,6 +113,24 @@ int main()
         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
         assert(*opt == *opt2);
     }
+    {
+        using O = optional<int>;
+#if TEST_STD_VER > 17
+        LIBCPP_STATIC_ASSERT(assign_empty(O{42}), "");
+        LIBCPP_STATIC_ASSERT(assign_value(O{42}), "");
+#endif
+        assert(assign_empty(O{42}));
+        assert(assign_value(O{42}));
+    }
+    {
+        using O = optional<TrivialTestTypes::TestType>;
+#if TEST_STD_VER > 17
+        LIBCPP_STATIC_ASSERT(assign_empty(O{42}), "");
+        LIBCPP_STATIC_ASSERT(assign_value(O{42}), "");
+#endif
+        assert(assign_empty(O{42}));
+        assert(assign_value(O{42}));
+    }
 #ifndef TEST_HAS_NO_EXCEPTIONS
     {
         static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, "");

Removed: libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.fail.cpp?rev=350883&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.fail.cpp (original)
+++ libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.fail.cpp (removed)
@@ -1,36 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     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
-// <optional>
-
-// constexpr optional(const optional<T>& rhs);
-//   If is_trivially_copy_constructible_v<T> is true,
-//    this constructor shall be a constexpr constructor.
-
-#include <optional>
-#include <type_traits>
-#include <cassert>
-
-#include "test_macros.h"
-
-struct S {
-    constexpr S()   : v_(0) {}
-    S(int v)        : v_(v) {}
-    S(const S &rhs) : v_(rhs.v_) {}  // make it not trivially copyable
-    int v_;
-};
-
-
-int main()
-{
-    static_assert (!std::is_trivially_copy_constructible_v<S>, "" );
-    constexpr std::optional<S> o1;
-    constexpr std::optional<S> o2 = o1;  // not constexpr
-}

Removed: libcxx/trunk/test/std/utilities/optional/optional.object/special_member_gen.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/optional/optional.object/special_member_gen.pass.cpp?rev=350883&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/optional/optional.object/special_member_gen.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/optional/optional.object/special_member_gen.pass.cpp (removed)
@@ -1,102 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     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
-// <optional>
-
-
-#include <optional>
-#include <type_traits>
-#include <cassert>
-
-#include "archetypes.hpp"
-
-template <class T>
-struct SpecialMemberTest {
-    using O = std::optional<T>;
-
-    static_assert(std::is_default_constructible_v<O>,
-        "optional is always default constructible.");
-    static_assert(std::is_copy_constructible_v<O> == std::is_copy_constructible_v<T>,
-        "optional<T> is copy constructible if and only if T is copy constructible.");
-    static_assert(std::is_move_constructible_v<O> ==
-        (std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>),
-        "optional<T> is move constructible if and only if T is copy or move constructible.");
-    static_assert(std::is_copy_assignable_v<O> ==
-        (std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>),
-        "optional<T> is copy assignable if and only if T is both copy "
-        "constructible and copy assignable.");
-    static_assert(std::is_move_assignable_v<O> ==
-        ((std::is_move_constructible_v<T> && std::is_move_assignable_v<T>) ||
-         (std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>)),
-        "optional<T> is move assignable if and only if T is both move constructible and "
-        "move assignable, or both copy constructible and copy assignable.");
-
-    // The following tests are for not-yet-standardized behavior (P0602):
-    static_assert(std::is_trivially_destructible_v<O> ==
-        std::is_trivially_destructible_v<T>,
-        "optional<T> is trivially destructible if and only if T is.");
-    static_assert(std::is_trivially_copy_constructible_v<O> ==
-        std::is_trivially_copy_constructible_v<T>,
-        "optional<T> is trivially copy constructible if and only if T is.");
-    static_assert(std::is_trivially_move_constructible_v<O> ==
-        std::is_trivially_move_constructible_v<T> ||
-        (!std::is_move_constructible_v<T> && std::is_trivially_copy_constructible_v<T>),
-        "optional<T> is trivially move constructible if T is trivially move constructible, "
-        "or if T is trivially copy constructible and is not move constructible.");
-    static_assert(std::is_trivially_copy_assignable_v<O> ==
-        (std::is_trivially_destructible_v<T> &&
-         std::is_trivially_copy_constructible_v<T> &&
-         std::is_trivially_copy_assignable_v<T>),
-        "optional<T> is trivially copy assignable if and only if T is trivially destructible, "
-        "trivially copy constructible, and trivially copy assignable.");
-    static_assert(std::is_trivially_move_assignable_v<O> ==
-        (std::is_trivially_destructible_v<T> &&
-         ((std::is_trivially_move_constructible_v<T> && std::is_trivially_move_assignable_v<T>) ||
-          ((!std::is_move_constructible_v<T> || !std::is_move_assignable_v<T>) &&
-           std::is_trivially_copy_constructible_v<T> && std::is_trivially_copy_assignable_v<T>))),
-        "optional<T> is trivially move assignable if T is trivially destructible, and either "
-        "(1) trivially move constructible and trivially move assignable, or "
-        "(2) not move constructible or not move assignable, and "
-        "trivially copy constructible and trivially copy assignable.");
-};
-
-template <class ...Args> static void sink(Args&&...) {}
-
-template <class ...TestTypes>
-struct DoTestsMetafunction {
-    DoTestsMetafunction() { sink(SpecialMemberTest<TestTypes>{}...); }
-};
-
-struct TrivialMoveNonTrivialCopy {
-    TrivialMoveNonTrivialCopy() = default;
-    TrivialMoveNonTrivialCopy(const TrivialMoveNonTrivialCopy&) {}
-    TrivialMoveNonTrivialCopy(TrivialMoveNonTrivialCopy&&) = default;
-    TrivialMoveNonTrivialCopy& operator=(const TrivialMoveNonTrivialCopy&) { return *this; }
-    TrivialMoveNonTrivialCopy& operator=(TrivialMoveNonTrivialCopy&&) = default;
-};
-
-struct TrivialCopyNonTrivialMove {
-    TrivialCopyNonTrivialMove() = default;
-    TrivialCopyNonTrivialMove(const TrivialCopyNonTrivialMove&) = default;
-    TrivialCopyNonTrivialMove(TrivialCopyNonTrivialMove&&) {}
-    TrivialCopyNonTrivialMove& operator=(const TrivialCopyNonTrivialMove&) = default;
-    TrivialCopyNonTrivialMove& operator=(TrivialCopyNonTrivialMove&&) { return *this; }
-};
-
-int main()
-{
-    sink(
-        ImplicitTypes::ApplyTypes<DoTestsMetafunction>{},
-        ExplicitTypes::ApplyTypes<DoTestsMetafunction>{},
-        NonLiteralTypes::ApplyTypes<DoTestsMetafunction>{},
-        NonTrivialTypes::ApplyTypes<DoTestsMetafunction>{},
-        DoTestsMetafunction<TrivialMoveNonTrivialCopy, TrivialCopyNonTrivialMove>{}
-    );
-}

Added: libcxx/trunk/test/std/utilities/optional/optional.object/special_members.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/optional/optional.object/special_members.pass.cpp?rev=350884&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/optional/optional.object/special_members.pass.cpp (added)
+++ libcxx/trunk/test/std/utilities/optional/optional.object/special_members.pass.cpp Thu Jan 10 12:06:11 2019
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <optional>
+
+// Make sure we properly generate special member functions for optional<T>
+// based on the properties of T itself.
+
+#include <optional>
+#include <type_traits>
+
+#include "archetypes.hpp"
+
+
+template <class T>
+struct SpecialMemberTest {
+    using O = std::optional<T>;
+
+    static_assert(std::is_default_constructible_v<O>,
+        "optional is always default constructible.");
+
+    static_assert(std::is_copy_constructible_v<O> == std::is_copy_constructible_v<T>,
+        "optional<T> is copy constructible if and only if T is copy constructible.");
+
+    static_assert(std::is_move_constructible_v<O> ==
+        (std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>),
+        "optional<T> is move constructible if and only if T is copy or move constructible.");
+
+    static_assert(std::is_copy_assignable_v<O> ==
+        (std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>),
+        "optional<T> is copy assignable if and only if T is both copy "
+        "constructible and copy assignable.");
+
+    static_assert(std::is_move_assignable_v<O> ==
+        ((std::is_move_constructible_v<T> && std::is_move_assignable_v<T>) ||
+         (std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>)),
+        "optional<T> is move assignable if and only if T is both move constructible and "
+        "move assignable, or both copy constructible and copy assignable.");
+};
+
+template <class ...Args> static void sink(Args&&...) {}
+
+template <class ...TestTypes>
+struct DoTestsMetafunction {
+    DoTestsMetafunction() { sink(SpecialMemberTest<TestTypes>{}...); }
+};
+
+int main() {
+    sink(
+        ImplicitTypes::ApplyTypes<DoTestsMetafunction>{},
+        ExplicitTypes::ApplyTypes<DoTestsMetafunction>{},
+        NonLiteralTypes::ApplyTypes<DoTestsMetafunction>{},
+        NonTrivialTypes::ApplyTypes<DoTestsMetafunction>{}
+    );
+}

Added: libcxx/trunk/test/std/utilities/optional/optional.object/triviality.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/optional/optional.object/triviality.pass.cpp?rev=350884&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/optional/optional.object/triviality.pass.cpp (added)
+++ libcxx/trunk/test/std/utilities/optional/optional.object/triviality.pass.cpp Thu Jan 10 12:06:11 2019
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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, c++17
+
+// <optional>
+
+// The following special member functions should propagate the triviality of
+// the element held in the optional (see P0602R4):
+//
+// constexpr optional(const optional& rhs);
+// constexpr optional(optional&& rhs) noexcept(see below);
+// constexpr optional<T>& operator=(const optional& rhs);
+// constexpr optional<T>& operator=(optional&& rhs) noexcept(see below);
+
+
+#include <optional>
+#include <type_traits>
+
+#include "archetypes.hpp"
+
+
+constexpr bool implies(bool p, bool q) {
+    return !p || q;
+}
+
+template <class T>
+struct SpecialMemberTest {
+    using O = std::optional<T>;
+
+    static_assert(implies(std::is_trivially_copy_constructible_v<T>,
+                          std::is_trivially_copy_constructible_v<O>),
+        "optional<T> is trivially copy constructible if T is trivially copy constructible.");
+
+    static_assert(implies(std::is_trivially_move_constructible_v<T>,
+                          std::is_trivially_move_constructible_v<O>),
+        "optional<T> is trivially move constructible if T is trivially move constructible");
+
+    static_assert(implies(std::is_trivially_copy_constructible_v<T> &&
+                          std::is_trivially_copy_assignable_v<T> &&
+                          std::is_trivially_destructible_v<T>,
+
+                          std::is_trivially_copy_assignable_v<O>),
+        "optional<T> is trivially copy assignable if T is "
+        "trivially copy constructible, "
+        "trivially copy assignable, and "
+        "trivially destructible");
+
+    static_assert(implies(std::is_trivially_move_constructible_v<T> &&
+                          std::is_trivially_move_assignable_v<T> &&
+                          std::is_trivially_destructible_v<T>,
+
+                          std::is_trivially_move_assignable_v<O>),
+        "optional<T> is trivially move assignable if T is "
+        "trivially move constructible, "
+        "trivially move assignable, and"
+        "trivially destructible.");
+};
+
+template <class ...Args> static void sink(Args&&...) {}
+
+template <class ...TestTypes>
+struct DoTestsMetafunction {
+    DoTestsMetafunction() { sink(SpecialMemberTest<TestTypes>{}...); }
+};
+
+struct TrivialMoveNonTrivialCopy {
+    TrivialMoveNonTrivialCopy() = default;
+    TrivialMoveNonTrivialCopy(const TrivialMoveNonTrivialCopy&) {}
+    TrivialMoveNonTrivialCopy(TrivialMoveNonTrivialCopy&&) = default;
+    TrivialMoveNonTrivialCopy& operator=(const TrivialMoveNonTrivialCopy&) { return *this; }
+    TrivialMoveNonTrivialCopy& operator=(TrivialMoveNonTrivialCopy&&) = default;
+};
+
+struct TrivialCopyNonTrivialMove {
+    TrivialCopyNonTrivialMove() = default;
+    TrivialCopyNonTrivialMove(const TrivialCopyNonTrivialMove&) = default;
+    TrivialCopyNonTrivialMove(TrivialCopyNonTrivialMove&&) {}
+    TrivialCopyNonTrivialMove& operator=(const TrivialCopyNonTrivialMove&) = default;
+    TrivialCopyNonTrivialMove& operator=(TrivialCopyNonTrivialMove&&) { return *this; }
+};
+
+int main() {
+    sink(
+        ImplicitTypes::ApplyTypes<DoTestsMetafunction>{},
+        ExplicitTypes::ApplyTypes<DoTestsMetafunction>{},
+        NonLiteralTypes::ApplyTypes<DoTestsMetafunction>{},
+        NonTrivialTypes::ApplyTypes<DoTestsMetafunction>{},
+        DoTestsMetafunction<TrivialMoveNonTrivialCopy, TrivialCopyNonTrivialMove>{}
+    );
+}

Modified: libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp?rev=350884&r1=350883&r2=350884&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp Thu Jan 10 12:06:11 2019
@@ -26,7 +26,7 @@
 
 // template <class ...Types> class variant;
 
-// variant& operator=(variant const&);
+// variant& operator=(variant const&); // constexpr in C++20
 
 #include <cassert>
 #include <string>
@@ -240,7 +240,8 @@ void test_copy_assignment_sfinae() {
     static_assert(!std::is_copy_assignable<V>::value, "");
   }
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality (see P0602R4).
+#if TEST_STD_VER > 17
   {
     using V = std::variant<int, long>;
     static_assert(std::is_trivially_copy_assignable<V>::value, "");
@@ -262,6 +263,7 @@ void test_copy_assignment_sfinae() {
     using V = std::variant<int, CopyOnly>;
     static_assert(std::is_trivially_copy_assignable<V>::value, "");
   }
+#endif // > C++17
 }
 
 void test_copy_assignment_empty_empty() {
@@ -384,7 +386,8 @@ void test_copy_assignment_same_index() {
   }
 #endif // TEST_HAS_NO_EXCEPTIONS
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   {
     struct {
       constexpr Result<int> operator()() const {
@@ -441,6 +444,7 @@ void test_copy_assignment_same_index() {
     static_assert(result.index == 1, "");
     static_assert(result.value == 42, "");
   }
+#endif // > C++17
 }
 
 void test_copy_assignment_different_index() {
@@ -530,7 +534,8 @@ void test_copy_assignment_different_inde
   }
 #endif // TEST_HAS_NO_EXCEPTIONS
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   {
     struct {
       constexpr Result<long> operator()() const {
@@ -559,10 +564,11 @@ void test_copy_assignment_different_inde
     static_assert(result.index == 1, "");
     static_assert(result.value == 42, "");
   }
+#endif // > C++17
 }
 
 template <size_t NewIdx, class ValueType>
-constexpr bool test_constexpr_assign_extension_imp(
+constexpr bool test_constexpr_assign_imp(
     std::variant<long, void*, int>&& v, ValueType&& new_value)
 {
   const std::variant<long, void*, int> cp(
@@ -572,15 +578,17 @@ constexpr bool test_constexpr_assign_ext
         std::get<NewIdx>(v) == std::get<NewIdx>(cp);
 }
 
-void test_constexpr_copy_assignment_extension() {
-  // The following tests are for not-yet-standardized behavior (P0602):
+void test_constexpr_copy_assignment() {
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   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), "");
+  static_assert(test_constexpr_assign_imp<0>(V(42l), 101l), "");
+  static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), "");
+  static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), "");
+  static_assert(test_constexpr_assign_imp<2>(V(42l), 101), "");
+#endif // > C++17
 }
 
 int main() {
@@ -591,5 +599,5 @@ int main() {
   test_copy_assignment_different_index();
   test_copy_assignment_sfinae();
   test_copy_assignment_not_noexcept();
-  test_constexpr_copy_assignment_extension();
+  test_constexpr_copy_assignment();
 }

Modified: libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp?rev=350884&r1=350883&r2=350884&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp Thu Jan 10 12:06:11 2019
@@ -27,7 +27,7 @@
 
 // template <class ...Types> class variant;
 
-// variant& operator=(variant&&) noexcept(see below);
+// variant& operator=(variant&&) noexcept(see below); // constexpr in C++20
 
 #include <cassert>
 #include <string>
@@ -206,7 +206,8 @@ void test_move_assignment_sfinae() {
     static_assert(!std::is_move_assignable<V>::value, "");
   }
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality (see P0602R4).
+#if TEST_STD_VER > 17
   {
     using V = std::variant<int, long>;
     static_assert(std::is_trivially_move_assignable<V>::value, "");
@@ -232,6 +233,7 @@ void test_move_assignment_sfinae() {
     using V = std::variant<int, CopyOnly>;
     static_assert(std::is_trivially_move_assignable<V>::value, "");
   }
+#endif // > C++17
 }
 
 void test_move_assignment_empty_empty() {
@@ -353,7 +355,8 @@ void test_move_assignment_same_index() {
   }
 #endif // TEST_HAS_NO_EXCEPTIONS
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   {
     struct {
       constexpr Result<int> operator()() const {
@@ -396,6 +399,7 @@ void test_move_assignment_same_index() {
     static_assert(result.index == 1, "");
     static_assert(result.value == 42, "");
   }
+#endif // > C++17
 }
 
 void test_move_assignment_different_index() {
@@ -445,7 +449,8 @@ void test_move_assignment_different_inde
   }
 #endif // TEST_HAS_NO_EXCEPTIONS
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   {
     struct {
       constexpr Result<long> operator()() const {
@@ -474,10 +479,11 @@ void test_move_assignment_different_inde
     static_assert(result.index == 1, "");
     static_assert(result.value == 42, "");
   }
+#endif // > C++17
 }
 
 template <size_t NewIdx, class ValueType>
-constexpr bool test_constexpr_assign_extension_imp(
+constexpr bool test_constexpr_assign_imp(
     std::variant<long, void*, int>&& v, ValueType&& new_value)
 {
   std::variant<long, void*, int> v2(
@@ -488,15 +494,17 @@ constexpr bool test_constexpr_assign_ext
         std::get<NewIdx>(v) == std::get<NewIdx>(cp);
 }
 
-void test_constexpr_move_assignment_extension() {
-  // The following tests are for not-yet-standardized behavior (P0602):
+void test_constexpr_move_assignment() {
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   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), "");
+  static_assert(test_constexpr_assign_imp<0>(V(42l), 101l), "");
+  static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), "");
+  static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), "");
+  static_assert(test_constexpr_assign_imp<2>(V(42l), 101), "");
+#endif // > C++17
 }
 
 int main() {
@@ -507,5 +515,5 @@ int main() {
   test_move_assignment_different_index();
   test_move_assignment_sfinae();
   test_move_assignment_noexcept();
-  test_constexpr_move_assignment_extension();
+  test_constexpr_move_assignment();
 }

Modified: libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp?rev=350884&r1=350883&r2=350884&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp Thu Jan 10 12:06:11 2019
@@ -22,7 +22,7 @@
 
 // template <class ...Types> class variant;
 
-// variant(variant const&);
+// variant(variant const&); // constexpr in C++20
 
 #include <cassert>
 #include <type_traits>
@@ -126,7 +126,8 @@ void test_copy_ctor_sfinae() {
     static_assert(!std::is_copy_constructible<V>::value, "");
   }
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality (see P0602R4).
+#if TEST_STD_VER > 17
   {
     using V = std::variant<int, long>;
     static_assert(std::is_trivially_copy_constructible<V>::value, "");
@@ -144,6 +145,7 @@ void test_copy_ctor_sfinae() {
     using V = std::variant<int, TCopyNTMove>;
     static_assert(std::is_trivially_copy_constructible<V>::value, "");
   }
+#endif // > C++17
 }
 
 void test_copy_ctor_basic() {
@@ -174,7 +176,8 @@ void test_copy_ctor_basic() {
     assert(std::get<1>(v2).value == 42);
   }
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   {
     constexpr std::variant<int> v(std::in_place_index<0>, 42);
     static_assert(v.index() == 0, "");
@@ -217,6 +220,7 @@ void test_copy_ctor_basic() {
     static_assert(v2.index() == 1, "");
     static_assert(std::get<1>(v2).value == 42, "");
   }
+#endif // > C++17
 }
 
 void test_copy_ctor_valueless_by_exception() {
@@ -231,17 +235,16 @@ void test_copy_ctor_valueless_by_excepti
 }
 
 template <size_t Idx>
-constexpr bool test_constexpr_copy_ctor_extension_imp(
-    std::variant<long, void*, const int> const& v)
-{
+constexpr bool test_constexpr_copy_ctor_imp(std::variant<long, void*, const int> const& v) {
   auto v2 = v;
   return v2.index() == v.index() &&
          v2.index() == Idx &&
          std::get<Idx>(v2) == std::get<Idx>(v);
 }
 
-void test_constexpr_copy_ctor_extension() {
-  // NOTE: This test is for not yet standardized behavior. (P0602)
+void test_constexpr_copy_ctor() {
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   using V = std::variant<long, void*, const int>;
 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
   static_assert(std::is_trivially_destructible<V>::value, "");
@@ -252,16 +255,17 @@ void test_constexpr_copy_ctor_extension(
 #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
   static_assert(std::is_trivially_copyable<V>::value, "");
 #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)), "");
+  static_assert(test_constexpr_copy_ctor_imp<0>(V(42l)), "");
+  static_assert(test_constexpr_copy_ctor_imp<1>(V(nullptr)), "");
+  static_assert(test_constexpr_copy_ctor_imp<2>(V(101)), "");
+#endif // > C++17
 }
 
 int main() {
   test_copy_ctor_basic();
   test_copy_ctor_valueless_by_exception();
   test_copy_ctor_sfinae();
-  test_constexpr_copy_ctor_extension();
+  test_constexpr_copy_ctor();
 #if 0
 // disable this for the moment; it fails on older compilers.
 //  Need to figure out which compilers will support it.

Modified: libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp?rev=350884&r1=350883&r2=350884&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp Thu Jan 10 12:06:11 2019
@@ -22,7 +22,7 @@
 
 // template <class ...Types> class variant;
 
-// variant(variant&&) noexcept(see below);
+// variant(variant&&) noexcept(see below); // constexpr in C++20
 
 #include <cassert>
 #include <string>
@@ -147,7 +147,8 @@ void test_move_ctor_sfinae() {
     static_assert(!std::is_move_constructible<V>::value, "");
   }
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality (see P0602R4).
+#if TEST_STD_VER > 17
   {
     using V = std::variant<int, long>;
     static_assert(std::is_trivially_move_constructible<V>::value, "");
@@ -165,6 +166,7 @@ void test_move_ctor_sfinae() {
     using V = std::variant<int, TMoveNTCopy>;
     static_assert(std::is_trivially_move_constructible<V>::value, "");
   }
+#endif // > C++17
 }
 
 template <typename T>
@@ -214,7 +216,8 @@ void test_move_ctor_basic() {
     assert(std::get<1>(v2).value == 42);
   }
 
-  // The following tests are for not-yet-standardized behavior (P0602):
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   {
     struct {
       constexpr Result<int> operator()() const {
@@ -287,6 +290,7 @@ void test_move_ctor_basic() {
     static_assert(result.index == 1, "");
     static_assert(result.value.value == 42, "");
   }
+#endif // > C++17
 }
 
 void test_move_ctor_valueless_by_exception() {
@@ -300,9 +304,7 @@ void test_move_ctor_valueless_by_excepti
 }
 
 template <size_t Idx>
-constexpr bool test_constexpr_ctor_extension_imp(
-    std::variant<long, void*, const int> const& v)
-{
+constexpr bool test_constexpr_ctor_imp(std::variant<long, void*, const int> const& v) {
   auto copy = v;
   auto v2 = std::move(copy);
   return v2.index() == v.index() &&
@@ -310,8 +312,9 @@ constexpr bool test_constexpr_ctor_exten
         std::get<Idx>(v2) == std::get<Idx>(v);
 }
 
-void test_constexpr_move_ctor_extension() {
-  // NOTE: This test is for not yet standardized behavior. (P0602)
+void test_constexpr_move_ctor() {
+  // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
+#if TEST_STD_VER > 17
   using V = std::variant<long, void*, const int>;
 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
   static_assert(std::is_trivially_destructible<V>::value, "");
@@ -323,9 +326,10 @@ void test_constexpr_move_ctor_extension(
   static_assert(std::is_trivially_copyable<V>::value, "");
 #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)), "");
-  static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), "");
+  static_assert(test_constexpr_ctor_imp<0>(V(42l)), "");
+  static_assert(test_constexpr_ctor_imp<1>(V(nullptr)), "");
+  static_assert(test_constexpr_ctor_imp<2>(V(101)), "");
+#endif // > C++17
 }
 
 int main() {
@@ -333,5 +337,5 @@ int main() {
   test_move_ctor_valueless_by_exception();
   test_move_noexcept();
   test_move_ctor_sfinae();
-  test_constexpr_move_ctor_extension();
+  test_constexpr_move_ctor();
 }

Modified: libcxx/trunk/www/cxx2a_status.html
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/www/cxx2a_status.html?rev=350884&r1=350883&r2=350884&view=diff
==============================================================================
--- libcxx/trunk/www/cxx2a_status.html (original)
+++ libcxx/trunk/www/cxx2a_status.html Thu Jan 10 12:06:11 2019
@@ -115,7 +115,7 @@
 	<tr><td><a href="https://wg21.link/P0487R1">P0487R1</a></td><td>LWG</td><td>Fixing operator>>(basic_istream&, CharT*) (LWG 2499)</td><td>San Diego</td><td>Complete</td><td>8.0</td></tr>
 	<tr><td><a href="https://wg21.link/P0591R4">P0591R4</a></td><td>LWG</td><td>Utility functions to implement uses-allocator construction</td><td>San Diego</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P0595R2">P0595R2</a></td><td>CWG</td><td>P0595R2 std::is_constant_evaluated()</td><td>San Diego</td><td><i> </i></td><td></td></tr>
-	<tr><td><a href="https://wg21.link/P0602R4">P0602R4</a></td><td>LWG</td><td>variant and optional should propagate copy/move triviality</td><td>San Diego</td><td><i> </i></td><td></td></tr>
+	<tr><td><a href="https://wg21.link/P0602R4">P0602R4</a></td><td>LWG</td><td>variant and optional should propagate copy/move triviality</td><td>San Diego</td><td>Complete</td><td>8.0</td></tr>
 	<tr><td><a href="https://wg21.link/P0608R3">P0608R3</a></td><td>LWG</td><td>A sane variant converting constructor</td><td>San Diego</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P0655R1">P0655R1</a></td><td>LWG</td><td>visit<R>: Explicit Return Type for visit</td><td>San Diego</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P0771R1">P0771R1</a></td><td>LWG</td><td>std::function move constructor should be noexcept</td><td>San Diego</td><td>Complete</td><td>6.0</td></tr>




More information about the libcxx-commits mailing list