256 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// From LWG2451:13// template<class U>14// optional<T>& operator=(const optional<U>& rhs);15 16#include <optional>17#include <type_traits>18#include <cassert>19 20#include "test_macros.h"21#include "archetypes.h"22 23using std::optional;24 25struct X26{27 static bool throw_now;28 29 X() = default;30 X(int)31 {32 if (throw_now)33 TEST_THROW(6);34 }35};36 37bool X::throw_now = false;38 39struct Y140{41 Y1() = default;42 Y1(const int&) {}43 Y1& operator=(const Y1&) = delete;44};45 46struct Y247{48 Y2() = default;49 Y2(const int&) = delete;50 Y2& operator=(const int&) { return *this; }51};52 53template <class T>54struct AssignableFrom {55 static int type_constructed;56 static int type_assigned;57static int int_constructed;58 static int int_assigned;59 60 static void reset() {61 type_constructed = int_constructed = 0;62 type_assigned = int_assigned = 0;63 }64 65 AssignableFrom() = default;66 67 explicit AssignableFrom(T) { ++type_constructed; }68 AssignableFrom& operator=(T) { ++type_assigned; return *this; }69 70 AssignableFrom(int) { ++int_constructed; }71 AssignableFrom& operator=(int) { ++int_assigned; return *this; }72private:73 AssignableFrom(AssignableFrom const&) = delete;74 AssignableFrom& operator=(AssignableFrom const&) = delete;75};76 77template <class T> int AssignableFrom<T>::type_constructed = 0;78template <class T> int AssignableFrom<T>::type_assigned = 0;79template <class T> int AssignableFrom<T>::int_constructed = 0;80template <class T> int AssignableFrom<T>::int_assigned = 0;81 82 83void test_with_test_type() {84 using T = TestTypes::TestType;85 T::reset();86 { // non-empty to empty87 T::reset_constructors();88 optional<T> opt;89 const optional<int> other(42);90 opt = other;91 assert(T::alive == 1);92 assert(T::constructed == 1);93 assert(T::value_constructed == 1);94 assert(T::assigned == 0);95 assert(T::destroyed == 0);96 assert(static_cast<bool>(other) == true);97 assert(*other == 42);98 assert(static_cast<bool>(opt) == true);99 assert(*opt == T(42));100 }101 assert(T::alive == 0);102 { // non-empty to non-empty103 optional<T> opt(101);104 const optional<int> other(42);105 T::reset_constructors();106 opt = other;107 assert(T::alive == 1);108 assert(T::constructed == 0);109 assert(T::assigned == 1);110 assert(T::value_assigned == 1);111 assert(T::destroyed == 0);112 assert(static_cast<bool>(other) == true);113 assert(*other == 42);114 assert(static_cast<bool>(opt) == true);115 assert(*opt == T(42));116 }117 assert(T::alive == 0);118 { // empty to non-empty119 optional<T> opt(101);120 const optional<int> other;121 T::reset_constructors();122 opt = other;123 assert(T::alive == 0);124 assert(T::constructed == 0);125 assert(T::assigned == 0);126 assert(T::destroyed == 1);127 assert(static_cast<bool>(other) == false);128 assert(static_cast<bool>(opt) == false);129 }130 assert(T::alive == 0);131 { // empty to empty132 optional<T> opt;133 const optional<int> other;134 T::reset_constructors();135 opt = other;136 assert(T::alive == 0);137 assert(T::constructed == 0);138 assert(T::assigned == 0);139 assert(T::destroyed == 0);140 assert(static_cast<bool>(other) == false);141 assert(static_cast<bool>(opt) == false);142 }143 assert(T::alive == 0);144}145 146void test_ambiguous_assign() {147 using OptInt = std::optional<int>;148 {149 using T = AssignableFrom<OptInt const&>;150 const OptInt a(42);151 T::reset();152 {153 std::optional<T> t;154 t = a;155 assert(T::type_constructed == 1);156 assert(T::type_assigned == 0);157 assert(T::int_constructed == 0);158 assert(T::int_assigned == 0);159 }160 T::reset();161 {162 std::optional<T> t(42);163 t = a;164 assert(T::type_constructed == 0);165 assert(T::type_assigned == 1);166 assert(T::int_constructed == 1);167 assert(T::int_assigned == 0);168 }169 T::reset();170 {171 std::optional<T> t(42);172 t = std::move(a);173 assert(T::type_constructed == 0);174 assert(T::type_assigned == 1);175 assert(T::int_constructed == 1);176 assert(T::int_assigned == 0);177 }178 }179 {180 using T = AssignableFrom<OptInt&>;181 OptInt a(42);182 T::reset();183 {184 std::optional<T> t;185 t = a;186 assert(T::type_constructed == 1);187 assert(T::type_assigned == 0);188 assert(T::int_constructed == 0);189 assert(T::int_assigned == 0);190 }191 {192 using Opt = std::optional<T>;193 static_assert(!std::is_assignable_v<Opt&, OptInt const&>, "");194 }195 }196}197 198 199int main(int, char**)200{201 test_with_test_type();202 test_ambiguous_assign();203 {204 optional<int> opt;205 constexpr optional<short> opt2;206 opt = opt2;207 static_assert(static_cast<bool>(opt2) == false, "");208 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));209 }210 {211 optional<int> opt;212 constexpr optional<short> opt2(short{2});213 opt = opt2;214 static_assert(static_cast<bool>(opt2) == true, "");215 static_assert(*opt2 == 2, "");216 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));217 assert(*opt == *opt2);218 }219 {220 optional<int> opt(3);221 constexpr optional<short> opt2;222 opt = opt2;223 static_assert(static_cast<bool>(opt2) == false, "");224 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));225 }226 {227 optional<int> opt(3);228 constexpr optional<short> opt2(short{2});229 opt = opt2;230 static_assert(static_cast<bool>(opt2) == true, "");231 static_assert(*opt2 == 2, "");232 assert(static_cast<bool>(opt) == static_cast<bool>(opt2));233 assert(*opt == *opt2);234 }235#ifndef TEST_HAS_NO_EXCEPTIONS236 {237 optional<X> opt;238 optional<int> opt2(42);239 assert(static_cast<bool>(opt2) == true);240 try241 {242 X::throw_now = true;243 opt = opt2;244 assert(false);245 }246 catch (int i)247 {248 assert(i == 6);249 assert(static_cast<bool>(opt) == false);250 }251 }252#endif253 254 return 0;255}256