[cfe-commits] r137130 - in /cfe/trunk: docs/LanguageExtensions.html include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Sema/SemaDeclAttr.cpp test/SemaCXX/warn-thread-safety.cpp

Caitlin Sadowski supertri at google.com
Tue Aug 9 10:59:31 PDT 2011


Author: supertri
Date: Tue Aug  9 12:59:31 2011
New Revision: 137130

URL: http://llvm.org/viewvc/llvm-project?rev=137130&view=rev
Log:
Thread Safety: Added basic argument parsing for all new attributes.

This patch special cases the parser for thread safety attributes so that all
attribute arguments are put in the argument list (instead of a special
parameter) since arguments may not otherwise resolve correctly without two-token
lookahead.

This patch also adds checks to make sure that attribute arguments are
lockable objects.

Modified:
    cfe/trunk/docs/LanguageExtensions.html
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseDecl.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=137130&r1=137129&r2=137130&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Tue Aug  9 12:59:31 2011
@@ -1164,12 +1164,12 @@
 <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>
+specify that the variable must be accessed while holding lock <tt>l</tt>.</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>
+specify that the pointer must be dereferenced while holding lock <tt>l</tt>.</p>
 
 <h4 id="ts_acquiredbefore">acquired_before(...)</h4>
 
@@ -1189,67 +1189,62 @@
 
 <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>
+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>
+ 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>
+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 
+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>
+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>
+declaration to specify that the function returns lock <tt>l</tt> (<tt>l</tt> 
+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>
+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>
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=137130&r1=137129&r2=137130&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Aug  9 12:59:31 2011
@@ -274,6 +274,9 @@
     OverloadedVirtual
  ]>;
 
+// Thread Safety warnings 
+def : DiagGroup<"thread-safety">;
+
 // -Wall is -Wmost -Wparentheses
 def : DiagGroup<"all", [Most, Parentheses]>;
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=137130&r1=137129&r2=137130&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Aug  9 12:59:31 2011
@@ -1142,6 +1142,10 @@
   "Neon vector size must be 64 or 128 bits">;
 def err_attribute_argument_not_int : Error<
   "'%0' attribute requires integer constant">;
+def err_attribute_argument_not_class : Error<
+  "%0 attribute requires arguments that are class type or point to class type">;
+def err_attribute_first_argument_not_int_or_bool : Error<
+  "%0 attribute first argument must be of int or bool type">;
 def err_attribute_argument_outof_range : Error<
   "init_priority attribute requires integer constant between "
   "101 and 65535 inclusive">;
@@ -1300,6 +1304,21 @@
   "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version "
   "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; "
   "attribute ignored">;
+  
+// Thread Safety Attributes
+// Errors when parsing the attributes
+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 err_attribute_argument_not_lockable : Error<
+  "%0 attribute requires arguments whose type is annotated "
+  "with 'lockable' attribute">;
+def err_attribute_decl_not_lockable : Error<
+  "%0 attribute can only be applied in a context annotated "
+  "with 'lockable' attribute">;
+
 
 def warn_impcast_vector_scalar : Warning<
   "implicit conversion turns vector to scalar: %0 to %1">,

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=137130&r1=137129&r2=137130&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Aug  9 12:59:31 2011
@@ -1691,6 +1691,13 @@
                                   ParsedAttributes &attrs,
                                   SourceLocation *endLoc);
 
+  bool IsThreadSafetyAttribute(llvm::StringRef AttrName);
+  void ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
+                                  SourceLocation AttrNameLoc,
+                                  ParsedAttributes &Attrs,
+                                  SourceLocation *EndLoc);
+
+
   void ParseTypeofSpecifier(DeclSpec &DS);
   void ParseDecltypeSpecifier(DeclSpec &DS);
   void ParseUnderlyingTypeSpecifier(DeclSpec &DS);

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=137130&r1=137129&r2=137130&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Aug  9 12:59:31 2011
@@ -19,6 +19,7 @@
 #include "clang/Sema/PrettyDeclStackTrace.h"
 #include "RAIIObjectsForParser.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringSwitch.h"
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
@@ -121,6 +122,10 @@
       // Availability attributes have their own grammar.
       if (AttrName->isStr("availability"))
         ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc);
+      // Thread safety attributes fit into the FIXME case above, so we
+      // just parse the arguments as a list of expressions
+      else if (IsThreadSafetyAttribute(AttrName->getName()))
+        ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, attrs, endLoc);
       // check if we have a "parameterized" attribute
       else if (Tok.is(tok::l_paren)) {
         ConsumeParen(); // ignore the left paren loc for now
@@ -650,6 +655,81 @@
                UnavailableLoc, false, false);
 }
 
