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