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