]> granicus.if.org Git - clang/commitdiff
Thread Safety: Patch to implement delayed parsing of attributes within a
authorCaitlin Sadowski <supertri@google.com>
Thu, 8 Sep 2011 17:42:22 +0000 (17:42 +0000)
committerCaitlin Sadowski <supertri@google.com>
Thu, 8 Sep 2011 17:42:22 +0000 (17:42 +0000)
class scope.

This patch was also written by DeLesley Hutchins.

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

14 files changed:
include/clang/Basic/Attr.td
include/clang/CMakeLists.txt
include/clang/Makefile
include/clang/Parse/CMakeLists.txt [new file with mode: 0644]
include/clang/Parse/Makefile [new file with mode: 0644]
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/Parse/CMakeLists.txt
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Sema/AnalysisBasedWarnings.cpp
lib/Sema/SemaDecl.cpp
test/SemaCXX/warn-thread-safety-analysis.cpp
test/SemaCXX/warn-thread-safety-parsing.cpp

index fb3ba0257552782df462a9522a1fbff1f911a1ab..d2de30a439b18f73bd10b04a2f48d501c339cd7b 100644 (file)
@@ -90,7 +90,9 @@ class Attr {
   // The attribute will not be permitted in C++0x attribute-specifiers if
   // this is empty; the empty string can be used as a namespace.
   list<string> Namespaces = [];
-  // Any additional text that should be included verbatim in the class.
+  // Set to true for attributes with arguments which require delayed parsing. 
+  bit LateParsed = 0;  
+  // Any additional text that should be included verbatim in the class.  
   code AdditionalMembers = [{}];
 }
 
