]> granicus.if.org Git - clang/commitdiff
Thread safety analysis: split warnings into two groups: attribute warnings
authorDeLesley Hutchins <delesley@google.com>
Thu, 19 Apr 2012 16:10:44 +0000 (16:10 +0000)
committerDeLesley Hutchins <delesley@google.com>
Thu, 19 Apr 2012 16:10:44 +0000 (16:10 +0000)
which are checked in the parser, and analysis warnings that require the
full analysis.  This allows attribute syntax to be checked independently
of the full thread safety analysis.  Also introduces a new warning for the
case where a string is used as a lock expression; this allows the analysis
to gracefully handle expressions that would otherwise cause a parse error.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155129 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclAttr.cpp
test/SemaCXX/warn-thread-safety-parsing.cpp

index c83985345bce6623a3b3eb1f8a056843dbdac094..3f6c5c0c0d29bfcd598a0924829579c386dd22ad 100644 (file)
@@ -354,7 +354,10 @@ def Most : DiagGroup<"most", [
  ]>;
 
 // Thread Safety warnings 
-def ThreadSafety : DiagGroup<"thread-safety">;
+def ThreadSafetyAttributes : DiagGroup<"thread-safety-attributes">;
+def ThreadSafetyAnalysis : DiagGroup<"thread-safety-analysis">;
+def ThreadSafety : DiagGroup<"thread-safety", 
+                             [ThreadSafetyAttributes, ThreadSafetyAnalysis]>;
 
 // Note that putting warnings in -Wall will not disable them by default. If a
 // warning should be active _only_ when -Wall is passed in, mark it as
index d9727746284dcd2de47cb3b9e3229d9fc02492f0..986479921d4b6f59b454361baa26388bb596cd43 100644 (file)
@@ -1656,72 +1656,79 @@ def warn_availability_version_ordering : Warning<
   "attribute ignored">;
   
 // Thread Safety Attributes
-// Errors when parsing the attributes
+def warn_thread_attribute_ignored : Warning<
+  "ignoring %0 attribute because its argument is invalid">,
+  InGroup<ThreadSafetyAttributes>, DefaultIgnore;
+def warn_thread_attribute_argument_not_lockable : Warning<
+  "%0 attribute requires arguments whose type is annotated "
+  "with 'lockable' attribute; type here is '%1'">,
+  InGroup<ThreadSafetyAttributes>, DefaultIgnore;
+def warn_thread_attribute_argument_not_class : Warning<
+  "%0 attribute requires arguments that are class type or point to"
+  " class type; type here is '%1'">,
+  InGroup<ThreadSafetyAttributes>, DefaultIgnore;  
+def warn_thread_attribute_decl_not_lockable : Warning<
+  "%0 attribute can only be applied in a context annotated "
+  "with 'lockable' attribute">,
+  InGroup<ThreadSafetyAttributes>, DefaultIgnore;
+def warn_thread_attribute_decl_not_pointer : Warning<
+  "'%0' only applies to pointer types; type here is %1">,
+  InGroup<ThreadSafetyAttributes>, DefaultIgnore;
 def err_attribute_argument_out_of_range : Error<
   "%0 attribute parameter %1 is out of bounds: "
   "%plural{0:no parameters to index into|"
   "1:can only be 1, since there is one parameter|"
   ":must be between 1 and %2}2">;
