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