https://github.com/vtjnash updated 
https://github.com/llvm/llvm-project/pull/211885

>From a6f8429b6b295e2fbbd1d1007bb2c3431fc70732 Mon Sep 17 00:00:00 2001
From: Jameson Nash <[email protected]>
Date: Fri, 24 Jul 2026 18:23:09 +0000
Subject: [PATCH 1/3] Thread Safety Analysis: Don't treat function pointer
 parameters as scoped capabilities

Capability attributes on a parameter mean one of two unrelated things:
on a scoped-lockable parameter they describe the locks the passed scope
object holds, while on a function pointer parameter they describe the
requirements of the function called through the pointer. Since #191187
allowed the latter, both of the scoped-lockable code paths have been
misreading function pointer parameters as scope objects.

At a call site, the argument bound to the parameter was translated into
a capability and required to be held, so passing a callback that
requires a capability was reported as a missing lock named after the
callback:

  void lookup(void *cache, eq_t eq EXCLUSIVE_LOCKS_REQUIRED(mu), void *key);
  static int my_eq(void *a, void *b) EXCLUSIVE_LOCKS_REQUIRED(mu);
  ...
  lookup(cache, my_eq, key); // warning: requires holding mutex 'my_eq'

In the callee, the same confusion seeded the parameter's capabilities
into the function's entry lockset, so they were considered held
throughout the body and the calls made through the pointer went
unchecked -- the opposite of what the annotation asks for.

Skip function pointer parameters in both places; their attributes are
already checked at the indirect call sites, the same way as for
annotated function pointer variables and fields.

The tests added with #191187 covered function pointer struct fields,
which take neither path, so extend them to cover parameters.

Assisted-by: Claude Opus 5 (1M context) <[email protected]>
---
 clang/lib/Analysis/ThreadSafety.cpp           | 15 ++++++++
 clang/test/Sema/warn-thread-safety-analysis.c | 36 +++++++++++++++++++
 2 files changed, 51 insertions(+)

diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index fe94910e905a3..57936aa5dfa8b 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -62,6 +62,17 @@ using namespace threadSafety;
 // Key method definition
 ThreadSafetyHandler::~ThreadSafetyHandler() = default;
 