-def warn_attribute_argument_not_lockable : Warning<
-  "%0 attribute requires arguments whose type is annotated "
-  "with 'lockable' attribute; type here is '%1'">,
-  InGroup<ThreadSafety>, DefaultIgnore;
-def warn_attribute_decl_not_lockable : Warning<
-  "%0 attribute can only be applied in a context annotated "
-  "with 'lockable' attribute">,
-  InGroup<ThreadSafety>, DefaultIgnore;
-def warn_attribute_argument_not_class : Warning<
-  "%0 attribute requires arguments that are class type or point to"
-  " class type; type here is '%1'">,
-  InGroup<ThreadSafety>, DefaultIgnore;   
+
+// Thread Safety Analysis   
 def warn_unlock_but_no_lock : Warning<
   "unlocking '%0' that was not locked">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_double_lock : Warning<
   "locking '%0' that is already locked">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_no_unlock : Warning<
   "mutex '%0' is still locked at the end of function">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 // FIXME: improve the error message about locks not in scope
 def warn_lock_some_predecessors : Warning<
   "mutex '%0' is not locked on every path through here">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_expecting_lock_held_on_loop : Warning<
   "expecting mutex '%0' to be locked at start of each loop">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def note_locked_here : Note<"mutex acquired here">;
 def warn_lock_exclusive_and_shared : Warning<
   "mutex '%0' is locked exclusively and shared in the same scope">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def note_lock_exclusive_and_shared : Note<
   "the other lock of mutex '%0' is here">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_variable_requires_lock : Warning<
   "%select{reading|writing}2 variable '%0' requires locking "
   "%select{'%1'|'%1' exclusively}2">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_var_deref_requires_lock : Warning<
   "%select{reading|writing}2 the value pointed to by '%0' requires locking "
   "%select{'%1'|'%1' exclusively}2">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_variable_requires_any_lock : Warning<
   "%select{reading|writing}1 variable '%0' requires locking "
   "%select{any mutex|any mutex exclusively}1">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_var_deref_requires_any_lock : Warning<
   "%select{reading|writing}1 the value pointed to by '%0' requires locking "
   "%select{any mutex|any mutex exclusively}1">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_fun_requires_lock : Warning<
   "calling function '%0' requires %select{shared|exclusive}2 lock on '%1'">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_fun_excludes_mutex : Warning<
   "cannot call function '%0' while mutex '%1' is locked">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 def warn_cannot_resolve_lock : Warning<
   "cannot resolve lock expression">,
-  InGroup<ThreadSafety>, DefaultIgnore;
+  InGroup<ThreadSafetyAnalysis>, DefaultIgnore;
 
 
 def warn_impcast_vector_scalar : Warning<
index 5c6ddd2cb97dbc8e5150576b785c9179d2f92e74..3770b3c37301f56f5a3a82742175757a20db5f58 100644 (file)
@@ -243,12 +243,13 @@ static bool isIntOrBool(Expr *Exp) {
 /// Note that this function may produce an error message.
 /// \return true if the Decl is a pointer type; false otherwise
 ///
-static bool checkIsPointer(Sema &S, const Decl *D, const AttributeList &Attr) {
+static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
+                                       const AttributeList &Attr) {
   if (const ValueDecl *vd = dyn_cast<ValueDecl>(D)) {
     QualType QT = vd->getType();
     if (QT->isAnyPointerType())
       return true;
-    S.Diag(Attr.getLoc(), diag::warn_pointer_attribute_wrong_type)
+    S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer)
       << Attr.getName()->getName() << QT;
   } else {
     S.Diag(Attr.getLoc(), diag::err_attribute_can_be_applied_only_to_value_decl)
@@ -271,14 +272,14 @@ static const RecordType *getRecordType(QualType QT) {
 }
 
 /// \brief Thread Safety Analysis: Checks that the passed in RecordType
-/// resolves to a lockable object. May flag an error.
+/// resolves to a lockable object.
 static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
                                    QualType Ty) {
   const RecordType *RT = getRecordType(Ty);
                                    
   // Warn if could not get record type for this argument.
   if (!RT) {
-    S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_class)
+    S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_class)
       << Attr.getName() << Ty.getAsString();
     return;
   }
@@ -287,18 +288,18 @@ static void checkForLockableRecord(Sema &S, Decl *D, const AttributeList &Attr,
     return;
   // Warn if the type is not lockable.
   if (!RT->getDecl()->getAttr<LockableAttr>()) {
-    S.Diag(Attr.getLoc(), diag::warn_attribute_argument_not_lockable)
+    S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
       << Attr.getName() << Ty.getAsString();
     return;
   }
 }
 
 /// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
-/// from Sidx, resolve to a lockable object. May flag an error.
+/// from Sidx, resolve to a lockable object.
 /// \param Sidx The attribute argument index to start checking with.
 /// \param ParamIdxOk Whether an argument can be indexing into a function
 /// parameter list.
-static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
+static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
                                          const AttributeList &Attr,
                                          SmallVectorImpl<Expr*> &Args,
                                          int Sidx = 0,
@@ -307,11 +308,19 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
     Expr *ArgExp = Attr.getArg(Idx);
 
     if (ArgExp->isTypeDependent()) {
-      // FIXME -- need to processs this again on template instantiation
+      // FIXME -- need to check this again on template instantiation
       Args.push_back(ArgExp);
       continue;
     }
 
+    if (isa<StringLiteral>(ArgExp)) {
+      // We allow constant strings to be used as a placeholder for expressions
+      // that are not valid C++ syntax, but warn that they are ignored.
+      S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) <<
+        Attr.getName();
+      continue;
+    }
+
     QualType ArgTy = ArgExp->getType();
 
     // First see if we can just cast to record type, or point to record type.
@@ -329,7 +338,7 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
         if(!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) {
           S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range)
             << Attr.getName() << Idx + 1 << NumParams;
-          return false;
+          continue;
         }
         ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType();
       }
@@ -339,7 +348,6 @@ static bool checkAttrArgsAreLockableObjs(Sema &S, Decl *D,
 
     Args.push_back(ArgExp);
   }
-  return true;
 }
 
 //===----------------------------------------------------------------------===//
@@ -364,7 +372,7 @@ static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr,
     return;
   }
 
-  if (pointer && !checkIsPointer(S, D, Attr))
+  if (pointer && !threadSafetyCheckIsPointer(S, D, Attr))
     return;
 
   if (pointer)
@@ -380,8 +388,6 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
   if (!checkAttributeNumArgs(S, Attr, 1))
     return;
 
-  Expr *Arg = Attr.getArg(0);
-
   // 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)
@@ -389,12 +395,16 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
     return;
   }
 
-  if (pointer && !checkIsPointer(S, D, Attr))
+  if (pointer && !threadSafetyCheckIsPointer(S, D, Attr))
     return;
 
-  if (!Arg->isTypeDependent()) {
-    checkForLockableRecord(S, D, Attr, Arg->getType());
-  }
+  SmallVector<Expr*, 1> Args;
+  // check that all arguments are lockable objects
+  checkAttrArgsAreLockableObjs(S, D, Attr, Args);
+  unsigned Size = Args.size();
+  if (Size != 1)
+    return;
+  Expr *Arg = Args[0];
 
   if (pointer)
     D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getRange(),
@@ -442,7 +452,7 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
 }
 
 static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
-                                     const AttributeList &Attr) {
+                                      const AttributeList &Attr) {
   assert(!Attr.isInvalid());
 
   if (!checkAttributeNumArgs(S, Attr, 0))
@@ -473,25 +483,24 @@ static void handleAcquireOrderAttr(Sema &S, Decl *D, const AttributeList &Attr,
     return;
   }
 
-  // Check that this attribute only applies to lockable types
+  // Check that this attribute only applies to lockable types.
   QualType QT = VD->getType();
   if (!QT->isDependentType()) {
     const RecordType *RT = getRecordType(QT);
     if (!RT || !RT->getDecl()->getAttr<LockableAttr>()) {
-      S.Diag(Attr.getLoc(), diag::warn_attribute_decl_not_lockable)
+      S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable)
               << Attr.getName();
       return;
     }
   }
 
   SmallVector<Expr*, 1> Args;
-  // check that all arguments are lockable objects
-  if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
-    return;
-
+  // Check that all arguments are lockable objects.
+  checkAttrArgsAreLockableObjs(S, D, Attr, Args);
   unsigned Size = Args.size();
-  assert(Size == Attr.getNumArgs());
-  Expr **StartArg = Size == 0 ? 0 : &Args[0];
+  if (Size == 0)
+    return;
+  Expr **StartArg = &Args[0];
 
   if (before)
     D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context,
@@ -516,11 +525,8 @@ static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
 
   // check that all arguments are lockable objects
   SmallVector<Expr*, 1> Args;
-  if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true))
-    return;
-
+  checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
   unsigned Size = Args.size();
-  assert(Size == Attr.getNumArgs());
   Expr **StartArg = Size == 0 ? 0 : &Args[0];
 
   if (exclusive)
@@ -540,7 +546,6 @@ static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
   if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
     return;
 
-
   if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
@@ -555,9 +560,7 @@ static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
 
   SmallVector<Expr*, 2> Args;
   // check that all arguments are lockable objects
-  if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1))
-    return;
-
+  checkAttrArgsAreLockableObjs(S, D, Attr, Args, 1);
   unsigned Size = Args.size();
   Expr **StartArg = Size == 0 ? 0 : &Args[0];
 
@@ -588,12 +591,11 @@ static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr,
 
   // check that all arguments are lockable objects
   SmallVector<Expr*, 1> Args;
-  if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
-    return;
-
+  checkAttrArgsAreLockableObjs(S, D, Attr, Args);
   unsigned Size = Args.size();
-  assert(Size == Attr.getNumArgs());
-  Expr **StartArg = Size == 0 ? 0 : &Args[0];
+  if (Size == 0)
+    return;
+  Expr **StartArg = &Args[0];
 
   if (exclusive)
     D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(),
@@ -619,11 +621,8 @@ static void handleUnlockFunAttr(Sema &S, Decl *D,
 
   // check that all arguments are lockable objects
   SmallVector<Expr*, 1> Args;
-  if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true))
-    return;
-
+  checkAttrArgsAreLockableObjs(S, D, Attr, Args, 0, /*ParamIdxOk=*/true);
   unsigned Size = Args.size();
-  assert(Size == Attr.getNumArgs());
   Expr **StartArg = Size == 0 ? 0 : &Args[0];
 
   D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getRange(), S.Context,
@@ -668,12 +667,11 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
 
   // check that all arguments are lockable objects
   SmallVector<Expr*, 1> Args;
-  if (!checkAttrArgsAreLockableObjs(S, D, Attr, Args))
-    return;
-
+  checkAttrArgsAreLockableObjs(S, D, Attr, Args);
   unsigned Size = Args.size();
-  assert(Size == Attr.getNumArgs());
-  Expr **StartArg = Size == 0 ? 0 : &Args[0];
+  if (Size == 0)
+    return;
+  Expr **StartArg = &Args[0];
 
   D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getRange(), S.Context,
                                                  StartArg, Size));
index c2fa1d77a01a41f32279fdf3e561d91ae6f0d53a..a9e58dd87289193bf3ce9a515100f9034ccf6445 100644 (file)
@@ -343,7 +343,7 @@ int gb_var_arg_8 __attribute__((guarded_by(muPointer)));
 int gb_var_arg_bad_1 __attribute__((guarded_by(1))); // \
   // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'int'}}
 int gb_var_arg_bad_2 __attribute__((guarded_by("mu"))); // \
-  // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'const char [3]'}}
+  // expected-warning {{ignoring 'guarded_by' attribute because its argument is invalid}}
 int gb_var_arg_bad_3 __attribute__((guarded_by(muDoublePointer))); // \
   // expected-warning {{'guarded_by' attribute requires arguments that are class type or point to class type; type here is 'class Mu **'}}
 int gb_var_arg_bad_4 __attribute__((guarded_by(umu))); // \
@@ -414,7 +414,7 @@ int * pgb_var_arg_8 __attribute__((pt_guarded_by(muPointer)));
 int * pgb_var_arg_bad_1 __attribute__((pt_guarded_by(1))); // \
   // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
 int * pgb_var_arg_bad_2 __attribute__((pt_guarded_by("mu"))); // \
-  // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'pt_guarded_by' attribute because its argument is invalid}}
 int * pgb_var_arg_bad_3 __attribute__((pt_guarded_by(muDoublePointer))); // \
   // expected-warning {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
 int * pgb_var_arg_bad_4 __attribute__((pt_guarded_by(umu))); // \
@@ -475,7 +475,7 @@ Mu aa_var_arg_8 __attribute__((acquired_after(muPointer)));
 Mu aa_var_arg_bad_1 __attribute__((acquired_after(1))); // \
   // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}}
 Mu aa_var_arg_bad_2 __attribute__((acquired_after("mu"))); // \
-  // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'acquired_after' attribute because its argument is invalid}}
 Mu aa_var_arg_bad_3 __attribute__((acquired_after(muDoublePointer))); // \
   // expected-warning {{'acquired_after' attribute requires arguments that are class type or point to class type}}
 Mu aa_var_arg_bad_4 __attribute__((acquired_after(umu))); // \
@@ -538,7 +538,7 @@ Mu ab_var_arg_8 __attribute__((acquired_before(muPointer)));
 Mu ab_var_arg_bad_1 __attribute__((acquired_before(1))); // \
   // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}}
 Mu ab_var_arg_bad_2 __attribute__((acquired_before("mu"))); // \
-  // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'acquired_before' attribute because its argument is invalid}}
 Mu ab_var_arg_bad_3 __attribute__((acquired_before(muDoublePointer))); // \
   // expected-warning {{'acquired_before' attribute requires arguments that are class type or point to class type}}
 Mu ab_var_arg_bad_4 __attribute__((acquired_before(umu))); // \
@@ -603,7 +603,7 @@ int elf_function_9(Mu x, Mu y) __attribute__((exclusive_lock_function(1,2)));
 
 // illegal attribute arguments
 int elf_function_bad_2() __attribute__((exclusive_lock_function("mu"))); // \
