xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (revision 72a28a3bf0b539bcdfd8f41905675ce6a890c0ac)
1af98b0afSStanislav Gatev //===- UncheckedOptionalAccessModelTest.cpp -------------------------------===//
2af98b0afSStanislav Gatev //
3af98b0afSStanislav Gatev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4af98b0afSStanislav Gatev // See https://llvm.org/LICENSE.txt for license information.
5af98b0afSStanislav Gatev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6af98b0afSStanislav Gatev //
7af98b0afSStanislav Gatev //===----------------------------------------------------------------------===//
8af98b0afSStanislav Gatev // FIXME: Move this to clang/unittests/Analysis/FlowSensitive/Models.
9af98b0afSStanislav Gatev 
10af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h"
11af98b0afSStanislav Gatev #include "TestingSupport.h"
12af98b0afSStanislav Gatev #include "clang/AST/ASTContext.h"
13af98b0afSStanislav Gatev #include "clang/ASTMatchers/ASTMatchers.h"
1458fe7f96SSam Estep #include "clang/Basic/SourceLocation.h"
158b5d3ba8SMartin Braenne #include "clang/Frontend/TextDiagnostic.h"
16af98b0afSStanislav Gatev #include "clang/Tooling/Tooling.h"
1758fe7f96SSam Estep #include "llvm/ADT/DenseSet.h"
1858fe7f96SSam Estep #include "llvm/ADT/STLExtras.h"
19af98b0afSStanislav Gatev #include "llvm/Support/Error.h"
20af98b0afSStanislav Gatev #include "gmock/gmock.h"
21af98b0afSStanislav Gatev #include "gtest/gtest.h"
22a1580d7bSKazu Hirata #include <optional>
23af98b0afSStanislav Gatev #include <string>
24af98b0afSStanislav Gatev #include <utility>
25af98b0afSStanislav Gatev #include <vector>
26af98b0afSStanislav Gatev 
27af98b0afSStanislav Gatev using namespace clang;
28af98b0afSStanislav Gatev using namespace dataflow;
29af98b0afSStanislav Gatev using namespace test;
30af98b0afSStanislav Gatev 
3158fe7f96SSam Estep using ::testing::ContainerEq;
32af98b0afSStanislav Gatev 
339e0fc676SStanislav Gatev // FIXME: Move header definitions in separate file(s).
34b000b770SStanislav Gatev static constexpr char CSDtdDefHeader[] = R"(
35b000b770SStanislav Gatev #ifndef CSTDDEF_H
36b000b770SStanislav Gatev #define CSTDDEF_H
379e0fc676SStanislav Gatev 
38af98b0afSStanislav Gatev namespace std {
39af98b0afSStanislav Gatev 
409e0fc676SStanislav Gatev typedef decltype(sizeof(char)) size_t;
419e0fc676SStanislav Gatev 
42b000b770SStanislav Gatev using nullptr_t = decltype(nullptr);
43b000b770SStanislav Gatev 
44b000b770SStanislav Gatev } // namespace std
45b000b770SStanislav Gatev 
46b000b770SStanislav Gatev #endif // CSTDDEF_H
47b000b770SStanislav Gatev )";
48b000b770SStanislav Gatev 
49b000b770SStanislav Gatev static constexpr char StdTypeTraitsHeader[] = R"(
50b000b770SStanislav Gatev #ifndef STD_TYPE_TRAITS_H
51b000b770SStanislav Gatev #define STD_TYPE_TRAITS_H
52b000b770SStanislav Gatev 
53b000b770SStanislav Gatev #include "cstddef.h"
54b000b770SStanislav Gatev 
55b000b770SStanislav Gatev namespace std {
56b000b770SStanislav Gatev 
579e0fc676SStanislav Gatev template <typename T, T V>
589e0fc676SStanislav Gatev struct integral_constant {
599e0fc676SStanislav Gatev   static constexpr T value = V;
609e0fc676SStanislav Gatev };
619e0fc676SStanislav Gatev 
629e0fc676SStanislav Gatev using true_type = integral_constant<bool, true>;
639e0fc676SStanislav Gatev using false_type = integral_constant<bool, false>;
649e0fc676SStanislav Gatev 
65af98b0afSStanislav Gatev template< class T > struct remove_reference      {typedef T type;};
66af98b0afSStanislav Gatev template< class T > struct remove_reference<T&>  {typedef T type;};
67af98b0afSStanislav Gatev template< class T > struct remove_reference<T&&> {typedef T type;};
68af98b0afSStanislav Gatev 
69af98b0afSStanislav Gatev template <class T>
70af98b0afSStanislav Gatev   using remove_reference_t = typename remove_reference<T>::type;
71af98b0afSStanislav Gatev 
729e0fc676SStanislav Gatev template <class T>
739e0fc676SStanislav Gatev struct remove_extent {
749e0fc676SStanislav Gatev   typedef T type;
759e0fc676SStanislav Gatev };
769e0fc676SStanislav Gatev 
779e0fc676SStanislav Gatev template <class T>
789e0fc676SStanislav Gatev struct remove_extent<T[]> {
799e0fc676SStanislav Gatev   typedef T type;
809e0fc676SStanislav Gatev };
819e0fc676SStanislav Gatev 
829e0fc676SStanislav Gatev template <class T, size_t N>
839e0fc676SStanislav Gatev struct remove_extent<T[N]> {
849e0fc676SStanislav Gatev   typedef T type;
859e0fc676SStanislav Gatev };
869e0fc676SStanislav Gatev 
879e0fc676SStanislav Gatev template <class T>
889e0fc676SStanislav Gatev struct is_array : false_type {};
899e0fc676SStanislav Gatev 
909e0fc676SStanislav Gatev template <class T>
919e0fc676SStanislav Gatev struct is_array<T[]> : true_type {};
929e0fc676SStanislav Gatev 
939e0fc676SStanislav Gatev template <class T, size_t N>
949e0fc676SStanislav Gatev struct is_array<T[N]> : true_type {};
959e0fc676SStanislav Gatev 
969e0fc676SStanislav Gatev template <class>
979e0fc676SStanislav Gatev struct is_function : false_type {};
989e0fc676SStanislav Gatev 
999e0fc676SStanislav Gatev template <class Ret, class... Args>
1009e0fc676SStanislav Gatev struct is_function<Ret(Args...)> : true_type {};
1019e0fc676SStanislav Gatev 
1029e0fc676SStanislav Gatev namespace detail {
1039e0fc676SStanislav Gatev 
1049e0fc676SStanislav Gatev template <class T>
1059e0fc676SStanislav Gatev struct type_identity {
1069e0fc676SStanislav Gatev   using type = T;
1079e0fc676SStanislav Gatev };  // or use type_identity (since C++20)
1089e0fc676SStanislav Gatev 
1099e0fc676SStanislav Gatev template <class T>
1109e0fc676SStanislav Gatev auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>;
1119e0fc676SStanislav Gatev template <class T>
1129e0fc676SStanislav Gatev auto try_add_pointer(...) -> type_identity<T>;
1139e0fc676SStanislav Gatev 
1149e0fc676SStanislav Gatev }  // namespace detail
1159e0fc676SStanislav Gatev 
1169e0fc676SStanislav Gatev template <class T>
1179e0fc676SStanislav Gatev struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
1189e0fc676SStanislav Gatev 
1199e0fc676SStanislav Gatev template <bool B, class T, class F>
1209e0fc676SStanislav Gatev struct conditional {
1219e0fc676SStanislav Gatev   typedef T type;
1229e0fc676SStanislav Gatev };
1239e0fc676SStanislav Gatev 
1249e0fc676SStanislav Gatev template <class T, class F>
1259e0fc676SStanislav Gatev struct conditional<false, T, F> {
1269e0fc676SStanislav Gatev   typedef F type;
1279e0fc676SStanislav Gatev };
1289e0fc676SStanislav Gatev 
1299e0fc676SStanislav Gatev template <class T>
1309e0fc676SStanislav Gatev struct remove_cv {
1319e0fc676SStanislav Gatev   typedef T type;
1329e0fc676SStanislav Gatev };
1339e0fc676SStanislav Gatev template <class T>
1349e0fc676SStanislav Gatev struct remove_cv<const T> {
1359e0fc676SStanislav Gatev   typedef T type;
1369e0fc676SStanislav Gatev };
1379e0fc676SStanislav Gatev template <class T>
1389e0fc676SStanislav Gatev struct remove_cv<volatile T> {
1399e0fc676SStanislav Gatev   typedef T type;
1409e0fc676SStanislav Gatev };
1419e0fc676SStanislav Gatev template <class T>
1429e0fc676SStanislav Gatev struct remove_cv<const volatile T> {
1439e0fc676SStanislav Gatev   typedef T type;
1449e0fc676SStanislav Gatev };
1459e0fc676SStanislav Gatev 
1469e0fc676SStanislav Gatev template <class T>
147092a530cSStanislav Gatev using remove_cv_t = typename remove_cv<T>::type;
148092a530cSStanislav Gatev 
149092a530cSStanislav Gatev template <class T>
1509e0fc676SStanislav Gatev struct decay {
1519e0fc676SStanislav Gatev  private:
1529e0fc676SStanislav Gatev   typedef typename remove_reference<T>::type U;
1539e0fc676SStanislav Gatev 
1549e0fc676SStanislav Gatev  public:
1559e0fc676SStanislav Gatev   typedef typename conditional<
1569e0fc676SStanislav Gatev       is_array<U>::value, typename remove_extent<U>::type*,
1579e0fc676SStanislav Gatev       typename conditional<is_function<U>::value, typename add_pointer<U>::type,
1589e0fc676SStanislav Gatev                            typename remove_cv<U>::type>::type>::type type;
1599e0fc676SStanislav Gatev };
1609e0fc676SStanislav Gatev 
161092a530cSStanislav Gatev template <bool B, class T = void>
162092a530cSStanislav Gatev struct enable_if {};
163092a530cSStanislav Gatev 
164092a530cSStanislav Gatev template <class T>
165092a530cSStanislav Gatev struct enable_if<true, T> {
166092a530cSStanislav Gatev   typedef T type;
167092a530cSStanislav Gatev };
168092a530cSStanislav Gatev 
169092a530cSStanislav Gatev template <bool B, class T = void>
170092a530cSStanislav Gatev using enable_if_t = typename enable_if<B, T>::type;
171092a530cSStanislav Gatev 
172092a530cSStanislav Gatev template <class T, class U>
173092a530cSStanislav Gatev struct is_same : false_type {};
174092a530cSStanislav Gatev 
175092a530cSStanislav Gatev template <class T>
176092a530cSStanislav Gatev struct is_same<T, T> : true_type {};
177092a530cSStanislav Gatev 
178092a530cSStanislav Gatev template <class T>
179092a530cSStanislav Gatev struct is_void : is_same<void, typename remove_cv<T>::type> {};
180092a530cSStanislav Gatev 
181092a530cSStanislav Gatev namespace detail {
182092a530cSStanislav Gatev 
183092a530cSStanislav Gatev template <class T>
184cd0d5261SSam Estep auto try_add_lvalue_reference(int) -> type_identity<T&>;
185cd0d5261SSam Estep template <class T>
186cd0d5261SSam Estep auto try_add_lvalue_reference(...) -> type_identity<T>;
187cd0d5261SSam Estep 
188cd0d5261SSam Estep template <class T>
189092a530cSStanislav Gatev auto try_add_rvalue_reference(int) -> type_identity<T&&>;
190092a530cSStanislav Gatev template <class T>
191092a530cSStanislav Gatev auto try_add_rvalue_reference(...) -> type_identity<T>;
192092a530cSStanislav Gatev 
193092a530cSStanislav Gatev }  // namespace detail
194092a530cSStanislav Gatev 
195092a530cSStanislav Gatev template <class T>
196cd0d5261SSam Estep struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {
197cd0d5261SSam Estep };
198cd0d5261SSam Estep 
199cd0d5261SSam Estep template <class T>
200092a530cSStanislav Gatev struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {
201092a530cSStanislav Gatev };
202092a530cSStanislav Gatev 
203092a530cSStanislav Gatev template <class T>
204092a530cSStanislav Gatev typename add_rvalue_reference<T>::type declval() noexcept;
205092a530cSStanislav Gatev 
206092a530cSStanislav Gatev namespace detail {
207092a530cSStanislav Gatev 
208092a530cSStanislav Gatev template <class T>
209092a530cSStanislav Gatev auto test_returnable(int)
210092a530cSStanislav Gatev     -> decltype(void(static_cast<T (*)()>(nullptr)), true_type{});
211092a530cSStanislav Gatev template <class>
212092a530cSStanislav Gatev auto test_returnable(...) -> false_type;
213092a530cSStanislav Gatev 
214092a530cSStanislav Gatev template <class From, class To>
215092a530cSStanislav Gatev auto test_implicitly_convertible(int)
216092a530cSStanislav Gatev     -> decltype(void(declval<void (&)(To)>()(declval<From>())), true_type{});
217092a530cSStanislav Gatev template <class, class>
218092a530cSStanislav Gatev auto test_implicitly_convertible(...) -> false_type;
219092a530cSStanislav Gatev 
220092a530cSStanislav Gatev }  // namespace detail
221092a530cSStanislav Gatev 
222092a530cSStanislav Gatev template <class From, class To>
223092a530cSStanislav Gatev struct is_convertible
224092a530cSStanislav Gatev     : integral_constant<bool,
225092a530cSStanislav Gatev                         (decltype(detail::test_returnable<To>(0))::value &&
226092a530cSStanislav Gatev                          decltype(detail::test_implicitly_convertible<From, To>(
227092a530cSStanislav Gatev                              0))::value) ||
228092a530cSStanislav Gatev                             (is_void<From>::value && is_void<To>::value)> {};
229092a530cSStanislav Gatev 
230092a530cSStanislav Gatev template <class From, class To>
231092a530cSStanislav Gatev inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
232092a530cSStanislav Gatev 
233092a530cSStanislav Gatev template <class...>
234092a530cSStanislav Gatev using void_t = void;
235092a530cSStanislav Gatev 
236092a530cSStanislav Gatev template <class, class T, class... Args>
237092a530cSStanislav Gatev struct is_constructible_ : false_type {};
238092a530cSStanislav Gatev 
239092a530cSStanislav Gatev template <class T, class... Args>
240092a530cSStanislav Gatev struct is_constructible_<void_t<decltype(T(declval<Args>()...))>, T, Args...>
241092a530cSStanislav Gatev     : true_type {};
242092a530cSStanislav Gatev 
243092a530cSStanislav Gatev template <class T, class... Args>
244092a530cSStanislav Gatev using is_constructible = is_constructible_<void_t<>, T, Args...>;
245092a530cSStanislav Gatev 
246092a530cSStanislav Gatev template <class T, class... Args>
247092a530cSStanislav Gatev inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
248092a530cSStanislav Gatev 
249092a530cSStanislav Gatev template <class _Tp>
250092a530cSStanislav Gatev struct __uncvref {
251092a530cSStanislav Gatev   typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type;
252092a530cSStanislav Gatev };
253092a530cSStanislav Gatev 
254092a530cSStanislav Gatev template <class _Tp>
255092a530cSStanislav Gatev using __uncvref_t = typename __uncvref<_Tp>::type;
256092a530cSStanislav Gatev 
257092a530cSStanislav Gatev template <bool _Val>
258092a530cSStanislav Gatev using _BoolConstant = integral_constant<bool, _Val>;
259092a530cSStanislav Gatev 
260092a530cSStanislav Gatev template <class _Tp, class _Up>
261092a530cSStanislav Gatev using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>;
262092a530cSStanislav Gatev 
263092a530cSStanislav Gatev template <class _Tp, class _Up>
264092a530cSStanislav Gatev using _IsNotSame = _BoolConstant<!__is_same(_Tp, _Up)>;
265092a530cSStanislav Gatev 
266092a530cSStanislav Gatev template <bool>
267092a530cSStanislav Gatev struct _MetaBase;
268092a530cSStanislav Gatev template <>
269092a530cSStanislav Gatev struct _MetaBase<true> {
270092a530cSStanislav Gatev   template <class _Tp, class _Up>
271092a530cSStanislav Gatev   using _SelectImpl = _Tp;
272092a530cSStanislav Gatev   template <template <class...> class _FirstFn, template <class...> class,
273092a530cSStanislav Gatev             class... _Args>
274092a530cSStanislav Gatev   using _SelectApplyImpl = _FirstFn<_Args...>;
275092a530cSStanislav Gatev   template <class _First, class...>
276092a530cSStanislav Gatev   using _FirstImpl = _First;
277092a530cSStanislav Gatev   template <class, class _Second, class...>
278092a530cSStanislav Gatev   using _SecondImpl = _Second;
279092a530cSStanislav Gatev   template <class _Result, class _First, class... _Rest>
280092a530cSStanislav Gatev   using _OrImpl =
281092a530cSStanislav Gatev       typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>::
282092a530cSStanislav Gatev           template _OrImpl<_First, _Rest...>;
283092a530cSStanislav Gatev };
284092a530cSStanislav Gatev 
285092a530cSStanislav Gatev template <>
286092a530cSStanislav Gatev struct _MetaBase<false> {
287092a530cSStanislav Gatev   template <class _Tp, class _Up>
288092a530cSStanislav Gatev   using _SelectImpl = _Up;
289092a530cSStanislav Gatev   template <template <class...> class, template <class...> class _SecondFn,
290092a530cSStanislav Gatev             class... _Args>
291092a530cSStanislav Gatev   using _SelectApplyImpl = _SecondFn<_Args...>;
292092a530cSStanislav Gatev   template <class _Result, class...>
293092a530cSStanislav Gatev   using _OrImpl = _Result;
294092a530cSStanislav Gatev };
295092a530cSStanislav Gatev 
296092a530cSStanislav Gatev template <bool _Cond, class _IfRes, class _ElseRes>
297092a530cSStanislav Gatev using _If = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;
298092a530cSStanislav Gatev 
299092a530cSStanislav Gatev template <class... _Rest>
300092a530cSStanislav Gatev using _Or = typename _MetaBase<sizeof...(_Rest) !=
301092a530cSStanislav Gatev                                0>::template _OrImpl<false_type, _Rest...>;
302092a530cSStanislav Gatev 
303092a530cSStanislav Gatev template <bool _Bp, class _Tp = void>
304092a530cSStanislav Gatev using __enable_if_t = typename enable_if<_Bp, _Tp>::type;
305092a530cSStanislav Gatev 
306092a530cSStanislav Gatev template <class...>
307092a530cSStanislav Gatev using __expand_to_true = true_type;
308092a530cSStanislav Gatev template <class... _Pred>
309092a530cSStanislav Gatev __expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int);
310092a530cSStanislav Gatev template <class...>
311092a530cSStanislav Gatev false_type __and_helper(...);
312092a530cSStanislav Gatev template <class... _Pred>
313092a530cSStanislav Gatev using _And = decltype(__and_helper<_Pred...>(0));
314092a530cSStanislav Gatev 
315b000b770SStanislav Gatev template <class _Pred>
316b000b770SStanislav Gatev struct _Not : _BoolConstant<!_Pred::value> {};
317b000b770SStanislav Gatev 
318092a530cSStanislav Gatev struct __check_tuple_constructor_fail {
319092a530cSStanislav Gatev   static constexpr bool __enable_explicit_default() { return false; }
320092a530cSStanislav Gatev   static constexpr bool __enable_implicit_default() { return false; }
321092a530cSStanislav Gatev   template <class...>
322092a530cSStanislav Gatev   static constexpr bool __enable_explicit() {
323092a530cSStanislav Gatev     return false;
324092a530cSStanislav Gatev   }
325092a530cSStanislav Gatev   template <class...>
326092a530cSStanislav Gatev   static constexpr bool __enable_implicit() {
327092a530cSStanislav Gatev     return false;
328092a530cSStanislav Gatev   }
329092a530cSStanislav Gatev };
330092a530cSStanislav Gatev 
331b000b770SStanislav Gatev template <typename, typename _Tp>
332b000b770SStanislav Gatev struct __select_2nd {
333b000b770SStanislav Gatev   typedef _Tp type;
334b000b770SStanislav Gatev };
335b000b770SStanislav Gatev template <class _Tp, class _Arg>
336b000b770SStanislav Gatev typename __select_2nd<decltype((declval<_Tp>() = declval<_Arg>())),
337b000b770SStanislav Gatev                       true_type>::type
338b000b770SStanislav Gatev __is_assignable_test(int);
339b000b770SStanislav Gatev template <class, class>
340b000b770SStanislav Gatev false_type __is_assignable_test(...);
341b000b770SStanislav Gatev template <class _Tp, class _Arg,
342b000b770SStanislav Gatev           bool = is_void<_Tp>::value || is_void<_Arg>::value>
343b000b770SStanislav Gatev struct __is_assignable_imp
344b000b770SStanislav Gatev     : public decltype((__is_assignable_test<_Tp, _Arg>(0))) {};
345b000b770SStanislav Gatev template <class _Tp, class _Arg>
346b000b770SStanislav Gatev struct __is_assignable_imp<_Tp, _Arg, true> : public false_type {};
347b000b770SStanislav Gatev template <class _Tp, class _Arg>
348b000b770SStanislav Gatev struct is_assignable : public __is_assignable_imp<_Tp, _Arg> {};
349b000b770SStanislav Gatev 
350b000b770SStanislav Gatev template <class _Tp>
351b000b770SStanislav Gatev struct __libcpp_is_integral : public false_type {};
352b000b770SStanislav Gatev template <>
353b000b770SStanislav Gatev struct __libcpp_is_integral<bool> : public true_type {};
354b000b770SStanislav Gatev template <>
355b000b770SStanislav Gatev struct __libcpp_is_integral<char> : public true_type {};
356b000b770SStanislav Gatev template <>
357b000b770SStanislav Gatev struct __libcpp_is_integral<signed char> : public true_type {};
358b000b770SStanislav Gatev template <>
359b000b770SStanislav Gatev struct __libcpp_is_integral<unsigned char> : public true_type {};
360b000b770SStanislav Gatev template <>
361b000b770SStanislav Gatev struct __libcpp_is_integral<wchar_t> : public true_type {};
362b000b770SStanislav Gatev template <>
363b000b770SStanislav Gatev struct __libcpp_is_integral<short> : public true_type {};  // NOLINT
364b000b770SStanislav Gatev template <>
365b000b770SStanislav Gatev struct __libcpp_is_integral<unsigned short> : public true_type {};  // NOLINT
366b000b770SStanislav Gatev template <>
367b000b770SStanislav Gatev struct __libcpp_is_integral<int> : public true_type {};
368b000b770SStanislav Gatev template <>
369b000b770SStanislav Gatev struct __libcpp_is_integral<unsigned int> : public true_type {};
370b000b770SStanislav Gatev template <>
371b000b770SStanislav Gatev struct __libcpp_is_integral<long> : public true_type {};  // NOLINT
372b000b770SStanislav Gatev template <>
373b000b770SStanislav Gatev struct __libcpp_is_integral<unsigned long> : public true_type {};  // NOLINT
374b000b770SStanislav Gatev template <>
375b000b770SStanislav Gatev struct __libcpp_is_integral<long long> : public true_type {};  // NOLINT
376b000b770SStanislav Gatev template <>                                                    // NOLINTNEXTLINE
377b000b770SStanislav Gatev struct __libcpp_is_integral<unsigned long long> : public true_type {};
378b000b770SStanislav Gatev template <class _Tp>
379b000b770SStanislav Gatev struct is_integral
380b000b770SStanislav Gatev     : public __libcpp_is_integral<typename remove_cv<_Tp>::type> {};
381b000b770SStanislav Gatev 
382b000b770SStanislav Gatev template <class _Tp>
383b000b770SStanislav Gatev struct __libcpp_is_floating_point : public false_type {};
384b000b770SStanislav Gatev template <>
385b000b770SStanislav Gatev struct __libcpp_is_floating_point<float> : public true_type {};
386b000b770SStanislav Gatev template <>
387b000b770SStanislav Gatev struct __libcpp_is_floating_point<double> : public true_type {};
388b000b770SStanislav Gatev template <>
389b000b770SStanislav Gatev struct __libcpp_is_floating_point<long double> : public true_type {};
390b000b770SStanislav Gatev template <class _Tp>
391b000b770SStanislav Gatev struct is_floating_point
392b000b770SStanislav Gatev     : public __libcpp_is_floating_point<typename remove_cv<_Tp>::type> {};
393b000b770SStanislav Gatev 
394b000b770SStanislav Gatev template <class _Tp>
395b000b770SStanislav Gatev struct is_arithmetic
396b000b770SStanislav Gatev     : public integral_constant<bool, is_integral<_Tp>::value ||
397b000b770SStanislav Gatev                                          is_floating_point<_Tp>::value> {};
398b000b770SStanislav Gatev 
399b000b770SStanislav Gatev template <class _Tp>
400b000b770SStanislav Gatev struct __libcpp_is_pointer : public false_type {};
401b000b770SStanislav Gatev template <class _Tp>
402b000b770SStanislav Gatev struct __libcpp_is_pointer<_Tp*> : public true_type {};
403b000b770SStanislav Gatev template <class _Tp>
404b000b770SStanislav Gatev struct is_pointer : public __libcpp_is_pointer<typename remove_cv<_Tp>::type> {
405b000b770SStanislav Gatev };
406b000b770SStanislav Gatev 
407b000b770SStanislav Gatev template <class _Tp>
408b000b770SStanislav Gatev struct __libcpp_is_member_pointer : public false_type {};
409b000b770SStanislav Gatev template <class _Tp, class _Up>
410b000b770SStanislav Gatev struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type {};
411b000b770SStanislav Gatev template <class _Tp>
412b000b770SStanislav Gatev struct is_member_pointer
413b000b770SStanislav Gatev     : public __libcpp_is_member_pointer<typename remove_cv<_Tp>::type> {};
414b000b770SStanislav Gatev 
415b000b770SStanislav Gatev template <class _Tp>
416b000b770SStanislav Gatev struct __libcpp_union : public false_type {};
417b000b770SStanislav Gatev template <class _Tp>
418b000b770SStanislav Gatev struct is_union : public __libcpp_union<typename remove_cv<_Tp>::type> {};
419b000b770SStanislav Gatev 
420b000b770SStanislav Gatev template <class T>
421b000b770SStanislav Gatev struct is_reference : false_type {};
422b000b770SStanislav Gatev template <class T>
423b000b770SStanislav Gatev struct is_reference<T&> : true_type {};
424b000b770SStanislav Gatev template <class T>
425b000b770SStanislav Gatev struct is_reference<T&&> : true_type {};
426b000b770SStanislav Gatev 
427b000b770SStanislav Gatev template <class T>
428b000b770SStanislav Gatev inline constexpr bool is_reference_v = is_reference<T>::value;
429b000b770SStanislav Gatev 
430b000b770SStanislav Gatev struct __two {
431b000b770SStanislav Gatev   char __lx[2];
432b000b770SStanislav Gatev };
433b000b770SStanislav Gatev 
434b000b770SStanislav Gatev namespace __is_class_imp {
435b000b770SStanislav Gatev template <class _Tp>
436b000b770SStanislav Gatev char __test(int _Tp::*);
437b000b770SStanislav Gatev template <class _Tp>
438b000b770SStanislav Gatev __two __test(...);
439b000b770SStanislav Gatev }  // namespace __is_class_imp
440b000b770SStanislav Gatev template <class _Tp>
441b000b770SStanislav Gatev struct is_class
442b000b770SStanislav Gatev     : public integral_constant<bool,
443b000b770SStanislav Gatev                                sizeof(__is_class_imp::__test<_Tp>(0)) == 1 &&
444b000b770SStanislav Gatev                                    !is_union<_Tp>::value> {};
445b000b770SStanislav Gatev 
446b000b770SStanislav Gatev template <class _Tp>
447b000b770SStanislav Gatev struct __is_nullptr_t_impl : public false_type {};
448b000b770SStanislav Gatev template <>
449b000b770SStanislav Gatev struct __is_nullptr_t_impl<nullptr_t> : public true_type {};
450b000b770SStanislav Gatev template <class _Tp>
451b000b770SStanislav Gatev struct __is_nullptr_t
452b000b770SStanislav Gatev     : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
453b000b770SStanislav Gatev template <class _Tp>
454b000b770SStanislav Gatev struct is_null_pointer
455b000b770SStanislav Gatev     : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
456b000b770SStanislav Gatev 
457b000b770SStanislav Gatev template <class _Tp>
458b000b770SStanislav Gatev struct is_enum
459b000b770SStanislav Gatev     : public integral_constant<
460b000b770SStanislav Gatev           bool, !is_void<_Tp>::value && !is_integral<_Tp>::value &&
461b000b770SStanislav Gatev                     !is_floating_point<_Tp>::value && !is_array<_Tp>::value &&
462b000b770SStanislav Gatev                     !is_pointer<_Tp>::value && !is_reference<_Tp>::value &&
463b000b770SStanislav Gatev                     !is_member_pointer<_Tp>::value && !is_union<_Tp>::value &&
464b000b770SStanislav Gatev                     !is_class<_Tp>::value && !is_function<_Tp>::value> {};
465b000b770SStanislav Gatev 
466b000b770SStanislav Gatev template <class _Tp>
467b000b770SStanislav Gatev struct is_scalar
468b000b770SStanislav Gatev     : public integral_constant<
469b000b770SStanislav Gatev           bool, is_arithmetic<_Tp>::value || is_member_pointer<_Tp>::value ||
470b000b770SStanislav Gatev                     is_pointer<_Tp>::value || __is_nullptr_t<_Tp>::value ||
471b000b770SStanislav Gatev                     is_enum<_Tp>::value> {};
472b000b770SStanislav Gatev template <>
473b000b770SStanislav Gatev struct is_scalar<nullptr_t> : public true_type {};
474b000b770SStanislav Gatev 
475af98b0afSStanislav Gatev } // namespace std
4769e0fc676SStanislav Gatev 
477092a530cSStanislav Gatev #endif // STD_TYPE_TRAITS_H
478092a530cSStanislav Gatev )";
479092a530cSStanislav Gatev 
480092a530cSStanislav Gatev static constexpr char AbslTypeTraitsHeader[] = R"(
481092a530cSStanislav Gatev #ifndef ABSL_TYPE_TRAITS_H
482092a530cSStanislav Gatev #define ABSL_TYPE_TRAITS_H
483092a530cSStanislav Gatev 
484092a530cSStanislav Gatev #include "std_type_traits.h"
485092a530cSStanislav Gatev 
486092a530cSStanislav Gatev namespace absl {
487092a530cSStanislav Gatev 
488092a530cSStanislav Gatev template <typename... Ts>
489092a530cSStanislav Gatev struct conjunction : std::true_type {};
490092a530cSStanislav Gatev 
491092a530cSStanislav Gatev template <typename T, typename... Ts>
492092a530cSStanislav Gatev struct conjunction<T, Ts...>
493092a530cSStanislav Gatev     : std::conditional<T::value, conjunction<Ts...>, T>::type {};
494092a530cSStanislav Gatev 
495092a530cSStanislav Gatev template <typename T>
496092a530cSStanislav Gatev struct conjunction<T> : T {};
497092a530cSStanislav Gatev 
498092a530cSStanislav Gatev template <typename T>
499092a530cSStanislav Gatev struct negation : std::integral_constant<bool, !T::value> {};
500092a530cSStanislav Gatev 
501092a530cSStanislav Gatev template <bool B, typename T = void>
502092a530cSStanislav Gatev using enable_if_t = typename std::enable_if<B, T>::type;
503092a530cSStanislav Gatev 
504092a530cSStanislav Gatev } // namespace absl
505092a530cSStanislav Gatev 
506092a530cSStanislav Gatev #endif // ABSL_TYPE_TRAITS_H
507af98b0afSStanislav Gatev )";
508af98b0afSStanislav Gatev 
5097f076004SYitzhak Mandelbaum static constexpr char StdStringHeader[] = R"(
5107f076004SYitzhak Mandelbaum #ifndef STRING_H
5117f076004SYitzhak Mandelbaum #define STRING_H
5127f076004SYitzhak Mandelbaum 
5137f076004SYitzhak Mandelbaum namespace std {
5147f076004SYitzhak Mandelbaum 
5157f076004SYitzhak Mandelbaum struct string {
5167f076004SYitzhak Mandelbaum   string(const char*);
5177f076004SYitzhak Mandelbaum   ~string();
5187f076004SYitzhak Mandelbaum   bool empty();
5197f076004SYitzhak Mandelbaum };
5207f076004SYitzhak Mandelbaum bool operator!=(const string &LHS, const char *RHS);
5217f076004SYitzhak Mandelbaum 
5227f076004SYitzhak Mandelbaum } // namespace std
5237f076004SYitzhak Mandelbaum 
5247f076004SYitzhak Mandelbaum #endif // STRING_H
5257f076004SYitzhak Mandelbaum )";
5267f076004SYitzhak Mandelbaum 
527af98b0afSStanislav Gatev static constexpr char StdUtilityHeader[] = R"(
5289e0fc676SStanislav Gatev #ifndef UTILITY_H
5299e0fc676SStanislav Gatev #define UTILITY_H
5309e0fc676SStanislav Gatev 
531af98b0afSStanislav Gatev #include "std_type_traits.h"
532af98b0afSStanislav Gatev 
533af98b0afSStanislav Gatev namespace std {
534af98b0afSStanislav Gatev 
535af98b0afSStanislav Gatev template <typename T>
5369e0fc676SStanislav Gatev constexpr remove_reference_t<T>&& move(T&& x);
537af98b0afSStanislav Gatev 
5382ddd57aeSStanislav Gatev template <typename T>
5392ddd57aeSStanislav Gatev void swap(T& a, T& b) noexcept;
5402ddd57aeSStanislav Gatev 
541af98b0afSStanislav Gatev } // namespace std
5429e0fc676SStanislav Gatev 
5439e0fc676SStanislav Gatev #endif // UTILITY_H
5449e0fc676SStanislav Gatev )";
5459e0fc676SStanislav Gatev 
5469e0fc676SStanislav Gatev static constexpr char StdInitializerListHeader[] = R"(
5479e0fc676SStanislav Gatev #ifndef INITIALIZER_LIST_H
5489e0fc676SStanislav Gatev #define INITIALIZER_LIST_H
5499e0fc676SStanislav Gatev 
5509e0fc676SStanislav Gatev namespace std {
5519e0fc676SStanislav Gatev 
5529e0fc676SStanislav Gatev template <typename T>
5539e0fc676SStanislav Gatev class initializer_list {
5549e0fc676SStanislav Gatev  public:
555482c41e9SMital Ashok   const T *a, *b;
5569e0fc676SStanislav Gatev   initializer_list() noexcept;
5579e0fc676SStanislav Gatev };
5589e0fc676SStanislav Gatev 
5599e0fc676SStanislav Gatev } // namespace std
5609e0fc676SStanislav Gatev 
5619e0fc676SStanislav Gatev #endif // INITIALIZER_LIST_H
562af98b0afSStanislav Gatev )";
563af98b0afSStanislav Gatev 
564af98b0afSStanislav Gatev static constexpr char StdOptionalHeader[] = R"(
5659e0fc676SStanislav Gatev #include "std_initializer_list.h"
5669e0fc676SStanislav Gatev #include "std_type_traits.h"
5679e0fc676SStanislav Gatev #include "std_utility.h"
5689e0fc676SStanislav Gatev 
569af98b0afSStanislav Gatev namespace std {
570af98b0afSStanislav Gatev 
571092a530cSStanislav Gatev struct in_place_t {};
572092a530cSStanislav Gatev constexpr in_place_t in_place;
573092a530cSStanislav Gatev 
574092a530cSStanislav Gatev struct nullopt_t {
575092a530cSStanislav Gatev   constexpr explicit nullopt_t() {}
576092a530cSStanislav Gatev };
577092a530cSStanislav Gatev constexpr nullopt_t nullopt;
578092a530cSStanislav Gatev 
579092a530cSStanislav Gatev template <class _Tp>
580092a530cSStanislav Gatev struct __optional_destruct_base {
581092a530cSStanislav Gatev   constexpr void reset() noexcept;
582092a530cSStanislav Gatev };
583092a530cSStanislav Gatev 
584092a530cSStanislav Gatev template <class _Tp>
585092a530cSStanislav Gatev struct __optional_storage_base : __optional_destruct_base<_Tp> {
586092a530cSStanislav Gatev   constexpr bool has_value() const noexcept;
587092a530cSStanislav Gatev };
588092a530cSStanislav Gatev 
589092a530cSStanislav Gatev template <typename _Tp>
590092a530cSStanislav Gatev class optional : private __optional_storage_base<_Tp> {
591092a530cSStanislav Gatev   using __base = __optional_storage_base<_Tp>;
592092a530cSStanislav Gatev 
593af98b0afSStanislav Gatev  public:
594092a530cSStanislav Gatev   using value_type = _Tp;
595af98b0afSStanislav Gatev 
596092a530cSStanislav Gatev  private:
597092a530cSStanislav Gatev   struct _CheckOptionalArgsConstructor {
598092a530cSStanislav Gatev     template <class _Up>
599092a530cSStanislav Gatev     static constexpr bool __enable_implicit() {
600092a530cSStanislav Gatev       return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
601092a530cSStanislav Gatev     }
602af98b0afSStanislav Gatev 
603092a530cSStanislav Gatev     template <class _Up>
604092a530cSStanislav Gatev     static constexpr bool __enable_explicit() {
605092a530cSStanislav Gatev       return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
606092a530cSStanislav Gatev     }
607092a530cSStanislav Gatev   };
608092a530cSStanislav Gatev   template <class _Up>
609092a530cSStanislav Gatev   using _CheckOptionalArgsCtor =
610092a530cSStanislav Gatev       _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value &&
611092a530cSStanislav Gatev               _IsNotSame<__uncvref_t<_Up>, optional>::value,
612092a530cSStanislav Gatev           _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>;
613092a530cSStanislav Gatev   template <class _QualUp>
614092a530cSStanislav Gatev   struct _CheckOptionalLikeConstructor {
615092a530cSStanislav Gatev     template <class _Up, class _Opt = optional<_Up>>
616092a530cSStanislav Gatev     using __check_constructible_from_opt =
617092a530cSStanislav Gatev         _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>,
618092a530cSStanislav Gatev             is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>,
619092a530cSStanislav Gatev             is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>,
620092a530cSStanislav Gatev             is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>;
621092a530cSStanislav Gatev     template <class _Up, class _QUp = _QualUp>
622092a530cSStanislav Gatev     static constexpr bool __enable_implicit() {
623092a530cSStanislav Gatev       return is_convertible<_QUp, _Tp>::value &&
624092a530cSStanislav Gatev              !__check_constructible_from_opt<_Up>::value;
625092a530cSStanislav Gatev     }
626092a530cSStanislav Gatev     template <class _Up, class _QUp = _QualUp>
627092a530cSStanislav Gatev     static constexpr bool __enable_explicit() {
628092a530cSStanislav Gatev       return !is_convertible<_QUp, _Tp>::value &&
629092a530cSStanislav Gatev              !__check_constructible_from_opt<_Up>::value;
630092a530cSStanislav Gatev     }
631092a530cSStanislav Gatev   };
632af98b0afSStanislav Gatev 
633092a530cSStanislav Gatev   template <class _Up, class _QualUp>
634092a530cSStanislav Gatev   using _CheckOptionalLikeCtor =
635092a530cSStanislav Gatev       _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value,
636092a530cSStanislav Gatev           _CheckOptionalLikeConstructor<_QualUp>,
637092a530cSStanislav Gatev           __check_tuple_constructor_fail>;
638092a530cSStanislav Gatev 
639b000b770SStanislav Gatev 
640b000b770SStanislav Gatev   template <class _Up, class _QualUp>
641b000b770SStanislav Gatev   using _CheckOptionalLikeAssign = _If<
642b000b770SStanislav Gatev       _And<
643b000b770SStanislav Gatev           _IsNotSame<_Up, _Tp>,
644b000b770SStanislav Gatev           is_constructible<_Tp, _QualUp>,
645b000b770SStanislav Gatev           is_assignable<_Tp&, _QualUp>
646b000b770SStanislav Gatev       >::value,
647b000b770SStanislav Gatev       _CheckOptionalLikeConstructor<_QualUp>,
648b000b770SStanislav Gatev       __check_tuple_constructor_fail
649b000b770SStanislav Gatev     >;
650b000b770SStanislav Gatev 
651092a530cSStanislav Gatev  public:
652092a530cSStanislav Gatev   constexpr optional() noexcept {}
653092a530cSStanislav Gatev   constexpr optional(const optional&) = default;
654092a530cSStanislav Gatev   constexpr optional(optional&&) = default;
655092a530cSStanislav Gatev   constexpr optional(nullopt_t) noexcept {}
656092a530cSStanislav Gatev 
657092a530cSStanislav Gatev   template <
658092a530cSStanislav Gatev       class _InPlaceT, class... _Args,
659092a530cSStanislav Gatev       class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>,
660092a530cSStanislav Gatev                              is_constructible<value_type, _Args...>>::value>>
661092a530cSStanislav Gatev   constexpr explicit optional(_InPlaceT, _Args&&... __args);
662092a530cSStanislav Gatev 
663092a530cSStanislav Gatev   template <class _Up, class... _Args,
664092a530cSStanislav Gatev             class = enable_if_t<is_constructible_v<
665092a530cSStanislav Gatev                 value_type, initializer_list<_Up>&, _Args...>>>
666092a530cSStanislav Gatev   constexpr explicit optional(in_place_t, initializer_list<_Up> __il,
667092a530cSStanislav Gatev                               _Args&&... __args);
668092a530cSStanislav Gatev 
669092a530cSStanislav Gatev   template <
670092a530cSStanislav Gatev       class _Up = value_type,
671092a530cSStanislav Gatev       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(),
672092a530cSStanislav Gatev                 int> = 0>
673092a530cSStanislav Gatev   constexpr optional(_Up&& __v);
674092a530cSStanislav Gatev 
675092a530cSStanislav Gatev   template <
676092a530cSStanislav Gatev       class _Up,
677092a530cSStanislav Gatev       enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(),
678092a530cSStanislav Gatev                 int> = 0>
679092a530cSStanislav Gatev   constexpr explicit optional(_Up&& __v);
680092a530cSStanislav Gatev 
681092a530cSStanislav Gatev   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
682092a530cSStanislav Gatev                                      template __enable_implicit<_Up>(),
683092a530cSStanislav Gatev                                  int> = 0>
684092a530cSStanislav Gatev   constexpr optional(const optional<_Up>& __v);
685092a530cSStanislav Gatev 
686092a530cSStanislav Gatev   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
687092a530cSStanislav Gatev                                      template __enable_explicit<_Up>(),
688092a530cSStanislav Gatev                                  int> = 0>
689092a530cSStanislav Gatev   constexpr explicit optional(const optional<_Up>& __v);
690092a530cSStanislav Gatev 
691092a530cSStanislav Gatev   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
692092a530cSStanislav Gatev                                      template __enable_implicit<_Up>(),
693092a530cSStanislav Gatev                                  int> = 0>
694092a530cSStanislav Gatev   constexpr optional(optional<_Up>&& __v);
695092a530cSStanislav Gatev 
696092a530cSStanislav Gatev   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
697092a530cSStanislav Gatev                                      template __enable_explicit<_Up>(),
698092a530cSStanislav Gatev                                  int> = 0>
699092a530cSStanislav Gatev   constexpr explicit optional(optional<_Up>&& __v);
700092a530cSStanislav Gatev 
701b000b770SStanislav Gatev   constexpr optional& operator=(nullopt_t) noexcept;
702b000b770SStanislav Gatev 
703b000b770SStanislav Gatev   optional& operator=(const optional&);
704b000b770SStanislav Gatev 
705b000b770SStanislav Gatev   optional& operator=(optional&&);
706b000b770SStanislav Gatev 
707b000b770SStanislav Gatev   template <class _Up = value_type,
708b000b770SStanislav Gatev             class = enable_if_t<_And<_IsNotSame<__uncvref_t<_Up>, optional>,
709b000b770SStanislav Gatev                                    _Or<_IsNotSame<__uncvref_t<_Up>, value_type>,
710b000b770SStanislav Gatev                                        _Not<is_scalar<value_type>>>,
711b000b770SStanislav Gatev                                    is_constructible<value_type, _Up>,
712b000b770SStanislav Gatev                                    is_assignable<value_type&, _Up>>::value>>
713b000b770SStanislav Gatev   constexpr optional& operator=(_Up&& __v);
714b000b770SStanislav Gatev 
715b000b770SStanislav Gatev   template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>::
716b000b770SStanislav Gatev                                      template __enable_assign<_Up>(),
717b000b770SStanislav Gatev                                  int> = 0>
718b000b770SStanislav Gatev   constexpr optional& operator=(const optional<_Up>& __v);
719b000b770SStanislav Gatev 
720b000b770SStanislav Gatev   template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::
721b000b770SStanislav Gatev                                      template __enable_assign<_Up>(),
722b000b770SStanislav Gatev                                  int> = 0>
723b000b770SStanislav Gatev   constexpr optional& operator=(optional<_Up>&& __v);
724b000b770SStanislav Gatev 
725092a530cSStanislav Gatev   const _Tp& operator*() const&;
726092a530cSStanislav Gatev   _Tp& operator*() &;
727092a530cSStanislav Gatev   const _Tp&& operator*() const&&;
728092a530cSStanislav Gatev   _Tp&& operator*() &&;
729092a530cSStanislav Gatev 
730092a530cSStanislav Gatev   const _Tp* operator->() const;
731092a530cSStanislav Gatev   _Tp* operator->();
732092a530cSStanislav Gatev 
733092a530cSStanislav Gatev   const _Tp& value() const&;
734092a530cSStanislav Gatev   _Tp& value() &;
735092a530cSStanislav Gatev   const _Tp&& value() const&&;
736092a530cSStanislav Gatev   _Tp&& value() &&;
737af98b0afSStanislav Gatev 
7389e0fc676SStanislav Gatev   template <typename U>
739092a530cSStanislav Gatev   constexpr _Tp value_or(U&& v) const&;
7409e0fc676SStanislav Gatev   template <typename U>
741092a530cSStanislav Gatev   _Tp value_or(U&& v) &&;
7429e0fc676SStanislav Gatev 
7439e0fc676SStanislav Gatev   template <typename... Args>
744092a530cSStanislav Gatev   _Tp& emplace(Args&&... args);
7459e0fc676SStanislav Gatev 
7469e0fc676SStanislav Gatev   template <typename U, typename... Args>
747092a530cSStanislav Gatev   _Tp& emplace(std::initializer_list<U> ilist, Args&&... args);
7489e0fc676SStanislav Gatev 
749092a530cSStanislav Gatev   using __base::reset;
7509e0fc676SStanislav Gatev 
7519e0fc676SStanislav Gatev   constexpr explicit operator bool() const noexcept;
752092a530cSStanislav Gatev   using __base::has_value;
7532ddd57aeSStanislav Gatev 
7542ddd57aeSStanislav Gatev   constexpr void swap(optional& __opt) noexcept;
755af98b0afSStanislav Gatev };
756af98b0afSStanislav Gatev 
7579e0fc676SStanislav Gatev template <typename T>
7589e0fc676SStanislav Gatev constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
7599e0fc676SStanislav Gatev 
7609e0fc676SStanislav Gatev template <typename T, typename... Args>
7619e0fc676SStanislav Gatev constexpr optional<T> make_optional(Args&&... args);
7629e0fc676SStanislav Gatev 
7639e0fc676SStanislav Gatev template <typename T, typename U, typename... Args>
7649e0fc676SStanislav Gatev constexpr optional<T> make_optional(std::initializer_list<U> il,
7659e0fc676SStanislav Gatev                                     Args&&... args);
7669e0fc676SStanislav Gatev 
767390029beSYitzhak Mandelbaum template <typename T, typename U>
768390029beSYitzhak Mandelbaum constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs);
769390029beSYitzhak Mandelbaum template <typename T, typename U>
770390029beSYitzhak Mandelbaum constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs);
771390029beSYitzhak Mandelbaum 
772390029beSYitzhak Mandelbaum template <typename T>
773390029beSYitzhak Mandelbaum constexpr bool operator==(const optional<T> &opt, nullopt_t);
774a446c9bfSmartinboehme 
775a446c9bfSmartinboehme // C++20 and later do not define the following overloads because they are
776a446c9bfSmartinboehme // provided by rewritten candidates instead.
777a446c9bfSmartinboehme #if __cplusplus < 202002L
778390029beSYitzhak Mandelbaum template <typename T>
779390029beSYitzhak Mandelbaum constexpr bool operator==(nullopt_t, const optional<T> &opt);
780390029beSYitzhak Mandelbaum template <typename T>
781390029beSYitzhak Mandelbaum constexpr bool operator!=(const optional<T> &opt, nullopt_t);
782390029beSYitzhak Mandelbaum template <typename T>
783390029beSYitzhak Mandelbaum constexpr bool operator!=(nullopt_t, const optional<T> &opt);
784a446c9bfSmartinboehme #endif  // __cplusplus < 202002L
785390029beSYitzhak Mandelbaum 
786390029beSYitzhak Mandelbaum template <typename T, typename U>
787390029beSYitzhak Mandelbaum constexpr bool operator==(const optional<T> &opt, const U &value);
788390029beSYitzhak Mandelbaum template <typename T, typename U>
789390029beSYitzhak Mandelbaum constexpr bool operator==(const T &value, const optional<U> &opt);
790390029beSYitzhak Mandelbaum template <typename T, typename U>
791390029beSYitzhak Mandelbaum constexpr bool operator!=(const optional<T> &opt, const U &value);
792390029beSYitzhak Mandelbaum template <typename T, typename U>
793390029beSYitzhak Mandelbaum constexpr bool operator!=(const T &value, const optional<U> &opt);
794390029beSYitzhak Mandelbaum 
795af98b0afSStanislav Gatev } // namespace std
796af98b0afSStanislav Gatev )";
797af98b0afSStanislav Gatev 
798af98b0afSStanislav Gatev static constexpr char AbslOptionalHeader[] = R"(
799092a530cSStanislav Gatev #include "absl_type_traits.h"
8009e0fc676SStanislav Gatev #include "std_initializer_list.h"
8019e0fc676SStanislav Gatev #include "std_type_traits.h"
8029e0fc676SStanislav Gatev #include "std_utility.h"
8039e0fc676SStanislav Gatev 
804af98b0afSStanislav Gatev namespace absl {
805af98b0afSStanislav Gatev 
806092a530cSStanislav Gatev struct nullopt_t {
807092a530cSStanislav Gatev   constexpr explicit nullopt_t() {}
808092a530cSStanislav Gatev };
809092a530cSStanislav Gatev constexpr nullopt_t nullopt;
810092a530cSStanislav Gatev 
811092a530cSStanislav Gatev struct in_place_t {};
812092a530cSStanislav Gatev constexpr in_place_t in_place;
813092a530cSStanislav Gatev 
814092a530cSStanislav Gatev template <typename T>
815092a530cSStanislav Gatev class optional;
816092a530cSStanislav Gatev 
817092a530cSStanislav Gatev namespace optional_internal {
818092a530cSStanislav Gatev 
819092a530cSStanislav Gatev template <typename T, typename U>
820092a530cSStanislav Gatev struct is_constructible_convertible_from_optional
821092a530cSStanislav Gatev     : std::integral_constant<
822092a530cSStanislav Gatev           bool, std::is_constructible<T, optional<U>&>::value ||
823092a530cSStanislav Gatev                     std::is_constructible<T, optional<U>&&>::value ||
824092a530cSStanislav Gatev                     std::is_constructible<T, const optional<U>&>::value ||
825092a530cSStanislav Gatev                     std::is_constructible<T, const optional<U>&&>::value ||
826092a530cSStanislav Gatev                     std::is_convertible<optional<U>&, T>::value ||
827092a530cSStanislav Gatev                     std::is_convertible<optional<U>&&, T>::value ||
828092a530cSStanislav Gatev                     std::is_convertible<const optional<U>&, T>::value ||
829092a530cSStanislav Gatev                     std::is_convertible<const optional<U>&&, T>::value> {};
830092a530cSStanislav Gatev 
831b000b770SStanislav Gatev template <typename T, typename U>
832b000b770SStanislav Gatev struct is_constructible_convertible_assignable_from_optional
833b000b770SStanislav Gatev     : std::integral_constant<
834b000b770SStanislav Gatev           bool, is_constructible_convertible_from_optional<T, U>::value ||
835b000b770SStanislav Gatev                     std::is_assignable<T&, optional<U>&>::value ||
836b000b770SStanislav Gatev                     std::is_assignable<T&, optional<U>&&>::value ||
837b000b770SStanislav Gatev                     std::is_assignable<T&, const optional<U>&>::value ||
838b000b770SStanislav Gatev                     std::is_assignable<T&, const optional<U>&&>::value> {};
839b000b770SStanislav Gatev 
840092a530cSStanislav Gatev }  // namespace optional_internal
841092a530cSStanislav Gatev 
842af98b0afSStanislav Gatev template <typename T>
843af98b0afSStanislav Gatev class optional {
844af98b0afSStanislav Gatev  public:
845af98b0afSStanislav Gatev   constexpr optional() noexcept;
846af98b0afSStanislav Gatev 
847092a530cSStanislav Gatev   constexpr optional(nullopt_t) noexcept;
848092a530cSStanislav Gatev 
849092a530cSStanislav Gatev   optional(const optional&) = default;
850092a530cSStanislav Gatev 
851092a530cSStanislav Gatev   optional(optional&&) = default;
852092a530cSStanislav Gatev 
853092a530cSStanislav Gatev   template <typename InPlaceT, typename... Args,
854092a530cSStanislav Gatev             absl::enable_if_t<absl::conjunction<
855092a530cSStanislav Gatev                 std::is_same<InPlaceT, in_place_t>,
856092a530cSStanislav Gatev                 std::is_constructible<T, Args&&...>>::value>* = nullptr>
857092a530cSStanislav Gatev   constexpr explicit optional(InPlaceT, Args&&... args);
858092a530cSStanislav Gatev 
859092a530cSStanislav Gatev   template <typename U, typename... Args,
860092a530cSStanislav Gatev             typename = typename std::enable_if<std::is_constructible<
861092a530cSStanislav Gatev                 T, std::initializer_list<U>&, Args&&...>::value>::type>
862092a530cSStanislav Gatev   constexpr explicit optional(in_place_t, std::initializer_list<U> il,
863092a530cSStanislav Gatev                               Args&&... args);
864092a530cSStanislav Gatev 
865092a530cSStanislav Gatev   template <
866092a530cSStanislav Gatev       typename U = T,
867092a530cSStanislav Gatev       typename std::enable_if<
868092a530cSStanislav Gatev           absl::conjunction<absl::negation<std::is_same<
869092a530cSStanislav Gatev                                 in_place_t, typename std::decay<U>::type>>,
870092a530cSStanislav Gatev                             absl::negation<std::is_same<
871092a530cSStanislav Gatev                                 optional<T>, typename std::decay<U>::type>>,
872092a530cSStanislav Gatev                             std::is_convertible<U&&, T>,
873092a530cSStanislav Gatev                             std::is_constructible<T, U&&>>::value,
874092a530cSStanislav Gatev           bool>::type = false>
875092a530cSStanislav Gatev   constexpr optional(U&& v);
876092a530cSStanislav Gatev 
877092a530cSStanislav Gatev   template <
878092a530cSStanislav Gatev       typename U = T,
879092a530cSStanislav Gatev       typename std::enable_if<
880092a530cSStanislav Gatev           absl::conjunction<absl::negation<std::is_same<
881092a530cSStanislav Gatev                                 in_place_t, typename std::decay<U>::type>>,
882092a530cSStanislav Gatev                             absl::negation<std::is_same<
883092a530cSStanislav Gatev                                 optional<T>, typename std::decay<U>::type>>,
884092a530cSStanislav Gatev                             absl::negation<std::is_convertible<U&&, T>>,
885092a530cSStanislav Gatev                             std::is_constructible<T, U&&>>::value,
886092a530cSStanislav Gatev           bool>::type = false>
887092a530cSStanislav Gatev   explicit constexpr optional(U&& v);
888092a530cSStanislav Gatev 
889092a530cSStanislav Gatev   template <typename U,
890092a530cSStanislav Gatev             typename std::enable_if<
891092a530cSStanislav Gatev                 absl::conjunction<
892092a530cSStanislav Gatev                     absl::negation<std::is_same<T, U>>,
893092a530cSStanislav Gatev                     std::is_constructible<T, const U&>,
894092a530cSStanislav Gatev                     absl::negation<
895092a530cSStanislav Gatev                         optional_internal::
896092a530cSStanislav Gatev                             is_constructible_convertible_from_optional<T, U>>,
897092a530cSStanislav Gatev                     std::is_convertible<const U&, T>>::value,
898092a530cSStanislav Gatev                 bool>::type = false>
899092a530cSStanislav Gatev   optional(const optional<U>& rhs);
900092a530cSStanislav Gatev 
901092a530cSStanislav Gatev   template <typename U,
902092a530cSStanislav Gatev             typename std::enable_if<
903092a530cSStanislav Gatev                 absl::conjunction<
904092a530cSStanislav Gatev                     absl::negation<std::is_same<T, U>>,
905092a530cSStanislav Gatev                     std::is_constructible<T, const U&>,
906092a530cSStanislav Gatev                     absl::negation<
907092a530cSStanislav Gatev                         optional_internal::
908092a530cSStanislav Gatev                             is_constructible_convertible_from_optional<T, U>>,
909092a530cSStanislav Gatev                     absl::negation<std::is_convertible<const U&, T>>>::value,
910092a530cSStanislav Gatev                 bool>::type = false>
911092a530cSStanislav Gatev   explicit optional(const optional<U>& rhs);
912092a530cSStanislav Gatev 
913092a530cSStanislav Gatev   template <
914092a530cSStanislav Gatev       typename U,
915092a530cSStanislav Gatev       typename std::enable_if<
916092a530cSStanislav Gatev           absl::conjunction<
917092a530cSStanislav Gatev               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
918092a530cSStanislav Gatev               absl::negation<
919092a530cSStanislav Gatev                   optional_internal::is_constructible_convertible_from_optional<
920092a530cSStanislav Gatev                       T, U>>,
921092a530cSStanislav Gatev               std::is_convertible<U&&, T>>::value,
922092a530cSStanislav Gatev           bool>::type = false>
923092a530cSStanislav Gatev   optional(optional<U>&& rhs);
924092a530cSStanislav Gatev 
925092a530cSStanislav Gatev   template <
926092a530cSStanislav Gatev       typename U,
927092a530cSStanislav Gatev       typename std::enable_if<
928092a530cSStanislav Gatev           absl::conjunction<
929092a530cSStanislav Gatev               absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
930092a530cSStanislav Gatev               absl::negation<
931092a530cSStanislav Gatev                   optional_internal::is_constructible_convertible_from_optional<
932092a530cSStanislav Gatev                       T, U>>,
933092a530cSStanislav Gatev               absl::negation<std::is_convertible<U&&, T>>>::value,
934092a530cSStanislav Gatev           bool>::type = false>
935092a530cSStanislav Gatev   explicit optional(optional<U>&& rhs);
936092a530cSStanislav Gatev 
937b000b770SStanislav Gatev   optional& operator=(nullopt_t) noexcept;
938b000b770SStanislav Gatev 
939b000b770SStanislav Gatev   optional& operator=(const optional& src);
940b000b770SStanislav Gatev 
941b000b770SStanislav Gatev   optional& operator=(optional&& src);
942b000b770SStanislav Gatev 
943b000b770SStanislav Gatev   template <
944b000b770SStanislav Gatev       typename U = T,
945b000b770SStanislav Gatev       typename = typename std::enable_if<absl::conjunction<
946b000b770SStanislav Gatev           absl::negation<
947b000b770SStanislav Gatev               std::is_same<optional<T>, typename std::decay<U>::type>>,
948b000b770SStanislav Gatev           absl::negation<
949b000b770SStanislav Gatev               absl::conjunction<std::is_scalar<T>,
950b000b770SStanislav Gatev                                 std::is_same<T, typename std::decay<U>::type>>>,
951b000b770SStanislav Gatev           std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
952b000b770SStanislav Gatev   optional& operator=(U&& v);
953b000b770SStanislav Gatev 
954b000b770SStanislav Gatev   template <
955b000b770SStanislav Gatev       typename U,
956b000b770SStanislav Gatev       typename = typename std::enable_if<absl::conjunction<
957b000b770SStanislav Gatev           absl::negation<std::is_same<T, U>>,
958b000b770SStanislav Gatev           std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
959b000b770SStanislav Gatev           absl::negation<
960b000b770SStanislav Gatev               optional_internal::
961b000b770SStanislav Gatev                   is_constructible_convertible_assignable_from_optional<
962b000b770SStanislav Gatev                       T, U>>>::value>::type>
963b000b770SStanislav Gatev   optional& operator=(const optional<U>& rhs);
964b000b770SStanislav Gatev 
965b000b770SStanislav Gatev   template <typename U,
966b000b770SStanislav Gatev             typename = typename std::enable_if<absl::conjunction<
967b000b770SStanislav Gatev                 absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
968b000b770SStanislav Gatev                 std::is_assignable<T&, U>,
969b000b770SStanislav Gatev                 absl::negation<
970b000b770SStanislav Gatev                     optional_internal::
971b000b770SStanislav Gatev                         is_constructible_convertible_assignable_from_optional<
972b000b770SStanislav Gatev                             T, U>>>::value>::type>
973b000b770SStanislav Gatev   optional& operator=(optional<U>&& rhs);
974b000b770SStanislav Gatev 
975af98b0afSStanislav Gatev   const T& operator*() const&;
976af98b0afSStanislav Gatev   T& operator*() &;
977af98b0afSStanislav Gatev   const T&& operator*() const&&;
978af98b0afSStanislav Gatev   T&& operator*() &&;
979af98b0afSStanislav Gatev 
980af98b0afSStanislav Gatev   const T* operator->() const;
981af98b0afSStanislav Gatev   T* operator->();
982af98b0afSStanislav Gatev 
983af98b0afSStanislav Gatev   const T& value() const&;
984af98b0afSStanislav Gatev   T& value() &;
985af98b0afSStanislav Gatev   const T&& value() const&&;
986af98b0afSStanislav Gatev   T&& value() &&;
987af98b0afSStanislav Gatev 
9889e0fc676SStanislav Gatev   template <typename U>
9899e0fc676SStanislav Gatev   constexpr T value_or(U&& v) const&;
9909e0fc676SStanislav Gatev   template <typename U>
9919e0fc676SStanislav Gatev   T value_or(U&& v) &&;
9929e0fc676SStanislav Gatev 
9939e0fc676SStanislav Gatev   template <typename... Args>
9949e0fc676SStanislav Gatev   T& emplace(Args&&... args);
9959e0fc676SStanislav Gatev 
9969e0fc676SStanislav Gatev   template <typename U, typename... Args>
9979e0fc676SStanislav Gatev   T& emplace(std::initializer_list<U> ilist, Args&&... args);
9989e0fc676SStanislav Gatev 
9999e0fc676SStanislav Gatev   void reset() noexcept;
10009e0fc676SStanislav Gatev 
10019e0fc676SStanislav Gatev   constexpr explicit operator bool() const noexcept;
1002af98b0afSStanislav Gatev   constexpr bool has_value() const noexcept;
10032ddd57aeSStanislav Gatev 
10042ddd57aeSStanislav Gatev   void swap(optional& rhs) noexcept;
1005af98b0afSStanislav Gatev };
1006af98b0afSStanislav Gatev 
10079e0fc676SStanislav Gatev template <typename T>
10089e0fc676SStanislav Gatev constexpr optional<typename std::decay<T>::type> make_optional(T&& v);
10099e0fc676SStanislav Gatev 
10109e0fc676SStanislav Gatev template <typename T, typename... Args>
10119e0fc676SStanislav Gatev constexpr optional<T> make_optional(Args&&... args);
10129e0fc676SStanislav Gatev 
10139e0fc676SStanislav Gatev template <typename T, typename U, typename... Args>
10149e0fc676SStanislav Gatev constexpr optional<T> make_optional(std::initializer_list<U> il,
10159e0fc676SStanislav Gatev                                     Args&&... args);
10169e0fc676SStanislav Gatev 
1017390029beSYitzhak Mandelbaum template <typename T, typename U>
1018390029beSYitzhak Mandelbaum constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs);
1019390029beSYitzhak Mandelbaum template <typename T, typename U>
1020390029beSYitzhak Mandelbaum constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs);
1021390029beSYitzhak Mandelbaum 
1022390029beSYitzhak Mandelbaum template <typename T>
1023390029beSYitzhak Mandelbaum constexpr bool operator==(const optional<T> &opt, nullopt_t);
1024390029beSYitzhak Mandelbaum template <typename T>
1025390029beSYitzhak Mandelbaum constexpr bool operator==(nullopt_t, const optional<T> &opt);
1026390029beSYitzhak Mandelbaum template <typename T>
1027390029beSYitzhak Mandelbaum constexpr bool operator!=(const optional<T> &opt, nullopt_t);
1028390029beSYitzhak Mandelbaum template <typename T>
1029390029beSYitzhak Mandelbaum constexpr bool operator!=(nullopt_t, const optional<T> &opt);
1030390029beSYitzhak Mandelbaum 
1031390029beSYitzhak Mandelbaum template <typename T, typename U>
1032390029beSYitzhak Mandelbaum constexpr bool operator==(const optional<T> &opt, const U &value);
1033390029beSYitzhak Mandelbaum template <typename T, typename U>
1034390029beSYitzhak Mandelbaum constexpr bool operator==(const T &value, const optional<U> &opt);
1035390029beSYitzhak Mandelbaum template <typename T, typename U>
1036390029beSYitzhak Mandelbaum constexpr bool operator!=(const optional<T> &opt, const U &value);
1037390029beSYitzhak Mandelbaum template <typename T, typename U>
1038390029beSYitzhak Mandelbaum constexpr bool operator!=(const T &value, const optional<U> &opt);
1039390029beSYitzhak Mandelbaum 
1040af98b0afSStanislav Gatev } // namespace absl
1041af98b0afSStanislav Gatev )";
1042af98b0afSStanislav Gatev 
1043af98b0afSStanislav Gatev static constexpr char BaseOptionalHeader[] = R"(
10449e0fc676SStanislav Gatev #include "std_initializer_list.h"
10459e0fc676SStanislav Gatev #include "std_type_traits.h"
10469e0fc676SStanislav Gatev #include "std_utility.h"
10479e0fc676SStanislav Gatev 
1048af98b0afSStanislav Gatev namespace base {
1049af98b0afSStanislav Gatev 
1050092a530cSStanislav Gatev struct in_place_t {};
1051092a530cSStanislav Gatev constexpr in_place_t in_place;
1052092a530cSStanislav Gatev 
1053092a530cSStanislav Gatev struct nullopt_t {
1054092a530cSStanislav Gatev   constexpr explicit nullopt_t() {}
1055092a530cSStanislav Gatev };
1056092a530cSStanislav Gatev constexpr nullopt_t nullopt;
1057092a530cSStanislav Gatev 
1058092a530cSStanislav Gatev template <typename T>
1059092a530cSStanislav Gatev class Optional;
1060092a530cSStanislav Gatev 
1061092a530cSStanislav Gatev namespace internal {
1062092a530cSStanislav Gatev 
1063092a530cSStanislav Gatev template <typename T>
1064092a530cSStanislav Gatev using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
1065092a530cSStanislav Gatev 
1066092a530cSStanislav Gatev template <typename T, typename U>
1067092a530cSStanislav Gatev struct IsConvertibleFromOptional
1068092a530cSStanislav Gatev     : std::integral_constant<
1069092a530cSStanislav Gatev           bool, std::is_constructible<T, Optional<U>&>::value ||
1070092a530cSStanislav Gatev                     std::is_constructible<T, const Optional<U>&>::value ||
1071092a530cSStanislav Gatev                     std::is_constructible<T, Optional<U>&&>::value ||
1072092a530cSStanislav Gatev                     std::is_constructible<T, const Optional<U>&&>::value ||
1073092a530cSStanislav Gatev                     std::is_convertible<Optional<U>&, T>::value ||
1074092a530cSStanislav Gatev                     std::is_convertible<const Optional<U>&, T>::value ||
1075092a530cSStanislav Gatev                     std::is_convertible<Optional<U>&&, T>::value ||
1076092a530cSStanislav Gatev                     std::is_convertible<const Optional<U>&&, T>::value> {};
1077092a530cSStanislav Gatev 
1078b000b770SStanislav Gatev template <typename T, typename U>
1079b000b770SStanislav Gatev struct IsAssignableFromOptional
1080b000b770SStanislav Gatev     : std::integral_constant<
1081b000b770SStanislav Gatev           bool, IsConvertibleFromOptional<T, U>::value ||
1082b000b770SStanislav Gatev                     std::is_assignable<T&, Optional<U>&>::value ||
1083b000b770SStanislav Gatev                     std::is_assignable<T&, const Optional<U>&>::value ||
1084b000b770SStanislav Gatev                     std::is_assignable<T&, Optional<U>&&>::value ||
1085b000b770SStanislav Gatev                     std::is_assignable<T&, const Optional<U>&&>::value> {};
1086b000b770SStanislav Gatev 
1087092a530cSStanislav Gatev }  // namespace internal
1088092a530cSStanislav Gatev 
1089af98b0afSStanislav Gatev template <typename T>
1090af98b0afSStanislav Gatev class Optional {
1091af98b0afSStanislav Gatev  public:
1092092a530cSStanislav Gatev   using value_type = T;
1093092a530cSStanislav Gatev 
1094092a530cSStanislav Gatev   constexpr Optional() = default;
1095092a530cSStanislav Gatev   constexpr Optional(const Optional& other) noexcept = default;
1096092a530cSStanislav Gatev   constexpr Optional(Optional&& other) noexcept = default;
1097092a530cSStanislav Gatev 
1098092a530cSStanislav Gatev   constexpr Optional(nullopt_t);
1099092a530cSStanislav Gatev 
1100092a530cSStanislav Gatev   template <typename U,
1101092a530cSStanislav Gatev             typename std::enable_if<
1102092a530cSStanislav Gatev                 std::is_constructible<T, const U&>::value &&
1103092a530cSStanislav Gatev                     !internal::IsConvertibleFromOptional<T, U>::value &&
1104092a530cSStanislav Gatev                     std::is_convertible<const U&, T>::value,
1105092a530cSStanislav Gatev                 bool>::type = false>
1106092a530cSStanislav Gatev   Optional(const Optional<U>& other) noexcept;
1107092a530cSStanislav Gatev 
1108092a530cSStanislav Gatev   template <typename U,
1109092a530cSStanislav Gatev             typename std::enable_if<
1110092a530cSStanislav Gatev                 std::is_constructible<T, const U&>::value &&
1111092a530cSStanislav Gatev                     !internal::IsConvertibleFromOptional<T, U>::value &&
1112092a530cSStanislav Gatev                     !std::is_convertible<const U&, T>::value,
1113092a530cSStanislav Gatev                 bool>::type = false>
1114092a530cSStanislav Gatev   explicit Optional(const Optional<U>& other) noexcept;
1115092a530cSStanislav Gatev 
1116092a530cSStanislav Gatev   template <typename U,
1117092a530cSStanislav Gatev             typename std::enable_if<
1118092a530cSStanislav Gatev                 std::is_constructible<T, U&&>::value &&
1119092a530cSStanislav Gatev                     !internal::IsConvertibleFromOptional<T, U>::value &&
1120092a530cSStanislav Gatev                     std::is_convertible<U&&, T>::value,
1121092a530cSStanislav Gatev                 bool>::type = false>
1122092a530cSStanislav Gatev   Optional(Optional<U>&& other) noexcept;
1123092a530cSStanislav Gatev 
1124092a530cSStanislav Gatev   template <typename U,
1125092a530cSStanislav Gatev             typename std::enable_if<
1126092a530cSStanislav Gatev                 std::is_constructible<T, U&&>::value &&
1127092a530cSStanislav Gatev                     !internal::IsConvertibleFromOptional<T, U>::value &&
1128092a530cSStanislav Gatev                     !std::is_convertible<U&&, T>::value,
1129092a530cSStanislav Gatev                 bool>::type = false>
1130092a530cSStanislav Gatev   explicit Optional(Optional<U>&& other) noexcept;
1131092a530cSStanislav Gatev 
1132092a530cSStanislav Gatev   template <class... Args>
1133092a530cSStanislav Gatev   constexpr explicit Optional(in_place_t, Args&&... args);
1134092a530cSStanislav Gatev 
1135092a530cSStanislav Gatev   template <class U, class... Args,
1136092a530cSStanislav Gatev             class = typename std::enable_if<std::is_constructible<
1137092a530cSStanislav Gatev                 value_type, std::initializer_list<U>&, Args...>::value>::type>
1138092a530cSStanislav Gatev   constexpr explicit Optional(in_place_t, std::initializer_list<U> il,
1139092a530cSStanislav Gatev                               Args&&... args);
1140092a530cSStanislav Gatev 
1141092a530cSStanislav Gatev   template <
1142092a530cSStanislav Gatev       typename U = value_type,
1143092a530cSStanislav Gatev       typename std::enable_if<
1144092a530cSStanislav Gatev           std::is_constructible<T, U&&>::value &&
1145092a530cSStanislav Gatev               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1146092a530cSStanislav Gatev               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1147092a530cSStanislav Gatev               std::is_convertible<U&&, T>::value,
1148092a530cSStanislav Gatev           bool>::type = false>
1149092a530cSStanislav Gatev   constexpr Optional(U&& value);
1150092a530cSStanislav Gatev 
1151092a530cSStanislav Gatev   template <
1152092a530cSStanislav Gatev       typename U = value_type,
1153092a530cSStanislav Gatev       typename std::enable_if<
1154092a530cSStanislav Gatev           std::is_constructible<T, U&&>::value &&
1155092a530cSStanislav Gatev               !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
1156092a530cSStanislav Gatev               !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1157092a530cSStanislav Gatev               !std::is_convertible<U&&, T>::value,
1158092a530cSStanislav Gatev           bool>::type = false>
1159092a530cSStanislav Gatev   constexpr explicit Optional(U&& value);
1160af98b0afSStanislav Gatev 
1161b000b770SStanislav Gatev   Optional& operator=(const Optional& other) noexcept;
1162b000b770SStanislav Gatev 
1163b000b770SStanislav Gatev   Optional& operator=(Optional&& other) noexcept;
1164b000b770SStanislav Gatev 
1165b000b770SStanislav Gatev   Optional& operator=(nullopt_t);
1166b000b770SStanislav Gatev 
1167b000b770SStanislav Gatev   template <typename U>
1168b000b770SStanislav Gatev   typename std::enable_if<
1169b000b770SStanislav Gatev       !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
1170b000b770SStanislav Gatev           std::is_constructible<T, U>::value &&
1171b000b770SStanislav Gatev           std::is_assignable<T&, U>::value &&
1172b000b770SStanislav Gatev           (!std::is_scalar<T>::value ||
1173b000b770SStanislav Gatev            !std::is_same<typename std::decay<U>::type, T>::value),
1174b000b770SStanislav Gatev       Optional&>::type
1175b000b770SStanislav Gatev   operator=(U&& value) noexcept;
1176b000b770SStanislav Gatev 
1177b000b770SStanislav Gatev   template <typename U>
1178b000b770SStanislav Gatev   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1179b000b770SStanislav Gatev                               std::is_constructible<T, const U&>::value &&
1180b000b770SStanislav Gatev                               std::is_assignable<T&, const U&>::value,
1181b000b770SStanislav Gatev                           Optional&>::type
1182b000b770SStanislav Gatev   operator=(const Optional<U>& other) noexcept;
1183b000b770SStanislav Gatev 
1184b000b770SStanislav Gatev   template <typename U>
1185b000b770SStanislav Gatev   typename std::enable_if<!internal::IsAssignableFromOptional<T, U>::value &&
1186b000b770SStanislav Gatev                               std::is_constructible<T, U>::value &&
1187b000b770SStanislav Gatev                               std::is_assignable<T&, U>::value,
1188b000b770SStanislav Gatev                           Optional&>::type
1189b000b770SStanislav Gatev   operator=(Optional<U>&& other) noexcept;
1190b000b770SStanislav Gatev 
1191af98b0afSStanislav Gatev   const T& operator*() const&;
1192af98b0afSStanislav Gatev   T& operator*() &;
1193af98b0afSStanislav Gatev   const T&& operator*() const&&;
1194af98b0afSStanislav Gatev   T&& operator*() &&;
1195af98b0afSStanislav Gatev 
1196af98b0afSStanislav Gatev   const T* operator->() const;
1197af98b0afSStanislav Gatev   T* operator->();
1198af98b0afSStanislav Gatev 
1199af98b0afSStanislav Gatev   const T& value() const&;
1200af98b0afSStanislav Gatev   T& value() &;
1201af98b0afSStanislav Gatev   const T&& value() const&&;
1202af98b0afSStanislav Gatev   T&& value() &&;
1203af98b0afSStanislav Gatev 
12049e0fc676SStanislav Gatev   template <typename U>
12059e0fc676SStanislav Gatev   constexpr T value_or(U&& v) const&;
12069e0fc676SStanislav Gatev   template <typename U>
12079e0fc676SStanislav Gatev   T value_or(U&& v) &&;
12089e0fc676SStanislav Gatev 
12099e0fc676SStanislav Gatev   template <typename... Args>
12109e0fc676SStanislav Gatev   T& emplace(Args&&... args);
12119e0fc676SStanislav Gatev 
12129e0fc676SStanislav Gatev   template <typename U, typename... Args>
12139e0fc676SStanislav Gatev   T& emplace(std::initializer_list<U> ilist, Args&&... args);
12149e0fc676SStanislav Gatev 
12159e0fc676SStanislav Gatev   void reset() noexcept;
12169e0fc676SStanislav Gatev 
12179e0fc676SStanislav Gatev   constexpr explicit operator bool() const noexcept;
1218af98b0afSStanislav Gatev   constexpr bool has_value() const noexcept;
12192ddd57aeSStanislav Gatev 
12202ddd57aeSStanislav Gatev   void swap(Optional& other);
1221af98b0afSStanislav Gatev };
1222af98b0afSStanislav Gatev 
12239e0fc676SStanislav Gatev template <typename T>
12249e0fc676SStanislav Gatev constexpr Optional<typename std::decay<T>::type> make_optional(T&& v);
12259e0fc676SStanislav Gatev 
12269e0fc676SStanislav Gatev template <typename T, typename... Args>
12279e0fc676SStanislav Gatev constexpr Optional<T> make_optional(Args&&... args);
12289e0fc676SStanislav Gatev 
12299e0fc676SStanislav Gatev template <typename T, typename U, typename... Args>
12309e0fc676SStanislav Gatev constexpr Optional<T> make_optional(std::initializer_list<U> il,
12319e0fc676SStanislav Gatev                                     Args&&... args);
12329e0fc676SStanislav Gatev 
1233390029beSYitzhak Mandelbaum template <typename T, typename U>
1234390029beSYitzhak Mandelbaum constexpr bool operator==(const Optional<T> &lhs, const Optional<U> &rhs);
1235390029beSYitzhak Mandelbaum template <typename T, typename U>
1236390029beSYitzhak Mandelbaum constexpr bool operator!=(const Optional<T> &lhs, const Optional<U> &rhs);
1237390029beSYitzhak Mandelbaum 
1238390029beSYitzhak Mandelbaum template <typename T>
1239390029beSYitzhak Mandelbaum constexpr bool operator==(const Optional<T> &opt, nullopt_t);
1240390029beSYitzhak Mandelbaum template <typename T>
1241390029beSYitzhak Mandelbaum constexpr bool operator==(nullopt_t, const Optional<T> &opt);
1242390029beSYitzhak Mandelbaum template <typename T>
1243390029beSYitzhak Mandelbaum constexpr bool operator!=(const Optional<T> &opt, nullopt_t);
1244390029beSYitzhak Mandelbaum template <typename T>
1245390029beSYitzhak Mandelbaum constexpr bool operator!=(nullopt_t, const Optional<T> &opt);
1246390029beSYitzhak Mandelbaum 
1247390029beSYitzhak Mandelbaum template <typename T, typename U>
1248390029beSYitzhak Mandelbaum constexpr bool operator==(const Optional<T> &opt, const U &value);
1249390029beSYitzhak Mandelbaum template <typename T, typename U>
1250390029beSYitzhak Mandelbaum constexpr bool operator==(const T &value, const Optional<U> &opt);
1251390029beSYitzhak Mandelbaum template <typename T, typename U>
1252390029beSYitzhak Mandelbaum constexpr bool operator!=(const Optional<T> &opt, const U &value);
1253390029beSYitzhak Mandelbaum template <typename T, typename U>
1254390029beSYitzhak Mandelbaum constexpr bool operator!=(const T &value, const Optional<U> &opt);
1255390029beSYitzhak Mandelbaum 
1256af98b0afSStanislav Gatev } // namespace base
1257af98b0afSStanislav Gatev )";
1258af98b0afSStanislav Gatev 
1259af98b0afSStanislav Gatev /// Replaces all occurrences of `Pattern` in `S` with `Replacement`.
1260af98b0afSStanislav Gatev static void ReplaceAllOccurrences(std::string &S, const std::string &Pattern,
1261af98b0afSStanislav Gatev                                   const std::string &Replacement) {
1262af98b0afSStanislav Gatev   size_t Pos = 0;
1263af98b0afSStanislav Gatev   while (true) {
1264af98b0afSStanislav Gatev     Pos = S.find(Pattern, Pos);
1265af98b0afSStanislav Gatev     if (Pos == std::string::npos)
1266af98b0afSStanislav Gatev       break;
1267af98b0afSStanislav Gatev     S.replace(Pos, Pattern.size(), Replacement);
1268af98b0afSStanislav Gatev   }
1269af98b0afSStanislav Gatev }
1270af98b0afSStanislav Gatev 
1271af98b0afSStanislav Gatev struct OptionalTypeIdentifier {
1272af98b0afSStanislav Gatev   std::string NamespaceName;
1273af98b0afSStanislav Gatev   std::string TypeName;
1274af98b0afSStanislav Gatev };
1275af98b0afSStanislav Gatev 
1276477ee05fSMartin Braenne static raw_ostream &operator<<(raw_ostream &OS,
1277477ee05fSMartin Braenne                                const OptionalTypeIdentifier &TypeId) {
1278477ee05fSMartin Braenne   OS << TypeId.NamespaceName << "::" << TypeId.TypeName;
1279477ee05fSMartin Braenne   return OS;
1280477ee05fSMartin Braenne }
1281477ee05fSMartin Braenne 
1282af98b0afSStanislav Gatev class UncheckedOptionalAccessTest
1283af98b0afSStanislav Gatev     : public ::testing::TestWithParam<OptionalTypeIdentifier> {
1284af98b0afSStanislav Gatev protected:
128558fe7f96SSam Estep   void ExpectDiagnosticsFor(std::string SourceCode,
128666bbbf2eSJan Voung                             bool IgnoreSmartPointerDereference = true) {
128766bbbf2eSJan Voung     ExpectDiagnosticsFor(SourceCode, ast_matchers::hasName("target"),
128866bbbf2eSJan Voung                          IgnoreSmartPointerDereference);
128966bbbf2eSJan Voung   }
129066bbbf2eSJan Voung 
129166bbbf2eSJan Voung   void ExpectDiagnosticsForLambda(std::string SourceCode,
129266bbbf2eSJan Voung                                   bool IgnoreSmartPointerDereference = true) {
129366bbbf2eSJan Voung     ExpectDiagnosticsFor(
129466bbbf2eSJan Voung         SourceCode,
129566bbbf2eSJan Voung         ast_matchers::hasDeclContext(
129666bbbf2eSJan Voung             ast_matchers::cxxRecordDecl(ast_matchers::isLambda())),
129766bbbf2eSJan Voung         IgnoreSmartPointerDereference);
1298a446c9bfSmartinboehme   }
1299a446c9bfSmartinboehme 
1300a446c9bfSmartinboehme   template <typename FuncDeclMatcher>
1301a446c9bfSmartinboehme   void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher,
130266bbbf2eSJan Voung                             bool IgnoreSmartPointerDereference = true) {
130366bbbf2eSJan Voung     // Run in C++17 and C++20 mode to cover differences in the AST between modes
130466bbbf2eSJan Voung     // (e.g. C++20 can contain `CXXRewrittenBinaryOperator`).
130566bbbf2eSJan Voung     for (const char *CxxMode : {"-std=c++17", "-std=c++20"})
130666bbbf2eSJan Voung       ExpectDiagnosticsFor(SourceCode, FuncMatcher, CxxMode,
130766bbbf2eSJan Voung                            IgnoreSmartPointerDereference);
130866bbbf2eSJan Voung   }
130966bbbf2eSJan Voung 
131066bbbf2eSJan Voung   template <typename FuncDeclMatcher>
131166bbbf2eSJan Voung   void ExpectDiagnosticsFor(std::string SourceCode, FuncDeclMatcher FuncMatcher,
131266bbbf2eSJan Voung                             const char *CxxMode,
131366bbbf2eSJan Voung                             bool IgnoreSmartPointerDereference) {
1314af98b0afSStanislav Gatev     ReplaceAllOccurrences(SourceCode, "$ns", GetParam().NamespaceName);
1315af98b0afSStanislav Gatev     ReplaceAllOccurrences(SourceCode, "$optional", GetParam().TypeName);
1316af98b0afSStanislav Gatev 
1317af98b0afSStanislav Gatev     std::vector<std::pair<std::string, std::string>> Headers;
1318b000b770SStanislav Gatev     Headers.emplace_back("cstddef.h", CSDtdDefHeader);
13199e0fc676SStanislav Gatev     Headers.emplace_back("std_initializer_list.h", StdInitializerListHeader);
13207f076004SYitzhak Mandelbaum     Headers.emplace_back("std_string.h", StdStringHeader);
1321af98b0afSStanislav Gatev     Headers.emplace_back("std_type_traits.h", StdTypeTraitsHeader);
1322af98b0afSStanislav Gatev     Headers.emplace_back("std_utility.h", StdUtilityHeader);
1323af98b0afSStanislav Gatev     Headers.emplace_back("std_optional.h", StdOptionalHeader);
1324092a530cSStanislav Gatev     Headers.emplace_back("absl_type_traits.h", AbslTypeTraitsHeader);
1325af98b0afSStanislav Gatev     Headers.emplace_back("absl_optional.h", AbslOptionalHeader);
1326af98b0afSStanislav Gatev     Headers.emplace_back("base_optional.h", BaseOptionalHeader);
1327af98b0afSStanislav Gatev     Headers.emplace_back("unchecked_optional_access_test.h", R"(
1328af98b0afSStanislav Gatev       #include "absl_optional.h"
1329af98b0afSStanislav Gatev       #include "base_optional.h"
13309e0fc676SStanislav Gatev       #include "std_initializer_list.h"
1331af98b0afSStanislav Gatev       #include "std_optional.h"
13327f076004SYitzhak Mandelbaum       #include "std_string.h"
1333af98b0afSStanislav Gatev       #include "std_utility.h"
13349e0fc676SStanislav Gatev 
13359e0fc676SStanislav Gatev       template <typename T>
13369e0fc676SStanislav Gatev       T Make();
1337af98b0afSStanislav Gatev     )");
133866bbbf2eSJan Voung     UncheckedOptionalAccessModelOptions Options{IgnoreSmartPointerDereference};
133958fe7f96SSam Estep     std::vector<SourceLocation> Diagnostics;
1340af98b0afSStanislav Gatev     llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
1341db898d43SWei Yi Tee         AnalysisInputs<UncheckedOptionalAccessModel>(
1342db898d43SWei Yi Tee             SourceCode, std::move(FuncMatcher),
134371f2ec2dSmartinboehme             [](ASTContext &Ctx, Environment &Env) {
134471f2ec2dSmartinboehme               return UncheckedOptionalAccessModel(Ctx, Env);
1345db898d43SWei Yi Tee             })
1346cfd20214Smartinboehme             .withDiagnosisCallbacks(
1347cfd20214Smartinboehme                 {/*Before=*/[&Diagnostics,
1348cfd20214Smartinboehme                              Diagnoser =
1349cfd20214Smartinboehme                                  UncheckedOptionalAccessDiagnoser(Options)](
1350db898d43SWei Yi Tee                                 ASTContext &Ctx, const CFGElement &Elt,
13516761b24aSJan Voung                                 const TransferStateForDiagnostics<
13526761b24aSJan Voung                                     UncheckedOptionalAccessLattice>
135382d50fefSDani Ferreira Franco Moura                                     &State) mutable {
1354e9570d1eSYitzhak Mandelbaum                    auto EltDiagnostics = Diagnoser(Elt, Ctx, State);
13557538b360SWei Yi Tee                    llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
1356cfd20214Smartinboehme                  },
1357cfd20214Smartinboehme                  /*After=*/nullptr})
1358db898d43SWei Yi Tee             .withASTBuildArgs(
1359a446c9bfSmartinboehme                 {"-fsyntax-only", CxxMode, "-Wno-undefined-inline"})
1360db898d43SWei Yi Tee             .withASTBuildVirtualMappedFiles(
1361db898d43SWei Yi Tee                 tooling::FileContentMappings(Headers.begin(), Headers.end())),
1362db898d43SWei Yi Tee         /*VerifyResults=*/[&Diagnostics](
1363db898d43SWei Yi Tee                               const llvm::DenseMap<unsigned, std::string>
1364db898d43SWei Yi Tee                                   &Annotations,
1365db898d43SWei Yi Tee                               const AnalysisOutputs &AO) {
1366db898d43SWei Yi Tee           llvm::DenseSet<unsigned> AnnotationLines;
1367db898d43SWei Yi Tee           for (const auto &[Line, _] : Annotations) {
1368db898d43SWei Yi Tee             AnnotationLines.insert(Line);
1369db898d43SWei Yi Tee           }
1370db898d43SWei Yi Tee           auto &SrcMgr = AO.ASTCtx.getSourceManager();
137158fe7f96SSam Estep           llvm::DenseSet<unsigned> DiagnosticLines;
137258fe7f96SSam Estep           for (SourceLocation &Loc : Diagnostics) {
13738b5d3ba8SMartin Braenne             unsigned Line = SrcMgr.getPresumedLineNumber(Loc);
13748b5d3ba8SMartin Braenne             DiagnosticLines.insert(Line);
13758b5d3ba8SMartin Braenne             if (!AnnotationLines.contains(Line)) {
13768b5d3ba8SMartin Braenne               IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
13778b5d3ba8SMartin Braenne                   new DiagnosticOptions());
13788b5d3ba8SMartin Braenne               TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
13798b5d3ba8SMartin Braenne                                 DiagOpts.get());
13804dd55c56SJay Foad               TD.emitDiagnostic(FullSourceLoc(Loc, SrcMgr),
13814dd55c56SJay Foad                                 DiagnosticsEngine::Error,
13824dd55c56SJay Foad                                 "unexpected diagnostic", {}, {});
13838b5d3ba8SMartin Braenne             }
138458fe7f96SSam Estep           }
138558fe7f96SSam Estep 
138658fe7f96SSam Estep           EXPECT_THAT(DiagnosticLines, ContainerEq(AnnotationLines));
1387db898d43SWei Yi Tee         });
1388af98b0afSStanislav Gatev     if (Error)
1389af98b0afSStanislav Gatev       FAIL() << llvm::toString(std::move(Error));
1390af98b0afSStanislav Gatev   }
1391af98b0afSStanislav Gatev };
1392af98b0afSStanislav Gatev 
1393af98b0afSStanislav Gatev INSTANTIATE_TEST_SUITE_P(
1394af98b0afSStanislav Gatev     UncheckedOptionalUseTestInst, UncheckedOptionalAccessTest,
1395af98b0afSStanislav Gatev     ::testing::Values(OptionalTypeIdentifier{"std", "optional"},
1396af98b0afSStanislav Gatev                       OptionalTypeIdentifier{"absl", "optional"},
1397af98b0afSStanislav Gatev                       OptionalTypeIdentifier{"base", "Optional"}),
1398af98b0afSStanislav Gatev     [](const ::testing::TestParamInfo<OptionalTypeIdentifier> &Info) {
1399af98b0afSStanislav Gatev       return Info.param.NamespaceName;
1400af98b0afSStanislav Gatev     });
1401af98b0afSStanislav Gatev 
1402cd22e0dcSYitzhak Mandelbaum // Verifies that similarly-named types are ignored.
1403cd22e0dcSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, NonTrackedOptionalType) {
1404cd22e0dcSYitzhak Mandelbaum   ExpectDiagnosticsFor(
1405cd22e0dcSYitzhak Mandelbaum       R"(
1406cd22e0dcSYitzhak Mandelbaum     namespace other {
1407cd22e0dcSYitzhak Mandelbaum     namespace $ns {
1408cd22e0dcSYitzhak Mandelbaum     template <typename T>
1409cd22e0dcSYitzhak Mandelbaum     struct $optional {
1410cd22e0dcSYitzhak Mandelbaum       T value();
1411cd22e0dcSYitzhak Mandelbaum     };
1412cd22e0dcSYitzhak Mandelbaum     }
1413cd22e0dcSYitzhak Mandelbaum 
1414cd22e0dcSYitzhak Mandelbaum     void target($ns::$optional<int> opt) {
1415cd22e0dcSYitzhak Mandelbaum       opt.value();
1416cd22e0dcSYitzhak Mandelbaum     }
1417cd22e0dcSYitzhak Mandelbaum     }
1418cd22e0dcSYitzhak Mandelbaum   )");
1419cd22e0dcSYitzhak Mandelbaum }
1420cd22e0dcSYitzhak Mandelbaum 
1421af98b0afSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, EmptyFunctionBody) {
142258fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1423af98b0afSStanislav Gatev     void target() {
1424af98b0afSStanislav Gatev       (void)0;
1425af98b0afSStanislav Gatev     }
142658fe7f96SSam Estep   )");
1427af98b0afSStanislav Gatev }
1428af98b0afSStanislav Gatev 
1429af98b0afSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, UnwrapUsingValueNoCheck) {
143058fe7f96SSam Estep   ExpectDiagnosticsFor(
1431af98b0afSStanislav Gatev       R"(
1432af98b0afSStanislav Gatev     #include "unchecked_optional_access_test.h"
1433af98b0afSStanislav Gatev 
1434af98b0afSStanislav Gatev     void target($ns::$optional<int> opt) {
143558fe7f96SSam Estep       opt.value(); // [[unsafe]]
1436af98b0afSStanislav Gatev     }
143758fe7f96SSam Estep   )");
1438af98b0afSStanislav Gatev 
143958fe7f96SSam Estep   ExpectDiagnosticsFor(
1440af98b0afSStanislav Gatev       R"(
1441af98b0afSStanislav Gatev     #include "unchecked_optional_access_test.h"
1442af98b0afSStanislav Gatev 
1443af98b0afSStanislav Gatev     void target($ns::$optional<int> opt) {
144458fe7f96SSam Estep       std::move(opt).value(); // [[unsafe]]
1445af98b0afSStanislav Gatev     }
144658fe7f96SSam Estep   )");
1447af98b0afSStanislav Gatev }
1448af98b0afSStanislav Gatev 
1449af98b0afSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorStarNoCheck) {
145058fe7f96SSam Estep   ExpectDiagnosticsFor(
1451af98b0afSStanislav Gatev       R"(
1452af98b0afSStanislav Gatev     #include "unchecked_optional_access_test.h"
1453af98b0afSStanislav Gatev 
1454af98b0afSStanislav Gatev     void target($ns::$optional<int> opt) {
145558fe7f96SSam Estep       *opt; // [[unsafe]]
1456af98b0afSStanislav Gatev     }
145758fe7f96SSam Estep   )");
1458af98b0afSStanislav Gatev 
145958fe7f96SSam Estep   ExpectDiagnosticsFor(
1460af98b0afSStanislav Gatev       R"(
1461af98b0afSStanislav Gatev     #include "unchecked_optional_access_test.h"
1462af98b0afSStanislav Gatev 
1463af98b0afSStanislav Gatev     void target($ns::$optional<int> opt) {
146458fe7f96SSam Estep       *std::move(opt); // [[unsafe]]
1465af98b0afSStanislav Gatev     }
146658fe7f96SSam Estep   )");
1467af98b0afSStanislav Gatev }
1468af98b0afSStanislav Gatev 
1469af98b0afSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, UnwrapUsingOperatorArrowNoCheck) {
147058fe7f96SSam Estep   ExpectDiagnosticsFor(
1471af98b0afSStanislav Gatev       R"(
1472af98b0afSStanislav Gatev     #include "unchecked_optional_access_test.h"
1473af98b0afSStanislav Gatev 
1474af98b0afSStanislav Gatev     struct Foo {
1475af98b0afSStanislav Gatev       void foo();
1476af98b0afSStanislav Gatev     };
1477af98b0afSStanislav Gatev 
1478af98b0afSStanislav Gatev     void target($ns::$optional<Foo> opt) {
147958fe7f96SSam Estep       opt->foo(); // [[unsafe]]
1480af98b0afSStanislav Gatev     }
148158fe7f96SSam Estep   )");
1482af98b0afSStanislav Gatev 
148358fe7f96SSam Estep   ExpectDiagnosticsFor(
1484af98b0afSStanislav Gatev       R"(
1485af98b0afSStanislav Gatev     #include "unchecked_optional_access_test.h"
1486af98b0afSStanislav Gatev 
1487af98b0afSStanislav Gatev     struct Foo {
1488af98b0afSStanislav Gatev       void foo();
1489af98b0afSStanislav Gatev     };
1490af98b0afSStanislav Gatev 
1491af98b0afSStanislav Gatev     void target($ns::$optional<Foo> opt) {
149258fe7f96SSam Estep       std::move(opt)->foo(); // [[unsafe]]
1493af98b0afSStanislav Gatev     }
149458fe7f96SSam Estep   )");
1495af98b0afSStanislav Gatev }
1496af98b0afSStanislav Gatev 
14979e0fc676SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, HasValueCheck) {
149858fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1499af98b0afSStanislav Gatev     #include "unchecked_optional_access_test.h"
1500af98b0afSStanislav Gatev 
1501af98b0afSStanislav Gatev     void target($ns::$optional<int> opt) {
1502af98b0afSStanislav Gatev       if (opt.has_value()) {
1503af98b0afSStanislav Gatev         opt.value();
1504af98b0afSStanislav Gatev       }
1505af98b0afSStanislav Gatev     }
150658fe7f96SSam Estep   )");
1507af98b0afSStanislav Gatev }
1508af98b0afSStanislav Gatev 
15099e0fc676SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, OperatorBoolCheck) {
151058fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
15119e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
15129e0fc676SStanislav Gatev 
15139e0fc676SStanislav Gatev     void target($ns::$optional<int> opt) {
15149e0fc676SStanislav Gatev       if (opt) {
15159e0fc676SStanislav Gatev         opt.value();
15169e0fc676SStanislav Gatev       }
15179e0fc676SStanislav Gatev     }
151858fe7f96SSam Estep   )");
15199e0fc676SStanislav Gatev }
15209e0fc676SStanislav Gatev 
15219e0fc676SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, UnwrapFunctionCallResultNoCheck) {
152258fe7f96SSam Estep   ExpectDiagnosticsFor(
15239e0fc676SStanislav Gatev       R"(
15249e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
15259e0fc676SStanislav Gatev 
15269e0fc676SStanislav Gatev     void target() {
152758fe7f96SSam Estep       Make<$ns::$optional<int>>().value(); // [[unsafe]]
15289e0fc676SStanislav Gatev       (void)0;
15299e0fc676SStanislav Gatev     }
153058fe7f96SSam Estep   )");
15319e0fc676SStanislav Gatev 
153258fe7f96SSam Estep   ExpectDiagnosticsFor(
15339e0fc676SStanislav Gatev       R"(
15349e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
15359e0fc676SStanislav Gatev 
15369e0fc676SStanislav Gatev     void target($ns::$optional<int> opt) {
153758fe7f96SSam Estep       std::move(opt).value(); // [[unsafe]]
15389e0fc676SStanislav Gatev     }
153958fe7f96SSam Estep   )");
15409e0fc676SStanislav Gatev }
15419e0fc676SStanislav Gatev 
15429e0fc676SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, DefaultConstructor) {
154358fe7f96SSam Estep   ExpectDiagnosticsFor(
15449e0fc676SStanislav Gatev       R"(
15459e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
15469e0fc676SStanislav Gatev 
15479e0fc676SStanislav Gatev     void target() {
15489e0fc676SStanislav Gatev       $ns::$optional<int> opt;
154958fe7f96SSam Estep       opt.value(); // [[unsafe]]
15509e0fc676SStanislav Gatev     }
155158fe7f96SSam Estep   )");
15529e0fc676SStanislav Gatev }
15539e0fc676SStanislav Gatev 
1554092a530cSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, NulloptConstructor) {
155558fe7f96SSam Estep   ExpectDiagnosticsFor(
1556092a530cSStanislav Gatev       R"(
1557092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1558092a530cSStanislav Gatev 
1559092a530cSStanislav Gatev     void target() {
1560092a530cSStanislav Gatev       $ns::$optional<int> opt($ns::nullopt);
156158fe7f96SSam Estep       opt.value(); // [[unsafe]]
1562092a530cSStanislav Gatev     }
156358fe7f96SSam Estep   )");
1564092a530cSStanislav Gatev }
1565092a530cSStanislav Gatev 
15660086a355SYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, NulloptConstructorWithSugaredType) {
15670086a355SYitzhak Mandelbaum   ExpectDiagnosticsFor(
15680086a355SYitzhak Mandelbaum       R"(
15690086a355SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
15700086a355SYitzhak Mandelbaum     template <typename T>
15710086a355SYitzhak Mandelbaum     using wrapper = T;
15720086a355SYitzhak Mandelbaum 
15730086a355SYitzhak Mandelbaum     template <typename T>
15740086a355SYitzhak Mandelbaum     wrapper<T> wrap(T);
15750086a355SYitzhak Mandelbaum 
15760086a355SYitzhak Mandelbaum     void target() {
15770086a355SYitzhak Mandelbaum       $ns::$optional<int> opt(wrap($ns::nullopt));
15780086a355SYitzhak Mandelbaum       opt.value(); // [[unsafe]]
15790086a355SYitzhak Mandelbaum     }
15800086a355SYitzhak Mandelbaum   )");
15810086a355SYitzhak Mandelbaum }
15820086a355SYitzhak Mandelbaum 
1583092a530cSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, InPlaceConstructor) {
158458fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1585092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1586092a530cSStanislav Gatev 
1587092a530cSStanislav Gatev     void target() {
1588092a530cSStanislav Gatev       $ns::$optional<int> opt($ns::in_place, 3);
1589092a530cSStanislav Gatev       opt.value();
1590092a530cSStanislav Gatev     }
159158fe7f96SSam Estep   )");
1592092a530cSStanislav Gatev 
159358fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1594092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1595092a530cSStanislav Gatev 
1596092a530cSStanislav Gatev     struct Foo {};
1597092a530cSStanislav Gatev 
1598092a530cSStanislav Gatev     void target() {
1599092a530cSStanislav Gatev       $ns::$optional<Foo> opt($ns::in_place);
1600092a530cSStanislav Gatev       opt.value();
1601092a530cSStanislav Gatev     }
160258fe7f96SSam Estep   )");
1603092a530cSStanislav Gatev 
160458fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1605092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1606092a530cSStanislav Gatev 
1607092a530cSStanislav Gatev     struct Foo {
1608092a530cSStanislav Gatev       explicit Foo(int, bool);
1609092a530cSStanislav Gatev     };
1610092a530cSStanislav Gatev 
1611092a530cSStanislav Gatev     void target() {
1612092a530cSStanislav Gatev       $ns::$optional<Foo> opt($ns::in_place, 3, false);
1613092a530cSStanislav Gatev       opt.value();
1614092a530cSStanislav Gatev     }
161558fe7f96SSam Estep   )");
1616092a530cSStanislav Gatev 
161758fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1618092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1619092a530cSStanislav Gatev 
1620092a530cSStanislav Gatev     struct Foo {
1621092a530cSStanislav Gatev       explicit Foo(std::initializer_list<int>);
1622092a530cSStanislav Gatev     };
1623092a530cSStanislav Gatev 
1624092a530cSStanislav Gatev     void target() {
1625092a530cSStanislav Gatev       $ns::$optional<Foo> opt($ns::in_place, {3});
1626092a530cSStanislav Gatev       opt.value();
1627092a530cSStanislav Gatev     }
162858fe7f96SSam Estep   )");
1629092a530cSStanislav Gatev }
1630092a530cSStanislav Gatev 
1631092a530cSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, ValueConstructor) {
163258fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1633092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1634092a530cSStanislav Gatev 
1635092a530cSStanislav Gatev     void target() {
1636092a530cSStanislav Gatev       $ns::$optional<int> opt(21);
1637092a530cSStanislav Gatev       opt.value();
1638092a530cSStanislav Gatev     }
163958fe7f96SSam Estep   )");
1640092a530cSStanislav Gatev 
164158fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1642092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1643092a530cSStanislav Gatev 
1644092a530cSStanislav Gatev     void target() {
1645092a530cSStanislav Gatev       $ns::$optional<int> opt = $ns::$optional<int>(21);
1646092a530cSStanislav Gatev       opt.value();
1647092a530cSStanislav Gatev     }
164858fe7f96SSam Estep   )");
164958fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1650092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1651092a530cSStanislav Gatev 
1652092a530cSStanislav Gatev     void target() {
1653092a530cSStanislav Gatev       $ns::$optional<$ns::$optional<int>> opt(Make<$ns::$optional<int>>());
1654092a530cSStanislav Gatev       opt.value();
1655092a530cSStanislav Gatev     }
165658fe7f96SSam Estep   )");
1657092a530cSStanislav Gatev 
165858fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1659092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1660092a530cSStanislav Gatev 
1661092a530cSStanislav Gatev     struct MyString {
1662092a530cSStanislav Gatev       MyString(const char*);
1663092a530cSStanislav Gatev     };
1664092a530cSStanislav Gatev 
1665092a530cSStanislav Gatev     void target() {
1666092a530cSStanislav Gatev       $ns::$optional<MyString> opt("foo");
1667092a530cSStanislav Gatev       opt.value();
1668092a530cSStanislav Gatev     }
166958fe7f96SSam Estep   )");
1670092a530cSStanislav Gatev 
167158fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1672092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1673092a530cSStanislav Gatev 
1674092a530cSStanislav Gatev     struct Foo {};
1675092a530cSStanislav Gatev 
1676092a530cSStanislav Gatev     struct Bar {
1677092a530cSStanislav Gatev       Bar(const Foo&);
1678092a530cSStanislav Gatev     };
1679092a530cSStanislav Gatev 
1680092a530cSStanislav Gatev     void target() {
1681092a530cSStanislav Gatev       $ns::$optional<Bar> opt(Make<Foo>());
1682092a530cSStanislav Gatev       opt.value();
1683092a530cSStanislav Gatev     }
168458fe7f96SSam Estep   )");
1685092a530cSStanislav Gatev 
168658fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1687092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1688092a530cSStanislav Gatev 
1689092a530cSStanislav Gatev     struct Foo {
1690092a530cSStanislav Gatev       explicit Foo(int);
1691092a530cSStanislav Gatev     };
1692092a530cSStanislav Gatev 
1693092a530cSStanislav Gatev     void target() {
1694092a530cSStanislav Gatev       $ns::$optional<Foo> opt(3);
1695092a530cSStanislav Gatev       opt.value();
1696092a530cSStanislav Gatev     }
169758fe7f96SSam Estep   )");
1698092a530cSStanislav Gatev }
1699092a530cSStanislav Gatev 
1700092a530cSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, ConvertibleOptionalConstructor) {
170158fe7f96SSam Estep   ExpectDiagnosticsFor(
1702092a530cSStanislav Gatev       R"(
1703092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1704092a530cSStanislav Gatev 
1705092a530cSStanislav Gatev     struct Foo {};
1706092a530cSStanislav Gatev 
1707092a530cSStanislav Gatev     struct Bar {
1708092a530cSStanislav Gatev       Bar(const Foo&);
1709092a530cSStanislav Gatev     };
1710092a530cSStanislav Gatev 
1711092a530cSStanislav Gatev     void target() {
1712092a530cSStanislav Gatev       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
171358fe7f96SSam Estep       opt.value(); // [[unsafe]]
1714092a530cSStanislav Gatev     }
171558fe7f96SSam Estep   )");
1716092a530cSStanislav Gatev 
171758fe7f96SSam Estep   ExpectDiagnosticsFor(
1718092a530cSStanislav Gatev       R"(
1719092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1720092a530cSStanislav Gatev 
1721092a530cSStanislav Gatev     struct Foo {};
1722092a530cSStanislav Gatev 
1723092a530cSStanislav Gatev     struct Bar {
1724092a530cSStanislav Gatev       explicit Bar(const Foo&);
1725092a530cSStanislav Gatev     };
1726092a530cSStanislav Gatev 
1727092a530cSStanislav Gatev     void target() {
1728092a530cSStanislav Gatev       $ns::$optional<Bar> opt(Make<$ns::$optional<Foo>>());
172958fe7f96SSam Estep       opt.value(); // [[unsafe]]
1730092a530cSStanislav Gatev     }
173158fe7f96SSam Estep   )");
1732092a530cSStanislav Gatev 
173358fe7f96SSam Estep   ExpectDiagnosticsFor(
1734092a530cSStanislav Gatev       R"(
1735092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1736092a530cSStanislav Gatev 
1737092a530cSStanislav Gatev     struct Foo {};
1738092a530cSStanislav Gatev 
1739092a530cSStanislav Gatev     struct Bar {
1740092a530cSStanislav Gatev       Bar(const Foo&);
1741092a530cSStanislav Gatev     };
1742092a530cSStanislav Gatev 
1743092a530cSStanislav Gatev     void target() {
1744092a530cSStanislav Gatev       $ns::$optional<Foo> opt1 = $ns::nullopt;
1745092a530cSStanislav Gatev       $ns::$optional<Bar> opt2(opt1);
174658fe7f96SSam Estep       opt2.value(); // [[unsafe]]
1747092a530cSStanislav Gatev     }
174858fe7f96SSam Estep   )");
1749092a530cSStanislav Gatev 
175058fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1751092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1752092a530cSStanislav Gatev 
1753092a530cSStanislav Gatev     struct Foo {};
1754092a530cSStanislav Gatev 
1755092a530cSStanislav Gatev     struct Bar {
1756092a530cSStanislav Gatev       Bar(const Foo&);
1757092a530cSStanislav Gatev     };
1758092a530cSStanislav Gatev 
1759092a530cSStanislav Gatev     void target() {
1760092a530cSStanislav Gatev       $ns::$optional<Foo> opt1(Make<Foo>());
1761092a530cSStanislav Gatev       $ns::$optional<Bar> opt2(opt1);
1762092a530cSStanislav Gatev       opt2.value();
1763092a530cSStanislav Gatev     }
176458fe7f96SSam Estep   )");
1765092a530cSStanislav Gatev 
176658fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1767092a530cSStanislav Gatev     #include "unchecked_optional_access_test.h"
1768092a530cSStanislav Gatev 
1769092a530cSStanislav Gatev     struct Foo {};
1770092a530cSStanislav Gatev 
1771092a530cSStanislav Gatev     struct Bar {
1772092a530cSStanislav Gatev       explicit Bar(const Foo&);
1773092a530cSStanislav Gatev     };
1774092a530cSStanislav Gatev 
1775092a530cSStanislav Gatev     void target() {
1776092a530cSStanislav Gatev       $ns::$optional<Foo> opt1(Make<Foo>());
1777092a530cSStanislav Gatev       $ns::$optional<Bar> opt2(opt1);
1778092a530cSStanislav Gatev       opt2.value();
1779092a530cSStanislav Gatev     }
178058fe7f96SSam Estep   )");
1781092a530cSStanislav Gatev }
1782092a530cSStanislav Gatev 
17839e0fc676SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, MakeOptional) {
178458fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
17859e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
17869e0fc676SStanislav Gatev 
17879e0fc676SStanislav Gatev     void target() {
17889e0fc676SStanislav Gatev       $ns::$optional<int> opt = $ns::make_optional(0);
17899e0fc676SStanislav Gatev       opt.value();
17909e0fc676SStanislav Gatev     }
179158fe7f96SSam Estep   )");
17929e0fc676SStanislav Gatev 
179358fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
17949e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
17959e0fc676SStanislav Gatev 
17969e0fc676SStanislav Gatev     struct Foo {
17979e0fc676SStanislav Gatev       Foo(int, int);
17989e0fc676SStanislav Gatev     };
17999e0fc676SStanislav Gatev 
18009e0fc676SStanislav Gatev     void target() {
18019e0fc676SStanislav Gatev       $ns::$optional<Foo> opt = $ns::make_optional<Foo>(21, 22);
18029e0fc676SStanislav Gatev       opt.value();
18039e0fc676SStanislav Gatev     }
180458fe7f96SSam Estep   )");
18059e0fc676SStanislav Gatev 
180658fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
18079e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
18089e0fc676SStanislav Gatev 
18099e0fc676SStanislav Gatev     struct Foo {
18109e0fc676SStanislav Gatev       constexpr Foo(std::initializer_list<char>);
18119e0fc676SStanislav Gatev     };
18129e0fc676SStanislav Gatev 
18139e0fc676SStanislav Gatev     void target() {
18149e0fc676SStanislav Gatev       char a = 'a';
18159e0fc676SStanislav Gatev       $ns::$optional<Foo> opt = $ns::make_optional<Foo>({a});
18169e0fc676SStanislav Gatev       opt.value();
18179e0fc676SStanislav Gatev     }
181858fe7f96SSam Estep   )");
18199e0fc676SStanislav Gatev }
18209e0fc676SStanislav Gatev 
18219e0fc676SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, ValueOr) {
182258fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
18239e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
18249e0fc676SStanislav Gatev 
18259e0fc676SStanislav Gatev     void target() {
18269e0fc676SStanislav Gatev       $ns::$optional<int> opt;
18279e0fc676SStanislav Gatev       opt.value_or(0);
18289e0fc676SStanislav Gatev       (void)0;
18299e0fc676SStanislav Gatev     }
183058fe7f96SSam Estep   )");
18319e0fc676SStanislav Gatev }
18329e0fc676SStanislav Gatev 
183309b462efSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointers) {
183458fe7f96SSam Estep   ExpectDiagnosticsFor(
18357f076004SYitzhak Mandelbaum       R"code(
18367f076004SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
18377f076004SYitzhak Mandelbaum 
18387f076004SYitzhak Mandelbaum     void target($ns::$optional<int*> opt) {
18397f076004SYitzhak Mandelbaum       if (opt.value_or(nullptr) != nullptr) {
18407f076004SYitzhak Mandelbaum         opt.value();
18417f076004SYitzhak Mandelbaum       } else {
184258fe7f96SSam Estep         opt.value(); // [[unsafe]]
18437f076004SYitzhak Mandelbaum       }
18447f076004SYitzhak Mandelbaum     }
184558fe7f96SSam Estep   )code");
184609b462efSYitzhak Mandelbaum }
18477f076004SYitzhak Mandelbaum 
184809b462efSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonIntegers) {
184958fe7f96SSam Estep   ExpectDiagnosticsFor(
18507f076004SYitzhak Mandelbaum       R"code(
18517f076004SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
18527f076004SYitzhak Mandelbaum 
18537f076004SYitzhak Mandelbaum     void target($ns::$optional<int> opt) {
18547f076004SYitzhak Mandelbaum       if (opt.value_or(0) != 0) {
18557f076004SYitzhak Mandelbaum         opt.value();
18567f076004SYitzhak Mandelbaum       } else {
185758fe7f96SSam Estep         opt.value(); // [[unsafe]]
18587f076004SYitzhak Mandelbaum       }
18597f076004SYitzhak Mandelbaum     }
186058fe7f96SSam Estep   )code");
186109b462efSYitzhak Mandelbaum }
18627f076004SYitzhak Mandelbaum 
186309b462efSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonStrings) {
186458fe7f96SSam Estep   ExpectDiagnosticsFor(
18657f076004SYitzhak Mandelbaum       R"code(
18667f076004SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
18677f076004SYitzhak Mandelbaum 
18687f076004SYitzhak Mandelbaum     void target($ns::$optional<std::string> opt) {
18697f076004SYitzhak Mandelbaum       if (!opt.value_or("").empty()) {
18707f076004SYitzhak Mandelbaum         opt.value();
18717f076004SYitzhak Mandelbaum       } else {
187258fe7f96SSam Estep         opt.value(); // [[unsafe]]
18737f076004SYitzhak Mandelbaum       }
18747f076004SYitzhak Mandelbaum     }
187558fe7f96SSam Estep   )code");
18767f076004SYitzhak Mandelbaum 
187758fe7f96SSam Estep   ExpectDiagnosticsFor(
18787f076004SYitzhak Mandelbaum       R"code(
18797f076004SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
18807f076004SYitzhak Mandelbaum 
18817f076004SYitzhak Mandelbaum     void target($ns::$optional<std::string> opt) {
18827f076004SYitzhak Mandelbaum       if (opt.value_or("") != "") {
18837f076004SYitzhak Mandelbaum         opt.value();
18847f076004SYitzhak Mandelbaum       } else {
188558fe7f96SSam Estep         opt.value(); // [[unsafe]]
18867f076004SYitzhak Mandelbaum       }
18877f076004SYitzhak Mandelbaum     }
188858fe7f96SSam Estep   )code");
188909b462efSYitzhak Mandelbaum }
18907f076004SYitzhak Mandelbaum 
189109b462efSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ValueOrComparisonPointerToOptional) {
18927f076004SYitzhak Mandelbaum   // FIXME: make `opt` a parameter directly, once we ensure that all `optional`
18937f076004SYitzhak Mandelbaum   // values have a `has_value` property.
189458fe7f96SSam Estep   ExpectDiagnosticsFor(
18957f076004SYitzhak Mandelbaum       R"code(
18967f076004SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
18977f076004SYitzhak Mandelbaum 
18987f076004SYitzhak Mandelbaum     void target($ns::$optional<int> p) {
18997f076004SYitzhak Mandelbaum       $ns::$optional<int> *opt = &p;
19007f076004SYitzhak Mandelbaum       if (opt->value_or(0) != 0) {
19017f076004SYitzhak Mandelbaum         opt->value();
19027f076004SYitzhak Mandelbaum       } else {
190358fe7f96SSam Estep         opt->value(); // [[unsafe]]
19047f076004SYitzhak Mandelbaum       }
19057f076004SYitzhak Mandelbaum     }
190658fe7f96SSam Estep   )code");
19077f076004SYitzhak Mandelbaum }
19087f076004SYitzhak Mandelbaum 
19099e0fc676SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, Emplace) {
191058fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
19119e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
19129e0fc676SStanislav Gatev 
19139e0fc676SStanislav Gatev     void target() {
19149e0fc676SStanislav Gatev       $ns::$optional<int> opt;
19159e0fc676SStanislav Gatev       opt.emplace(0);
19169e0fc676SStanislav Gatev       opt.value();
19179e0fc676SStanislav Gatev     }
191858fe7f96SSam Estep   )");
19199e0fc676SStanislav Gatev 
192058fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
19219e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
19229e0fc676SStanislav Gatev 
19239e0fc676SStanislav Gatev     void target($ns::$optional<int> *opt) {
19249e0fc676SStanislav Gatev       opt->emplace(0);
19259e0fc676SStanislav Gatev       opt->value();
19269e0fc676SStanislav Gatev     }
192758fe7f96SSam Estep   )");
19289e0fc676SStanislav Gatev 
19298fcdd625SStanislav Gatev   // FIXME: Add tests that call `emplace` in conditional branches:
193058fe7f96SSam Estep   //  ExpectDiagnosticsFor(
19318fcdd625SStanislav Gatev   //      R"(
19328fcdd625SStanislav Gatev   //    #include "unchecked_optional_access_test.h"
19338fcdd625SStanislav Gatev   //
19348fcdd625SStanislav Gatev   //    void target($ns::$optional<int> opt, bool b) {
19358fcdd625SStanislav Gatev   //      if (b) {
19368fcdd625SStanislav Gatev   //        opt.emplace(0);
19378fcdd625SStanislav Gatev   //      }
19388fcdd625SStanislav Gatev   //      if (b) {
19398fcdd625SStanislav Gatev   //        opt.value();
19408fcdd625SStanislav Gatev   //      } else {
194158fe7f96SSam Estep   //        opt.value(); // [[unsafe]]
19428fcdd625SStanislav Gatev   //      }
19438fcdd625SStanislav Gatev   //    }
194458fe7f96SSam Estep   //  )");
19459e0fc676SStanislav Gatev }
19469e0fc676SStanislav Gatev 
19479e0fc676SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, Reset) {
194858fe7f96SSam Estep   ExpectDiagnosticsFor(
19499e0fc676SStanislav Gatev       R"(
19509e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
19519e0fc676SStanislav Gatev 
19529e0fc676SStanislav Gatev     void target() {
19539e0fc676SStanislav Gatev       $ns::$optional<int> opt = $ns::make_optional(0);
19549e0fc676SStanislav Gatev       opt.reset();
195558fe7f96SSam Estep       opt.value(); // [[unsafe]]
19569e0fc676SStanislav Gatev     }
195758fe7f96SSam Estep   )");
19589e0fc676SStanislav Gatev 
195958fe7f96SSam Estep   ExpectDiagnosticsFor(
19609e0fc676SStanislav Gatev       R"(
19619e0fc676SStanislav Gatev     #include "unchecked_optional_access_test.h"
19629e0fc676SStanislav Gatev 
1963092a530cSStanislav Gatev     void target($ns::$optional<int> &opt) {
1964092a530cSStanislav Gatev       if (opt.has_value()) {
1965092a530cSStanislav Gatev         opt.reset();
196658fe7f96SSam Estep         opt.value(); // [[unsafe]]
19679e0fc676SStanislav Gatev       }
1968092a530cSStanislav Gatev     }
196958fe7f96SSam Estep   )");
19709e0fc676SStanislav Gatev 
19718fcdd625SStanislav Gatev   // FIXME: Add tests that call `reset` in conditional branches:
197258fe7f96SSam Estep   //  ExpectDiagnosticsFor(
19738fcdd625SStanislav Gatev   //      R"(
19748fcdd625SStanislav Gatev   //    #include "unchecked_optional_access_test.h"
19758fcdd625SStanislav Gatev   //
19768fcdd625SStanislav Gatev   //    void target(bool b) {
19778fcdd625SStanislav Gatev   //      $ns::$optional<int> opt = $ns::make_optional(0);
19788fcdd625SStanislav Gatev   //      if (b) {
19798fcdd625SStanislav Gatev   //        opt.reset();
19808fcdd625SStanislav Gatev   //      }
19818fcdd625SStanislav Gatev   //      if (b) {
198258fe7f96SSam Estep   //        opt.value(); // [[unsafe]]
19838fcdd625SStanislav Gatev   //      } else {
19848fcdd625SStanislav Gatev   //        opt.value();
19858fcdd625SStanislav Gatev   //      }
19868fcdd625SStanislav Gatev   //    }
198758fe7f96SSam Estep   //  )");
19889e0fc676SStanislav Gatev }
19899e0fc676SStanislav Gatev 
1990b000b770SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, ValueAssignment) {
199158fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
1992b000b770SStanislav Gatev     #include "unchecked_optional_access_test.h"
1993b000b770SStanislav Gatev 
1994b000b770SStanislav Gatev     struct Foo {};
1995b000b770SStanislav Gatev 
1996b000b770SStanislav Gatev     void target() {
1997b000b770SStanislav Gatev       $ns::$optional<Foo> opt;
1998b000b770SStanislav Gatev       opt = Foo();
1999b000b770SStanislav Gatev       opt.value();
2000b000b770SStanislav Gatev     }
200158fe7f96SSam Estep   )");
2002b000b770SStanislav Gatev 
200358fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
2004b000b770SStanislav Gatev     #include "unchecked_optional_access_test.h"
2005b000b770SStanislav Gatev 
2006b000b770SStanislav Gatev     struct Foo {};
2007b000b770SStanislav Gatev 
2008b000b770SStanislav Gatev     void target() {
2009b000b770SStanislav Gatev       $ns::$optional<Foo> opt;
2010b000b770SStanislav Gatev       (opt = Foo()).value();
2011b000b770SStanislav Gatev       (void)0;
2012b000b770SStanislav Gatev     }
201358fe7f96SSam Estep   )");
2014b000b770SStanislav Gatev 
201558fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
2016b000b770SStanislav Gatev     #include "unchecked_optional_access_test.h"
2017b000b770SStanislav Gatev 
2018b000b770SStanislav Gatev     struct MyString {
2019b000b770SStanislav Gatev       MyString(const char*);
2020b000b770SStanislav Gatev     };
2021b000b770SStanislav Gatev 
2022b000b770SStanislav Gatev     void target() {
2023b000b770SStanislav Gatev       $ns::$optional<MyString> opt;
2024b000b770SStanislav Gatev       opt = "foo";
2025b000b770SStanislav Gatev       opt.value();
2026b000b770SStanislav Gatev     }
202758fe7f96SSam Estep   )");
2028b000b770SStanislav Gatev 
202958fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
2030b000b770SStanislav Gatev     #include "unchecked_optional_access_test.h"
2031b000b770SStanislav Gatev 
2032b000b770SStanislav Gatev     struct MyString {
2033b000b770SStanislav Gatev       MyString(const char*);
2034b000b770SStanislav Gatev     };
2035b000b770SStanislav Gatev 
2036b000b770SStanislav Gatev     void target() {
2037b000b770SStanislav Gatev       $ns::$optional<MyString> opt;
2038b000b770SStanislav Gatev       (opt = "foo").value();
2039b000b770SStanislav Gatev     }
204058fe7f96SSam Estep   )");
2041b000b770SStanislav Gatev }
2042b000b770SStanislav Gatev 
2043b000b770SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, OptionalConversionAssignment) {
204458fe7f96SSam Estep   ExpectDiagnosticsFor(
2045b000b770SStanislav Gatev       R"(
2046b000b770SStanislav Gatev     #include "unchecked_optional_access_test.h"
2047b000b770SStanislav Gatev 
2048b000b770SStanislav Gatev     struct Foo {};
2049b000b770SStanislav Gatev 
2050b000b770SStanislav Gatev     struct Bar {
2051b000b770SStanislav Gatev       Bar(const Foo&);
2052b000b770SStanislav Gatev     };
2053b000b770SStanislav Gatev 
2054b000b770SStanislav Gatev     void target() {
2055b000b770SStanislav Gatev       $ns::$optional<Foo> opt1 = Foo();
2056b000b770SStanislav Gatev       $ns::$optional<Bar> opt2;
2057b000b770SStanislav Gatev       opt2 = opt1;
2058b000b770SStanislav Gatev       opt2.value();
2059b000b770SStanislav Gatev     }
206058fe7f96SSam Estep   )");
2061b000b770SStanislav Gatev 
206258fe7f96SSam Estep   ExpectDiagnosticsFor(
2063b000b770SStanislav Gatev       R"(
2064b000b770SStanislav Gatev     #include "unchecked_optional_access_test.h"
2065b000b770SStanislav Gatev 
2066b000b770SStanislav Gatev     struct Foo {};
2067b000b770SStanislav Gatev 
2068b000b770SStanislav Gatev     struct Bar {
2069b000b770SStanislav Gatev       Bar(const Foo&);
2070b000b770SStanislav Gatev     };
2071b000b770SStanislav Gatev 
2072b000b770SStanislav Gatev     void target() {
2073b000b770SStanislav Gatev       $ns::$optional<Foo> opt1;
2074b000b770SStanislav Gatev       $ns::$optional<Bar> opt2;
2075b000b770SStanislav Gatev       if (opt2.has_value()) {
2076b000b770SStanislav Gatev         opt2 = opt1;
207758fe7f96SSam Estep         opt2.value(); // [[unsafe]]
2078b000b770SStanislav Gatev       }
2079b000b770SStanislav Gatev     }
208058fe7f96SSam Estep   )");
2081b000b770SStanislav Gatev 
208258fe7f96SSam Estep   ExpectDiagnosticsFor(
2083b000b770SStanislav Gatev       R"(
2084b000b770SStanislav Gatev     #include "unchecked_optional_access_test.h"
2085b000b770SStanislav Gatev 
2086b000b770SStanislav Gatev     struct Foo {};
2087b000b770SStanislav Gatev 
2088b000b770SStanislav Gatev     struct Bar {
2089b000b770SStanislav Gatev       Bar(const Foo&);
2090b000b770SStanislav Gatev     };
2091b000b770SStanislav Gatev 
2092b000b770SStanislav Gatev     void target() {
2093b000b770SStanislav Gatev       $ns::$optional<Foo> opt1 = Foo();
2094b000b770SStanislav Gatev       $ns::$optional<Bar> opt2;
2095b000b770SStanislav Gatev       (opt2 = opt1).value();
2096b000b770SStanislav Gatev       (void)0;
2097b000b770SStanislav Gatev     }
209858fe7f96SSam Estep   )");
2099b000b770SStanislav Gatev }
2100b000b770SStanislav Gatev 
2101b000b770SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, NulloptAssignment) {
210258fe7f96SSam Estep   ExpectDiagnosticsFor(
2103b000b770SStanislav Gatev       R"(
2104b000b770SStanislav Gatev     #include "unchecked_optional_access_test.h"
2105b000b770SStanislav Gatev 
2106b000b770SStanislav Gatev     void target() {
2107b000b770SStanislav Gatev       $ns::$optional<int> opt = 3;
2108b000b770SStanislav Gatev       opt = $ns::nullopt;
210958fe7f96SSam Estep       opt.value(); // [[unsafe]]
2110b000b770SStanislav Gatev     }
211158fe7f96SSam Estep   )");
2112b000b770SStanislav Gatev 
211358fe7f96SSam Estep   ExpectDiagnosticsFor(
2114b000b770SStanislav Gatev       R"(
2115b000b770SStanislav Gatev     #include "unchecked_optional_access_test.h"
2116b000b770SStanislav Gatev 
2117b000b770SStanislav Gatev     void target() {
2118b000b770SStanislav Gatev       $ns::$optional<int> opt = 3;
211958fe7f96SSam Estep       (opt = $ns::nullopt).value(); // [[unsafe]]
2120b000b770SStanislav Gatev     }
212158fe7f96SSam Estep   )");
2122b000b770SStanislav Gatev }
2123b000b770SStanislav Gatev 
21242ddd57aeSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, OptionalSwap) {
212558fe7f96SSam Estep   ExpectDiagnosticsFor(
21262ddd57aeSStanislav Gatev       R"(
21272ddd57aeSStanislav Gatev     #include "unchecked_optional_access_test.h"
21282ddd57aeSStanislav Gatev 
21292ddd57aeSStanislav Gatev     void target() {
21302ddd57aeSStanislav Gatev       $ns::$optional<int> opt1 = $ns::nullopt;
21312ddd57aeSStanislav Gatev       $ns::$optional<int> opt2 = 3;
21322ddd57aeSStanislav Gatev 
21332ddd57aeSStanislav Gatev       opt1.swap(opt2);
21342ddd57aeSStanislav Gatev 
21352ddd57aeSStanislav Gatev       opt1.value();
21362ddd57aeSStanislav Gatev 
213758fe7f96SSam Estep       opt2.value(); // [[unsafe]]
21382ddd57aeSStanislav Gatev     }
213958fe7f96SSam Estep   )");
21402ddd57aeSStanislav Gatev 
214158fe7f96SSam Estep   ExpectDiagnosticsFor(
21422ddd57aeSStanislav Gatev       R"(
21432ddd57aeSStanislav Gatev     #include "unchecked_optional_access_test.h"
21442ddd57aeSStanislav Gatev 
21452ddd57aeSStanislav Gatev     void target() {
21462ddd57aeSStanislav Gatev       $ns::$optional<int> opt1 = $ns::nullopt;
21472ddd57aeSStanislav Gatev       $ns::$optional<int> opt2 = 3;
21482ddd57aeSStanislav Gatev 
21492ddd57aeSStanislav Gatev       opt2.swap(opt1);
21502ddd57aeSStanislav Gatev 
21512ddd57aeSStanislav Gatev       opt1.value();
21522ddd57aeSStanislav Gatev 
215358fe7f96SSam Estep       opt2.value(); // [[unsafe]]
21542ddd57aeSStanislav Gatev     }
215558fe7f96SSam Estep   )");
21562ddd57aeSStanislav Gatev }
21572ddd57aeSStanislav Gatev 
215814bc11a6SQizhi Hu TEST_P(UncheckedOptionalAccessTest, OptionalReturnedFromFuntionCall) {
215914bc11a6SQizhi Hu   ExpectDiagnosticsFor(
216014bc11a6SQizhi Hu       R"(
216114bc11a6SQizhi Hu     #include "unchecked_optional_access_test.h"
216214bc11a6SQizhi Hu 
216314bc11a6SQizhi Hu     struct S {
216414bc11a6SQizhi Hu       $ns::$optional<float> x;
216514bc11a6SQizhi Hu     } s;
216614bc11a6SQizhi Hu     S getOptional() {
216714bc11a6SQizhi Hu       return s;
216814bc11a6SQizhi Hu     }
216914bc11a6SQizhi Hu 
217014bc11a6SQizhi Hu     void target() {
217114bc11a6SQizhi Hu       getOptional().x = 0;
217214bc11a6SQizhi Hu     }
217314bc11a6SQizhi Hu   )");
217414bc11a6SQizhi Hu }
217514bc11a6SQizhi Hu 
21761f6741c1SJan Voung TEST_P(UncheckedOptionalAccessTest, NonConstMethodMayClearOptionalField) {
21776761b24aSJan Voung   ExpectDiagnosticsFor(
21786761b24aSJan Voung       R"(
21796761b24aSJan Voung     #include "unchecked_optional_access_test.h"
21806761b24aSJan Voung 
21816761b24aSJan Voung     struct Foo {
21826761b24aSJan Voung       $ns::$optional<std::string> opt;
21836761b24aSJan Voung       void clear();  // assume this may modify the opt field's state
21846761b24aSJan Voung     };
21856761b24aSJan Voung 
21866761b24aSJan Voung     void target(Foo& foo) {
21876761b24aSJan Voung       if (foo.opt) {
21886761b24aSJan Voung         foo.opt.value();
21896761b24aSJan Voung         foo.clear();
21906761b24aSJan Voung         foo.opt.value();  // [[unsafe]]
21916761b24aSJan Voung       }
21926761b24aSJan Voung     }
21936761b24aSJan Voung   )");
21946761b24aSJan Voung }
21956761b24aSJan Voung 
21961f6741c1SJan Voung TEST_P(UncheckedOptionalAccessTest,
21971f6741c1SJan Voung        NonConstMethodMayNotClearConstOptionalField) {
21981f6741c1SJan Voung   ExpectDiagnosticsFor(
21991f6741c1SJan Voung       R"(
22001f6741c1SJan Voung     #include "unchecked_optional_access_test.h"
22011f6741c1SJan Voung 
22021f6741c1SJan Voung     struct Foo {
22031f6741c1SJan Voung       const $ns::$optional<std::string> opt;
22041f6741c1SJan Voung       void clear();
22051f6741c1SJan Voung     };
22061f6741c1SJan Voung 
22071f6741c1SJan Voung     void target(Foo& foo) {
22081f6741c1SJan Voung       if (foo.opt) {
22091f6741c1SJan Voung         foo.opt.value();
22101f6741c1SJan Voung         foo.clear();
22111f6741c1SJan Voung         foo.opt.value();
22121f6741c1SJan Voung       }
22131f6741c1SJan Voung     }
22141f6741c1SJan Voung   )");
22151f6741c1SJan Voung }
22161f6741c1SJan Voung 
22172ddd57aeSStanislav Gatev TEST_P(UncheckedOptionalAccessTest, StdSwap) {
221858fe7f96SSam Estep   ExpectDiagnosticsFor(
22192ddd57aeSStanislav Gatev       R"(
22202ddd57aeSStanislav Gatev     #include "unchecked_optional_access_test.h"
22212ddd57aeSStanislav Gatev 
22222ddd57aeSStanislav Gatev     void target() {
22232ddd57aeSStanislav Gatev       $ns::$optional<int> opt1 = $ns::nullopt;
22242ddd57aeSStanislav Gatev       $ns::$optional<int> opt2 = 3;
22252ddd57aeSStanislav Gatev 
22262ddd57aeSStanislav Gatev       std::swap(opt1, opt2);
22272ddd57aeSStanislav Gatev 
22282ddd57aeSStanislav Gatev       opt1.value();
22292ddd57aeSStanislav Gatev 
223058fe7f96SSam Estep       opt2.value(); // [[unsafe]]
22312ddd57aeSStanislav Gatev     }
223258fe7f96SSam Estep   )");
22332ddd57aeSStanislav Gatev 
223458fe7f96SSam Estep   ExpectDiagnosticsFor(
22352ddd57aeSStanislav Gatev       R"(
22362ddd57aeSStanislav Gatev     #include "unchecked_optional_access_test.h"
22372ddd57aeSStanislav Gatev 
22382ddd57aeSStanislav Gatev     void target() {
22392ddd57aeSStanislav Gatev       $ns::$optional<int> opt1 = $ns::nullopt;
22402ddd57aeSStanislav Gatev       $ns::$optional<int> opt2 = 3;
22412ddd57aeSStanislav Gatev 
22422ddd57aeSStanislav Gatev       std::swap(opt2, opt1);
22432ddd57aeSStanislav Gatev 
22442ddd57aeSStanislav Gatev       opt1.value();
22452ddd57aeSStanislav Gatev 
224658fe7f96SSam Estep       opt2.value(); // [[unsafe]]
22472ddd57aeSStanislav Gatev     }
224858fe7f96SSam Estep   )");
22492ddd57aeSStanislav Gatev }
22502ddd57aeSStanislav Gatev 
2251d4fb829bSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocLeft) {
2252d4fb829bSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2253d4fb829bSYitzhak Mandelbaum       R"(
2254d4fb829bSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2255d4fb829bSYitzhak Mandelbaum 
2256d4fb829bSYitzhak Mandelbaum     struct L { $ns::$optional<int> hd; L* tl; };
2257d4fb829bSYitzhak Mandelbaum 
2258d4fb829bSYitzhak Mandelbaum     void target() {
2259d4fb829bSYitzhak Mandelbaum       $ns::$optional<int> foo = 3;
2260d4fb829bSYitzhak Mandelbaum       L bar;
2261d4fb829bSYitzhak Mandelbaum 
2262d4fb829bSYitzhak Mandelbaum       // Any `tl` beyond the first is not modeled.
2263d4fb829bSYitzhak Mandelbaum       bar.tl->tl->hd.swap(foo);
2264d4fb829bSYitzhak Mandelbaum 
2265d4fb829bSYitzhak Mandelbaum       bar.tl->tl->hd.value(); // [[unsafe]]
2266d4fb829bSYitzhak Mandelbaum       foo.value(); // [[unsafe]]
2267d4fb829bSYitzhak Mandelbaum     }
2268d4fb829bSYitzhak Mandelbaum   )");
2269d4fb829bSYitzhak Mandelbaum }
2270d4fb829bSYitzhak Mandelbaum 
2271d4fb829bSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledLocRight) {
2272d4fb829bSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2273d4fb829bSYitzhak Mandelbaum       R"(
2274d4fb829bSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2275d4fb829bSYitzhak Mandelbaum 
2276d4fb829bSYitzhak Mandelbaum     struct L { $ns::$optional<int> hd; L* tl; };
2277d4fb829bSYitzhak Mandelbaum 
2278d4fb829bSYitzhak Mandelbaum     void target() {
2279d4fb829bSYitzhak Mandelbaum       $ns::$optional<int> foo = 3;
2280d4fb829bSYitzhak Mandelbaum       L bar;
2281d4fb829bSYitzhak Mandelbaum 
2282d4fb829bSYitzhak Mandelbaum       // Any `tl` beyond the first is not modeled.
2283d4fb829bSYitzhak Mandelbaum       foo.swap(bar.tl->tl->hd);
2284d4fb829bSYitzhak Mandelbaum 
2285d4fb829bSYitzhak Mandelbaum       bar.tl->tl->hd.value(); // [[unsafe]]
2286d4fb829bSYitzhak Mandelbaum       foo.value(); // [[unsafe]]
2287d4fb829bSYitzhak Mandelbaum     }
2288d4fb829bSYitzhak Mandelbaum   )");
2289d4fb829bSYitzhak Mandelbaum }
2290d4fb829bSYitzhak Mandelbaum 
2291d4fb829bSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftSet) {
2292d4fb829bSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2293d4fb829bSYitzhak Mandelbaum       R"(
2294d4fb829bSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2295d4fb829bSYitzhak Mandelbaum 
2296d4fb829bSYitzhak Mandelbaum     struct S { int x; };
2297d4fb829bSYitzhak Mandelbaum     struct A { $ns::$optional<S> late; };
2298d4fb829bSYitzhak Mandelbaum     struct B { A f3; };
2299d4fb829bSYitzhak Mandelbaum     struct C { B f2; };
2300d4fb829bSYitzhak Mandelbaum     struct D { C f1; };
2301d4fb829bSYitzhak Mandelbaum 
2302d4fb829bSYitzhak Mandelbaum     void target() {
2303d4fb829bSYitzhak Mandelbaum       $ns::$optional<S> foo = S{3};
2304d4fb829bSYitzhak Mandelbaum       D bar;
2305d4fb829bSYitzhak Mandelbaum 
2306d4fb829bSYitzhak Mandelbaum       bar.f1.f2.f3.late.swap(foo);
2307d4fb829bSYitzhak Mandelbaum 
2308d4fb829bSYitzhak Mandelbaum       bar.f1.f2.f3.late.value();
2309d4fb829bSYitzhak Mandelbaum       foo.value(); // [[unsafe]]
2310d4fb829bSYitzhak Mandelbaum     }
2311d4fb829bSYitzhak Mandelbaum   )");
2312d4fb829bSYitzhak Mandelbaum }
2313d4fb829bSYitzhak Mandelbaum 
2314d4fb829bSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueLeftUnset) {
2315d4fb829bSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2316d4fb829bSYitzhak Mandelbaum       R"(
2317d4fb829bSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2318d4fb829bSYitzhak Mandelbaum 
2319d4fb829bSYitzhak Mandelbaum     struct S { int x; };
2320d4fb829bSYitzhak Mandelbaum     struct A { $ns::$optional<S> late; };
2321d4fb829bSYitzhak Mandelbaum     struct B { A f3; };
2322d4fb829bSYitzhak Mandelbaum     struct C { B f2; };
2323d4fb829bSYitzhak Mandelbaum     struct D { C f1; };
2324d4fb829bSYitzhak Mandelbaum 
2325d4fb829bSYitzhak Mandelbaum     void target() {
2326d4fb829bSYitzhak Mandelbaum       $ns::$optional<S> foo;
2327d4fb829bSYitzhak Mandelbaum       D bar;
2328d4fb829bSYitzhak Mandelbaum 
2329d4fb829bSYitzhak Mandelbaum       bar.f1.f2.f3.late.swap(foo);
2330d4fb829bSYitzhak Mandelbaum 
2331d4fb829bSYitzhak Mandelbaum       bar.f1.f2.f3.late.value(); // [[unsafe]]
2332d4fb829bSYitzhak Mandelbaum       foo.value(); // [[unsafe]]
2333d4fb829bSYitzhak Mandelbaum     }
2334d4fb829bSYitzhak Mandelbaum   )");
2335d4fb829bSYitzhak Mandelbaum }
2336d4fb829bSYitzhak Mandelbaum 
2337d4fb829bSYitzhak Mandelbaum // fixme: use recursion instead of depth.
2338d4fb829bSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightSet) {
2339d4fb829bSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2340d4fb829bSYitzhak Mandelbaum       R"(
2341d4fb829bSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2342d4fb829bSYitzhak Mandelbaum 
2343d4fb829bSYitzhak Mandelbaum     struct S { int x; };
2344d4fb829bSYitzhak Mandelbaum     struct A { $ns::$optional<S> late; };
2345d4fb829bSYitzhak Mandelbaum     struct B { A f3; };
2346d4fb829bSYitzhak Mandelbaum     struct C { B f2; };
2347d4fb829bSYitzhak Mandelbaum     struct D { C f1; };
2348d4fb829bSYitzhak Mandelbaum 
2349d4fb829bSYitzhak Mandelbaum     void target() {
2350d4fb829bSYitzhak Mandelbaum       $ns::$optional<S> foo = S{3};
2351d4fb829bSYitzhak Mandelbaum       D bar;
2352d4fb829bSYitzhak Mandelbaum 
2353d4fb829bSYitzhak Mandelbaum       foo.swap(bar.f1.f2.f3.late);
2354d4fb829bSYitzhak Mandelbaum 
2355d4fb829bSYitzhak Mandelbaum       bar.f1.f2.f3.late.value();
2356d4fb829bSYitzhak Mandelbaum       foo.value(); // [[unsafe]]
2357d4fb829bSYitzhak Mandelbaum     }
2358d4fb829bSYitzhak Mandelbaum   )");
2359d4fb829bSYitzhak Mandelbaum }
2360d4fb829bSYitzhak Mandelbaum 
2361d4fb829bSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, SwapUnmodeledValueRightUnset) {
2362d4fb829bSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2363d4fb829bSYitzhak Mandelbaum       R"(
2364d4fb829bSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2365d4fb829bSYitzhak Mandelbaum 
2366d4fb829bSYitzhak Mandelbaum     struct S { int x; };
2367d4fb829bSYitzhak Mandelbaum     struct A { $ns::$optional<S> late; };
2368d4fb829bSYitzhak Mandelbaum     struct B { A f3; };
2369d4fb829bSYitzhak Mandelbaum     struct C { B f2; };
2370d4fb829bSYitzhak Mandelbaum     struct D { C f1; };
2371d4fb829bSYitzhak Mandelbaum 
2372d4fb829bSYitzhak Mandelbaum     void target() {
2373d4fb829bSYitzhak Mandelbaum       $ns::$optional<S> foo;
2374d4fb829bSYitzhak Mandelbaum       D bar;
2375d4fb829bSYitzhak Mandelbaum 
2376d4fb829bSYitzhak Mandelbaum       foo.swap(bar.f1.f2.f3.late);
2377d4fb829bSYitzhak Mandelbaum 
2378d4fb829bSYitzhak Mandelbaum       bar.f1.f2.f3.late.value(); // [[unsafe]]
2379d4fb829bSYitzhak Mandelbaum       foo.value(); // [[unsafe]]
2380d4fb829bSYitzhak Mandelbaum     }
2381d4fb829bSYitzhak Mandelbaum   )");
2382d4fb829bSYitzhak Mandelbaum }
2383d4fb829bSYitzhak Mandelbaum 
23845d22d1f5SYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, UniquePtrToOptional) {
23855d22d1f5SYitzhak Mandelbaum   // We suppress diagnostics for optionals in smart pointers (other than
23865d22d1f5SYitzhak Mandelbaum   // `optional` itself).
23875d22d1f5SYitzhak Mandelbaum   ExpectDiagnosticsFor(
23885d22d1f5SYitzhak Mandelbaum       R"(
23895d22d1f5SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
23905d22d1f5SYitzhak Mandelbaum 
23915d22d1f5SYitzhak Mandelbaum     template <typename T>
23925d22d1f5SYitzhak Mandelbaum     struct smart_ptr {
23935d22d1f5SYitzhak Mandelbaum       T& operator*() &;
23945d22d1f5SYitzhak Mandelbaum       T* operator->();
23955d22d1f5SYitzhak Mandelbaum     };
23965d22d1f5SYitzhak Mandelbaum 
23975d22d1f5SYitzhak Mandelbaum     void target() {
23985d22d1f5SYitzhak Mandelbaum       smart_ptr<$ns::$optional<bool>> foo;
23995d22d1f5SYitzhak Mandelbaum       foo->value();
24005d22d1f5SYitzhak Mandelbaum       (*foo).value();
24015d22d1f5SYitzhak Mandelbaum     }
24025d22d1f5SYitzhak Mandelbaum   )");
24035d22d1f5SYitzhak Mandelbaum }
24045d22d1f5SYitzhak Mandelbaum 
2405a184a0d8SYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) {
24065d22d1f5SYitzhak Mandelbaum   // We suppress diagnostics for optional fields reachable from smart pointers
24075d22d1f5SYitzhak Mandelbaum   // (other than `optional` itself) through (exactly) one member access.
240858fe7f96SSam Estep   ExpectDiagnosticsFor(
2409a184a0d8SYitzhak Mandelbaum       R"(
2410a184a0d8SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2411a184a0d8SYitzhak Mandelbaum 
2412a184a0d8SYitzhak Mandelbaum     template <typename T>
2413a184a0d8SYitzhak Mandelbaum     struct smart_ptr {
2414a184a0d8SYitzhak Mandelbaum       T& operator*() &;
2415a184a0d8SYitzhak Mandelbaum       T* operator->();
2416a184a0d8SYitzhak Mandelbaum     };
2417a184a0d8SYitzhak Mandelbaum 
2418a184a0d8SYitzhak Mandelbaum     struct Foo {
2419a184a0d8SYitzhak Mandelbaum       $ns::$optional<int> opt;
2420a184a0d8SYitzhak Mandelbaum     };
2421a184a0d8SYitzhak Mandelbaum 
2422a184a0d8SYitzhak Mandelbaum     void target() {
2423a184a0d8SYitzhak Mandelbaum       smart_ptr<Foo> foo;
2424a184a0d8SYitzhak Mandelbaum       *foo->opt;
2425a184a0d8SYitzhak Mandelbaum       *(*foo).opt;
2426a184a0d8SYitzhak Mandelbaum     }
242758fe7f96SSam Estep   )");
2428a184a0d8SYitzhak Mandelbaum }
2429a184a0d8SYitzhak Mandelbaum 
243065e710c3SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) {
243158fe7f96SSam Estep   ExpectDiagnosticsFor(
243265e710c3SStanislav Gatev       R"(
243365e710c3SStanislav Gatev     #include "unchecked_optional_access_test.h"
243465e710c3SStanislav Gatev 
243565e710c3SStanislav Gatev     $ns::$optional<int> MakeOpt();
243665e710c3SStanislav Gatev 
243765e710c3SStanislav Gatev     void target() {
243865e710c3SStanislav Gatev       $ns::$optional<int> opt = 0;
243965e710c3SStanislav Gatev       opt = MakeOpt();
244058fe7f96SSam Estep       opt.value(); // [[unsafe]]
244165e710c3SStanislav Gatev     }
244258fe7f96SSam Estep   )");
244358fe7f96SSam Estep   ExpectDiagnosticsFor(
244465e710c3SStanislav Gatev       R"(
244565e710c3SStanislav Gatev     #include "unchecked_optional_access_test.h"
244665e710c3SStanislav Gatev 
244765e710c3SStanislav Gatev     const $ns::$optional<int>& MakeOpt();
244865e710c3SStanislav Gatev 
244965e710c3SStanislav Gatev     void target() {
245065e710c3SStanislav Gatev       $ns::$optional<int> opt = 0;
245165e710c3SStanislav Gatev       opt = MakeOpt();
245258fe7f96SSam Estep       opt.value(); // [[unsafe]]
245365e710c3SStanislav Gatev     }
245458fe7f96SSam Estep   )");
245565e710c3SStanislav Gatev 
245658fe7f96SSam Estep   ExpectDiagnosticsFor(
245765e710c3SStanislav Gatev       R"(
245865e710c3SStanislav Gatev     #include "unchecked_optional_access_test.h"
245965e710c3SStanislav Gatev 
246065e710c3SStanislav Gatev     using IntOpt = $ns::$optional<int>;
246165e710c3SStanislav Gatev     IntOpt MakeOpt();
246265e710c3SStanislav Gatev 
246365e710c3SStanislav Gatev     void target() {
246465e710c3SStanislav Gatev       IntOpt opt = 0;
246565e710c3SStanislav Gatev       opt = MakeOpt();
246658fe7f96SSam Estep       opt.value(); // [[unsafe]]
246765e710c3SStanislav Gatev     }
246858fe7f96SSam Estep   )");
246965e710c3SStanislav Gatev 
247058fe7f96SSam Estep   ExpectDiagnosticsFor(
247165e710c3SStanislav Gatev       R"(
247265e710c3SStanislav Gatev     #include "unchecked_optional_access_test.h"
247365e710c3SStanislav Gatev 
247465e710c3SStanislav Gatev     using IntOpt = $ns::$optional<int>;
247565e710c3SStanislav Gatev     const IntOpt& MakeOpt();
247665e710c3SStanislav Gatev 
247765e710c3SStanislav Gatev     void target() {
247865e710c3SStanislav Gatev       IntOpt opt = 0;
247965e710c3SStanislav Gatev       opt = MakeOpt();
248058fe7f96SSam Estep       opt.value(); // [[unsafe]]
248165e710c3SStanislav Gatev     }
248258fe7f96SSam Estep   )");
248365e710c3SStanislav Gatev }
248465e710c3SStanislav Gatev 
2485390029beSYitzhak Mandelbaum 
2486390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftSet) {
2487390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2488390029beSYitzhak Mandelbaum       R"(
2489390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2490390029beSYitzhak Mandelbaum 
2491390029beSYitzhak Mandelbaum     void target() {
2492390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = 3;
2493390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2494390029beSYitzhak Mandelbaum 
2495390029beSYitzhak Mandelbaum       if (opt1 == opt2) {
2496390029beSYitzhak Mandelbaum         opt2.value();
2497390029beSYitzhak Mandelbaum       } else {
2498390029beSYitzhak Mandelbaum         opt2.value(); // [[unsafe]]
2499390029beSYitzhak Mandelbaum       }
2500390029beSYitzhak Mandelbaum     }
2501390029beSYitzhak Mandelbaum   )");
2502390029beSYitzhak Mandelbaum }
2503390029beSYitzhak Mandelbaum 
2504390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightSet) {
2505390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2506390029beSYitzhak Mandelbaum       R"(
2507390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2508390029beSYitzhak Mandelbaum 
2509390029beSYitzhak Mandelbaum     void target() {
2510390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = 3;
2511390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2512390029beSYitzhak Mandelbaum 
2513390029beSYitzhak Mandelbaum       if (opt2 == opt1) {
2514390029beSYitzhak Mandelbaum         opt2.value();
2515390029beSYitzhak Mandelbaum       } else {
2516390029beSYitzhak Mandelbaum         opt2.value(); // [[unsafe]]
2517390029beSYitzhak Mandelbaum       }
2518390029beSYitzhak Mandelbaum     }
2519390029beSYitzhak Mandelbaum   )");
2520390029beSYitzhak Mandelbaum }
2521390029beSYitzhak Mandelbaum 
2522390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, EqualityCheckVerifySetAfterEq) {
2523390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2524390029beSYitzhak Mandelbaum       R"(
2525390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2526390029beSYitzhak Mandelbaum 
2527390029beSYitzhak Mandelbaum     void target() {
2528390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2529390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2530390029beSYitzhak Mandelbaum 
2531390029beSYitzhak Mandelbaum       if (opt1 == opt2) {
2532390029beSYitzhak Mandelbaum         if (opt1.has_value())
2533390029beSYitzhak Mandelbaum           opt2.value();
2534390029beSYitzhak Mandelbaum         if (opt2.has_value())
2535390029beSYitzhak Mandelbaum           opt1.value();
2536390029beSYitzhak Mandelbaum       }
2537390029beSYitzhak Mandelbaum     }
2538390029beSYitzhak Mandelbaum   )");
2539390029beSYitzhak Mandelbaum }
2540390029beSYitzhak Mandelbaum 
2541390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftUnset) {
2542390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2543390029beSYitzhak Mandelbaum       R"(
2544390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2545390029beSYitzhak Mandelbaum 
2546390029beSYitzhak Mandelbaum     void target() {
2547390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = $ns::nullopt;
2548390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2549390029beSYitzhak Mandelbaum 
2550390029beSYitzhak Mandelbaum       if (opt1 == opt2) {
2551390029beSYitzhak Mandelbaum         opt2.value(); // [[unsafe]]
2552390029beSYitzhak Mandelbaum       } else {
2553390029beSYitzhak Mandelbaum         opt2.value();
2554390029beSYitzhak Mandelbaum       }
2555390029beSYitzhak Mandelbaum     }
2556390029beSYitzhak Mandelbaum   )");
2557390029beSYitzhak Mandelbaum }
2558390029beSYitzhak Mandelbaum 
2559390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightUnset) {
2560390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2561390029beSYitzhak Mandelbaum       R"(
2562390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2563390029beSYitzhak Mandelbaum 
2564390029beSYitzhak Mandelbaum     void target() {
2565390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = $ns::nullopt;
2566390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2567390029beSYitzhak Mandelbaum 
2568390029beSYitzhak Mandelbaum       if (opt2 == opt1) {
2569390029beSYitzhak Mandelbaum         opt2.value(); // [[unsafe]]
2570390029beSYitzhak Mandelbaum       } else {
2571390029beSYitzhak Mandelbaum         opt2.value();
2572390029beSYitzhak Mandelbaum       }
2573390029beSYitzhak Mandelbaum     }
2574390029beSYitzhak Mandelbaum   )");
2575390029beSYitzhak Mandelbaum }
2576390029beSYitzhak Mandelbaum 
2577390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightNullopt) {
2578390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2579390029beSYitzhak Mandelbaum       R"(
2580390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2581390029beSYitzhak Mandelbaum 
2582390029beSYitzhak Mandelbaum     void target() {
2583390029beSYitzhak Mandelbaum       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2584390029beSYitzhak Mandelbaum 
2585390029beSYitzhak Mandelbaum       if (opt == $ns::nullopt) {
2586390029beSYitzhak Mandelbaum         opt.value(); // [[unsafe]]
2587390029beSYitzhak Mandelbaum       } else {
2588390029beSYitzhak Mandelbaum         opt.value();
2589390029beSYitzhak Mandelbaum       }
2590390029beSYitzhak Mandelbaum     }
2591390029beSYitzhak Mandelbaum   )");
2592390029beSYitzhak Mandelbaum }
2593390029beSYitzhak Mandelbaum 
2594390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftNullopt) {
2595390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2596390029beSYitzhak Mandelbaum       R"(
2597390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2598390029beSYitzhak Mandelbaum 
2599390029beSYitzhak Mandelbaum     void target() {
2600390029beSYitzhak Mandelbaum       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2601390029beSYitzhak Mandelbaum 
2602390029beSYitzhak Mandelbaum       if ($ns::nullopt == opt) {
2603390029beSYitzhak Mandelbaum         opt.value(); // [[unsafe]]
2604390029beSYitzhak Mandelbaum       } else {
2605390029beSYitzhak Mandelbaum         opt.value();
2606390029beSYitzhak Mandelbaum       }
2607390029beSYitzhak Mandelbaum     }
2608390029beSYitzhak Mandelbaum   )");
2609390029beSYitzhak Mandelbaum }
2610390029beSYitzhak Mandelbaum 
2611390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, EqualityCheckRightValue) {
2612390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2613390029beSYitzhak Mandelbaum       R"(
2614390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2615390029beSYitzhak Mandelbaum 
2616390029beSYitzhak Mandelbaum     void target() {
2617390029beSYitzhak Mandelbaum       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2618390029beSYitzhak Mandelbaum 
2619390029beSYitzhak Mandelbaum       if (opt == 3) {
2620390029beSYitzhak Mandelbaum         opt.value();
2621390029beSYitzhak Mandelbaum       } else {
2622390029beSYitzhak Mandelbaum         opt.value(); // [[unsafe]]
2623390029beSYitzhak Mandelbaum       }
2624390029beSYitzhak Mandelbaum     }
2625390029beSYitzhak Mandelbaum   )");
2626390029beSYitzhak Mandelbaum }
2627390029beSYitzhak Mandelbaum 
2628390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, EqualityCheckLeftValue) {
2629390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2630390029beSYitzhak Mandelbaum       R"(
2631390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2632390029beSYitzhak Mandelbaum 
2633390029beSYitzhak Mandelbaum     void target() {
2634390029beSYitzhak Mandelbaum       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2635390029beSYitzhak Mandelbaum 
2636390029beSYitzhak Mandelbaum       if (3 == opt) {
2637390029beSYitzhak Mandelbaum         opt.value();
2638390029beSYitzhak Mandelbaum       } else {
2639390029beSYitzhak Mandelbaum         opt.value(); // [[unsafe]]
2640390029beSYitzhak Mandelbaum       }
2641390029beSYitzhak Mandelbaum     }
2642390029beSYitzhak Mandelbaum   )");
2643390029beSYitzhak Mandelbaum }
2644390029beSYitzhak Mandelbaum 
2645390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftSet) {
2646390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2647390029beSYitzhak Mandelbaum       R"(
2648390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2649390029beSYitzhak Mandelbaum 
2650390029beSYitzhak Mandelbaum     void target() {
2651390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = 3;
2652390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2653390029beSYitzhak Mandelbaum 
2654390029beSYitzhak Mandelbaum       if (opt1 != opt2) {
2655390029beSYitzhak Mandelbaum         opt2.value(); // [[unsafe]]
2656390029beSYitzhak Mandelbaum       } else {
2657390029beSYitzhak Mandelbaum         opt2.value();
2658390029beSYitzhak Mandelbaum       }
2659390029beSYitzhak Mandelbaum     }
2660390029beSYitzhak Mandelbaum   )");
2661390029beSYitzhak Mandelbaum }
2662390029beSYitzhak Mandelbaum 
2663390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightSet) {
2664390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2665390029beSYitzhak Mandelbaum       R"(
2666390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2667390029beSYitzhak Mandelbaum 
2668390029beSYitzhak Mandelbaum     void target() {
2669390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = 3;
2670390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2671390029beSYitzhak Mandelbaum 
2672390029beSYitzhak Mandelbaum       if (opt2 != opt1) {
2673390029beSYitzhak Mandelbaum         opt2.value(); // [[unsafe]]
2674390029beSYitzhak Mandelbaum       } else {
2675390029beSYitzhak Mandelbaum         opt2.value();
2676390029beSYitzhak Mandelbaum       }
2677390029beSYitzhak Mandelbaum     }
2678390029beSYitzhak Mandelbaum   )");
2679390029beSYitzhak Mandelbaum }
2680390029beSYitzhak Mandelbaum 
2681390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, InequalityCheckVerifySetAfterEq) {
2682390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2683390029beSYitzhak Mandelbaum       R"(
2684390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2685390029beSYitzhak Mandelbaum 
2686390029beSYitzhak Mandelbaum     void target() {
2687390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = Make<$ns::$optional<int>>();
2688390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2689390029beSYitzhak Mandelbaum 
2690390029beSYitzhak Mandelbaum       if (opt1 != opt2) {
2691390029beSYitzhak Mandelbaum         if (opt1.has_value())
2692390029beSYitzhak Mandelbaum           opt2.value(); // [[unsafe]]
2693390029beSYitzhak Mandelbaum         if (opt2.has_value())
2694390029beSYitzhak Mandelbaum           opt1.value(); // [[unsafe]]
2695390029beSYitzhak Mandelbaum       }
2696390029beSYitzhak Mandelbaum     }
2697390029beSYitzhak Mandelbaum   )");
2698390029beSYitzhak Mandelbaum }
2699390029beSYitzhak Mandelbaum 
2700390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftUnset) {
2701390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2702390029beSYitzhak Mandelbaum       R"(
2703390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2704390029beSYitzhak Mandelbaum 
2705390029beSYitzhak Mandelbaum     void target() {
2706390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = $ns::nullopt;
2707390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2708390029beSYitzhak Mandelbaum 
2709390029beSYitzhak Mandelbaum       if (opt1 != opt2) {
2710390029beSYitzhak Mandelbaum         opt2.value();
2711390029beSYitzhak Mandelbaum       } else {
2712390029beSYitzhak Mandelbaum         opt2.value(); // [[unsafe]]
2713390029beSYitzhak Mandelbaum       }
2714390029beSYitzhak Mandelbaum     }
2715390029beSYitzhak Mandelbaum   )");
2716390029beSYitzhak Mandelbaum }
2717390029beSYitzhak Mandelbaum 
2718390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightUnset) {
2719390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2720390029beSYitzhak Mandelbaum       R"(
2721390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2722390029beSYitzhak Mandelbaum 
2723390029beSYitzhak Mandelbaum     void target() {
2724390029beSYitzhak Mandelbaum       $ns::$optional<int> opt1 = $ns::nullopt;
2725390029beSYitzhak Mandelbaum       $ns::$optional<int> opt2 = Make<$ns::$optional<int>>();
2726390029beSYitzhak Mandelbaum 
2727390029beSYitzhak Mandelbaum       if (opt2 != opt1) {
2728390029beSYitzhak Mandelbaum         opt2.value();
2729390029beSYitzhak Mandelbaum       } else {
2730390029beSYitzhak Mandelbaum         opt2.value(); // [[unsafe]]
2731390029beSYitzhak Mandelbaum       }
2732390029beSYitzhak Mandelbaum     }
2733390029beSYitzhak Mandelbaum   )");
2734390029beSYitzhak Mandelbaum }
2735390029beSYitzhak Mandelbaum 
2736390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightNullopt) {
2737390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2738390029beSYitzhak Mandelbaum       R"(
2739390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2740390029beSYitzhak Mandelbaum 
2741390029beSYitzhak Mandelbaum     void target() {
2742390029beSYitzhak Mandelbaum       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2743390029beSYitzhak Mandelbaum 
2744390029beSYitzhak Mandelbaum       if (opt != $ns::nullopt) {
2745390029beSYitzhak Mandelbaum         opt.value();
2746390029beSYitzhak Mandelbaum       } else {
2747390029beSYitzhak Mandelbaum         opt.value(); // [[unsafe]]
2748390029beSYitzhak Mandelbaum       }
2749390029beSYitzhak Mandelbaum     }
2750390029beSYitzhak Mandelbaum   )");
2751390029beSYitzhak Mandelbaum }
2752390029beSYitzhak Mandelbaum 
2753390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftNullopt) {
2754390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2755390029beSYitzhak Mandelbaum       R"(
2756390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2757390029beSYitzhak Mandelbaum 
2758390029beSYitzhak Mandelbaum     void target() {
2759390029beSYitzhak Mandelbaum       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2760390029beSYitzhak Mandelbaum 
2761390029beSYitzhak Mandelbaum       if ($ns::nullopt != opt) {
2762390029beSYitzhak Mandelbaum         opt.value();
2763390029beSYitzhak Mandelbaum       } else {
2764390029beSYitzhak Mandelbaum         opt.value(); // [[unsafe]]
2765390029beSYitzhak Mandelbaum       }
2766390029beSYitzhak Mandelbaum     }
2767390029beSYitzhak Mandelbaum   )");
2768390029beSYitzhak Mandelbaum }
2769390029beSYitzhak Mandelbaum 
2770390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, InequalityCheckRightValue) {
2771390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2772390029beSYitzhak Mandelbaum       R"(
2773390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2774390029beSYitzhak Mandelbaum 
2775390029beSYitzhak Mandelbaum     void target() {
2776390029beSYitzhak Mandelbaum       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2777390029beSYitzhak Mandelbaum 
2778390029beSYitzhak Mandelbaum       if (opt != 3) {
2779390029beSYitzhak Mandelbaum         opt.value(); // [[unsafe]]
2780390029beSYitzhak Mandelbaum       } else {
2781390029beSYitzhak Mandelbaum         opt.value();
2782390029beSYitzhak Mandelbaum       }
2783390029beSYitzhak Mandelbaum     }
2784390029beSYitzhak Mandelbaum   )");
2785390029beSYitzhak Mandelbaum }
2786390029beSYitzhak Mandelbaum 
2787390029beSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, InequalityCheckLeftValue) {
2788390029beSYitzhak Mandelbaum   ExpectDiagnosticsFor(
2789390029beSYitzhak Mandelbaum       R"(
2790390029beSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2791390029beSYitzhak Mandelbaum 
2792390029beSYitzhak Mandelbaum     void target() {
2793390029beSYitzhak Mandelbaum       $ns::$optional<int> opt = Make<$ns::$optional<int>>();
2794390029beSYitzhak Mandelbaum 
2795390029beSYitzhak Mandelbaum       if (3 != opt) {
2796390029beSYitzhak Mandelbaum         opt.value(); // [[unsafe]]
2797390029beSYitzhak Mandelbaum       } else {
2798390029beSYitzhak Mandelbaum         opt.value();
2799390029beSYitzhak Mandelbaum       }
2800390029beSYitzhak Mandelbaum     }
2801390029beSYitzhak Mandelbaum   )");
2802390029beSYitzhak Mandelbaum }
2803390029beSYitzhak Mandelbaum 
28046adfc64eSYitzhak Mandelbaum // Verifies that the model sees through aliases.
28056adfc64eSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, WithAlias) {
280658fe7f96SSam Estep   ExpectDiagnosticsFor(
28076adfc64eSYitzhak Mandelbaum       R"(
28086adfc64eSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
28096adfc64eSYitzhak Mandelbaum 
28106adfc64eSYitzhak Mandelbaum     template <typename T>
28116adfc64eSYitzhak Mandelbaum     using MyOptional = $ns::$optional<T>;
28126adfc64eSYitzhak Mandelbaum 
28136adfc64eSYitzhak Mandelbaum     void target(MyOptional<int> opt) {
281458fe7f96SSam Estep       opt.value(); // [[unsafe]]
28156adfc64eSYitzhak Mandelbaum     }
281658fe7f96SSam Estep   )");
28176adfc64eSYitzhak Mandelbaum }
28186adfc64eSYitzhak Mandelbaum 
2819dd38caf3SYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, OptionalValueOptional) {
2820dd38caf3SYitzhak Mandelbaum   // Basic test that nested values are populated.  We nest an optional because
2821dd38caf3SYitzhak Mandelbaum   // its easy to use in a test, but the type of the nested value shouldn't
2822dd38caf3SYitzhak Mandelbaum   // matter.
282358fe7f96SSam Estep   ExpectDiagnosticsFor(
2824dd38caf3SYitzhak Mandelbaum       R"(
2825dd38caf3SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2826dd38caf3SYitzhak Mandelbaum 
2827dd38caf3SYitzhak Mandelbaum     using Foo = $ns::$optional<std::string>;
2828dd38caf3SYitzhak Mandelbaum 
2829dd38caf3SYitzhak Mandelbaum     void target($ns::$optional<Foo> foo) {
2830dd38caf3SYitzhak Mandelbaum       if (foo && *foo) {
2831dd38caf3SYitzhak Mandelbaum         foo->value();
2832dd38caf3SYitzhak Mandelbaum       }
2833dd38caf3SYitzhak Mandelbaum     }
283458fe7f96SSam Estep   )");
2835dd38caf3SYitzhak Mandelbaum 
2836dd38caf3SYitzhak Mandelbaum   // Mutation is supported for nested values.
283758fe7f96SSam Estep   ExpectDiagnosticsFor(
2838dd38caf3SYitzhak Mandelbaum       R"(
2839dd38caf3SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2840dd38caf3SYitzhak Mandelbaum 
2841dd38caf3SYitzhak Mandelbaum     using Foo = $ns::$optional<std::string>;
2842dd38caf3SYitzhak Mandelbaum 
2843dd38caf3SYitzhak Mandelbaum     void target($ns::$optional<Foo> foo) {
2844dd38caf3SYitzhak Mandelbaum       if (foo && *foo) {
2845dd38caf3SYitzhak Mandelbaum         foo->reset();
284658fe7f96SSam Estep         foo->value(); // [[unsafe]]
2847dd38caf3SYitzhak Mandelbaum       }
2848dd38caf3SYitzhak Mandelbaum     }
284958fe7f96SSam Estep   )");
2850dd38caf3SYitzhak Mandelbaum }
2851dd38caf3SYitzhak Mandelbaum 
2852ae280281Smartinboehme TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignValue) {
2853ae280281Smartinboehme   ExpectDiagnosticsFor(
2854ae280281Smartinboehme       R"(
2855ae280281Smartinboehme     #include "unchecked_optional_access_test.h"
2856ae280281Smartinboehme 
2857ae280281Smartinboehme     using OptionalInt = $ns::$optional<int>;
2858ae280281Smartinboehme 
2859ae280281Smartinboehme     void target($ns::$optional<OptionalInt> opt) {
2860ae280281Smartinboehme       if (!opt) return;
2861ae280281Smartinboehme 
2862ae280281Smartinboehme       // Accessing the outer optional is OK now.
2863ae280281Smartinboehme       *opt;
2864ae280281Smartinboehme 
2865ae280281Smartinboehme       // But accessing the nested optional is still unsafe because we haven't
2866ae280281Smartinboehme       // checked it.
2867ae280281Smartinboehme       **opt;  // [[unsafe]]
2868ae280281Smartinboehme 
2869ae280281Smartinboehme       *opt = 1;
2870ae280281Smartinboehme 
2871ae280281Smartinboehme       // Accessing the nested optional is safe after assigning a value to it.
2872ae280281Smartinboehme       **opt;
2873ae280281Smartinboehme     }
2874ae280281Smartinboehme   )");
2875ae280281Smartinboehme }
2876ae280281Smartinboehme 
2877ae280281Smartinboehme TEST_P(UncheckedOptionalAccessTest, NestedOptionalAssignOptional) {
2878ae280281Smartinboehme   ExpectDiagnosticsFor(
2879ae280281Smartinboehme       R"(
2880ae280281Smartinboehme     #include "unchecked_optional_access_test.h"
2881ae280281Smartinboehme 
2882ae280281Smartinboehme     using OptionalInt = $ns::$optional<int>;
2883ae280281Smartinboehme 
2884ae280281Smartinboehme     void target($ns::$optional<OptionalInt> opt) {
2885ae280281Smartinboehme       if (!opt) return;
2886ae280281Smartinboehme 
2887ae280281Smartinboehme       // Accessing the outer optional is OK now.
2888ae280281Smartinboehme       *opt;
2889ae280281Smartinboehme 
2890ae280281Smartinboehme       // But accessing the nested optional is still unsafe because we haven't
2891ae280281Smartinboehme       // checked it.
2892ae280281Smartinboehme       **opt;  // [[unsafe]]
2893ae280281Smartinboehme 
2894ae280281Smartinboehme       // Assign from `optional<short>` so that we trigger conversion assignment
2895ae280281Smartinboehme       // instead of move assignment.
2896ae280281Smartinboehme       *opt = $ns::$optional<short>();
2897ae280281Smartinboehme 
2898ae280281Smartinboehme       // Accessing the nested optional is still unsafe after assigning an empty
2899ae280281Smartinboehme       // optional to it.
2900ae280281Smartinboehme       **opt;  // [[unsafe]]
2901ae280281Smartinboehme     }
2902ae280281Smartinboehme   )");
2903ae280281Smartinboehme }
2904ae280281Smartinboehme 
2905dd38caf3SYitzhak Mandelbaum // Tests that structs can be nested. We use an optional field because its easy
2906dd38caf3SYitzhak Mandelbaum // to use in a test, but the type of the field shouldn't matter.
2907dd38caf3SYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, OptionalValueStruct) {
290858fe7f96SSam Estep   ExpectDiagnosticsFor(
2909dd38caf3SYitzhak Mandelbaum       R"(
2910dd38caf3SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2911dd38caf3SYitzhak Mandelbaum 
2912dd38caf3SYitzhak Mandelbaum     struct Foo {
2913dd38caf3SYitzhak Mandelbaum       $ns::$optional<std::string> opt;
2914dd38caf3SYitzhak Mandelbaum     };
2915dd38caf3SYitzhak Mandelbaum 
2916dd38caf3SYitzhak Mandelbaum     void target($ns::$optional<Foo> foo) {
2917dd38caf3SYitzhak Mandelbaum       if (foo && foo->opt) {
2918dd38caf3SYitzhak Mandelbaum         foo->opt.value();
2919dd38caf3SYitzhak Mandelbaum       }
2920dd38caf3SYitzhak Mandelbaum     }
292158fe7f96SSam Estep   )");
2922dd38caf3SYitzhak Mandelbaum }
2923dd38caf3SYitzhak Mandelbaum 
292439851e3aSJan Voung // FIXME: A case that we should handle but currently don't.
292539851e3aSJan Voung // When there is a field of type reference to non-optional, we may
292639851e3aSJan Voung // stop recursively creating storage locations.
292739851e3aSJan Voung // E.g., the field `second` below in `pair` should eventually lead to
292839851e3aSJan Voung // the optional `x` in `A`.
292939851e3aSJan Voung TEST_P(UncheckedOptionalAccessTest, NestedOptionalThroughNonOptionalRefField) {
293039851e3aSJan Voung   ExpectDiagnosticsFor(R"(
293139851e3aSJan Voung     #include "unchecked_optional_access_test.h"
293239851e3aSJan Voung 
293339851e3aSJan Voung     struct A {
293439851e3aSJan Voung       $ns::$optional<int> x;
293539851e3aSJan Voung     };
293639851e3aSJan Voung 
293739851e3aSJan Voung     struct pair {
293839851e3aSJan Voung       int first;
293939851e3aSJan Voung       const A &second;
294039851e3aSJan Voung     };
294139851e3aSJan Voung 
294239851e3aSJan Voung     struct B {
294339851e3aSJan Voung       $ns::$optional<pair>& nonConstGetRef();
294439851e3aSJan Voung     };
294539851e3aSJan Voung 
294639851e3aSJan Voung     void target(B b) {
294739851e3aSJan Voung       const auto& maybe_pair = b.nonConstGetRef();
294839851e3aSJan Voung       if (!maybe_pair.has_value())
294939851e3aSJan Voung         return;
295039851e3aSJan Voung 
295139851e3aSJan Voung       if(!maybe_pair->second.x.has_value())
295239851e3aSJan Voung         return;
295339851e3aSJan Voung       maybe_pair->second.x.value();  // [[unsafe]]
295439851e3aSJan Voung     }
295539851e3aSJan Voung   )");
295639851e3aSJan Voung }
295739851e3aSJan Voung 
2958dd38caf3SYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, OptionalValueInitialization) {
295958fe7f96SSam Estep   ExpectDiagnosticsFor(
2960dd38caf3SYitzhak Mandelbaum       R"(
2961dd38caf3SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
2962dd38caf3SYitzhak Mandelbaum 
2963dd38caf3SYitzhak Mandelbaum     using Foo = $ns::$optional<std::string>;
2964dd38caf3SYitzhak Mandelbaum 
2965dd38caf3SYitzhak Mandelbaum     void target($ns::$optional<Foo> foo, bool b) {
2966dd38caf3SYitzhak Mandelbaum       if (!foo.has_value()) return;
2967dd38caf3SYitzhak Mandelbaum       if (b) {
2968dd38caf3SYitzhak Mandelbaum         if (!foo->has_value()) return;
2969dd38caf3SYitzhak Mandelbaum         // We have created `foo.value()`.
2970dd38caf3SYitzhak Mandelbaum         foo->value();
2971dd38caf3SYitzhak Mandelbaum       } else {
2972dd38caf3SYitzhak Mandelbaum         if (!foo->has_value()) return;
2973dd38caf3SYitzhak Mandelbaum         // We have created `foo.value()` again, in a different environment.
2974dd38caf3SYitzhak Mandelbaum         foo->value();
2975dd38caf3SYitzhak Mandelbaum       }
2976dd38caf3SYitzhak Mandelbaum       // Now we merge the two values. UncheckedOptionalAccessModel::merge() will
2977dd38caf3SYitzhak Mandelbaum       // throw away the "value" property.
29783bc1ea5bSMartin Braenne       foo->value();
2979dd38caf3SYitzhak Mandelbaum     }
298058fe7f96SSam Estep   )");
2981dd38caf3SYitzhak Mandelbaum }
2982dd38caf3SYitzhak Mandelbaum 
29835d22d1f5SYitzhak Mandelbaum // This test is aimed at the core model, not the diagnostic. It is a regression
29845d22d1f5SYitzhak Mandelbaum // test against a crash when using non-trivial smart pointers, like
29855d22d1f5SYitzhak Mandelbaum // `std::unique_ptr`. As such, it doesn't test the access itself, which would be
29865d22d1f5SYitzhak Mandelbaum // ignored regardless because of `IgnoreSmartPointerDereference = true`, above.
2987cd0d5261SSam Estep TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) {
298858fe7f96SSam Estep   ExpectDiagnosticsFor(
2989cd0d5261SSam Estep       R"(
2990cd0d5261SSam Estep     #include "unchecked_optional_access_test.h"
2991cd0d5261SSam Estep 
2992cd0d5261SSam Estep     template <typename T>
2993cd0d5261SSam Estep     struct smart_ptr {
2994cd0d5261SSam Estep       typename std::add_lvalue_reference<T>::type operator*() &;
2995cd0d5261SSam Estep     };
2996cd0d5261SSam Estep 
2997cd0d5261SSam Estep     void target() {
29985d22d1f5SYitzhak Mandelbaum       smart_ptr<$ns::$optional<int>> x;
29995d22d1f5SYitzhak Mandelbaum       // Verify that this assignment does not crash.
30005d22d1f5SYitzhak Mandelbaum       *x = 3;
3001cd0d5261SSam Estep     }
300258fe7f96SSam Estep   )");
3003cd0d5261SSam Estep }
3004cd0d5261SSam Estep 
30058fcdd625SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, CorrelatedBranches) {
300658fe7f96SSam Estep   ExpectDiagnosticsFor(R"code(
30078fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
30088fcdd625SStanislav Gatev 
30098fcdd625SStanislav Gatev     void target(bool b, $ns::$optional<int> opt) {
30108fcdd625SStanislav Gatev       if (b || opt.has_value()) {
30118fcdd625SStanislav Gatev         if (!b) {
30128fcdd625SStanislav Gatev           opt.value();
30138fcdd625SStanislav Gatev         }
30148fcdd625SStanislav Gatev       }
30158fcdd625SStanislav Gatev     }
301658fe7f96SSam Estep   )code");
30178fcdd625SStanislav Gatev 
301858fe7f96SSam Estep   ExpectDiagnosticsFor(R"code(
30198fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
30208fcdd625SStanislav Gatev 
30218fcdd625SStanislav Gatev     void target(bool b, $ns::$optional<int> opt) {
30228fcdd625SStanislav Gatev       if (b && !opt.has_value()) return;
30238fcdd625SStanislav Gatev       if (b) {
30248fcdd625SStanislav Gatev         opt.value();
30258fcdd625SStanislav Gatev       }
30268fcdd625SStanislav Gatev     }
302758fe7f96SSam Estep   )code");
30288fcdd625SStanislav Gatev 
302958fe7f96SSam Estep   ExpectDiagnosticsFor(
30308fcdd625SStanislav Gatev       R"code(
30318fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
30328fcdd625SStanislav Gatev 
30338fcdd625SStanislav Gatev     void target(bool b, $ns::$optional<int> opt) {
30348fcdd625SStanislav Gatev       if (opt.has_value()) b = true;
30358fcdd625SStanislav Gatev       if (b) {
303658fe7f96SSam Estep         opt.value(); // [[unsafe]]
30378fcdd625SStanislav Gatev       }
30388fcdd625SStanislav Gatev     }
303958fe7f96SSam Estep   )code");
30408fcdd625SStanislav Gatev 
304158fe7f96SSam Estep   ExpectDiagnosticsFor(R"code(
30428fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
30438fcdd625SStanislav Gatev 
30448fcdd625SStanislav Gatev     void target(bool b, $ns::$optional<int> opt) {
30458fcdd625SStanislav Gatev       if (b) return;
30468fcdd625SStanislav Gatev       if (opt.has_value()) b = true;
30478fcdd625SStanislav Gatev       if (b) {
30488fcdd625SStanislav Gatev         opt.value();
30498fcdd625SStanislav Gatev       }
30508fcdd625SStanislav Gatev     }
305158fe7f96SSam Estep   )code");
30528fcdd625SStanislav Gatev 
305358fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
30548fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
30558fcdd625SStanislav Gatev 
30568fcdd625SStanislav Gatev     void target(bool b, $ns::$optional<int> opt) {
30578fcdd625SStanislav Gatev       if (opt.has_value() == b) {
30588fcdd625SStanislav Gatev         if (b) {
30598fcdd625SStanislav Gatev           opt.value();
30608fcdd625SStanislav Gatev         }
30618fcdd625SStanislav Gatev       }
30628fcdd625SStanislav Gatev     }
306358fe7f96SSam Estep   )");
30648fcdd625SStanislav Gatev 
306558fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
30668fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
30678fcdd625SStanislav Gatev 
30688fcdd625SStanislav Gatev     void target(bool b, $ns::$optional<int> opt) {
30698fcdd625SStanislav Gatev       if (opt.has_value() != b) {
30708fcdd625SStanislav Gatev         if (!b) {
30718fcdd625SStanislav Gatev           opt.value();
30728fcdd625SStanislav Gatev         }
30738fcdd625SStanislav Gatev       }
30748fcdd625SStanislav Gatev     }
307558fe7f96SSam Estep   )");
30768fcdd625SStanislav Gatev 
307758fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
30788fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
30798fcdd625SStanislav Gatev 
30808fcdd625SStanislav Gatev     void target(bool b) {
30818fcdd625SStanislav Gatev       $ns::$optional<int> opt1 = $ns::nullopt;
30828fcdd625SStanislav Gatev       $ns::$optional<int> opt2;
30838fcdd625SStanislav Gatev       if (b) {
30848fcdd625SStanislav Gatev         opt2 = $ns::nullopt;
30858fcdd625SStanislav Gatev       } else {
30868fcdd625SStanislav Gatev         opt2 = $ns::nullopt;
30878fcdd625SStanislav Gatev       }
30888fcdd625SStanislav Gatev       if (opt2.has_value()) {
30898fcdd625SStanislav Gatev         opt1.value();
30908fcdd625SStanislav Gatev       }
30918fcdd625SStanislav Gatev     }
309258fe7f96SSam Estep   )");
30938fcdd625SStanislav Gatev }
30948fcdd625SStanislav Gatev 
30958fcdd625SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, JoinDistinctValues) {
309658fe7f96SSam Estep   ExpectDiagnosticsFor(
30978fcdd625SStanislav Gatev       R"code(
30988fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
30998fcdd625SStanislav Gatev 
31008fcdd625SStanislav Gatev     void target(bool b) {
31018fcdd625SStanislav Gatev       $ns::$optional<int> opt;
31028fcdd625SStanislav Gatev       if (b) {
31038fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
31048fcdd625SStanislav Gatev       } else {
31058fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
31068fcdd625SStanislav Gatev       }
31078fcdd625SStanislav Gatev       if (opt.has_value()) {
31088fcdd625SStanislav Gatev         opt.value();
31098fcdd625SStanislav Gatev       } else {
311058fe7f96SSam Estep         opt.value(); // [[unsafe]]
31118fcdd625SStanislav Gatev       }
31128fcdd625SStanislav Gatev     }
311358fe7f96SSam Estep   )code");
31148fcdd625SStanislav Gatev 
311558fe7f96SSam Estep   ExpectDiagnosticsFor(R"code(
31168fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
31178fcdd625SStanislav Gatev 
31188fcdd625SStanislav Gatev     void target(bool b) {
31198fcdd625SStanislav Gatev       $ns::$optional<int> opt;
31208fcdd625SStanislav Gatev       if (b) {
31218fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
31228fcdd625SStanislav Gatev         if (!opt.has_value()) return;
31238fcdd625SStanislav Gatev       } else {
31248fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
31258fcdd625SStanislav Gatev         if (!opt.has_value()) return;
31268fcdd625SStanislav Gatev       }
31278fcdd625SStanislav Gatev       opt.value();
31288fcdd625SStanislav Gatev     }
312958fe7f96SSam Estep   )code");
31308fcdd625SStanislav Gatev 
313158fe7f96SSam Estep   ExpectDiagnosticsFor(
31328fcdd625SStanislav Gatev       R"code(
31338fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
31348fcdd625SStanislav Gatev 
31358fcdd625SStanislav Gatev     void target(bool b) {
31368fcdd625SStanislav Gatev       $ns::$optional<int> opt;
31378fcdd625SStanislav Gatev       if (b) {
31388fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
31398fcdd625SStanislav Gatev         if (!opt.has_value()) return;
31408fcdd625SStanislav Gatev       } else {
31418fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
31428fcdd625SStanislav Gatev       }
314358fe7f96SSam Estep       opt.value(); // [[unsafe]]
31448fcdd625SStanislav Gatev     }
314558fe7f96SSam Estep   )code");
31468fcdd625SStanislav Gatev 
314758fe7f96SSam Estep   ExpectDiagnosticsFor(
31488fcdd625SStanislav Gatev       R"code(
31498fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
31508fcdd625SStanislav Gatev 
31518fcdd625SStanislav Gatev     void target(bool b) {
31528fcdd625SStanislav Gatev       $ns::$optional<int> opt;
31538fcdd625SStanislav Gatev       if (b) {
31548fcdd625SStanislav Gatev         opt = 1;
31558fcdd625SStanislav Gatev       } else {
31568fcdd625SStanislav Gatev         opt = 2;
31578fcdd625SStanislav Gatev       }
31588fcdd625SStanislav Gatev       opt.value();
31598fcdd625SStanislav Gatev     }
316058fe7f96SSam Estep   )code");
31618fcdd625SStanislav Gatev 
316258fe7f96SSam Estep   ExpectDiagnosticsFor(
31638fcdd625SStanislav Gatev       R"code(
31648fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
31658fcdd625SStanislav Gatev 
31668fcdd625SStanislav Gatev     void target(bool b) {
31678fcdd625SStanislav Gatev       $ns::$optional<int> opt;
31688fcdd625SStanislav Gatev       if (b) {
31698fcdd625SStanislav Gatev         opt = 1;
31708fcdd625SStanislav Gatev       } else {
31718fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
31728fcdd625SStanislav Gatev       }
317358fe7f96SSam Estep       opt.value(); // [[unsafe]]
31748fcdd625SStanislav Gatev     }
317558fe7f96SSam Estep   )code");
31768fcdd625SStanislav Gatev }
31778fcdd625SStanislav Gatev 
3178d34fbf2dSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, AccessValueInLoop) {
317958fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
31808fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
31818fcdd625SStanislav Gatev 
31828fcdd625SStanislav Gatev     void target() {
31838fcdd625SStanislav Gatev       $ns::$optional<int> opt = 3;
31848fcdd625SStanislav Gatev       while (Make<bool>()) {
31858fcdd625SStanislav Gatev         opt.value();
31868fcdd625SStanislav Gatev       }
31878fcdd625SStanislav Gatev     }
318858fe7f96SSam Estep   )");
3189d34fbf2dSYitzhak Mandelbaum }
31908fcdd625SStanislav Gatev 
3191d34fbf2dSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopWithCheckSafe) {
319258fe7f96SSam Estep   ExpectDiagnosticsFor(R"(
31938fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
31948fcdd625SStanislav Gatev 
31958fcdd625SStanislav Gatev     void target() {
31968fcdd625SStanislav Gatev       $ns::$optional<int> opt = 3;
31978fcdd625SStanislav Gatev       while (Make<bool>()) {
31988fcdd625SStanislav Gatev         opt.value();
31998fcdd625SStanislav Gatev 
32008fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
32018fcdd625SStanislav Gatev         if (!opt.has_value()) return;
32028fcdd625SStanislav Gatev       }
32038fcdd625SStanislav Gatev     }
320458fe7f96SSam Estep   )");
3205d34fbf2dSYitzhak Mandelbaum }
32068fcdd625SStanislav Gatev 
3207d34fbf2dSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopNoCheckUnsafe) {
320858fe7f96SSam Estep   ExpectDiagnosticsFor(
32098fcdd625SStanislav Gatev       R"(
32108fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
32118fcdd625SStanislav Gatev 
32128fcdd625SStanislav Gatev     void target() {
32138fcdd625SStanislav Gatev       $ns::$optional<int> opt = 3;
32148fcdd625SStanislav Gatev       while (Make<bool>()) {
321558fe7f96SSam Estep         opt.value(); // [[unsafe]]
32168fcdd625SStanislav Gatev 
32178fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
32188fcdd625SStanislav Gatev       }
32198fcdd625SStanislav Gatev     }
322058fe7f96SSam Estep   )");
3221d34fbf2dSYitzhak Mandelbaum }
32228fcdd625SStanislav Gatev 
3223d34fbf2dSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnsetUnsafe) {
3224d34fbf2dSYitzhak Mandelbaum   ExpectDiagnosticsFor(
3225d34fbf2dSYitzhak Mandelbaum       R"(
3226d34fbf2dSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
3227d34fbf2dSYitzhak Mandelbaum 
3228d34fbf2dSYitzhak Mandelbaum     void target() {
3229d34fbf2dSYitzhak Mandelbaum       $ns::$optional<int> opt = 3;
3230d34fbf2dSYitzhak Mandelbaum       while (Make<bool>())
3231d34fbf2dSYitzhak Mandelbaum         opt = $ns::nullopt;
3232d34fbf2dSYitzhak Mandelbaum       $ns::$optional<int> opt2 = $ns::nullopt;
3233d34fbf2dSYitzhak Mandelbaum       if (opt.has_value())
3234d34fbf2dSYitzhak Mandelbaum         opt2 = $ns::$optional<int>(3);
3235d34fbf2dSYitzhak Mandelbaum       opt2.value(); // [[unsafe]]
3236d34fbf2dSYitzhak Mandelbaum     }
3237d34fbf2dSYitzhak Mandelbaum   )");
3238d34fbf2dSYitzhak Mandelbaum }
3239d34fbf2dSYitzhak Mandelbaum 
3240d34fbf2dSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToSetUnsafe) {
3241d34fbf2dSYitzhak Mandelbaum   ExpectDiagnosticsFor(
3242d34fbf2dSYitzhak Mandelbaum       R"(
3243d34fbf2dSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
3244d34fbf2dSYitzhak Mandelbaum 
3245d34fbf2dSYitzhak Mandelbaum     void target() {
3246d34fbf2dSYitzhak Mandelbaum       $ns::$optional<int> opt = $ns::nullopt;
3247d34fbf2dSYitzhak Mandelbaum       while (Make<bool>())
3248d34fbf2dSYitzhak Mandelbaum         opt = $ns::$optional<int>(3);
3249d34fbf2dSYitzhak Mandelbaum       $ns::$optional<int> opt2 = $ns::nullopt;
3250d34fbf2dSYitzhak Mandelbaum       if (!opt.has_value())
3251d34fbf2dSYitzhak Mandelbaum         opt2 = $ns::$optional<int>(3);
3252d34fbf2dSYitzhak Mandelbaum       opt2.value(); // [[unsafe]]
3253d34fbf2dSYitzhak Mandelbaum     }
3254d34fbf2dSYitzhak Mandelbaum   )");
3255d34fbf2dSYitzhak Mandelbaum }
3256d34fbf2dSYitzhak Mandelbaum 
3257d34fbf2dSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopToUnknownUnsafe) {
3258d34fbf2dSYitzhak Mandelbaum   ExpectDiagnosticsFor(
3259d34fbf2dSYitzhak Mandelbaum       R"(
3260d34fbf2dSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
3261d34fbf2dSYitzhak Mandelbaum 
3262d34fbf2dSYitzhak Mandelbaum     void target() {
3263d34fbf2dSYitzhak Mandelbaum       $ns::$optional<int> opt = $ns::nullopt;
3264d34fbf2dSYitzhak Mandelbaum       while (Make<bool>())
3265d34fbf2dSYitzhak Mandelbaum         opt = Make<$ns::$optional<int>>();
3266d34fbf2dSYitzhak Mandelbaum       $ns::$optional<int> opt2 = $ns::nullopt;
3267d34fbf2dSYitzhak Mandelbaum       if (!opt.has_value())
3268d34fbf2dSYitzhak Mandelbaum         opt2 = $ns::$optional<int>(3);
3269d34fbf2dSYitzhak Mandelbaum       opt2.value(); // [[unsafe]]
3270d34fbf2dSYitzhak Mandelbaum     }
3271d34fbf2dSYitzhak Mandelbaum   )");
3272d34fbf2dSYitzhak Mandelbaum }
3273d34fbf2dSYitzhak Mandelbaum 
3274d34fbf2dSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, ReassignValueInLoopBadConditionUnsafe) {
327558fe7f96SSam Estep   ExpectDiagnosticsFor(
32768fcdd625SStanislav Gatev       R"(
32778fcdd625SStanislav Gatev     #include "unchecked_optional_access_test.h"
32788fcdd625SStanislav Gatev 
32798fcdd625SStanislav Gatev     void target() {
32808fcdd625SStanislav Gatev       $ns::$optional<int> opt = 3;
32818fcdd625SStanislav Gatev       while (Make<bool>()) {
328258fe7f96SSam Estep         opt.value(); // [[unsafe]]
32838fcdd625SStanislav Gatev 
32848fcdd625SStanislav Gatev         opt = Make<$ns::$optional<int>>();
32858fcdd625SStanislav Gatev         if (!opt.has_value()) continue;
32868fcdd625SStanislav Gatev       }
32878fcdd625SStanislav Gatev     }
328858fe7f96SSam Estep   )");
32898fcdd625SStanislav Gatev }
32908fcdd625SStanislav Gatev 
3291ef463545SYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromStruct) {
3292ef463545SYitzhak Mandelbaum   ExpectDiagnosticsFor(R"(
3293ef463545SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
3294ef463545SYitzhak Mandelbaum 
3295ef463545SYitzhak Mandelbaum     struct kv { $ns::$optional<int> opt; int x; };
3296ef463545SYitzhak Mandelbaum     int target() {
3297ef463545SYitzhak Mandelbaum       auto [contents, x] = Make<kv>();
3298ef463545SYitzhak Mandelbaum       return contents ? *contents : x;
3299ef463545SYitzhak Mandelbaum     }
3300ef463545SYitzhak Mandelbaum   )");
3301ef463545SYitzhak Mandelbaum 
3302ef463545SYitzhak Mandelbaum   ExpectDiagnosticsFor(R"(
3303ef463545SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
3304ef463545SYitzhak Mandelbaum 
3305ef463545SYitzhak Mandelbaum     template <typename T1, typename T2>
3306ef463545SYitzhak Mandelbaum     struct pair { T1 fst;  T2 snd; };
3307ef463545SYitzhak Mandelbaum     int target() {
3308ef463545SYitzhak Mandelbaum       auto [contents, x] = Make<pair<$ns::$optional<int>, int>>();
3309ef463545SYitzhak Mandelbaum       return contents ? *contents : x;
3310ef463545SYitzhak Mandelbaum     }
3311ef463545SYitzhak Mandelbaum   )");
3312ef463545SYitzhak Mandelbaum }
3313ef463545SYitzhak Mandelbaum 
3314ef463545SYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, StructuredBindingsFromTupleLikeType) {
3315ef463545SYitzhak Mandelbaum   ExpectDiagnosticsFor(R"(
3316ef463545SYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
3317ef463545SYitzhak Mandelbaum 
3318ef463545SYitzhak Mandelbaum     namespace std {
3319ef463545SYitzhak Mandelbaum     template <class> struct tuple_size;
3320ef463545SYitzhak Mandelbaum     template <size_t, class> struct tuple_element;
3321ef463545SYitzhak Mandelbaum     template <class...> class tuple;
3322ef463545SYitzhak Mandelbaum 
3323ef463545SYitzhak Mandelbaum     template <class... T>
3324ef463545SYitzhak Mandelbaum     struct tuple_size<tuple<T...>> : integral_constant<size_t, sizeof...(T)> {};
3325ef463545SYitzhak Mandelbaum 
3326ef463545SYitzhak Mandelbaum     template <size_t I, class... T>
3327ef463545SYitzhak Mandelbaum     struct tuple_element<I, tuple<T...>> {
3328ef463545SYitzhak Mandelbaum       using type =  __type_pack_element<I, T...>;
3329ef463545SYitzhak Mandelbaum     };
3330ef463545SYitzhak Mandelbaum 
3331ef463545SYitzhak Mandelbaum     template <class...> class tuple {};
3332ef463545SYitzhak Mandelbaum     template <size_t I, class... T>
3333ef463545SYitzhak Mandelbaum     typename tuple_element<I, tuple<T...>>::type get(tuple<T...>);
3334ef463545SYitzhak Mandelbaum     } // namespace std
3335ef463545SYitzhak Mandelbaum 
3336ef463545SYitzhak Mandelbaum     std::tuple<$ns::$optional<const char *>, int> get_opt();
3337ef463545SYitzhak Mandelbaum     void target() {
3338ef463545SYitzhak Mandelbaum       auto [content, ck] = get_opt();
3339ef463545SYitzhak Mandelbaum       content ? *content : "";
3340ef463545SYitzhak Mandelbaum     }
3341ef463545SYitzhak Mandelbaum   )");
3342ef463545SYitzhak Mandelbaum }
3343ef463545SYitzhak Mandelbaum 
33440e8d4a6dSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, CtorInitializerNullopt) {
33450e8d4a6dSYitzhak Mandelbaum   using namespace ast_matchers;
33460e8d4a6dSYitzhak Mandelbaum   ExpectDiagnosticsFor(
33470e8d4a6dSYitzhak Mandelbaum       R"(
33480e8d4a6dSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
33490e8d4a6dSYitzhak Mandelbaum 
33500e8d4a6dSYitzhak Mandelbaum     struct Target {
33510e8d4a6dSYitzhak Mandelbaum       Target(): opt($ns::nullopt) {
33520e8d4a6dSYitzhak Mandelbaum         opt.value(); // [[unsafe]]
33530e8d4a6dSYitzhak Mandelbaum       }
33540e8d4a6dSYitzhak Mandelbaum       $ns::$optional<int> opt;
33550e8d4a6dSYitzhak Mandelbaum     };
33560e8d4a6dSYitzhak Mandelbaum   )",
33570e8d4a6dSYitzhak Mandelbaum       cxxConstructorDecl(ofClass(hasName("Target"))));
33580e8d4a6dSYitzhak Mandelbaum }
33590e8d4a6dSYitzhak Mandelbaum 
33600e8d4a6dSYitzhak Mandelbaum TEST_P(UncheckedOptionalAccessTest, CtorInitializerValue) {
33610e8d4a6dSYitzhak Mandelbaum   using namespace ast_matchers;
33620e8d4a6dSYitzhak Mandelbaum   ExpectDiagnosticsFor(
33630e8d4a6dSYitzhak Mandelbaum       R"(
33640e8d4a6dSYitzhak Mandelbaum     #include "unchecked_optional_access_test.h"
33650e8d4a6dSYitzhak Mandelbaum 
33660e8d4a6dSYitzhak Mandelbaum     struct Target {
33670e8d4a6dSYitzhak Mandelbaum       Target(): opt(3) {
33680e8d4a6dSYitzhak Mandelbaum         opt.value();
33690e8d4a6dSYitzhak Mandelbaum       }
33700e8d4a6dSYitzhak Mandelbaum       $ns::$optional<int> opt;
33710e8d4a6dSYitzhak Mandelbaum     };
33720e8d4a6dSYitzhak Mandelbaum   )",
33730e8d4a6dSYitzhak Mandelbaum       cxxConstructorDecl(ofClass(hasName("Target"))));
33740e8d4a6dSYitzhak Mandelbaum }
33750e8d4a6dSYitzhak Mandelbaum 
3376eda2eaabSJun Zhang // This is regression test, it shouldn't crash.
3377eda2eaabSJun Zhang TEST_P(UncheckedOptionalAccessTest, Bitfield) {
3378eda2eaabSJun Zhang   using namespace ast_matchers;
3379eda2eaabSJun Zhang   ExpectDiagnosticsFor(
3380eda2eaabSJun Zhang       R"(
3381eda2eaabSJun Zhang     #include "unchecked_optional_access_test.h"
3382eda2eaabSJun Zhang     struct Dst {
3383eda2eaabSJun Zhang       unsigned int n : 1;
3384eda2eaabSJun Zhang     };
3385eda2eaabSJun Zhang     void target() {
3386eda2eaabSJun Zhang       $ns::$optional<bool> v;
3387eda2eaabSJun Zhang       Dst d;
3388eda2eaabSJun Zhang       if (v.has_value())
3389eda2eaabSJun Zhang         d.n = v.value();
3390eda2eaabSJun Zhang     }
3391eda2eaabSJun Zhang   )");
3392eda2eaabSJun Zhang }
339352d06963SStanislav Gatev 
339452d06963SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, LambdaParam) {
339552d06963SStanislav Gatev   ExpectDiagnosticsForLambda(R"(
339652d06963SStanislav Gatev     #include "unchecked_optional_access_test.h"
339752d06963SStanislav Gatev 
339852d06963SStanislav Gatev     void target() {
339952d06963SStanislav Gatev       []($ns::$optional<int> opt) {
340052d06963SStanislav Gatev         if (opt.has_value()) {
340152d06963SStanislav Gatev           opt.value();
340252d06963SStanislav Gatev         } else {
340352d06963SStanislav Gatev           opt.value(); // [[unsafe]]
340452d06963SStanislav Gatev         }
340552d06963SStanislav Gatev       }(Make<$ns::$optional<int>>());
340652d06963SStanislav Gatev     }
340752d06963SStanislav Gatev   )");
340852d06963SStanislav Gatev }
340952d06963SStanislav Gatev 
341052d06963SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopy) {
341152d06963SStanislav Gatev   ExpectDiagnosticsForLambda(R"(
341252d06963SStanislav Gatev     #include "unchecked_optional_access_test.h"
341352d06963SStanislav Gatev 
341452d06963SStanislav Gatev     void target($ns::$optional<int> opt) {
341552d06963SStanislav Gatev       [opt]() {
341652d06963SStanislav Gatev         if (opt.has_value()) {
341752d06963SStanislav Gatev           opt.value();
341852d06963SStanislav Gatev         } else {
341952d06963SStanislav Gatev           opt.value(); // [[unsafe]]
342052d06963SStanislav Gatev         }
342152d06963SStanislav Gatev       }();
342252d06963SStanislav Gatev     }
342352d06963SStanislav Gatev   )");
342452d06963SStanislav Gatev }
342552d06963SStanislav Gatev 
342652d06963SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReference) {
342752d06963SStanislav Gatev   ExpectDiagnosticsForLambda(R"(
342852d06963SStanislav Gatev     #include "unchecked_optional_access_test.h"
342952d06963SStanislav Gatev 
343052d06963SStanislav Gatev     void target($ns::$optional<int> opt) {
343152d06963SStanislav Gatev       [&opt]() {
343252d06963SStanislav Gatev         if (opt.has_value()) {
343352d06963SStanislav Gatev           opt.value();
343452d06963SStanislav Gatev         } else {
343552d06963SStanislav Gatev           opt.value(); // [[unsafe]]
343652d06963SStanislav Gatev         }
343752d06963SStanislav Gatev       }();
343852d06963SStanislav Gatev     }
343952d06963SStanislav Gatev   )");
344052d06963SStanislav Gatev }
344152d06963SStanislav Gatev 
344252d06963SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, LambdaCaptureWithInitializer) {
344352d06963SStanislav Gatev   ExpectDiagnosticsForLambda(R"(
344452d06963SStanislav Gatev     #include "unchecked_optional_access_test.h"
344552d06963SStanislav Gatev 
344652d06963SStanislav Gatev     void target($ns::$optional<int> opt) {
344752d06963SStanislav Gatev       [opt2=opt]() {
344852d06963SStanislav Gatev         if (opt2.has_value()) {
344952d06963SStanislav Gatev           opt2.value();
345052d06963SStanislav Gatev         } else {
345152d06963SStanislav Gatev           opt2.value(); // [[unsafe]]
345252d06963SStanislav Gatev         }
345352d06963SStanislav Gatev       }();
345452d06963SStanislav Gatev     }
345552d06963SStanislav Gatev   )");
345652d06963SStanislav Gatev }
345752d06963SStanislav Gatev 
345852d06963SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByCopyImplicit) {
345952d06963SStanislav Gatev   ExpectDiagnosticsForLambda(R"(
346052d06963SStanislav Gatev     #include "unchecked_optional_access_test.h"
346152d06963SStanislav Gatev 
346252d06963SStanislav Gatev     void target($ns::$optional<int> opt) {
346352d06963SStanislav Gatev       [=]() {
346452d06963SStanislav Gatev         if (opt.has_value()) {
346552d06963SStanislav Gatev           opt.value();
346652d06963SStanislav Gatev         } else {
346752d06963SStanislav Gatev           opt.value(); // [[unsafe]]
346852d06963SStanislav Gatev         }
346952d06963SStanislav Gatev       }();
347052d06963SStanislav Gatev     }
347152d06963SStanislav Gatev   )");
347252d06963SStanislav Gatev }
347352d06963SStanislav Gatev 
347452d06963SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, LambdaCaptureByReferenceImplicit) {
347552d06963SStanislav Gatev   ExpectDiagnosticsForLambda(R"(
347652d06963SStanislav Gatev     #include "unchecked_optional_access_test.h"
347752d06963SStanislav Gatev 
347852d06963SStanislav Gatev     void target($ns::$optional<int> opt) {
347952d06963SStanislav Gatev       [&]() {
348052d06963SStanislav Gatev         if (opt.has_value()) {
348152d06963SStanislav Gatev           opt.value();
348252d06963SStanislav Gatev         } else {
348352d06963SStanislav Gatev           opt.value(); // [[unsafe]]
348452d06963SStanislav Gatev         }
348552d06963SStanislav Gatev       }();
348652d06963SStanislav Gatev     }
348752d06963SStanislav Gatev   )");
348852d06963SStanislav Gatev }
348952d06963SStanislav Gatev 
349052d06963SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, LambdaCaptureThis) {
349152d06963SStanislav Gatev   ExpectDiagnosticsForLambda(R"(
349252d06963SStanislav Gatev     #include "unchecked_optional_access_test.h"
349352d06963SStanislav Gatev 
349452d06963SStanislav Gatev     struct Foo {
349552d06963SStanislav Gatev       $ns::$optional<int> opt;
349652d06963SStanislav Gatev 
349752d06963SStanislav Gatev       void target() {
349852d06963SStanislav Gatev         [this]() {
349952d06963SStanislav Gatev           if (opt.has_value()) {
350052d06963SStanislav Gatev             opt.value();
350152d06963SStanislav Gatev           } else {
350252d06963SStanislav Gatev             opt.value(); // [[unsafe]]
350352d06963SStanislav Gatev           }
350452d06963SStanislav Gatev         }();
350552d06963SStanislav Gatev       }
350652d06963SStanislav Gatev     };
350752d06963SStanislav Gatev   )");
350852d06963SStanislav Gatev }
350952d06963SStanislav Gatev 
351052d06963SStanislav Gatev TEST_P(UncheckedOptionalAccessTest, LambdaCaptureStateNotPropagated) {
351152d06963SStanislav Gatev   // We can't propagate information from the surrounding context.
351252d06963SStanislav Gatev   ExpectDiagnosticsForLambda(R"(
351352d06963SStanislav Gatev     #include "unchecked_optional_access_test.h"
351452d06963SStanislav Gatev 
351552d06963SStanislav Gatev     void target($ns::$optional<int> opt) {
351652d06963SStanislav Gatev       if (opt.has_value()) {
351752d06963SStanislav Gatev         [&opt]() {
351852d06963SStanislav Gatev           opt.value(); // [[unsafe]]
351952d06963SStanislav Gatev         }();
352052d06963SStanislav Gatev       }
352152d06963SStanislav Gatev     }
352252d06963SStanislav Gatev   )");
352352d06963SStanislav Gatev }
3524d712c5edSmartinboehme 
3525d712c5edSmartinboehme TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptional) {
3526d712c5edSmartinboehme   ExpectDiagnosticsFor(R"(
3527d712c5edSmartinboehme     #include "unchecked_optional_access_test.h"
3528d712c5edSmartinboehme 
3529d712c5edSmartinboehme     struct Derived : public $ns::$optional<int> {};
3530d712c5edSmartinboehme 
3531d712c5edSmartinboehme     void target(Derived opt) {
3532d712c5edSmartinboehme       *opt;  // [[unsafe]]
3533d712c5edSmartinboehme       if (opt.has_value())
3534d712c5edSmartinboehme         *opt;
3535d712c5edSmartinboehme 
3536d712c5edSmartinboehme       // The same thing, but with a pointer receiver.
3537d712c5edSmartinboehme       Derived *popt = &opt;
3538d712c5edSmartinboehme       **popt;  // [[unsafe]]
3539d712c5edSmartinboehme       if (popt->has_value())
3540d712c5edSmartinboehme         **popt;
3541d712c5edSmartinboehme     }
3542d712c5edSmartinboehme   )");
3543d712c5edSmartinboehme }
3544d712c5edSmartinboehme 
3545d712c5edSmartinboehme TEST_P(UncheckedOptionalAccessTest, ClassTemplateDerivedFromOptional) {
3546d712c5edSmartinboehme   ExpectDiagnosticsFor(R"(
3547d712c5edSmartinboehme     #include "unchecked_optional_access_test.h"
3548d712c5edSmartinboehme 
3549d712c5edSmartinboehme     template <class T>
3550d712c5edSmartinboehme     struct Derived : public $ns::$optional<T> {};
3551d712c5edSmartinboehme 
3552d712c5edSmartinboehme     void target(Derived<int> opt) {
3553d712c5edSmartinboehme       *opt;  // [[unsafe]]
3554d712c5edSmartinboehme       if (opt.has_value())
3555d712c5edSmartinboehme         *opt;
3556d712c5edSmartinboehme 
3557d712c5edSmartinboehme       // The same thing, but with a pointer receiver.
3558d712c5edSmartinboehme       Derived<int> *popt = &opt;
3559d712c5edSmartinboehme       **popt;  // [[unsafe]]
3560d712c5edSmartinboehme       if (popt->has_value())
3561d712c5edSmartinboehme         **popt;
3562d712c5edSmartinboehme     }
3563d712c5edSmartinboehme   )");
3564d712c5edSmartinboehme }
3565d712c5edSmartinboehme 
3566d712c5edSmartinboehme TEST_P(UncheckedOptionalAccessTest, ClassDerivedPrivatelyFromOptional) {
3567d712c5edSmartinboehme   // Classes that derive privately from optional can themselves still call
3568d712c5edSmartinboehme   // member functions of optional. Check that we model the optional correctly
3569d712c5edSmartinboehme   // in this situation.
3570d712c5edSmartinboehme   ExpectDiagnosticsFor(R"(
3571d712c5edSmartinboehme     #include "unchecked_optional_access_test.h"
3572d712c5edSmartinboehme 
3573d712c5edSmartinboehme     struct Derived : private $ns::$optional<int> {
3574d712c5edSmartinboehme       void Method() {
3575d712c5edSmartinboehme         **this;  // [[unsafe]]
3576d712c5edSmartinboehme         if (this->has_value())
3577d712c5edSmartinboehme           **this;
3578d712c5edSmartinboehme       }
3579d712c5edSmartinboehme     };
3580d712c5edSmartinboehme   )",
3581d712c5edSmartinboehme                        ast_matchers::hasName("Method"));
3582d712c5edSmartinboehme }
3583d712c5edSmartinboehme 
3584ae280281Smartinboehme TEST_P(UncheckedOptionalAccessTest, ClassDerivedFromOptionalValueConstructor) {
3585ae280281Smartinboehme   ExpectDiagnosticsFor(R"(
3586ae280281Smartinboehme     #include "unchecked_optional_access_test.h"
3587ae280281Smartinboehme 
3588ae280281Smartinboehme     struct Derived : public $ns::$optional<int> {
3589ae280281Smartinboehme       Derived(int);
3590ae280281Smartinboehme     };
3591ae280281Smartinboehme 
3592ae280281Smartinboehme     void target(Derived opt) {
3593ae280281Smartinboehme       *opt;  // [[unsafe]]
3594ae280281Smartinboehme       opt = 1;
3595ae280281Smartinboehme       *opt;
3596ae280281Smartinboehme     }
3597ae280281Smartinboehme   )");
3598ae280281Smartinboehme }
3599ae280281Smartinboehme 
36006761b24aSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstRefAccessor) {
36016761b24aSJan Voung   ExpectDiagnosticsFor(R"cc(
36026761b24aSJan Voung     #include "unchecked_optional_access_test.h"
36036761b24aSJan Voung 
36046761b24aSJan Voung     struct A {
36056761b24aSJan Voung       const $ns::$optional<int>& get() const { return x; }
36066761b24aSJan Voung       $ns::$optional<int> x;
36076761b24aSJan Voung     };
36086761b24aSJan Voung 
36096761b24aSJan Voung     void target(A& a) {
36106761b24aSJan Voung       if (a.get().has_value()) {
36116761b24aSJan Voung         a.get().value();
36126761b24aSJan Voung       }
36136761b24aSJan Voung     }
36146761b24aSJan Voung   )cc");
36156761b24aSJan Voung }
36166761b24aSJan Voung 
36176761b24aSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModInBetween) {
36186761b24aSJan Voung   ExpectDiagnosticsFor(R"cc(
36196761b24aSJan Voung     #include "unchecked_optional_access_test.h"
36206761b24aSJan Voung 
36216761b24aSJan Voung     struct A {
36226761b24aSJan Voung       const $ns::$optional<int>& get() const { return x; }
36236761b24aSJan Voung       void clear();
36246761b24aSJan Voung       $ns::$optional<int> x;
36256761b24aSJan Voung     };
36266761b24aSJan Voung 
36276761b24aSJan Voung     void target(A& a) {
36286761b24aSJan Voung       if (a.get().has_value()) {
36296761b24aSJan Voung         a.clear();
36306761b24aSJan Voung         a.get().value();  // [[unsafe]]
36316761b24aSJan Voung       }
36326761b24aSJan Voung     }
36336761b24aSJan Voung   )cc");
36346761b24aSJan Voung }
36356761b24aSJan Voung 
36366761b24aSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorWithModReturningOptional) {
36376761b24aSJan Voung   ExpectDiagnosticsFor(R"cc(
36386761b24aSJan Voung     #include "unchecked_optional_access_test.h"
36396761b24aSJan Voung 
36406761b24aSJan Voung     struct A {
36416761b24aSJan Voung       const $ns::$optional<int>& get() const { return x; }
36426761b24aSJan Voung       $ns::$optional<int> take();
36436761b24aSJan Voung       $ns::$optional<int> x;
36446761b24aSJan Voung     };
36456761b24aSJan Voung 
36466761b24aSJan Voung     void target(A& a) {
36476761b24aSJan Voung       if (a.get().has_value()) {
36486761b24aSJan Voung         $ns::$optional<int> other = a.take();
36496761b24aSJan Voung         a.get().value();  // [[unsafe]]
36506761b24aSJan Voung         if (other.has_value()) {
36516761b24aSJan Voung           other.value();
36526761b24aSJan Voung         }
36536761b24aSJan Voung       }
36546761b24aSJan Voung     }
36556761b24aSJan Voung   )cc");
36566761b24aSJan Voung }
36576761b24aSJan Voung 
36586761b24aSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorDifferentObjects) {
36596761b24aSJan Voung   ExpectDiagnosticsFor(R"cc(
36606761b24aSJan Voung     #include "unchecked_optional_access_test.h"
36616761b24aSJan Voung 
36626761b24aSJan Voung     struct A {
36636761b24aSJan Voung       const $ns::$optional<int>& get() const { return x; }
36646761b24aSJan Voung       $ns::$optional<int> x;
36656761b24aSJan Voung     };
36666761b24aSJan Voung 
36676761b24aSJan Voung     void target(A& a1, A& a2) {
36686761b24aSJan Voung       if (a1.get().has_value()) {
36696761b24aSJan Voung         a2.get().value();  // [[unsafe]]
36706761b24aSJan Voung       }
36716761b24aSJan Voung     }
36726761b24aSJan Voung   )cc");
36736761b24aSJan Voung }
36746761b24aSJan Voung 
36756761b24aSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorLoop) {
36766761b24aSJan Voung   ExpectDiagnosticsFor(R"cc(
36776761b24aSJan Voung     #include "unchecked_optional_access_test.h"
36786761b24aSJan Voung 
36796761b24aSJan Voung     struct A {
36806761b24aSJan Voung       const $ns::$optional<int>& get() const { return x; }
36816761b24aSJan Voung       $ns::$optional<int> x;
36826761b24aSJan Voung     };
36836761b24aSJan Voung 
36846761b24aSJan Voung     void target(A& a, int N) {
36856761b24aSJan Voung       for (int i = 0; i < N; ++i) {
36866761b24aSJan Voung         if (a.get().has_value()) {
36876761b24aSJan Voung           a.get().value();
36886761b24aSJan Voung         }
36896761b24aSJan Voung       }
36906761b24aSJan Voung     }
36916761b24aSJan Voung   )cc");
36926761b24aSJan Voung }
36936761b24aSJan Voung 
36946761b24aSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessor) {
36956761b24aSJan Voung   ExpectDiagnosticsFor(R"cc(
36966761b24aSJan Voung     #include "unchecked_optional_access_test.h"
36976761b24aSJan Voung 
36986761b24aSJan Voung     struct A {
36996761b24aSJan Voung       $ns::$optional<int> get() const { return x; }
37006761b24aSJan Voung       $ns::$optional<int> x;
37016761b24aSJan Voung     };
37026761b24aSJan Voung 
37036761b24aSJan Voung     void target(A& a) {
37046761b24aSJan Voung       if (a.get().has_value()) {
37056761b24aSJan Voung         a.get().value();
37066761b24aSJan Voung       }
37076761b24aSJan Voung     }
37086761b24aSJan Voung   )cc");
37096761b24aSJan Voung }
37106761b24aSJan Voung 
37116761b24aSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessorWithModInBetween) {
37126761b24aSJan Voung   ExpectDiagnosticsFor(R"cc(
37136761b24aSJan Voung     #include "unchecked_optional_access_test.h"
37146761b24aSJan Voung 
37156761b24aSJan Voung     struct A {
37166761b24aSJan Voung       $ns::$optional<int> get() const { return x; }
37176761b24aSJan Voung       void clear();
37186761b24aSJan Voung       $ns::$optional<int> x;
37196761b24aSJan Voung     };
37206761b24aSJan Voung 
37216761b24aSJan Voung     void target(A& a) {
37226761b24aSJan Voung       if (a.get().has_value()) {
37236761b24aSJan Voung         a.clear();
37246761b24aSJan Voung         a.get().value();  // [[unsafe]]
37256761b24aSJan Voung       }
37266761b24aSJan Voung     }
37276761b24aSJan Voung   )cc");
37286761b24aSJan Voung }
37296761b24aSJan Voung 
373066bbbf2eSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstPointerAccessor) {
373166bbbf2eSJan Voung   ExpectDiagnosticsFor(R"cc(
373266bbbf2eSJan Voung      #include "unchecked_optional_access_test.h"
373366bbbf2eSJan Voung 
373466bbbf2eSJan Voung     struct A {
373566bbbf2eSJan Voung       $ns::$optional<int> x;
373666bbbf2eSJan Voung     };
373766bbbf2eSJan Voung 
373866bbbf2eSJan Voung     struct MyUniquePtr {
373966bbbf2eSJan Voung       A* operator->() const;
374066bbbf2eSJan Voung     };
374166bbbf2eSJan Voung 
374266bbbf2eSJan Voung     void target(MyUniquePtr p) {
374366bbbf2eSJan Voung       if (p->x) {
374466bbbf2eSJan Voung         *p->x;
374566bbbf2eSJan Voung       }
374666bbbf2eSJan Voung     }
374766bbbf2eSJan Voung   )cc",
374866bbbf2eSJan Voung                        /*IgnoreSmartPointerDereference=*/false);
374966bbbf2eSJan Voung }
375066bbbf2eSJan Voung 
375166bbbf2eSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstPointerAccessorWithModInBetween) {
375266bbbf2eSJan Voung   ExpectDiagnosticsFor(R"cc(
375366bbbf2eSJan Voung     #include "unchecked_optional_access_test.h"
375466bbbf2eSJan Voung 
375566bbbf2eSJan Voung     struct A {
375666bbbf2eSJan Voung       $ns::$optional<int> x;
375766bbbf2eSJan Voung     };
375866bbbf2eSJan Voung 
375966bbbf2eSJan Voung     struct MyUniquePtr {
376066bbbf2eSJan Voung       A* operator->() const;
376166bbbf2eSJan Voung       void reset(A*);
376266bbbf2eSJan Voung     };
376366bbbf2eSJan Voung 
376466bbbf2eSJan Voung     void target(MyUniquePtr p) {
376566bbbf2eSJan Voung       if (p->x) {
376666bbbf2eSJan Voung         p.reset(nullptr);
376766bbbf2eSJan Voung         *p->x;  // [[unsafe]]
376866bbbf2eSJan Voung       }
376966bbbf2eSJan Voung     }
377066bbbf2eSJan Voung   )cc",
377166bbbf2eSJan Voung                        /*IgnoreSmartPointerDereference=*/false);
377266bbbf2eSJan Voung }
377366bbbf2eSJan Voung 
3774*72a28a3bSJan Voung TEST_P(UncheckedOptionalAccessTest, SmartPointerAccessorMixed) {
3775*72a28a3bSJan Voung   ExpectDiagnosticsFor(R"cc(
3776*72a28a3bSJan Voung      #include "unchecked_optional_access_test.h"
3777*72a28a3bSJan Voung 
3778*72a28a3bSJan Voung     struct A {
3779*72a28a3bSJan Voung       $ns::$optional<int> x;
3780*72a28a3bSJan Voung     };
3781*72a28a3bSJan Voung 
3782*72a28a3bSJan Voung     namespace absl {
3783*72a28a3bSJan Voung     template<typename T>
3784*72a28a3bSJan Voung     class StatusOr {
3785*72a28a3bSJan Voung       public:
3786*72a28a3bSJan Voung       bool ok() const;
3787*72a28a3bSJan Voung 
3788*72a28a3bSJan Voung       const T& operator*() const&;
3789*72a28a3bSJan Voung       T& operator*() &;
3790*72a28a3bSJan Voung 
3791*72a28a3bSJan Voung       const T* operator->() const;
3792*72a28a3bSJan Voung       T* operator->();
3793*72a28a3bSJan Voung 
3794*72a28a3bSJan Voung       const T& value() const;
3795*72a28a3bSJan Voung       T& value();
3796*72a28a3bSJan Voung     };
3797*72a28a3bSJan Voung     }
3798*72a28a3bSJan Voung 
3799*72a28a3bSJan Voung     void target(absl::StatusOr<A> &mut, const absl::StatusOr<A> &imm) {
3800*72a28a3bSJan Voung       if (!mut.ok() || !imm.ok())
3801*72a28a3bSJan Voung         return;
3802*72a28a3bSJan Voung 
3803*72a28a3bSJan Voung       if (mut->x.has_value()) {
3804*72a28a3bSJan Voung         mut->x.value();
3805*72a28a3bSJan Voung         ((*mut).x).value();
3806*72a28a3bSJan Voung         (mut.value().x).value();
3807*72a28a3bSJan Voung 
3808*72a28a3bSJan Voung         // check flagged after modifying
3809*72a28a3bSJan Voung         mut = imm;
3810*72a28a3bSJan Voung         mut->x.value();  // [[unsafe]]
3811*72a28a3bSJan Voung       }
3812*72a28a3bSJan Voung       if (imm->x.has_value()) {
3813*72a28a3bSJan Voung         imm->x.value();
3814*72a28a3bSJan Voung         ((*imm).x).value();
3815*72a28a3bSJan Voung         (imm.value().x).value();
3816*72a28a3bSJan Voung       }
3817*72a28a3bSJan Voung     }
3818*72a28a3bSJan Voung   )cc",
3819*72a28a3bSJan Voung                        /*IgnoreSmartPointerDereference=*/false);
3820*72a28a3bSJan Voung }
3821*72a28a3bSJan Voung 
38226761b24aSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessor) {
38236761b24aSJan Voung   ExpectDiagnosticsFor(R"cc(
38246761b24aSJan Voung     #include "unchecked_optional_access_test.h"
38256761b24aSJan Voung 
38266761b24aSJan Voung     struct A {
38276761b24aSJan Voung       bool isFoo() const { return f; }
38286761b24aSJan Voung       bool f;
38296761b24aSJan Voung     };
38306761b24aSJan Voung 
38316761b24aSJan Voung     void target(A& a) {
38326761b24aSJan Voung       std::optional<int> opt;
38336761b24aSJan Voung       if (a.isFoo()) {
38346761b24aSJan Voung         opt = 1;
38356761b24aSJan Voung       }
38366761b24aSJan Voung       if (a.isFoo()) {
38376761b24aSJan Voung         opt.value();
38386761b24aSJan Voung       }
38396761b24aSJan Voung     }
38406761b24aSJan Voung   )cc");
38416761b24aSJan Voung }
38426761b24aSJan Voung 
38436761b24aSJan Voung TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessorWithModInBetween) {
38446761b24aSJan Voung   ExpectDiagnosticsFor(R"cc(
38456761b24aSJan Voung     #include "unchecked_optional_access_test.h"
38466761b24aSJan Voung 
38476761b24aSJan Voung     struct A {
38486761b24aSJan Voung       bool isFoo() const { return f; }
38496761b24aSJan Voung       void clear();
38506761b24aSJan Voung       bool f;
38516761b24aSJan Voung     };
38526761b24aSJan Voung 
38536761b24aSJan Voung     void target(A& a) {
38546761b24aSJan Voung       std::optional<int> opt;
38556761b24aSJan Voung       if (a.isFoo()) {
38566761b24aSJan Voung         opt = 1;
38576761b24aSJan Voung       }
38586761b24aSJan Voung       a.clear();
38596761b24aSJan Voung       if (a.isFoo()) {
38606761b24aSJan Voung         opt.value();  // [[unsafe]]
38616761b24aSJan Voung       }
38626761b24aSJan Voung     }
38636761b24aSJan Voung   )cc");
38646761b24aSJan Voung }
38656761b24aSJan Voung 
3866af98b0afSStanislav Gatev // FIXME: Add support for:
3867092a530cSStanislav Gatev // - constructors (copy, move)
3868b000b770SStanislav Gatev // - assignment operators (default, copy, move)
3869af98b0afSStanislav Gatev // - invalidation (passing optional by non-const reference/pointer)
3870