+/// True if capability attributes on \p Param describe the function reached
+/// through it rather than the argument bound to it.
+///
+/// Sema accepts capability attributes on a parameter for two unrelated
+/// purposes: a scoped-lockable parameter, where the attributes describe the
+/// locks the passed scope object holds, and a function pointer parameter, 
where
+/// they describe the requirements of the function called through the pointer.
+static bool isFunctionPointerParam(const ParmVarDecl *Param) {
+  return Param->getType().getNonReferenceType()->isFunctionPointerType();
+}
+
 /// Issue a warning about an invalid lock expression
 static void warnInvalidLock(ThreadSafetyHandler &Handler,
                             const Expr *MutexExp, const NamedDecl *D,
@@ -2327,6 +2338,8 @@ void BuildLockset::handleCall(const Expr *Exp, const 
NamedDecl *D,
   const auto *CalledFunction = dyn_cast<FunctionDecl>(D);
   if (CalledFunction && Args.has_value()) {
     for (auto [Param, Arg] : zip(CalledFunction->parameters(), *Args)) {
+      if (isFunctionPointerParam(Param))
+        continue;
       CapExprSet DeclaredLocks;
       for (const Attr *At : Param->attrs()) {
         switch (At->getKind()) {
@@ -2899,6 +2912,8 @@ void 
ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
     else
       llvm_unreachable("Unknown function kind");
     for (const ParmVarDecl *Param : Params) {
+      if (isFunctionPointerParam(Param))
+        continue;
       CapExprSet UnderlyingLocks;
       for (const auto *Attr : Param->attrs()) {
         Loc = Attr->getLocation();
diff --git a/clang/test/Sema/warn-thread-safety-analysis.c 
b/clang/test/Sema/warn-thread-safety-analysis.c
index 6613f65e4b359..a439f1ca51623 100644
--- a/clang/test/Sema/warn-thread-safety-analysis.c
+++ b/clang/test/Sema/warn-thread-safety-analysis.c
@@ -319,6 +319,42 @@ void test_fp_ops_fail(struct FPOps *ops) {
   ops->requires_mu(); // expected-warning {{calling function 'requires_mu' 
requires holding mutex '&FPOps::mu' exclusively}}
 }
 
+// Function pointer parameters. The attributes constrain the function reached
+// through the pointer, so they are checked where the pointer is called, and
+// must not be mistaken for requirements of the enclosing function's callers
+// (nor for scoped-lockable parameter annotations).
+typedef void (*visit_fn)(int);
+
+void visit_all(visit_fn visit EXCLUSIVE_LOCKS_REQUIRED(mu1), int n);
+void visit_all_locked_fp(void (*visit)(int) EXCLUSIVE_LOCKS_REQUIRED(mu1), int 
n)
+    EXCLUSIVE_LOCKS_REQUIRED(mu1) {
+  visit(n);
+}
+void visit_all_unlocked_fp(void (*visit)(int) EXCLUSIVE_LOCKS_REQUIRED(mu1), 
int n) {
+  visit(n); // expected-warning {{calling function 'visit' requires holding 
mutex 'mu1' exclusively}}
+}
+
+void visit_cb(int x) EXCLUSIVE_LOCKS_REQUIRED(mu1);
+
+// Passing an annotated callee is not itself a use of the capability, so these
+// calls do not require mu1 to be held here.
+void test_fp_param(int n) {
+  visit_all(visit_cb, n);
+  visit_all(&visit_cb, n);
+  visit_all_unlocked_fp(visit_cb, n);
+  // Only visit_all_locked_fp's own attribute requires mu1.
+  visit_all_locked_fp(visit_cb, n); // expected-warning {{calling function 
'visit_all_locked_fp' requires holding mutex 'mu1' exclusively}}
+}
+
+// Acquire/release on a function pointer parameter likewise describe the 
pointee,
+// so calling the enclosing function neither acquires nor releases mu1.
+void call_locker(void (*lock)(void) EXCLUSIVE_LOCK_FUNCTION(mu1));
+void test_fp_param_acquire(void) {
+  call_locker(0);
+  mutex_exclusive_lock(&mu1);
+  mutex_exclusive_unlock(&mu1);
+}
+
 // Function pointer attributes referring to parameters.
 struct BDev {
   struct Mutex lock;

>From 4b5b3c5cd5ece7aeaf963e0ba38cc36dd0b96901 Mon Sep 17 00:00:00 2001
From: Jameson Nash <[email protected]>
Date: Mon, 27 Jul 2026 15:21:56 +0000
Subject: [PATCH 2/3] Thread Safety Analysis: Handle function reference
 parameters as callbacks

In C++ a callback can also be passed as a function reference, but Sema
accepted capability attributes only on function pointers, so `void
(&cb)(int) EXCLUSIVE_LOCKS_REQUIRED(mu)` was rejected with "applies to
function parameters only if their type is a reference to a
'scoped_lockable'-annotated type", and the analysis never saw it.

Accept function references wherever function pointers are accepted --
parameters, variables, and fields -- and classify them the same way in
the analysis. Both halves are needed: with Sema alone, a function
reference parameter takes the scoped-lockable paths and reproduces the
bug fixed in the parent commit, warning that the callback argument is a
capability that must be held.

Also document how attributes on a parameter differ from those on a
scoped-lockable one.

Assisted-by: Claude Opus 5
---
 clang/docs/ThreadSafetyAnalysis.md            | 40 ++++++--
 .../clang/Basic/DiagnosticSemaKinds.td        |  5 +-
 clang/lib/Analysis/ThreadSafety.cpp           | 14 +--
 clang/lib/Sema/SemaDeclAttr.cpp               | 20 ++--
 clang/test/Sema/attr-capabilities.c           |  6 +-
 clang/test/Sema/warn-thread-safety-analysis.c | 10 +-
 .../SemaCXX/warn-thread-safety-analysis.cpp   | 93 +++++++++++++++++++
 .../SemaCXX/warn-thread-safety-parsing.cpp    | 91 ++++++++++--------
 8 files changed, 204 insertions(+), 75 deletions(-)

diff --git a/clang/docs/ThreadSafetyAnalysis.md 
b/clang/docs/ThreadSafetyAnalysis.md
index 012c8a4c41373..610cccf777b69 100644
--- a/clang/docs/ThreadSafetyAnalysis.md
+++ b/clang/docs/ThreadSafetyAnalysis.md
@@ -510,9 +510,10 @@ Use of these attributes has been deprecated.
 
 ### Function Pointers
 
-Thread safety attributes may also be applied to function pointer variables and
-fields. The attributes describe the locking behavior of calling through that
-pointer, and the analysis will check calls through the pointer accordingly.
+Thread safety attributes may also be applied to variables, fields, and
+parameters of function pointer (or, in C++, function reference) type. The
+attributes describe the locking behavior of calling through that pointer, and
+the analysis will check calls through the pointer accordingly.
 
 ```c++
 Mutex mu;
@@ -533,14 +534,33 @@ void test(Ops *ops) {
 }
 ```
 
-Note that the attributes are on the *variable* (or field), not on the function
-pointer type. Assigning a function with different (or no) attributes to an
-annotated function pointer variable is not diagnosed. The analysis trusts the
-annotations on the variable at the call site.
+On a parameter, the attributes describe the function reached through the
+parameter, not a capability that the argument stands for: they are checked
+where the parameter is called, and are neither requirements on nor effects for
+callers of the enclosing function. (Contrast this with a parameter of
+`scoped_lockable` reference type, where the attributes describe the locks that
+the passed scope object holds; see {ref}`scoped_capability`.)
 
-This support is limited to plain function pointers. Pointers-to-member
-functions, blocks, and wrapper types such as `std::function` are not
-supported yet.
+```c++
+void visit_all(void (*visit)(int) REQUIRES(mu), int n) {
+  visit(n); // warning: calling function 'visit' requires holding mutex 'mu'
+}
+
+void visit_cb(int) REQUIRES(mu);
+
+void test_param(int n) {
+  visit_all(visit_cb, n); // OK: passing a callee is not a use of 'mu'
+}
+```
+
+Note that the attributes are on the *variable* (or field, or parameter), not on
+the function pointer type. Assigning a function with different (or no)
+attributes to an annotated function pointer variable is not diagnosed. The
+analysis trusts the annotations on the variable at the call site.
+
+This support is limited to plain function pointers and function references.
+Pointers-to-member functions, blocks, and wrapper types such as `std::function`
+are not supported yet.
 
 ### Warning flags
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cce6f70a58893..8f58c725570f4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4350,13 +4350,14 @@ def warn_thread_attribute_decl_not_pointer : Warning<
   InGroup<ThreadSafetyAttributes>, DefaultIgnore;
 def warn_thread_attribute_not_on_scoped_lockable_param : Warning<
   "%0 attribute applies to function parameters only if their type is a "
-  "reference to a 'scoped_lockable'-annotated type">,
+  "function pointer, a function reference, or a reference to a "
+  "'scoped_lockable'-annotated type">,
   InGroup<ThreadSafetyAttributes>, DefaultIgnore;
 def warn_thread_attribute_requires_preceded : Warning<
   "%0 attribute on %1 must be preceded by %2 attribute">,
   InGroup<ThreadSafetyAttributes>, DefaultIgnore;
 def warn_thread_attribute_not_on_fun_ptr : Warning<
-  "%0 attribute on a %select{variable|field}1 requires the 
%select{variable|field}1 to be of function pointer type">,
+  "%0 attribute on a %select{variable|field}1 requires the 
%select{variable|field}1 to be of function pointer or function reference type">,
   InGroup<ThreadSafetyAttributes>, DefaultIgnore;
 def err_attribute_argument_out_of_bounds_extra_info : Error<
   "%0 attribute parameter %1 is out of bounds: "
diff --git a/clang/lib/Analysis/ThreadSafety.cpp 
b/clang/lib/Analysis/ThreadSafety.cpp
index 57936aa5dfa8b..2c993342ba0b3 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -67,10 +67,12 @@ ThreadSafetyHandler::~ThreadSafetyHandler() = default;
 ///
 /// Sema accepts capability attributes on a parameter for two unrelated
 /// purposes: a scoped-lockable parameter, where the attributes describe the
-/// locks the passed scope object holds, and a function pointer parameter, 
where
-/// they describe the requirements of the function called through the pointer.
-static bool isFunctionPointerParam(const ParmVarDecl *Param) {
-  return Param->getType().getNonReferenceType()->isFunctionPointerType();
+/// locks the passed scope object holds, and a parameter naming a function to
+/// call -- a function pointer or a function reference -- where they describe
+/// the requirements of the function called through it.
+static bool isCallbackParam(const ParmVarDecl *Param) {
+  QualType T = Param->getType().getNonReferenceType();
+  return T->isFunctionPointerType() || T->isFunctionType();
 }
 
 /// Issue a warning about an invalid lock expression
@@ -2338,7 +2340,7 @@ void BuildLockset::handleCall(const Expr *Exp, const 
NamedDecl *D,
   const auto *CalledFunction = dyn_cast<FunctionDecl>(D);
   if (CalledFunction && Args.has_value()) {
     for (auto [Param, Arg] : zip(CalledFunction->parameters(), *Args)) {
-      if (isFunctionPointerParam(Param))
+      if (isCallbackParam(Param))
         continue;
       CapExprSet DeclaredLocks;
       for (const Attr *At : Param->attrs()) {
@@ -2912,7 +2914,7 @@ void 
ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
     else
       llvm_unreachable("Unknown function kind");
     for (const ParmVarDecl *Param : Params) {
-      if (isFunctionPointerParam(Param))
+      if (isCallbackParam(Param))
         continue;
       CapExprSet UnderlyingLocks;
       for (const auto *Attr : Param->attrs()) {
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 1b272b5416860..492b125587344 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -436,18 +436,20 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl 
*D,
   }
 }
 
-/// True if T (or its pointee, after stripping a top-level reference) is a
-/// function pointer or dependent.
-static bool isFunctionPointerOrDependent(QualType T) {
+/// True if T names a function to call: a function pointer, a function
+/// reference, or a reference to a function pointer. Dependent types are also
+/// accepted, and re-checked after instantiation.
+static bool isCallbackOrDependent(QualType T) {
   T = T.getNonReferenceType();
-  return T->isDependentType() || T->isFunctionPointerType();
+  return T->isDependentType() || T->isFunctionPointerType() ||
+         T->isFunctionType();
 }
 
 /// Checks that thread-safety attributes on variables or fields apply only to
-/// function pointer types.
+/// function pointer or function reference types.
 static bool checkThreadSafetyValueDeclIsFunPtr(Sema &S, const ValueDecl *VD,
                                                const AttributeCommonInfo &A) {
-  if (isFunctionPointerOrDependent(VD->getType()))
+  if (isCallbackOrDependent(VD->getType()))
     return true;
   S.Diag(A.getLoc(), diag::warn_thread_attribute_not_on_fun_ptr)
       << A << (isa<FieldDecl>(VD) ? 1 : 0);
@@ -477,8 +479,8 @@ static bool checkThreadSafetyAttrSubject(Sema &S, Decl *D, 
const ParsedAttr &AL,
 
   if (CheckParmVar) {
     if (const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
-      // A function-pointer parameter is also valid here.
-      if (isFunctionPointerOrDependent(PVD->getType()))
+      // A function-pointer or function-reference parameter is also valid here.
+      if (isCallbackOrDependent(PVD->getType()))
         return true;
       return checkFunParamsAreScopedLockable(S, PVD, AL);
     }
@@ -500,7 +502,7 @@ bool Sema::checkInstantiatedThreadSafetyAttrs(const Decl 
*D, const Attr *A) {
   // Parameters of template functions need to be re-checked during
   // instantiation because their types might have been dependent.
   if (const auto *PVD = dyn_cast<ParmVarDecl>(VD)) {
-    if (isFunctionPointerOrDependent(PVD->getType()))
+    if (isCallbackOrDependent(PVD->getType()))
       return true;
     return checkFunParamsAreScopedLockable(*this, PVD, *A);
   }
diff --git a/clang/test/Sema/attr-capabilities.c 
b/clang/test/Sema/attr-capabilities.c
index 6d594bca07535..1c1beb9eea59d 100644
--- a/clang/test/Sema/attr-capabilities.c
+++ b/clang/test/Sema/attr-capabilities.c
@@ -13,9 +13,9 @@ struct __attribute__((capability("custom"))) CustomName {};
 
 int Test1 __attribute__((capability("test1")));  // expected-error 
{{'capability' attribute only applies to structs, unions, classes, and 
typedefs}}
 int Test2 __attribute__((shared_capability("test2"))); // expected-error 
{{'shared_capability' attribute only applies to structs, unions, classes, and 
typedefs}}
-int Test3 __attribute__((acquire_capability("test3")));  // expected-warning 
{{'acquire_capability' attribute on a variable requires the variable to be of 
function pointer type}}
-int Test4 __attribute__((try_acquire_capability("test4"))); // 
expected-warning {{'try_acquire_capability' attribute on a variable requires 
the variable to be of function pointer type}}
-int Test5 __attribute__((release_capability("test5"))); // expected-warning 
{{'release_capability' attribute on a variable requires the variable to be of 
function pointer type}}
+int Test3 __attribute__((acquire_capability("test3")));  // expected-warning 
{{'acquire_capability' attribute on a variable requires the variable to be of 
function pointer or function reference type}}
+int Test4 __attribute__((try_acquire_capability("test4"))); // 
expected-warning {{'try_acquire_capability' attribute on a variable requires 
the variable to be of function pointer or function reference type}}
+int Test5 __attribute__((release_capability("test5"))); // expected-warning 
{{'release_capability' attribute on a variable requires the variable to be of 
function pointer or function reference type}}
 
 struct __attribute__((capability(12))) Test3 {}; // expected-error {{expected 
string literal as argument of 'capability' attribute}}
 struct __attribute__((shared_capability(Test2))) Test4 {}; // expected-error 
{{expected string literal as argument of 'shared_capability' attribute}}
diff --git a/clang/test/Sema/warn-thread-safety-analysis.c 
b/clang/test/Sema/warn-thread-safety-analysis.c
index a439f1ca51623..bc6ffcb379777 100644
--- a/clang/test/Sema/warn-thread-safety-analysis.c
+++ b/clang/test/Sema/warn-thread-safety-analysis.c
@@ -322,20 +322,20 @@ void test_fp_ops_fail(struct FPOps *ops) {
 // Function pointer parameters. The attributes constrain the function reached
 // through the pointer, so they are checked where the pointer is called, and
 // must not be mistaken for requirements of the enclosing function's callers
-// (nor for scoped-lockable parameter annotations).
+// (nor for scoped-lockable parameter annotations). SemaCXX's
+// warn-thread-safety-analysis.cpp covers the C++ spellings of this.
 typedef void (*visit_fn)(int);
 
+void visit_cb(int x) EXCLUSIVE_LOCKS_REQUIRED(mu1);
 void visit_all(visit_fn visit EXCLUSIVE_LOCKS_REQUIRED(mu1), int n);
-void visit_all_locked_fp(void (*visit)(int) EXCLUSIVE_LOCKS_REQUIRED(mu1), int 
n)
+void visit_all_locked_fp(visit_fn visit EXCLUSIVE_LOCKS_REQUIRED(mu1), int n)
     EXCLUSIVE_LOCKS_REQUIRED(mu1) {
   visit(n);
 }
-void visit_all_unlocked_fp(void (*visit)(int) EXCLUSIVE_LOCKS_REQUIRED(mu1), 
int n) {
+void visit_all_unlocked_fp(visit_fn visit EXCLUSIVE_LOCKS_REQUIRED(mu1), int 
n) {
   visit(n); // expected-warning {{calling function 'visit' requires holding 
mutex 'mu1' exclusively}}
 }
 
-void visit_cb(int x) EXCLUSIVE_LOCKS_REQUIRED(mu1);
-
 // Passing an annotated callee is not itself a use of the capability, so these
 // calls do not require mu1 to be held here.
 void test_fp_param(int n) {
diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp 
b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
index f82da827bd068..1a6d5cd117ca9 100644
--- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -8206,4 +8206,97 @@ void test_attr_refers_to_param(Mutex *m) {
   m->Unlock();
 }
 
+// Function references name a function to call just like function pointers do.
+void lock_impl(void) EXCLUSIVE_LOCK_FUNCTION(mu);
+void unlock_impl(void) UNLOCK_FUNCTION(mu);
+void requires_impl(void) EXCLUSIVE_LOCKS_REQUIRED(mu);
+
+void (&lock_ref)(void) EXCLUSIVE_LOCK_FUNCTION(mu) = lock_impl;
+void (&unlock_ref)(void) UNLOCK_FUNCTION(mu) = unlock_impl;
+void (&requires_ref)(void) EXCLUSIVE_LOCKS_REQUIRED(mu) = requires_impl;
+
+void testReferenceAcquireRelease() {
+  lock_ref();
+  x = 1;
+  requires_ref();
+  unlock_ref();
+}
+
+void testReferenceRequiresFail() {
+  requires_ref(); // expected-warning {{calling function 'requires_ref' 
requires holding mutex 'mu' exclusively}}
+}
+
 } // namespace FunctionPointers
+
+namespace FunctionPointerParams {
+
+// Capability attributes on a parameter that names a function to call -- a
+// function pointer, a function reference, or a reference to either -- describe
+// the function reached through the parameter, not a capability that the bound
+// argument stands for. They are checked where the parameter is called, and are
+// neither requirements on nor effects for callers of the enclosing function.
+
+Mutex mu;
+int x GUARDED_BY(mu);
+
+void callback(int) EXCLUSIVE_LOCKS_REQUIRED(mu);
+
+void takes_ptr(void (*cb)(int) EXCLUSIVE_LOCKS_REQUIRED(mu), int n);
+void takes_ref(void (&cb)(int) EXCLUSIVE_LOCKS_REQUIRED(mu), int n);
+void takes_ptr_ref(void (*&cb)(int) EXCLUSIVE_LOCKS_REQUIRED(mu), int n);
+
+// Passing an annotated callee is not itself a use of the capability.
+void testPassCallback(void (*&pcb)(int), int n) {
+  takes_ptr(callback, n);
+  takes_ptr(&callback, n);
+  takes_ref(callback, n);
+  takes_ptr_ref(pcb, n);
+}
+
+// The attributes are checked at the indirect call instead ...
+void testCallPtr(void (*cb)(int) EXCLUSIVE_LOCKS_REQUIRED(mu), int n) {
+  cb(n); // expected-warning {{calling function 'cb' requires holding mutex 
'mu' exclusively}}
+}
+
+void testCallRef(void (&cb)(int) EXCLUSIVE_LOCKS_REQUIRED(mu), int n) {
+  cb(n); // expected-warning {{calling function 'cb' requires holding mutex 
'mu' exclusively}}
+}
+
+void testCallPtrRef(void (*&cb)(int) EXCLUSIVE_LOCKS_REQUIRED(mu), int n) {
+  cb(n); // expected-warning {{calling function 'cb' requires holding mutex 
'mu' exclusively}}
+}
+
+// ... where the enclosing function's own requirements can satisfy them.
+void testCallRefLocked(void (&cb)(int) EXCLUSIVE_LOCKS_REQUIRED(mu), int n)
+    EXCLUSIVE_LOCKS_REQUIRED(mu) {
+  cb(n);
+}
+
+// Acquire and release likewise describe the function called through the
+// parameter, so calling the enclosing function neither acquires nor releases.
+void takes_locker(void (&lock)(void) EXCLUSIVE_LOCK_FUNCTION(mu));
+void lock_impl(void) EXCLUSIVE_LOCK_FUNCTION(mu);
+
+void testAcquireNotTransferred() {
+  takes_locker(lock_impl);
+  x = 1; // expected-warning {{writing variable 'x' requires holding mutex 
'mu' exclusively}}
+}
+
+void testCallAcquires(void (&lock)(void) EXCLUSIVE_LOCK_FUNCTION(mu)) {
+  lock();
+  x = 1;
+  mu.Unlock();
+}
+
+// A dependent parameter type is classified after instantiation.
+template <typename F>
+void callDependent(F cb EXCLUSIVE_LOCKS_REQUIRED(mu), int n) {
+  cb(n); // expected-warning 2 {{calling function 'cb' requires holding mutex 
'mu' exclusively}}
+}
+
+void testDependent(int n) {
+  callDependent<void (*)(int)>(callback, n); // expected-note {{in 
instantiation of function template specialization 
'FunctionPointerParams::callDependent<void (*)(int)>' requested here}}
+  callDependent<void (&)(int)>(callback, n); // expected-note {{in 
instantiation of function template specialization 
'FunctionPointerParams::callDependent<void (&)(int)>' requested here}}
+}
+
+} // namespace FunctionPointerParams
diff --git a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp 
b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp
index 368c20cb45209..2e764a9f59f45 100644
--- a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -596,17 +596,17 @@ int elf_testfn(int y) EXCLUSIVE_LOCK_FUNCTION(); // 
expected-warning {{'exclusiv
 
 int elf_testfn(int y) {
   int x EXCLUSIVE_LOCK_FUNCTION() = y; // \
-    // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+    // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
   return x;
 };
 
 int elf_test_var EXCLUSIVE_LOCK_FUNCTION(); // \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 
 class ElfFoo {
  private:
   int test_field EXCLUSIVE_LOCK_FUNCTION(); // \
-    // expected-warning {{'exclusive_lock_function' attribute on a field 
requires the field to be of function pointer type}}
+    // expected-warning {{'exclusive_lock_function' attribute on a field 
requires the field to be of function pointer or function reference type}}
   void test_method() EXCLUSIVE_LOCK_FUNCTION(); // \
     // expected-warning {{'exclusive_lock_function' attribute without 