+/// \brief Wrapper around a case statement checking if AttrName is
+/// one of the thread safety attributes
+bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){
+  return llvm::StringSwitch<bool>(AttrName)
+      .Case("guarded_by", true)
+      .Case("guarded_var", true)
+      .Case("pt_guarded_by", true)
+      .Case("pt_guarded_var", true)
+      .Case("lockable", true)
+      .Case("scoped_lockable", true)
+      .Case("no_thread_safety_analysis", true)
+      .Case("acquired_after", true)
+      .Case("acquired_before", true)
+      .Case("exclusive_lock_function", true)
+      .Case("shared_lock_function", true)
+      .Case("exclusive_trylock_function", true)
+      .Case("shared_trylock_function", true)
+      .Case("unlock_function", true)
+      .Case("lock_returned", true)
+      .Case("locks_excluded", true)
+      .Case("exclusive_locks_required", true)
+      .Case("shared_locks_required", true)
+      .Default(false);
+}
+
+/// \brief Parse the contents of thread safety attributes. These
+/// should always be parsed as an expression list.
+///
+/// We need to special case the parsing due to the fact that if the first token
+/// of the first argument is an identifier, the main parse loop will store
+/// that token as a "parameter" and the rest of
+/// the arguments will be added to a list of "arguments". However,
+/// subsequent tokens in the first argument are lost. We instead parse each
+/// argument as an expression and add all arguments to the list of "arguments".
+/// In future, we will take advantage of this special case to also
+/// deal with some argument scoping issues here (for example, referring to a
+/// function parameter in the attribute on that function).
+void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
+                                        SourceLocation AttrNameLoc,
+                                        ParsedAttributes &Attrs,
+                                        SourceLocation *EndLoc) {
+
+  if (Tok.is(tok::l_paren)) {
+    SourceLocation LeftParenLoc = Tok.getLocation();
+    ConsumeParen(); // ignore the left paren loc for now
+
+    ExprVector ArgExprs(Actions);
+    bool ArgExprsOk = true;
+
+    // now parse the list of expressions
+    while (1) {
+      ExprResult ArgExpr(ParseAssignmentExpression());
+      if (ArgExpr.isInvalid()) {
+        ArgExprsOk = false;
+        MatchRHSPunctuation(tok::r_paren, LeftParenLoc);
+        break;
+      } else {
+        ArgExprs.push_back(ArgExpr.release());
+      }
+      if (Tok.isNot(tok::comma))
+        break;
+      ConsumeToken(); // Eat the comma, move to the next argument
+    }
+    // Match the ')'.
+    if (ArgExprsOk && Tok.is(tok::r_paren)) {
+      ConsumeParen(); // ignore the right paren loc for now
+      Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
+                   ArgExprs.take(), ArgExprs.size());
+    }
+  } else {
+    Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc,
+                 0, SourceLocation(), 0, 0);
+  }
+}
+
 void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
   Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
     << attrs.Range;

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=137130&r1=137129&r2=137130&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Aug  9 12:59:31 2011
@@ -15,6 +15,7 @@
 #include "TargetAttributesSema.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/Basic/SourceManager.h"
@@ -27,7 +28,7 @@
 
 /// These constants match the enumerated choices of
 /// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type.
-enum AttributeDeclType {
+enum AttributeDeclKind {
   ExpectedFunction,
   ExpectedUnion,
   ExpectedVariableOrFunction,
@@ -195,6 +196,8 @@
   return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
 }
 
+/// \brief Check if the attribute has exactly as many args as Num. May
+/// output an error.
 static bool checkAttributeNumArgs(Sema &S, const AttributeList &Attr,
                                   unsigned int Num) {
   if (Attr.getNumArgs() != Num) {
@@ -205,31 +208,16 @@
   return true;
 }
 
-///
-/// \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) {
+/// \brief Check if the attribute has at least as many args as Num. May
+/// output an error.
+static bool checkAttributeAtLeastNumArgs(Sema &S, const AttributeList &Attr,
+                                  unsigned int Num) {
+  if (Attr.getNumArgs() < 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;
 }
 
@@ -246,6 +234,12 @@
   return false;
 }
 
+/// \brief Check if the passed-in expression is of type int or bool.
+static bool isIntOrBool(Expr *Exp) {
+  QualType QT = Exp->getType();
+  return QT->isBooleanType() || QT->isIntegerType();
+}
+
 ///
 /// \brief Check if passed in Decl is a pointer type.
 /// Note that this function may produce an error message.
@@ -265,6 +259,71 @@
   return false;
 }
 
+/// \brief Checks that the passed in QualType either is of RecordType or points
+/// to RecordType. Returns the relevant RecordType, null if it does not exit.
+const RecordType *getRecordType(QualType QT) {
+    const RecordType *RT = QT->getAs<RecordType>();
+    // now check if we point to record type
+    if(!RT && QT->isPointerType()){
+        QualType PT = QT->getAs<PointerType>()->getPointeeType();
+        RT = PT->getAs<RecordType>();
+    }
+    return RT;
+}
+
+/// \brief Thread Safety Analysis: Checks that all attribute arguments, starting
+/// from Sidx, resolve to a lockable object. May flag an error.
+static bool checkAttrArgsAreLockableObjs(Sema & S, Decl *D,
+                                         const AttributeList & Attr,
+                                         int Sidx = 0,
+                                         bool ParamIdxOk = false) {
+  for(unsigned int Idx = Sidx; Idx < Attr.getNumArgs(); ++Idx) {
+    Expr *ArgExp = Attr.getArg(Idx);
+    if (ArgExp->isTypeDependent())
+      continue;
+
+    QualType Arg_QT = ArgExp->getType();
+
+    // Get record type.
+    // first see if we can just cast to record type, or point to record type
+    const RecordType *RT = getRecordType(Arg_QT);
+
+    // now check if we idx into a record type function param
+    if (!RT && ParamIdxOk) {
+      FunctionDecl *FD = dyn_cast <FunctionDecl>(D);
+      IntegerLiteral *IL = dyn_cast<IntegerLiteral>(ArgExp);
+      if(FD && IL) {
+        unsigned int NumParams = FD->getNumParams();
+        llvm::APInt ArgValue = IL->getValue();
+        uint64_t ParamIdx_from1 = ArgValue.getZExtValue();
+        uint64_t ParamIdx_from0 = ParamIdx_from1 - 1;
+        if(!ArgValue.isStrictlyPositive() || ParamIdx_from1 > NumParams) {
+          S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_range)
+            << Attr.getName() << Idx + 1 << NumParams;
+          return false;
+        }
+        Arg_QT = FD->getParamDecl(ParamIdx_from0)->getType();
+        RT = getRecordType(Arg_QT);
+      }
+    }
+
+    //  Flag error if could not get record type for this argument
+    if (!RT) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_class)
+        << Attr.getName();
+      return false;
+    }
+
+    // Flag error if the type is not lockable
+    if (!RT->getDecl()->getAttr<LockableAttr>()) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_lockable)
+        << Attr.getName();
+      return false;
+    }
+  }
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 // Attribute Implementations
 //===----------------------------------------------------------------------===//
