llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Aaron Puchert (aaronpuchert)

<details>
<summary>Changes</summary>

Support for attribute parameter packs was added some time ago in commit 
ead1690d31f815c00fdd2bc23db4766191bbeabc. But template substitution didn't 
expand the packs yet. For now expansion can only happen within a 
`VariadicExprArgument`: i.e. in `try_acquire_capability`, which takes a regular 
and a variadic argument, the template can't have a single pack that then 
expands to cover both arguments.

This is a prerequisite for #<!-- -->42000.

---
Full diff: https://github.com/llvm/llvm-project/pull/137477.diff


4 Files Affected:

- (modified) clang/include/clang/Basic/Attr.td (+8) 
- (modified) clang/test/SemaCXX/warn-thread-safety-analysis.cpp (+47) 
- (modified) clang/test/SemaCXX/warn-thread-safety-parsing.cpp (+145-2) 
- (modified) clang/utils/TableGen/ClangAttrEmitter.cpp (+14-16) 


``````````diff
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index dcdcff8c46fe2..2548e60312a0d 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3856,6 +3856,7 @@ def AssertCapability : InheritableAttr {
   let ParseArgumentsAsUnevaluated = 1;
   let InheritEvenIfAlreadyPresent = 1;
   let Args = [VariadicExprArgument<"Args">];
+  let AcceptsExprPack = 1;
   let Accessors = [Accessor<"isShared",
                     [Clang<"assert_shared_capability", 0>,
                      GNU<"assert_shared_lock">]>];
@@ -3873,6 +3874,7 @@ def AcquireCapability : InheritableAttr {
   let ParseArgumentsAsUnevaluated = 1;
   let InheritEvenIfAlreadyPresent = 1;
   let Args = [VariadicExprArgument<"Args">];
+  let AcceptsExprPack = 1;
   let Accessors = [Accessor<"isShared",
                     [Clang<"acquire_shared_capability", 0>,
                      GNU<"shared_lock_function">]>];
@@ -3890,6 +3892,7 @@ def TryAcquireCapability : InheritableAttr {
   let ParseArgumentsAsUnevaluated = 1;
   let InheritEvenIfAlreadyPresent = 1;
   let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
+  let AcceptsExprPack = 1;
   let Accessors = [Accessor<"isShared",
                     [Clang<"try_acquire_shared_capability", 0>,
                      GNU<"shared_trylock_function">]>];
@@ -3907,6 +3910,7 @@ def ReleaseCapability : InheritableAttr {
   let ParseArgumentsAsUnevaluated = 1;
   let InheritEvenIfAlreadyPresent = 1;
   let Args = [VariadicExprArgument<"Args">];
+  let AcceptsExprPack = 1;
   let Accessors = [Accessor<"isShared",
                     [Clang<"release_shared_capability", 0>]>,
                    Accessor<"isGeneric",
@@ -3921,6 +3925,7 @@ def RequiresCapability : InheritableAttr {
                    Clang<"requires_shared_capability", 0>,
                    Clang<"shared_locks_required", 0>];
   let Args = [VariadicExprArgument<"Args">];
+  let AcceptsExprPack = 1;
   let LateParsed = LateAttrParseStandard;
   let TemplateDependent = 1;
   let ParseArgumentsAsUnevaluated = 1;
@@ -3963,6 +3968,7 @@ def PtGuardedBy : InheritableAttr {
 def AcquiredAfter : InheritableAttr {
   let Spellings = [GNU<"acquired_after">];
   let Args = [VariadicExprArgument<"Args">];
+  let AcceptsExprPack = 1;
   let LateParsed = LateAttrParseExperimentalExt;
   let TemplateDependent = 1;
   let ParseArgumentsAsUnevaluated = 1;
@@ -3974,6 +3980,7 @@ def AcquiredAfter : InheritableAttr {
 def AcquiredBefore : InheritableAttr {
   let Spellings = [GNU<"acquired_before">];
   let Args = [VariadicExprArgument<"Args">];
+  let AcceptsExprPack = 1;
   let LateParsed = LateAttrParseExperimentalExt;
   let TemplateDependent = 1;
   let ParseArgumentsAsUnevaluated = 1;
@@ -3995,6 +4002,7 @@ def LockReturned : InheritableAttr {
 def LocksExcluded : InheritableAttr {
   let Spellings = [GNU<"locks_excluded">];
   let Args = [VariadicExprArgument<"Args">];
+  let AcceptsExprPack = 1;
   let LateParsed = LateAttrParseStandard;
   let TemplateDependent = 1;
   let ParseArgumentsAsUnevaluated = 1;
diff --git a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp 
b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
index 2a04e820eb095..4c17294d11e79 100644
--- a/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/clang/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -57,6 +57,20 @@ class SCOPED_LOCKABLE DoubleMutexLock {
   ~DoubleMutexLock() UNLOCK_FUNCTION();
 };
 
+template<typename Mu>
+class SCOPED_LOCKABLE TemplateMutexLock {
+public:
+  TemplateMutexLock(Mu *mu) EXCLUSIVE_LOCK_FUNCTION(mu);
+  ~TemplateMutexLock() UNLOCK_FUNCTION();
+};
+
+template<typename... Mus>
+class SCOPED_LOCKABLE VariadicMutexLock {
+public:
+  VariadicMutexLock(Mus *...mus) EXCLUSIVE_LOCK_FUNCTION(mus...);
+  ~VariadicMutexLock() UNLOCK_FUNCTION();
+};
+
 // The universal lock, written "*", allows checking to be selectively turned
 // off for a particular piece of code.
 void beginNoWarnOnReads()  SHARED_LOCK_FUNCTION("*");
@@ -1821,6 +1835,18 @@ struct TestScopedLockable {
     a = b + 1;
     b = a + 1;
   }
+
+  void foo6() {
+    TemplateMutexLock<Mutex> mulock1(&mu1), mulock2(&mu2);
+    a = b + 1;
+    b = a + 1;
+  }
+
+  void foo7() {
+    VariadicMutexLock<Mutex, Mutex> mulock(&mu1, &mu2);
+    a = b + 1;
+    b = a + 1;
+  }
 };
 
 } // end namespace test_scoped_lockable
@@ -3114,6 +3140,16 @@ class SCOPED_LOCKABLE ReaderMutexUnlock {
   void Unlock() EXCLUSIVE_LOCK_FUNCTION();
 };
 
+template<typename... Mus>
+class SCOPED_LOCKABLE VariadicMutexUnlock {
+public:
+  VariadicMutexUnlock(Mus *...mus) EXCLUSIVE_UNLOCK_FUNCTION(mus...);
+  ~VariadicMutexUnlock() EXCLUSIVE_UNLOCK_FUNCTION();
+
+  void Lock() EXCLUSIVE_UNLOCK_FUNCTION();
+  void Unlock() EXCLUSIVE_LOCK_FUNCTION();
+};
+
 Mutex mu;
 int x GUARDED_BY(mu);
 bool c;
@@ -3176,6 +3212,17 @@ void doubleUnlock() EXCLUSIVE_LOCKS_REQUIRED(mu) {
   scope.Unlock(); // expected-warning {{releasing mutex 'mu' that was not 
held}}
 }
 
+Mutex mu2;
+int y GUARDED_BY(mu2);
+
+void variadic() EXCLUSIVE_LOCKS_REQUIRED(mu, mu2) {
+  VariadicMutexUnlock<Mutex, Mutex> scope(&mu, &mu2);
+  x = 2; // expected-warning {{writing variable 'x' requires holding mutex 
'mu' exclusively}}
+  y = 3; // expected-warning {{writing variable 'y' requires holding mutex 
'mu2' exclusively}}
+  scope.Lock();
+  x = y = 4;
+}
+
 class SCOPED_LOCKABLE MutexLockUnlock {
 public:
   MutexLockUnlock(Mutex *mu1, Mutex *mu2) EXCLUSIVE_UNLOCK_FUNCTION(mu1) 
EXCLUSIVE_LOCK_FUNCTION(mu2);
diff --git a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp 
b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp
index 752803e4a0543..bad71f7cdd07c 100644
--- a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp
+++ b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
 // RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++98 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 %s -D CPP11
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 %s
 
 #define LOCKABLE            __attribute__ ((lockable))
 #define SCOPED_LOCKABLE     __attribute__ ((scoped_lockable))
@@ -643,6 +643,24 @@ int elf_function_bad_6(Mutex x, Mutex y) 
EXCLUSIVE_LOCK_FUNCTION(0); // \
 int elf_function_bad_7() EXCLUSIVE_LOCK_FUNCTION(0); // \
   // expected-error {{'exclusive_lock_function' attribute parameter 1 is out 
of bounds: no parameters to index into}}
 
+template<typename Mu>
+int elf_template(Mu& mu) EXCLUSIVE_LOCK_FUNCTION(mu) {}
+
+template int elf_template<Mutex>(Mutex&);
+// FIXME: warn on template instantiation.
+template int elf_template<UnlockableMu>(UnlockableMu&);
+
+#if __cplusplus >= 201103
+
+template<typename... Mus>
+int elf_variadic_template(Mus&... mus) EXCLUSIVE_LOCK_FUNCTION(mus...) {}
+
+template int elf_variadic_template<Mutex, Mutex>(Mutex&, Mutex&);
+// FIXME: warn on template instantiation.
+template int elf_variadic_template<Mutex, UnlockableMu>(Mutex&, UnlockableMu&);
+
+#endif
+
 
 //-----------------------------------------//
 //  Shared Lock Function (slf)
@@ -719,6 +737,24 @@ int slf_function_bad_6(Mutex x, Mutex y) 
SHARED_LOCK_FUNCTION(0); // \
 int slf_function_bad_7() SHARED_LOCK_FUNCTION(0); // \
   // expected-error {{'shared_lock_function' attribute parameter 1 is out of 
bounds: no parameters to index into}}
 