capability arguments refers to 'this', but 'ElfFoo' isn't annotated with 
'capability' or 'scoped_lockable' attribute}}
 };
@@ -617,7 +617,7 @@ class EXCLUSIVE_LOCK_FUNCTION() ElfTestClass { // \
 
 void elf_fun_params1(MutexLock& scope EXCLUSIVE_LOCK_FUNCTION(mu1));
 void elf_fun_params2(int lvar EXCLUSIVE_LOCK_FUNCTION(mu1)); // \
-  // expected-warning{{'exclusive_lock_function' attribute applies to function 
parameters only if their type is a reference to a 'scoped_lockable'-annotated 
type}}
+  // expected-warning{{'exclusive_lock_function' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
 void elf_fun_params3(MutexLock& scope EXCLUSIVE_LOCK_FUNCTION()); // \
   // expected-warning{{'exclusive_lock_function' attribute without capability 
arguments can only be applied to non-static methods of a class}}
 
@@ -690,23 +690,23 @@ int slf_testfn(int y) SHARED_LOCK_FUNCTION(); // 
expected-warning {{'shared_lock
 
 int slf_testfn(int y) {
   int x SHARED_LOCK_FUNCTION() = y; // \
-    // expected-warning {{'shared_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+    // expected-warning {{'shared_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
   return x;
 };
 
 int slf_test_var SHARED_LOCK_FUNCTION(); // \
-  // expected-warning {{'shared_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'shared_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 
 void slf_fun_params1(MutexLock& scope SHARED_LOCK_FUNCTION(mu1));
 void slf_fun_params2(int lvar SHARED_LOCK_FUNCTION(mu1)); // \
-  // expected-warning {{'shared_lock_function' attribute applies to function 
parameters only if their type is a reference to a 'scoped_lockable'-annotated 
type}}
+  // expected-warning {{'shared_lock_function' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
 void slf_fun_params3(MutexLock& scope SHARED_LOCK_FUNCTION()); // \
   // expected-warning {{'shared_lock_function' attribute without capability 