@@ -283,7 +342,7 @@
   // 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*/;
+      << Attr.getName() << ExpectedFieldOrGlobalVar;
     return;
   }
 
@@ -297,22 +356,26 @@
 }
 
 static void handleGuardedByAttr(Sema &S, Decl *D, const AttributeList &Attr,
-                                 bool pointer = false) {
+                                bool pointer = false) {
   assert(!Attr.isInvalid());
 
-  if (!checkAttributeNumArgsPlusParams(S, Attr, 1))
+  if (!checkAttributeNumArgs(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*/;
+      << Attr.getName() << ExpectedFieldOrGlobalVar;
     return;
   }
 
   if (pointer && !checkIsPointer(S, D, Attr))
     return;
 
+  // check that all arguments are lockable objects
+  if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+    return;
+
   if (pointer)
     D->addAttr(::new (S.Context) PtGuardedByAttr(Attr.getLoc(), S.Context));
   else
@@ -346,7 +409,7 @@
   if (!checkAttributeNumArgs(S, Attr, 0))
     return;
 
-  if (!isFunction(D)) {
+  if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
     return;
@@ -360,16 +423,32 @@
                                    bool before) {
   assert(!Attr.isInvalid());
 
-  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+  if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
     return;
 
   // D must be either a member field or global (potentially shared) variable.
-  if (!mayBeSharedVariable(D)) {
+  ValueDecl *VD = dyn_cast<ValueDecl>(D);
+  if (!VD || !mayBeSharedVariable(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << Attr.getName() << 15; /*fields and global vars*/;
+      << Attr.getName() << ExpectedFieldOrGlobalVar;
     return;
   }
 
+  // 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::err_attribute_decl_not_lockable)
+              << Attr.getName();
+      return;
+    }
+  }
+
+  // check that all arguments are lockable objects
+  if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+    return;
+
   if (before)
     D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getLoc(), S.Context));
   else
@@ -377,17 +456,22 @@
 }
 
 static void handleLockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
-                                   bool exclusive = false) {
+                              bool exclusive = false) {
   assert(!Attr.isInvalid());
 
   // zero or more arguments ok
 
-  if (!isFunction(D)) {
+  // check that the attribute is applied to a function
+  if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
     return;
   }
 
+  // check that all arguments are lockable objects
+  if (!checkAttrArgsAreLockableObjs(S, D, Attr, 0, /*ParamIdxOk=*/true))
+    return;
+
   if (exclusive)
     D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getLoc(),
                                                            S.Context));
@@ -397,93 +481,118 @@
 }
 
 static void handleTrylockFunAttr(Sema &S, Decl *D, const AttributeList &Attr,
-                                      bool exclusive = false) {
+                                 bool exclusive = false) {
   assert(!Attr.isInvalid());
 
-  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+  if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
     return;
 
-  if (!isFunction(D)) {
+
+  if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
     return;
   }
 
+  if (!isIntOrBool(Attr.getArg(0))) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_first_argument_not_int_or_bool)
+        << Attr.getName();
+    return;
+  }
+
+  // check that all arguments are lockable objects
+  if (!checkAttrArgsAreLockableObjs(S, D, Attr, 1))
+    return;
+
   if (exclusive)
     D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getLoc(),
-                                                           S.Context));
+                                                              S.Context));
   else
     D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getLoc(),
-                                                        S.Context));
-
+                                                           S.Context));
 }
 
 static void handleLocksRequiredAttr(Sema &S, Decl *D, const AttributeList &Attr,
-                                   bool exclusive = false) {
+                                    bool exclusive = false) {
   assert(!Attr.isInvalid());
 
-  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+  if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
     return;
 
-  if (!isFunction(D)) {
+  if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
     return;
   }
 
+  // check that all arguments are lockable objects
+  if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+    return;
+
   if (exclusive)
     D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getLoc(),
-                                                           S.Context));
+                                                            S.Context));
   else
     D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getLoc(),
-                                                        S.Context));
+                                                         S.Context));
 }
 
-
 static void handleUnlockFunAttr(Sema &S, Decl *D,
-                                     const AttributeList &Attr) {
+                                const AttributeList &Attr) {
   assert(!Attr.isInvalid());
 
   // zero or more arguments ok
 
-  if (!isFunction(D)) {
+  if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
     return;
   }
 
+  // check that all arguments are lockable objects
+  if (!checkAttrArgsAreLockableObjs(S, D, Attr, 0, /*ParamIdxOk=*/true))
+    return;
+
   D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getLoc(), S.Context));
 }
 
 static void handleLockReturnedAttr(Sema &S, Decl *D,
-                                     const AttributeList &Attr) {
+                                   const AttributeList &Attr) {
   assert(!Attr.isInvalid());
 
-  if (!checkAttributeNumArgsPlusParams(S, Attr, 1))
+  if (!checkAttributeNumArgs(S, Attr, 1))
     return;
 
-  if (!isFunction(D)) {
+  if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
     return;
   }
 
+  // check that all arguments are lockable objects
+  if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+    return;
+
   D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getLoc(), S.Context));
 }
 
 static void handleLocksExcludedAttr(Sema &S, Decl *D,
-                                     const AttributeList &Attr) {
+                                    const AttributeList &Attr) {
   assert(!Attr.isInvalid());
 
-  if (!checkAttributeNumArgsPlusParams(S, Attr, 1, /*moreok=*/true))
+  if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
     return;
 
-  if (!isFunction(D)) {
+  if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
       << Attr.getName() << ExpectedFunctionOrMethod;
     return;
   }
 
+  // check that all arguments are lockable objects
+  if (!checkAttrArgsAreLockableObjs(S, D, Attr))
+    return;
+
   D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getLoc(), S.Context));
 }
 

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=137130&r1=137129&r2=137130&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-thread-safety.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-thread-safety.cpp Tue Aug  9 12:59:31 2011
@@ -1,19 +1,48 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
 
 
-/**
- *  Helper fields
- */
+//-----------------------------------------//
+//  Helper fields
+//-----------------------------------------//
 
 class __attribute__((lockable)) Mu {
 };
 
