[libcxx] r307505 - optional: Implement LWG 2900 and P0602

Casey Carter via cfe-commits cfe-commits at lists.llvm.org
Sun Jul 9 10:15:49 PDT 2017


Author: caseycarter
Date: Sun Jul  9 10:15:49 2017
New Revision: 307505

URL: http://llvm.org/viewvc/llvm-project?rev=307505&view=rev
Log:
optional: Implement LWG 2900 and P0602

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

Removed:
    libcxx/trunk/test/libcxx/utilities/optional/optional.object/special_member_gen.pass.cpp
Modified:
    libcxx/trunk/include/optional
    libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp
    libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
    libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp
    libcxx/trunk/test/std/utilities/optional/optional.object/special_member_gen.pass.cpp

Modified: libcxx/trunk/include/optional
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/optional?rev=307505&r1=307504&r2=307505&view=diff
==============================================================================
--- libcxx/trunk/include/optional (original)
+++ libcxx/trunk/include/optional Sun Jul  9 10:15:49 2017
@@ -439,46 +439,122 @@ struct __optional_storage_base<_Tp, true
     }
 };
 
-template <class _Tp, bool = is_trivially_copyable<_Tp>::value>
-struct __optional_storage;
-
-template <class _Tp>
-struct __optional_storage<_Tp, true> : __optional_storage_base<_Tp>
+template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
+struct __optional_copy_base : __optional_storage_base<_Tp>
 {
     using __optional_storage_base<_Tp>::__optional_storage_base;
 };
 
 template <class _Tp>
-struct __optional_storage<_Tp, false> : __optional_storage_base<_Tp>
+struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp>
 {
-    using value_type = _Tp;
     using __optional_storage_base<_Tp>::__optional_storage_base;
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage() = default;
+    __optional_copy_base() = default;
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage(const __optional_storage& __opt)
+    __optional_copy_base(const __optional_copy_base& __opt)
     {
         this->__construct_from(__opt);
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage(__optional_storage&& __opt)
+    __optional_copy_base(__optional_copy_base&&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_base& operator=(const __optional_copy_base&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_base& operator=(__optional_copy_base&&) = default;
+};
+
+template <class _Tp, bool = is_trivially_move_constructible<_Tp>::value>
+struct __optional_move_base : __optional_copy_base<_Tp>
+{
+    using __optional_copy_base<_Tp>::__optional_copy_base;
+};
+
+template <class _Tp>
+struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp>
+{
+    using value_type = _Tp;
+    using __optional_copy_base<_Tp>::__optional_copy_base;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_base() = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_base(const __optional_move_base&) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_base(__optional_move_base&& __opt)
         noexcept(is_nothrow_move_constructible_v<value_type>)
     {
         this->__construct_from(_VSTD::move(__opt));
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage& operator=(const __optional_storage& __opt)
+    __optional_move_base& operator=(const __optional_move_base&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_base& operator=(__optional_move_base&&) = default;
+};
+
+template <class _Tp, bool =
+    is_trivially_destructible<_Tp>::value &&
+    is_trivially_copy_constructible<_Tp>::value &&
+    is_trivially_copy_assignable<_Tp>::value>
+struct __optional_copy_assign_base : __optional_move_base<_Tp>
+{
+    using __optional_move_base<_Tp>::__optional_move_base;
+};
+
+template <class _Tp>
+struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp>
+{
+    using __optional_move_base<_Tp>::__optional_move_base;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_assign_base() = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_assign_base(const __optional_copy_assign_base&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_assign_base(__optional_copy_assign_base&&) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_copy_assign_base& operator=(const __optional_copy_assign_base& __opt)
     {
         this->__assign_from(__opt);
         return *this;
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_storage& operator=(__optional_storage&& __opt)
+    __optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default;
+};
+
+template <class _Tp, bool =
+    is_trivially_destructible<_Tp>::value &&
+    is_trivially_move_constructible<_Tp>::value &&
+    is_trivially_move_assignable<_Tp>::value>
+struct __optional_move_assign_base : __optional_copy_assign_base<_Tp>
+{
+    using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
+};
+
+template <class _Tp>
+struct __optional_move_assign_base<_Tp, false> : __optional_copy_assign_base<_Tp>
+{
+    using value_type = _Tp;
+    using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base() = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base(const __optional_move_assign_base& __opt) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base(__optional_move_assign_base&&) = default;
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base& operator=(const __optional_move_assign_base&) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __optional_move_assign_base& operator=(__optional_move_assign_base&& __opt)
         noexcept(is_nothrow_move_assignable_v<value_type> &&
                  is_nothrow_move_constructible_v<value_type>)
     {
@@ -501,11 +577,11 @@ using __optional_sfinae_assign_base_t =
 
 template <class _Tp>
 class optional
-    : private __optional_storage<_Tp>
+    : private __optional_move_assign_base<_Tp>
     , private __optional_sfinae_ctor_base_t<_Tp>
     , private __optional_sfinae_assign_base_t<_Tp>
 {
-    using __base = __optional_storage<_Tp>;
+    using __base = __optional_move_assign_base<_Tp>;
 public:
     using value_type = _Tp;
 

Removed: libcxx/trunk/test/libcxx/utilities/optional/optional.object/special_member_gen.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/optional/optional.object/special_member_gen.pass.cpp?rev=307504&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/utilities/optional/optional.object/special_member_gen.pass.cpp (original)
+++ libcxx/trunk/test/libcxx/utilities/optional/optional.object/special_member_gen.pass.cpp (removed)
@@ -1,66 +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>;
-
-    template <template <class> class TestMF>
-    static constexpr bool check_same() {
-        return TestMF<O>::value == TestMF<T>::value;
-    }
-
-    // Test that optional inherits the correct trivial/non-trivial members
-    static_assert(check_same<std::is_trivially_destructible>(), "");
-    static_assert(check_same<std::is_trivially_copyable>(), "");
-};
-
-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/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=307505&r1=307504&r2=307505&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 Sun Jul  9 10:15:49 2017
@@ -147,27 +147,27 @@ int main()
     }
     {
         struct ThrowsMove {
-          ThrowsMove() noexcept {}
-          ThrowsMove(ThrowsMove const&) noexcept {}
-          ThrowsMove(ThrowsMove &&) noexcept(false) {}
-          ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; }
-          ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; }
+            ThrowsMove() noexcept {}
+            ThrowsMove(ThrowsMove const&) noexcept {}
+            ThrowsMove(ThrowsMove &&) noexcept(false) {}
+            ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; }
+            ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; }
         };
         static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMove>>::value, "");
         struct ThrowsMoveAssign {
-          ThrowsMoveAssign() noexcept {}
-          ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {}
-          ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {}
-          ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; }
-          ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; }
+            ThrowsMoveAssign() noexcept {}
+            ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {}
+            ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {}
+            ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; }
+            ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; }
         };
         static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMoveAssign>>::value, "");
         struct NoThrowMove {
-          NoThrowMove() noexcept(false) {}
-          NoThrowMove(NoThrowMove const&) noexcept(false) {}
-          NoThrowMove(NoThrowMove &&) noexcept {}
-          NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; }
-          NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; }
+            NoThrowMove() noexcept(false) {}
+            NoThrowMove(NoThrowMove const&) noexcept(false) {}
+            NoThrowMove(NoThrowMove &&) noexcept {}
+            NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; }
+            NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; }
         };
         static_assert(std::is_nothrow_move_assignable<optional<NoThrowMove>>::value, "");
     }

