[cfe-commits] r39539 - in /cfe/cfe/trunk: AST/Decl.cpp Parse/ParseDecl.cpp Parse/ParseStmt.cpp Parse/Parser.cpp Sema/Sema.h Sema/SemaDecl.cpp clang.xcodeproj/project.pbxproj include/clang/AST/Decl.h include/clang/Parse/Action.h include/clang/Parse/Parser.h

Steve Naroff snaroff at apple.com
Wed Jul 11 09:45:24 PDT 2007


Author: snaroff
Date: Wed Jul 11 11:45:23 2007
New Revision: 39539

URL: http://llvm.org/viewvc/llvm-project?rev=39539&view=rev
Log:
Bug #:
Submitted by:
Reviewed by:
Implement support for GCC __attribute__.

- Implement "TODO" in Parser::ParseAttributes. Changed the return type from
void to Parser::DeclTy. Changed all call sites to accept the return value.
- Added Action::ParseAttribute and Sema::ParseAttribute to return an
appropriate AST node. Added new node AttributeDecl to Decl.h.

Still to do...hook up to the Decl...

Modified:
    cfe/cfe/trunk/AST/Decl.cpp
    cfe/cfe/trunk/Parse/ParseDecl.cpp
    cfe/cfe/trunk/Parse/ParseStmt.cpp
    cfe/cfe/trunk/Parse/Parser.cpp
    cfe/cfe/trunk/Sema/Sema.h
    cfe/cfe/trunk/Sema/SemaDecl.cpp
    cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
    cfe/cfe/trunk/include/clang/AST/Decl.h
    cfe/cfe/trunk/include/clang/Parse/Action.h
    cfe/cfe/trunk/include/clang/Parse/Parser.h

Modified: cfe/cfe/trunk/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Decl.cpp?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/Decl.cpp (original)
+++ cfe/cfe/trunk/AST/Decl.cpp Wed Jul 11 11:45:23 2007
@@ -102,6 +102,9 @@
     case Enum:
       nEnumDecls++;
       break;
+    case Attribute:
+      // FIXME
+      break;
   }
 }
 
@@ -176,3 +179,10 @@
   return 0;
 }
 
+AttributeDecl::AttributeDecl(SourceLocation L, IdentifierInfo *AttrName, 
+                IdentifierInfo *pname, Expr **elist, unsigned numargs)
+  : Decl(Attribute, L, AttrName), ParmName(pname), NumArgs(numargs) {
+  Args = new Expr*[numargs];
+  for (unsigned i = 0; i != numargs; ++i)
+    Args[i] = elist[i];
+}

Modified: cfe/cfe/trunk/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/ParseDecl.cpp?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/Parse/ParseDecl.cpp (original)
+++ cfe/cfe/trunk/Parse/ParseDecl.cpp Wed Jul 11 11:45:23 2007
@@ -51,24 +51,142 @@
 ///
 /// [GNU]  attrib:
 ///          empty
-///          any-word
-///          any-word '(' identifier ')'
-///          any-word '(' identifier ',' nonempty-expr-list ')'
-///          any-word '(' expr-list ')'
-///
-void Parser::ParseAttributes() {
+///          attrib-name
+///          attrib-name '(' identifier ')'
+///          attrib-name '(' identifier ',' nonempty-expr-list ')'
+///          attrib-name '(' argument-expression-list [C99 6.5.2] ')'
+///
+/// [GNU]  attrib-name:
+///          identifier
+///          typespec
+///          typequal
+///          storageclass
+///          
+/// FIXME: The GCC grammar/code for this construct implies we need two
+/// token lookahead. Comment from gcc: "If they start with an identifier 
+/// which is followed by a comma or close parenthesis, then the arguments 
+/// start with that identifier; otherwise they are an expression list."
+///
+/// At the moment, I am not doing 2 token lookahead. I am also unaware of
+/// any attributes that don't work (based on my limited testing). Most
+/// attributes are very simple in practice. Until we find a bug, I don't see
+/// a pressing need to implement the 2 token lookahead.
+
+Parser::DeclTy *Parser::ParseAttributes() {
   assert(Tok.getKind() == tok::kw___attribute && "Not an attribute list!");
-  ConsumeToken();
   
-  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
-                       "attribute"))
-    return;
+  DeclTy *CurrAttr = 0;
   
