diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/AST/Decl.cpp | 10 | ||||
-rw-r--r-- | clang/Parse/ParseDecl.cpp | 165 | ||||
-rw-r--r-- | clang/Parse/ParseStmt.cpp | 3 | ||||
-rw-r--r-- | clang/Parse/Parser.cpp | 3 | ||||
-rw-r--r-- | clang/Sema/Sema.h | 10 | ||||
-rw-r--r-- | clang/Sema/SemaDecl.cpp | 14 | ||||
-rw-r--r-- | clang/clang.xcodeproj/project.pbxproj | 23 | ||||
-rw-r--r-- | clang/include/clang/AST/Decl.h | 39 | ||||
-rw-r--r-- | clang/include/clang/Parse/Action.h | 10 | ||||
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 2 |
10 files changed, 255 insertions, 24 deletions
diff --git a/clang/AST/Decl.cpp b/clang/AST/Decl.cpp index 7a8030ab0fb..967d4eab1c0 100644 --- a/clang/AST/Decl.cpp +++ b/clang/AST/Decl.cpp @@ -102,6 +102,9 @@ void Decl::addDeclKind(const Kind k) { case Enum: nEnumDecls++; break; + case Attribute: + // FIXME + break; } } @@ -176,3 +179,10 @@ FieldDecl* RecordDecl::getMember(IdentifierInfo *name) { 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]; +} diff --git a/clang/Parse/ParseDecl.cpp b/clang/Parse/ParseDecl.cpp index 18911eaf1a9..850fd73b638 100644 --- a/clang/Parse/ParseDecl.cpp +++ b/clang/Parse/ParseDecl.cpp @@ -51,24 +51,142 @@ Parser::TypeTy *Parser::ParseTypeName() { /// /// [GNU] attrib: /// empty -/// any-word -/// any-word '(' identifier ')' -/// any-word '(' identifier ',' nonempty-expr-list ')' -/// any-word '(' expr-list ')' +/// attrib-name +/// attrib-name '(' identifier ')' +/// attrib-name '(' identifier ',' nonempty-expr-list ')' +/// attrib-name '(' argument-expression-list [C99 6.5.2] ')' /// -void Parser::ParseAttributes() { +/// [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 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) { 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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { /// 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 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } } + 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 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // 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 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, 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 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) { 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 @@ void Parser::ParseParenDeclarator(Declarator &D) { // 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 @@ void Parser::ParseParenDeclarator(Declarator &D) { 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. diff --git a/clang/Parse/ParseStmt.cpp b/clang/Parse/ParseStmt.cpp index 0651626cfe0..359632a4c30 100644 --- a/clang/Parse/ParseStmt.cpp +++ b/clang/Parse/ParseStmt.cpp @@ -185,9 +185,10 @@ Parser::StmtResult Parser::ParseIdentifierStatement(bool OnlyStatement) { 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(); diff --git a/clang/Parse/Parser.cpp b/clang/Parse/Parser.cpp index e63b698819d..6ffbb51da27 100644 --- a/clang/Parse/Parser.cpp +++ b/clang/Parse/Parser.cpp @@ -508,10 +508,11 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { // 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 = diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index 6b291d01757..55924bd9eb6 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -248,6 +248,16 @@ public: /// 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 diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index 93e97be0b1b..7c20329d44a 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -846,3 +846,17 @@ void Sema::AddTopLevelDecl(Decl *current, Decl *last) { 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; +} diff --git a/clang/clang.xcodeproj/project.pbxproj b/clang/clang.xcodeproj/project.pbxproj index 5a9178c2aec..0c6faa7de6c 100644 --- a/clang/clang.xcodeproj/project.pbxproj +++ b/clang/clang.xcodeproj/project.pbxproj @@ -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 = ""; diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index b4fbf1fad1d..e5f03476fd0 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -36,7 +36,7 @@ public: // 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 @@ public: 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 diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 740235975d8..ea61a81b21b 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -357,6 +357,16 @@ public: 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 diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index f4f0bb51079..385033b0a80 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -355,7 +355,7 @@ private: bool isTypeSpecifierQualifier() const; TypeTy *ParseTypeName(); - void ParseAttributes(); + DeclTy *ParseAttributes(); /// ParseDeclarator - Parse and verify a newly-initialized declarator. void ParseDeclarator(Declarator &D); |