Added rudimentary C++0x attribute support.
The following attributes are currently supported in C++0x attribute
lists (and in GNU ones as well):
 - align() - semantics believed to be conformant to n3000, except for
   redeclarations and what entities it may apply to
 - final - semantics believed to be conformant to CWG issue 817's proposed
   wording, except for redeclarations
 - noreturn - semantics believed to be conformant to n3000, except for
   redeclarations
 - carries_dependency - currently ignored (this is an optimization hint)


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89543 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index dde4bc8..7e2935c 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -17,11 +17,13 @@
 using namespace clang;
 
 AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc,
+                             IdentifierInfo *sName, SourceLocation sLoc,
                              IdentifierInfo *pName, SourceLocation pLoc,
                              ActionBase::ExprTy **ExprList, unsigned numArgs,
-                             AttributeList *n, bool declspec)
-  : AttrName(aName), AttrLoc(aLoc), ParmName(pName), ParmLoc(pLoc),
-    NumArgs(numArgs), Next(n), DeclspecAttribute(declspec) {
+                             AttributeList *n, bool declspec, bool cxx0x)
+  : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc),
+    ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n),
+    DeclspecAttribute(declspec), CXX0XAttribute(cxx0x) {
 
   if (numArgs == 0)
     Args = 0;
@@ -59,6 +61,8 @@
     .Case("mode", AT_mode)
     .Case("used", AT_used)
     .Case("alias", AT_alias)
+    .Case("align", AT_aligned)
+    .Case("final", AT_final)
     .Case("cdecl", AT_cdecl)
     .Case("const", AT_const)
     .Case("packed", AT_packed)
@@ -103,6 +107,7 @@
     .Case("transparent_union", AT_transparent_union)
     .Case("analyzer_noreturn", AT_analyzer_noreturn)
     .Case("warn_unused_result", AT_warn_unused_result)
+    .Case("carries_dependency", AT_carries_dependency)
     .Case("ns_returns_retained", AT_ns_returns_retained)
     .Case("cf_returns_retained", AT_cf_returns_retained)
     .Case("reqd_work_group_size", AT_reqd_wg_size)
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2bfda30..b13dc73 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1,3 +1,4 @@
+
 //===--- ParseDecl.cpp - Declaration Parsing ------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
@@ -45,7 +46,7 @@
   return Actions.ActOnTypeName(CurScope, DeclaratorInfo);
 }
 
-/// ParseAttributes - Parse a non-empty attributes list.
+/// ParseGNUAttributes - Parse a non-empty attributes list.
 ///
 /// [GNU] attributes:
 ///         attribute
@@ -81,8 +82,8 @@
 /// attributes are very simple in practice. Until we find a bug, I don't see
 /// a pressing need to implement the 2 token lookahead.
 
-AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) {
-  assert(Tok.is(tok::kw___attribute) && "Not an attribute list!");
+AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) {
+  assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
 
   AttributeList *CurrAttr = 0;
 
@@ -121,7 +122,7 @@
           if (Tok.is(tok::r_paren)) {
             // __attribute__(( mode(byte) ))
             ConsumeParen(); // ignore the right paren loc for now
-            CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+            CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
                                          ParmName, ParmLoc, 0, 0, CurrAttr);
           } else if (Tok.is(tok::comma)) {
             ConsumeToken();
@@ -145,8 +146,10 @@
             }
             if (ArgExprsOk && Tok.is(tok::r_paren)) {
               ConsumeParen(); // ignore the right paren loc for now
-              CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
-                           ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr);
+              CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+                                           AttrNameLoc, ParmName, ParmLoc,
+                                           ArgExprs.take(), ArgExprs.size(),
+                                           CurrAttr);
             }
           }
         } else { // not an identifier
@@ -155,7 +158,7 @@
           // parse a possibly empty comma separated list of expressions
             // __attribute__(( nonnull() ))
             ConsumeParen(); // ignore the right paren loc for now
-            CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+            CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
                                          0, SourceLocation(), 0, 0, CurrAttr);
             break;
           case tok::kw_char:
@@ -175,7 +178,7 @@
             // If it's a builtin type name, eat it and expect a rparen
             // __attribute__(( vec_type_hint(char) ))
             ConsumeToken();
-            CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+            CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
                                          0, SourceLocation(), 0, 0, CurrAttr);
             if (Tok.is(tok::r_paren))
               ConsumeParen();
@@ -203,20 +206,21 @@
             if (ArgExprsOk && Tok.is(tok::r_paren)) {
               ConsumeParen(); // ignore the right paren loc for now
               CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
-                           SourceLocation(), ArgExprs.take(), ArgExprs.size(),
+                           AttrNameLoc, 0, SourceLocation(), ArgExprs.take(),
+                           ArgExprs.size(),
                            CurrAttr);
             }
             break;
           }
         }
       } else {
-        CurrAttr = new AttributeList(AttrName, AttrNameLoc,
+        CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
                                      0, SourceLocation(), 0, 0, CurrAttr);
       }
     }
     if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
       SkipUntil(tok::r_paren, false);
-    SourceLocation Loc = Tok.getLocation();;
+    SourceLocation Loc = Tok.getLocation();
     if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
       SkipUntil(tok::r_paren, false);
     }
@@ -254,15 +258,15 @@
       OwningExprResult ArgExpr(ParseAssignmentExpression());
       if (!ArgExpr.isInvalid()) {
         ExprTy* ExprList = ArgExpr.take();
-        CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+        CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
                                      SourceLocation(), &ExprList, 1,
                                      CurrAttr, true);
       }
       if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
         SkipUntil(tok::r_paren, false);
     } else {
-      CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, SourceLocation(),
-                                   0, 0, CurrAttr, true);
+      CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc,
+                                   0, SourceLocation(), 0, 0, CurrAttr, true);
     }
   }
   if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen))
@@ -281,7 +285,7 @@
     if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64))
       // FIXME: Support these properly!
       continue;
-    CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
+    CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
                                  SourceLocation(), 0, 0, CurrAttr, true);
   }
   return CurrAttr;
@@ -304,26 +308,36 @@
 ///         others... [FIXME]
 ///
 Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
-                                                SourceLocation &DeclEnd) {
+                                                SourceLocation &DeclEnd,
+                                                CXX0XAttributeList Attr) {
   DeclPtrTy SingleDecl;
   switch (Tok.getKind()) {
   case tok::kw_template:
   case tok::kw_export:
+    if (Attr.HasAttr)
+      Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+        << Attr.Range;
     SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd);
     break;
   case tok::kw_namespace:
+    if (Attr.HasAttr)
+      Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+        << Attr.Range;
     SingleDecl = ParseNamespace(Context, DeclEnd);
     break;
   case tok::kw_using:
-    SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd);
+    SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd, Attr);
     break;
   case tok::kw_static_assert:
+    if (Attr.HasAttr)
+      Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+        << Attr.Range;
     SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
     break;
   default:
-    return ParseSimpleDeclaration(Context, DeclEnd);
+    return ParseSimpleDeclaration(Context, DeclEnd, Attr.AttrList);
   }
-
+  
   // This routine returns a DeclGroup, if the thing we parsed only contains a
   // single decl, convert it now.
   return Actions.ConvertDeclToDeclGroup(SingleDecl);
@@ -337,9 +351,12 @@
 /// If RequireSemi is false, this does not check for a ';' at the end of the
 /// declaration.
 Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context,
-                                                      SourceLocation &DeclEnd) {
+                                                      SourceLocation &DeclEnd,
+                                                      AttributeList *Attr) {
   // Parse the common declaration-specifiers piece.
   ParsingDeclSpec DS(*this);
+  if (Attr)
+    DS.AddAttributes(Attr);
   ParseDeclarationSpecifiers(DS);
 
   // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
@@ -422,7 +439,7 @@
     //    short x, __attribute__((common)) var;    -> declarator
     if (Tok.is(tok::kw___attribute)) {
       SourceLocation Loc;
-      AttributeList *AttrList = ParseAttributes(&Loc);
+      AttributeList *AttrList = ParseGNUAttributes(&Loc);
       D.AddAttributes(AttrList, Loc);
     }
 
@@ -491,7 +508,7 @@
   // If attributes are present, parse them.
   if (Tok.is(tok::kw___attribute)) {
     SourceLocation Loc;
-    AttributeList *AttrList = ParseAttributes(&Loc);
+    AttributeList *AttrList = ParseGNUAttributes(&Loc);
     D.AddAttributes(AttrList, Loc);
   }
 
@@ -988,7 +1005,7 @@
 
     // GNU attributes support.
     case tok::kw___attribute:
-      DS.AddAttributes(ParseAttributes());
+      DS.AddAttributes(ParseGNUAttributes());
       continue;
 
     // Microsoft declspec support.
@@ -1522,7 +1539,7 @@
     // Attributes are only allowed here on successive declarators.
     if (!FirstDeclarator && Tok.is(tok::kw___attribute)) {
       SourceLocation Loc;
-      AttributeList *AttrList = ParseAttributes(&Loc);
+      AttributeList *AttrList = ParseGNUAttributes(&Loc);
       DeclaratorInfo.D.AddAttributes(AttrList, Loc);
     }
 
@@ -1543,7 +1560,7 @@
     // If attributes exist after the declarator, parse them.
     if (Tok.is(tok::kw___attribute)) {
       SourceLocation Loc;
-      AttributeList *AttrList = ParseAttributes(&Loc);
+      AttributeList *AttrList = ParseGNUAttributes(&Loc);
       DeclaratorInfo.D.AddAttributes(AttrList, Loc);
     }
 
@@ -1667,7 +1684,7 @@
   AttributeList *AttrList = 0;
   // If attributes exist after struct contents, parse them.
   if (Tok.is(tok::kw___attribute))
-    AttrList = ParseAttributes();
+    AttrList = ParseGNUAttributes();
 
   Actions.ActOnFields(CurScope,
                       RecordLoc, TagDecl, FieldDecls.data(), FieldDecls.size(),
@@ -1702,7 +1719,7 @@
   AttributeList *Attr = 0;
   // If attributes exist after tag, parse them.
   if (Tok.is(tok::kw___attribute))
-    Attr = ParseAttributes();
+    Attr = ParseGNUAttributes();
 
   CXXScopeSpec SS;
   if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) {
@@ -1833,7 +1850,7 @@
   AttributeList *Attr = 0;
   // If attributes exist after the identifier list, parse them.
   if (Tok.is(tok::kw___attribute))
-    Attr = ParseAttributes();
+    Attr = ParseGNUAttributes(); // FIXME: where do they do?
 
   Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl,
                         EnumConstantDecls.data(), EnumConstantDecls.size(),
@@ -2049,8 +2066,20 @@
 /// [GNU]   attributes                        [ only if AttributesAllowed=true ]
 ///         type-qualifier-list type-qualifier
 /// [GNU]   type-qualifier-list attributes    [ only if AttributesAllowed=true ]
+/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq
+///           if CXX0XAttributesAllowed = true
 ///
-void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) {
+void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed,
+                                       bool CXX0XAttributesAllowed) {
+  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+    SourceLocation Loc = Tok.getLocation();
+    CXX0XAttributeList Attr = ParseCXX0XAttributes();
+    if (CXX0XAttributesAllowed)
+      DS.AddAttributes(Attr.AttrList);
+    else
+      Diag(Loc, diag::err_attributes_not_allowed);
+  }
+  
   while (1) {
     bool isInvalid = false;
     const char *PrevSpec = 0;
@@ -2075,14 +2104,14 @@
     case tok::kw___cdecl:
     case tok::kw___stdcall:
     case tok::kw___fastcall:
-      if (AttributesAllowed) {
+      if (GNUAttributesAllowed) {
         DS.AddAttributes(ParseMicrosoftTypeAttributes());
         continue;
       }
       goto DoneWithTypeQuals;
     case tok::kw___attribute:
-      if (AttributesAllowed) {
-        DS.AddAttributes(ParseAttributes());
+      if (GNUAttributesAllowed) {
+        DS.AddAttributes(ParseGNUAttributes());
         continue; // do *not* consume the next token!
       }
       // otherwise, FALL THROUGH!
@@ -2221,7 +2250,8 @@
     //
     // [GNU] Retricted references are allowed.
     // [GNU] Attributes on references are allowed.
-    ParseTypeQualifierListOpt(DS);
+    // [C++0x] Attributes on references are not allowed.
+    ParseTypeQualifierListOpt(DS, true, false);
     D.ExtendWithDeclSpec(DS);
 
     if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
@@ -2362,6 +2392,14 @@
   assert(D.isPastIdentifier() &&
          "Haven't past the location of the identifier yet?");
 
+  // Don't parse attributes unless we have an identifier.
+  if (D.getIdentifier() && getLang().CPlusPlus
+   && isCXX0XAttributeSpecifier(true)) {
+    SourceLocation AttrEndLoc;
+    CXX0XAttributeList Attr = ParseCXX0XAttributes();
+    D.AddAttributes(Attr.AttrList, AttrEndLoc);
+  }
+
   while (1) {
     if (Tok.is(tok::l_paren)) {
       // The paren may be part of a C++ direct initializer, eg. "int x(1);".
@@ -2413,7 +2451,7 @@
   AttributeList *AttrList = 0;
   bool RequiresArg = false;
   if (Tok.is(tok::kw___attribute)) {
-    AttrList = ParseAttributes();
+    AttrList = ParseGNUAttributes();
 
     // We require that the argument list (if this is a non-grouping paren) be
     // present even if the attribute list was empty.
@@ -2618,7 +2656,7 @@
     // Parse GNU attributes, if present.
     if (Tok.is(tok::kw___attribute)) {
       SourceLocation Loc;
-      AttributeList *AttrList = ParseAttributes(&Loc);
+      AttributeList *AttrList = ParseGNUAttributes(&Loc);
       ParmDecl.AddAttributes(AttrList, Loc);
     }
 
@@ -2722,6 +2760,7 @@
   bool hasAnyExceptionSpec = false;
   llvm::SmallVector<TypeTy*, 2> Exceptions;
   llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+  
   if (getLang().CPlusPlus) {
     // Parse cv-qualifier-seq[opt].
     ParseTypeQualifierListOpt(DS, false /*no attributes*/);
@@ -2842,6 +2881,12 @@
   // This code does a fast path to handle some of the most obvious cases.
   if (Tok.getKind() == tok::r_square) {
     SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+    //FIXME: Use these
+    CXX0XAttributeList Attr;
+    if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier(true)) {
+      Attr = ParseCXX0XAttributes();
+    }
+    
     // Remember that we parsed the empty array type.
     OwningExprResult NumElements(Actions);
     D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0,
@@ -2855,6 +2900,11 @@
     ConsumeToken();
 
     SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+    //FIXME: Use these
+    CXX0XAttributeList Attr;
+    if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+      Attr = ParseCXX0XAttributes();
+    }
 
     // If there was an error parsing the assignment-expression, recover.
     if (ExprRes.isInvalid())
@@ -2922,6 +2972,12 @@
 
   SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
 
+  //FIXME: Use these
+  CXX0XAttributeList Attr;
+  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+    Attr = ParseCXX0XAttributes();
+  }
+
   // Remember that we parsed a array type, and remember its features.
   D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
                                           StaticLoc.isValid(), isStar,
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 914bfc9..a21f034 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -69,7 +69,7 @@
     attrTok = Tok;
 
     // FIXME: save these somewhere.
-    AttrList = ParseAttributes();
+    AttrList = ParseGNUAttributes();
   }
 
   if (Tok.is(tok::equal)) {
@@ -97,8 +97,12 @@
                                         PP.getSourceManager(),
                                         "parsing namespace");
 
-  while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof))
-    ParseExternalDeclaration();
+  while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+    CXX0XAttributeList Attr;
+    if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+      Attr = ParseCXX0XAttributes();
+    ParseExternalDeclaration(Attr);
+  }
 
   // Leave the namespace scope.
   NamespaceScope.Exit();
@@ -175,15 +179,27 @@
                                        Tok.is(tok::l_brace)? Tok.getLocation()
                                                            : SourceLocation());
 
+  CXX0XAttributeList Attr;
+  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+    Attr = ParseCXX0XAttributes();
+  }
+  
   if (Tok.isNot(tok::l_brace)) {
-    ParseDeclarationOrFunctionDefinition();
+    ParseDeclarationOrFunctionDefinition(Attr.AttrList);
     return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec,
                                                    SourceLocation());
   }
 
