[cfe-commits] r136383 - in /cfe/trunk: docs/LanguageExtensions.html include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/Sema/AttributeList.cpp lib/Sema/SemaDeclAttr.cpp test/SemaCXX/warn-thread-safety.cpp

Caitlin Sadowski supertri at google.com
Thu Jul 28 13:12:35 PDT 2011


Author: supertri
Date: Thu Jul 28 15:12:35 2011
New Revision: 136383

URL: http://llvm.org/viewvc/llvm-project?rev=136383&view=rev
Log:
Added basic parsing for all remaining attributes, thread safety
analysis. This includes checking that the attributes are applied in the
correct contexts and with the correct number of arguments.

Modified:
    cfe/trunk/docs/LanguageExtensions.html
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/lib/Sema/AttributeList.cpp
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp
    cfe/trunk/test/SemaCXX/warn-thread-safety.cpp

Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Thu Jul 28 15:12:35 2011
@@ -89,11 +89,24 @@
 <li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
 <li><a href="#threadsafety">Thread Safety Annotation Checking</a></li>
     <ul>
+    <li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>   
+    <li><a href="#ts_lockable"><tt>lockable</tt></a></li>  
+    <li><a href="#ts_scopedlockable"><tt>scoped_lockable</tt></a></li>  
     <li><a href="#ts_guardedvar"><tt>guarded_var</tt></a></li>
     <li><a href="#ts_ptguardedvar"><tt>pt_guarded_var</tt></a></li>
-    <li><a href="#ts_lockable"><tt>lockable</tt></a></li>  
-    <li><a href="#ts_scopedlockable"><tt>scoped_lockable</tt></a></li>   
-    <li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>    
+    <li><a href="#ts_guardedby"><tt>guarded_by(l)</tt></a></li>
+    <li><a href="#ts_ptguardedby"><tt>pt_guarded_by(l)</tt></a></li>  
+    <li><a href="#ts_acquiredbefore"><tt>acquired_before(...)</tt></a></li>  
+    <li><a href="#ts_acquiredafter"><tt>acquired_after(...)</tt></a></li>    
+    <li><a href="#ts_elf"><tt>exclusive_lock_function(...)</tt></a></li>   
+    <li><a href="#ts_slf"><tt>shared_lock_function(...)</tt></a></li>   
+    <li><a href="#ts_etf"><tt>exclusive_trylock_function(...)</tt></a></li>   
+    <li><a href="#ts_stf"><tt>shared_trylock_function(...)</tt></a></li>   
+    <li><a href="#ts_uf"><tt>unlock_function(...)</tt></a></li>   
+    <li><a href="#ts_lr"><tt>lock_returned(l)</tt></a></li>   
+    <li><a href="#ts_le"><tt>locks_excluded(...)</tt></a></li>   
+    <li><a href="#ts_elr"><tt>exclusive_locks_required(...)</tt></a></li>   
+    <li><a href="#ts_slr"><tt>shared_locks_required(...)</tt></a></li>   
     </ul>
 </ul>
 
@@ -1109,15 +1122,12 @@
 <a href="http://gcc.gnu.org/wiki/ThreadSafetyAnnotation">GCC implementation</a>.
 </p>
 
-<h4 id="ts_guardedvar">guarded_var</h4>
-
-<p>Use <tt>__attribute__((guarded_var))</tt> on a variable declaration to 
-specify that the variable must be accessed while holding some lock.</p>
-
-<h4 id="ts_ptguardedvar">pt_guarded_var</h4>
+<h4 id="ts_noanal">no_thread_safety_analysis</h4>
 
-<p>Use <tt>__attribute__((pt_guarded_var))</tt> on a pointer declaration to 
-specify that the pointer must be dereferenced while holding some lock.</p>
+<p>Use <tt>__attribute__((no_thread_safety_analysis))</tt> on a function 
+declaration to specify that the thread safety analysis should not be run on that 
+function. This attribute provides an escape hatch (e.g. for situations when it
+is difficult to annotate the locking policy). </p> 
 
 <h4 id="ts_lockable">lockable</h4>
 
@@ -1133,12 +1143,119 @@
  This annotation is primarily used to check 
 consistency.</p> 
 
-<h4 id="ts_noanal">no_thread_safety_analysis</h4>
+<h4 id="ts_guardedvar">guarded_var</h4>
 
