diff --git a/libcxx/include/optional b/libcxx/include/optional --- a/libcxx/include/optional +++ b/libcxx/include/optional @@ -69,7 +69,7 @@ template constexpr bool operator>=(const T&, const optional&); // 23.6.9, specialized algorithms - template void swap(optional&, optional&) noexcept(see below ); + template void swap(optional&, optional&) noexcept(see below ); // constexpr in C++20 template constexpr optional make_optional(T&&); template constexpr optional make_optional(Args&&... args); @@ -95,12 +95,12 @@ template constexpr EXPLICIT optional(U &&); template - constexpr EXPLICIT optional(const optional &); + EXPLICIT optional(const optional &); // constexpr in C++20 template - constexpr EXPLICIT optional(optional &&); + EXPLICIT optional(optional &&); // 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; @@ -109,12 +109,12 @@ template optional &operator=(U &&); template optional &operator=(const optional &); template optional &operator=(optional &&); - template T& emplace(Args &&...); + template T& emplace(Args &&...); // constexpr in C++20 template - T& emplace(initializer_list, Args &&...); + T& emplace(initializer_list, 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 @@ template 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 @@ bool __engaged_; _LIBCPP_INLINE_VISIBILITY - ~__optional_destruct_base() + _LIBCPP_CONSTEXPR_AFTER_CXX17 ~__optional_destruct_base() { if (__engaged_) __val_.~value_type(); @@ -239,7 +239,7 @@ __engaged_(true) {} _LIBCPP_INLINE_VISIBILITY - void reset() noexcept + _LIBCPP_CONSTEXPR_AFTER_CXX17 void reset() noexcept { if (__engaged_) { @@ -274,7 +274,7 @@ __engaged_(true) {} _LIBCPP_INLINE_VISIBILITY - void reset() noexcept + _LIBCPP_CONSTEXPR_AFTER_CXX17 void reset() noexcept { if (__engaged_) { @@ -319,16 +319,20 @@ template _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 _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 @@ template _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 @@ } _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 @@ template _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 @@ template _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 @@ template _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 @@ __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 @@ __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) { this->__construct_from(_VSTD::move(__opt)); @@ -526,7 +530,7 @@ __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 @@ __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 && is_nothrow_move_constructible_v) { @@ -728,7 +732,7 @@ _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 @@ _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 @@ _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 @@ _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 @@ >::value> > _LIBCPP_INLINE_VISIBILITY - optional& + _LIBCPP_CONSTEXPR_AFTER_CXX17 optional& operator=(_Up&& __v) { if (this->has_value()) @@ -798,7 +802,7 @@ _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 @@ _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 @@ > > _LIBCPP_INLINE_VISIBILITY - _Tp & + _LIBCPP_CONSTEXPR_AFTER_CXX17 _Tp & emplace(_Args&&... __args) { reset(); @@ -839,7 +843,7 @@ > > _LIBCPP_INLINE_VISIBILITY - _Tp & + _LIBCPP_CONSTEXPR_AFTER_CXX17 _Tp & emplace(initializer_list<_Up> __il, _Args&&... __args) { reset(); @@ -848,7 +852,7 @@ } _LIBCPP_INLINE_VISIBILITY - void swap(optional& __opt) + _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(optional& __opt) noexcept(is_nothrow_move_constructible_v && is_nothrow_swappable_v) { @@ -1006,7 +1010,7 @@ private: template _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 @@ template -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 --- 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 @@ -26,11 +26,11 @@ 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 +46,7 @@ bool Y::dtor_called = false; template -void test_one_arg() { +constexpr bool test_one_arg() { using Opt = std::optional; { Opt opt; @@ -80,11 +80,12 @@ assert(*opt == T(1)); assert(&v == &*opt); } + return true; } template -void test_multi_arg() +constexpr bool test_multi_arg() { test_one_arg(); using Opt = std::optional; @@ -112,6 +113,7 @@ 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 @@ -206,7 +208,17 @@ } } - +constexpr bool test_empty_emplace() +{ + optional opt; + auto &v = opt.emplace(42); + static_assert( std::is_same_v, "" ); + assert(*opt == 42); + assert( v == 42); + opt.emplace(); + assert(*opt == 0); + return true; +} int main(int, char**) { @@ -218,31 +230,44 @@ using T = int; test_one_arg(); test_one_arg(); +#if TEST_STD_VER >= 20 + static_assert(test_one_arg()); + static_assert(test_one_arg()); +#endif } { using T = ConstexprTestTypes::TestType; test_multi_arg(); +#if TEST_STD_VER >= 20 + static_assert(test_multi_arg()); +#endif } { using T = ExplicitConstexprTestTypes::TestType; test_multi_arg(); +#if TEST_STD_VER >= 20 + static_assert(test_multi_arg()); +#endif } { using T = TrivialTestTypes::TestType; test_multi_arg(); +#if TEST_STD_VER >= 20 + static_assert(test_multi_arg()); +#endif } { using T = ExplicitTrivialTestTypes::TestType; test_multi_arg(); +#if TEST_STD_VER >= 20 + static_assert(test_multi_arg()); +#endif } { - optional opt; - auto &v = opt.emplace(42); - static_assert( std::is_same_v, "" ); - assert(*opt == 42); - assert( v == 42); - opt.emplace(); - assert(*opt == 0); + test_empty_emplace(); +#if TEST_STD_VER >= 20 + 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 --- 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 @@ -25,19 +25,18 @@ { 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 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 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 +68,38 @@ bool Z::dtor_called = false; +TEST_CONSTEXPR_CXX20 bool check_X() +{ + bool dtor_called = false; + X x(dtor_called); + optional opt(x); + assert(dtor_called == false); + auto &v = opt.emplace({1, 2}, dtor_called); + static_assert( std::is_same_v, "" ); + assert(dtor_called); + assert(*opt == X({1, 2}, dtor_called)); + assert(&v == &*opt); + return true; +} + +TEST_CONSTEXPR_CXX20 bool check_Y() +{ + optional opt; + auto &v = opt.emplace({1, 2}); + static_assert( std::is_same_v, "" ); + assert(static_cast(opt) == true); + assert(*opt == Y({1, 2})); + assert(&v == &*opt); + return true; +} + int main(int, char**) { { - X x; - optional opt(x); - assert(X::dtor_called == false); - auto &v = opt.emplace({1, 2}); - static_assert( std::is_same_v, "" ); - assert(X::dtor_called == true); - assert(*opt == X({1, 2})); - assert(&v == &*opt); + check_X(); +#if TEST_STD_VER >= 20 + static_assert(check_X()); +#endif } { optional> opt; @@ -90,12 +110,10 @@ assert(&v == &*opt); } { - optional opt; - auto &v = opt.emplace({1, 2}); - static_assert( std::is_same_v, "" ); - assert(static_cast(opt) == true); - assert(*opt == Y({1, 2})); - assert(&v == &*opt); + check_Y(); +#if TEST_STD_VER >= 20 + 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 --- 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,6 +22,51 @@ using std::nullopt_t; using std::nullopt; +#if TEST_STD_VER >= 20 +consteval bool test_consteval() +{ + enum class State { inactive, constructed, destroyed }; + State state = State::inactive; + + struct StateTracker { + constexpr StateTracker(State& s) + : state_(&s) + { + s = State::constructed; + } + constexpr ~StateTracker() { *state_ = State::destroyed; } + + State* state_; + }; + { + optional opt; + opt = nullopt; + assert(static_cast(opt) == false); + } + { + optional opt(3); + opt = nullopt; + assert(static_cast(opt) == false); + } + { + optional opt; + opt = nullopt; + assert(state == State::inactive); + assert(static_cast(opt) == false); + } + { + optional opt(state); + assert(state == State::constructed); + opt = nullopt; + assert(state == State::destroyed); + assert(static_cast(opt) == false); + } + return true; +} + +static_assert(test_consteval()); +#endif + int main(int, char**) { { 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 --- 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 @@ -21,7 +21,7 @@ using std::optional; template -void +TEST_CONSTEXPR_CXX20 void test(const optional& rhs, bool is_going_to_throw = false) { bool rhs_engaged = static_cast(rhs); @@ -51,17 +51,17 @@ { 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 +74,33 @@ 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 +constexpr bool test_all() +{ + { + optional rhs; + test(rhs); + } + { + optional rhs(U{3}); + test(rhs); + } + return true; +} int main(int, char**) { - { - typedef short U; - typedef int T; - optional rhs; - test(rhs); - } - { - typedef short U; - typedef int T; - optional rhs(U{3}); - test(rhs); - } - { - typedef X T; - typedef int U; - optional rhs; - test(rhs); - } - { - typedef X T; - typedef int U; - optional rhs(U{3}); - test(rhs); - } - { - typedef Y T; - typedef int U; - optional rhs; - test(rhs); - } - { - typedef Y T; - typedef int U; - optional rhs(U{3}); - test(rhs); - } + test_all(); + test_all(); + test_all(); +#if TEST_STD_VER >= 20 + static_assert(test_all()); + static_assert(test_all()); + static_assert(test_all()); +#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 --- 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 @@ -21,7 +21,7 @@ using std::optional; template -void +TEST_CONSTEXPR_CXX20 void test(const optional& rhs, bool is_going_to_throw = false) { static_assert(!(std::is_convertible&, optional>::value), ""); @@ -52,17 +52,17 @@ { 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 +73,34 @@ { 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 +constexpr bool test_all() +{ + { + optional rhs; + test(rhs); + } + { + optional rhs(3); + test(rhs); + } + return true; +} + int main(int, char**) { - { - typedef X T; - typedef int U; - optional rhs; - test(rhs); - } - { - typedef X T; - typedef int U; - optional rhs(3); - test(rhs); - } - { - typedef Y T; - typedef int U; - optional rhs; - test(rhs); - } - { - typedef Y T; - typedef int U; - optional rhs(3); - test(rhs); - } + test_all(); + test_all(); +#if TEST_STD_VER >= 20 + static_assert(test_all()); + static_assert(test_all()); +#endif { typedef Z T; typedef int U; 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 --- 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 // // constexpr optional(const optional&& 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 --- 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 @@ -22,7 +22,7 @@ using std::optional; template -void +TEST_CONSTEXPR_CXX20 void test(optional&& rhs, bool is_going_to_throw = false) { bool rhs_engaged = static_cast(rhs); @@ -48,37 +48,39 @@ { 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_;} + constexpr 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; - struct Z { Z(int) { TEST_THROW(6); } }; -int main(int, char**) +template +constexpr bool test_all() { { - optional rhs; - test(std::move(rhs)); + optional rhs; + test(std::move(rhs)); } { - optional rhs(short{3}); - test(std::move(rhs)); - } - { - optional rhs; - test(std::move(rhs)); - } - { - optional rhs(3); - test(std::move(rhs)); + optional rhs(short{3}); + test(std::move(rhs)); } + return true; +} + +int main(int, char**) +{ + test_all(); + test_all(); +#if TEST_STD_VER >= 20 + static_assert(test_all()); + static_assert(test_all()); +#endif { optional rhs; test(std::move(rhs)); 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 --- 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 @@ bool X::dtor_called = false; -int main(int, char**) +constexpr bool check_reset() { { optional opt; @@ -41,6 +41,15 @@ opt.reset(); assert(static_cast(opt) == false); } + return true; +} + +int main(int, char**) +{ + check_reset(); +#if TEST_STD_VER >= 20 + static_assert(check_reset()); +#endif { optional 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 --- 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 @@ -63,57 +63,78 @@ friend void swap(Z&, Z&) {TEST_THROW(6);} }; +class W +{ + int i_; +public: + constexpr W(int i) : i_(i) {} + + friend constexpr bool operator==(const W& x, const W& y) {return x.i_ == y.i_;} + friend constexpr void swap(W& x, W& y) noexcept {std::swap(x.i_, y.i_);} +}; + +template +constexpr bool check_swap() { + { + optional opt1; + optional opt2; + static_assert(noexcept(opt1.swap(opt2)) == true); + assert(static_cast(opt1) == false); + assert(static_cast(opt2) == false); + opt1.swap(opt2); + assert(static_cast(opt1) == false); + assert(static_cast(opt2) == false); + } + { + optional opt1(1); + optional opt2; + static_assert(noexcept(opt1.swap(opt2)) == true); + assert(static_cast(opt1) == true); + assert(*opt1 == 1); + assert(static_cast(opt2) == false); + opt1.swap(opt2); + assert(static_cast(opt1) == false); + assert(static_cast(opt2) == true); + assert(*opt2 == 1); + } + { + optional opt1; + optional opt2(2); + static_assert(noexcept(opt1.swap(opt2)) == true, ""); + assert(static_cast(opt1) == false); + assert(static_cast(opt2) == true); + assert(*opt2 == 2); + opt1.swap(opt2); + assert(static_cast(opt1) == true); + assert(*opt1 == 2); + assert(static_cast(opt2) == false); + } + { + optional opt1(1); + optional opt2(2); + static_assert(noexcept(opt1.swap(opt2)) == true, ""); + assert(static_cast(opt1) == true); + assert(*opt1 == 1); + assert(static_cast(opt2) == true); + assert(*opt2 == 2); + opt1.swap(opt2); + assert(static_cast(opt1) == true); + assert(*opt1 == 2); + assert(static_cast(opt2) == true); + assert(*opt2 == 1); + } + return true; +} int main(int, char**) { - { - optional opt1; - optional opt2; - static_assert(noexcept(opt1.swap(opt2)) == true, ""); - assert(static_cast(opt1) == false); - assert(static_cast(opt2) == false); - opt1.swap(opt2); - assert(static_cast(opt1) == false); - assert(static_cast(opt2) == false); - } - { - optional opt1(1); - optional opt2; - static_assert(noexcept(opt1.swap(opt2)) == true, ""); - assert(static_cast(opt1) == true); - assert(*opt1 == 1); - assert(static_cast(opt2) == false); - opt1.swap(opt2); - assert(static_cast(opt1) == false); - assert(static_cast(opt2) == true); - assert(*opt2 == 1); - } - { - optional opt1; - optional opt2(2); - static_assert(noexcept(opt1.swap(opt2)) == true, ""); - assert(static_cast(opt1) == false); - assert(static_cast(opt2) == true); - assert(*opt2 == 2); - opt1.swap(opt2); - assert(static_cast(opt1) == true); - assert(*opt1 == 2); - assert(static_cast(opt2) == false); - } - { - optional opt1(1); - optional opt2(2); - static_assert(noexcept(opt1.swap(opt2)) == true, ""); - assert(static_cast(opt1) == true); - assert(*opt1 == 1); - assert(static_cast(opt2) == true); - assert(*opt2 == 2); - opt1.swap(opt2); - assert(static_cast(opt1) == true); - assert(*opt1 == 2); - assert(static_cast(opt2) == true); - assert(*opt2 == 1); - } + check_swap(); + check_swap(); +#if TEST_STD_VER >= 20 + static_assert(check_swap()); + static_assert(check_swap()); +#endif + { optional opt1; optional opt2; diff --git a/libcxx/test/support/archetypes.h b/libcxx/test/support/archetypes.h --- a/libcxx/test/support/archetypes.h +++ b/libcxx/test/support/archetypes.h @@ -47,47 +47,47 @@ static int move_assigned; static int destroyed; - static void reset() { + TEST_CONSTEXPR_CXX20 static void reset() { assert(alive == 0); alive = 0; reset_constructors(); } - static void reset_constructors() { + TEST_CONSTEXPR_CXX20 static void reset_constructors() { constructed = value_constructed = default_constructed = copy_constructed = move_constructed = 0; assigned = value_assigned = copy_assigned = move_assigned = destroyed = 0; } - TestBase() noexcept : value(0) { + TEST_CONSTEXPR_CXX20 TestBase() noexcept : value(0) { ++alive; ++constructed; ++default_constructed; } template ::type = true> - explicit TestBase(int x) noexcept : value(x) { + TEST_CONSTEXPR_CXX20 explicit TestBase(int x) noexcept : value(x) { ++alive; ++constructed; ++value_constructed; } template ::type = true> - TestBase(int x) noexcept : value(x) { + TEST_CONSTEXPR_CXX20 TestBase(int x) noexcept : value(x) { ++alive; ++constructed; ++value_constructed; } template ::type = true> - explicit TestBase(int, int y) noexcept : value(y) { + TEST_CONSTEXPR_CXX20 explicit TestBase(int, int y) noexcept : value(y) { ++alive; ++constructed; ++value_constructed; } template ::type = true> - TestBase(int, int y) noexcept : value(y) { + TEST_CONSTEXPR_CXX20 TestBase(int, int y) noexcept : value(y) { ++alive; ++constructed; ++value_constructed; } template ::type = true> - explicit TestBase(std::initializer_list& il, int = 0) noexcept + TEST_CONSTEXPR_CXX20 explicit TestBase(std::initializer_list& il, int = 0) noexcept : value(static_cast(il.size())) { ++alive; ++constructed; ++value_constructed; } template ::type = true> - explicit TestBase(std::initializer_list& il, int = 0) noexcept : value(static_cast(il.size())) { + TEST_CONSTEXPR_CXX20 explicit TestBase(std::initializer_list& il, int = 0) noexcept : value(static_cast(il.size())) { ++alive; ++constructed; ++value_constructed; } - TestBase& operator=(int xvalue) noexcept { + TEST_CONSTEXPR_CXX20 TestBase& operator=(int xvalue) noexcept { value = xvalue; ++assigned; ++value_assigned; return *this; @@ -95,26 +95,26 @@ #ifndef TEST_WORKAROUND_C1XX_BROKEN_ZA_CTOR_CHECK protected: #endif // !TEST_WORKAROUND_C1XX_BROKEN_ZA_CTOR_CHECK - ~TestBase() { + TEST_CONSTEXPR_CXX20 ~TestBase() { assert(value != -999); assert(alive > 0); --alive; ++destroyed; value = -999; } - explicit TestBase(TestBase const& o) noexcept : value(o.value) { + TEST_CONSTEXPR_CXX20 explicit TestBase(TestBase const& o) noexcept : value(o.value) { assert(o.value != -1); assert(o.value != -999); ++alive; ++constructed; ++copy_constructed; } - explicit TestBase(TestBase && o) noexcept : value(o.value) { + TEST_CONSTEXPR_CXX20 explicit TestBase(TestBase && o) noexcept : value(o.value) { assert(o.value != -1); assert(o.value != -999); ++alive; ++constructed; ++move_constructed; o.value = -1; } - TestBase& operator=(TestBase const& o) noexcept { + TEST_CONSTEXPR_CXX20 TestBase& operator=(TestBase const& o) noexcept { assert(o.value != -1); assert(o.value != -999); ++assigned; ++copy_assigned; value = o.value; return *this; } - TestBase& operator=(TestBase&& o) noexcept { + TEST_CONSTEXPR_CXX20 TestBase& operator=(TestBase&& o) noexcept { assert(o.value != -1); assert(o.value != -999); ++assigned; ++move_assigned; value = o.value;