//===----------------------------------------------------------------------===// // // 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 // // template optional& operator=(U&& v); #include #include #include #include #include "test_macros.h" #include "archetypes.h" using std::optional; struct ThrowAssign { static int dtor_called; ThrowAssign() = default; ThrowAssign(int) { TEST_THROW(42); } ThrowAssign& operator=(int) { TEST_THROW(42); } ~ThrowAssign() { ++dtor_called; } }; int ThrowAssign::dtor_called = 0; template void assert_assignable() { static_assert(std::is_assignable&, Arg>::value == Expect, ""); static_assert(!std::is_assignable&, Arg>::value, ""); } struct MismatchType { explicit MismatchType(int) {} explicit MismatchType(char*) {} explicit MismatchType(int*) = delete; MismatchType& operator=(int) { return *this; } MismatchType& operator=(int*) { return *this; } MismatchType& operator=(char*) = delete; }; struct FromOptionalType { using Opt = std::optional; FromOptionalType() = default; FromOptionalType(FromOptionalType const&) = delete; template constexpr FromOptionalType(Opt&) { Dummy::BARK; } template constexpr FromOptionalType& operator=(Opt&) { Dummy::BARK; return *this; } }; void test_sfinae() { using I = TestTypes::TestType; using E = ExplicitTestTypes::TestType; assert_assignable(); assert_assignable(); assert_assignable(); // Implicit test type assert_assignable(); assert_assignable(); assert_assignable(); assert_assignable(); // Explicit test type assert_assignable(); assert_assignable(); assert_assignable(); assert_assignable(); // Mismatch type assert_assignable(); assert_assignable(); assert_assignable(); // Type constructible from optional assert_assignable&, false>(); } void test_with_test_type() { using T = TestTypes::TestType; T::reset(); { // to empty optional opt; opt = 3; assert(T::alive == 1); assert(T::constructed == 1); assert(T::value_constructed == 1); assert(T::assigned == 0); assert(T::destroyed == 0); assert(static_cast(opt) == true); assert(*opt == T(3)); } { // to existing optional opt(42); T::reset_constructors(); opt = 3; assert(T::alive == 1); assert(T::constructed == 0); assert(T::assigned == 1); assert(T::value_assigned == 1); assert(T::destroyed == 0); assert(static_cast(opt) == true); assert(*opt == T(3)); } { // test default argument optional opt; T::reset_constructors(); opt = {1, 2}; assert(T::alive == 1); assert(T::constructed == 2); assert(T::value_constructed == 1); assert(T::move_constructed == 1); assert(T::assigned == 0); assert(T::destroyed == 1); assert(static_cast(opt) == true); assert(*opt == T(1, 2)); } { // test default argument optional opt(42); T::reset_constructors(); opt = {1, 2}; assert(T::alive == 1); assert(T::constructed == 1); assert(T::value_constructed == 1); assert(T::assigned == 1); assert(T::move_assigned == 1); assert(T::destroyed == 1); assert(static_cast(opt) == true); assert(*opt == T(1, 2)); } { // test default argument optional opt; T::reset_constructors(); opt = {1}; assert(T::alive == 1); assert(T::constructed == 2); assert(T::value_constructed == 1); assert(T::move_constructed == 1); assert(T::assigned == 0); assert(T::destroyed == 1); assert(static_cast(opt) == true); assert(*opt == T(1)); } { // test default argument optional opt(42); T::reset_constructors(); opt = {}; assert(static_cast(opt) == false); assert(T::alive == 0); assert(T::constructed == 0); assert(T::assigned == 0); assert(T::destroyed == 1); } } template void test_with_type() { { // to empty optional opt; opt = Value(3); assert(static_cast(opt) == true); assert(*opt == T(3)); } { // to existing optional opt(Value(42)); opt = Value(3); assert(static_cast(opt) == true); assert(*opt == T(3)); } { // test const optional opt(Value(42)); const T t(Value(3)); opt = t; assert(static_cast(opt) == true); assert(*opt == T(3)); } { // test default argument optional opt; opt = {Value(1)}; assert(static_cast(opt) == true); assert(*opt == T(1)); } { // test default argument optional opt(Value(42)); opt = {}; assert(static_cast(opt) == false); } } template void test_with_type_multi() { test_with_type(); { // test default argument optional opt; opt = {1, 2}; assert(static_cast(opt) == true); assert(*opt == T(1, 2)); } { // test default argument optional opt(42); opt = {1, 2}; assert(static_cast(opt) == true); assert(*opt == T(1, 2)); } } void test_throws() { #ifndef TEST_HAS_NO_EXCEPTIONS using T = ThrowAssign; { optional opt; try { opt = 42; assert(false); } catch (int) {} assert(static_cast(opt) == false); } assert(T::dtor_called == 0); { T::dtor_called = 0; optional opt(std::in_place); try { opt = 42; assert(false); } catch (int) {} assert(static_cast(opt) == true); assert(T::dtor_called == 0); } assert(T::dtor_called == 1); #endif } enum MyEnum { Zero, One, Two, Three, FortyTwo = 42 }; using Fn = void(*)(); // https://bugs.llvm.org/show_bug.cgi?id=38638 template constexpr T pr38638(T v) { std::optional o; o = v; return *o + 2; } int main(int, char**) { test_sfinae(); // Test with instrumented type test_with_test_type(); // Test with various scalar types test_with_type(); test_with_type(); test_with_type(); test_with_type(); // Test types with multi argument constructors test_with_type_multi(); test_with_type_multi(); // Test move only types { optional> opt; opt = std::unique_ptr(new int(3)); assert(static_cast(opt) == true); assert(**opt == 3); } { optional> opt(std::unique_ptr(new int(2))); opt = std::unique_ptr(new int(3)); assert(static_cast(opt) == true); assert(**opt == 3); } test_throws(); static_assert(pr38638(3) == 5, ""); return 0; }