+class UnlockableMu{
+};
+
+class MuWrapper {
+  public:
+  Mu mu;
+  Mu getMu() {
+    return mu;
+  }
+  Mu * getMuPointer() {
+    return μ
+  }
+};
+
+
+class MuDoubleWrapper {
+  public:
+  MuWrapper* muWrapper;
+  MuWrapper* getWrapper() {
+    return muWrapper;
+  }
+};
+
 Mu mu1;
+UnlockableMu umu;
 Mu mu2;
-
-/***********************************
- *  No Thread Safety Analysis (noanal)
- ***********************************/
+MuWrapper muWrapper;
+MuDoubleWrapper muDoubleWrapper;
+Mu* muPointer;
+Mu ** muDoublePointer = & muPointer;
+Mu& muRef = mu1;
+
+//-----------------------------------------//
+//   No Thread Safety Analysis (noanal)    //
+//-----------------------------------------//
 
 // FIXME: Right now we cannot parse attributes put on function definitions
 // We would like to patch this at some point.
@@ -53,9 +82,9 @@
   expected-warning {{'no_thread_safety_analysis' attribute only applies to functions and methods}}
 
 
-/***********************************
- *  Guarded Var Attribute (gv)
- ***********************************/
+//-----------------------------------------//
+//  Guarded Var Attribute (gv)
+//-----------------------------------------//
 
 #if !__has_attribute(guarded_var)
 #error "Should support guarded_var attribute"
@@ -89,9 +118,9 @@
   return x;
 }
 
-/***********************************
- *  Pt Guarded Var Attribute (pgv)
- ***********************************/
+//-----------------------------------------//
+//   Pt Guarded Var Attribute (pgv)
+//-----------------------------------------//
 
 //FIXME: add support for boost::scoped_ptr<int> fancyptr  and references
 
@@ -133,9 +162,9 @@
   delete x;
 }
 
-/***********************************
- *  Lockable Attribute (l)
- ***********************************/
+//-----------------------------------------//
+//  Lockable Attribute (l)
+//-----------------------------------------//
 
 //FIXME: In future we may want to add support for structs, ObjC classes, etc.
 
@@ -175,9 +204,9 @@
   expected-warning {{'lockable' attribute only applies to classes}}
 
 
-/***********************************
- *  Scoped Lockable Attribute (sl)
- ***********************************/
+//-----------------------------------------//
+//  Scoped Lockable Attribute (sl)
+//-----------------------------------------//
 
 #if !__has_attribute(scoped_lockable)
 #error "Should support scoped_lockable attribute"
@@ -215,11 +244,11 @@
   expected-warning {{'scoped_lockable' attribute only applies to classes}}
 
 
-/***********************************
- *  Guarded By Attribute (gb)
- ***********************************/
+//-----------------------------------------//
+//  Guarded By Attribute (gb)
+//-----------------------------------------//
 
-// FIXME: Would we like this attribute to take more than 1 arg?
+// FIXME: Eventually, would we like this attribute to take more than 1 arg?
 
 #if !__has_attribute(guarded_by)
 #error "Should support guarded_by attribute"
@@ -258,24 +287,36 @@
   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