+  if (Attr.HasAttr)
+    Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+      << Attr.Range;
+
   SourceLocation LBrace = ConsumeBrace();
   while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
-    ParseExternalDeclaration();
+    CXX0XAttributeList Attr;
+    if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+      Attr = ParseCXX0XAttributes();
+    ParseExternalDeclaration(Attr);
   }
 
   SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
@@ -193,7 +209,8 @@
 /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
 /// using-directive. Assumes that current token is 'using'.
 Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
-                                                     SourceLocation &DeclEnd) {
+                                                     SourceLocation &DeclEnd,
+                                                     CXX0XAttributeList Attr) {
   assert(Tok.is(tok::kw_using) && "Not using token");
 
   // Eat 'using'.
@@ -206,9 +223,14 @@
   
   if (Tok.is(tok::kw_namespace))
     // Next token after 'using' is 'namespace' so it must be using-directive
-    return ParseUsingDirective(Context, UsingLoc, DeclEnd);
+    return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList);
+
+  if (Attr.HasAttr)
+    Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+      << Attr.Range;
 
   // Otherwise, it must be using-declaration.
+  // Ignore illegal attributes (the caller should already have issued an error.
   return ParseUsingDeclaration(Context, UsingLoc, DeclEnd);
 }
 
@@ -224,7 +246,8 @@
 ///
 Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context,
                                               SourceLocation UsingLoc,
-                                              SourceLocation &DeclEnd) {
+                                              SourceLocation &DeclEnd,
+                                              AttributeList *Attr) {
   assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token");
 
   // Eat 'namespace'.
@@ -239,7 +262,6 @@
   // Parse (optional) nested-name-specifier.
   ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false);
 
-  AttributeList *AttrList = 0;
   IdentifierInfo *NamespcName = 0;
   SourceLocation IdentLoc = SourceLocation();
 
@@ -257,17 +279,20 @@
   IdentLoc = ConsumeToken();
 
   // Parse (optional) attributes (most likely GNU strong-using extension).
-  if (Tok.is(tok::kw___attribute))
-    AttrList = ParseAttributes();
+  bool GNUAttr = false;
+  if (Tok.is(tok::kw___attribute)) {
+    GNUAttr = true;
+    Attr = addAttributeLists(Attr, ParseGNUAttributes());
+  }
 
   // Eat ';'.
   DeclEnd = Tok.getLocation();
   ExpectAndConsume(tok::semi,
-                   AttrList ? diag::err_expected_semi_after_attribute_list :
+                   GNUAttr ? diag::err_expected_semi_after_attribute_list :
                    diag::err_expected_semi_after_namespace_name, "", tok::semi);
 
   return Actions.ActOnUsingDirective(CurScope, UsingLoc, NamespcLoc, SS,
-                                      IdentLoc, NamespcName, AttrList);
+                                      IdentLoc, NamespcName, Attr);
 }
 
 /// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that
@@ -323,7 +348,7 @@
   
   // Parse (optional) attributes (most likely GNU strong-using extension).
   if (Tok.is(tok::kw___attribute))
-    AttrList = ParseAttributes();
+    AttrList = ParseGNUAttributes();
 
   // Eat ';'.
   DeclEnd = Tok.getLocation();