-  // TODO: Parse the attributes.
-  SkipUntil(tok::r_paren, false);
+  while (Tok.getKind() == tok::kw___attribute) {
+    ConsumeToken();
+    if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+                         "attribute")) {
+      SkipUntil(tok::r_paren, true); // skip until ) or ;
+      return CurrAttr;
+    }
+    if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) {
+      SkipUntil(tok::r_paren, true); // skip until ) or ;
+      return CurrAttr;
+    }
+    // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") ))
+    while (Tok.getKind() == tok::identifier || isDeclarationSpecifier() ||
+           Tok.getKind() == tok::comma) {
+           
+      if (Tok.getKind() == tok::comma) { 
+        // allows for empty/non-empty attributes. ((__vector_size__(16),,,,))
+        ConsumeToken();
+        continue;
+      }
+      // we have an identifier or declaration specifier (const, int, etc.)
+      IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+      SourceLocation AttrNameLoc = ConsumeToken();
+      SourceLocation LParenLoc, RParenLoc;
+      
+      // check if we have a "paramterized" attribute
+      if (Tok.getKind() == tok::l_paren) {
+        LParenLoc = ConsumeParen();
+        
+        if (Tok.getKind() == tok::identifier) {
+          IdentifierInfo *ParmName = Tok.getIdentifierInfo();
+          SourceLocation ParmLoc = ConsumeToken();
+          
+          if (Tok.getKind() == tok::r_paren) { 
+            // __attribute__(( mode(byte) ))
+            RParenLoc = ConsumeParen();
+            CurrAttr = Actions.ParseAttribute(AttrName, AttrNameLoc, CurrAttr, 
+              ParmName, ParmLoc, 0, 0, LParenLoc, RParenLoc);
+          } else if (Tok.getKind() == tok::comma) {
+            ConsumeToken();
+            // __attribute__(( format(printf, 1, 2) ))
+            SmallVector<ExprTy*, 8> ArgExprs;
+            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.Val);
+              }
+              if (Tok.getKind() != tok::comma)
+                break;
+              ConsumeToken(); // Eat the comma, move to the next argument
+            }
+            if (ArgExprsOk && Tok.getKind() == tok::r_paren) {
+              RParenLoc = ConsumeParen();
+              CurrAttr = Actions.ParseAttribute(AttrName, AttrNameLoc, CurrAttr, 
+                ParmName, ParmLoc, &ArgExprs[0], ArgExprs.size(), 
+                LParenLoc, RParenLoc);
+            }
+          }
+        } else { // not an identifier
+          // parse a possibly empty comma separated list of expressions
+          if (Tok.getKind() == tok::r_paren) { 
+            // __attribute__(( nonnull() ))
+            RParenLoc = ConsumeParen();
+            CurrAttr = Actions.ParseAttribute(AttrName, AttrNameLoc, CurrAttr,
+              0, SourceLocation(), 0, 0, LParenLoc, RParenLoc);
+          } else { 
+            // __attribute__(( aligned(16) ))
+            SmallVector<ExprTy*, 8> ArgExprs;
+            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.Val);
+              }
+              if (Tok.getKind() != tok::comma)
+                break;
+              ConsumeToken(); // Eat the comma, move to the next argument
+            }
+            // Match the ')'.
+            if (ArgExprsOk && Tok.getKind() == tok::r_paren) {
+              RParenLoc = ConsumeParen();
+              CurrAttr = Actions.ParseAttribute(AttrName, AttrNameLoc, CurrAttr, 
+                0, SourceLocation(), &ArgExprs[0], ArgExprs.size(), 
+                LParenLoc, RParenLoc);
+            }
+          }
+        }
+      } else {
+        CurrAttr = Actions.ParseAttribute(AttrName, AttrNameLoc, CurrAttr);
+      }
+    }
+    SkipUntil(tok::r_paren, false);
+    SkipUntil(tok::r_paren, false);
+  }
+  return CurrAttr;
 }
 
-
 /// ParseDeclaration - Parse a full 'declaration', which consists of
 /// declaration-specifiers, some number of declarators, and a semicolon.
 /// 'Context' should be a Declarator::TheContext value.
@@ -123,9 +241,10 @@
     if (Tok.getKind() == tok::kw_asm)
       ParseSimpleAsm();
     
+    DeclTy *AttrList = 0;
     // If attributes are present, parse them.
     if (Tok.getKind() == tok::kw___attribute)
-      ParseAttributes();
+      AttrList = ParseAttributes();
     
     // Parse declarator '=' initializer.
     ExprResult Init;
@@ -400,9 +519,10 @@
 /// of DeclSpec::TST (TagType).  This returns true if there is an error parsing,
 /// otherwise it returns false and fills in Decl.
 bool Parser::ParseTag(DeclTy *&Decl, unsigned TagType, SourceLocation StartLoc){
+  DeclTy *AttrList = 0;
   // If attributes exist after tag, parse them.
   if (Tok.getKind() == tok::kw___attribute)
-    ParseAttributes();
+    AttrList = ParseAttributes();
   
   // Must have either 'struct name' or 'struct {...}'.
   if (Tok.getKind() != tok::identifier &&
@@ -547,9 +667,10 @@
         }
       }
       
+      DeclTy *AttrList = 0;
       // If attributes exist after the declarator, parse them.
       if (Tok.getKind() == tok::kw___attribute)
-        ParseAttributes();
+        AttrList = ParseAttributes();
       
       // Install the declarator into the current TagDecl.
       DeclTy *Field = Actions.ParseField(CurScope, TagDecl, SpecQualLoc,
@@ -569,7 +690,7 @@
       
       // Attributes are only allowed on the second declarator.
       if (Tok.getKind() == tok::kw___attribute)
-        ParseAttributes();
+        AttrList = ParseAttributes();
     }
     
     if (Tok.getKind() == tok::semi) {
@@ -585,9 +706,10 @@
   
   Actions.ParseRecordBody(RecordLoc, TagDecl, &FieldDecls[0],FieldDecls.size());
   
+  DeclTy *AttrList = 0;
   // If attributes exist after struct contents, parse them.
   if (Tok.getKind() == tok::kw___attribute)
-    ParseAttributes();
+    AttrList = ParseAttributes(); // FIXME: where should I put them?
 }
 
 
@@ -671,9 +793,10 @@
   Actions.ParseEnumBody(StartLoc, EnumDecl, &EnumConstantDecls[0],
                         EnumConstantDecls.size());
   
+  DeclTy *AttrList = 0;
   // If attributes exist after the identifier list, parse them.
   if (Tok.getKind() == tok::kw___attribute)
-    ParseAttributes();
+    AttrList = ParseAttributes(); // FIXME: where do they do?
 }
 
 /// isTypeSpecifierQualifier - Return true if the current token could be the