+template<typename Mu>
+int slf_template(Mu& mu) SHARED_LOCK_FUNCTION(mu) {}
+
+template int slf_template<Mutex>(Mutex&);
+// FIXME: warn on template instantiation.
+template int slf_template<UnlockableMu>(UnlockableMu&);
+
+#if __cplusplus >= 201103
+
+template<typename... Mus>
+int slf_variadic_template(Mus&... mus) SHARED_LOCK_FUNCTION(mus...) {}
+
+template int slf_variadic_template<Mutex, Mutex>(Mutex&, Mutex&);
+// FIXME: warn on template instantiation.
+template int slf_variadic_template<Mutex, UnlockableMu>(Mutex&, UnlockableMu&);
+
+#endif
+
 
 //-----------------------------------------//
 //  Exclusive TryLock Function (etf)
@@ -796,6 +832,24 @@ int etf_function_bad_5() EXCLUSIVE_TRYLOCK_FUNCTION(1, 
muDoublePointer); // \
 int etf_function_bad_6() EXCLUSIVE_TRYLOCK_FUNCTION(1, umu); // \
   // expected-warning {{'exclusive_trylock_function' attribute requires 
arguments whose type is annotated with 'capability' attribute}}
 
+template<typename Mu>
+int etf_template(Mu& mu) EXCLUSIVE_TRYLOCK_FUNCTION(1, mu) {}
+
+template int etf_template<Mutex>(Mutex&);
+// FIXME: warn on template instantiation.
+template int etf_template<UnlockableMu>(UnlockableMu&);
+
+#if __cplusplus >= 201103
+
+template<typename... Mus>
+int etf_variadic_template(Mus&... mus) EXCLUSIVE_TRYLOCK_FUNCTION(1, mus...) {}
+
+template int etf_variadic_template<Mutex, Mutex>(Mutex&, Mutex&);
+// FIXME: warn on template instantiation.
+template int etf_variadic_template<Mutex, UnlockableMu>(Mutex&, UnlockableMu&);
+
+#endif
+
 
 //-----------------------------------------//
 //  Shared TryLock Function (stf)