@@ -538,14 +563,20 @@
     ConsumeToken();
   }
   
-  AttributeList *Attr = 0;
+  AttributeList *AttrList = 0;
   // If attributes exist after tag, parse them.
   if (Tok.is(tok::kw___attribute))
-    Attr = ParseAttributes();
+    AttrList = ParseGNUAttributes();
 
   // If declspecs exist after tag, parse them.
   if (Tok.is(tok::kw___declspec))
-    Attr = ParseMicrosoftDeclSpec(Attr);
+    AttrList = ParseMicrosoftDeclSpec(AttrList);
+  
+  // If C++0x attributes exist here, parse them.
+  // FIXME: Are we consistent with the ordering of parsing of different
+  // styles of attributes?
+  if (isCXX0XAttributeSpecifier())
+    AttrList = addAttributeLists(AttrList, ParseCXX0XAttributes().AttrList);
 
   if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) {
     // GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but
@@ -683,7 +714,6 @@
     Diag(StartLoc, diag::err_anon_type_definition)
       << DeclSpec::getSpecifierName(TagType);
 
-    // Skip the rest of this declarator, up until the comma or semicolon.
     SkipUntil(tok::comma, true);
 
     if (TemplateId)
@@ -720,7 +750,7 @@
                                              TemplateId->LAngleLoc,
                                              TemplateArgsPtr,
                                              TemplateId->RAngleLoc,
-                                             Attr);
+                                             AttrList);
     } else if (TUK == Action::TUK_Reference) {
       TypeResult
         = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
@@ -775,7 +805,7 @@
                        TemplateId->LAngleLoc,
                        TemplateArgsPtr,
                        TemplateId->RAngleLoc,
-                       Attr,
+                       AttrList,
                        Action::MultiTemplateParamsArg(Actions,
                                     TemplateParams? &(*TemplateParams)[0] : 0,
                                  TemplateParams? TemplateParams->size() : 0));
@@ -793,7 +823,7 @@
                                            TemplateInfo.ExternLoc,
                                            TemplateInfo.TemplateLoc,
                                            TagType, StartLoc, SS, Name,
-                                           NameLoc, Attr);
+                                           NameLoc, AttrList);
   } else {
     if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
         TUK == Action::TUK_Definition) {
@@ -804,7 +834,7 @@
 
     // Declaration or definition of a class type
     TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS,
-                                       Name, NameLoc, Attr, AS,
+                                       Name, NameLoc, AttrList, AS,
                                   Action::MultiTemplateParamsArg(Actions,
                                     TemplateParams? &(*TemplateParams)[0] : 0,
                                     TemplateParams? TemplateParams->size() : 0),
@@ -1055,8 +1085,18 @@
     return ParseCXXClassMemberDeclaration(AS, TemplateInfo);
   }
 
