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