arguments can only be applied to non-static methods of a class}}
 
 class SlfFoo {
  private:
   int test_field SHARED_LOCK_FUNCTION(); // \
-    // expected-warning {{'shared_lock_function' attribute on a field requires 
the field to be of function pointer type}}
+    // expected-warning {{'shared_lock_function' attribute on a field requires 
the field to be of function pointer or function reference type}}
   void test_method() SHARED_LOCK_FUNCTION(); // \
     // expected-warning {{'shared_lock_function' attribute without capability 
arguments refers to 'this', but 'SlfFoo' isn't annotated with 'capability' or 
'scoped_lockable' attribute}}
 };
@@ -790,17 +790,17 @@ int etf_testfn(int y) EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
 
 int etf_testfn(int y) {
   int x EXCLUSIVE_TRYLOCK_FUNCTION(1) = y; // \
-    // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+    // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
   return x;
 };
 
 int etf_test_var EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
-  // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 
 class EtfFoo {
  private:
   int test_field EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
-    // expected-warning {{'exclusive_trylock_function' attribute on a field 
requires the field to be of function pointer type}}
+    // expected-warning {{'exclusive_trylock_function' attribute on a field 
requires the field to be of function pointer or function reference type}}
   void test_method() EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
     // expected-warning {{'exclusive_trylock_function' attribute without 
capability arguments refers to 'this', but 'EtfFoo' isn't annotated with 
'capability' or 'scoped_lockable' attribute}}
 };
@@ -810,7 +810,7 @@ class EXCLUSIVE_TRYLOCK_FUNCTION(1) EtfTestClass { // \
 };
 
 void etf_fun_params(int lvar EXCLUSIVE_TRYLOCK_FUNCTION(1)); // \
-  // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 
 // Check argument parsing.
 
@@ -885,21 +885,21 @@ int stf_testfn(int y) SHARED_TRYLOCK_FUNCTION(1); // \
 
 int stf_testfn(int y) {
   int x SHARED_TRYLOCK_FUNCTION(1) = y; // \
-    // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+    // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
   return x;
 };
 
 int stf_test_var SHARED_TRYLOCK_FUNCTION(1); // \
-  // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 
 void stf_fun_params(int lvar SHARED_TRYLOCK_FUNCTION(1)); // \
-  // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 
 
 class StfFoo {
  private:
   int test_field SHARED_TRYLOCK_FUNCTION(1); // \
-    // expected-warning {{'shared_trylock_function' attribute on a field 
requires the field to be of function pointer type}}
+    // expected-warning {{'shared_trylock_function' attribute on a field 
requires the field to be of function pointer or function reference type}}
   void test_method() SHARED_TRYLOCK_FUNCTION(1); // \
     // expected-warning {{'shared_trylock_function' attribute without 
capability arguments refers to 'this', but 'StfFoo' isn't annotated with 
'capability' or 'scoped_lockable' attribute}}
 };
@@ -978,17 +978,17 @@ int uf_testfn(int y) UNLOCK_FUNCTION(); //\
 
 int uf_testfn(int y) {
   int x UNLOCK_FUNCTION() = y; // \
-    // expected-warning {{'unlock_function' attribute on a variable requires 
the variable to be of function pointer type}}
+    // expected-warning {{'unlock_function' attribute on a variable requires 
the variable to be of function pointer or function reference type}}
   return x;
 };
 
 int uf_test_var UNLOCK_FUNCTION(); // \
-  // expected-warning {{'unlock_function' attribute on a variable requires the 
variable to be of function pointer type}}
+  // expected-warning {{'unlock_function' attribute on a variable requires the 
variable to be of function pointer or function reference type}}
 
 class UfFoo {
  private:
   int test_field UNLOCK_FUNCTION(); // \
-    // expected-warning {{'unlock_function' attribute on a field requires the 
field to be of function pointer type}}
+    // expected-warning {{'unlock_function' attribute on a field requires the 
field to be of function pointer or function reference type}}
   void test_method() UNLOCK_FUNCTION(); // \
     // expected-warning {{'unlock_function' attribute without capability 
arguments refers to 'this', but 'UfFoo' isn't annotated with 'capability' or 
'scoped_lockable' attribute}}
 };