@@ -566,64 +568,77 @@ def NoThreadSafetyAnalysis : InheritableAttr {
 def GuardedBy : InheritableAttr {
   let Spellings = ["guarded_by"];
   let Args = [ExprArgument<"Arg">];
+  let LateParsed = 1;
 }
 
 def PtGuardedBy : InheritableAttr {
   let Spellings = ["pt_guarded_by"];
   let Args = [ExprArgument<"Arg">];
+  let LateParsed = 1;
 }
 
 def AcquiredAfter : InheritableAttr {
   let Spellings = ["acquired_after"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
 
 def AcquiredBefore : InheritableAttr {
   let Spellings = ["acquired_before"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
 
 def ExclusiveLockFunction : InheritableAttr {
   let Spellings = ["exclusive_lock_function"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
 
 def SharedLockFunction : InheritableAttr {
   let Spellings = ["shared_lock_function"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
 
 def ExclusiveTrylockFunction : InheritableAttr {
   let Spellings = ["exclusive_trylock_function"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
 
 def SharedTrylockFunction : InheritableAttr {
   let Spellings = ["shared_trylock_function"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
 
 def UnlockFunction : InheritableAttr {
   let Spellings = ["unlock_function"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
 
 def LockReturned : InheritableAttr {
   let Spellings = ["lock_returned"];
   let Args = [ExprArgument<"Arg">];
+  let LateParsed = 1;
 }
 
 def LocksExcluded : InheritableAttr {
   let Spellings = ["locks_excluded"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
 
 def ExclusiveLocksRequired : InheritableAttr {
   let Spellings = ["exclusive_locks_required"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
 
 def SharedLocksRequired : InheritableAttr {
   let Spellings = ["shared_locks_required"];
   let Args = [VariadicExprArgument<"Args">];
+  let LateParsed = 1;
 }
index 375ae5bdabc85a322c04a9b048b06cc9610ddee2..fb4e04d55b1569b067546d1892d701ed487f2915 100644 (file)
@@ -2,4 +2,5 @@ add_subdirectory(AST)
 add_subdirectory(Basic)
 add_subdirectory(Driver)
 add_subdirectory(Lex)
+add_subdirectory(Parse)
 add_subdirectory(Serialization)
index a7be0319e5fa18ef625f3e37f15988b071744b54..a6f2597cb95a2727a54672110120468fa0b55fb6 100644 (file)
@@ -1,5 +1,5 @@
 CLANG_LEVEL := ../..
-DIRS := AST Basic Driver Lex Serialization
+DIRS := AST Basic Driver Lex Parse Serialization
 
 include $(CLANG_LEVEL)/Makefile
 
diff --git a/include/clang/Parse/CMakeLists.txt b/include/clang/Parse/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d1ff2ab
--- /dev/null
@@ -0,0 +1,4 @@
+clang_tablegen(AttrLateParsed.inc -gen-clang-attr-late-parsed-list
+  -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+  SOURCE ../Basic/Attr.td
+  TARGET ClangAttrLateParsed)
diff --git a/include/clang/Parse/Makefile b/include/clang/Parse/Makefile
new file mode 100644 (file)
index 0000000..b1c81df
--- /dev/null
@@ -0,0 +1,13 @@
+CLANG_LEVEL := ../../..
+TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
+BUILT_SOURCES = AttrLateParsed.inc
+
+TABLEGEN_INC_FILES_COMMON = 1
+
+include $(CLANG_LEVEL)/Makefile
+
+$(ObjDir)/AttrLateParsed.inc.tmp : $(TD_SRC_DIR)/Attr.td $(TBLGEN) \
+                                   $(ObjDir)/.dir
+       $(Echo) "Building Clang attribute late-parsed table with tblgen"
+       $(Verb) $(TableGen) -gen-clang-attr-late-parsed-list -o $(call SYSPATH, $@) \
+               -I $(PROJ_SRC_DIR)/../../ $<
\ No newline at end of file
index 1b0949c3242c67bd4dcecd484b5e8d32f52b3455..71042303baacee071aabcb1676d304f5db93a128 100644 (file)
@@ -22,6 +22,7 @@
 #include "clang/Sema/DeclSpec.h"
 #include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
 #include <stack>
 
 namespace clang {
@@ -664,6 +665,7 @@ private:
     virtual void ParseLexedMethodDeclarations();
     virtual void ParseLexedMemberInitializers();
     virtual void ParseLexedMethodDefs();
+    virtual void ParseLexedAttributes();
   };
 
   /// Inner node of the LateParsedDeclaration tree that parses
@@ -676,12 +678,39 @@ private:
     virtual void ParseLexedMethodDeclarations();
     virtual void ParseLexedMemberInitializers();
     virtual void ParseLexedMethodDefs();
+    virtual void ParseLexedAttributes();
 
   private:
     Parser *Self;
     ParsingClass *Class;
   };
 
+  /// Contains the lexed tokens of an attribute with arguments that 
+  /// may reference member variables and so need to be parsed at the 
+  /// end of the class declaration after parsing all other member 
+  /// member declarations.
+  /// FIXME: Perhaps we should change the name of LateParsedDeclaration to
+  /// LateParsedTokens.
+  struct LateParsedAttribute : public LateParsedDeclaration {
+    Parser *Self;
+    CachedTokens Toks;
+    IdentifierInfo &AttrName;
+    SourceLocation AttrNameLoc;
+    Decl *D;
+
+    explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name, 
+                                 SourceLocation Loc)
+      : Self(P), AttrName(Name), AttrNameLoc(Loc), D(0)  {}
+
+    virtual void ParseLexedAttributes();
+
+    void setDecl(Decl *Dec) { D = Dec; }
+  };
+
+  /// A list of late parsed attributes.  Used by ParseGNUAttributes.
+  typedef llvm::SmallVector<LateParsedAttribute*, 2> LateParsedAttrList;
+
+
   /// Contains the lexed tokens of a member function definition
   /// which needs to be parsed at the end of the class declaration
   /// after parsing all other member declarations.
@@ -1028,6 +1057,8 @@ private:
                                 const ParsedTemplateInfo &TemplateInfo,
                                 const VirtSpecifiers& VS, ExprResult& Init);
   void ParseCXXNonStaticMemberInitializer(Decl *VarD);
+  void ParseLexedAttributes(ParsingClass &Class);
+  void ParseLexedAttribute(LateParsedAttribute &LA);
   void ParseLexedMethodDeclarations(ParsingClass &Class);
   void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM);
   void ParseLexedMethodDefs(ParsingClass &Class);
@@ -1665,21 +1696,28 @@ bool ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
   }
   void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs);
 
-  void MaybeParseGNUAttributes(Declarator &D) {
+  void MaybeParseGNUAttributes(Declarator &D,
+                               LateParsedAttrList *LateAttrs = 0) {
     if (Tok.is(tok::kw___attribute)) {
       ParsedAttributes attrs(AttrFactory);
       SourceLocation endLoc;
-      ParseGNUAttributes(attrs, &endLoc);
+      ParseGNUAttributes(attrs, &endLoc, LateAttrs);
       D.takeAttributes(attrs, endLoc);
     }
   }
   void MaybeParseGNUAttributes(ParsedAttributes &attrs,
-                               SourceLocation *endLoc = 0) {
+                               SourceLocation *endLoc = 0,
+                               LateParsedAttrList *LateAttrs = 0) {
     if (Tok.is(tok::kw___attribute))
-      ParseGNUAttributes(attrs, endLoc);
+      ParseGNUAttributes(attrs, endLoc, LateAttrs);
   }
   void ParseGNUAttributes(ParsedAttributes &attrs,
-                          SourceLocation *endLoc = 0);
+                          SourceLocation *endLoc = 0,
+                          LateParsedAttrList *LateAttrs = 0);
+  void ParseGNUAttributeArgs(IdentifierInfo *AttrName,
+                             SourceLocation AttrNameLoc,
+                             ParsedAttributes &Attrs,
+                             SourceLocation *EndLoc);
 
   void MaybeParseCXX0XAttributes(Declarator &D) {
     if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
index fce56f06217b2f94ef26f5dcd3c826e795ba664f..89d210f135a5f1d154283f7b0b42cd387cb8a737 100644 (file)
@@ -1064,6 +1064,10 @@ public:
   Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
   Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
 
+  /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an
+  /// attribute for which parsing is delayed.
+  void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs);
+
   /// \brief Diagnose any unused parameters in the given sequence of
   /// ParmVarDecl pointers.
   void DiagnoseUnusedParameters(ParmVarDecl * const *Begin,
index 6bf5e64cc6f89d91000b46ef905203ee724d1f45..6c980ced7ee418e57c2712b45ad5b8a574c2e962 100644 (file)
@@ -16,4 +16,4 @@ add_clang_library(clangParse
   Parser.cpp
   )
 
-add_dependencies(clangParse ClangAttrClasses ClangAttrList ClangDeclNodes ClangDiagnosticParse ClangStmtNodes)
+add_dependencies(clangParse ClangAttrClasses ClangAttrList ClangDeclNodes ClangDiagnosticParse ClangStmtNodes ClangAttrLateParsed)
index 40674ee7a98f73ff474ca4baf4a7b14df42ae83c..1f9f85bab71b7d4c03e16a47d9a49c3914ef4611 100644 (file)
@@ -55,6 +55,16 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
   return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
 }
 
+
+/// isAttributeLateParsed - Return true if the attribute has arguments that
+/// require late parsing.
+static bool isAttributeLateParsed(const IdentifierInfo &II) {
+    return llvm::StringSwitch<bool>(II.getName())
+#include "clang/Parse/AttrLateParsed.inc"
+        .Default(false);
+}
+
+
 /// ParseGNUAttributes - Parse a non-empty attributes list.
 ///
 /// [GNU] attributes:
@@ -92,7 +102,8 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
 /// a pressing need to implement the 2 token lookahead.
 
 void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
-                                SourceLocation *endLoc) {
+                                SourceLocation *endLoc,
+                                LateParsedAttrList *LateAttrs) {
   assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
 
   while (Tok.is(tok::kw___attribute)) {
@@ -109,7 +120,6 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
     // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
     while (Tok.is(tok::identifier) || isDeclarationSpecifier() ||
            Tok.is(tok::comma)) {
-
       if (Tok.is(tok::comma)) {
         // allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
         ConsumeToken();
@@ -119,116 +129,26 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
       IdentifierInfo *AttrName = Tok.getIdentifierInfo();
       SourceLocation AttrNameLoc = ConsumeToken();
 
-      // 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
-
-        if (Tok.is(tok::identifier)) {
-          IdentifierInfo *ParmName = Tok.getIdentifierInfo();
-          SourceLocation ParmLoc = ConsumeToken();
-
-          if (Tok.is(tok::r_paren)) {
-            // __attribute__(( mode(byte) ))
-            ConsumeParen(); // ignore the right paren loc for now
-            attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
-                         ParmName, ParmLoc, 0, 0);
-          } else if (Tok.is(tok::comma)) {
-            ConsumeToken();
-            // __attribute__(( format(printf, 1, 2) ))
-            ExprVector ArgExprs(Actions);
-            bool ArgExprsOk = true;
-
-            // now parse the non-empty comma separated list of expressions
-            while (1) {
-              ExprResult ArgExpr(ParseAssignmentExpression());
-              if (ArgExpr.isInvalid()) {
-                ArgExprsOk = false;
-                SkipUntil(tok::r_paren);
-                break;
-              } else {
-                ArgExprs.push_back(ArgExpr.release());
-              }
-              if (Tok.isNot(tok::comma))
-                break;
-              ConsumeToken(); // Eat the comma, move to the next argument
-            }
-            if (ArgExprsOk && Tok.is(tok::r_paren)) {
-              ConsumeParen(); // ignore the right paren loc for now
-              attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
-                           ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
-            }
-          }
-        } else { // not an identifier
-          switch (Tok.getKind()) {
-          case tok::r_paren:
-          // parse a possibly empty comma separated list of expressions
-            // __attribute__(( nonnull() ))
-            ConsumeParen(); // ignore the right paren loc for now
-            attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
-                         0, SourceLocation(), 0, 0);
-            break;
-          case tok::kw_char:
-          case tok::kw_wchar_t:
-          case tok::kw_char16_t:
-          case tok::kw_char32_t:
-          case tok::kw_bool:
-          case tok::kw_short:
-          case tok::kw_int:
-          case tok::kw_long:
-          case tok::kw___int64:
-          case tok::kw_signed:
-          case tok::kw_unsigned:
-          case tok::kw_float:
-          case tok::kw_double:
-          case tok::kw_void:
-          case tok::kw_typeof: {
-            AttributeList *attr
-              = attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
-                             0, SourceLocation(), 0, 0);
-            if (attr->getKind() == AttributeList::AT_IBOutletCollection)
-              Diag(Tok, diag::err_iboutletcollection_builtintype);
-            // If it's a builtin type name, eat it and expect a rparen
-            // __attribute__(( vec_type_hint(char) ))
-            ConsumeToken();
-            if (Tok.is(tok::r_paren))
-              ConsumeParen();
-            break;
-          }
-          default:
-            // __attribute__(( aligned(16) ))
-            ExprVector ArgExprs(Actions);
-            bool ArgExprsOk = true;
-
-            // now parse the list of expressions
-            while (1) {
-              ExprResult ArgExpr(ParseAssignmentExpression());
-              if (ArgExpr.isInvalid()) {
-                ArgExprsOk = false;
-                SkipUntil(tok::r_paren);
-                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());
-            }
-            break;
-          }
+      if (Tok.is(tok::l_paren)) {
+        // handle "parameterized" attributes
+        if (LateAttrs && !ClassStack.empty() &&
+            isAttributeLateParsed(*AttrName)) {
+          // Delayed parsing is only available for attributes that occur
+          // in certain locations within a class scope.
+          LateParsedAttribute *LA =
+            new LateParsedAttribute(this, *AttrName, AttrNameLoc);
+          LateAttrs->push_back(LA);
+          getCurrentClass().LateParsedDeclarations.push_back(LA);
+
+          // consume everything up to and including the matching right parens
+          ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false);
+
+          Token Eof;
+          Eof.startToken();
+          Eof.setLocation(Tok.getLocation());
+          LA->Toks.push_back(Eof);
+        } else {
+          ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc);
         }
       } else {
         attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
@@ -246,6 +166,132 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
   }
 }
 
+
+/// Parse the arguments to a parameterized GNU attribute
+void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
+                                   SourceLocation AttrNameLoc,
+                                   ParsedAttributes &Attrs,
+                                   SourceLocation *EndLoc) {
+
+  assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
+
+  // Availability attributes have their own grammar.
+  if (AttrName->isStr("availability")) {
+    ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
+    return;
+  }
+  // Thread safety attributes fit into the FIXME case above, so we
+  // just parse the arguments as a list of expressions
+  if (IsThreadSafetyAttribute(AttrName->getName())) {
+    ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc);
+    return;
+  }
+
+  ConsumeParen(); // ignore the left paren loc for now
+
+  if (Tok.is(tok::identifier)) {
+    IdentifierInfo *ParmName = Tok.getIdentifierInfo();
+    SourceLocation ParmLoc = ConsumeToken();
+
+    if (Tok.is(tok::r_paren)) {
+      // __attribute__(( mode(byte) ))
+      ConsumeParen(); // ignore the right paren loc for now
+      Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+                   ParmName, ParmLoc, 0, 0);
+    } else if (Tok.is(tok::comma)) {
+      ConsumeToken();
+      // __attribute__(( format(printf, 1, 2) ))
+      ExprVector ArgExprs(Actions);
+      bool ArgExprsOk = true;
+
+      // now parse the non-empty comma separated list of expressions
+      while (1) {
+        ExprResult ArgExpr(ParseAssignmentExpression());
+        if (ArgExpr.isInvalid()) {
+          ArgExprsOk = false;
+          SkipUntil(tok::r_paren);
+          break;
+        } else {
+          ArgExprs.push_back(ArgExpr.release());
+        }
+        if (Tok.isNot(tok::comma))
+          break;
+        ConsumeToken(); // Eat the comma, move to the next argument
+      }
+      if (ArgExprsOk && Tok.is(tok::r_paren)) {
+        ConsumeParen(); // ignore the right paren loc for now
+        Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+                     ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size());
+      }
+    }
+  } else { // not an identifier
+    switch (Tok.getKind()) {
+    case tok::r_paren:
+    // parse a possibly empty comma separated list of expressions
+      // __attribute__(( nonnull() ))
+      ConsumeParen(); // ignore the right paren loc for now
+      Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+                   0, SourceLocation(), 0, 0);
+      break;
+    case tok::kw_char:
+    case tok::kw_wchar_t:
+    case tok::kw_char16_t:
+    case tok::kw_char32_t:
+    case tok::kw_bool:
+    case tok::kw_short:
+    case tok::kw_int:
+    case tok::kw_long:
+    case tok::kw___int64:
+    case tok::kw_signed:
+    case tok::kw_unsigned:
+    case tok::kw_float:
+    case tok::kw_double:
+    case tok::kw_void:
+    case tok::kw_typeof: {
+      AttributeList *attr
+        = Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc,
+                       0, SourceLocation(), 0, 0);
+      if (attr->getKind() == AttributeList::AT_IBOutletCollection)
+        Diag(Tok, diag::err_iboutletcollection_builtintype);
+      // If it's a builtin type name, eat it and expect a rparen
+      // __attribute__(( vec_type_hint(char) ))
+      ConsumeToken();
+      if (Tok.is(tok::r_paren))
+        ConsumeParen();
+      break;
+    }
+    default:
+      // __attribute__(( aligned(16) ))
+      ExprVector ArgExprs(Actions);
+      bool ArgExprsOk = true;
+
+      // now parse the list of expressions
+      while (1) {
+        ExprResult ArgExpr(ParseAssignmentExpression());
+        if (ArgExpr.isInvalid()) {
+          ArgExprsOk = false;
+          SkipUntil(tok::r_paren);
+          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());
+      }
+      break;
+    }
+  }
+}
+
+
 /// ParseMicrosoftDeclSpec - Parse an __declspec construct
 ///
 /// [MS] decl-specifier:
@@ -658,6 +704,80 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
                UnavailableLoc, false, false);
 }
 
+
+// Late Parsed Attributes:
+// See other examples of late parsing in lib/Parse/ParseCXXInlineMethods
+
+void Parser::LateParsedDeclaration::ParseLexedAttributes() {}
+
+void Parser::LateParsedClass::ParseLexedAttributes() {
+  Self->ParseLexedAttributes(*Class);
+}
+
+void Parser::LateParsedAttribute::ParseLexedAttributes() {
+  Self->ParseLexedAttribute(*this);
+}
+
+/// Wrapper class which calls ParseLexedAttribute, after setting up the
+/// scope appropriately.
+void Parser::ParseLexedAttributes(ParsingClass &Class) {
+  // Deal with templates
+  // FIXME: Test cases to make sure this does the right thing for templates.
+  bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+  ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
+                                HasTemplateScope);
+  if (HasTemplateScope)
+    Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
+
+  // Set or update the scope flags to include Scope::ThisScope.
+  bool AlreadyHasClassScope = Class.TopLevelClass;
+  unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope;
+  ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
+  ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
+
+  for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i) {
+    Class.LateParsedDeclarations[i]->ParseLexedAttributes();
+  }
+}
+
+/// \brief Finish parsing an attribute for which parsing was delayed.
+/// This will be called at the end of parsing a class declaration
+/// for each LateParsedAttribute. We consume the saved tokens and
+/// create an attribute with the arguments filled in. We add this 
+/// to the Attribute list for the decl.
+void Parser::ParseLexedAttribute(LateParsedAttribute &LA) {
+  // Save the current token position.
+  SourceLocation OrigLoc = Tok.getLocation();
+
+  // Append the current token at the end of the new token stream so that it
+  // doesn't get lost.
+  LA.Toks.push_back(Tok);
+  PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false);
+  // Consume the previously pushed token.
+  ConsumeAnyToken();
+
+  ParsedAttributes Attrs(AttrFactory);
+  SourceLocation endLoc;
+
+  ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc);
+
+  // Late parsed attributes must be attached to Decls by hand.  If the
+  // LA.D is not set, then this was not done properly.
+  assert(LA.D && "No decl attached to late parsed attribute");
+  Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.D, Attrs);
+
+  if (Tok.getLocation() != OrigLoc) {
+    // Due to a parsing error, we either went over the cached tokens or
+    // there are still cached tokens left, so we skip the leftover tokens.
+    // Since this is an uncommon situation that should be avoided, use the
+    // expensive isBeforeInTranslationUnit call.
+    if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
+                                                        OrigLoc))
+    while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof))
+        ConsumeAnyToken();
+  }
+}
+
 /// \brief Wrapper around a case statement checking if AttrName is
 /// one of the thread safety attributes
 bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){
@@ -699,37 +819,35 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
                                         SourceLocation AttrNameLoc,
                                         ParsedAttributes &Attrs,
                                         SourceLocation *EndLoc) {
+  assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
 
-  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());
+  SourceLocation LeftParenLoc = Tok.getLocation();
+  ConsumeParen();
+  
+  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());
     }
