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
24#include <tuple>
25
26using std::experimental::bad_optional_access;
27static_assert( std::is_default_constructible<bad_optional_access>::value, "" );
28
29struct trivially_destructible
30{
31  trivially_destructible() = delete;
32  trivially_destructible(trivially_destructible const&) = delete;
33  trivially_destructible& operator=(trivially_destructible const&) = delete;
34  trivially_destructible(trivially_destructible&&) = delete;
35  trivially_destructible& operator=(trivially_destructible&&) = delete;
36  ~trivially_destructible() noexcept = default;
37};
38
39static_assert( std::is_trivially_destructible<trivially_destructible>(), "" );
40
41struct no_default_constructor
42{
43  no_default_constructor() = delete;
44};
45
46struct no_copy_constructor
47{
48  no_copy_constructor() = default;
49  no_copy_constructor(no_copy_constructor const&) = delete;
50  no_copy_constructor& operator=(no_copy_constructor const&) = default;
51  no_copy_constructor(no_copy_constructor&&) = default;
52  no_copy_constructor& operator=(no_copy_constructor&&) = default;
53};
54
55struct no_copy_assignment
56{
57  no_copy_assignment() = default;
58  no_copy_assignment(no_copy_assignment const&) = default;
59  no_copy_assignment(no_copy_assignment&&) = default;
60  no_copy_assignment& operator=(no_copy_assignment&&) = default;
61};
62
63struct no_move_constructor
64{
65  no_move_constructor() = default;
66  no_move_constructor(no_move_constructor const&) = default;
67  no_move_constructor& operator=(no_move_constructor const&) = default;
68  no_move_constructor(no_move_constructor&&) = delete;
69  no_move_constructor& operator=(no_move_constructor&&) = default;
70};
71
72struct no_move_assignment
73{
74  no_move_assignment() = default;
75  no_move_assignment(no_move_assignment const&) = default;
76  no_move_assignment& operator=(no_move_assignment const&) = default;
77  no_move_assignment(no_move_assignment&&) = default;
78  no_move_assignment& operator=(no_move_assignment&&) = delete;
79};
80
81struct no_copy : no_copy_constructor, no_copy_assignment { };
82struct no_move : no_move_constructor, no_move_assignment { };
83
84// Laxest possible model of a value type for optional
85struct only_destructible
86{
87  only_destructible(only_destructible&&) = delete;
88};
89
90int main()
91{
92  {
93    static_assert( std::is_trivially_destructible<std::experimental::optional<trivially_destructible>>(), "" );
94  }
95
96  {
97    using T = no_default_constructor;
98    using O = std::experimental::optional<T>;
99    static_assert( std::is_same<O::value_type, T>(), "" );
100    static_assert( std::is_default_constructible<O>(), "" );
101    { O o; }
102    static_assert( std::is_copy_constructible<O>(), "" );
103    { O o; auto copy = o; }
104    static_assert( std::is_copy_assignable<O>(), "" );
105    { O o, p; p = o; }
106    static_assert( std::is_move_constructible<O>(), "" );
107    { O o; auto moved_to = std::move(o); }
108    static_assert( std::is_move_assignable<O>(), "" );
109    { O o, p; p = std::move(o); }
110  }
111
112  {
113    using T = no_copy_constructor;
114    using O = std::experimental::optional<T>;
115    static_assert( std::is_same<O::value_type, T>(), "" );
116    static_assert( std::is_default_constructible<O>(), "" );
117    { O o; }
118    static_assert( !std::is_copy_constructible<O>(), "" );
119    static_assert( !std::is_copy_assignable<O>(), "" );
120    static_assert( std::is_move_constructible<O>(), "" );
121    { O o; auto moved_to = std::move(o); }
122    static_assert( std::is_move_assignable<O>(), "" );
123    { O o, p; p = std::move(o); }
124  }
125
126  {
127    using T = no_copy_assignment;
128    using O = std::experimental::optional<T>;
129    static_assert( std::is_default_constructible<O>(), "" );
130    { O o; }
131    static_assert( std::is_copy_constructible<O>(), "" );
132    { O o; auto copy = o; }
133    static_assert( !std::is_copy_assignable<O>(), "" );
134    static_assert( std::is_move_constructible<O>(), "" );
135    { O o; auto moved_to = std::move(o); }
136    static_assert( std::is_move_assignable<O>(), "" );
137    { O o, p; p = std::move(o); }
138  }
139
140  {
141    using T = no_copy;
142    using O = std::experimental::optional<T>;
143    static_assert( std::is_same<O::value_type, T>(), "" );
144    static_assert( std::is_default_constructible<O>(), "" );
145    { O o; }
146    static_assert( !std::is_copy_constructible<O>(), "" );
147    static_assert( !std::is_copy_assignable<O>(), "" );
148    static_assert( std::is_move_constructible<O>(), "" );
149    { O o; auto moved_to = std::move(o); }
150    static_assert( std::is_move_assignable<O>(), "" );
151    { O o, p; p = std::move(o); }
152  }
153
154  {
155    using T = no_move_constructor;
156    using O = std::experimental::optional<T>;
157    static_assert( std::is_same<O::value_type, T>(), "" );
158    static_assert( std::is_default_constructible<O>(), "" );
159    { O o; }
160    static_assert( std::is_copy_constructible<O>(), "" );
161    { O o; auto copy = o; }
162    static_assert( std::is_copy_assignable<O>(), "" );
163    /*
164     * T should be move constructible due to [12.8/11], which is a new rule in C++1y
165     * not yet implemented by GCC. Because there is already a special exception in C++11
166     * for the generation of the special members that GCC implements (at least some of the
167     * time), this does not affect the std::experimental::optional implementation however. So the assertion
168     * for T should be changed (or removed altogether) when the time comes, but the rest
169     * should however remain correct and unchanged.
170     */
171    static_assert( !std::is_move_constructible<T>(), "" );
172    static_assert( std::is_move_constructible<O>(), "" );
173    { O o; auto moved_to = std::move(o); }
174    static_assert( std::is_move_assignable<O>(), "" );
175    { O o, p; p = std::move(o); }
176  }
177
178  {
179    using T = no_move_assignment;
180    using O = std::experimental::optional<T>;
181    static_assert( std::is_same<O::value_type, T>(), "" );
182    static_assert( std::is_default_constructible<O>(), "" );
183    { O o; }
184    static_assert( std::is_copy_constructible<O>(), "" );
185    { O o; auto copy = o; }
186    static_assert( std::is_copy_assignable<O>(), "" );
187    { O o, p; p = o; }
188    static_assert( std::is_move_constructible<O>(), "" );
189    { O o; auto moved_to = std::move(o); }
190    /*
191     * Paragraph 23 of same leads to a similar situation but with respect to move
192     * assignment.
193     */
194    static_assert( !std::is_move_assignable<T>(), "" );
195    static_assert( std::is_move_assignable<O>(), "" );
196    { O o, p; p = std::move(o); }
197  }
198
199  {
200    using T = no_move;
201    using O = std::experimental::optional<T>;
202    static_assert( std::is_same<O::value_type, T>(), "" );
203    static_assert( std::is_default_constructible<O>(), "" );
204    { O o; }
205    static_assert( std::is_copy_constructible<O>(), "" );
206    { O o; auto copy = o; }
207    static_assert( std::is_copy_assignable<O>(), "" );
208    { O o, p; p = o; }
209    static_assert( std::is_move_constructible<O>(), "" );
210    { O o; auto moved_to = std::move(o); }
211    static_assert( std::is_move_assignable<O>(), "" );
212    { O o, p; p = std::move(o); }
213  }
214
215  {
216    using T = only_destructible;
217    using O = std::experimental::optional<T>;
218    static_assert( std::is_same<O::value_type, T>(), "" );
219    static_assert( std::is_default_constructible<O>(), "" );
220    { O o; }
221    static_assert( !std::is_copy_constructible<O>(), "" );
222    static_assert( !std::is_copy_assignable<O>(), "" );
223    static_assert( !std::is_move_constructible<O>(), "" );
224    static_assert( !std::is_move_assignable<O>(), "" );
225  }
226
227  {
228    /*
229     * Should not complain about 'invalid' specializations as long as
230     * they're not instantiated.
231     */
232    using A = std::experimental::optional<int&>;
233    using B = std::experimental::optional<int&&>;
234    using C1 = std::experimental::optional<std::experimental::in_place_t>;
235    using C2 = std::experimental::optional<std::experimental::in_place_t const>;
236    using C3 = std::experimental::optional<std::experimental::in_place_t volatile>;
237    using C4 = std::experimental::optional<std::experimental::in_place_t const volatile>;
238    using D1 = std::experimental::optional<std::experimental::nullopt_t>;
239    using D2 = std::experimental::optional<std::experimental::nullopt_t const>;
240    using D3 = std::experimental::optional<std::experimental::nullopt_t volatile>;
241    using D4 = std::experimental::optional<std::experimental::nullopt_t const volatile>;
242
243    using X = std::tuple<A, B, C1, C2, C3, C4, D1, D2, D3, D4>;
244  }
245
246  {
247    std::experimental::optional<const int> o { 42 };
248    static_assert( std::is_same<decltype(o)::value_type, const int>(), "" );
249    VERIFY( o );
250    VERIFY( *o == 42 );
251  }
252
253  {
254    constexpr std::experimental::optional<const int> o { 33 };
255    static_assert( std::is_same<decltype(o)::value_type, const int>(), "" );
256    static_assert( o, "" );
257    static_assert( *o == 33, "" );
258  }
259}
260