@@ -999,7 +999,7 @@ class NO_THREAD_SAFETY_ANALYSIS UfTestClass { // \
 
 void uf_fun_params1(MutexLock& scope UNLOCK_FUNCTION(mu1));
 void uf_fun_params2(int lvar UNLOCK_FUNCTION(mu1)); // \
-  // expected-warning {{'unlock_function' attribute applies to function 
parameters only if their type is a reference to a 'scoped_lockable'-annotated 
type}}
+  // expected-warning {{'unlock_function' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
 void uf_fun_params3(MutexLock& scope UNLOCK_FUNCTION()); // \
   // expected-warning {{'unlock_function' attribute without capability 
arguments can only be applied to non-static methods of a class}}
 
@@ -1143,20 +1143,20 @@ int le_testfn(int y) LOCKS_EXCLUDED(mu1);
 
 int le_testfn(int y) {
   int x LOCKS_EXCLUDED(mu1) = y; // \
-    // expected-warning {{'locks_excluded' attribute on a variable requires 
the variable to be of function pointer type}}
+    // expected-warning {{'locks_excluded' attribute on a variable requires 
the variable to be of function pointer or function reference type}}
   return x;
 };
 
 int le_test_var LOCKS_EXCLUDED(mu1); // \
-  // expected-warning {{'locks_excluded' attribute on a variable requires the 
variable to be of function pointer type}}
+  // expected-warning {{'locks_excluded' attribute on a variable requires the 
variable to be of function pointer or function reference type}}
 
 void le_fun_params1(MutexLock& scope LOCKS_EXCLUDED(mu1));
 void le_fun_params2(int lvar LOCKS_EXCLUDED(mu1)); // \
-  // expected-warning{{'locks_excluded' attribute applies to function 
parameters only if their type is a reference to a 'scoped_lockable'-annotated 
type}}
+  // expected-warning{{'locks_excluded' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
 
 template <typename T>
 void le_fun_params3(T& lvar LOCKS_EXCLUDED(mu1)) {} // \
-  // expected-warning{{'locks_excluded' attribute applies to function 
parameters only if their type is a reference to a 'scoped_lockable'-annotated 
type}}
+  // expected-warning{{'locks_excluded' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
 void call_le_fun_params3(int i) {
   MutexLock scope(&mu1);
   le_fun_params3(i); // expected-note {{while substituting deduced template 
arguments into function template 'le_fun_params3' [with T = int]}}
@@ -1166,7 +1166,7 @@ void call_le_fun_params3(int i) {
 class LeFoo {
  private:
   int test_field LOCKS_EXCLUDED(mu1); // \
-    // expected-warning {{'locks_excluded' attribute on a field requires the 
field to be of function pointer type}}
+    // expected-warning {{'locks_excluded' attribute on a field requires the 
field to be of function pointer or function reference type}}
   void test_method() LOCKS_EXCLUDED(mu1);
 };
 
@@ -1237,21 +1237,21 @@ int elr_testfn(int y) EXCLUSIVE_LOCKS_REQUIRED(mu1);
 
 int elr_testfn(int y) {
   int x EXCLUSIVE_LOCKS_REQUIRED(mu1) = y; // \
-    // expected-warning {{'exclusive_locks_required' attribute on a variable 
requires the variable to be of function pointer type}}
+    // expected-warning {{'exclusive_locks_required' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
   return x;
 };
 
 int elr_test_var EXCLUSIVE_LOCKS_REQUIRED(mu1); // \
-  // expected-warning {{'exclusive_locks_required' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'exclusive_locks_required' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 
 void elr_fun_params1(MutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu1));
 void elr_fun_params2(int lvar EXCLUSIVE_LOCKS_REQUIRED(mu1)); // \
-  // expected-warning {{'exclusive_locks_required' attribute applies to 
function parameters only if their type is a reference to a 
'scoped_lockable'-annotated type}}
+  // expected-warning {{'exclusive_locks_required' attribute applies to 
function parameters only if their type is a function pointer, a function 
reference, or a reference to a 'scoped_lockable'-annotated type}}
 
 class ElrFoo {
  private:
   int test_field EXCLUSIVE_LOCKS_REQUIRED(mu1); // \
-    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer type}}
+    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer or function reference type}}
   void test_method() EXCLUSIVE_LOCKS_REQUIRED(mu1);
 };
 
@@ -1324,21 +1324,21 @@ int slr_testfn(int y) SHARED_LOCKS_REQUIRED(mu1);
 
 int slr_testfn(int y) {
   int x SHARED_LOCKS_REQUIRED(mu1) = y; // \
-    // expected-warning {{'shared_locks_required' attribute on a variable 
requires the variable to be of function pointer type}}
+    // expected-warning {{'shared_locks_required' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
   return x;
 };
 
 int slr_test_var SHARED_LOCKS_REQUIRED(mu1); // \
-  // expected-warning {{'shared_locks_required' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'shared_locks_required' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 
 void slr_fun_params1(MutexLock& scope SHARED_LOCKS_REQUIRED(mu1));
 void slr_fun_params2(int lvar SHARED_LOCKS_REQUIRED(mu1)); // \
-  // expected-warning {{'shared_locks_required' attribute applies to function 
parameters only if their type is a reference to a 'scoped_lockable'-annotated 
type}}
+  // expected-warning {{'shared_locks_required' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
 
 class SlrFoo {
  private:
   int test_field SHARED_LOCKS_REQUIRED(mu1); // \
-    // expected-warning {{'shared_locks_required' attribute on a field 
requires the field to be of function pointer type}}
+    // expected-warning {{'shared_locks_required' attribute on a field 
requires the field to be of function pointer or function reference type}}
   void test_method() SHARED_LOCKS_REQUIRED(mu1);
 };
 
@@ -1784,21 +1784,32 @@ void fp_param_assert(void (*pf)(void) 
ASSERT_EXCLUSIVE_LOCK(mu1));
 void fp_param_try(bool (*pf)(void) EXCLUSIVE_TRYLOCK_FUNCTION(true, mu1));
 void fp_ref(void (*&rf)(void) EXCLUSIVE_LOCKS_REQUIRED(mu1));
 
+// Function references name a function to call, just like function pointers.
+void fn_impl(void);
+void (&fn_ref_lock)(void) EXCLUSIVE_LOCK_FUNCTION(mu1) = fn_impl;
+void (&fn_ref_requires)(void) EXCLUSIVE_LOCKS_REQUIRED(mu1) = fn_impl;
+struct FnRefFields {
+  void (&lock)(void) EXCLUSIVE_LOCK_FUNCTION(mu1);
+  void (&requires_mu)(void) EXCLUSIVE_LOCKS_REQUIRED(mu1);
+};
+void fn_ref_param(void (&rf)(void) EXCLUSIVE_LOCK_FUNCTION(mu1));
+void fn_ref_param_requires(void (&rf)(void) EXCLUSIVE_LOCKS_REQUIRED(mu1));
+
 int bad_fp_var EXCLUSIVE_LOCK_FUNCTION(mu1); // \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 struct BadFPFields {
   int bad_field EXCLUSIVE_LOCKS_REQUIRED(mu1); // \
-    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer type}}
+    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer or function reference type}}
 };
 
 // Compound types (array of, pointer/reference to array of function pointers)
 // are not analyzed; a plain function pointer is required.
 void (*fp_array[4])(void) EXCLUSIVE_LOCK_FUNCTION(mu1); // \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 void (*(*fp_ptr_to_array)[4])(void) EXCLUSIVE_LOCK_FUNCTION(mu1); // \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 void (*(&fp_ref_to_array)[4])(void) EXCLUSIVE_LOCK_FUNCTION(mu1) = fp_array; 
// \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
 
 // C++11 spelling at the declaration prefix so attribute applies to variable.
 [[clang::acquire_capability(mu1)]] void (*fp_cxx11)(void);
@@ -1807,9 +1818,9 @@ void (*(&fp_ref_to_array)[4])(void) 
EXCLUSIVE_LOCK_FUNCTION(mu1) = fp_array; //
 template <typename FuncPtr>
 struct DependentFPFields {
   FuncPtr lock EXCLUSIVE_LOCK_FUNCTION(mu1); // \
-    // expected-warning {{'exclusive_lock_function' attribute on a field 
requires the field to be of function pointer type}}
+    // expected-warning {{'exclusive_lock_function' attribute on a field 
requires the field to be of function pointer or function reference type}}
   FuncPtr requires_mu EXCLUSIVE_LOCKS_REQUIRED(mu1); // \