-  } else {
-    Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc,
-                 0, SourceLocation(), 0, 0);
+    if (Tok.isNot(tok::comma))
+      break;
+    ConsumeToken(); // Eat the comma, move to the next argument
+  }
+  // Match the ')'.
+  if (ArgExprsOk && Tok.is(tok::r_paren)) {
+    if (EndLoc)
+      *EndLoc = Tok.getLocation();
+    ConsumeParen();
+    Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(),
+                 ArgExprs.take(), ArgExprs.size());
   }
 }
 
index 385683abd6a3979b2d076b9b6dd3a37a34503e69..0dacf3c8a394c108ff4a4f58faa67b1ff6e2004d 100644 (file)
@@ -1707,6 +1707,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
   VirtSpecifiers VS;
   ExprResult Init;
 
+  // Hold late-parsed attributes so we can attach a Decl to them later.
+  LateParsedAttrList LateParsedAttrs;
+
   if (Tok.isNot(tok::colon)) {
     // Don't parse FOO:BAR as if it were a typo for FOO::BAR.
     ColonProtectionRAIIObject X(*this);
@@ -1725,7 +1728,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
     ParseOptionalCXX0XVirtSpecifierSeq(VS);
 
     // If attributes exist after the declarator, but before an '{', parse them.
-    MaybeParseGNUAttributes(DeclaratorInfo);
+    MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
 
     // MSVC permits pure specifier on inline functions declared at class scope.
     // Hence check for =0 before checking for function definition.
@@ -1782,7 +1785,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
         return;
       }
 
