340 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// template <class U> optional<T>& operator=(U&& v);13 14#include <optional>15#include <type_traits>16#include <cassert>17#include <memory>18 19#include "test_macros.h"20#include "archetypes.h"21 22using std::optional;23 24struct ThrowAssign {25 static int dtor_called;26 ThrowAssign() = default;27 ThrowAssign(int) { TEST_THROW(42); }28 ThrowAssign& operator=(int) {29 TEST_THROW(42);30 }31 ~ThrowAssign() { ++dtor_called; }32};33int ThrowAssign::dtor_called = 0;34 35template <class T, class Arg = T, bool Expect = true>36void assert_assignable() {37 static_assert(std::is_assignable<optional<T>&, Arg>::value == Expect, "");38 static_assert(!std::is_assignable<const optional<T>&, Arg>::value, "");39}40 41struct MismatchType {42 explicit MismatchType(int) {}43 explicit MismatchType(char*) {}44 explicit MismatchType(int*) = delete;45 MismatchType& operator=(int) { return *this; }46 MismatchType& operator=(int*) { return *this; }47 MismatchType& operator=(char*) = delete;48};49 50struct FromOptionalType {51 using Opt = std::optional<FromOptionalType>;52 FromOptionalType() = default;53 FromOptionalType(FromOptionalType const&) = delete;54 template <class Dummy = void>55 constexpr FromOptionalType(Opt&) { Dummy::BARK; }56 template <class Dummy = void>57 constexpr FromOptionalType& operator=(Opt&) { Dummy::BARK; return *this; }58};59 60void test_sfinae() {61 using I = TestTypes::TestType;62 using E = ExplicitTestTypes::TestType;63 assert_assignable<int>();64 assert_assignable<int, int&>();65 assert_assignable<int, int const&>();66 // Implicit test type67 assert_assignable<I, I const&>();68 assert_assignable<I, I&&>();69 assert_assignable<I, int>();70 assert_assignable<I, void*, false>();71 // Explicit test type72 assert_assignable<E, E const&>();73 assert_assignable<E, E &&>();74 assert_assignable<E, int>();75 assert_assignable<E, void*, false>();76 // Mismatch type77 assert_assignable<MismatchType, int>();78 assert_assignable<MismatchType, int*, false>();79 assert_assignable<MismatchType, char*, false>();80 // Type constructible from optional81 assert_assignable<FromOptionalType, std::optional<FromOptionalType>&, false>();82}83 84void test_with_test_type()85{86 using T = TestTypes::TestType;87 T::reset();88 { // to empty89 optional<T> opt;90 opt = 3;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>(opt) == true);97 assert(*opt == T(3));98 }99 { // to existing100 optional<T> opt(42);101 T::reset_constructors();102 opt = 3;103 assert(T::alive == 1);104 assert(T::constructed == 0);105 assert(T::assigned == 1);106 assert(T::value_assigned == 1);107 assert(T::destroyed == 0);108 assert(static_cast<bool>(opt) == true);109 assert(*opt == T(3));110 }111 { // test default argument112 optional<T> opt;113 T::reset_constructors();114 opt = {1, 2};115 assert(T::alive == 1);116 assert(T::constructed == 2);117 assert(T::value_constructed == 1);118 assert(T::move_constructed == 1);119 assert(T::assigned == 0);120 assert(T::destroyed == 1);121 assert(static_cast<bool>(opt) == true);122 assert(*opt == T(1, 2));123 }124 { // test default argument125 optional<T> opt(42);126 T::reset_constructors();127 opt = {1, 2};128 assert(T::alive == 1);129 assert(T::constructed == 1);130 assert(T::value_constructed == 1);131 assert(T::assigned == 1);132 assert(T::move_assigned == 1);133 assert(T::destroyed == 1);134 assert(static_cast<bool>(opt) == true);135 assert(*opt == T(1, 2));136 }137 { // test default argument138 optional<T> opt;139 T::reset_constructors();140 opt = {1};141 assert(T::alive == 1);142 assert(T::constructed == 2);143 assert(T::value_constructed == 1);144 assert(T::move_constructed == 1);145 assert(T::assigned == 0);146 assert(T::destroyed == 1);147 assert(static_cast<bool>(opt) == true);148 assert(*opt == T(1));149 }150 { // test default argument151 optional<T> opt(42);152 T::reset_constructors();153 opt = {};154 assert(static_cast<bool>(opt) == false);155 assert(T::alive == 0);156 assert(T::constructed == 0);157 assert(T::assigned == 0);158 assert(T::destroyed == 1);159 }160}161 162template <class T, class Value = int>163void test_with_type() {164 { // to empty165 optional<T> opt;166 opt = Value(3);167 assert(static_cast<bool>(opt) == true);168 assert(*opt == T(3));169 }170 { // to existing171 optional<T> opt(Value(42));172 opt = Value(3);173 assert(static_cast<bool>(opt) == true);174 assert(*opt == T(3));175 }176 { // test const177 optional<T> opt(Value(42));178 const T t(Value(3));179 opt = t;180 assert(static_cast<bool>(opt) == true);181 assert(*opt == T(3));182 }183 { // test default argument184 optional<T> opt;185 opt = {Value(1)};186 assert(static_cast<bool>(opt) == true);187 assert(*opt == T(1));188 }189 { // test default argument190 optional<T> opt(Value(42));191 opt = {};192 assert(static_cast<bool>(opt) == false);193 }194}195 196template <class T>197void test_with_type_multi() {198 test_with_type<T>();199 { // test default argument200 optional<T> opt;201 opt = {1, 2};202 assert(static_cast<bool>(opt) == true);203 assert(*opt == T(1, 2));204 }205 { // test default argument206 optional<T> opt(42);207 opt = {1, 2};208 assert(static_cast<bool>(opt) == true);209 assert(*opt == T(1, 2));210 }211}212 213void test_throws()214{215#ifndef TEST_HAS_NO_EXCEPTIONS216 using T = ThrowAssign;217 {218 optional<T> opt;219 try {220 opt = 42;221 assert(false);222 } catch (int) {}223 assert(static_cast<bool>(opt) == false);224 }225 assert(T::dtor_called == 0);226 {227 T::dtor_called = 0;228 optional<T> opt(std::in_place);229 try {230 opt = 42;231 assert(false);232 } catch (int) {}233 assert(static_cast<bool>(opt) == true);234 assert(T::dtor_called == 0);235 }236 assert(T::dtor_called == 1);237#endif238}239 240enum MyEnum { Zero, One, Two, Three, FortyTwo = 42 };241 242using Fn = void(*)();243 244// https://llvm.org/PR38638245template <class T>246constexpr T pr38638(T v)247{248 std::optional<T> o;249 o = v;250 return *o + 2;251}252 253#if TEST_STD_VER >= 26254 255template <typename T, std::remove_reference_t<T> _Val>256constexpr void test_with_ref() {257 T t{_Val};258 { // to empty259 optional<T&> opt;260 opt = t;261 assert(static_cast<bool>(opt) == true);262 assert(*opt == t);263 }264 { // to existing265 optional<T&> opt{t};266 opt = t;267 assert(static_cast<bool>(opt) == true);268 assert(*opt == t);269 }270 { // test default argument271 optional<T&> opt;272 opt = {t};273 assert(static_cast<bool>(opt) == true);274 assert(*opt == t);275 }276 { // test default argument277 optional<T&> opt{t};278 opt = {};279 assert(static_cast<bool>(opt) == false);280 }281 // test two objects, make sure that the optional only changes what it holds a reference to282 {283 T t2{_Val};284 optional<T&> opt{t};285 opt = t2;286 287 assert(std::addressof(*opt) != std::addressof(t));288 assert(std::addressof(*opt) == std::addressof(t2));289 }290 // test that reassigning the reference for an optional<T&> doesn't affect the objet it's holding a reference to291 {292 int i = -1;293 int j = 2;294 optional<int&> opt{i};295 opt = j;296 297 assert(i == -1);298 assert(std::addressof(*opt) != std::addressof(i));299 assert(std::addressof(*opt) == std::addressof(j));300 assert(*opt == 2);301 }302}303#endif304 305int main(int, char**)306{307 test_sfinae();308 // Test with instrumented type309 test_with_test_type();310 // Test with various scalar types311 test_with_type<int>();312 test_with_type<MyEnum, MyEnum>();313 test_with_type<int, MyEnum>();314 test_with_type<Fn, Fn>();315 // Test types with multi argument constructors316 test_with_type_multi<ConstexprTestTypes::TestType>();317 test_with_type_multi<TrivialTestTypes::TestType>();318 // Test move only types319 {320 optional<std::unique_ptr<int>> opt;321 opt = std::unique_ptr<int>(new int(3));322 assert(static_cast<bool>(opt) == true);323 assert(**opt == 3);324 }325 {326 optional<std::unique_ptr<int>> opt(std::unique_ptr<int>(new int(2)));327 opt = std::unique_ptr<int>(new int(3));328 assert(static_cast<bool>(opt) == true);329 assert(**opt == 3);330 }331 test_throws();332 333 static_assert(pr38638(3) == 5, "");334 335#if TEST_STD_VER >= 26336 test_with_ref<int, 3>();337#endif338 return 0;339}340