+//2. Check argument parsing.
+
+// legal attribute arguments
+int gb_var_arg_1 __attribute__((guarded_by(muWrapper.mu)));
+int gb_var_arg_2 __attribute__((guarded_by(muDoubleWrapper.muWrapper->mu)));
+int gb_var_arg_3 __attribute__((guarded_by(muWrapper.getMu())));
+int gb_var_arg_4 __attribute__((guarded_by(*muWrapper.getMuPointer())));
+int gb_var_arg_5 __attribute__((guarded_by(&mu1)));
+int gb_var_arg_6 __attribute__((guarded_by(muRef)));
+int gb_var_arg_7 __attribute__((guarded_by(muDoubleWrapper.getWrapper()->getMu())));
+int gb_var_arg_8 __attribute__((guarded_by(muPointer)));
+
+
+// illegal attribute arguments
+int gb_var_arg_bad_1 __attribute__((guarded_by(1))); // \
+  expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+int gb_var_arg_bad_2 __attribute__((guarded_by("mu"))); // \
+  expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+int gb_var_arg_bad_3 __attribute__((guarded_by(muDoublePointer))); // \
+  expected-error {{'guarded_by' attribute requires arguments that are class type or point to class type}}
+int gb_var_arg_bad_4 __attribute__((guarded_by(umu))); // \
+  expected-error {{'guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
 
 //3.
 // Thread Safety analysis tests
 
 
-/***********************************
- *  Pt Guarded By Attribute (pgb)
- ***********************************/
+//-----------------------------------------//
+//  Pt Guarded By Attribute (pgb)
+//-----------------------------------------//
 
 #if !__has_attribute(pt_guarded_by)
 #error "Should support pt_guarded_by attribute"
@@ -317,12 +358,35 @@
   delete x;
 }
 
-/***********************************
- *  Acquired After (aa)
- ***********************************/
+//2. Check argument parsing.
+
+// legal attribute arguments
+int * pgb_var_arg_1 __attribute__((pt_guarded_by(muWrapper.mu)));
+int * pgb_var_arg_2 __attribute__((pt_guarded_by(muDoubleWrapper.muWrapper->mu)));
+int * pgb_var_arg_3 __attribute__((pt_guarded_by(muWrapper.getMu())));
+int * pgb_var_arg_4 __attribute__((pt_guarded_by(*muWrapper.getMuPointer())));
+int * pgb_var_arg_5 __attribute__((pt_guarded_by(&mu1)));
+int * pgb_var_arg_6 __attribute__((pt_guarded_by(muRef)));
+int * pgb_var_arg_7 __attribute__((pt_guarded_by(muDoubleWrapper.getWrapper()->getMu())));
+int * pgb_var_arg_8 __attribute__((pt_guarded_by(muPointer)));
+
+
+// illegal attribute arguments
+int * pgb_var_arg_bad_1 __attribute__((pt_guarded_by(1))); // \
+  expected-error {{'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-error {{'pt_guarded_by' attribute requires arguments that are class type or point to class type}}
+int * pgb_var_arg_bad_3 __attribute__((pt_guarded_by(muDoublePointer))); // \
+  expected-error {{'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))); // \
+  expected-error {{'pt_guarded_by' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+//  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"
@@ -355,13 +419,34 @@
       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.
-
+//Check argument parsing.
 
-/***********************************
- *  Acquired Before (ab)
- ***********************************/
+// legal attribute arguments
+Mu aa_var_arg_1 __attribute__((acquired_after(muWrapper.mu)));
+Mu aa_var_arg_2 __attribute__((acquired_after(muDoubleWrapper.muWrapper->mu)));
+Mu aa_var_arg_3 __attribute__((acquired_after(muWrapper.getMu())));
+Mu aa_var_arg_4 __attribute__((acquired_after(*muWrapper.getMuPointer())));
+Mu aa_var_arg_5 __attribute__((acquired_after(&mu1)));
+Mu aa_var_arg_6 __attribute__((acquired_after(muRef)));
+Mu aa_var_arg_7 __attribute__((acquired_after(muDoubleWrapper.getWrapper()->getMu())));
+Mu aa_var_arg_8 __attribute__((acquired_after(muPointer)));
+
+
+// illegal attribute arguments
+Mu aa_var_arg_bad_1 __attribute__((acquired_after(1))); // \
+  expected-error {{'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-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+Mu aa_var_arg_bad_3 __attribute__((acquired_after(muDoublePointer))); // \
+  expected-error {{'acquired_after' attribute requires arguments that are class type or point to class type}}
+Mu aa_var_arg_bad_4 __attribute__((acquired_after(umu))); // \
+  expected-error {{'acquired_after' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+UnlockableMu aa_var_arg_bad_5 __attribute__((acquired_after(mu_aa))); // \
+  expected-error {{'acquired_after' attribute can only be applied in a context annotated with 'lockable' attribute}}
+
+//-----------------------------------------//
+//  Acquired Before (ab)
+//-----------------------------------------//
 
 #if !__has_attribute(acquired_before)
 #error "Should support acquired_before attribute"
@@ -397,9 +482,35 @@
 // 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)
- ***********************************/
+//Check argument parsing.
+
+// legal attribute arguments
+Mu ab_var_arg_1 __attribute__((acquired_before(muWrapper.mu)));
+Mu ab_var_arg_2 __attribute__((acquired_before(muDoubleWrapper.muWrapper->mu)));
+Mu ab_var_arg_3 __attribute__((acquired_before(muWrapper.getMu())));
+Mu ab_var_arg_4 __attribute__((acquired_before(*muWrapper.getMuPointer())));
+Mu ab_var_arg_5 __attribute__((acquired_before(&mu1)));
+Mu ab_var_arg_6 __attribute__((acquired_before(muRef)));
+Mu ab_var_arg_7 __attribute__((acquired_before(muDoubleWrapper.getWrapper()->getMu())));
+Mu ab_var_arg_8 __attribute__((acquired_before(muPointer)));
+
+
+// illegal attribute arguments
+Mu ab_var_arg_bad_1 __attribute__((acquired_before(1))); // \
+  expected-error {{'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-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+Mu ab_var_arg_bad_3 __attribute__((acquired_before(muDoublePointer))); // \
+  expected-error {{'acquired_before' attribute requires arguments that are class type or point to class type}}
+Mu ab_var_arg_bad_4 __attribute__((acquired_before(umu))); // \
+  expected-error {{'acquired_before' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+UnlockableMu ab_var_arg_bad_5 __attribute__((acquired_before(mu_ab))); // \
+  expected-error {{'acquired_before' attribute can only be applied in a context annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+//  Exclusive Lock Function (elf)
+//-----------------------------------------//
 
 #if !__has_attribute(exclusive_lock_function)
 #error "Should support exclusive_lock_function attribute"
@@ -436,11 +547,42 @@
 void elf_fun_params(int lvar __attribute__((exclusive_lock_function))); // \
   expected-warning {{'exclusive_lock_function' attribute only applies to functions and methods}}
 
+// Check argument parsing.
 
-
-/***********************************
- *  Shared Lock Function (slf)
- ***********************************/
+// legal attribute arguments
+int elf_function_1() __attribute__((exclusive_lock_function(muWrapper.mu)));
+int elf_function_2() __attribute__((exclusive_lock_function(muDoubleWrapper.muWrapper->mu)));
+int elf_function_3() __attribute__((exclusive_lock_function(muWrapper.getMu())));
+int elf_function_4() __attribute__((exclusive_lock_function(*muWrapper.getMuPointer())));
+int elf_function_5() __attribute__((exclusive_lock_function(&mu1)));
+int elf_function_6() __attribute__((exclusive_lock_function(muRef)));
+int elf_function_7() __attribute__((exclusive_lock_function(muDoubleWrapper.getWrapper()->getMu())));
+int elf_function_8() __attribute__((exclusive_lock_function(muPointer)));
+int elf_function_9(Mu x) __attribute__((exclusive_lock_function(1)));
+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-error {{'exclusive_lock_function' attribute requires arguments that are class type or point to class type}}
+int elf_function_bad_3() __attribute__((exclusive_lock_function(muDoublePointer))); // \
+  expected-error {{'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))); // \
+  expected-error {{'exclusive_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+int elf_function_bad_1() __attribute__((exclusive_lock_function(1))); // \
+  expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+int elf_function_bad_5(Mu x) __attribute__((exclusive_lock_function(0))); // \
+  expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: can only be 1, since there is one parameter}}
+int elf_function_bad_6(Mu x, Mu y) __attribute__((exclusive_lock_function(0))); // \
+  expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: must be between 1 and 2}}
+int elf_function_bad_7() __attribute__((exclusive_lock_function(0))); // \
+  expected-error {{'exclusive_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+
+
+//-----------------------------------------//
+//  Shared Lock Function (slf)
+//-----------------------------------------//
 
 #if !__has_attribute(shared_lock_function)
 #error "Should support shared_lock_function attribute"
@@ -477,10 +619,42 @@
     expected-warning {{'shared_lock_function' attribute only applies to functions and methods}}
 };
 
+// Check argument parsing.
 
-/***********************************
- *  Exclusive TryLock Function (etf)
- ***********************************/
+// legal attribute arguments
+int slf_function_1() __attribute__((shared_lock_function(muWrapper.mu)));
+int slf_function_2() __attribute__((shared_lock_function(muDoubleWrapper.muWrapper->mu)));
+int slf_function_3() __attribute__((shared_lock_function(muWrapper.getMu())));
+int slf_function_4() __attribute__((shared_lock_function(*muWrapper.getMuPointer())));
+int slf_function_5() __attribute__((shared_lock_function(&mu1)));
+int slf_function_6() __attribute__((shared_lock_function(muRef)));
+int slf_function_7() __attribute__((shared_lock_function(muDoubleWrapper.getWrapper()->getMu())));
+int slf_function_8() __attribute__((shared_lock_function(muPointer)));
+int slf_function_9(Mu x) __attribute__((shared_lock_function(1)));
+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-error {{'shared_lock_function' attribute requires arguments that are class type or point to class type}}
+int slf_function_bad_3() __attribute__((shared_lock_function(muDoublePointer))); // \
+  expected-error {{'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))); // \
+  expected-error {{'shared_lock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+int slf_function_bad_1() __attribute__((shared_lock_function(1))); // \
+  expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+int slf_function_bad_5(Mu x) __attribute__((shared_lock_function(0))); // \
+  expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: can only be 1, since there is one parameter}}
+int slf_function_bad_6(Mu x, Mu y) __attribute__((shared_lock_function(0))); // \
+  expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: must be between 1 and 2}}
+int slf_function_bad_7() __attribute__((shared_lock_function(0))); // \
+  expected-error {{'shared_lock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+
+
+//-----------------------------------------//
+//  Exclusive TryLock Function (etf)
+//-----------------------------------------//
 
 #if !__has_attribute(exclusive_trylock_function)
 #error "Should support exclusive_trylock_function attribute"
@@ -521,11 +695,39 @@
 void etf_fun_params(int lvar __attribute__((exclusive_trylock_function(1)))); // \
   expected-warning {{'exclusive_trylock_function' attribute only applies to functions and methods}}
 
+// Check argument parsing.
 
-
-/***********************************
- *  Shared TryLock Function (stf)
- ***********************************/
+// legal attribute arguments
+int etf_function_1() __attribute__((exclusive_trylock_function(1, muWrapper.mu)));
+int etf_function_2() __attribute__((exclusive_trylock_function(1, muDoubleWrapper.muWrapper->mu)));
+int etf_function_3() __attribute__((exclusive_trylock_function(1, muWrapper.getMu())));
+int etf_function_4() __attribute__((exclusive_trylock_function(1, *muWrapper.getMuPointer())));
+int etf_function_5() __attribute__((exclusive_trylock_function(1, &mu1)));
+int etf_function_6() __attribute__((exclusive_trylock_function(1, muRef)));
+int etf_function_7() __attribute__((exclusive_trylock_function(1, muDoubleWrapper.getWrapper()->getMu())));
+int etf_functetfn_8() __attribute__((exclusive_trylock_function(1, muPointer)));
+int etf_function_9() __attribute__((exclusive_trylock_function(true)));
+
+
+// illegal attribute arguments
+int etf_function_bad_1() __attribute__((exclusive_trylock_function(mu1))); // \
+  expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+int etf_function_bad_2() __attribute__((exclusive_trylock_function("mu"))); // \
+  expected-error {{'exclusive_trylock_function' attribute first argument must be of int or bool type}}
+int etf_function_bad_3() __attribute__((exclusive_trylock_function(muDoublePointer))); // \
+  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-error {{'exclusive_trylock_function' attribute requires arguments that are class type or point to class type}}
+int etf_function_bad_5() __attribute__((exclusive_trylock_function(1, muDoublePointer))); // \
+  expected-error {{'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))); // \
+  expected-error {{'exclusive_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+//  Shared TryLock Function (stf)
+//-----------------------------------------//
 
 #if !__has_attribute(shared_trylock_function)
 #error "Should support shared_trylock_function attribute"
@@ -567,10 +769,39 @@
     expected-warning {{'shared_trylock_function' attribute only applies to functions and methods}}
 };
 
+// Check argument parsing.
 
-/***********************************
- *  Unlock Function (uf)
- ***********************************/
+// legal attribute arguments
+int stf_function_1() __attribute__((shared_trylock_function(1, muWrapper.mu)));
+int stf_function_2() __attribute__((shared_trylock_function(1, muDoubleWrapper.muWrapper->mu)));
+int stf_function_3() __attribute__((shared_trylock_function(1, muWrapper.getMu())));
+int stf_function_4() __attribute__((shared_trylock_function(1, *muWrapper.getMuPointer())));
+int stf_function_5() __attribute__((shared_trylock_function(1, &mu1)));
+int stf_function_6() __attribute__((shared_trylock_function(1, muRef)));
+int stf_function_7() __attribute__((shared_trylock_function(1, muDoubleWrapper.getWrapper()->getMu())));
+int stf_function_8() __attribute__((shared_trylock_function(1, muPointer)));
+int stf_function_9() __attribute__((shared_trylock_function(true)));
+
+
+// illegal attribute arguments
+int stf_function_bad_1() __attribute__((shared_trylock_function(mu1))); // \
+  expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+int stf_function_bad_2() __attribute__((shared_trylock_function("mu"))); // \
+  expected-error {{'shared_trylock_function' attribute first argument must be of int or bool type}}
+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-error {{'shared_trylock_function' attribute requires arguments that are class type or point to class type}}
+int stf_function_bad_5() __attribute__((shared_trylock_function(1, muDoublePointer))); // \
+  expected-error {{'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))); // \
+  expected-error {{'shared_trylock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+//-----------------------------------------//
+//  Unlock Function (uf)
+//-----------------------------------------//
 
 #if !__has_attribute(unlock_function)
 #error "Should support unlock_function attribute"
@@ -607,10 +838,42 @@
 void uf_fun_params(int lvar __attribute__((unlock_function))); // \
   expected-warning {{'unlock_function' attribute only applies to functions and methods}}
 
+// Check argument parsing.
 
-/***********************************
- *  Lock Returned (lr)
- ***********************************/
+// legal attribute arguments
+int uf_function_1() __attribute__((unlock_function(muWrapper.mu)));
+int uf_function_2() __attribute__((unlock_function(muDoubleWrapper.muWrapper->mu)));
+int uf_function_3() __attribute__((unlock_function(muWrapper.getMu())));
+int uf_function_4() __attribute__((unlock_function(*muWrapper.getMuPointer())));
+int uf_function_5() __attribute__((unlock_function(&mu1)));
+int uf_function_6() __attribute__((unlock_function(muRef)));
+int uf_function_7() __attribute__((unlock_function(muDoubleWrapper.getWrapper()->getMu())));
+int uf_function_8() __attribute__((unlock_function(muPointer)));
+int uf_function_9(Mu x) __attribute__((unlock_function(1)));
+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-error {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+int uf_function_bad_3() __attribute__((unlock_function(muDoublePointer))); // \
+expected-error {{'unlock_function' attribute requires arguments that are class type or point to class type}}
+int uf_function_bad_4() __attribute__((unlock_function(umu))); // \
+  expected-error {{'unlock_function' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+int uf_function_bad_1() __attribute__((unlock_function(1))); // \
+  expected-error {{'unlock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+int uf_function_bad_5(Mu x) __attribute__((unlock_function(0))); // \
+  expected-error {{'unlock_function' attribute parameter 1 is out of bounds: can only be 1, since there is one parameter}}
+int uf_function_bad_6(Mu x, Mu y) __attribute__((unlock_function(0))); // \
+  expected-error {{'unlock_function' attribute parameter 1 is out of bounds: must be between 1 and 2}}
+int uf_function_bad_7() __attribute__((unlock_function(0))); // \
+  expected-error {{'unlock_function' attribute parameter 1 is out of bounds: no parameters to index into}}
+
+
+//-----------------------------------------//
+//  Lock Returned (lr)
+//-----------------------------------------//
 
 #if !__has_attribute(lock_returned)
 #error "Should support lock_returned attribute"
@@ -651,9 +914,34 @@
     expected-warning {{'lock_returned' attribute only applies to functions and methods}}
 };
 
-/***********************************
- *  Locks Excluded (le)
- ***********************************/
+// Check argument parsing.
+
+// legal attribute arguments
+int lr_function_1() __attribute__((lock_returned(muWrapper.mu)));
+int lr_function_2() __attribute__((lock_returned(muDoubleWrapper.muWrapper->mu)));
+int lr_function_3() __attribute__((lock_returned(muWrapper.getMu())));
+int lr_function_4() __attribute__((lock_returned(*muWrapper.getMuPointer())));
+int lr_function_5() __attribute__((lock_returned(&mu1)));
+int lr_function_6() __attribute__((lock_returned(muRef)));
+int lr_function_7() __attribute__((lock_returned(muDoubleWrapper.getWrapper()->getMu())));
+int lr_function_8() __attribute__((lock_returned(muPointer)));
+
+
+// illegal attribute arguments
+int lr_function_bad_1() __attribute__((lock_returned(1))); // \
+  expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+int lr_function_bad_2() __attribute__((lock_returned("mu"))); // \
+  expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+int lr_function_bad_3() __attribute__((lock_returned(muDoublePointer))); // \
+  expected-error {{'lock_returned' attribute requires arguments that are class type or point to class type}}
+int lr_function_bad_4() __attribute__((lock_returned(umu))); // \
+  expected-error {{'lock_returned' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+
+//-----------------------------------------//
+//  Locks Excluded (le)
+//-----------------------------------------//
 
 #if !__has_attribute(locks_excluded)
 #error "Should support locks_excluded attribute"
@@ -693,10 +981,34 @@
     expected-warning {{'locks_excluded' attribute only applies to functions and methods}}
 };
 
+// Check argument parsing.
 
-/***********************************
- *  Exclusive Locks Required (elr)
- ***********************************/
+// legal attribute arguments
+int le_function_1() __attribute__((locks_excluded(muWrapper.mu)));
+int le_function_2() __attribute__((locks_excluded(muDoubleWrapper.muWrapper->mu)));
+int le_function_3() __attribute__((locks_excluded(muWrapper.getMu())));
+int le_function_4() __attribute__((locks_excluded(*muWrapper.getMuPointer())));
+int le_function_5() __attribute__((locks_excluded(&mu1)));
+int le_function_6() __attribute__((locks_excluded(muRef)));
+int le_function_7() __attribute__((locks_excluded(muDoubleWrapper.getWrapper()->getMu())));
+int le_function_8() __attribute__((locks_excluded(muPointer)));
+
+
+// illegal attribute arguments
+int le_function_bad_1() __attribute__((locks_excluded(1))); // \
+  expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+int le_function_bad_2() __attribute__((locks_excluded("mu"))); // \
+  expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+int le_function_bad_3() __attribute__((locks_excluded(muDoublePointer))); // \
+  expected-error {{'locks_excluded' attribute requires arguments that are class type or point to class type}}
+int le_function_bad_4() __attribute__((locks_excluded(umu))); // \
+  expected-error {{'locks_excluded' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+
+//-----------------------------------------//
+//  Exclusive Locks Required (elr)
+//-----------------------------------------//
 
 #if !__has_attribute(exclusive_locks_required)
 #error "Should support exclusive_locks_required attribute"
@@ -736,9 +1048,35 @@
     expected-warning {{'exclusive_locks_required' attribute only applies to functions and methods}}
 };
 
-/***********************************
- *  Shared Locks Required (slr)
- ***********************************/
+// Check argument parsing.
+
+// legal attribute arguments
+int elr_function_1() __attribute__((exclusive_locks_required(muWrapper.mu)));
+int elr_function_2() __attribute__((exclusive_locks_required(muDoubleWrapper.muWrapper->mu)));
+int elr_function_3() __attribute__((exclusive_locks_required(muWrapper.getMu())));
+int elr_function_4() __attribute__((exclusive_locks_required(*muWrapper.getMuPointer())));
+int elr_function_5() __attribute__((exclusive_locks_required(&mu1)));
+int elr_function_6() __attribute__((exclusive_locks_required(muRef)));
+int elr_function_7() __attribute__((exclusive_locks_required(muDoubleWrapper.getWrapper()->getMu())));
+int elr_function_8() __attribute__((exclusive_locks_required(muPointer)));
+
+
+// illegal attribute arguments
+int elr_function_bad_1() __attribute__((exclusive_locks_required(1))); // \
+  expected-error {{'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-error {{'exclusive_locks_required' attribute requires arguments that are class type or point to class type}}
+int elr_function_bad_3() __attribute__((exclusive_locks_required(muDoublePointer))); // \
+  expected-error {{'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))); // \
+  expected-error {{'exclusive_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+
+
+
+
+//-----------------------------------------//
+//  Shared Locks Required (slr)
+//-----------------------------------------//
 
 #if !__has_attribute(shared_locks_required)
 #error "Should support shared_locks_required attribute"
@@ -777,3 +1115,27 @@
 class __attribute__((shared_locks_required(mu1))) SlrTestClass { // \
     expected-warning {{'shared_locks_required' attribute only applies to functions and methods}}
 };
+
+// Check argument parsing.
+
+// legal attribute arguments
+int slr_function_1() __attribute__((shared_locks_required(muWrapper.mu)));
+int slr_function_2() __attribute__((shared_locks_required(muDoubleWrapper.muWrapper->mu)));
+int slr_function_3() __attribute__((shared_locks_required(muWrapper.getMu())));
+int slr_function_4() __attribute__((shared_locks_required(*muWrapper.getMuPointer())));
+int slr_function_5() __attribute__((shared_locks_required(&mu1)));
+int slr_function_6() __attribute__((shared_locks_required(muRef)));
+int slr_function_7() __attribute__((shared_locks_required(muDoubleWrapper.getWrapper()->getMu())));
+int slr_function_8() __attribute__((shared_locks_required(muPointer)));
+
+
+// illegal attribute arguments
+int slr_function_bad_1() __attribute__((shared_locks_required(1))); // \
+  expected-error {{'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-error {{'shared_locks_required' attribute requires arguments that are class type or point to class type}}
+int slr_function_bad_3() __attribute__((shared_locks_required(muDoublePointer))); // \
+  expected-error {{'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))); // \
+  expected-error {{'shared_locks_required' attribute requires arguments whose type is annotated with 'lockable' attribute}}
+





More information about the cfe-commits mailing list