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 engaged optional 108 109 // From disengaged optional 110 { 111 O o = make(S::zero); 112 VERIFY( o ); 113 O p; 114 o = p; 115 VERIFY( !o ); 116 VERIFY( !p ); 117 } 118 119 { 120 O o = make(S::zero); 121 VERIFY( o ); 122 O p; 123 o = std::move(p); 124 VERIFY( !o ); 125 VERIFY( !p ); 126 } 127 128 { 129 O o = make(S::zero); 130 VERIFY( o ); 131 o = {}; 132 VERIFY( !o ); 133 } 134 135 // From engaged optional 136 { 137 O o = make(S::zero); 138 VERIFY( o ); 139 O p = make(S::throwing_copy); 140 o = p; 141 VERIFY( o && o->state == S::throwing_copy); 142 VERIFY( p && p->state == S::throwing_copy); 143 } 144 145 { 146 O o = make(S::zero); 147 VERIFY( o ); 148 O p = make(S::throwing_move); 149 o = std::move(p); 150 VERIFY( o && o->state == S::throwing_move); 151 VERIFY( p && p->state == S::moved_from); 152 } 153 154 { 155 outcome_type outcome {}; 156 O o = make(S::zero); 157 VERIFY( o ); 158 O p = make(S::throwing_copy_assignment); 159 160 try 161 { 162 o = p; 163 } 164 catch(exception const&) 165 { outcome = caught; } 166 catch(...) 167 { outcome = bad_catch; } 168 169 VERIFY( o && o->state == S::threw); 170 VERIFY( p && p->state == S::throwing_copy_assignment); 171 } 172 173 { 174 outcome_type outcome {}; 175 O o = make(S::zero); 176 VERIFY( o ); 177 O p = make(S::throwing_move_assignment); 178 179 try 180 { 181 o = std::move(p); 182 } 183 catch(exception const&) 184 { outcome = caught; } 185 catch(...) 186 { outcome = bad_catch; } 187 188 VERIFY( o && o->state == S::threw); 189 VERIFY( p && p->state == S::moved_from); 190 } 191 192 VERIFY( counter == 0 ); 193} 194