-    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer type}}
+    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer or function reference type}}
 };
 
 typedef void (*GoodLockFn)(void);

>From 373ab06abaf39af7f78bcbaa6eac06d15db1d670 Mon Sep 17 00:00:00 2001
From: Jameson Nash <[email protected]>
Date: Tue, 28 Jul 2026 12:11:50 +0000
Subject: [PATCH 3/3] Thread Safety Analysis: Review feedback on the
 callback-parameter docs and tests

Fold the parameter example into the existing function pointer example block
in the docs, as a positive case, and drop the explanatory paragraph: the
section already says the attributes apply to parameters, and calling through
the parameter behaves as expected.

Keep the diagnostics free of "function reference", which does not need
mentioning in a C translation unit: restore the previous wording of
warn_thread_attribute_not_on_fun_ptr, and only add function pointers to
warn_thread_attribute_not_on_scoped_lockable_param.

Fold the FunctionPointerParams test namespace into FunctionPointers.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 clang/docs/ThreadSafetyAnalysis.md            | 19 +----
 .../clang/Basic/DiagnosticSemaKinds.td        |  5 +-
 clang/test/Sema/attr-capabilities.c           |  6 +-
 .../SemaCXX/warn-thread-safety-analysis.cpp   | 14 +---
 .../SemaCXX/warn-thread-safety-parsing.cpp    | 80 +++++++++----------
 5 files changed, 51 insertions(+), 73 deletions(-)

diff --git a/clang/docs/ThreadSafetyAnalysis.md 
b/clang/docs/ThreadSafetyAnalysis.md
index 610cccf777b69..f29b5bbc55e1e 100644
--- a/clang/docs/ThreadSafetyAnalysis.md
+++ b/clang/docs/ThreadSafetyAnalysis.md
@@ -532,24 +532,11 @@ void test(Ops *ops) {
   ops->read();
   unlock_fn();
 }
