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
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 6af20df..e4d9f0a 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -97,8 +97,8 @@
 
 /// \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 @@
       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 3a44183..0d1066b 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -169,6 +169,23 @@
   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 e5526ce..4bdded1 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -109,6 +109,11 @@
   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 d1334a5..f4d9a35 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 @@
     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 @@
 
 /// 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 bf42dcb..a1d0789 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -79,6 +79,7 @@
   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 @@
   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 @@
   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 f57dd5f..0f3f8f9 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1948,6 +1948,7 @@
   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 cf3dca2..be84cdc 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -958,7 +958,7 @@
 /// [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 7f3a815..6d31396 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -1926,11 +1926,9 @@
   // 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 fdb9788..44320df 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -78,13 +78,30 @@
 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 @@
   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 @@
     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 @@
     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 @@
       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 @@
   }
 
   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 @@
 }
 
 /// \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 @@
       << 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 @@
   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 @@
   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 @@
   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 @@
     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 @@
 ///         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 @@
   // 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 @@
 
   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 @@
 ///         '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 @@
 ///         '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 @@
                                   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 @@
 /// [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 @@
 /// [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 @@
 ///       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 @@
 ///       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 @@
 ///       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 @@
 /// [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 @@
 ///
 /// 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 @@
 ///
 /// 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 @@
 ///
 /// 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 @@
 /// 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 @@
 ///       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 @@
   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 @@
   }
   else {
     StmtVector Handlers(Actions);
+    ParsedAttributesWithRange attrs(AttrFactory);
     MaybeParseCXX0XAttributes(attrs);
     ProhibitAttributes(attrs);
 
@@ -2168,8 +2157,7 @@
     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 @@
   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 5d297f9..07734c7 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -40,6 +40,7 @@
   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 97c8eb0..9052278 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -345,7 +345,6 @@
 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 @@
   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 0000000..21c3297
--- /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 fdb861e..acfea6e 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1044,6 +1044,15 @@
     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 @@
                                         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 @@
 
 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 2eeb090..007ecee 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -159,9 +159,18 @@
   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 @@
       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 a4301b5..81c0a9d 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -651,6 +651,7 @@
   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 827caa0..1e31211 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -106,6 +106,14 @@
   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 d2da9aa..1fd9068 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -536,6 +536,7 @@
     case Stmt::IfStmtClass:
     case Stmt::IndirectGotoStmtClass:
     case Stmt::LabelStmtClass:
+    case Stmt::AttributedStmtClass:
     case Stmt::NoStmtClass:
     case Stmt::NullStmtClass:
     case Stmt::SwitchStmtClass: