1// { dg-options "-std=gnu++14" } 2// { dg-do run } 3 4// Copyright (C) 2013-2015 Free Software Foundation, Inc. 5// 6// This file is part of the GNU ISO C++ Library. This library is free 7// software; you can redistribute it and/or modify it under the 8// terms of the GNU General Public License as published by the 9// Free Software Foundation; either version 3, or (at your option) 10// any later version. 11 12// This library is distributed in the hope that it will be useful, 13// but WITHOUT ANY WARRANTY; without even the implied warranty of 14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15// GNU General Public License for more details. 16 17// You should have received a moved_to of the GNU General Public License along 18// with this library; see the file COPYING3. If not see 19// <http://www.gnu.org/licenses/>. 20 21#include <experimental/optional> 22#include <testsuite_hooks.h> 23 24struct exception {}; 25 26int counter = 0; 27 28struct mixin_counter 29{ 30 mixin_counter() { ++counter; } 31 mixin_counter(mixin_counter const&) { ++counter; } 32 ~mixin_counter() { --counter; } 33}; 34 35struct value_type : private mixin_counter 36{ 37 enum state_type 38 { 39 zero, 40 moved_from, 41 throwing_construction, 42 throwing_copy, 43 throwing_copy_assignment, 44 throwing_move, 45 throwing_move_assignment, 46 threw, 47 }; 48 49 value_type() = default; 50 51 explicit value_type(state_type state_) 52 : state(state_) 53 { 54 throw_if(throwing_construction); 55 } 56 57 value_type(value_type const& other) 58 : state(other.state) 59 { 60 throw_if(throwing_copy); 61 } 62 63 value_type& 64 operator=(value_type const& other) 65 { 66 state = other.state; 67 throw_if(throwing_copy_assignment); 68 return *this; 69 } 70 71 value_type(value_type&& other) 72 : state(other.state) 73 { 74 other.state = moved_from; 75 throw_if(throwing_move); 76 } 77 78 value_type& 79 operator=(value_type&& other) 80 { 81 state = other.state; 82 other.state = moved_from; 83 throw_if(throwing_move_assignment); 84 return *this; 85 } 86 87 void throw_if(state_type match) 88 { 89 if(state == match) 90 { 91 state = threw; 92 throw exception {}; 93 } 94 } 95 96 state_type state = zero; 97}; 98 99int main() 100{ 101 using O = std::experimental::optional<value_type>; 102 using S = value_type::state_type; 103 auto const make = [](S s = S::zero) { return O { std::experimental::in_place, s }; }; 104 105 enum outcome_type { nothrow, caught, bad_catch }; 106 107 // Check copy/move assignment for disengaged optional 108 109 // From disengaged optional 110 { 111 O o; 112 VERIFY( !o ); 113 O p; 114 o = p; 115 VERIFY( !o ); 116 VERIFY( !p ); 117 } 118 119 { 120 O o; 121 VERIFY( !o ); 122 O p; 123 o = std::move(p); 124 VERIFY( !o ); 125 VERIFY( !p ); 126 } 127 128 { 129 O o; 130 VERIFY( !o ); 131 o = {}; 132 VERIFY( !o ); 133 } 134 135 // From engaged optional 136 { 137 O o; 138 VERIFY( !o ); 139 O p = make(S::throwing_copy_assignment); 140 o = p; 141 VERIFY( o && o->state == S::throwing_copy_assignment ); 142 VERIFY( p && p->state == S::throwing_copy_assignment ); 143 } 144 145 { 146 O o; 147 VERIFY( !o ); 148 O p = make(S::throwing_move_assignment); 149 o = std::move(p); 150 VERIFY( o && o->state == S::throwing_move_assignment ); 151 VERIFY( p && p->state == S::moved_from ); 152 } 153 154 { 155 outcome_type outcome {}; 156 O o; 157 VERIFY( !o ); 158 O p = make(S::throwing_copy); 159 160 try 161 { 162 o = p; 163 } 164 catch(exception const&) 165 { outcome = caught; } 166 catch(...) 167 { outcome = bad_catch; } 168 169 VERIFY( outcome == caught ); 170 VERIFY( !o ); 171 VERIFY( p && p->state == S::throwing_copy ); 172 } 173 174 { 175 outcome_type outcome {}; 176 O o; 177 VERIFY( !o ); 178 O p = make(S::throwing_move); 179 180 try 181 { 182 o = std::move(p); 183 } 184 catch(exception const&) 185 { outcome = caught; } 186 catch(...) 187 { outcome = bad_catch; } 188 189 VERIFY( outcome == caught ); 190 VERIFY( !o ); 191 VERIFY( p && p->state == S::moved_from ); 192 } 193 194 VERIFY( counter == 0 ); 195} 196