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