[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