@@ -981,8 +1104,9 @@
     // direct-declarator: '(' declarator ')'
     // direct-declarator: '(' attributes declarator ')'
     if (isGrouping) {
+      DeclTy *AttrList = 0;
       if (Tok.getKind() == tok::kw___attribute)
-        ParseAttributes();
+        AttrList = ParseAttributes();
       
       ParseDeclaratorInternal(D);
       // Match the ')'.
@@ -1097,8 +1221,9 @@
       ParseDeclarator(ParmDecl);
 
       // Parse GNU attributes, if present.
+      DeclTy *AttrList = 0;
       if (Tok.getKind() == tok::kw___attribute)
-        ParseAttributes();
+        AttrList = ParseAttributes();
       
       // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
       // NOTE: we could trivially allow 'int foo(auto int X)' if we wanted.

Modified: cfe/cfe/trunk/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/ParseStmt.cpp?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/Parse/ParseStmt.cpp (original)
+++ cfe/cfe/trunk/Parse/ParseStmt.cpp Wed Jul 11 11:45:23 2007
@@ -185,9 +185,10 @@
     SourceLocation ColonLoc = ConsumeToken();
 
     // Read label attributes, if present.
+    DeclTy *AttrList = 0;
     if (Tok.getKind() == tok::kw___attribute)
       // TODO: save these somewhere.
-      ParseAttributes();
+      AttrList = ParseAttributes();
 
     StmtResult SubStmt = ParseStatement();
     

Modified: cfe/cfe/trunk/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/Parser.cpp?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/Parse/Parser.cpp (original)
+++ cfe/cfe/trunk/Parse/Parser.cpp Wed Jul 11 11:45:23 2007
@@ -508,10 +508,11 @@
 
     // Handle the full declarator list.
     while (1) {
+      DeclTy *AttrList;
       // If attributes are present, parse them.
       if (Tok.getKind() == tok::kw___attribute)
         // FIXME: attach attributes too.
-        ParseAttributes();
+        AttrList = ParseAttributes();
       
       // Ask the actions module to compute the type for this declarator.
       Action::TypeResult TR =

Modified: cfe/cfe/trunk/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/Sema.h?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/Sema/Sema.h (original)
+++ cfe/cfe/trunk/Sema/Sema.h Wed Jul 11 11:45:23 2007
@@ -248,6 +248,16 @@
   /// ParseCXXBoolLiteral - Parse {true,false} literals.
   virtual ExprResult ParseCXXBoolLiteral(SourceLocation OpLoc,
                                          tok::TokenKind Kind);
+                                         
+  /// ParseAttribute GCC __attribute__
+  virtual DeclTy *ParseAttribute(
+    IdentifierInfo *AttrName, SourceLocation AttrNameLoc, DeclTy *PrevAttr,
+    IdentifierInfo *ParmName = 0, SourceLocation ParmNameLoc = SourceLocation(),
+    ExprTy **Args = 0, unsigned NumArgs = 0, 
+    SourceLocation LParenLoc = SourceLocation(),
+    SourceLocation RParenLoc = SourceLocation()
+  );
+    
 private:
   QualType UsualUnaryConversion(QualType t); // C99 6.3
   QualType UsualArithmeticConversions(QualType t1, QualType t2); // C99 6.3.1.8

Modified: cfe/cfe/trunk/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaDecl.cpp?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/Sema/SemaDecl.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaDecl.cpp Wed Jul 11 11:45:23 2007
@@ -846,3 +846,17 @@
     LastInGroupList.push_back((Decl*)last);
   }
 }
+
+/// ParseAttribute GCC __attribute__
+Sema::DeclTy *Sema::ParseAttribute(
+    IdentifierInfo *AttrName, SourceLocation AttrNameLoc, DeclTy *PrevAttr,
+    IdentifierInfo *ParmName, SourceLocation ParmNameLoc,
+    ExprTy **Args, unsigned NumArgs, 
+    SourceLocation LParenLoc, SourceLocation RParenLoc) {
+  AttributeDecl *attrib = new AttributeDecl(AttrNameLoc, AttrName, ParmName, 
+                                            (Expr **)Args, NumArgs);
+  if (PrevAttr)
+    // reuse Decl's "Next" pointer for chaining the attribute list
+    attrib->setNext(static_cast<Decl *>(PrevAttr));
+  return attrib;
+}

Modified: cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/clang.xcodeproj/project.pbxproj?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jul 11 11:45:23 2007
@@ -103,6 +103,23 @@
 		DED7D9E50A5257F6003AD0FB /* ScratchBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DED7D9E40A5257F6003AD0FB /* ScratchBuffer.cpp */; };
 /* End PBXBuildFile section */
 
