Index: include/optional =================================================================== --- include/optional +++ include/optional @@ -105,8 +105,8 @@ // 23.6.3.3, assignment optional &operator=(nullopt_t) noexcept; - optional &operator=(const optional &); - optional &operator=(optional &&) noexcept(see below ); + 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 &&); Index: include/variant =================================================================== --- include/variant +++ include/variant @@ -23,8 +23,8 @@ // 20.7.2.1, constructors constexpr variant() noexcept(see below); - variant(const variant&); - variant(variant&&) noexcept(see below); + variant(const variant&); // constexpr in C++20 + variant(variant&&) noexcept(see below); // constexpr in C++20 template constexpr variant(T&&) noexcept(see below); @@ -46,8 +46,8 @@ ~variant(); // 20.7.2.3, assignment - variant& operator=(const variant&); - variant& operator=(variant&&) noexcept(see below); + variant& operator=(const variant&); // constexpr in C++20 + variant& operator=(variant&&) noexcept(see below); // constexpr in C++20 template variant& operator=(T&&) noexcept(see below); Index: test/libcxx/utilities/optional/optional.object/triviality.abi.pass.cpp =================================================================== --- test/libcxx/utilities/optional/optional.object/triviality.abi.pass.cpp +++ test/libcxx/utilities/optional/optional.object/triviality.abi.pass.cpp @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// This test asserts the triviality of special member functions of optional +// whenever T has these special member functions trivial. The goal of this test +// is to make sure that we do not change the triviality of those, since that +// constitues an ABI break (small enough optionals would be passed by registers). +// +// constexpr optional(const optional& rhs); +// constexpr optional(optional&& rhs) noexcept(see below); +// constexpr optional& operator=(const optional& rhs); +// constexpr optional& operator=(optional&& rhs) noexcept(see below); + +#include +#include +#include + +#include "archetypes.hpp" + +template +struct SpecialMemberTest { + using O = std::optional; + + static_assert(std::is_trivially_destructible_v == + std::is_trivially_destructible_v, + "optional is trivially destructible if and only if T is."); + + static_assert(std::is_trivially_copy_constructible_v == + std::is_trivially_copy_constructible_v, + "optional is trivially copy constructible if and only if T is."); + + static_assert(std::is_trivially_move_constructible_v == + std::is_trivially_move_constructible_v || + (!std::is_move_constructible_v && std::is_trivially_copy_constructible_v), + "optional is trivially move constructible if T is trivially move constructible, " + "or if T is trivially copy constructible and is not move constructible."); + + static_assert(std::is_trivially_copy_assignable_v == + (std::is_trivially_destructible_v && + std::is_trivially_copy_constructible_v && + std::is_trivially_copy_assignable_v), + "optional is trivially copy assignable if and only if T is trivially destructible, " + "trivially copy constructible, and trivially copy assignable."); + + static_assert(std::is_trivially_move_assignable_v == + (std::is_trivially_destructible_v && + ((std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v) || + ((!std::is_move_constructible_v || !std::is_move_assignable_v) && + std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v))), + "optional is trivially move assignable if T is trivially destructible, and either " + "(1) trivially move constructible and trivially move assignable, or " + "(2) not move constructible or not move assignable, and " + "trivially copy constructible and trivially copy assignable."); +}; + +template static void sink(Args&&...) {} + +template +struct DoTestsMetafunction { + DoTestsMetafunction() { sink(SpecialMemberTest{}...); } +}; + +struct TrivialMoveNonTrivialCopy { + TrivialMoveNonTrivialCopy() = default; + TrivialMoveNonTrivialCopy(const TrivialMoveNonTrivialCopy&) {} + TrivialMoveNonTrivialCopy(TrivialMoveNonTrivialCopy&&) = default; + TrivialMoveNonTrivialCopy& operator=(const TrivialMoveNonTrivialCopy&) { return *this; } + TrivialMoveNonTrivialCopy& operator=(TrivialMoveNonTrivialCopy&&) = default; +}; + +struct TrivialCopyNonTrivialMove { + TrivialCopyNonTrivialMove() = default; + TrivialCopyNonTrivialMove(const TrivialCopyNonTrivialMove&) = default; + TrivialCopyNonTrivialMove(TrivialCopyNonTrivialMove&&) {} + TrivialCopyNonTrivialMove& operator=(const TrivialCopyNonTrivialMove&) = default; + TrivialCopyNonTrivialMove& operator=(TrivialCopyNonTrivialMove&&) { return *this; } +}; + +int main() +{ + sink( + ImplicitTypes::ApplyTypes{}, + ExplicitTypes::ApplyTypes{}, + NonLiteralTypes::ApplyTypes{}, + NonTrivialTypes::ApplyTypes{}, + DoTestsMetafunction{} + ); +} Index: test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp =================================================================== --- test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp +++ test/std/utilities/optional/optional.object/optional.object.assign/copy.pass.cpp @@ -10,7 +10,7 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 // -// optional& operator=(const optional& rhs); +// optional& operator=(const optional& rhs); // constexpr in C++20 #include #include @@ -53,15 +53,19 @@ { { using O = optional; +#if TEST_STD_VER > 17 LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); +#endif assert(assign_empty(O{42})); assert(assign_value(O{42})); } { using O = optional; +#if TEST_STD_VER > 17 LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); +#endif assert(assign_empty(O{42})); assert(assign_value(O{42})); } Index: test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp =================================================================== --- test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp +++ test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp @@ -12,11 +12,12 @@ // optional& operator=(optional&& rhs) // noexcept(is_nothrow_move_assignable::value && -// is_nothrow_move_constructible::value); +// is_nothrow_move_constructible::value); // constexpr in C++20 #include -#include #include +#include +#include #include "test_macros.h" #include "archetypes.hpp" @@ -51,6 +52,21 @@ bool X::throw_now = false; int X::alive = 0; + +template +constexpr bool assign_empty(optional&& lhs) { + optional rhs; + lhs = std::move(rhs); + return !lhs.has_value() && !rhs.has_value(); +} + +template +constexpr bool assign_value(optional&& lhs) { + optional rhs(101); + lhs = std::move(rhs); + return lhs.has_value() && rhs.has_value() && *lhs == Tp{101}; +} + int main() { { @@ -97,6 +113,24 @@ assert(static_cast(opt) == static_cast(opt2)); assert(*opt == *opt2); } + { + using O = optional; +#if TEST_STD_VER > 17 + LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); + LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); +#endif + assert(assign_empty(O{42})); + assert(assign_value(O{42})); + } + { + using O = optional; +#if TEST_STD_VER > 17 + LIBCPP_STATIC_ASSERT(assign_empty(O{42}), ""); + LIBCPP_STATIC_ASSERT(assign_value(O{42}), ""); +#endif + assert(assign_empty(O{42})); + assert(assign_value(O{42})); + } #ifndef TEST_HAS_NO_EXCEPTIONS { static_assert(!std::is_nothrow_move_assignable>::value, ""); Index: test/std/utilities/optional/optional.object/optional.object.ctor/copy.fail.cpp =================================================================== --- test/std/utilities/optional/optional.object/optional.object.ctor/copy.fail.cpp +++ test/std/utilities/optional/optional.object/optional.object.ctor/copy.fail.cpp @@ -1,36 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++98, c++03, c++11, c++14 -// - -// constexpr optional(const optional& rhs); -// If is_trivially_copy_constructible_v is true, -// this constructor shall be a constexpr constructor. - -#include -#include -#include - -#include "test_macros.h" - -struct S { - constexpr S() : v_(0) {} - S(int v) : v_(v) {} - S(const S &rhs) : v_(rhs.v_) {} // make it not trivially copyable - int v_; -}; - - -int main() -{ - static_assert (!std::is_trivially_copy_constructible_v, "" ); - constexpr std::optional o1; - constexpr std::optional o2 = o1; // not constexpr -} Index: test/std/utilities/optional/optional.object/special_member_gen.pass.cpp =================================================================== --- test/std/utilities/optional/optional.object/special_member_gen.pass.cpp +++ test/std/utilities/optional/optional.object/special_member_gen.pass.cpp @@ -1,102 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++98, c++03, c++11, c++14 -// - - -#include -#include -#include - -#include "archetypes.hpp" - -template -struct SpecialMemberTest { - using O = std::optional; - - static_assert(std::is_default_constructible_v, - "optional is always default constructible."); - static_assert(std::is_copy_constructible_v == std::is_copy_constructible_v, - "optional is copy constructible if and only if T is copy constructible."); - static_assert(std::is_move_constructible_v == - (std::is_copy_constructible_v || std::is_move_constructible_v), - "optional is move constructible if and only if T is copy or move constructible."); - static_assert(std::is_copy_assignable_v == - (std::is_copy_constructible_v && std::is_copy_assignable_v), - "optional is copy assignable if and only if T is both copy " - "constructible and copy assignable."); - static_assert(std::is_move_assignable_v == - ((std::is_move_constructible_v && std::is_move_assignable_v) || - (std::is_copy_constructible_v && std::is_copy_assignable_v)), - "optional is move assignable if and only if T is both move constructible and " - "move assignable, or both copy constructible and copy assignable."); - - // The following tests are for not-yet-standardized behavior (P0602): - static_assert(std::is_trivially_destructible_v == - std::is_trivially_destructible_v, - "optional is trivially destructible if and only if T is."); - static_assert(std::is_trivially_copy_constructible_v == - std::is_trivially_copy_constructible_v, - "optional is trivially copy constructible if and only if T is."); - static_assert(std::is_trivially_move_constructible_v == - std::is_trivially_move_constructible_v || - (!std::is_move_constructible_v && std::is_trivially_copy_constructible_v), - "optional is trivially move constructible if T is trivially move constructible, " - "or if T is trivially copy constructible and is not move constructible."); - static_assert(std::is_trivially_copy_assignable_v == - (std::is_trivially_destructible_v && - std::is_trivially_copy_constructible_v && - std::is_trivially_copy_assignable_v), - "optional is trivially copy assignable if and only if T is trivially destructible, " - "trivially copy constructible, and trivially copy assignable."); - static_assert(std::is_trivially_move_assignable_v == - (std::is_trivially_destructible_v && - ((std::is_trivially_move_constructible_v && std::is_trivially_move_assignable_v) || - ((!std::is_move_constructible_v || !std::is_move_assignable_v) && - std::is_trivially_copy_constructible_v && std::is_trivially_copy_assignable_v))), - "optional is trivially move assignable if T is trivially destructible, and either " - "(1) trivially move constructible and trivially move assignable, or " - "(2) not move constructible or not move assignable, and " - "trivially copy constructible and trivially copy assignable."); -}; - -template static void sink(Args&&...) {} - -template -struct DoTestsMetafunction { - DoTestsMetafunction() { sink(SpecialMemberTest{}...); } -}; - -struct TrivialMoveNonTrivialCopy { - TrivialMoveNonTrivialCopy() = default; - TrivialMoveNonTrivialCopy(const TrivialMoveNonTrivialCopy&) {} - TrivialMoveNonTrivialCopy(TrivialMoveNonTrivialCopy&&) = default; - TrivialMoveNonTrivialCopy& operator=(const TrivialMoveNonTrivialCopy&) { return *this; } - TrivialMoveNonTrivialCopy& operator=(TrivialMoveNonTrivialCopy&&) = default; -}; - -struct TrivialCopyNonTrivialMove { - TrivialCopyNonTrivialMove() = default; - TrivialCopyNonTrivialMove(const TrivialCopyNonTrivialMove&) = default; - TrivialCopyNonTrivialMove(TrivialCopyNonTrivialMove&&) {} - TrivialCopyNonTrivialMove& operator=(const TrivialCopyNonTrivialMove&) = default; - TrivialCopyNonTrivialMove& operator=(TrivialCopyNonTrivialMove&&) { return *this; } -}; - -int main() -{ - sink( - ImplicitTypes::ApplyTypes{}, - ExplicitTypes::ApplyTypes{}, - NonLiteralTypes::ApplyTypes{}, - NonTrivialTypes::ApplyTypes{}, - DoTestsMetafunction{} - ); -} Index: test/std/utilities/optional/optional.object/special_members.pass.cpp =================================================================== --- test/std/utilities/optional/optional.object/special_members.pass.cpp +++ test/std/utilities/optional/optional.object/special_members.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// Make sure we properly generate special member functions for optional +// based on the properties of T itself. + +#include +#include + +#include "archetypes.hpp" + + +template +struct SpecialMemberTest { + using O = std::optional; + + static_assert(std::is_default_constructible_v, + "optional is always default constructible."); + + static_assert(std::is_copy_constructible_v == std::is_copy_constructible_v, + "optional is copy constructible if and only if T is copy constructible."); + + static_assert(std::is_move_constructible_v == + (std::is_copy_constructible_v || std::is_move_constructible_v), + "optional is move constructible if and only if T is copy or move constructible."); + + static_assert(std::is_copy_assignable_v == + (std::is_copy_constructible_v && std::is_copy_assignable_v), + "optional is copy assignable if and only if T is both copy " + "constructible and copy assignable."); + + static_assert(std::is_move_assignable_v == + ((std::is_move_constructible_v && std::is_move_assignable_v) || + (std::is_copy_constructible_v && std::is_copy_assignable_v)), + "optional is move assignable if and only if T is both move constructible and " + "move assignable, or both copy constructible and copy assignable."); +}; + +template static void sink(Args&&...) {} + +template +struct DoTestsMetafunction { + DoTestsMetafunction() { sink(SpecialMemberTest{}...); } +}; + +int main() { + sink( + ImplicitTypes::ApplyTypes{}, + ExplicitTypes::ApplyTypes{}, + NonLiteralTypes::ApplyTypes{}, + NonTrivialTypes::ApplyTypes{} + ); +} Index: test/std/utilities/optional/optional.object/triviality.pass.cpp =================================================================== --- test/std/utilities/optional/optional.object/triviality.pass.cpp +++ test/std/utilities/optional/optional.object/triviality.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17 + +// + +// The following special member functions should propagate the triviality of +// the element held in the optional (see P0602R4): +// +// constexpr optional(const optional& rhs); +// constexpr optional(optional&& rhs) noexcept(see below); +// constexpr optional& operator=(const optional& rhs); +// constexpr optional& operator=(optional&& rhs) noexcept(see below); + + +#include +#include + +#include "archetypes.hpp" + + +constexpr bool implies(bool p, bool q) { + return !p || q; +} + +template +struct SpecialMemberTest { + using O = std::optional; + + static_assert(implies(std::is_trivially_copy_constructible_v, + std::is_trivially_copy_constructible_v), + "optional is trivially copy constructible if T is trivially copy constructible."); + + static_assert(implies(std::is_trivially_move_constructible_v, + std::is_trivially_move_constructible_v), + "optional is trivially move constructible if T is trivially move constructible"); + + static_assert(implies(std::is_trivially_copy_constructible_v && + std::is_trivially_copy_assignable_v && + std::is_trivially_destructible_v, + + std::is_trivially_copy_assignable_v), + "optional is trivially copy assignable if T is " + "trivially copy constructible, " + "trivially copy assignable, and " + "trivially destructible"); + + static_assert(implies(std::is_trivially_move_constructible_v && + std::is_trivially_move_assignable_v && + std::is_trivially_destructible_v, + + std::is_trivially_move_assignable_v), + "optional is trivially move assignable if T is " + "trivially move constructible, " + "trivially move assignable, and" + "trivially destructible."); +}; + +template static void sink(Args&&...) {} + +template +struct DoTestsMetafunction { + DoTestsMetafunction() { sink(SpecialMemberTest{}...); } +}; + +struct TrivialMoveNonTrivialCopy { + TrivialMoveNonTrivialCopy() = default; + TrivialMoveNonTrivialCopy(const TrivialMoveNonTrivialCopy&) {} + TrivialMoveNonTrivialCopy(TrivialMoveNonTrivialCopy&&) = default; + TrivialMoveNonTrivialCopy& operator=(const TrivialMoveNonTrivialCopy&) { return *this; } + TrivialMoveNonTrivialCopy& operator=(TrivialMoveNonTrivialCopy&&) = default; +}; + +struct TrivialCopyNonTrivialMove { + TrivialCopyNonTrivialMove() = default; + TrivialCopyNonTrivialMove(const TrivialCopyNonTrivialMove&) = default; + TrivialCopyNonTrivialMove(TrivialCopyNonTrivialMove&&) {} + TrivialCopyNonTrivialMove& operator=(const TrivialCopyNonTrivialMove&) = default; + TrivialCopyNonTrivialMove& operator=(TrivialCopyNonTrivialMove&&) { return *this; } +}; + +int main() { + sink( + ImplicitTypes::ApplyTypes{}, + ExplicitTypes::ApplyTypes{}, + NonLiteralTypes::ApplyTypes{}, + NonTrivialTypes::ApplyTypes{}, + DoTestsMetafunction{} + ); +} Index: test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp =================================================================== --- test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.assign/copy.pass.cpp @@ -26,7 +26,7 @@ // template class variant; -// variant& operator=(variant const&); +// variant& operator=(variant const&); // constexpr in C++20 #include #include @@ -240,7 +240,8 @@ static_assert(!std::is_copy_assignable::value, ""); } - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality (see P0602R4). +#if TEST_STD_VER > 17 { using V = std::variant; static_assert(std::is_trivially_copy_assignable::value, ""); @@ -262,6 +263,7 @@ using V = std::variant; static_assert(std::is_trivially_copy_assignable::value, ""); } +#endif // > C++17 } void test_copy_assignment_empty_empty() { @@ -384,7 +386,8 @@ } #endif // TEST_HAS_NO_EXCEPTIONS - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -441,6 +444,7 @@ static_assert(result.index == 1, ""); static_assert(result.value == 42, ""); } +#endif // > C++17 } void test_copy_assignment_different_index() { @@ -530,7 +534,8 @@ } #endif // TEST_HAS_NO_EXCEPTIONS - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -559,10 +564,11 @@ static_assert(result.index == 1, ""); static_assert(result.value == 42, ""); } +#endif // > C++17 } template -constexpr bool test_constexpr_assign_extension_imp( +constexpr bool test_constexpr_assign_imp( std::variant&& v, ValueType&& new_value) { const std::variant cp( @@ -572,15 +578,17 @@ std::get(v) == std::get(cp); } -void test_constexpr_copy_assignment_extension() { - // The following tests are for not-yet-standardized behavior (P0602): +void test_constexpr_copy_assignment() { + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 using V = std::variant; static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_copy_assignable::value, ""); - static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); - static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); - static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); - static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); + static_assert(test_constexpr_assign_imp<0>(V(42l), 101l), ""); + static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), ""); + static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), ""); + static_assert(test_constexpr_assign_imp<2>(V(42l), 101), ""); +#endif // > C++17 } int main() { @@ -591,5 +599,5 @@ test_copy_assignment_different_index(); test_copy_assignment_sfinae(); test_copy_assignment_not_noexcept(); - test_constexpr_copy_assignment_extension(); + test_constexpr_copy_assignment(); } Index: test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp =================================================================== --- test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.assign/move.pass.cpp @@ -27,7 +27,7 @@ // template class variant; -// variant& operator=(variant&&) noexcept(see below); +// variant& operator=(variant&&) noexcept(see below); // constexpr in C++20 #include #include @@ -206,7 +206,8 @@ static_assert(!std::is_move_assignable::value, ""); } - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality (see P0602R4). +#if TEST_STD_VER > 17 { using V = std::variant; static_assert(std::is_trivially_move_assignable::value, ""); @@ -232,6 +233,7 @@ using V = std::variant; static_assert(std::is_trivially_move_assignable::value, ""); } +#endif // > C++17 } void test_move_assignment_empty_empty() { @@ -353,7 +355,8 @@ } #endif // TEST_HAS_NO_EXCEPTIONS - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -396,6 +399,7 @@ static_assert(result.index == 1, ""); static_assert(result.value == 42, ""); } +#endif // > C++17 } void test_move_assignment_different_index() { @@ -445,7 +449,8 @@ } #endif // TEST_HAS_NO_EXCEPTIONS - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -474,10 +479,11 @@ static_assert(result.index == 1, ""); static_assert(result.value == 42, ""); } +#endif // > C++17 } template -constexpr bool test_constexpr_assign_extension_imp( +constexpr bool test_constexpr_assign_imp( std::variant&& v, ValueType&& new_value) { std::variant v2( @@ -488,15 +494,17 @@ std::get(v) == std::get(cp); } -void test_constexpr_move_assignment_extension() { - // The following tests are for not-yet-standardized behavior (P0602): +void test_constexpr_move_assignment() { + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 using V = std::variant; static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_move_assignable::value, ""); - static_assert(test_constexpr_assign_extension_imp<0>(V(42l), 101l), ""); - static_assert(test_constexpr_assign_extension_imp<0>(V(nullptr), 101l), ""); - static_assert(test_constexpr_assign_extension_imp<1>(V(42l), nullptr), ""); - static_assert(test_constexpr_assign_extension_imp<2>(V(42l), 101), ""); + static_assert(test_constexpr_assign_imp<0>(V(42l), 101l), ""); + static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), ""); + static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), ""); + static_assert(test_constexpr_assign_imp<2>(V(42l), 101), ""); +#endif // > C++17 } int main() { @@ -507,5 +515,5 @@ test_move_assignment_different_index(); test_move_assignment_sfinae(); test_move_assignment_noexcept(); - test_constexpr_move_assignment_extension(); + test_constexpr_move_assignment(); } Index: test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp =================================================================== --- test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.ctor/copy.pass.cpp @@ -22,7 +22,7 @@ // template class variant; -// variant(variant const&); +// variant(variant const&); // constexpr in C++20 #include #include @@ -126,7 +126,8 @@ static_assert(!std::is_copy_constructible::value, ""); } - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality (see P0602R4). +#if TEST_STD_VER > 17 { using V = std::variant; static_assert(std::is_trivially_copy_constructible::value, ""); @@ -144,6 +145,7 @@ using V = std::variant; static_assert(std::is_trivially_copy_constructible::value, ""); } +#endif // > C++17 } void test_copy_ctor_basic() { @@ -174,7 +176,8 @@ assert(std::get<1>(v2).value == 42); } - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 { constexpr std::variant v(std::in_place_index<0>, 42); static_assert(v.index() == 0, ""); @@ -217,6 +220,7 @@ static_assert(v2.index() == 1, ""); static_assert(std::get<1>(v2).value == 42, ""); } +#endif // > C++17 } void test_copy_ctor_valueless_by_exception() { @@ -231,17 +235,16 @@ } template -constexpr bool test_constexpr_copy_ctor_extension_imp( - std::variant const& v) -{ +constexpr bool test_constexpr_copy_ctor_imp(std::variant const& v) { auto v2 = v; return v2.index() == v.index() && v2.index() == Idx && std::get(v2) == std::get(v); } -void test_constexpr_copy_ctor_extension() { - // NOTE: This test is for not yet standardized behavior. (P0602) +void test_constexpr_copy_ctor() { + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 using V = std::variant; #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible::value, ""); @@ -252,16 +255,17 @@ #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_copyable::value, ""); #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE - static_assert(test_constexpr_copy_ctor_extension_imp<0>(V(42l)), ""); - static_assert(test_constexpr_copy_ctor_extension_imp<1>(V(nullptr)), ""); - static_assert(test_constexpr_copy_ctor_extension_imp<2>(V(101)), ""); + static_assert(test_constexpr_copy_ctor_imp<0>(V(42l)), ""); + static_assert(test_constexpr_copy_ctor_imp<1>(V(nullptr)), ""); + static_assert(test_constexpr_copy_ctor_imp<2>(V(101)), ""); +#endif // > C++17 } int main() { test_copy_ctor_basic(); test_copy_ctor_valueless_by_exception(); test_copy_ctor_sfinae(); - test_constexpr_copy_ctor_extension(); + test_constexpr_copy_ctor(); #if 0 // disable this for the moment; it fails on older compilers. // Need to figure out which compilers will support it. Index: test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp =================================================================== --- test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp +++ test/std/utilities/variant/variant.variant/variant.ctor/move.pass.cpp @@ -22,7 +22,7 @@ // template class variant; -// variant(variant&&) noexcept(see below); +// variant(variant&&) noexcept(see below); // constexpr in C++20 #include #include @@ -147,7 +147,8 @@ static_assert(!std::is_move_constructible::value, ""); } - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality (see P0602R4). +#if TEST_STD_VER > 17 { using V = std::variant; static_assert(std::is_trivially_move_constructible::value, ""); @@ -165,6 +166,7 @@ using V = std::variant; static_assert(std::is_trivially_move_constructible::value, ""); } +#endif // > C++17 } template @@ -214,7 +216,8 @@ assert(std::get<1>(v2).value == 42); } - // The following tests are for not-yet-standardized behavior (P0602): + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 { struct { constexpr Result operator()() const { @@ -287,6 +290,7 @@ static_assert(result.index == 1, ""); static_assert(result.value.value == 42, ""); } +#endif // > C++17 } void test_move_ctor_valueless_by_exception() { @@ -300,9 +304,7 @@ } template -constexpr bool test_constexpr_ctor_extension_imp( - std::variant const& v) -{ +constexpr bool test_constexpr_ctor_imp(std::variant const& v) { auto copy = v; auto v2 = std::move(copy); return v2.index() == v.index() && @@ -310,8 +312,9 @@ std::get(v2) == std::get(v); } -void test_constexpr_move_ctor_extension() { - // NOTE: This test is for not yet standardized behavior. (P0602) +void test_constexpr_move_ctor() { + // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). +#if TEST_STD_VER > 17 using V = std::variant; #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_destructible::value, ""); @@ -323,9 +326,10 @@ static_assert(std::is_trivially_copyable::value, ""); #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE static_assert(std::is_trivially_move_constructible::value, ""); - static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), ""); - static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), ""); - static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), ""); + static_assert(test_constexpr_ctor_imp<0>(V(42l)), ""); + static_assert(test_constexpr_ctor_imp<1>(V(nullptr)), ""); + static_assert(test_constexpr_ctor_imp<2>(V(101)), ""); +#endif // > C++17 } int main() { @@ -333,5 +337,5 @@ test_move_ctor_valueless_by_exception(); test_move_noexcept(); test_move_ctor_sfinae(); - test_constexpr_move_ctor_extension(); + test_constexpr_move_ctor(); } Index: www/cxx2a_status.html =================================================================== --- www/cxx2a_status.html +++ www/cxx2a_status.html @@ -115,7 +115,7 @@ P0487R1LWGFixing operator>>(basic_istream&, CharT*) (LWG 2499)San DiegoComplete8.0 P0591R4LWGUtility functions to implement uses-allocator constructionSan Diego P0595R2CWGP0595R2 std::is_constant_evaluated()San Diego - P0602R4LWGvariant and optional should propagate copy/move trivialitySan Diego + P0602R4LWGvariant and optional should propagate copy/move trivialitySan DiegoComplete8.0 P0608R3LWGA sane variant converting constructorSan Diego P0655R1LWGvisit<R>: Explicit Return Type for visitSan Diego P0771R1LWGstd::function move constructor should be noexceptSan DiegoComplete6.0