Skip to content

Conversation

fmayer
Copy link
Contributor

@fmayer fmayer commented Oct 11, 2025

No description provided.

Created using spr 1.3.4
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html labels Oct 11, 2025
@fmayer fmayer requested a review from jvoung October 11, 2025 04:27
@llvmbot
Copy link
Member

llvmbot commented Oct 11, 2025

@llvm/pr-subscribers-clang

Author: Florian Mayer (fmayer)

Changes

Patch is 84.26 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/162970.diff

5 Files Affected:

  • (modified) clang/unittests/Analysis/FlowSensitive/CMakeLists.txt (+1)
  • (added) clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp (+1259)
  • (added) clang/unittests/Analysis/FlowSensitive/MockHeaders.h (+30)
  • (modified) clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (+2-1236)
  • (modified) llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn (+1)
diff --git a/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt b/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
index 3bd4a6e21bee7..35082387b46e9 100644
--- a/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
+++ b/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_unittest(ClangAnalysisFlowSensitiveTests
   LoggerTest.cpp
   MapLatticeTest.cpp
   MatchSwitchTest.cpp
+  MockHeaders.cpp
   MultiVarConstantPropagationTest.cpp
   RecordOpsTest.cpp
   SignAnalysisTest.cpp
diff --git a/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp
new file mode 100644
index 0000000000000..e70a0c3644e83
--- /dev/null
+++ b/clang/unittests/Analysis/FlowSensitive/MockHeaders.cpp
@@ -0,0 +1,1259 @@
+//===--- MockHeaders.cpp - Mock headers for dataflow analyses -*- C++ ---*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines utilities to simplify testing of dataflow analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MockHeaders.h"
+
+namespace clang {
+namespace dataflow {
+namespace test {
+static constexpr char CSDtdDefHeader[] = R"(
+#ifndef CSTDDEF_H
+#define CSTDDEF_H
+
+namespace std {
+
+typedef decltype(sizeof(char)) size_t;
+
+using nullptr_t = decltype(nullptr);
+
+} // namespace std
+
+#endif // CSTDDEF_H
+)";
+
+static constexpr char StdTypeTraitsHeader[] = R"(
+#ifndef STD_TYPE_TRAITS_H
+#define STD_TYPE_TRAITS_H
+
+#include "cstddef.h"
+
+namespace std {
+
+template <typename T, T V>
+struct integral_constant {
+  static constexpr T value = V;
+};
+
+using true_type = integral_constant<bool, true>;
+using false_type = integral_constant<bool, false>;
+
+template< class T > struct remove_reference      {typedef T type;};
+template< class T > struct remove_reference<T&>  {typedef T type;};
+template< class T > struct remove_reference<T&&> {typedef T type;};
+
+template <class T>
+  using remove_reference_t = typename remove_reference<T>::type;
+
+template <class T>
+struct remove_extent {
+  typedef T type;
+};
+
+template <class T>
+struct remove_extent<T[]> {
+  typedef T type;
+};
+
+template <class T, size_t N>
+struct remove_extent<T[N]> {
+  typedef T type;
+};
+
+template <class T>
+struct is_array : false_type {};
+
+template <class T>
+struct is_array<T[]> : true_type {};
+
+template <class T, size_t N>
+struct is_array<T[N]> : true_type {};
+
+template <class>
+struct is_function : false_type {};
+
+template <class Ret, class... Args>
+struct is_function<Ret(Args...)> : true_type {};
+
+namespace detail {
+
+template <class T>
+struct type_identity {
+  using type = T;
+};  // or use type_identity (since C++20)
+
+template <class T>
+auto try_add_pointer(int) -> type_identity<typename remove_reference<T>::type*>;
+template <class T>
+auto try_add_pointer(...) -> type_identity<T>;
+
+}  // namespace detail
+
+template <class T>
+struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {};
+
+template <bool B, class T, class F>
+struct conditional {
+  typedef T type;
+};
+
+template <class T, class F>
+struct conditional<false, T, F> {
+  typedef F type;
+};
+
+template <class T>
+struct remove_cv {
+  typedef T type;
+};
+template <class T>
+struct remove_cv<const T> {
+  typedef T type;
+};
+template <class T>
+struct remove_cv<volatile T> {
+  typedef T type;
+};
+template <class T>
+struct remove_cv<const volatile T> {
+  typedef T type;
+};
+
+template <class T>
+using remove_cv_t = typename remove_cv<T>::type;
+
+template <class T>
+struct decay {
+ private:
+  typedef typename remove_reference<T>::type U;
+
+ public:
+  typedef typename conditional<
+      is_array<U>::value, typename remove_extent<U>::type*,
+      typename conditional<is_function<U>::value, typename add_pointer<U>::type,
+                           typename remove_cv<U>::type>::type>::type type;
+};
+
+template <bool B, class T = void>
+struct enable_if {};
+
+template <class T>
+struct enable_if<true, T> {
+  typedef T type;
+};
+
+template <bool B, class T = void>
+using enable_if_t = typename enable_if<B, T>::type;
+
+template <class T, class U>
+struct is_same : false_type {};
+
+template <class T>
+struct is_same<T, T> : true_type {};
+
+template <class T>
+struct is_void : is_same<void, typename remove_cv<T>::type> {};
+
+namespace detail {
+
+template <class T>
+auto try_add_lvalue_reference(int) -> type_identity<T&>;
+template <class T>
+auto try_add_lvalue_reference(...) -> type_identity<T>;
+
+template <class T>
+auto try_add_rvalue_reference(int) -> type_identity<T&&>;
+template <class T>
+auto try_add_rvalue_reference(...) -> type_identity<T>;
+
+}  // namespace detail
+
+template <class T>
+struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {
+};
+
+template <class T>
+struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {
+};
+
+template <class T>
+typename add_rvalue_reference<T>::type declval() noexcept;
+
+namespace detail {
+
+template <class T>
+auto test_returnable(int)
+    -> decltype(void(static_cast<T (*)()>(nullptr)), true_type{});
+template <class>
+auto test_returnable(...) -> false_type;
+
+template <class From, class To>
+auto test_implicitly_convertible(int)
+    -> decltype(void(declval<void (&)(To)>()(declval<From>())), true_type{});
+template <class, class>
+auto test_implicitly_convertible(...) -> false_type;
+
+}  // namespace detail
+
+template <class From, class To>
+struct is_convertible
+    : integral_constant<bool,
+                        (decltype(detail::test_returnable<To>(0))::value &&
+                         decltype(detail::test_implicitly_convertible<From, To>(
+                             0))::value) ||
+                            (is_void<From>::value && is_void<To>::value)> {};
+
+template <class From, class To>
+inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
+
+template <class...>
+using void_t = void;
+
+template <class, class T, class... Args>
+struct is_constructible_ : false_type {};
+
+template <class T, class... Args>
+struct is_constructible_<void_t<decltype(T(declval<Args>()...))>, T, Args...>
+    : true_type {};
+
+template <class T, class... Args>
+using is_constructible = is_constructible_<void_t<>, T, Args...>;
+
+template <class T, class... Args>
+inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
+
+template <class _Tp>
+struct __uncvref {
+  typedef typename remove_cv<typename remove_reference<_Tp>::type>::type type;
+};
+
+template <class _Tp>
+using __uncvref_t = typename __uncvref<_Tp>::type;
+
+template <bool _Val>
+using _BoolConstant = integral_constant<bool, _Val>;
+
+template <class _Tp, class _Up>
+using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>;
+
+template <class _Tp, class _Up>
+using _IsNotSame = _BoolConstant<!__is_same(_Tp, _Up)>;
+
+template <bool>
+struct _MetaBase;
+template <>
+struct _MetaBase<true> {
+  template <class _Tp, class _Up>
+  using _SelectImpl = _Tp;
+  template <template <class...> class _FirstFn, template <class...> class,
+            class... _Args>
+  using _SelectApplyImpl = _FirstFn<_Args...>;
+  template <class _First, class...>
+  using _FirstImpl = _First;
+  template <class, class _Second, class...>
+  using _SecondImpl = _Second;
+  template <class _Result, class _First, class... _Rest>
+  using _OrImpl =
+      typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>::
+          template _OrImpl<_First, _Rest...>;
+};
+
+template <>
+struct _MetaBase<false> {
+  template <class _Tp, class _Up>
+  using _SelectImpl = _Up;
+  template <template <class...> class, template <class...> class _SecondFn,
+            class... _Args>
+  using _SelectApplyImpl = _SecondFn<_Args...>;
+  template <class _Result, class...>
+  using _OrImpl = _Result;
+};
+
+template <bool _Cond, class _IfRes, class _ElseRes>
+using _If = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;
+
+template <class... _Rest>
+using _Or = typename _MetaBase<sizeof...(_Rest) !=
+                               0>::template _OrImpl<false_type, _Rest...>;
+
+template <bool _Bp, class _Tp = void>
+using __enable_if_t = typename enable_if<_Bp, _Tp>::type;
+
+template <class...>
+using __expand_to_true = true_type;
+template <class... _Pred>
+__expand_to_true<__enable_if_t<_Pred::value>...> __and_helper(int);
+template <class...>
+false_type __and_helper(...);
+template <class... _Pred>
+using _And = decltype(__and_helper<_Pred...>(0));
+
+template <class _Pred>
+struct _Not : _BoolConstant<!_Pred::value> {};
+
+struct __check_tuple_constructor_fail {
+  static constexpr bool __enable_explicit_default() { return false; }
+  static constexpr bool __enable_implicit_default() { return false; }
+  template <class...>
+  static constexpr bool __enable_explicit() {
+    return false;
+  }
+  template <class...>
+  static constexpr bool __enable_implicit() {
+    return false;
+  }
+};
+
+template <typename, typename _Tp>
+struct __select_2nd {
+  typedef _Tp type;
+};
+template <class _Tp, class _Arg>
+typename __select_2nd<decltype((declval<_Tp>() = declval<_Arg>())),
+                      true_type>::type
+__is_assignable_test(int);
+template <class, class>
+false_type __is_assignable_test(...);
+template <class _Tp, class _Arg,
+          bool = is_void<_Tp>::value || is_void<_Arg>::value>
+struct __is_assignable_imp
+    : public decltype((__is_assignable_test<_Tp, _Arg>(0))) {};
+template <class _Tp, class _Arg>
+struct __is_assignable_imp<_Tp, _Arg, true> : public false_type {};
+template <class _Tp, class _Arg>
+struct is_assignable : public __is_assignable_imp<_Tp, _Arg> {};
+
+template <class _Tp>
+struct __libcpp_is_integral : public false_type {};
+template <>
+struct __libcpp_is_integral<bool> : public true_type {};
+template <>
+struct __libcpp_is_integral<char> : public true_type {};
+template <>
+struct __libcpp_is_integral<signed char> : public true_type {};
+template <>
+struct __libcpp_is_integral<unsigned char> : public true_type {};
+template <>
+struct __libcpp_is_integral<wchar_t> : public true_type {};
+template <>
+struct __libcpp_is_integral<short> : public true_type {};  // NOLINT
+template <>
+struct __libcpp_is_integral<unsigned short> : public true_type {};  // NOLINT
+template <>
+struct __libcpp_is_integral<int> : public true_type {};
+template <>
+struct __libcpp_is_integral<unsigned int> : public true_type {};
+template <>
+struct __libcpp_is_integral<long> : public true_type {};  // NOLINT
+template <>
+struct __libcpp_is_integral<unsigned long> : public true_type {};  // NOLINT
+template <>
+struct __libcpp_is_integral<long long> : public true_type {};  // NOLINT
+template <>                                                    // NOLINTNEXTLINE
+struct __libcpp_is_integral<unsigned long long> : public true_type {};
+template <class _Tp>
+struct is_integral
+    : public __libcpp_is_integral<typename remove_cv<_Tp>::type> {};
+
+template <class _Tp>
+struct __libcpp_is_floating_point : public false_type {};
+template <>
+struct __libcpp_is_floating_point<float> : public true_type {};
+template <>
+struct __libcpp_is_floating_point<double> : public true_type {};
+template <>
+struct __libcpp_is_floating_point<long double> : public true_type {};
+template <class _Tp>
+struct is_floating_point
+    : public __libcpp_is_floating_point<typename remove_cv<_Tp>::type> {};
+
+template <class _Tp>
+struct is_arithmetic
+    : public integral_constant<bool, is_integral<_Tp>::value ||
+                                         is_floating_point<_Tp>::value> {};
+
+template <class _Tp>
+struct __libcpp_is_pointer : public false_type {};
+template <class _Tp>
+struct __libcpp_is_pointer<_Tp*> : public true_type {};
+template <class _Tp>
+struct is_pointer : public __libcpp_is_pointer<typename remove_cv<_Tp>::type> {
+};
+
+template <class _Tp>
+struct __libcpp_is_member_pointer : public false_type {};
+template <class _Tp, class _Up>
+struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type {};
+template <class _Tp>
+struct is_member_pointer
+    : public __libcpp_is_member_pointer<typename remove_cv<_Tp>::type> {};
+
+template <class _Tp>
+struct __libcpp_union : public false_type {};
+template <class _Tp>
+struct is_union : public __libcpp_union<typename remove_cv<_Tp>::type> {};
+
+template <class T>
+struct is_reference : false_type {};
+template <class T>
+struct is_reference<T&> : true_type {};
+template <class T>
+struct is_reference<T&&> : true_type {};
+
+template <class T>
+inline constexpr bool is_reference_v = is_reference<T>::value;
+
+struct __two {
+  char __lx[2];
+};
+
+namespace __is_class_imp {
+template <class _Tp>
+char __test(int _Tp::*);
+template <class _Tp>
+__two __test(...);
+}  // namespace __is_class_imp
+template <class _Tp>
+struct is_class
+    : public integral_constant<bool,
+                               sizeof(__is_class_imp::__test<_Tp>(0)) == 1 &&
+                                   !is_union<_Tp>::value> {};
+
+template <class _Tp>
+struct __is_nullptr_t_impl : public false_type {};
+template <>
+struct __is_nullptr_t_impl<nullptr_t> : public true_type {};
+template <class _Tp>
+struct __is_nullptr_t
+    : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
+template <class _Tp>
+struct is_null_pointer
+    : public __is_nullptr_t_impl<typename remove_cv<_Tp>::type> {};
+
+template <class _Tp>
+struct is_enum
+    : public integral_constant<
+          bool, !is_void<_Tp>::value && !is_integral<_Tp>::value &&
+                    !is_floating_point<_Tp>::value && !is_array<_Tp>::value &&
+                    !is_pointer<_Tp>::value && !is_reference<_Tp>::value &&
+                    !is_member_pointer<_Tp>::value && !is_union<_Tp>::value &&
+                    !is_class<_Tp>::value && !is_function<_Tp>::value> {};
+
+template <class _Tp>
+struct is_scalar
+    : public integral_constant<
+          bool, is_arithmetic<_Tp>::value || is_member_pointer<_Tp>::value ||
+                    is_pointer<_Tp>::value || __is_nullptr_t<_Tp>::value ||
+                    is_enum<_Tp>::value> {};
+template <>
+struct is_scalar<nullptr_t> : public true_type {};
+
+} // namespace std
+
+#endif // STD_TYPE_TRAITS_H
+)";
+
+static constexpr char AbslTypeTraitsHeader[] = R"(
+#ifndef ABSL_TYPE_TRAITS_H
+#define ABSL_TYPE_TRAITS_H
+
+#include "std_type_traits.h"
+
+namespace absl {
+
+template <typename... Ts>
+struct conjunction : std::true_type {};
+
+template <typename T, typename... Ts>
+struct conjunction<T, Ts...>
+    : std::conditional<T::value, conjunction<Ts...>, T>::type {};
+
+template <typename T>
+struct conjunction<T> : T {};
+
+template <typename T>
+struct negation : std::integral_constant<bool, !T::value> {};
+
+template <bool B, typename T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+} // namespace absl
+
+#endif // ABSL_TYPE_TRAITS_H
+)";
+
+static constexpr char StdStringHeader[] = R"(
+#ifndef STRING_H
+#define STRING_H
+
+namespace std {
+
+struct string {
+  string(const char*);
+  ~string();
+  bool empty();
+};
+bool operator!=(const string &LHS, const char *RHS);
+
+} // namespace std
+
+#endif // STRING_H
+)";
+
+static constexpr char StdUtilityHeader[] = R"(
+#ifndef UTILITY_H
+#define UTILITY_H
+
+#include "std_type_traits.h"
+
+namespace std {
+
+template <typename T>
+constexpr remove_reference_t<T>&& move(T&& x);
+
+template <typename T>
+void swap(T& a, T& b) noexcept;
+
+} // namespace std
+
+#endif // UTILITY_H
+)";
+
+static constexpr char StdInitializerListHeader[] = R"(
+#ifndef INITIALIZER_LIST_H
+#define INITIALIZER_LIST_H
+
+namespace std {
+
+template <typename T>
+class initializer_list {
+ public:
+  const T *a, *b;
+  initializer_list() noexcept;
+};
+
+} // namespace std
+
+#endif // INITIALIZER_LIST_H
+)";
+
+static constexpr char StdOptionalHeader[] = R"(
+#include "std_initializer_list.h"
+#include "std_type_traits.h"
+#include "std_utility.h"
+
+namespace std {
+
+struct in_place_t {};
+constexpr in_place_t in_place;
+
+struct nullopt_t {
+  constexpr explicit nullopt_t() {}
+};
+constexpr nullopt_t nullopt;
+
+template <class _Tp>
+struct __optional_destruct_base {
+  constexpr void reset() noexcept;
+};
+
+template <class _Tp>
+struct __optional_storage_base : __optional_destruct_base<_Tp> {
+  constexpr bool has_value() const noexcept;
+};
+
+template <typename _Tp>
+class optional : private __optional_storage_base<_Tp> {
+  using __base = __optional_storage_base<_Tp>;
+
+ public:
+  using value_type = _Tp;
+
+ private:
+  struct _CheckOptionalArgsConstructor {
+    template <class _Up>
+    static constexpr bool __enable_implicit() {
+      return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
+    }
+
+    template <class _Up>
+    static constexpr bool __enable_explicit() {
+      return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
+    }
+  };
+  template <class _Up>
+  using _CheckOptionalArgsCtor =
+      _If<_IsNotSame<__uncvref_t<_Up>, in_place_t>::value &&
+              _IsNotSame<__uncvref_t<_Up>, optional>::value,
+          _CheckOptionalArgsConstructor, __check_tuple_constructor_fail>;
+  template <class _QualUp>
+  struct _CheckOptionalLikeConstructor {
+    template <class _Up, class _Opt = optional<_Up>>
+    using __check_constructible_from_opt =
+        _Or<is_constructible<_Tp, _Opt&>, is_constructible<_Tp, _Opt const&>,
+            is_constructible<_Tp, _Opt&&>, is_constructible<_Tp, _Opt const&&>,
+            is_convertible<_Opt&, _Tp>, is_convertible<_Opt const&, _Tp>,
+            is_convertible<_Opt&&, _Tp>, is_convertible<_Opt const&&, _Tp>>;
+    template <class _Up, class _QUp = _QualUp>
+    static constexpr bool __enable_implicit() {
+      return is_convertible<_QUp, _Tp>::value &&
+             !__check_constructible_from_opt<_Up>::value;
+    }
+    template <class _Up, class _QUp = _QualUp>
+    static constexpr bool __enable_explicit() {
+      return !is_convertible<_QUp, _Tp>::value &&
+             !__check_constructible_from_opt<_Up>::value;
+    }
+  };
+
+  template <class _Up, class _QualUp>
+  using _CheckOptionalLikeCtor =
+      _If<_And<_IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>>::value,
+          _CheckOptionalLikeConstructor<_QualUp>,
+          __check_tuple_constructor_fail>;
+
+
+  template <class _Up, class _QualUp>
+  using _CheckOptionalLikeAssign = _If<
+      _And<
+          _IsNotSame<_Up, _Tp>,
+          is_constructible<_Tp, _QualUp>,
+          is_assignable<_Tp&, _QualUp>
+      >::value,
+      _CheckOptionalLikeConstructor<_QualUp>,
+      __check_tuple_constructor_fail
+    >;
+
+ public:
+  constexpr optional() noexcept {}
+  constexpr optional(const optional&) = default;
+  constexpr optional(optional&&) = default;
+  constexpr optional(nullopt_t) noexcept {}
+
+  template <
+      class _InPlaceT, class... _Args,
+      class = enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>,
+                             is_constructible<value_type, _Args...>>::value>>
+  constexpr explicit optional(_InPlaceT, _Args&&... __args);
+
+  template <class _Up, class... _Args,
+            class = enable_if_t<is_constructible_v<
+                value_type, initializer_list<_Up>&, _Args...>>>
+  constexpr explicit optional(in_place_t, initializer_list<_Up> __il,
+                              _Args&&... __args);
+
+  template <
+      class _Up = value_type,
+      enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(),
+                int> = 0>
+  constexpr optional(_Up&& __v);
+
+  template <
+      class _Up,
+      enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(),
+                int> = 0>
+  constexpr explicit optional(_Up&& __v);
+
+  template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
+                                     template __enable_implicit<_Up>(),
+                                 int> = 0>
+  constexpr optional(const optional<_Up>& __v);
+
+  template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::
+                                  ...
[truncated]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants