[libcxx-commits] [libcxx] 5464499 - [libcxx][optional] adds missing constexpr operations

Christopher Di Bella via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jun 9 22:53:12 PDT 2021


Author: Christopher Di Bella
Date: 2021-06-10T05:52:47Z
New Revision: 546449938a39dcc65f60f8d6e44e7b058a026549

URL: https://github.com/llvm/llvm-project/commit/546449938a39dcc65f60f8d6e44e7b058a026549
DIFF: https://github.com/llvm/llvm-project/commit/546449938a39dcc65f60f8d6e44e7b058a026549.diff

LOG: [libcxx][optional] adds missing constexpr operations

Makes the following operations constexpr:
  * `std::swap(optional, optional)`
  * `optional(optional<U> const&)`
  * `optional(optional<U>&&)`
  * `~optional()`
  * `operator=(nullopt_t)`
  * `operator=(U&&)`
  * `operator=(optional<U> const&)`
  * `operator=(optional<U>&&)`
  * `emplace(Args&&...)`
  * `emplace(initializer_list<U>, Args&&...)`
  * `swap(optional&)`
  * `reset()`

P2231 has been accepted by plenary, with the committee recommending
implementers retroactively apply to C++20. It's necessary for us to
implement _`semiregular-box`_ and _`non-propagating-cache`_, both of
which are required for ranges (otherwise we'll need to reimplement
`std::optional` with these members `constexpr`ified).

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

Added: 
    

Modified: 
    libcxx/docs/Cxx2aStatusPaperStatus.csv
    libcxx/include/optional
    libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_const_optional_U.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_optional_U.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.fail.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.dtor/dtor.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp
    libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv
index ce4da44071697..be1a2470672b1 100644
--- a/libcxx/docs/Cxx2aStatusPaperStatus.csv
+++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv
@@ -193,3 +193,4 @@
 "`P2102 <https://wg21.link/P2102>`__","LWG","Make 'implicit expression variations' more explicit (Wording for US185)","Prague","* *",""
 "`P2106 <https://wg21.link/P2106>`__","LWG","Alternative wording for GB315 and GB316","Prague","* *",""
 "`P2116 <https://wg21.link/P2116>`__","LWG","Remove tuple-like protocol support from fixed-extent span","Prague","|Complete|","11.0"
+"`P2231 <https://wg21.link/P2231>`__","LWG","Missing constexpr in std::optional and std::variant","February 2021","|In progress|","13.0"

diff  --git a/libcxx/include/optional b/libcxx/include/optional
index b6a464f54e6fb..8a291a6ac2dbb 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -69,7 +69,7 @@ namespace std {
   template <class T, class U> constexpr bool operator>=(const T&, const optional<U>&);
 
   // 23.6.9, specialized algorithms
-  template <class T> void swap(optional<T>&, optional<T>&) noexcept(see below );
+  template <class T> void swap(optional<T>&, optional<T>&) noexcept(see below ); // constexpr in C++20
   template <class T> constexpr optional<see below > make_optional(T&&);
   template <class T, class... Args>
     constexpr optional<T> make_optional(Args&&... args);
@@ -95,26 +95,26 @@ namespace std {
     template <class U = T>
       constexpr EXPLICIT optional(U &&);
     template <class U>
-      constexpr EXPLICIT optional(const optional<U> &);
+      EXPLICIT optional(const optional<U> &);   // constexpr in C++20
     template <class U>
-      constexpr EXPLICIT optional(optional<U> &&);
+      EXPLICIT optional(optional<U> &&);        // constexpr in C++20
 
     // 23.6.3.2, destructor
-    ~optional();
+    ~optional(); // constexpr in C++20
 
     // 23.6.3.3, assignment
-    optional &operator=(nullopt_t) noexcept;
-    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> &&);
-    template <class... Args> T& emplace(Args &&...);
+    optional &operator=(nullopt_t) noexcept;                     // constexpr in C++20
+    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 &&);            // constexpr in C++20
+    template <class U> optional &operator=(const optional<U> &); // constexpr in C++20
+    template <class U> optional &operator=(optional<U> &&);      // constexpr in C++20
+    template <class... Args> T& emplace(Args &&...);             // constexpr in C++20
     template <class U, class... Args>
-      T& emplace(initializer_list<U>, Args &&...);
+      T& emplace(initializer_list<U>, Args &&...);               // constexpr in C++20
 
     // 23.6.3.4, swap
-    void swap(optional &) noexcept(see below );
+    void swap(optional &) noexcept(see below ); // constexpr in C++20
 
     // 23.6.3.5, observers
     constexpr T const *operator->() const;