@@ -874,6 +928,24 @@ int stf_function_bad_5() SHARED_TRYLOCK_FUNCTION(1, 
muDoublePointer); // \
 int stf_function_bad_6() SHARED_TRYLOCK_FUNCTION(1, umu); // \
   // expected-warning {{'shared_trylock_function' attribute requires arguments 
whose type is annotated with 'capability' attribute}}
 
+template<typename Mu>
+int stf_template(Mu& mu) SHARED_TRYLOCK_FUNCTION(1, mu) {}
+
+template int stf_template<Mutex>(Mutex&);
+// FIXME: warn on template instantiation.
+template int stf_template<UnlockableMu>(UnlockableMu&);
+
+#if __cplusplus >= 201103
+
+template<typename... Mus>
+int stf_variadic_template(Mus&... mus) SHARED_TRYLOCK_FUNCTION(1, mus...) {}
+
+template int stf_variadic_template<Mutex, Mutex>(Mutex&, Mutex&);
+// FIXME: warn on template instantiation.
+template int stf_variadic_template<Mutex, UnlockableMu>(Mutex&, UnlockableMu&);
+
+#endif
+
 
 //-----------------------------------------//
 //  Unlock Function (uf)
@@ -953,6 +1025,24 @@ int uf_function_bad_6(Mutex x, Mutex y) 
UNLOCK_FUNCTION(0); // \
 int uf_function_bad_7() UNLOCK_FUNCTION(0); // \
   // expected-error {{'unlock_function' attribute parameter 1 is out of 
