216 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410 11// <optional>12 13// constexpr optional(optional<T>&& rhs);14 15#include <cassert>16#include <optional>17#include <type_traits>18 19#include "test_macros.h"20#include "archetypes.h"21 22using std::optional;23 24template <class T, class... InitArgs>25void test(InitArgs&&... args) {26 const optional<T> orig(std::forward<InitArgs>(args)...);27 optional<T> rhs(orig);28 bool rhs_engaged = static_cast<bool>(rhs);29 optional<T> lhs = std::move(rhs);30 assert(static_cast<bool>(lhs) == rhs_engaged);31 if (rhs_engaged)32 assert(*lhs == *orig);33}34 35template <class T, class... InitArgs>36constexpr bool constexpr_test(InitArgs&&... args) {37 static_assert(std::is_trivially_copy_constructible_v<T>, ""); // requirement38 const optional<T> orig(std::forward<InitArgs>(args)...);39 optional<T> rhs(orig);40 optional<T> lhs = std::move(rhs);41 return (lhs.has_value() == orig.has_value()) && (lhs.has_value() ? *lhs == *orig : true);42}43 44void test_throwing_ctor() {45#ifndef TEST_HAS_NO_EXCEPTIONS46 struct Z {47 Z() : count(0) {}48 Z(Z&& o) : count(o.count + 1) {49 if (count == 2)50 throw 6;51 }52 int count;53 };54 Z z;55 optional<Z> rhs(std::move(z));56 try {57 optional<Z> lhs(std::move(rhs));58 assert(false);59 } catch (int i) {60 assert(i == 6);61 }62#endif63}64 65template <class T, class... InitArgs>66void test_ref(InitArgs&&... args) {67 optional<T> rhs(std::forward<InitArgs>(args)...);68 bool rhs_engaged = static_cast<bool>(rhs);69 optional<T> lhs = std::move(rhs);70 assert(static_cast<bool>(lhs) == rhs_engaged);71 if (rhs_engaged)72 assert(&(*lhs) == &(*rhs));73}74 75void test_reference_extension() {76#if TEST_STD_VER >= 2677 using T = TestTypes::TestType;78 T::reset();79 {80 T t;81 T::reset_constructors();82 test_ref<T&>();83 test_ref<T&>(t);84 assert(T::alive == 1);85 assert(T::constructed == 0);86 assert(T::assigned == 0);87 assert(T::destroyed == 0);88 }89 assert(T::destroyed == 1);90 assert(T::alive == 0);91 {92 T t;93 const T& ct = t;94 T::reset_constructors();95 test_ref<T const&>();96 test_ref<T const&>(t);97 test_ref<T const&>(ct);98 assert(T::alive == 1);99 assert(T::constructed == 0);100 assert(T::assigned == 0);101 assert(T::destroyed == 0);102 }103 assert(T::alive == 0);104 assert(T::destroyed == 1);105# if 0 // FIXME: optional<T&&> is not allowed.106 {107 T t;108 T::reset_constructors();109 test_ref<T&&>();110 test_ref<T&&>(std::move(t));111 assert(T::alive == 1);112 assert(T::constructed == 0);113 assert(T::assigned == 0);114 assert(T::destroyed == 0);115 }116 assert(T::alive == 0);117 assert(T::destroyed == 1);118 {119 T t;120 const T& ct = t;121 T::reset_constructors();122 test_ref<T const&&>();123 test_ref<T const&&>(std::move(t));124 test_ref<T const&&>(std::move(ct));125 assert(T::alive == 1);126 assert(T::constructed == 0);127 assert(T::assigned == 0);128 assert(T::destroyed == 0);129 }130 assert(T::alive == 0);131 assert(T::destroyed == 1);132 {133 static_assert(!std::is_copy_constructible_v<std::optional<T&&>>);134 static_assert(!std::is_copy_constructible_v<std::optional<T const&&>>);135 }136# endif137#endif138}139 140int main(int, char**) {141 test<int>();142 test<int>(3);143 static_assert(constexpr_test<int>(), "");144 static_assert(constexpr_test<int>(3), "");145 146 {147 optional<const int> o(42);148 optional<const int> o2(std::move(o));149 assert(*o2 == 42);150 }151 {152 using T = TestTypes::TestType;153 T::reset();154 optional<T> rhs;155 assert(T::alive == 0);156 const optional<T> lhs(std::move(rhs));157 assert(lhs.has_value() == false);158 assert(rhs.has_value() == false);159 assert(T::alive == 0);160 }161 TestTypes::TestType::reset();162 {163 using T = TestTypes::TestType;164 T::reset();165 optional<T> rhs(42);166 assert(T::alive == 1);167 assert(T::value_constructed == 1);168 assert(T::move_constructed == 0);169 const optional<T> lhs(std::move(rhs));170 assert(lhs.has_value());171 assert(rhs.has_value());172 assert(lhs.value().value == 42);173 assert(rhs.value().value == -1);174 assert(T::move_constructed == 1);175 assert(T::alive == 2);176 }177 TestTypes::TestType::reset();178 {179 using namespace ConstexprTestTypes;180 test<TestType>();181 test<TestType>(42);182 }183 {184 using namespace TrivialTestTypes;185 test<TestType>();186 test<TestType>(42);187 }188 {189 test_throwing_ctor();190 }191 {192 struct ThrowsMove {193 ThrowsMove() noexcept(false) {}194 ThrowsMove(ThrowsMove const&) noexcept(false) {}195 ThrowsMove(ThrowsMove&&) noexcept(false) {}196 };197 static_assert(!std::is_nothrow_move_constructible<optional<ThrowsMove>>::value, "");198 struct NoThrowMove {199 NoThrowMove() noexcept(false) {}200 NoThrowMove(NoThrowMove const&) noexcept(false) {}201 NoThrowMove(NoThrowMove&&) noexcept(true) {}202 };203 static_assert(std::is_nothrow_move_constructible<optional<NoThrowMove>>::value, "");204 }205 {206 test_reference_extension();207 }208 {209 constexpr std::optional<int> o1{4};210 constexpr std::optional<int> o2 = std::move(o1);211 static_assert(*o2 == 4, "");212 }213 214 return 0;215}216