diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-04-14 00:33:13 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-04-14 00:33:13 +0000 |
commit | 534986f2b21e6050bf00163cd6423fd92155a6ed (patch) | |
tree | a8e8a492336134952e331deec690f010f5c7b71f /lib | |
parent | 9cdd1e3450a07c1bafc32c96f1db88084497f282 (diff) |
Add an AttributedStmt type to represent a statement with C++11 attributes
attached. Since we do not support any attributes which appertain to a statement
(yet), testing of this is necessarily quite minimal.
Patch by Alexander Kornienko!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154723 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Stmt.cpp | 6 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 17 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 5 | ||||
-rw-r--r-- | lib/Analysis/CFG.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 1 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 181 | ||||
-rw-r--r-- | lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaStmtAttr.cpp | 48 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 29 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 15 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 1 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 8 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 |
17 files changed, 235 insertions, 108 deletions
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 6af20df4be..e4d9f0a1ef 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -97,8 +97,8 @@ Stmt *Stmt::IgnoreImplicit() { /// \brief Strip off all label-like statements. /// -/// This will strip off label statements, case statements, and default -/// statements recursively. +/// This will strip off label statements, case statements, attributed +/// statements and default statements recursively. const Stmt *Stmt::stripLabelLikeStatements() const { const Stmt *S = this; while (true) { @@ -106,6 +106,8 @@ const Stmt *Stmt::stripLabelLikeStatements() const { S = LS->getSubStmt(); else if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) S = SC->getSubStmt(); + else if (const AttributedStmt *AS = dyn_cast<AttributedStmt>(S)) + S = AS->getSubStmt(); else return S; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 3a44183e20..0d1066b7e3 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -169,6 +169,23 @@ void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { PrintStmt(Node->getSubStmt(), 0); } +void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { + OS << "[["; + bool first = true; + for (AttrVec::const_iterator it = Node->getAttrs().begin(), + end = Node->getAttrs().end(); + it != end; ++it) { + if (!first) { + OS << ", "; + first = false; + } + // TODO: check this + (*it)->printPretty(OS, Context); + } + OS << "]] "; + PrintStmt(Node->getSubStmt(), 0); +} + void StmtPrinter::PrintRawIfStmt(IfStmt *If) { OS << "if ("; PrintExpr(If->getCond()); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index e5526cea74..4bdded1d60 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -109,6 +109,11 @@ void StmtProfiler::VisitLabelStmt(const LabelStmt *S) { VisitDecl(S->getDecl()); } +void StmtProfiler::VisitAttributedStmt(const AttributedStmt *S) { + VisitStmt(S); + // TODO: maybe visit attributes? +} + void StmtProfiler::VisitIfStmt(const IfStmt *S) { VisitStmt(S); VisitDecl(S->getConditionVariable()); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index d1334a5431..f4d9a354a5 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -18,6 +18,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/CharUnits.h" +#include "clang/Basic/AttrKinds.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Format.h" @@ -1069,6 +1070,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { case Stmt::LambdaExprClass: return VisitLambdaExpr(cast<LambdaExpr>(S), asc); + case Stmt::AttributedStmtClass: + return Visit(cast<AttributedStmt>(S)->getSubStmt(), asc); + case Stmt::MemberExprClass: return VisitMemberExpr(cast<MemberExpr>(S), asc); @@ -1131,7 +1135,7 @@ CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) { /// VisitChildren - Visit the children of a Stmt. CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) { - CFGBlock *lastBlock = Block; + CFGBlock *lastBlock = Block; for (Stmt::child_range I = Terminator->children(); I; ++I) if (Stmt *child = *I) if (CFGBlock *b = Visit(child)) diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index bf42dcb8e2..a1d0789573 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -79,6 +79,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::CompoundStmtClass: case Stmt::DeclStmtClass: case Stmt::LabelStmtClass: + case Stmt::AttributedStmtClass: case Stmt::GotoStmtClass: case Stmt::BreakStmtClass: case Stmt::ContinueStmtClass: @@ -173,6 +174,8 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) { case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break; case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*S)); break; case Stmt::LabelStmtClass: EmitLabelStmt(cast<LabelStmt>(*S)); break; + case Stmt::AttributedStmtClass: + EmitAttributedStmt(cast<AttributedStmt>(*S)); break; case Stmt::GotoStmtClass: EmitGotoStmt(cast<GotoStmt>(*S)); break; case Stmt::BreakStmtClass: EmitBreakStmt(cast<BreakStmt>(*S)); break; case Stmt::ContinueStmtClass: EmitContinueStmt(cast<ContinueStmt>(*S)); break; @@ -332,6 +335,10 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { EmitStmt(S.getSubStmt()); } +void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) { + EmitStmt(S.getSubStmt()); +} + void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { // If this code is reachable then emit a stop point (if generating // debug info). We have to do this ourselves because we are on the diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f57dd5f587..0f3f8f962c 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1948,6 +1948,7 @@ public: void EmitLabel(const LabelDecl *D); // helper for EmitLabelStmt. void EmitLabelStmt(const LabelStmt &S); + void EmitAttributedStmt(const AttributedStmt &S); void EmitGotoStmt(const GotoStmt &S); void EmitIndirectGotoStmt(const IndirectGotoStmt &S); void EmitIfStmt(const IfStmt &S); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index cf3dca20d9..be84cdc55a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -958,7 +958,7 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { /// [C++] namespace-definition /// [C++] using-directive /// [C++] using-declaration -/// [C++0x/C11] static_assert-declaration +/// [C++11/C11] static_assert-declaration /// others... [FIXME] /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 7f3a815edc..6d31396cc0 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1926,11 +1926,9 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // unless they've already reported an error. if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); - Actions.ActOnStartStmtExpr(); - ParsedAttributes attrs(AttrFactory); - StmtResult Stmt(ParseCompoundStatement(attrs, true)); + StmtResult Stmt(ParseCompoundStatement(true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index fdb9788667..44320dfcb3 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -78,13 +78,30 @@ using namespace clang; StmtResult Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, SourceLocation *TrailingElseLoc) { - const char *SemiError = 0; - StmtResult Res; ParenBraceBracketBalancer BalancerRAIIObj(*this); - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true); + ParsedAttributesWithRange Attrs(AttrFactory); + MaybeParseCXX0XAttributes(Attrs, 0, /*MightBeObjCMessageSend*/ true); + + StmtResult Res = ParseStatementOrDeclarationAfterAttributes(Stmts, + OnlyStatement, TrailingElseLoc, Attrs); + + assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) && + "attributes on empty statement"); + + if (Attrs.empty() || Res.isInvalid()) + return Res; + + return Actions.ProcessStmtAttributes(Res.get(), Attrs.getList(), Attrs.Range); +} + +StmtResult +Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts, + bool OnlyStatement, SourceLocation *TrailingElseLoc, + ParsedAttributesWithRange &Attrs) { + const char *SemiError = 0; + StmtResult Res; // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), @@ -95,6 +112,7 @@ Retry: switch (Kind) { case tok::at: // May be a @try or @throw statement { + ProhibitAttributes(Attrs); // TODO: is it correct? AtLoc = ConsumeToken(); // consume @ return ParseObjCAtStatement(AtLoc); } @@ -108,7 +126,7 @@ Retry: Token Next = NextToken(); if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement - return ParseLabeledStatement(attrs); + return ParseLabeledStatement(Attrs); } if (Next.isNot(tok::coloncolon)) { @@ -210,7 +228,7 @@ Retry: if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext, - DeclEnd, attrs); + DeclEnd, Attrs); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); } @@ -219,54 +237,54 @@ Retry: return StmtError(); } - return ParseExprStatement(attrs); + return ParseExprStatement(); } case tok::kw_case: // C99 6.8.1: labeled-statement - return ParseCaseStatement(attrs); + return ParseCaseStatement(); case tok::kw_default: // C99 6.8.1: labeled-statement - return ParseDefaultStatement(attrs); + return ParseDefaultStatement(); case tok::l_brace: // C99 6.8.2: compound-statement - return ParseCompoundStatement(attrs); + return ParseCompoundStatement(); case tok::semi: { // C99 6.8.3p3: expression[opt] ';' bool HasLeadingEmptyMacro = Tok.hasLeadingEmptyMacro(); return Actions.ActOnNullStmt(ConsumeToken(), HasLeadingEmptyMacro); } case tok::kw_if: // C99 6.8.4.1: if-statement - return ParseIfStatement(attrs, TrailingElseLoc); + return ParseIfStatement(TrailingElseLoc); case tok::kw_switch: // C99 6.8.4.2: switch-statement - return ParseSwitchStatement(attrs, TrailingElseLoc); + return ParseSwitchStatement(TrailingElseLoc); case tok::kw_while: // C99 6.8.5.1: while-statement - return ParseWhileStatement(attrs, TrailingElseLoc); + return ParseWhileStatement(TrailingElseLoc); case tok::kw_do: // C99 6.8.5.2: do-statement - Res = ParseDoStatement(attrs); + Res = ParseDoStatement(); SemiError = "do/while"; break; case tok::kw_for: // C99 6.8.5.3: for-statement - return ParseForStatement(attrs, TrailingElseLoc); + return ParseForStatement(TrailingElseLoc); case tok::kw_goto: // C99 6.8.6.1: goto-statement - Res = ParseGotoStatement(attrs); + Res = ParseGotoStatement(); SemiError = "goto"; break; case tok::kw_continue: // C99 6.8.6.2: continue-statement - Res = ParseContinueStatement(attrs); + Res = ParseContinueStatement(); SemiError = "continue"; break; case tok::kw_break: // C99 6.8.6.3: break-statement - Res = ParseBreakStatement(attrs); + Res = ParseBreakStatement(); SemiError = "break"; break; case tok::kw_return: // C99 6.8.6.4: return-statement - Res = ParseReturnStatement(attrs); + Res = ParseReturnStatement(); SemiError = "return"; break; case tok::kw_asm: { - ProhibitAttributes(attrs); + ProhibitAttributes(Attrs); bool msAsm = false; Res = ParseAsmStatement(msAsm); Res = Actions.ActOnFinishFullStmt(Res.get()); @@ -276,16 +294,19 @@ Retry: } case tok::kw_try: // C++ 15: try-block - return ParseCXXTryBlock(attrs); + return ParseCXXTryBlock(); case tok::kw___try: - return ParseSEHTryBlock(attrs); + ProhibitAttributes(Attrs); // TODO: is it correct? + return ParseSEHTryBlock(); case tok::annot_pragma_vis: + ProhibitAttributes(Attrs); HandlePragmaVisibility(); return StmtEmpty(); case tok::annot_pragma_pack: + ProhibitAttributes(Attrs); HandlePragmaPack(); return StmtEmpty(); } @@ -306,11 +327,10 @@ Retry: } /// \brief Parse an expression statement. -StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { +StmtResult Parser::ParseExprStatement() { // If a case keyword is missing, this is where it should be inserted. Token OldToken = Tok; - // FIXME: Use the attributes // expression[opt] ';' ExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { @@ -331,7 +351,7 @@ StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { << FixItHint::CreateInsertion(OldToken.getLocation(), "case "); // Recover parsing as a case statement. - return ParseCaseStatement(Attrs, /*MissingCase=*/true, Expr); + return ParseCaseStatement(/*MissingCase=*/true, Expr); } // Otherwise, eat the semicolon. @@ -339,7 +359,7 @@ StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); } -StmtResult Parser::ParseSEHTryBlock(ParsedAttributes & Attrs) { +StmtResult Parser::ParseSEHTryBlock() { assert(Tok.is(tok::kw___try) && "Expected '__try'"); SourceLocation Loc = ConsumeToken(); return ParseSEHTryBlockCommon(Loc); @@ -358,13 +378,12 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { if(Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok,diag::err_expected_lbrace)); - ParsedAttributesWithRange attrs(AttrFactory); - StmtResult TryBlock(ParseCompoundStatement(attrs)); + StmtResult TryBlock(ParseCompoundStatement()); if(TryBlock.isInvalid()) return move(TryBlock); StmtResult Handler; - if (Tok.is(tok::identifier) && + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == getSEHExceptKeyword()) { SourceLocation Loc = ConsumeToken(); Handler = ParseSEHExceptBlock(Loc); @@ -418,8 +437,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen)) return StmtError(); - ParsedAttributesWithRange attrs(AttrFactory); - StmtResult Block(ParseCompoundStatement(attrs)); + StmtResult Block(ParseCompoundStatement()); if(Block.isInvalid()) return move(Block); @@ -437,8 +455,7 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) { raii2(Ident___abnormal_termination, false), raii3(Ident_AbnormalTermination, false); - ParsedAttributesWithRange attrs(AttrFactory); - StmtResult Block(ParseCompoundStatement(attrs)); + StmtResult Block(ParseCompoundStatement()); if(Block.isInvalid()) return move(Block); @@ -451,7 +468,7 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) { /// identifier ':' statement /// [GNU] identifier ':' attributes[opt] statement /// -StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { +StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); @@ -463,7 +480,8 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { // identifier ':' statement SourceLocation ColonLoc = ConsumeToken(); - // Read label attributes, if present. + // Read label attributes, if present. attrs will contain both C++11 and GNU + // attributes (if present) after this point. MaybeParseGNUAttributes(attrs); StmtResult SubStmt(ParseStatement()); @@ -474,8 +492,10 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(), IdentTok.getLocation()); - if (AttributeList *Attrs = attrs.getList()) + if (AttributeList *Attrs = attrs.getList()) { Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs); + attrs.clear(); + } return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc, SubStmt.get()); @@ -486,10 +506,8 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, - ExprResult Expr) { +StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!"); - // FIXME: Use attributes? // It is very very common for code to contain many case statements recursively // nested, as in (but usually without indentation): @@ -625,9 +643,7 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// -StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) { - //FIXME: Use attributes? - +StmtResult Parser::ParseDefaultStatement() { assert(Tok.is(tok::kw_default) && "Not a default stmt!"); SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'. @@ -668,9 +684,8 @@ StmtResult Parser::ParseDefaultStatement(ParsedAttributes &attrs) { SubStmt.get(), getCurScope()); } -StmtResult Parser::ParseCompoundStatement(ParsedAttributes &Attr, - bool isStmtExpr) { - return ParseCompoundStatement(Attr, isStmtExpr, Scope::DeclScope); +StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) { + return ParseCompoundStatement(isStmtExpr, Scope::DeclScope); } /// ParseCompoundStatement - Parse a "{}" block. @@ -700,11 +715,8 @@ StmtResult Parser::ParseCompoundStatement(ParsedAttributes &Attr, /// [OMP] barrier-directive /// [OMP] flush-directive /// -StmtResult Parser::ParseCompoundStatement(ParsedAttributes &attrs, - bool isStmtExpr, +StmtResult Parser::ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags) { - //FIXME: Use attributes? - assert(Tok.is(tok::l_brace) && "Not a compount stmt!"); // Enter a scope to hold everything within the compound stmt. Compound @@ -894,10 +906,7 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// -StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs, - SourceLocation *TrailingElseLoc) { - // FIXME: Use attributes? - +StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. @@ -1028,10 +1037,7 @@ StmtResult Parser::ParseIfStatement(ParsedAttributes &attrs, /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement -StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs, - SourceLocation *TrailingElseLoc) { - // FIXME: Use attributes? - +StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_switch) && "Not a switch stmt!"); SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'. @@ -1119,10 +1125,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs, /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement -StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs, - SourceLocation *TrailingElseLoc) { - // FIXME: Use attributes? - +StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_while) && "Not a while stmt!"); SourceLocation WhileLoc = Tok.getLocation(); ConsumeToken(); // eat the 'while'. @@ -1194,9 +1197,7 @@ StmtResult Parser::ParseWhileStatement(ParsedAttributes &attrs, /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// Note: this lets the caller parse the end ';'. -StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseDoStatement() { assert(Tok.is(tok::kw_do) && "Not a do stmt!"); SourceLocation DoLoc = ConsumeToken(); // eat the 'do'. @@ -1277,10 +1278,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { /// [C++0x] for-range-initializer: /// [C++0x] expression /// [C++0x] braced-init-list [TODO] -StmtResult Parser::ParseForStatement(ParsedAttributes &attrs, - SourceLocation *TrailingElseLoc) { - // FIXME: Use attributes? - +StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_for) && "Not a for stmt!"); SourceLocation ForLoc = ConsumeToken(); // eat the 'for'. @@ -1535,9 +1533,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs, /// /// Note: this lets the caller parse the end ';'. /// -StmtResult Parser::ParseGotoStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseGotoStatement() { assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. @@ -1571,9 +1567,7 @@ StmtResult Parser::ParseGotoStatement(ParsedAttributes &attrs) { /// /// Note: this lets the caller parse the end ';'. /// -StmtResult Parser::ParseContinueStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseContinueStatement() { SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'. return Actions.ActOnContinueStmt(ContinueLoc, getCurScope()); } @@ -1584,9 +1578,7 @@ StmtResult Parser::ParseContinueStatement(ParsedAttributes &attrs) { /// /// Note: this lets the caller parse the end ';'. /// -StmtResult Parser::ParseBreakStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseBreakStatement() { SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'. return Actions.ActOnBreakStmt(BreakLoc, getCurScope()); } @@ -1594,9 +1586,7 @@ StmtResult Parser::ParseBreakStatement(ParsedAttributes &attrs) { /// ParseReturnStatement /// jump-statement: /// 'return' expression[opt] ';' -StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) { - // FIXME: Use attributes? - +StmtResult Parser::ParseReturnStatement() { assert(Tok.is(tok::kw_return) && "Not a return stmt!"); SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. @@ -2043,9 +2033,7 @@ bool Parser::trySkippingFunctionBody() { /// try-block: /// 'try' compound-statement handler-seq /// -StmtResult Parser::ParseCXXTryBlock(ParsedAttributes &attrs) { - // FIXME: Add attributes? - +StmtResult Parser::ParseCXXTryBlock() { assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); @@ -2072,17 +2060,17 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - ParsedAttributesWithRange attrs(AttrFactory); - StmtResult TryBlock(ParseCompoundStatement(attrs, /*isStmtExpr=*/false, + + StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, Scope::DeclScope|Scope::TryScope)); if (TryBlock.isInvalid()) return move(TryBlock); // Borland allows SEH-handlers with 'try' - if((Tok.is(tok::identifier) && - Tok.getIdentifierInfo() == getSEHExceptKeyword()) || - Tok.is(tok::kw___finally)) { + if ((Tok.is(tok::identifier) && + Tok.getIdentifierInfo() == getSEHExceptKeyword()) || + Tok.is(tok::kw___finally)) { // TODO: Factor into common return ParseSEHHandlerCommon(...) StmtResult Handler; if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) { @@ -2103,6 +2091,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { } else { StmtVector Handlers(Actions); + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); ProhibitAttributes(attrs); @@ -2168,8 +2157,7 @@ StmtResult Parser::ParseCXXCatchBlock() { return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - ParsedAttributes attrs(AttrFactory); - StmtResult Block(ParseCompoundStatement(attrs)); + StmtResult Block(ParseCompoundStatement()); if (Block.isInvalid()) return move(Block); @@ -2188,24 +2176,23 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { if (Result.Behavior == IEB_Dependent) { if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected_lbrace); - return; + return; } - - ParsedAttributes Attrs(AttrFactory); - StmtResult Compound = ParseCompoundStatement(Attrs); + + StmtResult Compound = ParseCompoundStatement(); if (Compound.isInvalid()) return; - + StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc, Result.IsIfExists, - Result.SS, + Result.SS, Result.Name, Compound.get()); if (DepResult.isUsable()) Stmts.push_back(DepResult.get()); return; } - + BalancedDelimiterTracker Braces(*this, tok::l_brace); if (Braces.consumeOpen()) { Diag(Tok, diag::err_expected_lbrace); diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 5d297f9831..07734c7c7b 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -40,6 +40,7 @@ add_clang_library(clangSema SemaOverload.cpp SemaPseudoObject.cpp SemaStmt.cpp + SemaStmtAttr.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp SemaTemplateInstantiate.cpp diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 97c8eb04e9..9052278d73 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -345,7 +345,6 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, StmtResult Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt) { - // If the label was multiply defined, reject it now. if (TheDecl->getStmt()) { Diag(IdentLoc, diag::err_redefinition_of_label) << TheDecl->getDeclName(); @@ -361,6 +360,16 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, return Owned(LS); } +StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc, + const AttrVec &Attrs, + Stmt *SubStmt) { + // Fill in the declaration and return it. Variable length will require to + // change this to AttributedStmt::Create(Context, ....); + // and probably using ArrayRef + AttributedStmt *LS = new (Context) AttributedStmt(AttrLoc, Attrs, SubStmt); + return Owned(LS); +} + StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, Stmt *thenStmt, SourceLocation ElseLoc, diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp new file mode 100644 index 0000000000..21c329758e --- /dev/null +++ b/lib/Sema/SemaStmtAttr.cpp @@ -0,0 +1,48 @@ +//===--- SemaStmtAttr.cpp - Statement Attribute Handling ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements stmt-related attribute processing. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaInternal.h" +#include "TargetAttributesSema.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Lookup.h" +#include "llvm/ADT/StringExtras.h" +using namespace clang; +using namespace sema; + + +static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A) { + switch (A.getKind()) { + default: + // if we're here, then we parsed an attribute, but didn't recognize it as a + // statement attribute => it is declaration attribute + S.Diag(A.getRange().getBegin(), diag::warn_attribute_invalid_on_stmt) << + A.getName()->getName(); + return 0; + } +} + +StmtResult Sema::ProcessStmtAttributes(Stmt *S, AttributeList *AttrList, + SourceRange Range) { + AttrVec Attrs; + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + if (Attr *a = ProcessStmtAttribute(*this, S, *l)) + Attrs.push_back(a); + } + + if (Attrs.empty()) + return S; + + return ActOnAttributedStmt(Range.getBegin(), Attrs, S); +} diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index fdb861eea5..acfea6e3e4 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1044,6 +1044,15 @@ public: return SemaRef.ActOnLabelStmt(IdentLoc, L, ColonLoc, SubStmt); } + /// \brief Build a new label statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult RebuildAttributedStmt(SourceLocation AttrLoc, const AttrVec &Attrs, + Stmt *SubStmt) { + return SemaRef.ActOnAttributedStmt(AttrLoc, Attrs, SubStmt); + } + /// \brief Build a new "if" statement. /// /// By default, performs semantic analysis to build the new statement. @@ -5154,8 +5163,8 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { S->getDecl()); if (!LD) return StmtError(); - - + + // FIXME: Pass the real colon location in. return getDerived().RebuildLabelStmt(S->getIdentLoc(), cast<LabelDecl>(LD), SourceLocation(), @@ -5164,6 +5173,22 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { template<typename Derived> StmtResult +TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) { + StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + if (SubStmt.isInvalid()) + return StmtError(); + + // TODO: transform attributes + if (SubStmt.get() == S->getSubStmt() /* && attrs are the same */) + return S; + + return getDerived().RebuildAttributedStmt(S->getAttrLoc(), + S->getAttrs(), + SubStmt.get()); +} + +template<typename Derived> +StmtResult TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { // Transform the condition ExprResult Cond; diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 2eeb090af0..007ecee9f5 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -159,9 +159,18 @@ void ASTStmtReader::VisitLabelStmt(LabelStmt *S) { S->setIdentLoc(ReadSourceLocation(Record, Idx)); } +void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) { + VisitStmt(S); + AttrVec Attrs; + Reader.ReadAttributes(F, Attrs, Record, Idx); + S->Attrs = Attrs; + S->SubStmt = Reader.ReadSubStmt(); + S->AttrLoc = ReadSourceLocation(Record, Idx); +} + void ASTStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); - S->setConditionVariable(Reader.getContext(), + S->setConditionVariable(Reader.getContext(), ReadDeclAs<VarDecl>(Record, Idx)); S->setCond(Reader.ReadSubExpr()); S->setThen(Reader.ReadSubStmt()); @@ -1630,6 +1639,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) LabelStmt(Empty); break; + case STMT_ATTRIBUTED: + S = new (Context) AttributedStmt(Empty); + break; + case STMT_IF: S = new (Context) IfStmt(Empty); break; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index a4301b53e8..81c0a9dd48 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -651,6 +651,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream, RECORD(STMT_CASE); RECORD(STMT_DEFAULT); RECORD(STMT_LABEL); + RECORD(STMT_ATTRIBUTED); RECORD(STMT_IF); RECORD(STMT_SWITCH); RECORD(STMT_WHILE); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 827caa026a..1e31211463 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -106,6 +106,14 @@ void ASTStmtWriter::VisitLabelStmt(LabelStmt *S) { Code = serialization::STMT_LABEL; } +void ASTStmtWriter::VisitAttributedStmt(AttributedStmt *S) { + VisitStmt(S); + Writer.WriteAttributes(S->getAttrs(), Record); + Writer.AddStmt(S->getSubStmt()); + Writer.AddSourceLocation(S->getAttrLoc(), Record); + Code = serialization::STMT_ATTRIBUTED; +} + void ASTStmtWriter::VisitIfStmt(IfStmt *S) { VisitStmt(S); Writer.AddDeclRef(S->getConditionVariable(), Record); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index d2da9aaccb..1fd9068518 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -536,6 +536,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::IfStmtClass: case Stmt::IndirectGotoStmtClass: case Stmt::LabelStmtClass: + case Stmt::AttributedStmtClass: case Stmt::NoStmtClass: case Stmt::NullStmtClass: case Stmt::SwitchStmtClass: |