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_