xref: /aosp_15_r20/external/cronet/base/functional/unretained_traits.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_FUNCTIONAL_UNRETAINED_TRAITS_H_
6 #define BASE_FUNCTIONAL_UNRETAINED_TRAITS_H_
7 
8 #include <concepts>
9 #include <type_traits>
10 
11 #include "base/types/is_complete.h"
12 #include "build/build_config.h"
13 
14 // Various opaque system types that should still be usable with the base
15 // callback system. Please keep sorted.
16 #define BASE_INTERNAL_LIST_OF_SAFE_FOR_UNRETAINED           \
17   BASE_INTERNAL_SAFE_FOR_UNRETAINED(ANativeWindow)          \
18   BASE_INTERNAL_SAFE_FOR_UNRETAINED(DBusMessage)            \
19   BASE_INTERNAL_SAFE_FOR_UNRETAINED(HWND__)                 \
20   BASE_INTERNAL_SAFE_FOR_UNRETAINED(VkBuffer_T)             \
21   BASE_INTERNAL_SAFE_FOR_UNRETAINED(VkDeviceMemory_T)       \
22   BASE_INTERNAL_SAFE_FOR_UNRETAINED(VkImage_T)              \
23   BASE_INTERNAL_SAFE_FOR_UNRETAINED(VkSemaphore_T)          \
24   BASE_INTERNAL_SAFE_FOR_UNRETAINED(VmaAllocation_T)        \
25   BASE_INTERNAL_SAFE_FOR_UNRETAINED(WGPUAdapterImpl)        \
26   BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_action_t__)        \
27   BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_annotation_t__)    \
28   BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_attachment_t__)    \
29   BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_bookmark_t__)      \
30   BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_document_t__)      \
31   BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_form_handle_t__)   \
32   BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_page_t__)          \
33   BASE_INTERNAL_SAFE_FOR_UNRETAINED(fpdf_structelement_t__) \
34   BASE_INTERNAL_SAFE_FOR_UNRETAINED(hb_set_t)               \
35   BASE_INTERNAL_SAFE_FOR_UNRETAINED(wl_gpu)                 \
36   BASE_INTERNAL_SAFE_FOR_UNRETAINED(wl_shm)                 \
37   BASE_INTERNAL_SAFE_FOR_UNRETAINED(wl_surface)
38 
39 #define BASE_INTERNAL_SAFE_FOR_UNRETAINED(x) struct x;
40 BASE_INTERNAL_LIST_OF_SAFE_FOR_UNRETAINED
41 #undef BASE_INTERNAL_SAFE_FOR_UNRETAINED
42 
43 namespace base::internal {
44 
45 template <typename T, typename... Ts>
46 concept SameAsAny = (std::same_as<T, Ts> || ...);
47 
48 // Determining whether a type can be used with `Unretained()` requires that `T`
49 // be completely defined. Some system types have an intentionally opaque and
50 // incomplete representation, but should still be usable with `Unretained()`.
51 template <typename T>
52 concept SafeIncompleteTypeForUnretained =
53     SameAsAny<std::remove_cvref_t<T>,
54 #define BASE_INTERNAL_SAFE_FOR_UNRETAINED(x) x,
55               BASE_INTERNAL_LIST_OF_SAFE_FOR_UNRETAINED
56 #undef BASE_INTERNAL_SAFE_FOR_UNRETAINED
57               // void* is occasionally used with callbacks; in the future,
58               // this may be more restricted/limited, but allow it for now.
59               void>;
60 
61 // Customization point. Specialize this to be `false` for types as needed. In
62 // general, you should not need this; types that do not support `Unretained()`
63 // should use `DISALLOW_UNRETAINED()`. However, this is necessary when
64 // disallowing `Unretained()` for types that do not (or cannot) use //base.
65 template <typename T>
66 inline constexpr bool kCustomizeSupportsUnretained = true;
67 
68 template <typename T>
69 concept DisallowsUnretained = !kCustomizeSupportsUnretained<T> || requires {
70   // Matches against the marker tag created by the `DISALLOW_UNRETAINED()` macro
71   // in //base/functional/disallow_unretained.h.
72   typename T::DisallowBaseUnretainedMarker;
73 };
74 
75 template <typename T>
76 struct SupportsUnretainedImpl {
77   // For context on this "templated struct with a lambda that asserts" pattern,
78   // see comments in `Invoker<>`.
79   template <bool v = IsComplete<T> || SafeIncompleteTypeForUnretained<T>>
80   struct AllowlistIncompleteTypes {
81     static constexpr bool value = [] {
82 // Incrementally enforce the requirement to be completely defined. For now,
83 // limit the failures to:
84 //
85 // - non-test code
86 // - non-official code (because these builds don't run as part of the default CQ
87 //   and are slower due to PGO and LTO)
88 // - Android, Linux or Windows
89 //
90 // to make this easier to land without potentially breaking the tree.
91 //
92 // TODO(https://crbug.com/1392872): Enable this on all platforms, then in
93 // official builds, and then in non-test code as well.
94 #if defined(FORCE_UNRETAINED_COMPLETENESS_CHECKS_FOR_TESTS) || \
95     (!defined(UNIT_TEST) && !defined(OFFICIAL_BUILD) &&        \
96      (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)))
97       static_assert(v,
98                     "Argument requires unretained storage, but type is not "
99                     "fully defined. This prevents determining whether "
100                     "`Unretained()` is supported.");
101       return v;
102 #else
103       return true;
104 #endif
105     }();
106   };
107 
108   template <bool v = !DisallowsUnretained<T>>
109   struct AllowsUnretained {
110     static constexpr bool value = [] {
111       static_assert(v,
112                     "Argument requires unretained storage, but type does not "
113                     "support `Unretained()`. See "
114                     "base/functional/disallow_unretained.h for alternatives.");
115       return v;
116     }();
117   };
118 
119   static constexpr bool value =
120       std::conjunction_v<AllowlistIncompleteTypes<>, AllowsUnretained<>>;
121 };
122 
123 // Not meant for general use: merely checking this concept will
124 // `static_assert()` if the type does not support unretained. This is meant only
125 // for use inside the `Bind()` machinery, which wants that assertion.
126 //
127 // If we ever want to use this concept outside that machinery, we'll need to not
128 // only move the "allows unretained" assertion from above to the `Bind()` side,
129 // we'll also need to hoist or duplicate the incomplete type check there (and
130 // not assert in that case) so it does not fire multiple `static_assert()`s for
131 // incomplete types.
132 template <typename T>
133 concept SupportsUnretained = SupportsUnretainedImpl<T>::value;
134 
135 }  // namespace base::internal
136 
137 #endif  // BASE_FUNCTIONAL_UNRETAINED_TRAITS_H_
138