diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv --- a/libcxx/docs/Cxx2aStatusPaperStatus.csv +++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -193,3 +193,4 @@ "`P2102 `__","LWG","Make 'implicit expression variations' more explicit (Wording for US185)","Prague","* *","" "`P2106 `__","LWG","Alternative wording for GB315 and GB316","Prague","* *","" "`P2116 `__","LWG","Remove tuple-like protocol support from fixed-extent span","Prague","|Complete|","11.0" +"`P2231 `__","LWG","Missing constexpr in std::optional and std::variant","February 2021","|In progress|","13.0" diff --git a/libcxx/docs/Cxx2bStatus.rst b/libcxx/docs/Cxx2bStatus.rst --- a/libcxx/docs/Cxx2bStatus.rst +++ b/libcxx/docs/Cxx2bStatus.rst @@ -37,6 +37,10 @@ :header-rows: 1 :widths: auto +.. note:: + + .. [#note-P2231] P2231: Implemented ahead of time and backported to C++20, so as to not block C++20 ranges. + .. _issues-status-cxx2b: Library Working Group Issues Status 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,26 +95,26 @@ 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; - optional &operator=(const optional &); // constexpr in C++20 - optional &operator=(optional &&) noexcept(see below); // constexpr in C++20 - template optional &operator=(U &&); - template optional &operator=(const optional &); - template optional &operator=(optional &&); - template 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 optional &operator=(U &&); // constexpr in C++20 + template optional &operator=(const optional &); // constexpr in C++20 + template optional &operator=(optional &&); // constexpr in C++20 + 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 @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: gcc-10 // // template T& optional::emplace(Args&&... args); @@ -26,11 +27,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 +47,7 @@ bool Y::dtor_called = false; template -void test_one_arg() { +constexpr bool test_one_arg() { using Opt = std::optional; { Opt opt; @@ -80,11 +81,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 +114,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 +209,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 +231,32 @@ using T = int; test_one_arg(); test_one_arg(); + static_assert(test_one_arg()); + static_assert(test_one_arg()); } { using T = ConstexprTestTypes::TestType; test_multi_arg(); + static_assert(test_multi_arg()); } { using T = ExplicitConstexprTestTypes::TestType; test_multi_arg(); + static_assert(test_multi_arg()); } { using T = TrivialTestTypes::TestType; test_multi_arg(); + static_assert(test_multi_arg()); } { using T = ExplicitTrivialTestTypes::TestType; test_multi_arg(); + static_assert(test_multi_arg()); } { - 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(); + static_assert(test_empty_emplace()); } #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 @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: gcc-10 // // template @@ -25,19 +26,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 +69,36 @@ 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(); + static_assert(check_X()); } { optional> opt; @@ -90,12 +109,8 @@ 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(); + static_assert(check_Y()); } #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,8 +22,21 @@ 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 opt; static_assert(noexcept(opt = nullopt) == true, ""); @@ -35,6 +48,27 @@ 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; +} + + +int main(int, char**) +{ + static_assert(test()); + 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 --- 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& operator=(optional&& rhs); #include -#include -#include + +#include #include +#include +#include #include "test_macros.h" #include "archetypes.h" @@ -201,10 +203,8 @@ } -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { - test_with_test_type(); - test_ambiguous_assign(); { optional opt; optional opt2; @@ -237,6 +237,75 @@ assert(static_cast(opt) == static_cast(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(state[0]); + assert(state[0] == state_t::constructed); + + auto opt2 = std::optional(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(state[0]); + assert(state[0] == state_t::constructed); + + auto opt2 = std::optional(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> opt; optional> 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 --- 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 // // template @@ -21,7 +22,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 +52,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 +75,31 @@ 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(); + static_assert(test_all()); + static_assert(test_all()); + static_assert(test_all()); { 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 @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: gcc-10 // // template @@ -21,7 +22,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 +53,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 +74,32 @@ { 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(); + static_assert(test_all()); + static_assert(test_all()); { 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 --- 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 -void -test(optional&& rhs, bool is_going_to_throw = false) +TEST_CONSTEXPR_CXX20 void test(optional&& rhs, bool is_going_to_throw = false) { static_assert(!(std::is_convertible&&, optional>::value), ""); bool rhs_engaged = static_cast(rhs); @@ -48,10 +47,10 @@ { 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 @@ explicit Z(int) { TEST_THROW(6); } }; -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { { optional rhs; @@ -72,6 +71,16 @@ optional rhs(3); test(std::move(rhs)); } + + return true; +} + +int main(int, char**) +{ +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + test(); { optional rhs; test(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 --- 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 @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: gcc-10 // // template @@ -22,7 +23,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 +49,37 @@ { 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 +TEST_CONSTEXPR_CXX20 bool test_all() { { - optional rhs; - test(std::move(rhs)); - } - { - optional rhs(short{3}); - test(std::move(rhs)); - } - { - optional rhs; - 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(); + static_assert(test_all()); + static_assert(test_all()); { optional rhs; test(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 --- 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 @@ typedef int T; static_assert(std::is_trivially_destructible::value, ""); static_assert(std::is_trivially_destructible>::value, ""); - static_assert(std::is_literal_type>::value, ""); } { typedef double T; static_assert(std::is_trivially_destructible::value, ""); static_assert(std::is_trivially_destructible>::value, ""); - static_assert(std::is_literal_type>::value, ""); } { typedef PODType T; static_assert(std::is_trivially_destructible::value, ""); static_assert(std::is_trivially_destructible>::value, ""); - static_assert(std::is_literal_type>::value, ""); } { typedef X T; static_assert(!std::is_trivially_destructible::value, ""); static_assert(!std::is_trivially_destructible>::value, ""); - static_assert(!std::is_literal_type>::value, ""); { X x; optional 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 --- 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 @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: gcc-10 // // void swap(optional&) @@ -63,13 +64,23 @@ 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 +TEST_CONSTEXPR_CXX20 bool check_swap() { { - optional opt1; - optional opt2; - static_assert(noexcept(opt1.swap(opt2)) == true, ""); + optional opt1; + optional opt2; + static_assert(noexcept(opt1.swap(opt2)) == true); assert(static_cast(opt1) == false); assert(static_cast(opt2) == false); opt1.swap(opt2); @@ -77,9 +88,9 @@ assert(static_cast(opt2) == false); } { - optional opt1(1); - optional opt2; - static_assert(noexcept(opt1.swap(opt2)) == true, ""); + 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); @@ -89,8 +100,8 @@ assert(*opt2 == 1); } { - optional opt1; - optional opt2(2); + optional opt1; + optional opt2(2); static_assert(noexcept(opt1.swap(opt2)) == true, ""); assert(static_cast(opt1) == false); assert(static_cast(opt2) == true); @@ -101,8 +112,8 @@ assert(static_cast(opt2) == false); } { - optional opt1(1); - optional opt2(2); + optional opt1(1); + optional opt2(2); static_assert(noexcept(opt1.swap(opt2)) == true, ""); assert(static_cast(opt1) == true); assert(*opt1 == 1); @@ -114,6 +125,16 @@ assert(static_cast(opt2) == true); assert(*opt2 == 1); } + return true; +} + +int main(int, char**) +{ + check_swap(); + check_swap(); + static_assert(check_swap()); + static_assert(check_swap()); + { 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;