+  CXX0XAttributeList AttrList;
+  // Optional C++0x attribute-specifier
+  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+    AttrList = ParseCXX0XAttributes();
+  }
+
   if (Tok.is(tok::kw_using)) {
     // FIXME: Check for template aliases
+    
+    if (AttrList.HasAttr)
+      Diag(AttrList.Range.getBegin(), diag::err_attributes_not_allowed)
+        << AttrList.Range;
 
     // Eat 'using'.
     SourceLocation UsingLoc = ConsumeToken();
@@ -1077,6 +1117,7 @@
   // decl-specifier-seq:
   // Parse the common declaration-specifiers piece.
   ParsingDeclSpec DS(*this);
+  DS.AddAttributes(AttrList.AttrList);
   ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class);
 
   Action::MultiTemplateParamsArg TemplateParams(Actions,
@@ -1139,7 +1180,6 @@
   bool Deleted = false;
 
   while (1) {
-
     // member-declarator:
     //   declarator pure-specifier[opt]
     //   declarator constant-initializer[opt]
@@ -1177,7 +1217,7 @@
     // If attributes exist after the declarator, parse them.
     if (Tok.is(tok::kw___attribute)) {
       SourceLocation Loc;
-      AttributeList *AttrList = ParseAttributes(&Loc);
+      AttributeList *AttrList = ParseGNUAttributes(&Loc);
       DeclaratorInfo.AddAttributes(AttrList, Loc);
     }
 
@@ -1227,7 +1267,7 @@
     // Attributes are only allowed on the second declarator.
     if (Tok.is(tok::kw___attribute)) {
       SourceLocation Loc;
-      AttributeList *AttrList = ParseAttributes(&Loc);
+      AttributeList *AttrList = ParseGNUAttributes(&Loc);
       DeclaratorInfo.AddAttributes(AttrList, Loc);
     }
 
@@ -1326,7 +1366,7 @@
   AttributeList *AttrList = 0;
   // If attributes exist after class contents, parse them.
   if (Tok.is(tok::kw___attribute))
-    AttrList = ParseAttributes(); // FIXME: where should I put them?
+    AttrList = ParseGNUAttributes(); // FIXME: where should I put them?
 
   Actions.ActOnFinishCXXMemberSpecification(CurScope, RecordLoc, TagDecl,
                                             LBraceLoc, RBraceLoc);
@@ -1573,3 +1613,170 @@
   ClassStack.top()->NestedClasses.push_back(Victim);
   Victim->TemplateScope = CurScope->getParent()->isTemplateParamScope();
 }
+
+/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier. Currently only
+/// parses standard attributes.
+///
+/// [C++0x] attribute-specifier:
+///         '[' '[' attribute-list ']' ']'
+///
+/// [C++0x] attribute-list:
+///         attribute[opt]
+///         attribute-list ',' attribute[opt]
+///
+/// [C++0x] attribute:
+///         attribute-token attribute-argument-clause[opt]
+///
+/// [C++0x] attribute-token:
+///         identifier
+///         attribute-scoped-token
+///
+/// [C++0x] attribute-scoped-token:
+///         attribute-namespace '::' identifier
+///
+/// [C++0x] attribute-namespace:
+///         identifier
+///
+/// [C++0x] attribute-argument-clause:
+///         '(' balanced-token-seq ')'
+///
+/// [C++0x] balanced-token-seq:
+///         balanced-token
+///         balanced-token-seq balanced-token
+///
+/// [C++0x] balanced-token:
+///         '(' balanced-token-seq ')'
+///         '[' balanced-token-seq ']'
+///         '{' balanced-token-seq '}'
+///         any token but '(', ')', '[', ']', '{', or '}'
+CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) {
+  assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
+      && "Not a C++0x attribute list");
+
+  SourceLocation StartLoc = Tok.getLocation(), Loc;
+  AttributeList *CurrAttr = 0;
+
+  ConsumeBracket();
+  ConsumeBracket();
+  
+  if (Tok.is(tok::comma)) {
+    Diag(Tok.getLocation(), diag::err_expected_ident);
+    ConsumeToken();
+  }
+
+  while (Tok.is(tok::identifier) || Tok.is(tok::comma)) {
+    // attribute not present
+    if (Tok.is(tok::comma)) {
+      ConsumeToken();
+      continue;
+    }
+
+    IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo();
+    SourceLocation ScopeLoc, AttrLoc = ConsumeToken();
+    
+    // scoped attribute
+    if (Tok.is(tok::coloncolon)) {
+      ConsumeToken();
+
+      if (!Tok.is(tok::identifier)) {
+        Diag(Tok.getLocation(), diag::err_expected_ident);
+        SkipUntil(tok::r_square, tok::comma, true, true);
+        continue;
+      }
+      
+      ScopeName = AttrName;
+      ScopeLoc = AttrLoc;
+
+      AttrName = Tok.getIdentifierInfo();
+      AttrLoc = ConsumeToken();
+    }
+
+    bool AttrParsed = false;
+    // No scoped names are supported; ideally we could put all non-standard
+    // attributes into namespaces.
+    if (!ScopeName) {
+      switch(AttributeList::getKind(AttrName))
+      {
+      // No arguments
+      case AttributeList::AT_noreturn:
+      case AttributeList::AT_final:
+      case AttributeList::AT_carries_dependency: {
+        if (Tok.is(tok::l_paren)) {
+          Diag(Tok.getLocation(), diag::err_cxx0x_attribute_forbids_arguments)
+            << AttrName->getName();
+          break;
+        }
+
+        CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc, 0,
+                                     SourceLocation(), 0, 0, CurrAttr, false,
+                                     true);
+        AttrParsed = true;
+        break;
+      }
+
+      // One argument; must be a type-id or assignment-expression
+      case AttributeList::AT_aligned: {
+        if (Tok.isNot(tok::l_paren)) {
+          Diag(Tok.getLocation(), diag::err_cxx0x_attribute_requires_arguments)
+            << AttrName->getName();
+          break;
+        }
+        SourceLocation ParamLoc = ConsumeParen();
+
+        OwningExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc);
+
+        MatchRHSPunctuation(tok::r_paren, ParamLoc);
+
+        ExprVector ArgExprs(Actions);
+        ArgExprs.push_back(ArgExpr.release());
+        CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc,
+                                     0, ParamLoc, ArgExprs.take(), 1, CurrAttr,
+                                     false, true);
+
+        AttrParsed = true;
+        break;
+      }
+
+      // Silence warnings
+      default: break;
+      }
+    }
+
+    // Skip the entire parameter clause, if any
+    if (!AttrParsed && Tok.is(tok::l_paren)) {
+      ConsumeParen();
+      // SkipUntil maintains the balancedness of tokens.
+      SkipUntil(tok::r_paren, false);
+    }
+  }
+
+  if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
+    SkipUntil(tok::r_square, false);
+  Loc = Tok.getLocation();
+  if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
+    SkipUntil(tok::r_square, false);
+
+  CXX0XAttributeList Attr (CurrAttr, SourceRange(StartLoc, Loc), true);
+  return Attr;
+}
+
+/// ParseCXX0XAlignArgument - Parse the argument to C++0x's [[align]]
+/// attribute.
+///
+/// FIXME: Simply returns an alignof() expression if the argument is a
+/// type. Ideally, the type should be propagated directly into Sema.
+///
+/// [C++0x] 'align' '(' type-id ')'
+/// [C++0x] 'align' '(' assignment-expression ')'
+Parser::OwningExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) {
+  if (isTypeIdInParens()) {
+    EnterExpressionEvaluationContext Unevaluated(Actions,
+                                                  Action::Unevaluated);
+    SourceLocation TypeLoc = Tok.getLocation();
+    TypeTy *Ty = ParseTypeName().get();
+    SourceRange TypeRange(Start, Tok.getLocation());
+    return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, Ty,
+                                              TypeRange);
+  } else
+    return ParseConstantExpression();
+}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index d2b3b84..bb6dfce 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -1315,7 +1315,7 @@
 
   if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
     Diag(Tok, diag::ext_gnu_statement_expr);
-    OwningStmtResult Stmt(ParseCompoundStatement(true));
+    OwningStmtResult Stmt(ParseCompoundStatement(0, true));
     ExprType = CompoundStmt;
 
     // If the substmt parsed correctly, build the AST node.
@@ -1503,7 +1503,7 @@
 
   if (Tok.is(tok::kw___attribute)) {
     SourceLocation Loc;
-    AttributeList *AttrList = ParseAttributes(&Loc);
+    AttributeList *AttrList = ParseGNUAttributes(&Loc);
     DeclaratorInfo.AddAttributes(AttrList, Loc);
   }
 
@@ -1565,7 +1565,7 @@
 
     if (Tok.is(tok::kw___attribute)) {
       SourceLocation Loc;
-      AttributeList *AttrList = ParseAttributes(&Loc);
+      AttributeList *AttrList = ParseGNUAttributes(&Loc);
       ParamInfo.AddAttributes(AttrList, Loc);
     }
 
@@ -1586,7 +1586,7 @@
 
     if (Tok.is(tok::kw___attribute)) {
       SourceLocation Loc;
-      AttributeList *AttrList = ParseAttributes(&Loc);
+      AttributeList *AttrList = ParseGNUAttributes(&Loc);
       ParamInfo.AddAttributes(AttrList, Loc);
     }
 
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 992211d..a57d718 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -568,7 +568,7 @@
   // If attributes are present, parse them.
   if (Tok.is(tok::kw___attribute)) {
     SourceLocation Loc;
-    AttributeList *AttrList = ParseAttributes(&Loc);
+    AttributeList *AttrList = ParseGNUAttributes(&Loc);
     DeclaratorInfo.AddAttributes(AttrList, Loc);
   }
 
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 5ba1dd1..295625a 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -282,7 +282,7 @@
 
       // FIXME: as the name implies, this rule allows function definitions.
       // We could pass a flag or check for functions during semantic analysis.
-      allTUVariables.push_back(ParseDeclarationOrFunctionDefinition());
+      allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(0));
       continue;
     }
 
@@ -759,7 +759,7 @@
     // If attributes exist after the method, parse them.
     AttributeList *MethodAttrs = 0;
     if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
-      MethodAttrs = ParseAttributes();
+      MethodAttrs = ParseGNUAttributes();
 
     Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
     DeclPtrTy Result
