205 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// <optional>11 12// constexpr optional<T>& operator=(optional<T>&& rhs)13// noexcept(is_nothrow_move_assignable<T>::value &&14// is_nothrow_move_constructible<T>::value);15 16#include <optional>17#include <cassert>18#include <type_traits>19#include <utility>20 21#include "test_macros.h"22#include "archetypes.h"23 24using std::optional;25 26struct X27{28 static bool throw_now;29 static int alive;30 31 X() { ++alive; }32 X(X&&)33 {34 if (throw_now)35 TEST_THROW(6);36 ++alive;37 }38 39 X& operator=(X&&)40 {41 if (throw_now)42 TEST_THROW(42);43 return *this;44 }45 46 ~X() { assert(alive > 0); --alive; }47};48 49struct Y {};50 51bool X::throw_now = false;52int X::alive = 0;53 54 55template <class Tp>56constexpr bool assign_empty(optional<Tp>&& lhs) {57 optional<Tp> rhs;58 lhs = std::move(rhs);59 return !lhs.has_value() && !rhs.has_value();60}61 62template <class Tp>63constexpr bool assign_value(optional<Tp>&& lhs) {64 optional<Tp> rhs(101);65 lhs = std::move(rhs);66 return lhs.has_value() && rhs.has_value() && *lhs == Tp{101};67}68 69int main(int, char**)70{71 {72 static_assert(std::is_nothrow_move_assignable<optional<int>>::value, "");73 optional<int> opt;74 constexpr optional<int> opt2;75 opt = std::move(opt2);76 static_assert(static_cast<bool>(opt2) == false, "");77 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));78 }79 {80 optional<int> opt;81 constexpr optional<int> opt2(2);82 opt = std::move(opt2);83 static_assert(static_cast<bool>(opt2) == true, "");84 static_assert(*opt2 == 2, "");85 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));86 assert(*opt == *opt2);87 }88 {89 optional<int> opt(3);90 constexpr optional<int> opt2;91 opt = std::move(opt2);92 static_assert(static_cast<bool>(opt2) == false, "");93 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));94 }95 {96 using T = TestTypes::TestType;97 T::reset();98 optional<T> opt(3);99 optional<T> opt2;100 assert(T::alive == 1);101 opt = std::move(opt2);102 assert(T::alive == 0);103 assert(static_cast<bool>(opt2) == false);104 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));105 }106 {107 optional<int> opt(3);108 constexpr optional<int> opt2(2);109 opt = std::move(opt2);110 static_assert(static_cast<bool>(opt2) == true, "");111 static_assert(*opt2 == 2, "");112 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));113 assert(*opt == *opt2);114 }115 {116 using O = optional<int>;117 static_assert(assign_empty(O{42}));118 static_assert(assign_value(O{42}));119 assert(assign_empty(O{42}));120 assert(assign_value(O{42}));121 }122 {123 using O = optional<TrivialTestTypes::TestType>;124 static_assert(assign_empty(O{42}));125 static_assert(assign_value(O{42}));126 assert(assign_empty(O{42}));127 assert(assign_value(O{42}));128 }129#ifndef TEST_HAS_NO_EXCEPTIONS130 {131 static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, "");132 X::alive = 0;133 X::throw_now = false;134 optional<X> opt;135 optional<X> opt2(X{});136 assert(X::alive == 1);137 assert(static_cast<bool>(opt2) == true);138 try139 {140 X::throw_now = true;141 opt = std::move(opt2);142 assert(false);143 }144 catch (int i)145 {146 assert(i == 6);147 assert(static_cast<bool>(opt) == false);148 }149 assert(X::alive == 1);150 }151 assert(X::alive == 0);152 {153 static_assert(!std::is_nothrow_move_assignable<optional<X>>::value, "");154 X::throw_now = false;155 optional<X> opt(X{});156 optional<X> opt2(X{});157 assert(X::alive == 2);158 assert(static_cast<bool>(opt2) == true);159 try160 {161 X::throw_now = true;162 opt = std::move(opt2);163 assert(false);164 }165 catch (int i)166 {167 assert(i == 42);168 assert(static_cast<bool>(opt) == true);169 }170 assert(X::alive == 2);171 }172 assert(X::alive == 0);173#endif // TEST_HAS_NO_EXCEPTIONS174 {175 static_assert(std::is_nothrow_move_assignable<optional<Y>>::value, "");176 }177 {178 struct ThrowsMove {179 ThrowsMove() noexcept {}180 ThrowsMove(ThrowsMove const&) noexcept {}181 ThrowsMove(ThrowsMove &&) noexcept(false) {}182 ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; }183 ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; }184 };185 static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMove>>::value, "");186 struct ThrowsMoveAssign {187 ThrowsMoveAssign() noexcept {}188 ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {}189 ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {}190 ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; }191 ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; }192 };193 static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMoveAssign>>::value, "");194 struct NoThrowMove {195 NoThrowMove() noexcept(false) {}196 NoThrowMove(NoThrowMove const&) noexcept(false) {}197 NoThrowMove(NoThrowMove &&) noexcept {}198 NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; }199 NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; }200 };201 static_assert(std::is_nothrow_move_assignable<optional<NoThrowMove>>::value, "");202 }203 return 0;204}205