Modified: libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp?rev=307505&r1=307504&r2=307505&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp Sun Jul  9 10:15:49 2017
@@ -45,10 +45,10 @@ constexpr bool constexpr_test(InitArgs&&
 void test_throwing_ctor() {
 #ifndef TEST_HAS_NO_EXCEPTIONS
     struct Z {
-      Z() : count(0) {}
-      Z(Z const& o) : count(o.count + 1)
-      { if (count == 2) throw 6; }
-      int count;
+        Z() : count(0) {}
+        Z(Z const& o) : count(o.count + 1)
+        { if (count == 2) throw 6; }
+        int count;
     };
     const Z z;
     const optional<Z> rhs(z);

Modified: libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp?rev=307505&r1=307504&r2=307505&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp Sun Jul  9 10:15:49 2017
@@ -55,10 +55,10 @@ constexpr bool constexpr_test(InitArgs&&
 void test_throwing_ctor() {
 #ifndef TEST_HAS_NO_EXCEPTIONS
     struct Z {
-      Z() : count(0) {}
-      Z(Z&& o) : count(o.count + 1)
-      { if (count == 2) throw 6; }
-      int count;
+        Z() : count(0) {}
+        Z(Z&& o) : count(o.count + 1)
+        { if (count == 2) throw 6; }
+        int count;
     };
     Z z;
     optional<Z> rhs(std::move(z));

Modified: 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=307505&r1=307504&r2=307505&view=diff
==============================================================================
--- 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 Sun Jul  9 10:15:49 2017
@@ -33,10 +33,38 @@ struct SpecialMemberTest {
         "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_copy_constructible_v<T> && std::is_copy_assignable_v<T>) ||
-         (std::is_move_constructible_v<T> && std::is_move_assignable_v<T>)),
-        "optional<T> is move assignable if and only if T is both move assignable and "
-        "move constructible, or both copy constructible and copy assignable.");
+        ((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&&...) {}




More information about the cfe-commits mailing list