-<p>Use <tt>__attribute__((no_thread_safety_analysis))</tt> on a function 
-declaration to specify that the thread safety analysis should not be run on that 
-function. This attribute provides an escape hatch (e.g. for situations when it
-is difficult to annotate the locking policy). </p> 
+<p>Use <tt>__attribute__((guarded_var))</tt> on a variable declaration to 
+specify that the variable must be accessed while holding some lock.</p>
+
+<h4 id="ts_ptguardedvar">pt_guarded_var</h4>
+
+<p>Use <tt>__attribute__((pt_guarded_var))</tt> on a pointer declaration to 
+specify that the pointer must be dereferenced while holding some lock.</p>
+
+<h4 id="ts_guardedby">guarded_by(l)</h4>
+
+<p>Use <tt>__attribute__((guarded_by(l)))</tt> on a variable declaration to 
+specify that the variable must be accessed while holding lock l.</p>
+
+<h4 id="ts_ptguardedby">pt_guarded_by(l)</h4>
+
+<p>Use <tt>__attribute__((pt_guarded_by(l)))</tt> on a pointer declaration to 
+specify that the pointer must be dereferenced while holding lock l.</p>
+
+<h4 id="ts_acquiredbefore">acquired_before(...)</h4>
+
+<p>Use <tt>__attribute__((acquired_before(...)))</tt> on a declaration 
+of a lockable variable to specify that the lock must be acquired before all 
+attribute arguments. Arguments must be lockable type, and there must be at 
+least one argument.</p> 
+
+<h4 id="ts_acquiredafter">acquired_after(...)</h4>
+
+<p>Use <tt>__attribute__((acquired_after(...)))</tt> on a declaration 
+of a lockable variable to specify that the lock must be acquired after all 
+attribute arguments. Arguments must be lockable type, and there must be at 
+least one argument.</p> 
+
+<h4 id="ts_elf">exclusive_lock_function(...)</h4>
+
+<p>Use <tt>__attribute__((exclusive_lock_function(...)))</tt> on a function 
+declaration to specify that the function acquires all listed locks 
+exclusively. This attribute takes zero or more 
+arguments: either of lockable type or integers indexing into 
+function parameters of lockable type. If no arguments are given, the acquired 
+lock is implicitly <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_slf">shared_lock_function(...)</h4>
+
+<p>Use <tt>__attribute__((shared_lock_function(...)))</tt> on a function 
+declaration to specify that the function acquires all listed locks, although
+ the locks may be shared (e.g. read locks). 
+This attribute takes zero or more 
+arguments: either of lockable type or integers indexing into 
+function parameters of lockable type. If no arguments are given, the acquired 
+lock is implicitly <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_etf">exclusive_trylock_function(...)</h4>
+
+<p>Use <tt>__attribute__((exclusive_lock_function(...)))</tt> on a function 
+declaration to specify that the function will try (without blocking) to acquire
+all listed locks exclusively. This attribute takes one or more 
+arguments. The first argument is an integer or boolean value specifying the 
+return value of a successful lock acquisition. The remaining arugments are 
+either of lockable type or integers indexing into 
+function parameters of lockable type. If only one argument is given, the 
+acquired lock is implicitly <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_stf">shared_trylock_function(...)</h4>
+
+<p>Use <tt>__attribute__((shared_lock_function(...)))</tt> on a function 
+declaration to specify that the function will try (without blocking) to acquire
+all listed locks, although
+ the locks may be shared (e.g. read locks). 
+This attribute takes one or more 
+arguments. The first argument is an integer or boolean value specifying the 
+return value of a successful lock acquisition. The remaining arugments are 
+either of lockable type or integers indexing into 
+function parameters of lockable type. If only one argument is given, the 
+acquired lock is implicitly <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_uf">unlock_function(...)</h4>
+
+<p>Use <tt>__attribute__((unlock_function(...)))</tt> on a function 
+declaration to specify that the function release all listed locks.
+ This attribute takes zero or more 
+arguments: either of lockable type or integers indexing into 
+function parameters of lockable type. If no arguments are given, the acquired 
+lock is implicitly <tt>this</tt> of the enclosing object.</p>
+
+<h4 id="ts_lr">lock_returned(l)</h4>
+
+<p>Use <tt>__attribute__((lock_returned(l)))</tt> on a function 
+declaration to specify that the function returns lock l (l must be of lockable 
+type). This annotation is used
+to aid in resolving lock expressions.</p>
+
+<h4 id="ts_le">locks_excluded(...)</h4>
+
+<p>Use <tt>__attribute__((locks_excluded(...)))</tt> on a function declaration 
+to specify that the function must not be called with the listed locks. 
+Arguments must be lockable type, and there must be at 
+least one argument.</p>
+
+<h4 id="ts_elr">exclusive_locks_required(...)</h4>
+
+<p>Use <tt>__attribute__((exclusive_locks_required(...)))</tt> on a function 
+declaration to specify that the function must be called while holding the listed
+exclusive locks. Arguments must be lockable type, and there must be at 
+least one argument.</p> 
+
+<h4 id="ts_slr">shared_locks_required(...)</h4>
+
+<p>Use <tt>__attribute__((shared_locks_required(...)))</tt> on a function 
+declaration to specify that the function must be called while holding the listed 
+shared locks. Arguments must be lockable type, and there must be at 
+least one argument.</p> 
 
 </div>
 </body>

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Thu Jul 28 15:12:35 2011
@@ -561,3 +561,55 @@
 def NoThreadSafetyAnalysis : InheritableAttr {
   let Spellings = ["no_thread_safety_analysis"];
 }
