[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