-      ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
+      Decl *FunDecl =
+        ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
+
+      for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
+        LateParsedAttrs[i]->setDecl(FunDecl);
+      }
+      LateParsedAttrs.clear();
 
       // Consume the ';' - it's optional unless we have a delete or default
       if (Tok.is(tok::semi)) {
@@ -1824,7 +1833,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
     }
 
     // If attributes exist after the declarator, parse them.
-    MaybeParseGNUAttributes(DeclaratorInfo);
+    MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
 
     // FIXME: When g++ adds support for this, we'll need to check whether it
     // goes before or after the GNU attributes and __asm__.
@@ -1882,6 +1891,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
 
     DeclaratorInfo.complete(ThisDecl);
 
+    // Set the Decl for any late parsed attributes
+    for (unsigned i = 0, ni = LateParsedAttrs.size(); i < ni; ++i) {
+      LateParsedAttrs[i]->setDecl(ThisDecl);
+    }
+    LateParsedAttrs.clear();
+
     if (HasDeferredInitializer) {
       if (!getLang().CPlusPlus0x)
         Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension);
@@ -2153,8 +2168,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
   if (TagDecl && NonNestedClass) {
     // We are not inside a nested class. This class and its nested classes
     // are complete and we can parse the delayed portions of method
-    // declarations and the lexed inline method definitions.
+    // declarations and the lexed inline method definitions, along with any
+    // delayed attributes.
     SourceLocation SavedPrevTokLocation = PrevTokLocation;
+    ParseLexedAttributes(getCurrentClass());
     ParseLexedMethodDeclarations(getCurrentClass());
     ParseLexedMemberInitializers(getCurrentClass());
     ParseLexedMethodDefs(getCurrentClass());
index b11089cc1b302c9991a09068196d543b03a3c4d8..2d6a483e0d6694ca07ec35a3e3be52624ed0751b 100644 (file)
@@ -734,6 +734,8 @@ class LockID {
       NamedDecl *ND = ME->getMemberDecl();
       DeclSeq.push_back(ND);
       buildLock(ME->getBase());
+    } else if (isa<CXXThisExpr>(Exp)) {
+      return;
     } else {
       // FIXME: add diagnostic
       llvm::report_fatal_error("Expected lock expression!");
index f4898a1dd8f1adc318c113845ea4e0fb05dedfc5..251913eb796173257bceda880fd424ae43116cc1 100644 (file)
@@ -6778,6 +6778,15 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
   return dcl;
 }
 
+
+/// When we finish delayed parsing of an attribute, we must attach it to the
+/// relevant Decl.
+void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
+                                       ParsedAttributes &Attrs) {
+  ProcessDeclAttributeList(S, D, Attrs.getList());
+}
+
+
 /// ImplicitlyDefineFunction - An undeclared identifier was used in a function
 /// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
 NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