+
+def GuardedBy : InheritableAttr {
+  let Spellings = ["guarded_by"];
+}
+
+def PtGuardedBy : InheritableAttr {
+  let Spellings = ["pt_guarded_by"];
+}
+
+def AcquiredAfter : InheritableAttr {
+  let Spellings = ["acquired_after"];
+}
+
+def AcquiredBefore : InheritableAttr {
+  let Spellings = ["acquired_before"];
+}
+
+def ExclusiveLockFunction : InheritableAttr {
+  let Spellings = ["exclusive_lock_function"];
+}
+
+def SharedLockFunction : InheritableAttr {
+  let Spellings = ["shared_lock_function"];
+}
+
+def ExclusiveTrylockFunction : InheritableAttr {
+  let Spellings = ["exclusive_trylock_function"];
+}
+
+def SharedTrylockFunction : InheritableAttr {
+  let Spellings = ["shared_trylock_function"];
+}
+
+def UnlockFunction : InheritableAttr {
+  let Spellings = ["unlock_function"];
+}
+
+def LockReturned : InheritableAttr {
+  let Spellings = ["lock_returned"];
+}
+
+def LocksExcluded : InheritableAttr {
+  let Spellings = ["locks_excluded"];
+}
+
+def ExclusiveLocksRequired : InheritableAttr {
+  let Spellings = ["exclusive_locks_required"];
+}
+
+def SharedLocksRequired : InheritableAttr {
+  let Spellings = ["shared_locks_required"];
+}

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 28 15:12:35 2011
@@ -1128,6 +1128,8 @@
   ":requires exactly %0 arguments}0">;
 def err_attribute_too_many_arguments : Error<
   "attribute takes no more than %0 argument%s0">;
+def err_attribute_too_few_arguments : Error<
+  "attribute takes at least %0 argument%s0">;
 def err_iboutletcollection_type : Error<
   "invalid type %0 as argument of iboutletcollection attribute">;
 def err_iboutletcollection_object_type : Error<

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Thu Jul 28 15:12:35 2011
@@ -152,6 +152,8 @@
 
 public:
   enum Kind {             // Please keep this list alphabetized.
+    AT_acquired_after,
+    AT_acquired_before,
     AT_address_space,
     AT_alias,
     AT_aligned,
@@ -178,12 +180,16 @@
     AT_device,
     AT_dllexport,
     AT_dllimport,
+    AT_exclusive_lock_function,
+    AT_exclusive_locks_required,
+    AT_exclusive_trylock_function,
     AT_ext_vector_type,
     AT_fastcall,
     AT_format,
     AT_format_arg,
     AT_global,
     AT_gnu_inline,
+    AT_guarded_by,
     AT_guarded_var,
     AT_host,
     AT_IBAction,          // Clang-specific.
@@ -191,7 +197,9 @@
     AT_IBOutletCollection, // Clang-specific.
     AT_init_priority,
     AT_launch_bounds,
+    AT_lock_returned,
     AT_lockable,
+    AT_locks_excluded,
     AT_malloc,
     AT_may_alias,
     AT_mode,
@@ -228,6 +236,7 @@
     AT_packed,
     AT_pascal,
     AT_pcs,  // ARM specific
+    AT_pt_guarded_by,
     AT_pt_guarded_var,
     AT_pure,
     AT_regparm,
@@ -236,10 +245,14 @@
     AT_section,
     AT_sentinel,
     AT_shared,
+    AT_shared_lock_function,
+    AT_shared_locks_required,
+    AT_shared_trylock_function,
     AT_stdcall,
     AT_thiscall,
     AT_transparent_union,
     AT_unavailable,
+    AT_unlock_function,
     AT_unused,
     AT_used,
     AT_uuid,

Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Thu Jul 28 15:12:35 2011
@@ -215,5 +215,18 @@
     .Case("scoped_lockable", AT_scoped_lockable)
     .Case("lockable", AT_lockable)
     .Case("no_thread_safety_analysis", AT_no_thread_safety_analysis)
+    .Case("guarded_by", AT_guarded_by)
+    .Case("pt_guarded_by", AT_pt_guarded_by)
+    .Case("acquired_after", AT_acquired_after)
+    .Case("acquired_before", AT_acquired_before)
+    .Case("exclusive_lock_function", AT_exclusive_lock_function)
+    .Case("exclusive_locks_required", AT_exclusive_locks_required)
+    .Case("exclusive_trylock_function", AT_exclusive_trylock_function)
+    .Case("lock_returned", AT_lock_returned)
+    .Case("locks_excluded", AT_locks_excluded)
+    .Case("shared_lock_function", AT_shared_lock_function)
+    .Case("shared_locks_required", AT_shared_locks_required)
+    .Case("shared_trylock_function", AT_shared_trylock_function)
+    .Case("unlock_function", AT_unlock_function)
     .Default(UnknownAttribute);
 }

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Thu Jul 28 15:12:35 2011
@@ -27,7 +27,7 @@
 
 /// These constants match the enumerated choices of
 /// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type.
-enum {
+enum AttributeDeclType {
   ExpectedFunction,
   ExpectedUnion,
   ExpectedVariableOrFunction,
@@ -42,7 +42,8 @@
   ExpectedClassMember,
   ExpectedVariable,
   ExpectedMethod,
-  ExpectedVariableFunctionOrLabel
+  ExpectedVariableFunctionOrLabel,
+  ExpectedFieldOrGlobalVar
 };
 
 //===----------------------------------------------------------------------===//
@@ -205,6 +206,34 @@
 }
 
 ///
+/// \brief Check the total number of argumenation, whether parsed by clang
+/// as arguments or parameters. Outputs a warning.
+/// \return false if the number of argumenation units does not match expectation
+///
+static bool checkAttributeNumArgsPlusParams(Sema &S, const AttributeList &Attr,
+                                             unsigned int Num,
+                                             bool moreok = false) {
+  unsigned int numArgsPlusParams = 0;
+
+  if (Attr.getParameterName())
+    numArgsPlusParams++;
+
+  numArgsPlusParams += Attr.getNumArgs();
+
+  if (moreok && numArgsPlusParams < Num) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_too_few_arguments) << Num;
+    return false;
+  }
+
+  if (!moreok && numArgsPlusParams != Num) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Num;
+    return false;
+  }
+
+  return true;
+}
+
+///
 /// \brief Check if passed in Decl is a field or potentially shared global var
 /// \return true if the Decl is a field or potentially shared global variable
 ///
@@ -225,7 +254,7 @@
 bool checkIsPointer(Sema & S, Decl * D, const AttributeList & Attr) {
   if(ValueDecl * vd = dyn_cast <ValueDecl>(D)) {
     QualType QT = vd->getType();
-    if(QT->isAnyPointerType()){
+    if(QT->isAnyPointerType()) {
       return true;
     }
     S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type)
@@ -268,6 +297,30 @@
     D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getLoc(), S.Context));
 }
 
+static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                 bool pointer = false) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1))
+    return;
+
+  // D must be either a member field or global (potentially shared) variable.
+  if (!mayBeSharedVariable(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << 15; /*fields and global vars*/;
+    return;
+  }
+
+  if (pointer && !checkIsPointer(S, D, Attr))
+    return;
+
+  if (pointer)
+    D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getLoc(), S.Context));
+  else
+    D->addAttr(::new (S.Context) GuardedByAttr(Attr.getLoc(), S.Context));
+}
+
+
 static void handleLockableAttr(Sema &S, Decl *D, const AttributeList &Attr,
                                bool scoped = false) {
   assert(!Attr.isInvalid());
@@ -304,6 +357,138 @@
                                                           S.Context));
 }
 
+static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                   bool before) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+    return;
+
+  // D must be either a member field or global (potentially shared) variable.
+  if (!mayBeSharedVariable(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << 15; /*fields and global vars*/;
+    return;
+  }
+
+  if (before)
+    D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getLoc(), S.Context));
+  else
+    D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                   bool exclusive = false) {
+  assert(!Attr.isInvalid());
+
+  // zero or more arguments ok
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  if (exclusive)
+    D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getLoc(),
+                                                           S.Context));
+  else
+    D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getLoc(),
+                                                        S.Context));
+}
+
+static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                      bool exclusive = false) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+    return;
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  if (exclusive)
+    D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getLoc(),
+                                                           S.Context));
+  else
+    D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getLoc(),
+                                                        S.Context));
+
+}
+
+static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr,
+                                   bool exclusive = false) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+    return;
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  if (exclusive)
+    D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getLoc(),
+                                                           S.Context));
+  else
+    D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getLoc(),
+                                                        S.Context));
+}
+
+
+static void handleUnlockFunAttr(Sema &S, Decl *D,
+                                     const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+
+  // zero or more arguments ok
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleLockReturnedAttr(Sema &S, Decl *D,
+                                     const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1))
+    return;
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getLoc(), S.Context));
+}
+
+static void handleLocksExcludedAttr(Sema &S, Decl *D,
+                                     const AttributeList &Attr) {
+  assert(!Attr.isInvalid());
+
+  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+    return;
+
+  if (!isFunction(D)) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << Attr.getName() << ExpectedFunctionOrMethod;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getLoc(), S.Context));
+}
+
+
 static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
                                     const AttributeList &Attr) {
   TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D);
@@ -3180,6 +3365,45 @@
   case AttributeList::AT_lockable:
     handleLockableAttr(S, D, Attr);
     break;