bounds: no parameters to index into}}
 
+template<typename Mu>
+int uf_template(Mu& mu) UNLOCK_FUNCTION(mu) {}
+
+template int uf_template<Mutex>(Mutex&);
+// FIXME: warn on template instantiation.
+template int uf_template<UnlockableMu>(UnlockableMu&);
+
+#if __cplusplus >= 201103
+
+template<typename... Mus>
+int uf_variadic_template(Mus&... mus) UNLOCK_FUNCTION(mus...) {}
+
+template int uf_variadic_template<Mutex, Mutex>(Mutex&, Mutex&);
+// FIXME: warn on template instantiation.
+template int uf_variadic_template<Mutex, UnlockableMu>(Mutex&, UnlockableMu&);
+
+#endif
+
 
 //-----------------------------------------//
 //  Lock Returned (lr)
@@ -1088,6 +1178,23 @@ int le_function_bad_3() LOCKS_EXCLUDED(muDoublePointer); 
// \
 int le_function_bad_4() LOCKS_EXCLUDED(umu); // \
   // expected-warning {{'locks_excluded' attribute requires arguments whose 
type is annotated with 'capability' attribute}}
 
+template<typename Mu>
+int le_template(Mu& mu) LOCKS_EXCLUDED(mu) {}
+
+template int le_template<Mutex>(Mutex&);
+// FIXME: warn on template instantiation.
+template int le_template<UnlockableMu>(UnlockableMu&);
+
+#if __cplusplus >= 201103
+
+template<typename... Mus>
+int le_variadic_template(Mus&... mus) LOCKS_EXCLUDED(mus...) {}
+
+template int le_variadic_template<Mutex, Mutex>(Mutex&, Mutex&);
+// FIXME: warn on template instantiation.
+template int le_variadic_template<Mutex, UnlockableMu>(Mutex&, UnlockableMu&);
+
+#endif
 
 
 //-----------------------------------------//
@@ -1156,6 +1263,24 @@ int elr_function_bad_3() 
EXCLUSIVE_LOCKS_REQUIRED(muDoublePointer); // \
 int elr_function_bad_4() EXCLUSIVE_LOCKS_REQUIRED(umu); // \
   // expected-warning {{'exclusive_locks_required' attribute requires 
arguments whose type is annotated with 'capability' attribute}}
 
+template<typename Mu>
+int elr_template(Mu& mu) EXCLUSIVE_LOCKS_REQUIRED(mu) {}
+
+template int elr_template<Mutex>(Mutex&);
+// FIXME: warn on template instantiation.
+template int elr_template<UnlockableMu>(UnlockableMu&);
+
+#if __cplusplus >= 201103
+
+template<typename... Mus>
+int elr_variadic_template(Mus&... mus) EXCLUSIVE_LOCKS_REQUIRED(mus...) {}
+
+template int elr_variadic_template<Mutex, Mutex>(Mutex&, Mutex&);
+// FIXME: warn on template instantiation.
+template int elr_variadic_template<Mutex, UnlockableMu>(Mutex&, UnlockableMu&);
+
+#endif
+
 
 
 
