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 value_type { s }; }; 104 105 enum outcome_type { nothrow, caught, bad_catch }; 106 107 // Check value assignment for disengaged optional 108 109 { 110 O o; 111 value_type v = make(S::throwing_copy_assignment); 112 o = v; 113 VERIFY( o && o->state == S::throwing_copy_assignment ); 114 } 115 116 { 117 O o; 118 value_type v = make(S::throwing_move_assignment); 119 o = std::move(v); 120 VERIFY( o && o->state == S::throwing_move_assignment ); 121 } 122 123 { 124 outcome_type outcome {}; 125 O o; 126 value_type v = make(S::throwing_copy); 127 128 try 129 { 130 o = v; 131 } 132 catch(exception const&) 133 { outcome = caught; } 134 catch(...) 135 { outcome = bad_catch; } 136 137 VERIFY( !o ); 138 } 139 140 { 141 outcome_type outcome {}; 142 O o; 143 value_type v = make(S::throwing_move); 144 145 try 146 { 147 o = std::move(v); 148 } 149 catch(exception const&) 150 { outcome = caught; } 151 catch(...) 152 { outcome = bad_catch; } 153 154 VERIFY( !o ); 155 } 156 157 VERIFY( counter == 0 ); 158} 159