+  case AttributeList::AT_guarded_by:
+    handleGuardedByAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_pt_guarded_by:
+    handleGuardedByAttr(S, D, Attr, /*pointer = */true);
+    break;
+  case AttributeList::AT_exclusive_lock_function:
+    handleLockFunAttr(S, D, Attr, /*exclusive = */true);
+    break;
+  case AttributeList::AT_exclusive_locks_required:
+    handleLocksRequiredAttr(S, D, Attr, /*exclusive = */true);
+    break;
+  case AttributeList::AT_exclusive_trylock_function:
+    handleTrylockFunAttr(S, D, Attr, /*exclusive = */true);
+    break;
+  case AttributeList::AT_lock_returned:
+    handleLockReturnedAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_locks_excluded:
+    handleLocksExcludedAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_shared_lock_function:
+    handleLockFunAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_shared_locks_required:
+    handleLocksRequiredAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_shared_trylock_function:
+    handleTrylockFunAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_unlock_function:
+    handleUnlockFunAttr(S, D, Attr);
+    break;
+  case AttributeList::AT_acquired_before:
+    handleAcquireOrderAttr(S, D, Attr, /*before = */true);
+    break;
+  case AttributeList::AT_acquired_after:
+    handleAcquireOrderAttr(S, D, Attr, /*before = */false);
+    break;
 
   default:
     // Ask target about the attribute.

Modified: cfe/trunk/test/SemaCXX/warn-thread-safety.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety.cpp?rev=136383&r1=136382&r2=136383&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety.cpp Thu Jul 28 15:12:35 2011
@@ -1,5 +1,16 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
+
+/**
+ *  Helper fields
+ */
+
+class __attribute__((lockable)) Mu {
+};
+
+Mu mu1;
+Mu mu2;
+
 /***********************************
  *  No Thread Safety Analysis (noanal)
  ***********************************/
@@ -202,3 +213,567 @@
 
 void sl_function_params(int lvar __attribute__((scoped_lockable))); // \
   expected-warning {{'scoped_lockable' attribute only applies to classes}}