@@ -1225,6 +1350,24 @@ int slr_function_bad_3() 
SHARED_LOCKS_REQUIRED(muDoublePointer); // \
 int slr_function_bad_4() SHARED_LOCKS_REQUIRED(umu); // \
   // expected-warning {{'shared_locks_required' attribute requires arguments 
whose type is annotated with 'capability' attribute}}
 
+template<typename Mu>
+int slr_template(Mu& mu) SHARED_LOCKS_REQUIRED(mu) {}
+
+template int slr_template<Mutex>(Mutex&);
+// FIXME: warn on template instantiation.
+template int slr_template<UnlockableMu>(UnlockableMu&);
+
+#if __cplusplus >= 201103
+
+template<typename... Mus>
+int slr_variadic_template(Mus&... mus) SHARED_LOCKS_REQUIRED(mus...) {}
+
+template int slr_variadic_template<Mutex, Mutex>(Mutex&, Mutex&);
+// FIXME: warn on template instantiation.
+template int slr_variadic_template<Mutex, UnlockableMu>(Mutex&, UnlockableMu&);
+
+#endif
+
 
 //-----------------------------------------//
 //  Regression tests for unusual cases.
@@ -1582,7 +1725,7 @@ class Foo {
 }  // end namespace FunctionAttributesInsideClass_ICE_Test
 
 
-#ifdef CPP11
+#if __cplusplus >= 201103
 namespace CRASH_POST_R301735 {
   class SomeClass {
    public:
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp 
b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 00df99d04d873..b7f7f8f0b2fe2 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -1329,28 +1329,26 @@ namespace {
 
     void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
       OS << "tempInst" << getUpperName() << ", "
-         << "A->" << getLowerName() << "_size()";
+         << "numTempInst" << getUpperName();
     }
 
     void writeTemplateInstantiation(raw_ostream &OS) const override {
-      OS << "      auto *tempInst" << getUpperName()
-         << " = new (C, 16) " << getType()
-         << "[A->" << getLowerName() << "_size()];\n";
+      OS << "      size_t numTempInst" << getUpperName() << ";\n";
+      OS << "      " << getType() << "*tempInst" << getUpperName() << ";\n";
       OS << "      {\n";
       OS << "        EnterExpressionEvaluationContext "
          << "Unevaluated(S, 
Sema::ExpressionEvaluationContext::Unevaluated);\n";
-      OS << "        " << getType() << " *TI = tempInst" << getUpperName()
-         << ";\n";
-      OS << "        " << getType() << " *I = A->" << getLowerName()
-         << "_begin();\n";
-      OS << "        " << getType() << " *E = A->" << getLowerName()
-         << "_end();\n";
-      OS << "        for (; I != E; ++I, ++TI) {\n";
-      OS << "          ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n";
-      OS << "          if (Result.isInvalid())\n";
-      OS << "            return nullptr;\n";
-      OS << "          *TI = Result.get();\n";
-      OS << "        }\n";
+      OS << "        ArrayRef<" << getType() << "> ArgsToInstantiate(A->"
+         << getLowerName() << "_begin(), A->" << getLowerName() << 
"_end());\n";
+      OS << "        SmallVector<" << getType() << ", 4> InstArgs;\n";
+      OS << "        if (S.SubstExprs(ArgsToInstantiate, /*IsCall=*/false, "
+            "TemplateArgs, InstArgs))\n";
+      OS << "          return nullptr;\n";
+      OS << "        numTempInst" << getUpperName() << " = InstArgs.size();\n";
+      OS << "        tempInst" << getUpperName() << " = new (C, 16) "
+         << getType() << "[numTempInst" << getUpperName() << "];\n";
+      OS << "        std::copy(InstArgs.begin(), InstArgs.end(), tempInst"
+         << getUpperName() << ");\n";
       OS << "      }\n";
     }
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/137477
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to