summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/AST/Decl.cpp10
-rw-r--r--clang/Parse/ParseDecl.cpp165
-rw-r--r--clang/Parse/ParseStmt.cpp3
-rw-r--r--clang/Parse/Parser.cpp3
-rw-r--r--clang/Sema/Sema.h10
-rw-r--r--clang/Sema/SemaDecl.cpp14
-rw-r--r--clang/clang.xcodeproj/project.pbxproj23
-rw-r--r--clang/include/clang/AST/Decl.h39
-rw-r--r--clang/include/clang/Parse/Action.h10
-rw-r--r--clang/include/clang/Parse/Parser.h2
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);
OpenPOWER on IntegriCloud