@@ -791,7 +791,7 @@
     // If attributes exist before the argument name, parse them.
     ArgInfo.ArgAttrs = 0;
     if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
-      ArgInfo.ArgAttrs = ParseAttributes();
+      ArgInfo.ArgAttrs = ParseGNUAttributes();
 
     if (Tok.isNot(tok::identifier)) {
       Diag(Tok, diag::err_expected_ident); // missing argument name.
@@ -835,7 +835,7 @@
   // If attributes exist after the method, parse them.
   AttributeList *MethodAttrs = 0;
   if (getLang().ObjC2 && Tok.is(tok::kw___attribute))
-    MethodAttrs = ParseAttributes();
+    MethodAttrs = ParseGNUAttributes();
 
   if (KeyIdents.size() == 0)
     return DeclPtrTy();
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index ff08ebb..66e61dd 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -78,6 +78,10 @@
   const char *SemiError = 0;
   OwningStmtResult Res(Actions);
 
+  CXX0XAttributeList Attr;
+  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+    Attr = ParseCXX0XAttributes();
+
   // 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),
   // or they directly 'return;' if not.
@@ -98,14 +102,15 @@
   case tok::identifier:
     if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
       // identifier ':' statement
-      return ParseLabeledStatement();
+      return ParseLabeledStatement(Attr.AttrList);
     }
     // PASS THROUGH.
 
   default: {
     if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
       SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
-      DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd);
+      DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext, DeclEnd,
+                                             Attr);
       return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
     }
 
@@ -114,6 +119,7 @@
       return StmtError();
     }
 
+    // FIXME: Use the attributes
     // expression[opt] ';'
     OwningExprResult Expr(ParseExpression());
     if (Expr.isInvalid()) {
@@ -129,47 +135,50 @@
   }
 
   case tok::kw_case:                // C99 6.8.1: labeled-statement
-    return ParseCaseStatement();
+    return ParseCaseStatement(Attr.AttrList);
   case tok::kw_default:             // C99 6.8.1: labeled-statement
-    return ParseDefaultStatement();
+    return ParseDefaultStatement(Attr.AttrList);
 
   case tok::l_brace:                // C99 6.8.2: compound-statement
-    return ParseCompoundStatement();
+    return ParseCompoundStatement(Attr.AttrList);
   case tok::semi:                   // C99 6.8.3p3: expression[opt] ';'
     return Actions.ActOnNullStmt(ConsumeToken());
 
   case tok::kw_if:                  // C99 6.8.4.1: if-statement
-    return ParseIfStatement();
+    return ParseIfStatement(Attr.AttrList);
   case tok::kw_switch:              // C99 6.8.4.2: switch-statement
-    return ParseSwitchStatement();
+    return ParseSwitchStatement(Attr.AttrList);
 
   case tok::kw_while:               // C99 6.8.5.1: while-statement
-    return ParseWhileStatement();
+    return ParseWhileStatement(Attr.AttrList);
   case tok::kw_do:                  // C99 6.8.5.2: do-statement
-    Res = ParseDoStatement();
+    Res = ParseDoStatement(Attr.AttrList);
     SemiError = "do/while";
     break;
   case tok::kw_for:                 // C99 6.8.5.3: for-statement
-    return ParseForStatement();
+    return ParseForStatement(Attr.AttrList);
 
   case tok::kw_goto:                // C99 6.8.6.1: goto-statement
-    Res = ParseGotoStatement();
+    Res = ParseGotoStatement(Attr.AttrList);
     SemiError = "goto";
     break;
   case tok::kw_continue:            // C99 6.8.6.2: continue-statement
-    Res = ParseContinueStatement();
+    Res = ParseContinueStatement(Attr.AttrList);
     SemiError = "continue";
     break;
   case tok::kw_break:               // C99 6.8.6.3: break-statement
-    Res = ParseBreakStatement();
+    Res = ParseBreakStatement(Attr.AttrList);
     SemiError = "break";
     break;
   case tok::kw_return:              // C99 6.8.6.4: return-statement
-    Res = ParseReturnStatement();
+    Res = ParseReturnStatement(Attr.AttrList);
     SemiError = "return";
     break;
 
   case tok::kw_asm: {
+    if (Attr.HasAttr)
+      Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+        << Attr.Range;
     bool msAsm = false;
     Res = ParseAsmStatement(msAsm);
     if (msAsm) return move(Res);
@@ -178,7 +187,7 @@
   }
 
   case tok::kw_try:                 // C++ 15: try-block
-    return ParseCXXTryBlock();
+    return ParseCXXTryBlock(Attr.AttrList);
   }
 
   // If we reached this code, the statement must end in a semicolon.
@@ -202,7 +211,7 @@
 ///         identifier ':' statement
 /// [GNU]   identifier ':' attributes[opt] statement
 ///
-Parser::OwningStmtResult Parser::ParseLabeledStatement() {
+Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) {
   assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
          "Not an identifier!");
 
@@ -215,10 +224,8 @@
   SourceLocation ColonLoc = ConsumeToken();
 
   // Read label attributes, if present.
-  Action::AttrTy *AttrList = 0;
   if (Tok.is(tok::kw___attribute))
-    // TODO: save these somewhere.
-    AttrList = ParseAttributes();
+    Attr = addAttributeLists(Attr, ParseGNUAttributes());
 
   OwningStmtResult SubStmt(ParseStatement());
 
@@ -236,8 +243,9 @@
 ///         'case' constant-expression ':' statement
 /// [GNU]   'case' constant-expression '...' constant-expression ':' statement
 ///
-Parser::OwningStmtResult Parser::ParseCaseStatement() {
+Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) {
   assert(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):
@@ -354,7 +362,8 @@
 ///         'default' ':' statement
 /// Note that this does not parse the 'statement' at the end.
 ///
-Parser::OwningStmtResult Parser::ParseDefaultStatement() {
+Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) {
+  //FIXME: Use attributes?
   assert(Tok.is(tok::kw_default) && "Not a default stmt!");
   SourceLocation DefaultLoc = ConsumeToken();  // eat the 'default'.
 
@@ -408,7 +417,9 @@
 /// [OMP]   barrier-directive
 /// [OMP]   flush-directive
 ///
-Parser::OwningStmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
+Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr,
+                                                        bool isStmtExpr) {
+  //FIXME: Use attributes?
   assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
 
   // Enter a scope to hold everything within the compound stmt.  Compound
@@ -449,6 +460,10 @@
       while (Tok.is(tok::kw___extension__))
         ConsumeToken();
 
+      CXX0XAttributeList Attr;
+      if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+        Attr = ParseCXX0XAttributes();
+
       // If this is the start of a declaration, parse it as such.
       if (isDeclarationStatement()) {
         // __extension__ silences extension warnings in the subdeclaration.
@@ -456,7 +471,8 @@
         ExtensionRAIIObject O(Diags);
 
         SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
-        DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext,DeclEnd);
+        DeclGroupPtrTy Res = ParseDeclaration(Declarator::BlockContext, DeclEnd,
+                                              Attr);
         R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
       } else {
         // Otherwise this was a unary __extension__ marker.
@@ -467,6 +483,7 @@
           continue;
         }
 
+        // FIXME: Use attributes?
         // Eat the semicolon at the end of stmt and convert the expr into a
         // statement.
         ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr);