+
+
+/***********************************
+ *  Guarded By Attribute (gb)
+ ***********************************/
+
+// FIXME: Would we like this attribute to take more than 1 arg?
+
+#if !__has_attribute(guarded_by)
+#error "Should support guarded_by attribute"
+#endif
+
+//1. Check applied to the right types & argument number
+
+int gb_var_arg __attribute__((guarded_by(mu1)));
+
+int gb_var_args __attribute__((guarded_by(mu1, mu2))); // \
+  expected-error {{attribute takes one argument}}
+
+int gb_var_noargs __attribute__((guarded_by)); // \
+  expected-error {{attribute takes one argument}}
+
+class GBFoo {
+ private:
+  int gb_field_noargs __attribute__((guarded_by)); // \
+    expected-error {{attribute takes one argument}}
+  int gb_field_args __attribute__((guarded_by(mu1)));
+};
+
+class __attribute__((guarded_by(mu1))) GB { // \
+      expected-warning {{'guarded_by' attribute only applies to fields and global variables}}
+};
+
+void gb_function() __attribute__((guarded_by(mu1))); // \
+    expected-warning {{'guarded_by' attribute only applies to fields and global variables}}
+
+void gb_function_params(int gv_lvar __attribute__((guarded_by(mu1)))); // \
+    expected-warning {{'guarded_by' attribute only applies to fields and global variables}}
+
+int gb_testfn(int y){
+  int x __attribute__((guarded_by(mu1))) = y; // \
+      expected-warning {{'guarded_by' attribute only applies to fields and global variables}}
+  return x;
+}
+
+//2.Deal with argument parsing:
+// grab token stream parsing from C++0x branch
+// possibly create new, more permissive category for gcc attributes
+
+//foo
+//foo.bar
+//foo.bar->baz
+//foo.bar()->baz()->a
+//&foo
+//*foo
+
+//3.
+// Thread Safety analysis tests
+
+
+/***********************************
+ *  Pt Guarded By Attribute (pgb)
+ ***********************************/
+
+#if !__has_attribute(pt_guarded_by)
+#error "Should support pt_guarded_by attribute"
+#endif
+
+//1. Check applied to the right types & argument number
+
+int *pgb_var_noargs __attribute__((pt_guarded_by)); // \
+  expected-error {{attribute takes one argument}}
+
+int *pgb_ptr_var_arg __attribute__((pt_guarded_by(mu1)));
+
+int *pgb_ptr_var_args __attribute__((guarded_by(mu1, mu2))); // \
+  expected-error {{attribute takes one argument}}
+
+int pgb_var_args __attribute__((pt_guarded_by(mu1))); // \
+    expected-warning {{'pt_guarded_by' only applies to pointer types; type here is 'int'}}
+
+class PGBFoo {
+ private:
+  int *pgb_field_noargs __attribute__((pt_guarded_by)); // \
+    expected-error {{attribute takes one argument}}
+  int *pgb_field_args __attribute__((pt_guarded_by(mu1)));
+};
+
+class __attribute__((pt_guarded_by(mu1))) PGB { // \
+      expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}}
+};
+
+void pgb_function() __attribute__((pt_guarded_by(mu1))); // \
+    expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}}
+
+void pgb_function_params(int gv_lvar __attribute__((pt_guarded_by(mu1)))); // \
+    expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}}
+
+void pgb_testfn(int y){
+  int *x __attribute__((pt_guarded_by(mu1))) = new int(0); // \
+      expected-warning {{'pt_guarded_by' attribute only applies to fields and global variables}}
+  delete x;
+}
+
+/***********************************
+ *  Acquired After (aa)
+ ***********************************/
+
+// FIXME: Would we like this attribute to take more than 1 arg?
+// FIXME: What about pointers to locks?
+
+#if !__has_attribute(acquired_after)
+#error "Should support acquired_after attribute"
+#endif
+
+Mu mu_aa __attribute__((acquired_after(mu1)));
+
+Mu aa_var_noargs __attribute__((acquired_after)); // \
+  expected-error {{attribute takes at least 1 argument}}
+
+class AAFoo {
+ private:
+  Mu aa_field_noargs __attribute__((acquired_after)); // \
+    expected-error {{attribute takes at least 1 argument}}
+  Mu aa_field_args __attribute__((acquired_after(mu1)));
+};
+
+class __attribute__((acquired_after(mu1))) AA { // \
+      expected-warning {{'acquired_after' attribute only applies to fields and global variables}}
+};
+
+void aa_function() __attribute__((acquired_after(mu1))); // \
+    expected-warning {{'acquired_after' attribute only applies to fields and global variables}}
+
+void aa_function_params(int gv_lvar __attribute__((acquired_after(mu1)))); // \
+    expected-warning {{'acquired_after' attribute only applies to fields and global variables}}
+
+void aa_testfn(int y){
+  Mu x __attribute__((acquired_after(mu1))) = Mu(); // \
+      expected-warning {{'acquired_after' attribute only applies to fields and global variables}}
+}
+
+// Note: illegal int aa_int __attribute__((acquired_after(mu1))) will
+// be taken care of by warnings that aa__int is not lockable.
+
+
+/***********************************
+ *  Acquired Before (ab)
+ ***********************************/
+
+#if !__has_attribute(acquired_before)
+#error "Should support acquired_before attribute"
+#endif
+
+Mu mu_ab __attribute__((acquired_before(mu1)));
+
+Mu ab_var_noargs __attribute__((acquired_before)); // \
+  expected-error {{attribute takes at least 1 argument}}
+
+class ABFoo {
+ private:
+  Mu ab_field_noargs __attribute__((acquired_before)); // \
+    expected-error {{attribute takes at least 1 argument}}
+  Mu ab_field_args __attribute__((acquired_before(mu1)));
+};
+
+class __attribute__((acquired_before(mu1))) AB { // \
+      expected-warning {{'acquired_before' attribute only applies to fields and global variables}}
+};
+
+void ab_function() __attribute__((acquired_before(mu1))); // \
+    expected-warning {{'acquired_before' attribute only applies to fields and global variables}}
+
+void ab_function_params(int gv_lvar __attribute__((acquired_before(mu1)))); // \
+    expected-warning {{'acquired_before' attribute only applies to fields and global variables}}
+
+void ab_testfn(int y){
+  Mu x __attribute__((acquired_before(mu1))) = Mu(); // \
+      expected-warning {{'acquired_before' attribute only applies to fields and global variables}}
+}
+
+// Note: illegal int ab_int __attribute__((acquired_before(mu1))) will
+// be taken care of by warnings that ab__int is not lockable.
+
+/***********************************
+ *  Exclusive Lock Function (elf)
+ ***********************************/
+
+#if !__has_attribute(exclusive_lock_function)
+#error "Should support exclusive_lock_function attribute"
+#endif
+
+// takes zero or more arguments, all locks (vars/fields)
+
+void elf_function() __attribute__((exclusive_lock_function));
+
+void elf_function_args() __attribute__((exclusive_lock_function(mu1, mu2)));
+
+int elf_testfn(int y) __attribute__((exclusive_lock_function));
+
+int elf_testfn(int y) {
+  int x __attribute__((exclusive_lock_function)) = y; // \
+    expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+  return x;
+};
+
+int elf_test_var __attribute__((exclusive_lock_function)); // \
+  expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+
+class ElfFoo {
+ private:
+  int test_field __attribute__((exclusive_lock_function)); // \
+    expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+  void test_method() __attribute__((exclusive_lock_function));
+};
+
+class __attribute__((exclusive_lock_function)) ElfTestClass { // \
+    expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+};
+
+void elf_fun_params(int lvar __attribute__((exclusive_lock_function))); // \
+  expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
+
+
+
+/***********************************
+ *  Shared Lock Function (slf)
+ ***********************************/
+
+#if !__has_attribute(shared_lock_function)
+#error "Should support shared_lock_function attribute"
+#endif
+
+// takes zero or more arguments, all locks (vars/fields)
+
+void slf_function() __attribute__((shared_lock_function));
+
+void slf_function_args() __attribute__((shared_lock_function(mu1, mu2)));
+
+int slf_testfn(int y) __attribute__((shared_lock_function));
+
+int slf_testfn(int y) {
+  int x __attribute__((shared_lock_function)) = y; // \
+    expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+  return x;
+};
+
+int slf_test_var __attribute__((shared_lock_function)); // \
+  expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+
+void slf_fun_params(int lvar __attribute__((shared_lock_function))); // \
+  expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+
+class SlfFoo {
+ private:
+  int test_field __attribute__((shared_lock_function)); // \
+    expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+  void test_method() __attribute__((shared_lock_function));
+};
+
+class __attribute__((shared_lock_function)) SlfTestClass { // \
+    expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
+};
+
+
+/***********************************
+ *  Exclusive TryLock Function (etf)
+ ***********************************/
+
+#if !__has_attribute(exclusive_trylock_function)
+#error "Should support exclusive_trylock_function attribute"
+#endif
+
+// takes a mandatory boolean or integer argument specifying the retval
+// plus an optional list of locks (vars/fields)
+
+void etf_function() __attribute__((exclusive_trylock_function));  // \
+  expected-error {{attribute takes attribute takes at least 1 argument arguments}}
+
+void etf_function_args() __attribute__((exclusive_trylock_function(1, mu2)));
+
+void etf_function_arg() __attribute__((exclusive_trylock_function(1)));
+
+int etf_testfn(int y) __attribute__((exclusive_trylock_function(1)));
+
+int etf_testfn(int y) {
+  int x __attribute__((exclusive_trylock_function(1))) = y; // \
+    expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+  return x;
+};
+
+int etf_test_var __attribute__((exclusive_trylock_function(1))); // \
+  expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+
+class EtfFoo {
+ private:
+  int test_field __attribute__((exclusive_trylock_function(1))); // \
+    expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+  void test_method() __attribute__((exclusive_trylock_function(1)));
+};
+
+class __attribute__((exclusive_trylock_function(1))) EtfTestClass { // \
+    expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+};
+
+void etf_fun_params(int lvar __attribute__((exclusive_trylock_function(1)))); // \
+  expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
+
+
+
+/***********************************
+ *  Shared TryLock Function (stf)
+ ***********************************/
+
+#if !__has_attribute(shared_trylock_function)
+#error "Should support shared_trylock_function attribute"
+#endif
+
+// takes a mandatory boolean or integer argument specifying the retval
+// plus an optional list of locks (vars/fields)
+
+void stf_function() __attribute__((shared_trylock_function));  // \
+  expected-error {{attribute takes at least 1 argument}}
+
+void stf_function_args() __attribute__((shared_trylock_function(1, mu2)));
+
+void stf_function_arg() __attribute__((shared_trylock_function(1)));
+
+int stf_testfn(int y) __attribute__((shared_trylock_function(1)));
+
+int stf_testfn(int y) {
+  int x __attribute__((shared_trylock_function(1))) = y; // \
+    expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+  return x;
+};
+
+int stf_test_var __attribute__((shared_trylock_function(1))); // \
+  expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+
+void stf_fun_params(int lvar __attribute__((shared_trylock_function(1)))); // \
+  expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+
+
+class StfFoo {
+ private:
+  int test_field __attribute__((shared_trylock_function(1))); // \
+    expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+  void test_method() __attribute__((shared_trylock_function(1)));
+};
+
+class __attribute__((shared_trylock_function(1))) StfTestClass { // \
+    expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
+};
+
+
+/***********************************
+ *  Unlock Function (uf)
+ ***********************************/
+
+#if !__has_attribute(unlock_function)
+#error "Should support unlock_function attribute"
+#endif
+
+// takes zero or more arguments, all locks (vars/fields)
+
+void uf_function() __attribute__((unlock_function));
+
+void uf_function_args() __attribute__((unlock_function(mu1, mu2)));
+
+int uf_testfn(int y) __attribute__((unlock_function));
+
+int uf_testfn(int y) {
+  int x __attribute__((unlock_function)) = y; // \
+    expected-warning {{'unlock_function' attribute only applies to functions and methods}}
+  return x;
+};
+
+int uf_test_var __attribute__((unlock_function)); // \
+  expected-warning {{'unlock_function' attribute only applies to functions and methods}}
+
+class UfFoo {
+ private:
+  int test_field __attribute__((unlock_function)); // \
+    expected-warning {{'unlock_function' attribute only applies to functions and methods}}
+  void test_method() __attribute__((unlock_function));
+};
+
+class __attribute__((no_thread_safety_analysis)) UfTestClass { // \
+    expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
+};
+
+void uf_fun_params(int lvar __attribute__((unlock_function))); // \
+  expected-warning {{'unlock_function' attribute only applies to functions and methods}}
+
+
+/***********************************
+ *  Lock Returned (lr)
+ ***********************************/
+
+#if !__has_attribute(lock_returned)
+#error "Should support lock_returned attribute"
+#endif
+
+// Takes exactly one argument, a var/field
+
+void lr_function() __attribute__((lock_returned)); // \
+  expected-error {{attribute takes one argument}}
+
+void lr_function_arg() __attribute__((lock_returned(mu1)));
+
+void lr_function_args() __attribute__((lock_returned(mu1, mu2))); // \
+  expected-error {{attribute takes one argument}}
+
+int lr_testfn(int y) __attribute__((lock_returned(mu1)));
+
+int lr_testfn(int y) {
+  int x __attribute__((lock_returned(mu1))) = y; // \
+    expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+  return x;
+};
+
+int lr_test_var __attribute__((lock_returned(mu1))); // \
+  expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+
+void lr_fun_params(int lvar __attribute__((lock_returned(mu1)))); // \
+  expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+
+class LrFoo {
+ private:
+  int test_field __attribute__((lock_returned(mu1))); // \
+    expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+  void test_method() __attribute__((lock_returned(mu1)));
+};
+
+class __attribute__((lock_returned(mu1))) LrTestClass { // \
+    expected-warning {{'lock_returned' attribute only applies to functions and methods}}
+};
+
+/***********************************
+ *  Locks Excluded (le)
+ ***********************************/
+
+#if !__has_attribute(locks_excluded)
+#error "Should support locks_excluded attribute"
+#endif
+
+// takes one or more arguments, all locks (vars/fields)
+
+void le_function() __attribute__((locks_excluded)); // \
+  expected-error {{attribute takes at least 1 argument}}
+
+void le_function_arg() __attribute__((locks_excluded(mu1)));
+
+void le_function_args() __attribute__((locks_excluded(mu1, mu2)));
+
+int le_testfn(int y) __attribute__((locks_excluded(mu1)));
+
+int le_testfn(int y) {
+  int x __attribute__((locks_excluded(mu1))) = y; // \
+    expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+  return x;
+};
+
+int le_test_var __attribute__((locks_excluded(mu1))); // \
+  expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+
+void le_fun_params(int lvar __attribute__((locks_excluded(mu1)))); // \
+  expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+
+class LeFoo {
+ private:
+  int test_field __attribute__((locks_excluded(mu1))); // \
+    expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+  void test_method() __attribute__((locks_excluded(mu1)));
+};
+
+class __attribute__((locks_excluded(mu1))) LeTestClass { // \
+    expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
+};
+
+
+/***********************************
+ *  Exclusive Locks Required (elr)
+ ***********************************/
+
+#if !__has_attribute(exclusive_locks_required)
+#error "Should support exclusive_locks_required attribute"
+#endif
+
+// takes one or more arguments, all locks (vars/fields)
+
+void elr_function() __attribute__((exclusive_locks_required)); // \
+  expected-error {{attribute takes at least 1 argument}}
+
+void elr_function_arg() __attribute__((exclusive_locks_required(mu1)));
+
+void elr_function_args() __attribute__((exclusive_locks_required(mu1, mu2)));
+
+int elr_testfn(int y) __attribute__((exclusive_locks_required(mu1)));
+
+int elr_testfn(int y) {
+  int x __attribute__((exclusive_locks_required(mu1))) = y; // \
+    expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+  return x;
+};
+
+int elr_test_var __attribute__((exclusive_locks_required(mu1))); // \
+  expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+
+void elr_fun_params(int lvar __attribute__((exclusive_locks_required(mu1)))); // \
+  expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+
+class ElrFoo {
+ private:
+  int test_field __attribute__((exclusive_locks_required(mu1))); // \
+    expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+  void test_method() __attribute__((exclusive_locks_required(mu1)));
+};
+
+class __attribute__((exclusive_locks_required(mu1))) ElrTestClass { // \
+    expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
+};
+
+/***********************************
+ *  Shared Locks Required (slr)
+ ***********************************/
+
+#if !__has_attribute(shared_locks_required)
+#error "Should support shared_locks_required attribute"
+#endif
+
+// takes one or more arguments, all locks (vars/fields)
+
+void slr_function() __attribute__((shared_locks_required)); // \
+  expected-error {{attribute takes at least 1 argument}}
+
+void slr_function_arg() __attribute__((shared_locks_required(mu1)));
+
+void slr_function_args() __attribute__((shared_locks_required(mu1, mu2)));
+
+int slr_testfn(int y) __attribute__((shared_locks_required(mu1)));
+
+int slr_testfn(int y) {
+  int x __attribute__((shared_locks_required(mu1))) = y; // \
+    expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+  return x;
+};
+
+int slr_test_var __attribute__((shared_locks_required(mu1))); // \
+  expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+
+void slr_fun_params(int lvar __attribute__((shared_locks_required(mu1)))); // \
+  expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+
+class SlrFoo {
+ private:
+  int test_field __attribute__((shared_locks_required(mu1))); // \
+    expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+  void test_method() __attribute__((shared_locks_required(mu1)));
+};
+
+class __attribute__((shared_locks_required(mu1))) SlrTestClass { // \
+    expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
+};





More information about the cfe-commits mailing list