//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 // // constexpr optional(const optional& rhs); #include #include #include #include "test_macros.h" #include "archetypes.h" using std::optional; template void test(InitArgs&&... args) { const optional rhs(std::forward(args)...); bool rhs_engaged = static_cast(rhs); optional lhs = rhs; assert(static_cast(lhs) == rhs_engaged); if (rhs_engaged) assert(*lhs == *rhs); } template constexpr bool constexpr_test(InitArgs&&... args) { static_assert(std::is_trivially_copy_constructible_v, ""); // requirement const optional rhs(std::forward(args)...); optional lhs = rhs; return (lhs.has_value() == rhs.has_value()) && (lhs.has_value() ? *lhs == *rhs : true); } void test_throwing_ctor() { #ifndef TEST_HAS_NO_EXCEPTIONS struct Z { Z() : count(0) {} Z(Z const& o) : count(o.count + 1) { if (count == 2) throw 6; } int count; }; const Z z; const optional rhs(z); try { optional lhs(rhs); assert(false); } catch (int i) { assert(i == 6); } #endif } template void test_ref(InitArgs&&... args) { const optional rhs(std::forward(args)...); bool rhs_engaged = static_cast(rhs); optional lhs = rhs; assert(static_cast(lhs) == rhs_engaged); if (rhs_engaged) assert(&(*lhs) == &(*rhs)); } #if TEST_STD_VER >= 26 void test_reference_extension() { using T = TestTypes::TestType; T::reset(); { T t; T::reset_constructors(); test_ref(); test_ref(t); assert(T::alive == 1); assert(T::constructed == 0); assert(T::assigned == 0); assert(T::destroyed == 0); } assert(T::destroyed == 1); assert(T::alive == 0); { T t; const T& ct = t; T::reset_constructors(); test_ref(); test_ref(t); test_ref(ct); assert(T::alive == 1); assert(T::constructed == 0); assert(T::assigned == 0); assert(T::destroyed == 0); } assert(T::alive == 0); assert(T::destroyed == 1); # if 0 // optional is not permitted. { static_assert(!std::is_copy_constructible>::value, ""); static_assert(!std::is_copy_constructible>::value, ""); } # endif } #endif int main(int, char**) { test(); test(3); static_assert(constexpr_test(), ""); static_assert(constexpr_test(3), ""); { const optional o(42); optional o2(o); assert(*o2 == 42); } { using T = TestTypes::TestType; T::reset(); const optional rhs; assert(T::alive == 0); const optional lhs(rhs); assert(lhs.has_value() == false); assert(T::alive == 0); } TestTypes::TestType::reset(); { using T = TestTypes::TestType; T::reset(); const optional rhs(42); assert(T::alive == 1); assert(T::value_constructed == 1); assert(T::copy_constructed == 0); const optional lhs(rhs); assert(lhs.has_value()); assert(T::copy_constructed == 1); assert(T::alive == 2); } TestTypes::TestType::reset(); { using namespace ConstexprTestTypes; test(); test(42); } { using namespace TrivialTestTypes; test(); test(42); } { test_throwing_ctor(); } #if TEST_STD_VER >= 26 { test_reference_extension(); } #endif { constexpr std::optional o1{4}; constexpr std::optional o2 = o1; static_assert(*o2 == 4, ""); } // LWG3836 https://wg21.link/LWG3836 // std::optional conversion constructor optional(const optional&) // should take precedence over optional(U&&) with operator bool { std::optional o1(false); std::optional o2(o1); assert(!o2.value()); } return 0; }