@@ -537,7 +554,8 @@
 /// [C++]   'if' '(' condition ')' statement
 /// [C++]   'if' '(' condition ')' statement 'else' statement
 ///
-Parser::OwningStmtResult Parser::ParseIfStatement() {
+Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) {
+  // FIXME: Use attributes?
   assert(Tok.is(tok::kw_if) && "Not an if stmt!");
   SourceLocation IfLoc = ConsumeToken();  // eat the 'if'.
 
@@ -659,7 +677,8 @@
 ///       switch-statement:
 ///         'switch' '(' expression ')' statement
 /// [C++]   'switch' '(' condition ')' statement
-Parser::OwningStmtResult Parser::ParseSwitchStatement() {
+Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) {
+  // FIXME: Use attributes?
   assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
   SourceLocation SwitchLoc = ConsumeToken();  // eat the 'switch'.
 
@@ -734,7 +753,8 @@
 ///       while-statement: [C99 6.8.5.1]
 ///         'while' '(' expression ')' statement
 /// [C++]   'while' '(' condition ')' statement
-Parser::OwningStmtResult Parser::ParseWhileStatement() {
+Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) {
+  // FIXME: Use attributes?
   assert(Tok.is(tok::kw_while) && "Not a while stmt!");
   SourceLocation WhileLoc = Tok.getLocation();
   ConsumeToken();  // eat the 'while'.
@@ -805,7 +825,8 @@
 ///       do-statement: [C99 6.8.5.2]
 ///         'do' statement 'while' '(' expression ')' ';'
 /// Note: this lets the caller parse the end ';'.
-Parser::OwningStmtResult Parser::ParseDoStatement() {
+Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) {
+  // FIXME: Use attributes?
   assert(Tok.is(tok::kw_do) && "Not a do stmt!");
   SourceLocation DoLoc = ConsumeToken();  // eat the 'do'.
 
@@ -880,7 +901,8 @@
 /// [C++]   expression-statement
 /// [C++]   simple-declaration
 ///
-Parser::OwningStmtResult Parser::ParseForStatement() {
+Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) {
+  // FIXME: Use attributes?
   assert(Tok.is(tok::kw_for) && "Not a for stmt!");
   SourceLocation ForLoc = ConsumeToken();  // eat the 'for'.
 
@@ -937,8 +959,13 @@
     if (!C99orCXXorObjC)   // Use of C99-style for loops in C90 mode?
       Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
 
+    AttributeList *AttrList = 0;
+    if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+      AttrList = ParseCXX0XAttributes().AttrList;
+
     SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
-    DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd);
+    DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd,
+                                               AttrList);
     FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
 
     if (Tok.is(tok::semi)) {  // for (int x = 4;
@@ -1036,7 +1063,8 @@
 ///
 /// Note: this lets the caller parse the end ';'.
 ///
-Parser::OwningStmtResult Parser::ParseGotoStatement() {
+Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) {
+  // FIXME: Use attributes?
   assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
   SourceLocation GotoLoc = ConsumeToken();  // eat the 'goto'.
 
@@ -1069,7 +1097,8 @@
 ///
 /// Note: this lets the caller parse the end ';'.
 ///
-Parser::OwningStmtResult Parser::ParseContinueStatement() {
+Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) {
+  // FIXME: Use attributes?
   SourceLocation ContinueLoc = ConsumeToken();  // eat the 'continue'.
   return Actions.ActOnContinueStmt(ContinueLoc, CurScope);
 }
@@ -1080,7 +1109,8 @@
 ///
 /// Note: this lets the caller parse the end ';'.
 ///
-Parser::OwningStmtResult Parser::ParseBreakStatement() {
+Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) {
+  // FIXME: Use attributes?
   SourceLocation BreakLoc = ConsumeToken();  // eat the 'break'.
   return Actions.ActOnBreakStmt(BreakLoc, CurScope);
 }
@@ -1088,7 +1118,8 @@
 /// ParseReturnStatement
 ///       jump-statement:
 ///         'return' expression[opt] ';'
-Parser::OwningStmtResult Parser::ParseReturnStatement() {
+Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) {
+  // FIXME: Use attributes?
   assert(Tok.is(tok::kw_return) && "Not a return stmt!");
   SourceLocation ReturnLoc = ConsumeToken();  // eat the 'return'.
 
@@ -1164,7 +1195,7 @@
   }
   DeclSpec DS;
   SourceLocation Loc = Tok.getLocation();
-  ParseTypeQualifierListOpt(DS);
+  ParseTypeQualifierListOpt(DS, true, false);
 
   // GNU asms accept, but warn, about type-qualifiers other than volatile.
   if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
@@ -1372,7 +1403,8 @@
 ///       try-block:
 ///         'try' compound-statement handler-seq
 ///
-Parser::OwningStmtResult Parser::ParseCXXTryBlock() {
+Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) {
+  // FIXME: Add attributes?
   assert(Tok.is(tok::kw_try) && "Expected 'try'");
 
   SourceLocation TryLoc = ConsumeToken();
@@ -1394,11 +1426,17 @@
 Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
   if (Tok.isNot(tok::l_brace))
     return StmtError(Diag(Tok, diag::err_expected_lbrace));
-  OwningStmtResult TryBlock(ParseCompoundStatement());
+  // FIXME: Possible draft standard bug: attribute-specifier should be allowed?
+  OwningStmtResult TryBlock(ParseCompoundStatement(0));
   if (TryBlock.isInvalid())
     return move(TryBlock);
 
   StmtVector Handlers(Actions);
+  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+    CXX0XAttributeList Attr = ParseCXX0XAttributes();
+    Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+      << Attr.Range;
+  }
   if (Tok.isNot(tok::kw_catch))
     return StmtError(Diag(Tok, diag::err_expected_catch));
   while (Tok.is(tok::kw_catch)) {
@@ -1458,7 +1496,8 @@
   if (Tok.isNot(tok::l_brace))
     return StmtError(Diag(Tok, diag::err_expected_lbrace));
 
-  OwningStmtResult Block(ParseCompoundStatement());
+  // FIXME: Possible draft standard bug: attribute-specifier should be allowed?
+  OwningStmtResult Block(ParseCompoundStatement(0));
   if (Block.isInvalid())
     return move(Block);
 
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index e655ded..d2f13f2 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -192,6 +192,10 @@
 
   // Parse the declaration specifiers.
   ParsingDeclSpec DS(*this);
+
+  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+    DS.AddAttributes(ParseCXX0XAttributes().AttrList);
+
   ParseDeclarationSpecifiers(DS, TemplateInfo, AS);
 
   if (Tok.is(tok::semi)) {
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 7ac2977..dabd065 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -55,12 +55,11 @@
     // using-declaration
     // using-directive
   case tok::kw_using:
-    return true;
-  case tok::kw_static_assert:
     // static_assert-declaration
+  case tok::kw_static_assert:
     return true;
-  default:
     // simple-declaration
+  default:
     return isCXXSimpleDeclaration();
   }
 }
@@ -351,6 +350,89 @@
   return TPR == TPResult::True();
 }
 
+/// isCXX0XAttributeSpecifier - returns true if this is a C++0x
+/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is
+/// performed that will simply return true if a [[ is seen. Currently C++ has no
+/// syntactical ambiguities from this check, but it may inhibit error recovery.
+/// If CheckClosing is true, a check is made for closing ]] brackets.
+///
+/// If given, After is set to the token after the attribute-specifier so that
+/// appropriate parsing decisions can be made; it is left untouched if false is
+/// returned.
+///
+/// FIXME: If an error is in the closing ]] brackets, the program assumes
+/// the absence of an attribute-specifier, which can cause very yucky errors
+/// to occur.
+///
+/// [C++0x] attribute-specifier:
+///         '[' '[' attribute-list ']' ']'
+///
+/// [C++0x] attribute-list:
+///         attribute[opt]
+///         attribute-list ',' attribute[opt]
+///
+/// [C++0x] attribute:
+///         attribute-token attribute-argument-clause[opt]
+///
+/// [C++0x] attribute-token:
+///         identifier
+///         attribute-scoped-token
+///
+/// [C++0x] attribute-scoped-token:
+///         attribute-namespace '::' identifier
+///
+/// [C++0x] attribute-namespace:
+///         identifier
+///
+/// [C++0x] attribute-argument-clause:
+///         '(' balanced-token-seq ')'
+///
+/// [C++0x] balanced-token-seq:
+///         balanced-token
+///         balanced-token-seq balanced-token
+///
+/// [C++0x] balanced-token:
+///         '(' balanced-token-seq ')'
+///         '[' balanced-token-seq ']'
+///         '{' balanced-token-seq '}'
+///         any token but '(', ')', '[', ']', '{', or '}'
+bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing,
+                                        tok::TokenKind *After) {
+  if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
+    return false;
+  
+  // No tentative parsing if we don't need to look for ]]
+  if (!CheckClosing && !getLang().ObjC1)
+    return true;
+  
+  struct TentativeReverter {
+    TentativeParsingAction PA;
+
+    TentativeReverter (Parser& P)
+      : PA(P)
+    {}
+    ~TentativeReverter () {
+      PA.Revert();
+    }
+  } R(*this);
+
+  // Opening brackets were checked for above.
+  ConsumeBracket();
+  ConsumeBracket();
+
+  // SkipUntil will handle balanced tokens, which are guaranteed in attributes.
+  SkipUntil(tok::r_square, false);
+
+  if (Tok.isNot(tok::r_square))
+    return false;
+  ConsumeBracket();
+
+  if (After)
+    *After = Tok.getKind();
+
+  return true;
+}
+
 ///         declarator:
 ///           direct-declarator
 ///           ptr-operator declarator
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index a915274..e321564 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -355,7 +355,10 @@
     return true;
   }
 
-  Result = ParseExternalDeclaration();
+  CXX0XAttributeList Attr;
+  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+    Attr = ParseCXX0XAttributes();
+  Result = ParseExternalDeclaration(Attr);
   return false;
 }
 
@@ -396,7 +399,7 @@
 ///           ';'
 ///
 /// [C++0x/GNU] 'extern' 'template' declaration
-Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() {
+Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) {
   DeclPtrTy SingleDecl;
   switch (Tok.getKind()) {
   case tok::semi:
@@ -418,9 +421,13 @@
     // __extension__ silences extension warnings in the subexpression.
     ExtensionRAIIObject O(Diags);  // Use RAII to do this.
     ConsumeToken();
-    return ParseExternalDeclaration();
+    return ParseExternalDeclaration(Attr);
   }
   case tok::kw_asm: {
+    if (Attr.HasAttr)
+      Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
+        << Attr.Range;
+
     OwningExprResult Result(ParseSimpleAsm());
 
     ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
@@ -449,7 +456,7 @@
   case tok::code_completion:
     Actions.CodeCompleteOrdinaryName(CurScope);
     ConsumeToken();
-    return ParseExternalDeclaration();
+    return ParseExternalDeclaration(Attr);
   case tok::kw_using:
   case tok::kw_namespace:
   case tok::kw_typedef:
@@ -459,7 +466,7 @@
     // A function definition cannot start with a these keywords.
     {
       SourceLocation DeclEnd;
-      return ParseDeclaration(Declarator::FileContext, DeclEnd);
+      return ParseDeclaration(Declarator::FileContext, DeclEnd, Attr);
     }
   case tok::kw_extern:
     if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) {
@@ -477,7 +484,7 @@
 
   default:
     // We can't tell whether this is a function-definition or declaration yet.
-    return ParseDeclarationOrFunctionDefinition();
+    return ParseDeclarationOrFunctionDefinition(Attr.AttrList);
   }
 
   // This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -525,9 +532,13 @@
 /// [OMP]   threadprivate-directive                              [TODO]
 ///
 Parser::DeclGroupPtrTy
-Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
+Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr,
+                                             AccessSpecifier AS) {
   // Parse the common declaration-specifiers piece.
   ParsingDeclSpec DS(*this);
+  if (Attr)
+    DS.AddAttributes(Attr);
+
   ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
 
   // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
@@ -719,7 +730,7 @@
       // If attributes are present, parse them.
       if (Tok.is(tok::kw___attribute))
         // FIXME: attach attributes too.
-        AttrList = ParseAttributes();
+        AttrList = ParseGNUAttributes();
 
       // Ask the actions module to compute the type for this declarator.
       Action::DeclPtrTy Param =