// Copyright 2011 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_BIND_INTERNAL_H_ #define BASE_FUNCTIONAL_BIND_INTERNAL_H_ #include <stddef.h> #include <concepts> #include <functional> #include <memory> #include <tuple> #include <type_traits> #include <utility> #include "base/check.h" #include "base/compiler_specific.h" #include "base/functional/callback_internal.h" #include "base/functional/unretained_traits.h" #include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr_asan_bound_arg_tracker.h" #include "base/memory/raw_ref.h" #include "base/memory/raw_scoped_refptr_mismatch_checker.h" #include "base/memory/weak_ptr.h" #include "base/notreached.h" #include "base/types/always_false.h" #include "base/types/is_complete.h" #include "base/types/is_instantiation.h" #include "base/types/to_address.h" #include "build/build_config.h" #include "partition_alloc/buildflags.h" #include "partition_alloc/partition_alloc_config.h" #include "third_party/abseil-cpp/absl/functional/function_ref.h" // See docs/callback.md for user documentation. // // Concepts: // Functor -- A movable type representing something that should be called. // All function pointers and `Callback<>` are functors even if the // invocation syntax differs. // RunType -- A function type (as opposed to function _pointer_ type) for // a `Callback<>::Run()`. Usually just a convenience typedef. // (Bound)Args -- A set of types that stores the arguments. // // Types: // `ForceVoidReturn<>` -- Helper class for translating function signatures to // equivalent forms with a `void` return type. // `FunctorTraits<>` -- Type traits used to determine the correct RunType and // invocation manner for a Functor. This is where // function signature adapters are applied. // `StorageTraits<>` -- Type traits that determine how a bound argument is // stored in `BindState<>`. // `InvokeHelper<>` -- Takes a Functor + arguments and actually invokes it. // Handles the differing syntaxes needed for `WeakPtr<>` // support. This is separate from `Invoker<>` to avoid // creating multiple versions of `Invoker<>`. // `Invoker<>` -- Unwraps the curried parameters and executes the Functor. // `BindState<>` -- Stores the curried parameters, and is the main entry point // into the `Bind()` system. #if BUILDFLAG(IS_WIN) namespace Microsoft { namespace WRL { template <typename> class ComPtr; } // namespace WRL } // namespace Microsoft #endif namespace base { template <typename T> struct IsWeakReceiver; template <typename> struct BindUnwrapTraits; template <typename Functor, typename BoundArgsTuple> struct CallbackCancellationTraits; template <typename Signature> class FunctionRef; // A tag type to return when `Bind()` calls fail. In this case we intentionally // don't return `void`, since that would produce spurious errors like "variable // has incomplete type 'void'" when assigning the result of // `Bind{Once,Repeating}()` to an `auto`. struct BindFailedCheckPreviousErrors { … }; namespace unretained_traits { // `UnretainedWrapper` will check and report if pointer is dangling upon // invocation. struct MayNotDangle { … }; // `UnretainedWrapper` won't check if pointer is dangling upon invocation. For // extra safety, the receiver must be of type `MayBeDangling<>`. struct MayDangle { … }; // `UnretainedWrapper` won't check if pointer is dangling upon invocation. The // receiver doesn't have to be a `raw_ptr<>`. This is just a temporary state, to // allow dangling pointers that would otherwise crash if `MayNotDangle` was // used. It should be replaced ASAP with `MayNotDangle` (after fixing the // dangling pointers) or with `MayDangle` if there is really no other way (after // making receivers `MayBeDangling<>`). struct MayDangleUntriaged { … }; } // namespace unretained_traits namespace internal { template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits = RawPtrTraits::kEmpty> class UnretainedWrapper { … }; // Storage type for `std::reference_wrapper` so `BindState` can internally store // unprotected references using `raw_ref`. // // `std::reference_wrapper<T>` and `T&` do not work, since the reference // lifetime is not safely protected by MiraclePtr. // // `UnretainedWrapper<T>` and `raw_ptr<T>` do not work, since `BindUnwrapTraits` // would try to pass by `T*` rather than `T&`. template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits = RawPtrTraits::kEmpty> class UnretainedRefWrapper { … }; // Can't use `is_instantiation` to detect the unretained wrappers, since they // have non-type template params. kIsUnretainedWrapper; kIsUnretainedWrapper; // The class is used to wrap `UnretainedRefWrapper` when the latter is used as // a method receiver (a reference on `this` argument). This is needed because // the internal callback mechanism expects the receiver to have the type // `MyClass*` and to have `operator*`. // This is used as storage. template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits> class UnretainedRefWrapperReceiver { … }; // `MethodReceiverStorage` converts the current receiver type to its stored // type. For instance, it converts pointers to `scoped_refptr`, and wraps // `UnretainedRefWrapper` to make it compliant with the internal callback // invocation mechanism. template <typename T> struct MethodReceiverStorage { … }; MethodReceiverStorage<UnretainedRefWrapper<T, UnretainedTrait, PtrTraits>>; template <typename T> class RetainedRefWrapper { … }; template <typename T> struct IgnoreResultHelper { … }; template <typename T, typename Deleter = std::default_delete<T>> class OwnedWrapper { public: explicit OwnedWrapper(T* o) : … { … } explicit OwnedWrapper(std::unique_ptr<T, Deleter>&& ptr) : … { … } T* get() const { … } private: std::unique_ptr<T, Deleter> ptr_; }; template <typename T> class OwnedRefWrapper { … }; // `PassedWrapper` is a copyable adapter for a scoper that ignores `const`. // // It is needed to get around the fact that `Bind()` takes a const reference to // all its arguments. Because `Bind()` takes a const reference to avoid // unnecessary copies, it is incompatible with movable-but-not-copyable // types; doing a destructive "move" of the type into `Bind()` would violate // the const correctness. // // This conundrum cannot be solved without either rvalue references or an O(2^n) // blowup of `Bind()` templates to handle each combination of regular types and // movable-but-not-copyable types. Thus we introduce a wrapper type that is // copyable to transmit the correct type information down into `BindState<>`. // Ignoring `const` in this type makes sense because it is only created when we // are explicitly trying to do a destructive move. // // Two notes: // 1) `PassedWrapper` supports any type that has a move constructor, however // the type will need to be specifically allowed in order for it to be // bound to a `Callback`. We guard this explicitly at the call of `Passed()` // to make for clear errors. Things not given to `Passed()` will be // forwarded and stored by value which will not work for general move-only // types. // 2) `is_valid_` is distinct from `nullptr` because it is valid to bind a null // scoper to a `Callback` and allow the `Callback` to execute once. // // TODO(crbug.com/40840557): We have rvalue references and such now. Remove. template <typename T> class PassedWrapper { … }; Unwrapper; template <typename T> decltype(auto) Unwrap(T&& o) { … } // `kIsWeakMethod` is a helper that determines if we are binding a `WeakPtr<>` // to a method. It is used internally by `Bind()` to select the correct // `InvokeHelper` that will no-op itself in the event the `WeakPtr<>` for the // target object is invalidated. // // The first argument should be the type of the object that will be received by // the method. kIsWeakMethod; kIsWeakMethod; // Packs a list of types to hold them in a single type. template <typename... Types> struct TypeList { … }; // Implements `DropTypeListItem`. template <size_t n, typename List> requires is_instantiation<TypeList, List> struct DropTypeListItemImpl { … }; DropTypeListItemImpl<n, TypeList<T, List...>>; // A type-level function that drops `n` list items from a given `TypeList`. DropTypeListItem; // Implements `TakeTypeListItem`. template <size_t n, typename List, typename... Accum> requires is_instantiation<TypeList, List> struct TakeTypeListItemImpl { … }; TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>; // A type-level function that takes the first `n` items from a given `TypeList`; // e.g. `TakeTypeListItem<3, TypeList<A, B, C, D>>` -> `TypeList<A, B, C>`. TakeTypeListItem; // Implements `MakeFunctionType`. template <typename R, typename ArgList> struct MakeFunctionTypeImpl; MakeFunctionTypeImpl<R, TypeList<Args...>>; // A type-level function that constructs a function type that has `R` as its // return type and has a `TypeList`'s items as its arguments. MakeFunctionType; // Implements `ExtractArgs` and `ExtractReturnType`. template <typename Signature> struct ExtractArgsImpl; ExtractArgsImpl<R (Args...)>; // A type-level function that extracts function arguments into a `TypeList`; // e.g. `ExtractArgs<R(A, B, C)>` -> `TypeList<A, B, C>`. ExtractArgs; // A type-level function that extracts the return type of a function. // e.g. `ExtractReturnType<R(A, B, C)>` -> `R`. ExtractReturnType; template <typename Callable, typename Signature = decltype(&Callable::operator())> struct ExtractCallableRunTypeImpl; #define BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS … BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS; BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS; BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS; BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS; #undef BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS // Evaluated to the RunType of the given callable type; e.g. // `ExtractCallableRunType<decltype([](int, char*) { return 0.1; })>` -> // `double(int, char*)`. ExtractCallableRunType; // True when `Functor` has a non-overloaded `operator()()`, e.g.: // struct S1 { // int operator()(int); // }; // static_assert(HasNonOverloadedCallOp<S1>); // // int i = 0; // auto f = [i] {}; // static_assert(HasNonOverloadedCallOp<decltype(f)>); // // struct S2 { // int operator()(int); // std::string operator()(std::string); // }; // static_assert(!HasNonOverloadedCallOp<S2>); // // static_assert(!HasNonOverloadedCallOp<void(*)()>); // // struct S3 {}; // static_assert(!HasNonOverloadedCallOp<S3>); // ``` HasNonOverloadedCallOp; IsObjCArcBlockPointer; #if __OBJC__ && HAS_FEATURE(objc_arc) template <typename R, typename... Args> inline constexpr bool IsObjCArcBlockPointer<R (^)(Args...)> = true; #endif // True when `Functor` has an overloaded `operator()()` that can be invoked with // the provided `BoundArgs`. // // Do not decay `Functor` before testing this, lest it give an incorrect result // for overloads with different ref-qualifiers. HasOverloadedCallOp; // `HasRefCountedTypeAsRawPtr` is true when any of the `Args` is a raw pointer // to a `RefCounted` type. HasRefCountedTypeAsRawPtr; // `ForceVoidReturn<>` converts a signature to have a `void` return type. template <typename Sig> struct ForceVoidReturn; ForceVoidReturn<R (Args...)>; // `FunctorTraits<>` // // See description at top of file. This must be declared here so it can be // referenced in `DecayedFunctorTraits`. template <typename Functor, typename... BoundArgs> struct FunctorTraits; // Provides functor traits for pre-decayed functor types. template <typename Functor, typename... BoundArgs> struct DecayedFunctorTraits; // Callable types. // This specialization handles lambdas (captureless and capturing) and functors // with a call operator. Capturing lambdas and stateful functors are explicitly // disallowed by `BindHelper<>::Bind()`; e.g.: // ``` // // Captureless lambda: Allowed // [] { return 42; }; // // // Capturing lambda: Disallowed // int x; // [x] { return x; }; // // // Empty class with `operator()()`: Allowed // struct Foo { // void operator()() const {} // // No non-`static` member variables and no virtual functions. // }; // ``` DecayedFunctorTraits<Functor, BoundArgs...>; // Functions. DecayedFunctorTraits<R (*)(Args...), BoundArgs...>; DecayedFunctorTraits<R (*)(Args...) noexcept, BoundArgs...>; #if BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS) // `__stdcall` and `__fastcall` functions. #define BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS … BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS(__stdcall, ); BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS(__stdcall, noexcept); BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS(__fastcall, ); BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS(__fastcall, noexcept); #undef BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS #endif // BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS) #if __OBJC__ && HAS_FEATURE(objc_arc) // Objective-C blocks. Blocks can be bound as the compiler will ensure their // lifetimes will be correctly managed. template <typename R, typename... Args, typename... BoundArgs> struct DecayedFunctorTraits<R (^)(Args...), BoundArgs...> { using RunType = R(Args...); static constexpr bool is_method = false; static constexpr bool is_nullable = true; static constexpr bool is_callback = false; static constexpr bool is_stateless = true; template <typename BlockType, typename... RunArgs> static R Invoke(BlockType&& block, RunArgs&&... args) { // According to LLVM documentation (§ 6.3), "local variables of automatic // storage duration do not have precise lifetime." Use // `objc_precise_lifetime` to ensure that the Objective-C block is not // deallocated until it has finished executing even if the `Callback<>` is // destroyed during the block execution. // https://clang.llvm.org/docs/AutomaticReferenceCounting.html#precise-lifetime-semantics __attribute__((objc_precise_lifetime)) R (^scoped_block)(Args...) = block; return scoped_block(std::forward<RunArgs>(args)...); } }; #endif // __OBJC__ && HAS_FEATURE(objc_arc) // Methods. DecayedFunctorTraits<R (Receiver::*)(Args...), BoundArgs...>; DecayedFunctorTraits<R (Receiver::*)(Args...) const, BoundArgs...>; #define BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONST_AND_QUALS … BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONST_AND_QUALS; BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONST_AND_QUALS; #undef BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONST_AND_QUALS #if BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS) // `__stdcall` methods. #define BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS … BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS(); BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS(const); BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS(noexcept); BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS(const noexcept); #undef BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS #endif // BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS) // `IgnoreResult`s. DecayedFunctorTraits<IgnoreResultHelper<T>, BoundArgs...>; // `OnceCallback`s. DecayedFunctorTraits<OnceCallback<R (Args...)>, BoundArgs...>; // `RepeatingCallback`s. DecayedFunctorTraits<RepeatingCallback<R (Args...)>, BoundArgs...>; // For most functors, the traits should not depend on how the functor is passed, // so decay the functor. FunctorTraits<Functor, BoundArgs...>; // For `overloaded operator()()`s, it's possible the ref qualifiers of the // functor matter, so be careful to use the undecayed type. FunctorTraits<Functor, BoundArgs...>; // `StorageTraits<>` // // See description at top of file. template <typename T> struct StorageTraits { … }; // For `T*`, store as `UnretainedWrapper<T>` for safety, as it internally uses // `raw_ptr<T>` (when possible). StorageTraits<T *>; // For `raw_ptr<T>`, store as `UnretainedWrapper<T>` for safety. This may seem // contradictory, but this ensures guaranteed protection for the pointer even // during execution of callbacks with parameters of type `raw_ptr<T>`. StorageTraits<raw_ptr<T, PtrTraits>>; // Unwrap `std::reference_wrapper` and store it in a custom wrapper so that // references are also protected with `raw_ptr<T>`. StorageTraits<std::reference_wrapper<T>>; ValidateStorageTraits; // `InvokeHelper<>` // // There are 2 logical `InvokeHelper<>` specializations: normal, weak. // // The normal type just calls the underlying runnable. // // Weak calls need special syntax that is applied to the first argument to check // if they should no-op themselves. template <bool is_weak_call, typename Traits, typename ReturnType, size_t... indices> struct InvokeHelper; InvokeHelper<false, Traits, ReturnType, indices...>; InvokeHelper<true, Traits, ReturnType, index_target, index_tail...>; // `Invoker<>` // // See description at the top of the file. template <typename Traits, typename StorageType, typename UnboundRunType> struct Invoker; Invoker<Traits, StorageType, R (UnboundArgs...)>; // Allow binding a method call with no receiver. // TODO(crbug.com/41484339): Remove or make safe. template <typename... Unused> void VerifyMethodReceiver(Unused&&...) { … } template <typename Receiver, typename... Unused> void VerifyMethodReceiver(Receiver&& receiver, Unused&&...) { … } // `BindState<>` // // This stores all the state passed into `Bind()`. template <bool is_method, bool is_nullable, bool is_callback, typename Functor, typename... BoundArgs> struct BindState final : BindStateBase { … }; // Used to determine and validate the appropriate `BindState`. The // specializations below cover all cases. The members are similar in intent to // those in `StorageTraits`; see comments there. template <bool is_method, bool is_nullable, bool is_callback, typename Functor, typename... BoundArgs> struct ValidateBindStateType; ValidateBindStateType<false, is_nullable, is_callback, Functor, BoundArgs...>; ValidateBindStateType<true, is_nullable, is_callback, Functor>; ValidateBindStateType<true, is_nullable, is_callback, Functor, Receiver, BoundArgs...>; // Transforms `T` into an unwrapped type, which is passed to the target // function; e.g.: // * `is_once` cases: // ** `TransformToUnwrappedType<true, int&&>` -> `int&&` // ** `TransformToUnwrappedType<true, const int&>` -> `int&&` // ** `TransformToUnwrappedType<true, OwnedWrapper<int>&>` -> `int*&&` // * `!is_once` cases: // ** `TransformToUnwrappedType<false, int&&>` -> `const int&` // ** `TransformToUnwrappedType<false, const int&>` -> `const int&` // ** `TransformToUnwrappedType<false, OwnedWrapper<int>&>` -> `int* const &` TransformToUnwrappedType; // Used to convert `this` arguments to underlying pointer types; e.g.: // `int*` -> `int*` // `std::unique_ptr<int>` -> `int*` // `int` -> (assertion failure; `this` must be a pointer-like object) template <typename T> struct ValidateReceiverType { … }; ValidateReceiverType<T>; // Transforms `Args` into unwrapped types, and packs them into a `TypeList`. If // `is_method` is true, tries to dereference the first argument to support smart // pointers. template <bool is_once, bool is_method, typename... Args> struct ValidateUnwrappedTypeList { … }; ValidateUnwrappedTypeList<is_once, true, Receiver, Args...>; // `IsUnretainedMayDangle` is true iff `StorageType` is marked with // `unretained_traits::MayDangle`. Note that it is false for // `unretained_traits::MayDangleUntriaged`. IsUnretainedMayDangle; IsUnretainedMayDangle; // `UnretainedAndRawPtrHaveCompatibleTraits` is true iff `StorageType` is marked // with `unretained_traits::MayDangle`, `FunctionParamType` is a `raw_ptr`, and // `StorageType::GetPtrType` is the same type as `FunctionParamType`. UnretainedAndRawPtrHaveCompatibleTraits; UnretainedAndRawPtrHaveCompatibleTraits; // Helpers to make error messages slightly more readable. template <int i> struct BindArgument { … }; // Helper to assert that parameter `i` of type `Arg` can be bound, which means: // * `Arg` can be retained internally as `Storage` // * `Arg` can be forwarded as `Unwrapped` to `Param` template <int i, bool is_method, typename Arg, typename Storage, typename Unwrapped, typename Param> struct ParamCanBeBound { … }; // Takes three same-length `TypeList`s, and checks `ParamCanBeBound` for each // triple. template <bool is_method, typename Index, typename Args, typename UnwrappedTypeList, typename ParamsList> struct ParamsCanBeBound { … }; ParamsCanBeBound<is_method, std::index_sequence<Ns...>, TypeList<Args...>, TypeList<UnwrappedTypes...>, TypeList<Params...>>; // Core implementation of `Bind()`, which checks common preconditions before // returning an appropriate callback. template <template <typename> class CallbackT> struct BindHelper { … }; } // namespace internal // An injection point to control `this` pointer behavior on a method invocation. // If `IsWeakReceiver<T>::value` is `true` and `T` is used as a method receiver, // `Bind()` cancels the method invocation if the receiver tests as false. // ``` // struct S : SupportsWeakPtr<S> { // void f() {} // }; // // WeakPtr<S> weak_s = nullptr; // BindOnce(&S::f, weak_s).Run(); // `S::f()` is not called. // ``` template <typename T> struct IsWeakReceiver : std::bool_constant<is_instantiation<WeakPtr, T>> { … }; IsWeakReceiver<std::reference_wrapper<T>>; // An injection point to control how objects are checked for maybe validity, // which is an optimistic thread-safe check for full validity. template <typename> struct MaybeValidTraits { … }; // An injection point to control how bound objects passed to the target // function. `BindUnwrapTraits<>::Unwrap()` is called for each bound object // right before the target function is invoked. template <typename> struct BindUnwrapTraits { … }; BindUnwrapTraits<T>; BindUnwrapTraits<internal::PassedWrapper<T>>; #if BUILDFLAG(IS_WIN) template <typename T> struct BindUnwrapTraits<Microsoft::WRL::ComPtr<T>> { static T* Unwrap(const Microsoft::WRL::ComPtr<T>& ptr) { return ptr.Get(); } }; #endif // `CallbackCancellationTraits` allows customization of `Callback`'s // cancellation semantics. By default, callbacks are not cancellable. A // specialization should set `is_cancellable` and implement an `IsCancelled()` // that returns whether the callback should be cancelled, as well as a // `MaybeValid()` that returns whether the underlying functor/object is maybe // valid. template <typename Functor, typename BoundArgsTuple> struct CallbackCancellationTraits { … }; // Specialization for a weak receiver. CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>>; // Specialization for a nested `Bind()`. CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>>; } // namespace base #endif // BASE_FUNCTIONAL_BIND_INTERNAL_H_