index cbc947787d786341ad9255b304c852b18362cb40..6483a90a3c041373033da87bf6abe0466a667e64 100644 (file)
@@ -407,3 +407,28 @@ void gb_bad_9() {
     expected-warning {{accessing variable 'sls_guard_var' requires some lock}}    
 }
 
+//-----------------------------------------------//
+// Warnings on variables with late parsed attributes
+// ----------------------------------------------//
+
+class LateFoo {
+public:
+  int a __attribute__((guarded_by(mu)));
+  int b;
+
+  void foo() __attribute__((exclusive_locks_required(mu))) { }
+
+  void test() {
+    a = 0; // \
+      expected-warning {{accessing variable 'a' requires lock 'mu'}}
+    b = a; // \
+      expected-warning {{accessing variable 'a' requires lock 'mu'}}
+    c = 0; // \
+      expected-warning {{accessing variable 'c' requires lock 'mu'}}
+  }
+
+  int c __attribute__((guarded_by(mu)));
+
+  Mutex mu;
+};
+
index e943f3b3839529b87bad223c7b97f38194fcfa32..5063c643c37ff3b549df6335f5ce4e507ba5f956 100644 (file)
@@ -6,6 +6,8 @@
 //-----------------------------------------//
 
 class __attribute__((lockable)) Mu {
+  public:
+  void Lock();
 };
 
 class UnlockableMu{
@@ -40,6 +42,26 @@ Mu* muPointer;
 Mu ** muDoublePointer = & muPointer;
 Mu& muRef = mu1;
 
+//---------------------------------------//
+// Scoping tests
+//--------------------------------------//
+
+class Foo {
+  Mu foomu;    
+  void needLock() __attribute__((exclusive_lock_function(foomu)));
+};
+
+class Foo2 {
+  void needLock() __attribute__((exclusive_lock_function(foomu)));
+  Mu foomu;    
+};
+
+class Bar {
+ Mu barmu;
+ Mu barmu2 __attribute__((acquired_after(barmu)));
+};
+
+
 //-----------------------------------------//
 //   No Thread Safety Analysis (noanal)    //
 //-----------------------------------------//