1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // UNSUPPORTED: c++03, c++11, c++14
10 
11 // XFAIL: dylib-has-no-bad_optional_access && !no-exceptions
12 
13 // <optional>
14 
15 // template <class U>
16 //   constexpr EXPLICIT optional(U&& u);
17 
18 #include <optional>
19 #include <type_traits>
20 #include <cassert>
21 
22 #include "test_macros.h"
23 #include "archetypes.h"
24 #include "test_convertible.h"
25 
26 
27 using std::optional;
28 
29 struct ImplicitThrow
30 {
31     constexpr ImplicitThrow(int x) { if (x != -1) TEST_THROW(6);}
32 };
33 
34 struct ExplicitThrow
35 {
36     constexpr explicit ExplicitThrow(int x) { if (x != -1) TEST_THROW(6);}
37 };
38 
39 struct ImplicitAny {
40   template <class U>
41   constexpr ImplicitAny(U&&) {}
42 };
43 
44 
45 template <class To, class From>
46 constexpr bool implicit_conversion(optional<To>&& opt, const From& v)
47 {
48     using O = optional<To>;
49     static_assert(test_convertible<O, From>(), "");
50     static_assert(!test_convertible<O, void*>(), "");
51     static_assert(!test_convertible<O, From, int>(), "");
52     return opt && *opt == static_cast<To>(v);
53 }
54 
55 template <class To, class Input, class Expect>
56 constexpr bool explicit_conversion(Input&& in, const Expect& v)
57 {
58     using O = optional<To>;
59     static_assert(std::is_constructible<O, Input>::value, "");
60     static_assert(!std::is_convertible<Input, O>::value, "");
61     static_assert(!std::is_constructible<O, void*>::value, "");
62     static_assert(!std::is_constructible<O, Input, int>::value, "");
63     optional<To> opt(std::forward<Input>(in));
64     return opt && *opt == static_cast<To>(v);
65 }
66 
67 void test_implicit()
68 {
69     {
70         static_assert(implicit_conversion<long long>(42, 42), "");
71     }
72     {
73         static_assert(implicit_conversion<long double>(3.14, 3.14), "");
74     }
75     {
76         int x = 42;
77         optional<void* const> o(&x);
78         assert(*o == &x);
79     }
80     {
81         using T = TrivialTestTypes::TestType;
82         static_assert(implicit_conversion<T>(42, 42), "");
83     }
84     {
85         using T = TestTypes::TestType;
86         assert(implicit_conversion<T>(3, T(3)));
87     }
88   {
89     using O = optional<ImplicitAny>;
90     static_assert(!test_convertible<O, std::in_place_t>(), "");
91     static_assert(!test_convertible<O, std::in_place_t&>(), "");
92     static_assert(!test_convertible<O, const std::in_place_t&>(), "");
93     static_assert(!test_convertible<O, std::in_place_t&&>(), "");
94     static_assert(!test_convertible<O, const std::in_place_t&&>(), "");
95 
96   }
97 #ifndef TEST_HAS_NO_EXCEPTIONS
98     {
99         try {
100             using T = ImplicitThrow;
101             optional<T> t = 42;
102             assert(false);
103             ((void)t);
104         } catch (int) {
105         }
106     }
107 #endif
108 }
109 
110 void test_explicit() {
111     {
112         using T = ExplicitTrivialTestTypes::TestType;
113         static_assert(explicit_conversion<T>(42, 42), "");
114     }
115     {
116         using T = ExplicitConstexprTestTypes::TestType;
117         static_assert(explicit_conversion<T>(42, 42), "");
118         static_assert(!std::is_convertible<int, T>::value, "");
119     }
120     {
121         using T = ExplicitTestTypes::TestType;
122         T::reset();
123         {
124             assert(explicit_conversion<T>(42, 42));
125             assert(T::alive == 0);
126         }
127         T::reset();
128         {
129             optional<T> t(42);
130             assert(T::alive == 1);
131             assert(T::value_constructed == 1);
132             assert(T::move_constructed == 0);
133             assert(T::copy_constructed == 0);
134             assert(t.value().value == 42);
135         }
136         assert(T::alive == 0);
137     }
138 #ifndef TEST_HAS_NO_EXCEPTIONS
139     {
140         try {
141             using T = ExplicitThrow;
142             optional<T> t(42);
143             assert(false);
144         } catch (int) {
145         }
146     }
147 #endif
148 }
149 
150 int main(int, char**) {
151     test_implicit();
152     test_explicit();
153 
154   return 0;
155 }
156