@@ -133,7 +133,7 @@ namespace std {
     template <class U> constexpr T value_or(U &&) &&;
 
     // 23.6.3.6, modifiers
-    void reset() noexcept;
+    void reset() noexcept; // constexpr in C++20
 
   private:
     T *val; // exposition only
@@ -221,7 +221,7 @@ struct __optional_destruct_base<_Tp, false>
     bool __engaged_;
 
     _LIBCPP_INLINE_VISIBILITY
-    ~__optional_destruct_base()
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 ~__optional_destruct_base()
     {
         if (__engaged_)
             __val_.~value_type();
@@ -239,7 +239,7 @@ struct __optional_destruct_base<_Tp, false>
            __engaged_(true) {}
 
     _LIBCPP_INLINE_VISIBILITY
-    void reset() noexcept
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void reset() noexcept
     {
         if (__engaged_)
         {
@@ -274,7 +274,7 @@ struct __optional_destruct_base<_Tp, true>
            __engaged_(true) {}
 
     _LIBCPP_INLINE_VISIBILITY
-    void reset() noexcept
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void reset() noexcept
     {
         if (__engaged_)
         {
@@ -319,16 +319,20 @@ struct __optional_storage_base : __optional_destruct_base<_Tp>
 
     template <class... _Args>
     _LIBCPP_INLINE_VISIBILITY
-    void __construct(_Args&&... __args)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void __construct(_Args&&... __args)
     {
         _LIBCPP_ASSERT(!has_value(), "__construct called for engaged __optional_storage");
+#if _LIBCPP_STD_VER > 17
+        _VSTD::construct_at(_VSTD::addressof(this->__val_), _VSTD::forward<_Args>(__args)...);
+#else
         ::new ((void*)_VSTD::addressof(this->__val_)) value_type(_VSTD::forward<_Args>(__args)...);
+#endif
         this->__engaged_ = true;
     }
 
     template <class _That>
     _LIBCPP_INLINE_VISIBILITY
-    void __construct_from(_That&& __opt)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void __construct_from(_That&& __opt)
     {
         if (__opt.has_value())
             __construct(_VSTD::forward<_That>(__opt).__get());
@@ -336,7 +340,7 @@ struct __optional_storage_base : __optional_destruct_base<_Tp>
 
     template <class _That>
     _LIBCPP_INLINE_VISIBILITY
-    void __assign_from(_That&& __opt)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void __assign_from(_That&& __opt)
     {
         if (this->__engaged_ == __opt.has_value())
         {
@@ -394,7 +398,7 @@ struct __optional_storage_base<_Tp, true>
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    void reset() noexcept { __value_ = nullptr; }
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void reset() noexcept { __value_ = nullptr; }
 
     _LIBCPP_INLINE_VISIBILITY
     constexpr bool has_value() const noexcept
@@ -410,7 +414,7 @@ struct __optional_storage_base<_Tp, true>
 
     template <class _UArg>
     _LIBCPP_INLINE_VISIBILITY
-    void __construct(_UArg&& __val)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void __construct(_UArg&& __val)
     {
         _LIBCPP_ASSERT(!has_value(), "__construct called for engaged __optional_storage");
         static_assert(__can_bind_reference<_UArg>(),
@@ -421,7 +425,7 @@ struct __optional_storage_base<_Tp, true>
 
     template <class _That>
     _LIBCPP_INLINE_VISIBILITY
-    void __construct_from(_That&& __opt)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void __construct_from(_That&& __opt)
     {
         if (__opt.has_value())
             __construct(_VSTD::forward<_That>(__opt).__get());
@@ -429,7 +433,7 @@ struct __optional_storage_base<_Tp, true>
 
     template <class _That>
     _LIBCPP_INLINE_VISIBILITY
-    void __assign_from(_That&& __opt)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void __assign_from(_That&& __opt)
     {
         if (has_value() == __opt.has_value())
         {
@@ -461,7 +465,7 @@ struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp>
     __optional_copy_base() = default;
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_copy_base(const __optional_copy_base& __opt)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 __optional_copy_base(const __optional_copy_base& __opt)
     {
         this->__construct_from(__opt);
     }
@@ -492,7 +496,7 @@ struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp>
     __optional_move_base(const __optional_move_base&) = default;
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_move_base(__optional_move_base&& __opt)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 __optional_move_base(__optional_move_base&& __opt)
         noexcept(is_nothrow_move_constructible_v<value_type>)
     {
         this->__construct_from(_VSTD::move(__opt));
@@ -526,7 +530,7 @@ struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp>
     __optional_copy_assign_base(__optional_copy_assign_base&&) = default;
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_copy_assign_base& operator=(const __optional_copy_assign_base& __opt)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 __optional_copy_assign_base& operator=(const __optional_copy_assign_base& __opt)
     {
         this->__assign_from(__opt);
         return *this;
@@ -561,7 +565,7 @@ struct __optional_move_assign_base<_Tp, false> : __optional_copy_assign_base<_Tp
     __optional_move_assign_base& operator=(const __optional_move_assign_base&) = default;
 
     _LIBCPP_INLINE_VISIBILITY
-    __optional_move_assign_base& operator=(__optional_move_assign_base&& __opt)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 __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>)
     {
@@ -728,7 +732,7 @@ public:
         _CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_implicit<_Up>()
     , int> = 0>
     _LIBCPP_INLINE_VISIBILITY
-    optional(const optional<_Up>& __v)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 optional(const optional<_Up>& __v)
     {
         this->__construct_from(__v);
     }
@@ -736,7 +740,7 @@ public:
         _CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_explicit<_Up>()
     , int> = 0>
     _LIBCPP_INLINE_VISIBILITY
-    explicit optional(const optional<_Up>& __v)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 explicit optional(const optional<_Up>& __v)
     {
         this->__construct_from(__v);
     }
@@ -746,7 +750,7 @@ public:
         _CheckOptionalLikeCtor<_Up, _Up &&>::template __enable_implicit<_Up>()
     , int> = 0>
     _LIBCPP_INLINE_VISIBILITY
-    optional(optional<_Up>&& __v)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 optional(optional<_Up>&& __v)
     {
         this->__construct_from(_VSTD::move(__v));
     }
@@ -754,13 +758,13 @@ public:
         _CheckOptionalLikeCtor<_Up, _Up &&>::template __enable_explicit<_Up>()
     , int> = 0>
     _LIBCPP_INLINE_VISIBILITY
-    explicit optional(optional<_Up>&& __v)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 explicit optional(optional<_Up>&& __v)
     {
         this->__construct_from(_VSTD::move(__v));
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    optional& operator=(nullopt_t) noexcept
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 optional& operator=(nullopt_t) noexcept
     {
         reset();
         return *this;
@@ -783,7 +787,7 @@ public:
                       >::value>
              >
     _LIBCPP_INLINE_VISIBILITY
-    optional&
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 optional&
     operator=(_Up&& __v)
     {
         if (this->has_value())
@@ -798,7 +802,7 @@ public:
         _CheckOptionalLikeAssign<_Up, _Up const&>::template __enable_assign<_Up>()
     , int> = 0>
     _LIBCPP_INLINE_VISIBILITY
-    optional&
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 optional&
     operator=(const optional<_Up>& __v)
     {
         this->__assign_from(__v);
@@ -810,7 +814,7 @@ public:
         _CheckOptionalLikeCtor<_Up, _Up &&>::template __enable_assign<_Up>()
     , int> = 0>
     _LIBCPP_INLINE_VISIBILITY
-    optional&
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 optional&
     operator=(optional<_Up>&& __v)
     {
         this->__assign_from(_VSTD::move(__v));
@@ -824,7 +828,7 @@ public:
                       >
              >
     _LIBCPP_INLINE_VISIBILITY
-    _Tp &
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 _Tp &
     emplace(_Args&&... __args)
     {
         reset();
@@ -839,7 +843,7 @@ public:
                       >
              >
     _LIBCPP_INLINE_VISIBILITY
-    _Tp &
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 _Tp &
     emplace(initializer_list<_Up> __il, _Args&&... __args)
     {
         reset();
@@ -848,7 +852,7 @@ public:
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    void swap(optional& __opt)
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(optional& __opt)
         noexcept(is_nothrow_move_constructible_v<value_type> &&
                  is_nothrow_swappable_v<value_type>)
     {
@@ -1006,7 +1010,7 @@ public:
 private:
     template <class _Up>
     _LIBCPP_INLINE_VISIBILITY
-    static _Up*
+    static _LIBCPP_CONSTEXPR_AFTER_CXX17 _Up*
     __operator_arrow(true_type, _Up& __x)
     {
         return _VSTD::addressof(__x);
@@ -1367,7 +1371,7 @@ operator>=(const _Tp& __v, const optional<_Up>& __x)
 
 
 template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 _EnableIf<
     is_move_constructible_v<_Tp> && is_swappable_v<_Tp>,
     void

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp
index faa2856324716..a23b54ebe260b 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: gcc-10
 // <optional>
 
 // template <class... Args> T& optional<T>::emplace(Args&&... args);
@@ -26,11 +27,11 @@ class X
     int i_;
     int j_ = 0;
 public:
-    X() : i_(0) {}
-    X(int i) : i_(i) {}
-    X(int i, int j) : i_(i), j_(j) {}
+    constexpr X() : i_(0) {}
+    constexpr X(int i) : i_(i) {}
+    constexpr X(int i, int j) : i_(i), j_(j) {}
 
-    friend bool operator==(const X& x, const X& y)
+    constexpr friend bool operator==(const X& x, const X& y)
         {return x.i_ == y.i_ && x.j_ == y.j_;}
 };
 
@@ -46,7 +47,7 @@ class Y
 bool Y::dtor_called = false;
 
 template <class T>
-void test_one_arg() {
+constexpr bool test_one_arg() {
     using Opt = std::optional<T>;
     {
         Opt opt;
@@ -80,11 +81,12 @@ void test_one_arg() {
         assert(*opt == T(1));
         assert(&v == &*opt);
     }
+    return true;
 }
 
 
 template <class T>
-void test_multi_arg()
+constexpr bool test_multi_arg()
 {
     test_one_arg<T>();
     using Opt = std::optional<T>;
@@ -112,6 +114,7 @@ void test_multi_arg()
         assert(  v == T(5)); // T sets its value to the size of the init list
         assert(*opt == T(5)); // T sets its value to the size of the init list
     }
+    return true;
 }
 
 template <class T>
@@ -206,7 +209,17 @@ void test_on_test_type() {
     }
 }
 
-
+constexpr bool test_empty_emplace()
+{
+    optional<const int> opt;
+    auto &v = opt.emplace(42);
+    static_assert( std::is_same_v<const int&, decltype(v)>, "" );
+    assert(*opt == 42);
+    assert(   v == 42);
+    opt.emplace();
+    assert(*opt == 0);
+    return true;
+}
 
 int main(int, char**)
 {
@@ -218,31 +231,44 @@ int main(int, char**)
         using T = int;
         test_one_arg<T>();
         test_one_arg<const T>();
+#if TEST_STD_VER > 17
+        static_assert(test_one_arg<T>());
+        static_assert(test_one_arg<const T>());
+#endif
     }
     {
         using T = ConstexprTestTypes::TestType;
         test_multi_arg<T>();
+#if TEST_STD_VER > 17
+        static_assert(test_multi_arg<T>());
+#endif
     }
     {
         using T = ExplicitConstexprTestTypes::TestType;
         test_multi_arg<T>();
+#if TEST_STD_VER > 17
+        static_assert(test_multi_arg<T>());
+#endif
     }
     {
         using T = TrivialTestTypes::TestType;
         test_multi_arg<T>();
+#if TEST_STD_VER > 17
+        static_assert(test_multi_arg<T>());
+#endif
     }
     {
         using T = ExplicitTrivialTestTypes::TestType;
         test_multi_arg<T>();
+#if TEST_STD_VER > 17
+        static_assert(test_multi_arg<T>());
+#endif
     }
     {
-        optional<const int> opt;
-        auto &v = opt.emplace(42);
-        static_assert( std::is_same_v<const int&, decltype(v)>, "" );
-        assert(*opt == 42);
-        assert(   v == 42);
-        opt.emplace();
-        assert(*opt == 0);
+        test_empty_emplace();
+#if TEST_STD_VER > 17
+        static_assert(test_empty_emplace());
+#endif
     }
 #ifndef TEST_HAS_NO_EXCEPTIONS
     Y::dtor_called = false;

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp
index 8ab06f1a3a156..aa13f6284441b 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace_initializer_list.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: gcc-10
 // <optional>
 
 // template <class U, class... Args>
@@ -25,19 +26,18 @@ class X
 {
     int i_;
     int j_ = 0;
+    bool* dtor_called_;
 public:
-    static bool dtor_called;
-    constexpr X() : i_(0) {}
-    constexpr X(int i) : i_(i) {}
-    constexpr X(std::initializer_list<int> il) : i_(il.begin()[0]), j_(il.begin()[1]) {}
-    ~X() {dtor_called = true;}
+    constexpr X(bool& dtor_called) : i_(0), dtor_called_(&dtor_called) {}
+    constexpr X(int i, bool& dtor_called) : i_(i), dtor_called_(&dtor_called) {}
+    constexpr X(std::initializer_list<int> il, bool& dtor_called)
+    : i_(il.begin()[0]), j_(il.begin()[1]), dtor_called_(&dtor_called) {}
+    TEST_CONSTEXPR_CXX20 ~X() {*dtor_called_ = true;}
 
     friend constexpr bool operator==(const X& x, const X& y)
         {return x.i_ == y.i_ && x.j_ == y.j_;}
 };
 
-bool X::dtor_called = false;
-
 class Y
 {
     int i_;
@@ -69,17 +69,38 @@ class Z
 
 bool Z::dtor_called = false;
 
+TEST_CONSTEXPR_CXX20 bool check_X()
+{
+    bool dtor_called = false;
+    X x(dtor_called);
+    optional<X> opt(x);
+    assert(dtor_called == false);
+    auto &v = opt.emplace({1, 2}, dtor_called);
+    static_assert( std::is_same_v<X&, decltype(v)>, "" );
+    assert(dtor_called);
+    assert(*opt == X({1, 2}, dtor_called));
+    assert(&v == &*opt);
+    return true;
+}
+
+TEST_CONSTEXPR_CXX20 bool check_Y()
+{
+    optional<Y> opt;
+    auto &v = opt.emplace({1, 2});
+    static_assert( std::is_same_v<Y&, decltype(v)>, "" );
+    assert(static_cast<bool>(opt) == true);
+    assert(*opt == Y({1, 2}));
+    assert(&v == &*opt);
+    return true;
+}
+
 int main(int, char**)
 {
     {
-        X x;
-        optional<X> opt(x);
-        assert(X::dtor_called == false);
-        auto &v = opt.emplace({1, 2});
-        static_assert( std::is_same_v<X&, decltype(v)>, "" );
-        assert(X::dtor_called == true);
-        assert(*opt == X({1, 2}));
-        assert(&v == &*opt);
+        check_X();
+#if TEST_STD_VER > 17
+        static_assert(check_X());
+#endif
     }
     {
         optional<std::vector<int>> opt;
@@ -90,12 +111,10 @@ int main(int, char**)
         assert(&v == &*opt);
     }
     {
-        optional<Y> opt;
-        auto &v = opt.emplace({1, 2});
-        static_assert( std::is_same_v<Y&, decltype(v)>, "" );
-        assert(static_cast<bool>(opt) == true);
-        assert(*opt == Y({1, 2}));
-        assert(&v == &*opt);
+        check_Y();
+#if TEST_STD_VER > 17
+        static_assert(check_Y());
+#endif
     }
 #ifndef TEST_HAS_NO_EXCEPTIONS
     {

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp
index 4587eda3198ce..9d0843b7338df 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp
@@ -22,8 +22,21 @@ using std::optional;
 using std::nullopt_t;
 using std::nullopt;
 
-int main(int, char**)
+TEST_CONSTEXPR_CXX20 bool test()
 {
+    enum class State { inactive, constructed, destroyed };
+    State state = State::inactive;
+
+    struct StateTracker {
+      TEST_CONSTEXPR_CXX20 StateTracker(State& s)
+      : state_(&s)
+      {
+        s = State::constructed;
+      }
+      TEST_CONSTEXPR_CXX20 ~StateTracker() { *state_ = State::destroyed; }
+
+      State* state_;
+    };
     {
         optional<int> opt;
         static_assert(noexcept(opt = nullopt) == true, "");
@@ -35,6 +48,29 @@ int main(int, char**)
         opt = nullopt;
         assert(static_cast<bool>(opt) == false);
     }
+    {
+        optional<StateTracker> opt;
+        opt = nullopt;
+        assert(state == State::inactive);
+        assert(static_cast<bool>(opt) == false);
+    }
+    {
+        optional<StateTracker> opt(state);
+        assert(state == State::constructed);
+        opt = nullopt;
+        assert(state == State::destroyed);
+        assert(static_cast<bool>(opt) == false);
+    }
+    return true;
+}
+
+
+int main(int, char**)
+{
+#if TEST_STD_VER > 17
+    static_assert(test());
+#endif
+    test();
     using TT = TestTypes::TestType;
     TT::reset();
     {

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
index eb0e83fb0efb7..cc1b17157f2b4 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/optional_U.pass.cpp
@@ -14,9 +14,11 @@
 // optional<T>& operator=(optional<U>&& rhs);
 
 #include <optional>
-#include <type_traits>
-#include <memory>
+
+#include <array>
 #include <cassert>
+#include <memory>
+#include <type_traits>
 
 #include "test_macros.h"
 #include "archetypes.h"
@@ -201,10 +203,8 @@ void test_ambiguous_assign() {
 }
 
 
-int main(int, char**)
+TEST_CONSTEXPR_CXX20 bool test()
 {
-    test_with_test_type();
-    test_ambiguous_assign();
     {
         optional<int> opt;
         optional<short> opt2;
@@ -237,6 +237,75 @@ int main(int, char**)
         assert(static_cast<bool>(opt) == static_cast<bool>(opt2));
         assert(*opt == *opt2);
     }
+
+    enum class state_t { inactive, constructed, copy_assigned, move_assigned };
+    class StateTracker {
+    public:
+      constexpr StateTracker(state_t& s)
+      : state_(&s)
+      {
+        *state_ = state_t::constructed;
+      }
+
+      StateTracker(StateTracker&&) = default;
+      StateTracker(StateTracker const&) = default;
+
+      constexpr StateTracker& operator=(StateTracker&& other) noexcept
+      {
+        *state_ = state_t::inactive;
+        state_ = other.state_;
+        *state_ = state_t::move_assigned;
+        other.state_ = nullptr;
+        return *this;
+      }
+
+      constexpr StateTracker& operator=(StateTracker const& other) noexcept
+      {
+        *state_ = state_t::inactive;
+        state_ = other.state_;
+        *state_ = state_t::copy_assigned;
+        return *this;
+      }
+    private:
+      state_t* state_;
+    };
+    {
+      auto state = std::array{state_t::inactive, state_t::inactive};
+      auto opt1 = std::optional<StateTracker>(state[0]);
+      assert(state[0] == state_t::constructed);
+
+      auto opt2 = std::optional<StateTracker>(state[1]);
+      assert(state[1] == state_t::constructed);
+
+      opt1 = std::move(opt2);
+      assert(state[0] == state_t::inactive);
+      assert(state[1] == state_t::move_assigned);
+    }
+    {
+      auto state = std::array{state_t::inactive, state_t::inactive};
+      auto opt1 = std::optional<StateTracker>(state[0]);
+      assert(state[0] == state_t::constructed);
+
+      auto opt2 = std::optional<StateTracker>(state[1]);
+      assert(state[1] == state_t::constructed);
+
+      opt1 = opt2;
+      assert(state[0] == state_t::inactive);
+      assert(state[1] == state_t::copy_assigned);
+    }
+
+    return true;
+}
+
+
+int main(int, char**)
+{
+#if TEST_STD_VER > 17
+    static_assert(test());
+#endif
+    test_with_test_type();
+    test_ambiguous_assign();
+    test();
     {
         optional<std::unique_ptr<B>> opt;
         optional<std::unique_ptr<D>> other(new D());

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp
index 90c620f458c55..d653d724dae2c 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: gcc-10
 // <optional>
 
 // template <class U>
@@ -21,7 +22,7 @@
 using std::optional;
 
 template <class T, class U>
-void
+TEST_CONSTEXPR_CXX20 void
 test(const optional<U>& rhs, bool is_going_to_throw = false)
 {
     bool rhs_engaged = static_cast<bool>(rhs);
@@ -51,17 +52,17 @@ class X
 {
     int i_;
 public:
-    X(int i) : i_(i) {}
-    X(const X& x) : i_(x.i_) {}
-    ~X() {i_ = 0;}
-    friend bool operator==(const X& x, const X& y) {return x.i_ == y.i_;}
+    constexpr X(int i) : i_(i) {}
+    constexpr X(const X& x) : i_(x.i_) {}
+    TEST_CONSTEXPR_CXX20 ~X() {i_ = 0;}
+    friend constexpr bool operator==(const X& x, const X& y) {return x.i_ == y.i_;}
 };
 
 class Y
 {
     int i_;
 public:
-    Y(int i) : i_(i) {}
+    constexpr Y(int i) : i_(i) {}
 
     friend constexpr bool operator==(const Y& x, const Y& y) {return x.i_ == y.i_;}
 };
@@ -74,48 +75,33 @@ class Z
 public:
     Z(int i) : i_(i) {TEST_THROW(6);}
 
-    friend constexpr bool operator==(const Z& x, const Z& y) {return x.i_ == y.i_;}
+    friend bool operator==(const Z& x, const Z& y) {return x.i_ == y.i_;}
 };
 
+template<class T, class U>
+constexpr bool test_all()
+{
+  {
+    optional<U> rhs;
+    test<T>(rhs);
+  }
+  {
+    optional<U> rhs(U{3});
+    test<T>(rhs);
+  }
+  return true;
+}
 
 int main(int, char**)
 {
-    {
-        typedef short U;
-        typedef int T;
-        optional<U> rhs;
-        test<T>(rhs);
-    }
-    {
-        typedef short U;
-        typedef int T;
-        optional<U> rhs(U{3});
-        test<T>(rhs);
-    }
-    {
-        typedef X T;
-        typedef int U;
-        optional<U> rhs;
-        test<T>(rhs);
-    }
-    {
-        typedef X T;
-        typedef int U;
-        optional<U> rhs(U{3});
-        test<T>(rhs);
-    }
-    {
-        typedef Y T;
-        typedef int U;
-        optional<U> rhs;
-        test<T>(rhs);
-    }
-    {
-        typedef Y T;
-        typedef int U;
-        optional<U> rhs(U{3});
-        test<T>(rhs);
-    }
+    test_all<int, short>();
+    test_all<X, int>();
+    test_all<Y, int>();
+#if TEST_STD_VER > 17
+    static_assert(test_all<int, short>());
+    static_assert(test_all<X, int>());
+    static_assert(test_all<Y, int>());
+#endif
     {
         typedef Z T;
         typedef int U;

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_const_optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_const_optional_U.pass.cpp
index 199180a32eb84..5c245c4248a46 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_const_optional_U.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_const_optional_U.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: gcc-10
 // <optional>
 
 // template <class U>
@@ -21,7 +22,7 @@
 using std::optional;
 
 template <class T, class U>
-void
+TEST_CONSTEXPR_CXX20 void
 test(const optional<U>& rhs, bool is_going_to_throw = false)
 {
     static_assert(!(std::is_convertible<const optional<U>&, optional<T>>::value), "");
@@ -52,17 +53,17 @@ class X
 {
     int i_;
 public:
-    explicit X(int i) : i_(i) {}
-    X(const X& x) : i_(x.i_) {}
-    ~X() {i_ = 0;}
-    friend bool operator==(const X& x, const X& y) {return x.i_ == y.i_;}
+    constexpr explicit X(int i) : i_(i) {}
+    constexpr X(const X& x) : i_(x.i_) {}
+    TEST_CONSTEXPR_CXX20 ~X() {i_ = 0;}
+    friend constexpr bool operator==(const X& x, const X& y) {return x.i_ == y.i_;}
 };
 
 class Y
 {
     int i_;
 public:
-    explicit Y(int i) : i_(i) {}
+    constexpr explicit Y(int i) : i_(i) {}
 
     friend constexpr bool operator==(const Y& x, const Y& y) {return x.i_ == y.i_;}
 };
@@ -73,38 +74,34 @@ class Z
 {
     int i_;
 public:
-    explicit Z(int i) : i_(i) { TEST_THROW(6);}
+    constexpr explicit Z(int i) : i_(i) { TEST_THROW(6);}
 
     friend constexpr bool operator==(const Z& x, const Z& y) {return x.i_ == y.i_;}
 };
 
+template<class T, class U>
+constexpr bool test_all()
+{
+  {
+    optional<U> rhs;
+    test<T>(rhs);
+  }
+  {
+    optional<U> rhs(3);
+    test<T>(rhs);
+  }
+  return true;
+}
+
 
 int main(int, char**)
 {
-    {
-        typedef X T;
-        typedef int U;
-        optional<U> rhs;
-        test<T>(rhs);
-    }
-    {
-        typedef X T;
-        typedef int U;
-        optional<U> rhs(3);
-        test<T>(rhs);
-    }
-    {
-        typedef Y T;
-        typedef int U;
-        optional<U> rhs;
-        test<T>(rhs);
-    }
-    {
-        typedef Y T;
-        typedef int U;
-        optional<U> rhs(3);
-        test<T>(rhs);
-    }
+    test_all<X, int>();
+    test_all<Y, int>();
+#if TEST_STD_VER > 17
+    static_assert(test_all<X, int>());
+    static_assert(test_all<Y, int>());
+#endif
     {
         typedef Z T;
         typedef int U;

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_optional_U.pass.cpp
index 00711918369e4..a591b5f62e69b 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_optional_U.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/explicit_optional_U.pass.cpp
@@ -21,8 +21,7 @@
 using std::optional;
 
 template <class T, class U>
-void
-test(optional<U>&& rhs, bool is_going_to_throw = false)
+TEST_CONSTEXPR_CXX20 void test(optional<U>&& rhs, bool is_going_to_throw = false)
 {
     static_assert(!(std::is_convertible<optional<U>&&, optional<T>>::value), "");
     bool rhs_engaged = static_cast<bool>(rhs);
@@ -48,10 +47,10 @@ class X
 {
     int i_;
 public:
-    explicit X(int i) : i_(i) {}
-    X(X&& x) : i_(std::exchange(x.i_, 0)) {}
-    ~X() {i_ = 0;}
-    friend bool operator==(const X& x, const X& y) {return x.i_ == y.i_;}
+    constexpr explicit X(int i) : i_(i) {}
+    constexpr X(X&& x) : i_(std::exchange(x.i_, 0)) {}
+    TEST_CONSTEXPR_CXX20 ~X() {i_ = 0;}
+    friend constexpr bool operator==(const X& x, const X& y) {return x.i_ == y.i_;}
 };
 
 int count = 0;
@@ -62,7 +61,7 @@ class Z
     explicit Z(int) { TEST_THROW(6); }
 };
 
-int main(int, char**)
+TEST_CONSTEXPR_CXX20 bool test()
 {
     {
         optional<int> rhs;
@@ -72,6 +71,16 @@ int main(int, char**)
         optional<int> rhs(3);
         test<X>(std::move(rhs));
     }
+
+    return true;
+}
+
+int main(int, char**)
+{
+#if TEST_STD_VER > 17
+    static_assert(test());
+#endif
+    test();
     {
         optional<int> rhs;
         test<Z>(std::move(rhs));

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.fail.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.fail.cpp
index 8c99965d61509..e6b48b53b2185 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.fail.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.fail.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++17
 // <optional>
 
 // constexpr optional(const optional<T>&& rhs);

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp
index 8e7bfa993412a..436d67a2cf080 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: gcc-10
 // <optional>
 
 // template <class U>
@@ -22,7 +23,7 @@
 using std::optional;
 
 template <class T, class U>
-void
+TEST_CONSTEXPR_CXX20 void
 test(optional<U>&& rhs, bool is_going_to_throw = false)
 {
     bool rhs_engaged = static_cast<bool>(rhs);
@@ -48,37 +49,39 @@ class X
 {
     int i_;
 public:
-    X(int i) : i_(i) {}
-    X(X&& x) : i_(std::exchange(x.i_, 0)) {}
-    ~X() {i_ = 0;}
-    friend bool operator==(const X& x, const X& y) {return x.i_ == y.i_;}
+    TEST_CONSTEXPR_CXX20 X(int i) : i_(i) {}
+    TEST_CONSTEXPR_CXX20 X(X&& x) : i_(std::exchange(x.i_, 0)) {}
+    TEST_CONSTEXPR_CXX20 ~X() {i_ = 0;}
+    friend constexpr bool operator==(const X& x, const X& y) {return x.i_ == y.i_;}
 };
 
-int count = 0;
-
 struct Z
 {
     Z(int) { TEST_THROW(6); }
 };
 
-int main(int, char**)
+template<class T, class U>
+TEST_CONSTEXPR_CXX20 bool test_all()
 {
     {
-        optional<short> rhs;
-        test<int>(std::move(rhs));
+        optional<T> rhs;
+        test<U>(std::move(rhs));
     }
     {
-        optional<short> rhs(short{3});
-        test<int>(std::move(rhs));
-    }
-    {
-        optional<int> rhs;
-        test<X>(std::move(rhs));
-    }
-    {
-        optional<int> rhs(3);
-        test<X>(std::move(rhs));
+        optional<T> rhs(short{3});
+        test<U>(std::move(rhs));
     }
+    return true;
+}
+
+int main(int, char**)
+{
+    test_all<short, int>();
+    test_all<int, X>();
+#if TEST_STD_VER > 17
+    static_assert(test_all<short, int>());
+    static_assert(test_all<int, X>());
+#endif
     {
         optional<int> rhs;
         test<Z>(std::move(rhs));

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.dtor/dtor.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.dtor/dtor.pass.cpp
index ed6467bc43d59..be127a6295d7f 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.dtor/dtor.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.dtor/dtor.pass.cpp
@@ -40,25 +40,21 @@ int main(int, char**)
         typedef int T;
         static_assert(std::is_trivially_destructible<T>::value, "");
         static_assert(std::is_trivially_destructible<optional<T>>::value, "");
-        static_assert(std::is_literal_type<optional<T>>::value, "");
     }
     {
         typedef double T;
         static_assert(std::is_trivially_destructible<T>::value, "");
         static_assert(std::is_trivially_destructible<optional<T>>::value, "");
-        static_assert(std::is_literal_type<optional<T>>::value, "");
     }
     {
         typedef PODType T;
         static_assert(std::is_trivially_destructible<T>::value, "");
         static_assert(std::is_trivially_destructible<optional<T>>::value, "");
-        static_assert(std::is_literal_type<optional<T>>::value, "");
     }
     {
         typedef X T;
         static_assert(!std::is_trivially_destructible<T>::value, "");
         static_assert(!std::is_trivially_destructible<optional<T>>::value, "");
-        static_assert(!std::is_literal_type<optional<T>>::value, "");
         {
             X x;
             optional<X> opt{x};

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp
index f04b19629e6fd..22544c98eb0e7 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp
@@ -28,7 +28,7 @@ struct X
 
 bool X::dtor_called = false;
 
-int main(int, char**)
+constexpr bool check_reset()
 {
     {
         optional<int> opt;
@@ -41,6 +41,15 @@ int main(int, char**)
         opt.reset();
         assert(static_cast<bool>(opt) == false);
     }
+    return true;
+}
+
+int main(int, char**)
+{
+    check_reset();
+#if TEST_STD_VER >= 20
+    static_assert(check_reset());
+#endif
     {
         optional<X> opt;
         static_assert(noexcept(opt.reset()) == true, "");

diff  --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp
index 298e49d72461e..bb5780865b9b4 100644
--- a/libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 // UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: gcc-10
 // <optional>
 
 // void swap(optional&)
@@ -63,13 +64,23 @@ class Z
     friend void swap(Z&, Z&) {TEST_THROW(6);}
 };
 
+class W
+{
+    int i_;
+public:
+    constexpr W(int i) : i_(i) {}
 
-int main(int, char**)
+    friend constexpr bool operator==(const W& x, const W& y) {return x.i_ == y.i_;}
+    friend TEST_CONSTEXPR_CXX20 void swap(W& x, W& y) noexcept {std::swap(x.i_, y.i_);}
+};
+
+template<class T>
+TEST_CONSTEXPR_CXX20 bool check_swap()
 {
     {
-        optional<int> opt1;
-        optional<int> opt2;
-        static_assert(noexcept(opt1.swap(opt2)) == true, "");
+        optional<T> opt1;
+        optional<T> opt2;
+        static_assert(noexcept(opt1.swap(opt2)) == true);
         assert(static_cast<bool>(opt1) == false);
         assert(static_cast<bool>(opt2) == false);
         opt1.swap(opt2);
@@ -77,9 +88,9 @@ int main(int, char**)
         assert(static_cast<bool>(opt2) == false);
     }
     {
-        optional<int> opt1(1);
-        optional<int> opt2;
-        static_assert(noexcept(opt1.swap(opt2)) == true, "");
+        optional<T> opt1(1);
+        optional<T> opt2;
+        static_assert(noexcept(opt1.swap(opt2)) == true);
         assert(static_cast<bool>(opt1) == true);
         assert(*opt1 == 1);
         assert(static_cast<bool>(opt2) == false);
@@ -89,8 +100,8 @@ int main(int, char**)
         assert(*opt2 == 1);
     }
     {
-        optional<int> opt1;
-        optional<int> opt2(2);
+        optional<T> opt1;
+        optional<T> opt2(2);
         static_assert(noexcept(opt1.swap(opt2)) == true, "");
         assert(static_cast<bool>(opt1) == false);
         assert(static_cast<bool>(opt2) == true);
@@ -101,8 +112,8 @@ int main(int, char**)
         assert(static_cast<bool>(opt2) == false);
     }
     {
-        optional<int> opt1(1);
-        optional<int> opt2(2);
+        optional<T> opt1(1);
+        optional<T> opt2(2);
         static_assert(noexcept(opt1.swap(opt2)) == true, "");
         assert(static_cast<bool>(opt1) == true);
         assert(*opt1 == 1);
@@ -114,6 +125,17 @@ int main(int, char**)
         assert(static_cast<bool>(opt2) == true);
         assert(*opt2 == 1);
     }
+    return true;
+}
+
+int main(int, char**)
+{
+    check_swap<int>();
+    check_swap<W>();
+#if TEST_STD_VER > 17
+    static_assert(check_swap<int>());
+    static_assert(check_swap<W>());
+#endif
     {
         optional<X> opt1;
         optional<X> opt2;


        


More information about the libcxx-commits mailing list