-  // expected-warning {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'exclusive_lock_function' attribute because its argument is invalid}}
 int elf_function_bad_3() __attribute__((exclusive_lock_function(muDoublePointer))); // \
   // expected-warning {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
 int elf_function_bad_4() __attribute__((exclusive_lock_function(umu))); // \
@@ -675,7 +675,7 @@ int slf_function_9(Mu x, Mu y) __attribute__((shared_lock_function(1,2)));
 
 // illegal attribute arguments
 int slf_function_bad_2() __attribute__((shared_lock_function("mu"))); // \
-  // expected-warning {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'shared_lock_function' attribute because its argument is invalid}}
 int slf_function_bad_3() __attribute__((shared_lock_function(muDoublePointer))); // \
   // expected-warning {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
 int slf_function_bad_4() __attribute__((shared_lock_function(umu))); // \
@@ -757,7 +757,7 @@ int etf_function_bad_3() __attribute__((exclusive_trylock_function(muDoublePoint
   // expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
 
 int etf_function_bad_4() __attribute__((exclusive_trylock_function(1, "mu"))); // \
-  // expected-warning {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'exclusive_trylock_function' attribute because its argument is invalid}}
 int etf_function_bad_5() __attribute__((exclusive_trylock_function(1, muDoublePointer))); // \
   // expected-warning {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
 int etf_function_bad_6() __attribute__((exclusive_trylock_function(1, umu))); // \
@@ -831,7 +831,7 @@ int stf_function_bad_3() __attribute__((shared_trylock_function(muDoublePointer)
   // expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
 
 int stf_function_bad_4() __attribute__((shared_trylock_function(1, "mu"))); // \
-  // expected-warning {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'shared_trylock_function' attribute because its argument is invalid}}
 int stf_function_bad_5() __attribute__((shared_trylock_function(1, muDoublePointer))); // \
   // expected-warning {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
 int stf_function_bad_6() __attribute__((shared_trylock_function(1, umu))); // \
@@ -894,7 +894,7 @@ int uf_function_9(Mu x, Mu y) __attribute__((unlock_function(1,2)));
 
 // illegal attribute arguments
 int uf_function_bad_2() __attribute__((unlock_function("mu"))); // \
-  // expected-warning {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'unlock_function' attribute because its argument is invalid}}
 int uf_function_bad_3() __attribute__((unlock_function(muDoublePointer))); // \
   // expected-warning {{'unlock_function' attribute requires arguments that are class type or point to class type}}
 int uf_function_bad_4() __attribute__((unlock_function(umu))); // \
@@ -1037,7 +1037,7 @@ int le_function_8() __attribute__((locks_excluded(muPointer)));
 int le_function_bad_1() __attribute__((locks_excluded(1))); // \
   // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
 int le_function_bad_2() __attribute__((locks_excluded("mu"))); // \
-  // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'locks_excluded' attribute because its argument is invalid}}
 int le_function_bad_3() __attribute__((locks_excluded(muDoublePointer))); // \
   // expected-warning {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
 int le_function_bad_4() __attribute__((locks_excluded(umu))); // \
@@ -1104,7 +1104,7 @@ int elr_function_8() __attribute__((exclusive_locks_required(muPointer)));
 int elr_function_bad_1() __attribute__((exclusive_locks_required(1))); // \
   // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
 int elr_function_bad_2() __attribute__((exclusive_locks_required("mu"))); // \
-  // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'exclusive_locks_required' attribute because its argument is invalid}}
 int elr_function_bad_3() __attribute__((exclusive_locks_required(muDoublePointer))); // \
   // expected-warning {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
 int elr_function_bad_4() __attribute__((exclusive_locks_required(umu))); // \
@@ -1172,7 +1172,7 @@ int slr_function_8() __attribute__((shared_locks_required(muPointer)));
 int slr_function_bad_1() __attribute__((shared_locks_required(1))); // \
   // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
 int slr_function_bad_2() __attribute__((shared_locks_required("mu"))); // \
-  // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+  // expected-warning {{ignoring 'shared_locks_required' attribute because its argument is invalid}}
 int slr_function_bad_3() __attribute__((shared_locks_required(muDoublePointer))); // \
   // expected-warning {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
 int slr_function_bad_4() __attribute__((shared_locks_required(umu))); // \