Migrate //base/functional/bind* and helpers to use C++20 constraints.
Bug: 1501952
Change-Id: I877521632ccdd25665925a65f9a870664ab36a33
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5027747
Reviewed-by: danakj <danakj@chromium.org>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1224632}
NOKEYCHECK=True
GitOrigin-RevId: ef1375f2c9fffa0d9cd664b43b0035c09fb70e99
diff --git a/functional/bind.h b/functional/bind.h
index 3d9a9b5..c3b7556 100644
--- a/functional/bind.h
+++ b/functional/bind.h
@@ -424,8 +424,8 @@
// via use of enable_if, and the second takes a T* which will not bind to T&.
//
// DEPRECATED - Do not use in new code. See https://crbug.com/1326449
-template <typename T,
- std::enable_if_t<!std::is_lvalue_reference_v<T>>* = nullptr>
+template <typename T>
+ requires(!std::is_lvalue_reference_v<T>)
inline internal::PassedWrapper<T> Passed(T&& scoper) {
return internal::PassedWrapper<T>(std::move(scoper));
}
diff --git a/functional/bind_internal.h b/functional/bind_internal.h
index 37e66ed..8adc845 100644
--- a/functional/bind_internal.h
+++ b/functional/bind_internal.h
@@ -74,7 +74,7 @@
template <typename>
struct BindUnwrapTraits;
-template <typename Functor, typename BoundArgsTuple, typename SFINAE = void>
+template <typename Functor, typename BoundArgsTuple>
struct CallbackCancellationTraits;
template <typename Signature>
@@ -100,7 +100,7 @@
namespace internal {
-template <typename Functor, typename SFINAE = void>
+template <typename Functor>
struct FunctorTraits;
template <typename T,
@@ -133,17 +133,17 @@
// Raw pointer makes sense only if there are no PtrTraits. If there are,
// it means that a `raw_ptr` is being passed, so use the ctors below instead.
- template <RawPtrTraits PTraits = PtrTraits,
- typename = std::enable_if_t<PTraits == RawPtrTraits::kEmpty>>
- explicit UnretainedWrapper(T* o) : ptr_(o) {}
- // Trick to only instantiate these constructors if they are used. Otherwise,
- // instantiating UnretainedWrapper with a T that is not supported by
- // raw_ptr would trigger raw_ptr<T>'s static_assert.
- template <typename U = T>
- explicit UnretainedWrapper(const raw_ptr<U, PtrTraits>& o) : ptr_(o) {}
- template <typename U = T>
- explicit UnretainedWrapper(raw_ptr<U, PtrTraits>&& o) : ptr_(std::move(o)) {}
+ explicit UnretainedWrapper(T* o)
+ requires(PtrTraits == RawPtrTraits::kEmpty)
+ : ptr_(o) {}
+
+ explicit UnretainedWrapper(const raw_ptr<T, PtrTraits>& o)
+ requires(raw_ptr_traits::IsSupportedType<T>::value)
+ : ptr_(o) {}
+ explicit UnretainedWrapper(raw_ptr<T, PtrTraits>&& o)
+ requires(raw_ptr_traits::IsSupportedType<T>::value)
+ : ptr_(std::move(o)) {}
GetPtrType get() const { return GetInternal(ptr_); }
@@ -206,17 +206,17 @@
// Raw reference makes sense only if there are no PtrTraits. If there are,
// it means that a `raw_ref` is being passed, so use the ctors below instead.
- template <RawPtrTraits PTraits = PtrTraits,
- typename = std::enable_if_t<PTraits == RawPtrTraits::kEmpty>>
- explicit UnretainedRefWrapper(T& o) : ref_(o) {}
- // Trick to only instantiate these constructors if they are used. Otherwise,
- // instantiating UnretainedWrapper with a T that is not supported by
- // raw_ref would trigger raw_ref<T>'s static_assert.
- template <typename U = T>
- explicit UnretainedRefWrapper(const raw_ref<U, PtrTraits>& o) : ref_(o) {}
- template <typename U = T>
- explicit UnretainedRefWrapper(raw_ref<U, PtrTraits>&& o)
+ explicit UnretainedRefWrapper(T& o)
+ requires(PtrTraits == RawPtrTraits::kEmpty)
+ : ref_(o) {}
+
+ explicit UnretainedRefWrapper(const raw_ref<T, PtrTraits>& o)
+ requires(raw_ptr_traits::IsSupportedType<T>::value)
+ : ref_(o) {}
+ explicit UnretainedRefWrapper(raw_ref<T, PtrTraits>&& o)
+
+ requires(raw_ptr_traits::IsSupportedType<T>::value)
: ref_(std::move(o)) {}
T& get() const { return GetInternal(ref_); }
@@ -551,12 +551,12 @@
// int i = 0;
// auto f = [i] {};
// IsCallableObject<decltype(f)>::value is false.
-template <typename Functor, typename SFINAE = void>
+template <typename Functor>
struct IsCallableObject : std::false_type {};
template <typename Callable>
-struct IsCallableObject<Callable, std::void_t<decltype(&Callable::operator())>>
- : std::true_type {};
+ requires requires { &Callable::operator(); }
+struct IsCallableObject<Callable> : std::true_type {};
// HasRefCountedTypeAsRawPtr inherits from true_type when any of the |Args| is a
// raw pointer to a RefCounted type.
@@ -578,7 +578,7 @@
// FunctorTraits<>
//
// See description at top of file.
-template <typename Functor, typename SFINAE>
+template <typename Functor>
struct FunctorTraits;
// For callable types.
@@ -601,8 +601,8 @@
// // No non-static member variable and no virtual functions.
// };
template <typename Functor>
-struct FunctorTraits<Functor,
- std::enable_if_t<IsCallableObject<Functor>::value>> {
+ requires(IsCallableObject<Functor>::value)
+struct FunctorTraits<Functor> {
using RunType = ExtractCallableRunType<Functor>;
static constexpr bool is_method = false;
static constexpr bool is_nullable = false;
@@ -1000,14 +1000,14 @@
};
template <typename Functor>
-std::enable_if_t<FunctorTraits<Functor>::is_nullable, bool> IsNull(
- const Functor& functor) {
+ requires(FunctorTraits<Functor>::is_nullable)
+constexpr bool IsNull(const Functor& functor) {
return !functor;
}
template <typename Functor>
-std::enable_if_t<!FunctorTraits<Functor>::is_nullable, bool> IsNull(
- const Functor&) {
+ requires(!FunctorTraits<Functor>::is_nullable)
+constexpr bool IsNull(const Functor&) {
return false;
}
@@ -1043,23 +1043,15 @@
}
// The base case of BanUnconstructedRefCountedReceiver that checks nothing.
-template <typename Functor, typename Receiver, typename... Unused>
-std::enable_if_t<
- !(MakeFunctorTraits<Functor>::is_method &&
- IsPointerV<std::decay_t<Receiver>> &&
- IsRefCountedType<RemovePointerT<std::decay_t<Receiver>>>::value)>
-BanUnconstructedRefCountedReceiver(const Receiver& receiver, Unused&&...) {}
-
-template <typename Functor>
-void BanUnconstructedRefCountedReceiver() {}
+template <typename Functor, typename... Unused>
+void BanUnconstructedRefCountedReceiver(Unused&&...) {}
// Asserts that Callback is not the first owner of a ref-counted receiver.
template <typename Functor, typename Receiver, typename... Unused>
-std::enable_if_t<
- MakeFunctorTraits<Functor>::is_method &&
- IsPointerV<std::decay_t<Receiver>> &&
- IsRefCountedType<RemovePointerT<std::decay_t<Receiver>>>::value>
-BanUnconstructedRefCountedReceiver(const Receiver& receiver, Unused&&...) {
+ requires(MakeFunctorTraits<Functor>::is_method &&
+ IsPointerV<std::decay_t<Receiver>> &&
+ IsRefCountedType<RemovePointerT<std::decay_t<Receiver>>>)
+void BanUnconstructedRefCountedReceiver(Receiver&& receiver, Unused&&...) {
DCHECK(receiver);
// It's error prone to make the implicit first reference to ref-counted types.
@@ -1197,7 +1189,7 @@
" it's safe.");
static_assert(
!IsPointerV<DecayedReceiver> ||
- IsRefCountedType<RemovePointerT<DecayedReceiver>>::value,
+ IsRefCountedType<RemovePointerT<DecayedReceiver>>,
"Receivers may not be raw pointers. If using a raw pointer here is safe"
" and has no lifetime concerns, use base::Unretained() and document why"
" it's safe.");
@@ -1589,29 +1581,22 @@
// bound arguments. We CHECK() the validity of callback to guard against null
// pointers accidentally ending up in posted tasks, causing hard-to-debug
// crashes.
-template <template <typename> class CallbackT,
- typename Signature,
- std::enable_if_t<std::is_same_v<CallbackT<Signature>,
- OnceCallback<Signature>>>* = nullptr>
+template <template <typename> class CallbackT, typename Signature>
+ requires(std::same_as<CallbackT<Signature>, OnceCallback<Signature>>)
OnceCallback<Signature> BindImpl(OnceCallback<Signature> callback) {
CHECK(callback);
return callback;
}
-template <template <typename> class CallbackT,
- typename Signature,
- std::enable_if_t<std::is_same_v<CallbackT<Signature>,
- OnceCallback<Signature>>>* = nullptr>
+template <template <typename> class CallbackT, typename Signature>
+ requires(std::same_as<CallbackT<Signature>, OnceCallback<Signature>>)
OnceCallback<Signature> BindImpl(RepeatingCallback<Signature> callback) {
CHECK(callback);
return callback;
}
-template <template <typename> class CallbackT,
- typename Signature,
- std::enable_if_t<std::is_same_v<CallbackT<Signature>,
- RepeatingCallback<Signature>>>* =
- nullptr>
+template <template <typename> class CallbackT, typename Signature>
+ requires(std::same_as<CallbackT<Signature>, RepeatingCallback<Signature>>)
RepeatingCallback<Signature> BindImpl(RepeatingCallback<Signature> callback) {
CHECK(callback);
return callback;
@@ -1731,19 +1716,16 @@
// semantics. By default, callbacks are not cancellable. A specialization should
// set is_cancellable = true and implement an IsCancelled() that returns if the
// callback should be cancelled.
-template <typename Functor, typename BoundArgsTuple, typename SFINAE>
+template <typename Functor, typename BoundArgsTuple>
struct CallbackCancellationTraits {
static constexpr bool is_cancellable = false;
};
// Specialization for method bound to weak pointer receiver.
template <typename Functor, typename... BoundArgs>
-struct CallbackCancellationTraits<
- Functor,
- std::tuple<BoundArgs...>,
- std::enable_if_t<
- internal::IsWeakMethod<internal::FunctorTraits<Functor>::is_method,
- BoundArgs...>::value>> {
+ requires(internal::IsWeakMethod<internal::FunctorTraits<Functor>::is_method,
+ BoundArgs...>::value)
+struct CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>> {
static constexpr bool is_cancellable = true;
template <typename Receiver, typename... Args>
diff --git a/functional/bind_nocompile.nc b/functional/bind_nocompile.nc
index 4ff84b6..f0aefbc 100644
--- a/functional/bind_nocompile.nc
+++ b/functional/bind_nocompile.nc
@@ -113,7 +113,7 @@
method_to_const_cb.Run();
}
-#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static assertion failed due to requirement '!IsPointerV<base::NoRef \*> \|\| IsRefCountedType<base::NoRef, void>::value': Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained\(\) and document why it's safe."]
+#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static assertion failed due to requirement '!IsPointerV<base::NoRef \*> \|\| IsRefCountedType<base::NoRef>': Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained\(\) and document why it's safe."]
// Method bound to non-refcounted object.
@@ -126,7 +126,7 @@
no_ref_cb.Run();
}
-#elif defined(NCTEST_CONST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static assertion failed due to requirement '!IsPointerV<base::NoRef \*> \|\| IsRefCountedType<base::NoRef, void>::value': Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained\(\) and document why it's safe."]
+#elif defined(NCTEST_CONST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static assertion failed due to requirement '!IsPointerV<base::NoRef \*> \|\| IsRefCountedType<base::NoRef>': Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained\(\) and document why it's safe."]
// Const Method bound to non-refcounted object.
//
@@ -138,7 +138,7 @@
no_ref_const_cb.Run();
}
-#elif defined(NCTEST_METHOD_BIND_RAW_PTR_RECEIVER_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static assertion failed due to requirement '!IsPointerV<base::raw_ptr<base::NoRef, [^>]+>?>> \|\| IsRefCountedType<base::NoRef, void>::value': Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained\(\) and document why it's safe."]
+#elif defined(NCTEST_METHOD_BIND_RAW_PTR_RECEIVER_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static assertion failed due to requirement '!IsPointerV<base::raw_ptr<base::NoRef, [^>]+>?>> \|\| IsRefCountedType<base::NoRef>': Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained\(\) and document why it's safe."]
// Method bound to non-refcounted object.
@@ -152,7 +152,7 @@
no_ref_cb.Run();
}
-#elif defined(NCTEST_CONST_METHOD_BIND_RAW_PTR_RECEIVER_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static assertion failed due to requirement '!IsPointerV<base::raw_ptr<base::NoRef, [^>]+>?>> \|\| IsRefCountedType<base::NoRef, void>::value': Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained\(\) and document why it's safe."]
+#elif defined(NCTEST_CONST_METHOD_BIND_RAW_PTR_RECEIVER_NEEDS_REFCOUNTED_OBJECT) // [r"fatal error: static assertion failed due to requirement '!IsPointerV<base::raw_ptr<base::NoRef, [^>]+>?>> \|\| IsRefCountedType<base::NoRef>': Receivers may not be raw pointers. If using a raw pointer here is safe and has no lifetime concerns, use base::Unretained\(\) and document why it's safe."]
// Const Method bound to non-refcounted object.
//
@@ -396,7 +396,7 @@
BindRepeating(&VoidPolymorphic1<int>);
}
-#elif defined(NCTEST_DISALLOW_CAPTURING_LAMBDA) // [r"static assertion failed due to requirement 'FunctorTraits<\(lambda at [^)]+\), void>::is_stateless': Capturing lambdas and stateful lambdas are intentionally not supported\."]
+#elif defined(NCTEST_DISALLOW_CAPTURING_LAMBDA) // [r"static assertion failed due to requirement 'FunctorTraits<\(lambda at [^)]+\)>::is_stateless': Capturing lambdas and stateful lambdas are intentionally not supported\."]
void WontCompile() {
int i = 0, j = 0;
@@ -464,7 +464,7 @@
BindRepeating(&TakesMoveOnly, std::move(x));
}
-#elif defined(NCTEST_BIND_NON_EMPTY_FUNCTOR) // [r"static assertion failed due to requirement 'FunctorTraits<base::NonEmptyFunctor, void>::is_stateless': Capturing lambdas and stateful lambdas are intentionally not supported\."]
+#elif defined(NCTEST_BIND_NON_EMPTY_FUNCTOR) // [r"static assertion failed due to requirement 'FunctorTraits<base::NonEmptyFunctor>::is_stateless': Capturing lambdas and stateful lambdas are intentionally not supported\."]
void WontCompile() {
BindRepeating(NonEmptyFunctor());
diff --git a/memory/raw_scoped_refptr_mismatch_checker.h b/memory/raw_scoped_refptr_mismatch_checker.h
index 06df106..c0d7045 100644
--- a/memory/raw_scoped_refptr_mismatch_checker.h
+++ b/memory/raw_scoped_refptr_mismatch_checker.h
@@ -18,38 +18,32 @@
// The following set of traits are designed to generate a compile error
// whenever this antipattern is attempted.
-namespace base {
-
-// This is a base internal implementation file used by task.h and callback.h.
-// Not for public consumption, so we wrap it in namespace internal.
-namespace internal {
-
-template <typename T, typename = void>
-struct IsRefCountedType : std::false_type {};
+namespace base::internal {
template <typename T>
-struct IsRefCountedType<T,
- std::void_t<decltype(std::declval<T*>()->AddRef()),
- decltype(std::declval<T*>()->Release())>>
- : std::true_type {};
+concept IsRefCountedType = requires(T& x) {
+ // There are no additional constraints on `AddRef()` and `Release()` since
+ // `scoped_refptr`, for better or worse`, seamlessly interoperates with other
+ // non-base types that happen to implement the same signatures (e.g. COM's
+ // IUnknown).
+ x.AddRef();
+ x.Release();
+};
// Human readable translation: you needed to be a scoped_refptr if you are a raw
// pointer type and are convertible to a RefCounted(Base|ThreadSafeBase) type.
template <typename T>
-struct NeedsScopedRefptrButGetsRawPtr
- : std::disjunction<
- // TODO(danakj): Should ban native references and
- // std::reference_wrapper here too.
- std::conjunction<base::IsRawRef<T>,
- IsRefCountedType<base::RemoveRawRefT<T>>>,
- std::conjunction<base::IsPointer<T>,
- IsRefCountedType<base::RemovePointerT<T>>>> {
+struct NeedsScopedRefptrButGetsRawPtr {
static_assert(!std::is_reference_v<T>,
"NeedsScopedRefptrButGetsRawPtr requires non-reference type.");
+
+ // TODO(danakj): Should ban native references and
+ // std::reference_wrapper here too.
+ static constexpr bool value =
+ (base::IsRawRef<T>::value && IsRefCountedType<base::RemoveRawRefT<T>>) ||
+ (base::IsPointer<T>::value && IsRefCountedType<base::RemovePointerT<T>>);
};
-} // namespace internal
-
-} // namespace base
+} // namespace base::internal
#endif // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_