+/* Begin PBXBuildStyle section */
+		8424C61B0C0E1747008BC1FE /* Development */ = {
+			isa = PBXBuildStyle;
+			buildSettings = {
+				COPY_PHASE_STRIP = NO;
+			};
+			name = Development;
+		};
+		8424C61C0C0E1747008BC1FE /* Deployment */ = {
+			isa = PBXBuildStyle;
+			buildSettings = {
+				COPY_PHASE_STRIP = YES;
+			};
+			name = Deployment;
+		};
+/* End PBXBuildStyle section */
+
 /* Begin PBXCopyFilesBuildPhase section */
 		8DD76F690486A84900D96B5E /* CopyFiles */ = {
 			isa = PBXCopyFilesBuildPhase;
@@ -538,6 +555,12 @@
 		08FB7793FE84155DC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
+			buildSettings = {
+			};
+			buildStyles = (
+				8424C61B0C0E1747008BC1FE /* Development */,
+				8424C61C0C0E1747008BC1FE /* Deployment */,
+			);
 			hasScannedForEncodings = 1;
 			mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
 			projectDirPath = "";

Modified: cfe/cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Decl.h?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Decl.h Wed Jul 11 11:45:23 2007
@@ -36,7 +36,7 @@
     // Concrete sub-classes of TypeDecl
     Typedef, Struct, Union, Class, Enum, 
     // Concrete sub-class of Decl
-    Field
+    Field, Attribute
   };
 
   /// IdentifierNamespace - According to C99 6.2.3, there are four namespaces,
@@ -405,6 +405,43 @@
   static bool classof(const RecordDecl *D) { return true; }
 };
 
+/// AttributeDecl - Represents GCC's __attribute__ declaration. There are
+/// 4 forms of this construct...they are:
+///
+/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused.
+/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused.
+/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used.
+/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used.
+///
+class AttributeDecl : public Decl {
+  IdentifierInfo *ParmName;
+  Expr **Args;
+  unsigned NumArgs;
+public:
+  AttributeDecl(SourceLocation L, IdentifierInfo *AttrName, 
+                IdentifierInfo *ParmName, Expr **args, unsigned numargs);
+  ~AttributeDecl() {
+    delete [] Args;
+  }
+  
+  IdentifierInfo *getAttributeName() const { return getIdentifier(); }
+  IdentifierInfo *getParameterName() const { return ParmName; }
+  
+  /// getNumArgs - Return the number of actual arguments to this attribute.
+  unsigned getNumArgs() const { return NumArgs; }
+  
+  /// getArg - Return the specified argument.
+  Expr *getArg(unsigned Arg) const {
+    assert(Arg < NumArgs && "Arg access out of range!");
+    return Args[Arg];
+  }
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) {
+    return D->getKind() == Attribute;
+  }
+  static bool classof(const AttributeDecl *D) { return true; }
+};
+
 }  // end namespace clang
 }  // end namespace llvm
 

Modified: cfe/cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/Action.h?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/Action.h Wed Jul 11 11:45:23 2007
@@ -357,6 +357,16 @@
                                          tok::TokenKind Kind) {
     return 0;
   }
+  /// ParseAttribute
+  virtual DeclTy *ParseAttribute(
+    IdentifierInfo *AttrName, SourceLocation AttrNameLoc, DeclTy *PrevAttr,
+    IdentifierInfo *ParmName = 0, SourceLocation ParmNameLoc = SourceLocation(),
+    ExprTy **Args = 0, unsigned NumArgs = 0,
+    SourceLocation LParenLoc = SourceLocation(),
+    SourceLocation RParenLoc = SourceLocation()) {
+    return 0;
+  }
+  
 };
 
 /// MinimalAction - Minimal actions are used by light-weight clients of the

Modified: cfe/cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/Parser.h?rev=39539&r1=39538&r2=39539&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/Parser.h Wed Jul 11 11:45:23 2007
@@ -355,7 +355,7 @@
   bool isTypeSpecifierQualifier() const;
 
   TypeTy *ParseTypeName();
-  void ParseAttributes();
+  DeclTy *ParseAttributes();
   
   /// ParseDeclarator - Parse and verify a newly-initialized declarator.
   void ParseDeclarator(Declarator &D);





More information about the cfe-commits mailing list