-```
-
-On a parameter, the attributes describe the function reached through the
-parameter, not a capability that the argument stands for: they are checked
-where the parameter is called, and are neither requirements on nor effects for
-callers of the enclosing function. (Contrast this with a parameter of
-`scoped_lockable` reference type, where the attributes describe the locks that
-the passed scope object holds; see {ref}`scoped_capability`.)
 
-```c++
 void visit_all(void (*visit)(int) REQUIRES(mu), int n) {
-  visit(n); // warning: calling function 'visit' requires holding mutex 'mu'
-}
-
-void visit_cb(int) REQUIRES(mu);
-
-void test_param(int n) {
-  visit_all(visit_cb, n); // OK: passing a callee is not a use of 'mu'
+  lock_fn();
+  visit(n); // OK: 'mu' is held here
+  unlock_fn();
 }
 ```
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8f58c725570f4..d9d0d485f16ac 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4350,14 +4350,13 @@ def warn_thread_attribute_decl_not_pointer : Warning<
   InGroup<ThreadSafetyAttributes>, DefaultIgnore;
 def warn_thread_attribute_not_on_scoped_lockable_param : Warning<
   "%0 attribute applies to function parameters only if their type is a "
-  "function pointer, a function reference, or a reference to a "
-  "'scoped_lockable'-annotated type">,
+  "function pointer or a reference to a 'scoped_lockable'-annotated type">,
   InGroup<ThreadSafetyAttributes>, DefaultIgnore;
 def warn_thread_attribute_requires_preceded : Warning<
   "%0 attribute on %1 must be preceded by %2 attribute">,
   InGroup<ThreadSafetyAttributes>, DefaultIgnore;
 def warn_thread_attribute_not_on_fun_ptr : Warning<
-  "%0 attribute on a %select{variable|field}1 requires the 
%select{variable|field}1 to be of function pointer or function reference type">,
+  "%0 attribute on a %select{variable|field}1 requires the 
%select{variable|field}1 to be of function pointer type">,
   InGroup<ThreadSafetyAttributes>, DefaultIgnore;
 def err_attribute_argument_out_of_bounds_extra_info : Error<
   "%0 attribute parameter %1 is out of bounds: "
diff --git a/clang/test/Sema/attr-capabilities.c 
b/clang/test/Sema/attr-capabilities.c
index 1c1beb9eea59d..6d594bca07535 100644
--- a/clang/test/Sema/attr-capabilities.c
+++ b/clang/test/Sema/attr-capabilities.c
@@ -13,9 +13,9 @@ struct __attribute__((capability("custom"))) CustomName {};
 
 int Test1 __attribute__((capability("test1")));  // expected-error 
{{'capability' attribute only applies to structs, unions, classes, and 
typedefs}}
 int Test2 __attribute__((shared_capability("test2"))); // expected-error 
{{'shared_capability' attribute only applies to structs, unions, classes, and 
typedefs}}
-int Test3 __attribute__((acquire_capability("test3")));  // expected-warning 
{{'acquire_capability' attribute on a variable requires the variable to be of 
function pointer or function reference type}}
-int Test4 __attribute__((try_acquire_capability("test4"))); // 
expected-warning {{'try_acquire_capability' attribute on a variable requires 
the variable to be of function pointer or function reference type}}
-int Test5 __attribute__((release_capability("test5"))); // expected-warning 
{{'release_capability' attribute on a variable requires the variable to be of 
function pointer or function reference type}}
+int Test3 __attribute__((acquire_capability("test3")));  // expected-warning 
{{'acquire_capability' attribute on a variable requires the variable to be of 
function pointer type}}
+int Test4 __attribute__((try_acquire_capability("test4"))); // 
expected-warning {{'try_acquire_capability' attribute on a variable requires 
the variable to be of function pointer type}}
+int Test5 __attribute__((release_capability("test5"))); // expected-warning 
{{'release_capability' attribute on a variable requires the variable to be of 
function pointer type}}
 
 struct __attribute__((capability(12))) Test3 {}; // expected-error {{expected 
string literal as argument of 'capability' attribute}}
 struct __attribute__((shared_capability(Test2))) Test4 {}; // expected-error 
{{expected string literal as argument of 'shared_capability' attribute}}
diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp 
b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
index 1a6d5cd117ca9..75d5cb5f5b0f5 100644
--- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -8226,19 +8226,12 @@ void testReferenceRequiresFail() {
   requires_ref(); // expected-warning {{calling function 'requires_ref' 
requires holding mutex 'mu' exclusively}}
 }
 
-} // namespace FunctionPointers
-
-namespace FunctionPointerParams {
-
 // Capability attributes on a parameter that names a function to call -- a
 // function pointer, a function reference, or a reference to either -- describe
 // the function reached through the parameter, not a capability that the bound
 // argument stands for. They are checked where the parameter is called, and are
 // neither requirements on nor effects for callers of the enclosing function.
 
-Mutex mu;
-int x GUARDED_BY(mu);
-
 void callback(int) EXCLUSIVE_LOCKS_REQUIRED(mu);
 
 void takes_ptr(void (*cb)(int) EXCLUSIVE_LOCKS_REQUIRED(mu), int n);
@@ -8275,7 +8268,6 @@ void testCallRefLocked(void (&cb)(int) 
EXCLUSIVE_LOCKS_REQUIRED(mu), int n)
 // Acquire and release likewise describe the function called through the
 // parameter, so calling the enclosing function neither acquires nor releases.
 void takes_locker(void (&lock)(void) EXCLUSIVE_LOCK_FUNCTION(mu));
-void lock_impl(void) EXCLUSIVE_LOCK_FUNCTION(mu);
 
 void testAcquireNotTransferred() {
   takes_locker(lock_impl);
@@ -8295,8 +8287,8 @@ void callDependent(F cb EXCLUSIVE_LOCKS_REQUIRED(mu), int 
n) {
 }
 
 void testDependent(int n) {
-  callDependent<void (*)(int)>(callback, n); // expected-note {{in 
instantiation of function template specialization 
'FunctionPointerParams::callDependent<void (*)(int)>' requested here}}
-  callDependent<void (&)(int)>(callback, n); // expected-note {{in 
instantiation of function template specialization 
'FunctionPointerParams::callDependent<void (&)(int)>' requested here}}
+  callDependent<void (*)(int)>(callback, n); // expected-note {{in 
instantiation of function template specialization 
'FunctionPointers::callDependent<void (*)(int)>' requested here}}
+  callDependent<void (&)(int)>(callback, n); // expected-note {{in 
instantiation of function template specialization 
'FunctionPointers::callDependent<void (&)(int)>' requested here}}
 }
 
-} // namespace FunctionPointerParams
+} // namespace FunctionPointers
diff --git a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp 
b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp
index 2e764a9f59f45..8ceacb5a83418 100644
--- a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -596,17 +596,17 @@ int elf_testfn(int y) EXCLUSIVE_LOCK_FUNCTION(); // 
expected-warning {{'exclusiv
 
 int elf_testfn(int y) {
   int x EXCLUSIVE_LOCK_FUNCTION() = y; // \
-    // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+    // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
   return x;
 };
 
 int elf_test_var EXCLUSIVE_LOCK_FUNCTION(); // \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 
 class ElfFoo {
  private:
   int test_field EXCLUSIVE_LOCK_FUNCTION(); // \
-    // expected-warning {{'exclusive_lock_function' attribute on a field 
requires the field to be of function pointer or function reference type}}
+    // expected-warning {{'exclusive_lock_function' attribute on a field 
requires the field to be of function pointer type}}
   void test_method() EXCLUSIVE_LOCK_FUNCTION(); // \
     // expected-warning {{'exclusive_lock_function' attribute without 
capability arguments refers to 'this', but 'ElfFoo' isn't annotated with 
'capability' or 'scoped_lockable' attribute}}
 };
@@ -617,7 +617,7 @@ class EXCLUSIVE_LOCK_FUNCTION() ElfTestClass { // \
 
 void elf_fun_params1(MutexLock& scope EXCLUSIVE_LOCK_FUNCTION(mu1));
 void elf_fun_params2(int lvar EXCLUSIVE_LOCK_FUNCTION(mu1)); // \
-  // expected-warning{{'exclusive_lock_function' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
+  // expected-warning{{'exclusive_lock_function' attribute applies to function 
parameters only if their type is a function pointer or a reference to a 
'scoped_lockable'-annotated type}}
 void elf_fun_params3(MutexLock& scope EXCLUSIVE_LOCK_FUNCTION()); // \
   // expected-warning{{'exclusive_lock_function' attribute without capability 
arguments can only be applied to non-static methods of a class}}
 
@@ -690,23 +690,23 @@ int slf_testfn(int y) SHARED_LOCK_FUNCTION(); // 
expected-warning {{'shared_lock
 
 int slf_testfn(int y) {
   int x SHARED_LOCK_FUNCTION() = y; // \
-    // expected-warning {{'shared_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+    // expected-warning {{'shared_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
   return x;
 };
 
 int slf_test_var SHARED_LOCK_FUNCTION(); // \
-  // expected-warning {{'shared_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'shared_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 
 void slf_fun_params1(MutexLock& scope SHARED_LOCK_FUNCTION(mu1));
 void slf_fun_params2(int lvar SHARED_LOCK_FUNCTION(mu1)); // \
-  // expected-warning {{'shared_lock_function' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
+  // expected-warning {{'shared_lock_function' attribute applies to function 
parameters only if their type is a function pointer or a reference to a 
'scoped_lockable'-annotated type}}
 void slf_fun_params3(MutexLock& scope SHARED_LOCK_FUNCTION()); // \
   // expected-warning {{'shared_lock_function' attribute without capability 
arguments can only be applied to non-static methods of a class}}
 
 class SlfFoo {
  private:
   int test_field SHARED_LOCK_FUNCTION(); // \
-    // expected-warning {{'shared_lock_function' attribute on a field requires 
the field to be of function pointer or function reference type}}
+    // expected-warning {{'shared_lock_function' attribute on a field requires 
the field to be of function pointer type}}
   void test_method() SHARED_LOCK_FUNCTION(); // \
     // expected-warning {{'shared_lock_function' attribute without capability 
arguments refers to 'this', but 'SlfFoo' isn't annotated with 'capability' or 
'scoped_lockable' attribute}}
 };
@@ -790,17 +790,17 @@ int etf_testfn(int y) EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
 
 int etf_testfn(int y) {
   int x EXCLUSIVE_TRYLOCK_FUNCTION(1) = y; // \
-    // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+    // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
   return x;
 };
 
 int etf_test_var EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
-  // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 
 class EtfFoo {
  private:
   int test_field EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
-    // expected-warning {{'exclusive_trylock_function' attribute on a field 
requires the field to be of function pointer or function reference type}}
+    // expected-warning {{'exclusive_trylock_function' attribute on a field 
requires the field to be of function pointer type}}
   void test_method() EXCLUSIVE_TRYLOCK_FUNCTION(1); // \
     // expected-warning {{'exclusive_trylock_function' attribute without 
capability arguments refers to 'this', but 'EtfFoo' isn't annotated with 
'capability' or 'scoped_lockable' attribute}}
 };
@@ -810,7 +810,7 @@ class EXCLUSIVE_TRYLOCK_FUNCTION(1) EtfTestClass { // \
 };
 
 void etf_fun_params(int lvar EXCLUSIVE_TRYLOCK_FUNCTION(1)); // \
-  // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'exclusive_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 
 // Check argument parsing.
 
@@ -885,21 +885,21 @@ int stf_testfn(int y) SHARED_TRYLOCK_FUNCTION(1); // \
 
 int stf_testfn(int y) {
   int x SHARED_TRYLOCK_FUNCTION(1) = y; // \
-    // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+    // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
   return x;
 };
 
 int stf_test_var SHARED_TRYLOCK_FUNCTION(1); // \
-  // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 
 void stf_fun_params(int lvar SHARED_TRYLOCK_FUNCTION(1)); // \
-  // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'shared_trylock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 
 
 class StfFoo {
  private:
   int test_field SHARED_TRYLOCK_FUNCTION(1); // \
-    // expected-warning {{'shared_trylock_function' attribute on a field 
requires the field to be of function pointer or function reference type}}
+    // expected-warning {{'shared_trylock_function' attribute on a field 
requires the field to be of function pointer type}}
   void test_method() SHARED_TRYLOCK_FUNCTION(1); // \
     // expected-warning {{'shared_trylock_function' attribute without 
capability arguments refers to 'this', but 'StfFoo' isn't annotated with 
'capability' or 'scoped_lockable' attribute}}
 };
@@ -978,17 +978,17 @@ int uf_testfn(int y) UNLOCK_FUNCTION(); //\
 
 int uf_testfn(int y) {
   int x UNLOCK_FUNCTION() = y; // \
-    // expected-warning {{'unlock_function' attribute on a variable requires 
the variable to be of function pointer or function reference type}}
+    // expected-warning {{'unlock_function' attribute on a variable requires 
the variable to be of function pointer type}}
   return x;
 };
 
 int uf_test_var UNLOCK_FUNCTION(); // \
-  // expected-warning {{'unlock_function' attribute on a variable requires the 
variable to be of function pointer or function reference type}}
+  // expected-warning {{'unlock_function' attribute on a variable requires the 
variable to be of function pointer type}}
 
 class UfFoo {
  private:
   int test_field UNLOCK_FUNCTION(); // \
-    // expected-warning {{'unlock_function' attribute on a field requires the 
field to be of function pointer or function reference type}}
+    // expected-warning {{'unlock_function' attribute on a field requires the 
field to be of function pointer type}}
   void test_method() UNLOCK_FUNCTION(); // \
     // expected-warning {{'unlock_function' attribute without capability 
arguments refers to 'this', but 'UfFoo' isn't annotated with 'capability' or 
'scoped_lockable' attribute}}
 };
@@ -999,7 +999,7 @@ class NO_THREAD_SAFETY_ANALYSIS UfTestClass { // \
 
 void uf_fun_params1(MutexLock& scope UNLOCK_FUNCTION(mu1));
 void uf_fun_params2(int lvar UNLOCK_FUNCTION(mu1)); // \
-  // expected-warning {{'unlock_function' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
+  // expected-warning {{'unlock_function' attribute applies to function 
parameters only if their type is a function pointer or a reference to a 
'scoped_lockable'-annotated type}}
 void uf_fun_params3(MutexLock& scope UNLOCK_FUNCTION()); // \
   // expected-warning {{'unlock_function' attribute without capability 
arguments can only be applied to non-static methods of a class}}
 
@@ -1143,20 +1143,20 @@ int le_testfn(int y) LOCKS_EXCLUDED(mu1);
 
 int le_testfn(int y) {
   int x LOCKS_EXCLUDED(mu1) = y; // \
-    // expected-warning {{'locks_excluded' attribute on a variable requires 
the variable to be of function pointer or function reference type}}
+    // expected-warning {{'locks_excluded' attribute on a variable requires 
the variable to be of function pointer type}}
   return x;
 };
 
 int le_test_var LOCKS_EXCLUDED(mu1); // \
-  // expected-warning {{'locks_excluded' attribute on a variable requires the 
variable to be of function pointer or function reference type}}
+  // expected-warning {{'locks_excluded' attribute on a variable requires the 
variable to be of function pointer type}}
 
 void le_fun_params1(MutexLock& scope LOCKS_EXCLUDED(mu1));
 void le_fun_params2(int lvar LOCKS_EXCLUDED(mu1)); // \
-  // expected-warning{{'locks_excluded' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
+  // expected-warning{{'locks_excluded' attribute applies to function 
parameters only if their type is a function pointer or a reference to a 
'scoped_lockable'-annotated type}}
 
 template <typename T>
 void le_fun_params3(T& lvar LOCKS_EXCLUDED(mu1)) {} // \
-  // expected-warning{{'locks_excluded' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
+  // expected-warning{{'locks_excluded' attribute applies to function 
parameters only if their type is a function pointer or a reference to a 
'scoped_lockable'-annotated type}}
 void call_le_fun_params3(int i) {
   MutexLock scope(&mu1);
   le_fun_params3(i); // expected-note {{while substituting deduced template 
arguments into function template 'le_fun_params3' [with T = int]}}
@@ -1166,7 +1166,7 @@ void call_le_fun_params3(int i) {
 class LeFoo {
  private:
   int test_field LOCKS_EXCLUDED(mu1); // \
-    // expected-warning {{'locks_excluded' attribute on a field requires the 
field to be of function pointer or function reference type}}
+    // expected-warning {{'locks_excluded' attribute on a field requires the 
field to be of function pointer type}}
   void test_method() LOCKS_EXCLUDED(mu1);
 };
 
@@ -1237,21 +1237,21 @@ int elr_testfn(int y) EXCLUSIVE_LOCKS_REQUIRED(mu1);
 
 int elr_testfn(int y) {
   int x EXCLUSIVE_LOCKS_REQUIRED(mu1) = y; // \
-    // expected-warning {{'exclusive_locks_required' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+    // expected-warning {{'exclusive_locks_required' attribute on a variable 
requires the variable to be of function pointer type}}
   return x;
 };
 
 int elr_test_var EXCLUSIVE_LOCKS_REQUIRED(mu1); // \
-  // expected-warning {{'exclusive_locks_required' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'exclusive_locks_required' attribute on a variable 
requires the variable to be of function pointer type}}
 
 void elr_fun_params1(MutexLock& scope EXCLUSIVE_LOCKS_REQUIRED(mu1));
 void elr_fun_params2(int lvar EXCLUSIVE_LOCKS_REQUIRED(mu1)); // \
-  // expected-warning {{'exclusive_locks_required' attribute applies to 
function parameters only if their type is a function pointer, a function 
reference, or a reference to a 'scoped_lockable'-annotated type}}
+  // expected-warning {{'exclusive_locks_required' attribute applies to 
function parameters only if their type is a function pointer or a reference to 
a 'scoped_lockable'-annotated type}}
 
 class ElrFoo {
  private:
   int test_field EXCLUSIVE_LOCKS_REQUIRED(mu1); // \
-    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer or function reference type}}
+    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer type}}
   void test_method() EXCLUSIVE_LOCKS_REQUIRED(mu1);
 };
 
@@ -1324,21 +1324,21 @@ int slr_testfn(int y) SHARED_LOCKS_REQUIRED(mu1);
 
 int slr_testfn(int y) {
   int x SHARED_LOCKS_REQUIRED(mu1) = y; // \
-    // expected-warning {{'shared_locks_required' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+    // expected-warning {{'shared_locks_required' attribute on a variable 
requires the variable to be of function pointer type}}
   return x;
 };
 
 int slr_test_var SHARED_LOCKS_REQUIRED(mu1); // \
-  // expected-warning {{'shared_locks_required' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'shared_locks_required' attribute on a variable 
requires the variable to be of function pointer type}}
 
 void slr_fun_params1(MutexLock& scope SHARED_LOCKS_REQUIRED(mu1));
 void slr_fun_params2(int lvar SHARED_LOCKS_REQUIRED(mu1)); // \
-  // expected-warning {{'shared_locks_required' attribute applies to function 
parameters only if their type is a function pointer, a function reference, or a 
reference to a 'scoped_lockable'-annotated type}}
+  // expected-warning {{'shared_locks_required' attribute applies to function 
parameters only if their type is a function pointer or a reference to a 
'scoped_lockable'-annotated type}}
 
 class SlrFoo {
  private:
   int test_field SHARED_LOCKS_REQUIRED(mu1); // \
-    // expected-warning {{'shared_locks_required' attribute on a field 
requires the field to be of function pointer or function reference type}}
+    // expected-warning {{'shared_locks_required' attribute on a field 
requires the field to be of function pointer type}}
   void test_method() SHARED_LOCKS_REQUIRED(mu1);
 };
 
@@ -1796,20 +1796,20 @@ void fn_ref_param(void (&rf)(void) 
EXCLUSIVE_LOCK_FUNCTION(mu1));
 void fn_ref_param_requires(void (&rf)(void) EXCLUSIVE_LOCKS_REQUIRED(mu1));
 
 int bad_fp_var EXCLUSIVE_LOCK_FUNCTION(mu1); // \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 struct BadFPFields {
   int bad_field EXCLUSIVE_LOCKS_REQUIRED(mu1); // \
-    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer or function reference type}}
+    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer type}}
 };
 
 // Compound types (array of, pointer/reference to array of function pointers)
 // are not analyzed; a plain function pointer is required.
 void (*fp_array[4])(void) EXCLUSIVE_LOCK_FUNCTION(mu1); // \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 void (*(*fp_ptr_to_array)[4])(void) EXCLUSIVE_LOCK_FUNCTION(mu1); // \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 void (*(&fp_ref_to_array)[4])(void) EXCLUSIVE_LOCK_FUNCTION(mu1) = fp_array; 
// \
-  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer or function reference type}}
+  // expected-warning {{'exclusive_lock_function' attribute on a variable 
requires the variable to be of function pointer type}}
 
 // C++11 spelling at the declaration prefix so attribute applies to variable.
 [[clang::acquire_capability(mu1)]] void (*fp_cxx11)(void);
@@ -1818,9 +1818,9 @@ void (*(&fp_ref_to_array)[4])(void) 
EXCLUSIVE_LOCK_FUNCTION(mu1) = fp_array; //
 template <typename FuncPtr>
 struct DependentFPFields {
   FuncPtr lock EXCLUSIVE_LOCK_FUNCTION(mu1); // \
-    // expected-warning {{'exclusive_lock_function' attribute on a field 
requires the field to be of function pointer or function reference type}}
+    // expected-warning {{'exclusive_lock_function' attribute on a field 
requires the field to be of function pointer type}}
   FuncPtr requires_mu EXCLUSIVE_LOCKS_REQUIRED(mu1); // \
-    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer or function reference type}}
+    // expected-warning {{'exclusive_locks_required' attribute on a field 
requires the field to be of function pointer type}}
 };
 
 typedef void (*GoodLockFn)(void);

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to