[cfe-dev] Writing a tentative parser for C++0x attributes

Argyrios Kyrtzidis kyrtzidis at apple.com
Wed Aug 12 11:20:02 PDT 2009


Hi Sean,

Don't forget to do "Reply-all" so that cfe-dev is included.
Also, for future patches look into getting them attached instead of  
embedded into the email, so that they are easier to use.

About the patch, since attributes appear before statements &  
declarations, I suggest parsing them at
Parser::ParseStatementOrDeclaration() before going into the "stmt or  
decl" parsing part. That way you will parse them once
and then pass the AttributeList* to the statement parsing methods,  
instead of parsing them at each one.

Then for the decl/stmt ambiguity part, you only need to check for  
attributes in Parser::TryParseDeclarator().

-Argiris

On Aug 10, 2009, at 6:55 PM, Sean Hunt wrote:

> The patch is attached. The attached patch will successfully interpret
> attributes at the beginning of a declaration or in a class declaration
> ([[noreturn]] void foo() or struct bar [[final]]), it also implements
> the semantics on [[final]], which should carry over to the
> __attribute__(()) notation, but I haven't tested that.
>
> Try 'make test' to see the crashes; they occur as a result of the
> changes to isCXXDeclarationStatement.
>
> Sean Hunt
> Index: test/Sema/attr-noreturn.c
> ===================================================================
> --- test/Sema/attr-noreturn.c	(revision 78234)
> +++ test/Sema/attr-noreturn.c	(working copy)
> @@ -4,7 +4,7 @@
>
> static void __attribute__((noreturn)) f0(void) {
>   fatal();
> -} // expected-error {{function declared 'noreturn' should not  
> return}}
> +} // expected-warning {{function declared 'noreturn' should not  
> return}}
>
> // On K&R
> int f1() __attribute__((noreturn));
> @@ -15,14 +15,14 @@
>
> void f3() __attribute__((noreturn));
> void f3() {
> -  return;  // expected-error {{function 'f3' declared 'noreturn'  
> should not return}}
> +  return;  // expected-warning {{function 'f3' declared 'noreturn'  
> should not return}}
> }
>
> -#pragma clang diagnostic warning "-Winvalid-noreturn"
> +#pragma clang diagnostic warning "-Werror=invalid-noreturn"
>
> void f4() __attribute__((noreturn));
> void f4() {
> -  return;  // expected-warning {{function 'f4' declared 'noreturn'  
> should not return}}
> +  return;  // expected-error {{function 'f4' declared 'noreturn'  
> should not return}}
> }
>
> // PR4685Index: include/clang/Basic/DiagnosticSemaKinds.td
> ===================================================================
> --- include/clang/Basic/DiagnosticSemaKinds.td	(revision 78234)
> +++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
> @@ -472,6 +472,13 @@
>   "|class member|exception declaration|template parameter|block  
> literal}0">;
> def err_auto_var_requires_init : Error<
>   "declaration of variable %0 with type %1 requires an initializer">;
> +
> +// C++0x [[final]]
> +def err_final_function_overridden : Error<
> +  "declaration of '%0' overrides a function declared with  
> [[final]]">;
> +def err_final_base : Error<
> +  "'%0' cannot be used as a base class because it was declared with "
> +  "[[final]]">;
>
> // Objective-C++
> def err_objc_decls_may_only_appear_in_global_scope : Error<
> @@ -1974,10 +1981,10 @@
> def ext_return_has_void_expr : Extension<
>   "void %select{function|method}1 %0 should not return void  
> expression">;
> def warn_noreturn_function_has_return_expr : Warning<
> -  "function %0 declared 'noreturn' should not return">, DefaultError,
> +  "function %0 declared 'noreturn' should not return">,
>   InGroup<DiagGroup<"invalid-noreturn">>;
> def warn_falloff_noreturn_function : Warning<
> -  "function declared 'noreturn' should not return">, DefaultError,
> +  "function declared 'noreturn' should not return">,
>   InGroup<DiagGroup<"invalid-noreturn">>;
> def err_noreturn_block_has_return_expr : Error<
>   "block declared 'noreturn' should not return">;
> Index: include/clang/Basic/DiagnosticParseKinds.td
> ===================================================================
> --- include/clang/Basic/DiagnosticParseKinds.td	(revision 78234)
> +++ include/clang/Basic/DiagnosticParseKinds.td	(working copy)
> @@ -74,6 +74,7 @@
> def err_expected_lbrace : Error<"expected '{'">;
> def err_expected_lparen : Error<"expected '('">;
> def err_expected_rparen : Error<"expected ')'">;
> +def err_expected_lsquare : Error<"expected '['">;
> def err_expected_rsquare : Error<"expected ']'">;
> def err_expected_rbrace : Error<"expected '}'">;
> def err_expected_greater : Error<"expected '>'">;
> @@ -234,6 +235,12 @@
> def err_anon_type_definition : Error<
>   "declaration of anonymous %0 must be a definition">;
>
> +def err_cxx0x_attribute_forbids_arguments : Error<
> +  "C++0x forbids the attribute '%0' from having an argument list">;
> +def err_cxx0x_attribute_requires_arguments : Error<
> +  "C++0x requires that the attribute '%0' has an argument list">;
> +def err_attributes_on_using_declaration : Error<
> +  "attributes are not allowed on using-declarations">;
>
> /// C++ Templates
> def err_expected_template : Error<"expected template">;
> Index: include/clang/AST/Attr.h
> ===================================================================
> --- include/clang/AST/Attr.h	(revision 78234)
> +++ include/clang/AST/Attr.h	(working copy)
> @@ -54,7 +54,8 @@
>     DLLImport,
>     Deprecated,
>     Destructor,
> -    FastCall,
> +    FastCall,
> +    Final,
>     Format,
>     FormatArg,
>     GNUInline,
> @@ -288,6 +289,7 @@
> DEF_SIMPLE_ATTR(NoReturn);
> DEF_SIMPLE_ATTR(AnalyzerNoReturn);
> DEF_SIMPLE_ATTR(Deprecated);
> +DEF_SIMPLE_ATTR(Final);
>
> class SectionAttr : public Attr {
>   std::string Name;
> Index: include/clang/Parse/Parser.h
> ===================================================================
> --- include/clang/Parse/Parser.h	(revision 78234)
> +++ include/clang/Parse/Parser.h	(working copy)
> @@ -910,7 +910,8 @@
>   DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation  
> &DeclEnd);
>   DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context,
>                                         SourceLocation &DeclEnd,
> -                                        bool RequireSemi = true);
> +                                        bool RequireSemi = true,
> +                                        AttributeList *Attr = 0);
>   DeclPtrTy ParseDeclarationAfterDeclarator(Declarator &D,
>                const ParsedTemplateInfo &TemplateInfo =  
> ParsedTemplateInfo());
>   DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator 
> (Declarator &D);
> @@ -1069,7 +1070,8 @@
>   void ParseBlockId();
>   // EndLoc, if non-NULL, is filled with the location of the last  
> token of
>   // the attribute list.
> -  AttributeList *ParseAttributes(SourceLocation *EndLoc = 0);
> +  AttributeList *ParseCXX0XAttributes(SourceLocation *EndLoc = 0);
> +  AttributeList *ParseGNUAttributes(SourceLocation *EndLoc = 0);
>   AttributeList *ParseMicrosoftDeclSpec(AttributeList* CurrAttr = 0);
>   AttributeList *ParseMicrosoftTypeAttributes(AttributeList*  
> CurrAttr = 0);
>   void ParseTypeofSpecifier(DeclSpec &DS);
> @@ -1121,10 +1123,13 @@
>   // 
> = 
> = 
> =-------------------------------------------------------------------- 
> ===//
>   // C++ 7: Declarations [dcl.dcl]
>
> +  bool isCXX0XAttributeSpecifier(Token **After = 0);
> +
>   DeclPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd);
>   DeclPtrTy ParseLinkage(unsigned Context);
>   DeclPtrTy ParseUsingDirectiveOrDeclaration(unsigned Context,
> -                                             SourceLocation  
> &DeclEnd);
> +                                             SourceLocation &DeclEnd,
> +                                             AttributeList *Attr =  
> 0);
>   DeclPtrTy ParseUsingDirective(unsigned Context, SourceLocation  
> UsingLoc,
>                                 SourceLocation &DeclEnd);
>   DeclPtrTy ParseUsingDeclaration(unsigned Context, SourceLocation  
> UsingLoc,
> Index: include/clang/Parse/AttributeList.h
> ===================================================================
> --- include/clang/Parse/AttributeList.h	(revision 78234)
> +++ include/clang/Parse/AttributeList.h	(working copy)
> @@ -33,19 +33,22 @@
> class AttributeList {
>   IdentifierInfo *AttrName;
>   SourceLocation AttrLoc;
> +  IdentifierInfo *ScopeName;
> +  SourceLocation ScopeLoc;
>   IdentifierInfo *ParmName;
>   SourceLocation ParmLoc;
>   ActionBase::ExprTy **Args;
>   unsigned NumArgs;
>   AttributeList *Next;
> -  bool DeclspecAttribute;
> +  bool DeclspecAttribute, CXX0XAttribute;
>   AttributeList(const AttributeList &); // DO NOT IMPLEMENT
>   void operator=(const AttributeList &); // DO NOT IMPLEMENT
> public:
>   AttributeList(IdentifierInfo *AttrName, SourceLocation AttrLoc,
> +                IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
>                 IdentifierInfo *ParmName, SourceLocation ParmLoc,
>                 ActionBase::ExprTy **args, unsigned numargs,
> -                AttributeList *Next, bool declspec = false);
> +                AttributeList *Next, bool declspec = false, bool  
> cxx0x = false);
>   ~AttributeList();
>
>   enum Kind {              // Please keep this list alphabetized.
> @@ -57,6 +60,7 @@
>     AT_analyzer_noreturn,
>     AT_annotate,
>     AT_blocks,
> +    AT_carries_dependency,
>     AT_cleanup,
>     AT_const,
>     AT_constructor,
> @@ -66,6 +70,7 @@
>     AT_dllimport,
>     AT_ext_vector_type,
>     AT_fastcall,
> +    AT_final,
>     AT_format,
>     AT_format_arg,
>     AT_gnu_inline,
> @@ -104,9 +109,16 @@
>
>   IdentifierInfo *getName() const { return AttrName; }
>   SourceLocation getLoc() const { return AttrLoc; }
> +
> +  bool hasScope() const { return ScopeName; }
> +  IdentifierInfo *getScopeName() const { return ScopeName; }
> +  SourceLocation getScopeLoc() const { return ScopeLoc; }
> +
>   IdentifierInfo *getParameterName() const { return ParmName; }
> +
>   bool isDeclspecAttribute() const { return DeclspecAttribute; }
> -
> +  bool isCXX0XAttribute() const { return CXX0XAttribute; }
> +
>   Kind getKind() const { return getKind(getName()); }
>   static Kind getKind(const IdentifierInfo *Name);
>
> Index: lib/Sema/SemaDeclCXX.cpp
> ===================================================================
> --- lib/Sema/SemaDeclCXX.cpp	(revision 78234)
> +++ lib/Sema/SemaDeclCXX.cpp	(working copy)
> @@ -3440,6 +3454,19 @@
>                                   New->getLocation());
> }
>
> +bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl  
> *New,
> +                                             const CXXMethodDecl  
> *Old)
> +{
> +  if (Old->hasAttr<FinalAttr>()) {
> +    Diag(New->getLocation(), diag::err_final_function_overridden)
> +      << New->getDeclName();
> +    Diag(Old->getLocation(), diag::note_overridden_virtual_function);
> +    return true;
> +  }
> +
> +  return false;
> +}
> +
> /// ActOnCXXEnterDeclInitializer - Invoked when we are about to  
> parse an
> /// initializer for the declaration 'Dcl'.
> /// After this method is called, according to [C++ 3.4.1p13], if  
> 'Dcl' is a
> Index: lib/Sema/SemaDeclAttr.cpp
> ===================================================================
> --- lib/Sema/SemaDeclAttr.cpp	(revision 78234)
> +++ lib/Sema/SemaDeclAttr.cpp	(working copy)
> @@ -1680,6 +1680,27 @@
>   d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue()));
> }
>
> +static void HandleFinalAttr(Decl *d, const AttributeList &Attr,  
> Sema &S) {
> +  // check the attribute arguments.
> +  if (Attr.getNumArgs() != 0) {
> +    S.Diag(Attr.getLoc(),  
> diag::err_attribute_wrong_number_arguments) << 0;
> +    return;
> +  }
> +
> +  // FIXME: As a C++0x standard attribute, this should error, not  
> warn.
> +  //        Also, the diagnostic sucks, but that will need changing  
> anyways.
> +  if (!isa<CXXRecordDecl>(d)
> +   && (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual 
> ())) {
> +    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
> +      << Attr.getName() << 0 /*function*/;
> +    return;
> +  }
> +
> +  // FIXME: Check that it's not specified more than once in an  
> attribute-specifier
> +
> +  d->addAttr(::new (S.Context) FinalAttr());
> +}
> +
> // 
> = 
> = 
> = 
> ----------------------------------------------------------------------= 
> ==//
> // Checker-specific attribute handlers.
> // 
> = 
> = 
> = 
> ----------------------------------------------------------------------= 
> ==//
> @@ -1725,7 +1746,8 @@
>
> /// ProcessDeclAttribute - Apply the specific attribute to the  
> specified decl if
> /// the attribute applies to decls.  If the attribute is a type  
> attribute, just
> -/// silently ignore it.
> +/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x  
> attribute to
> +/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
> static void ProcessDeclAttribute(Scope *scope, Decl *D,
>                                  const AttributeList &Attr, Sema &S) {
>   if (Attr.isDeclspecAttribute())
> @@ -1754,9 +1776,10 @@
>     HandleExtVectorTypeAttr(scope, D, Attr, S);
>     break;
>   case AttributeList::AT_fastcall:    HandleFastCallAttr  (D, Attr,  
> S); break;
> +  case AttributeList::AT_final:       HandleFinalAttr     (D, Attr,  
> S); break;
>   case AttributeList::AT_format:      HandleFormatAttr    (D, Attr,  
> S); break;
>   case AttributeList::AT_format_arg:  HandleFormatArgAttr (D, Attr,  
> S); break;
> -  case AttributeList::AT_gnu_inline:  HandleGNUInlineAttr(D, Attr,  
> S); break;
> +  case AttributeList::AT_gnu_inline:  HandleGNUInlineAttr (D, Attr,  
> S); break;
>   case AttributeList::AT_mode:        HandleModeAttr      (D, Attr,  
> S); break;
>   case AttributeList::AT_nonnull:     HandleNonNullAttr   (D, Attr,  
> S); break;
>   case AttributeList::AT_noreturn:    HandleNoReturnAttr  (D, Attr,  
> S); break;
> Index: lib/Sema/SemaDecl.cpp
> ===================================================================
> --- lib/Sema/SemaDecl.cpp	(revision 78234)
> +++ lib/Sema/SemaDecl.cpp	(working copy)
> @@ -2512,8 +2513,11 @@
>            E = Paths.found_decls_end(); I != E; ++I) {
>         if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
>           if (!CheckOverridingFunctionReturnType(NewMD, OldMD) &&
> -              !CheckOverridingFunctionExceptionSpec(NewMD, OldMD))
> +              !CheckOverridingFunctionExceptionSpec(NewMD, OldMD) &&
> +              !CheckOverridingFunctionAttributes(NewMD, OldMD))
>             NewMD->addOverriddenMethod(OldMD);
> +          else
> +            return 0;
>         }
>       }
>     }
> Index: lib/Sema/Sema.h
> ===================================================================
> --- lib/Sema/Sema.h	(revision 78234)
> +++ lib/Sema/Sema.h	(working copy)
> @@ -2058,6 +2058,11 @@
>   bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
>                                             const CXXMethodDecl *Old);
>
> +  /// CheckOverridingFunctionAttributes - Checks whether attributes  
> are
> +  /// incompatible or prevent overriding.
> +  bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
> +                                         const CXXMethodDecl *Old);
> +
>   // 
> = 
> = 
> =-------------------------------------------------------------------- 
> ===//
>   // C++ Access Control
>   //
> Index: lib/Parse/ParseTentative.cpp
> ===================================================================
> --- lib/Parse/ParseTentative.cpp	(revision 78234)
> +++ lib/Parse/ParseTentative.cpp	(working copy)
> @@ -47,6 +47,8 @@
> ///                 namespace-name ';'
> ///
> bool Parser::isCXXDeclarationStatement() {
> +  TentativeParsingAction PA(*this);
> +
>   switch (Tok.getKind()) {
>     // asm-definition
>   case tok::kw_asm:
> @@ -55,13 +57,33 @@
>     // using-declaration
>     // using-directive
>   case tok::kw_using:
> -    return true;
> +    // static_assert-declaration
>   case tok::kw_static_assert:
> -    // static_assert-declaration
> +    PA.Revert();
>     return true;
> +    // Might be a lambda or an attribute, or even an Obj-C message  
> send.
> +  case tok::l_square:
> +    // Pre-C++0x, there are no attributes, and a single [ means a  
> lambda.
> +    if (!getLang().CPlusPlus0x || !NextToken().is(tok::l_square)) {
> +      PA.Revert();
> +      return false;
> +    }
> +
> +    ConsumeBracket();
> +    ConsumeBracket();
> +    SkipUntil(tok::r_square);
> +    // Objective-C can't follow this up with another ]
> +    if (!Tok.is(tok::r_square)) {
> +      PA.Revert();
> +      return false;
> +    }
> +    ConsumeBracket();
> +    // Fall-through
>   default:
>     // simple-declaration
> -    return isCXXSimpleDeclaration();
> +    bool Result = isCXXSimpleDeclaration();
> +    PA.Revert();
> +    return Result;
>   }
> }
>
> @@ -351,6 +373,83 @@
>   return TPR == TPResult::True();
> }
>
> +/// isCXX0XAttributeSpecifier - returns true if this is a C++0x
> +/// attribute-specifier. 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.
> +///
> +/// This does not do a full check for an attribute-specifier, as  
> [[]] is
> +/// unique within the langague and internal parse errors should be  
> saved
> +/// for ParseCXX0XAttributes, rather than getting an "unexpected ["  
> or the
> +/// like.
> +///
> +/// FIXME: If an error is in the closing ]] brackets, the program  
> assumes
> +/// the absence of an attribute-specifier, which causes 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 (Token **After) {
> +  struct TentativeReverter {
> +    TentativeParsingAction PA;
> +
> +    TentativeReverter (Parser& P)
> +      : PA(P)
> +    {}
> +    ~TentativeReverter () {
> +      PA.Revert();
> +    }
> +  } R(*this);
> +
> +  if (Tok.isNot(tok::l_square))
> +    return false;
> +  ConsumeBracket();
> +  if (Tok.isNot(tok::l_square))
> +    return false;
> +  ConsumeBracket();
> +
> +  SkipUntil(tok::r_square, false);
> +
> +  if (Tok.isNot(tok::r_square))
> +    return false;
> +  ConsumeBracket();
> +
> +  if (After)
> +    *After = &Tok;
> +
> +  return true;
> +}
> +
> ///         declarator:
> ///           direct-declarator
> ///           ptr-operator declarator
> Index: lib/Parse/AttributeList.cpp
> ===================================================================
> --- lib/Parse/AttributeList.cpp	(revision 78234)
> +++ lib/Parse/AttributeList.cpp	(working copy)
> @@ -16,11 +16,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;
> @@ -66,6 +68,8 @@
>   case 5:
>     if (!memcmp(Str, "alias", 5)) return AT_alias;
>     if (!memcmp(Str, "const", 5)) return AT_const;
> +    if (!memcmp(Str, "final", 5)) return AT_final;
> +    if (!memcmp(Str, "align", 5)) return AT_aligned;
>     break;
>   case 6:
>     if (!memcmp(Str, "packed", 6)) return AT_packed;
> @@ -132,11 +136,12 @@
>     break;
>   case 18:
>     if (!memcmp(Str, "warn_unused_result", 18)) return  
> AT_warn_unused_result;
> +    if (!memcmp(Str, "carries_dependency", 18)) return  
> AT_carries_dependency;
>     break;
>   case 19:
>     if (!memcmp(Str, "ns_returns_retained", 19)) return  
> AT_ns_returns_retained;
>     if (!memcmp(Str, "cf_returns_retained", 19)) return  
> AT_cf_returns_retained;
> -    break;
> +    break;
>   case 20:
>     if (!memcmp(Str, "reqd_work_group_size", 20)) return  
> AT_reqd_wg_size;
>   case 22:
> Index: lib/Parse/ParseDecl.cpp
> ===================================================================
> --- lib/Parse/ParseDecl.cpp	(revision 78234)
> +++ lib/Parse/ParseDecl.cpp	(working copy)
> @@ -44,8 +44,135 @@
>   return Actions.ActOnTypeName(CurScope, DeclaratorInfo);
> }
>
> -/// ParseAttributes - Parse a non-empty attributes list.
> +/// ParseCXX0XAttributes - Parse a C++0x attribute-specifier.  
> Currently only
> +/// parses standard attributes as the syntax is in some ways more  
> permitting and
> +/// in some ways more restrictive than GNU.
> ///
> +/// [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 '}'
> +AttributeList *Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) {
> +  assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
> +      && "Not a C++0x attribute list");
> +
> +  SourceLocation Loc;
> +  AttributeList *CurrAttr = 0;
> +
> +  ConsumeBracket();
> +  ConsumeBracket();
> +
> +  while (Tok.is(tok::identifier) || Tok.is(tok::comma)) {
> +    // attribute not present
> +    if (Tok.is(tok::comma)) {
> +      ConsumeToken();
> +      continue;
> +    }
> +
> +    IdentifierInfo *ScopeName = 0;
> +    SourceLocation ScopeLoc;
> +    // scoped attribute
> +    if (NextToken().is(tok::coloncolon)) {
> +      ScopeName = Tok.getIdentifierInfo();
> +      ScopeLoc = ConsumeToken();
> +      // consume ::
> +      Loc = ConsumeToken();
> +
> +      if (!Tok.is(tok::identifier)) {
> +        Diag(Loc, diag::err_expected_ident);
> +        SkipUntil(tok::r_paren, tok::comma, true, true);
> +        continue;
> +      }
> +    }
> +
> +    IdentifierInfo *AttrName = Tok.getIdentifierInfo();
> +    SourceLocation 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(SourceLocation(),  
> diag::err_cxx0x_attribute_forbids_arguments);
> +            break;
> +          }
> +
> +          CurrAttr = new AttributeList(AttrName, AttrLoc, 0, AttrLoc,
> +                                       0, SourceLocation(), 0, 0,  
> CurrAttr);
> +          AttrParsed = true;
> +          break;
> +        }
> +
> +        // One argument; must be a type-id or assignment-expression
> +        case AttributeList::AT_aligned:
> +          if (!Tok.is(tok::l_paren)) {
> +            Diag(SourceLocation(),  
> diag::err_cxx0x_attribute_requires_arguments);
> +            break;
> +          }
> +
> +          /*Loc = ConsumeParen();
> +
> +          OwningExprResult ArgExpr;
> +
> +          if (isTypeIdInParens)
> +            ArgExpr = ParseTypeName();
> +          else
> +            ArgExpr = ParseAssignmentExpression();*/
> +
> +        // Silence warnings
> +        default: break;
> +      }
> +    }
> +
> +    // Skip the entire parameter clause, if any
> +    if (!AttrParsed && Tok.is(tok::r_paren))
> +      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);
> +
> +  return CurrAttr;
> +}
> +/// ParseGNUAttributes - Parse a non-empty attributes list.
> +///
> /// [GNU] attributes:
> ///         attribute
> ///         attributes attribute
> @@ -80,8 +207,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;
>
> @@ -120,7 +247,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();
> @@ -144,8 +271,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
> @@ -154,7 +283,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:
> @@ -174,7 +303,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();
> @@ -202,20 +331,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);
>     }
> @@ -253,15 +383,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))
> @@ -280,7 +410,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;
> @@ -305,24 +435,32 @@
> Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
>                                                 SourceLocation  
> &DeclEnd) {
>   DeclPtrTy SingleDecl;
> -  switch (Tok.getKind()) {
> -  case tok::kw_template:
> -  case tok::kw_export:
> -    SingleDecl = ParseDeclarationStartingWithTemplate(Context,  
> DeclEnd);
> -    break;
> -  case tok::kw_namespace:
> -    SingleDecl = ParseNamespace(Context, DeclEnd);
> -    break;
> -  case tok::kw_using:
> -    SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd);
> -    break;
> -  case tok::kw_static_assert:
> -    SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
> -    break;
> -  default:
> -    return ParseSimpleDeclaration(Context, DeclEnd);
> +  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
> +    AttributeList *Attr = ParseCXX0XAttributes();
> +
> +    if (Tok.is(tok::kw_using))
> +      SingleDecl = ParseUsingDirectiveOrDeclaration(Context,  
> DeclEnd, Attr);
> +    else
> +      return ParseSimpleDeclaration(Context, DeclEnd, Attr);
> +  } else {
> +    switch (Tok.getKind()) {
> +    case tok::kw_template:
> +    case tok::kw_export:
> +      SingleDecl = ParseDeclarationStartingWithTemplate(Context,  
> DeclEnd);
> +      break;
> +    case tok::kw_namespace:
> +      SingleDecl = ParseNamespace(Context, DeclEnd);
> +      break;
> +    case tok::kw_using:
> +      SingleDecl = ParseUsingDirectiveOrDeclaration(Context,  
> DeclEnd);
> +      break;
> +    case tok::kw_static_assert:
> +      SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
> +      break;
> +    default:
> +      return ParseSimpleDeclaration(Context, DeclEnd);
> +    }
>   }
> -
>   // This routine returns a DeclGroup, if the thing we parsed only  
> contains a
>   // single decl, convert it now.
>   return Actions.ConvertDeclToDeclGroup(SingleDecl);
> @@ -337,9 +475,12 @@
> /// declaration.
> Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned  
> Context,
>                                                       SourceLocation  
> &DeclEnd,
> -                                                      bool  
> RequireSemi) {
> +                                                      bool  
> RequireSemi,
> +                                                      AttributeList  
> *Attr) {
>   // Parse the common declaration-specifiers piece.
>   DeclSpec DS;
> +  if (Attr)
> +    DS.AddAttributes(Attr);
>   ParseDeclarationSpecifiers(DS);
>
>   // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum  
> { X };"
> @@ -414,7 +555,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);
>   }
>
> @@ -520,7 +661,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);
>     }
>
> @@ -893,7 +1034,7 @@
>
>     // GNU attributes support.
>     case tok::kw___attribute:
> -      DS.AddAttributes(ParseAttributes());
> +      DS.AddAttributes(ParseGNUAttributes());
>       continue;
>
>     // Microsoft declspec support.
> @@ -1424,7 +1565,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);
>     }
>
> @@ -1442,7 +1583,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);
>       Fields.back().D.AddAttributes(AttrList, Loc);
>     }
>   }
> @@ -1544,7 +1685,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(),
> @@ -1574,7 +1715,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)) {
> @@ -1706,7 +1847,7 @@
>   Action::AttrTy *AttrList = 0;
>   // If attributes exist after the identifier list, parse them.
>   if (Tok.is(tok::kw___attribute))
> -    AttrList = ParseAttributes(); // FIXME: where do they do?
> +    AttrList = ParseGNUAttributes(); // FIXME: where do they do?
>
>   EnumScope.Exit();
>   Actions.ActOnTagFinishDefinition(CurScope, EnumDecl, RBraceLoc);
> @@ -1951,7 +2092,7 @@
>       goto DoneWithTypeQuals;
>     case tok::kw___attribute:
>       if (AttributesAllowed) {
> -        DS.AddAttributes(ParseAttributes());
> +        DS.AddAttributes(ParseGNUAttributes());
>         continue; // do *not* consume the next token!
>       }
>       // otherwise, FALL THROUGH!
> @@ -2338,7 +2479,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.
> @@ -2540,7 +2681,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);
>     }
>
> Index: lib/Parse/ParseObjc.cpp
> ===================================================================
> --- lib/Parse/ParseObjc.cpp	(revision 78234)
> +++ lib/Parse/ParseObjc.cpp	(working copy)
> @@ -696,7 +696,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);
>     return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(),
> @@ -725,7 +725,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.
> @@ -769,7 +769,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();
> Index: lib/Parse/ParseExpr.cpp
> ===================================================================
> --- lib/Parse/ParseExpr.cpp	(revision 78234)
> +++ lib/Parse/ParseExpr.cpp	(working copy)
> @@ -1440,7 +1441,7 @@
>
>   if (Tok.is(tok::kw___attribute)) {
>     SourceLocation Loc;
> -    AttributeList *AttrList = ParseAttributes(&Loc);
> +    AttributeList *AttrList = ParseGNUAttributes(&Loc);
>     DeclaratorInfo.AddAttributes(AttrList, Loc);
>   }
>
> @@ -1502,7 +1503,7 @@
>
>     if (Tok.is(tok::kw___attribute)) {
>       SourceLocation Loc;
> -      AttributeList *AttrList = ParseAttributes(&Loc);
> +      AttributeList *AttrList = ParseGNUAttributes(&Loc);
>       ParamInfo.AddAttributes(AttrList, Loc);
>     }
>
> @@ -1522,7 +1523,7 @@
>
>     if (Tok.is(tok::kw___attribute)) {
>       SourceLocation Loc;
> -      AttributeList *AttrList = ParseAttributes(&Loc);
> +      AttributeList *AttrList = ParseGNUAttributes(&Loc);
>       ParamInfo.AddAttributes(AttrList, Loc);
>     }
>
> Index: lib/Parse/ParseStmt.cpp
> ===================================================================
> --- lib/Parse/ParseStmt.cpp	(revision 78234)
> +++ lib/Parse/ParseStmt.cpp	(working copy)
> @@ -213,7 +213,7 @@
>   Action::AttrTy *AttrList = 0;
>   if (Tok.is(tok::kw___attribute))
>     // TODO: save these somewhere.
> -    AttrList = ParseAttributes();
> +    AttrList = ParseGNUAttributes();
>
>   OwningStmtResult SubStmt(ParseStatement());
>
> Index: lib/Parse/ParseDeclCXX.cpp
> ===================================================================
> --- lib/Parse/ParseDeclCXX.cpp	(revision 78234)
> +++ lib/Parse/ParseDeclCXX.cpp	(working copy)
> @@ -63,7 +63,7 @@
>     attrTok = Tok;
>
>     // FIXME: save these somewhere.
> -    AttrList = ParseAttributes();
> +    AttrList = ParseGNUAttributes();
>   }
>
>   if (Tok.is(tok::equal)) {
> @@ -182,7 +182,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,
> +                                                     AttributeList  
> *Attr) {
>   assert(Tok.is(tok::kw_using) && "Not using token");
>
>   // Eat 'using'.
> @@ -192,6 +193,11 @@
>     // Next token after 'using' is 'namespace' so it must be using- 
> directive
>     return ParseUsingDirective(Context, UsingLoc, DeclEnd);
>
> +  // FIXME: All callers with AttrributeLists should probably  
> instead call
> +  //        ParseUsingDirective directly rather than forward  
> through here.
> +  if (Attr)
> +    Diag(SourceLocation(),  
> diag::err_attributes_on_using_declaration);
> +
>   // Otherwise, it must be using-declaration.
>   return ParseUsingDeclaration(Context, UsingLoc, DeclEnd);
> }
> @@ -237,7 +243,7 @@
>
>   // Parse (optional) attributes (most likely GNU strong-using  
> extension).
>   if (Tok.is(tok::kw___attribute))
> -    AttrList = ParseAttributes();
> +    AttrList = ParseGNUAttributes();
>
>   // Eat ';'.
>   DeclEnd = Tok.getLocation();
> @@ -315,7 +321,7 @@
>
>   // Parse (optional) attributes (most likely GNU strong-using  
> extension).
>   if (Tok.is(tok::kw___attribute))
> -    AttrList = ParseAttributes();
> +    AttrList = ParseGNUAttributes();
>
>   // Eat ';'.
>   DeclEnd = Tok.getLocation();
> @@ -526,7 +532,7 @@
>   AttributeList *Attr = 0;
>   // If attributes exist after tag, parse them.
>   if (Tok.is(tok::kw___attribute))
> -    Attr = ParseAttributes();
> +    Attr = ParseGNUAttributes();
>
>   // If declspecs exist after tag, parse them.
>   if (Tok.is(tok::kw___declspec))
> @@ -567,18 +573,38 @@
>     }
>   }
>
> +  Token *AfterTok = &Tok;
> +  bool HasAttr = false;
> +
> +  // Check for the optional attribute-specifier (C++0x only).
> +  if (getLang().CPlusPlus0x)
> +    HasAttr = isCXX0XAttributeSpecifier(&AfterTok);
> +
>   // There are three options here.  If we have 'struct foo;', then
>   // this is a forward declaration.  If we have 'struct foo {...' or
> -  // 'struct foo :...' then this is a definition. Otherwise we have
> -  // something like 'struct foo xyz', a reference.
> +  // 'struct foo :...' or 'struct foo [[...]]', then this is a  
> definition.
> +  // Otherwise we have something like 'struct foo xyz', a  
> reference. We have to
> +  // be careful with the attribute-list as it may actually be in a  
> type-id with
> +  // an array declarator.
>   Action::TagUseKind TUK;
> -  if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is 
> (tok::colon)))
> +  if (AfterTok->is(tok::l_brace)
> +   || (getLang().CPlusPlus && AfterTok->is(tok::colon)))
>     TUK = Action::TUK_Definition;
> -  else if (Tok.is(tok::semi) && !DS.isFriendSpecified())
> +  else if (AfterTok->is(tok::semi) && !DS.isFriendSpecified())
>     TUK = Action::TUK_Declaration;
>   else
>     TUK = Action::TUK_Reference;
>
> +  // We parse the attribute-specifier on a definition; otherwise it  
> appertains
> +  // to something else so we leave it in the stream.
> +  if (HasAttr && TUK == Action::TUK_Definition) {
> +    AttributeList *NewAttr = ParseCXX0XAttributes();
> +    if (Attr)
> +      Attr->addAttributeList(NewAttr);
> +    else
> +      Attr = NewAttr;
> +  }
> +
>   if (!Name && !TemplateId && TUK != Action::TUK_Definition) {
>     // We have a declaration or reference to an anonymous class.
>     Diag(StartLoc, diag::err_anon_type_definition)
> @@ -931,6 +957,17 @@
>     return ParseCXXClassMemberDeclaration(AS);
>   }
>
> +  AttributeList *Attr = 0;
> +  // Optional C++0x attribute-specifier
> +  if (getLang().CPlusPlus0x && Tok.is(tok::l_square)) {
> +    if (!NextToken().is(tok::l_square)) {
> +        Diag(SourceLocation(), diag::err_expected_lsquare);
> +        SkipUntil(tok::r_square, false);
> +    } else {
> +      Attr = ParseCXX0XAttributes();
> +    }
> +  }
> +
>   if (Tok.is(tok::kw_using)) {
>     // Eat 'using'.
>     SourceLocation UsingLoc = ConsumeToken();
> @@ -951,6 +988,8 @@
>   // decl-specifier-seq:
>   // Parse the common declaration-specifiers piece.
>   DeclSpec DS;
> +  if (Attr)
> +    DS.AddAttributes(Attr);
>   ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
>
>   if (Tok.is(tok::semi)) {
> @@ -1059,7 +1098,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);
>     }
>
> @@ -1097,7 +1136,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);
>     }
>
> @@ -1193,7 +1232,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);
> Index: lib/Parse/ParseExprCXX.cpp
> ===================================================================
> --- lib/Parse/ParseExprCXX.cpp	(revision 78234)
> +++ lib/Parse/ParseExprCXX.cpp	(working copy)
> @@ -564,7 +564,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);
>   }
>
> Index: lib/Parse/Parser.cpp
> ===================================================================
> --- lib/Parse/Parser.cpp	(revision 78234)
> +++ lib/Parse/Parser.cpp	(working copy)
> @@ -392,8 +392,9 @@
>   DeclPtrTy SingleDecl;
>   switch (Tok.getKind()) {
>   case tok::semi:
> -    Diag(Tok, diag::ext_top_level_semi)
> -      << CodeModificationHint::CreateRemoval(SourceRange 
> (Tok.getLocation()));
> +    if (!getLang().CPlusPlus0x)
> +      Diag(Tok, diag::ext_top_level_semi)
> +        << CodeModificationHint::CreateRemoval(SourceRange 
> (Tok.getLocation()));
>     ConsumeToken();
>     // TODO: Invoke action for top-level semicolon.
>     return DeclGroupPtrTy();
> @@ -500,6 +501,23 @@
> Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) {
>   // Parse the common declaration-specifiers piece.
>   DeclSpec DS;
> +
> +  // Optional C++0x attribute
> +  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
> +    AttributeList *Attr = ParseCXX0XAttributes();
> +
> +    // We might actually have a using directive, since we can't  
> disambiguate
> +    // until after the attributes are parsed.
> +    if (Tok.is(tok::kw_using)) {
> +        SourceLocation Loc;
> +      return Actions.ConvertDeclToDeclGroup(
> +                     ParseUsingDirectiveOrDeclaration 
> (Declarator::FileContext,
> +                                                      Loc, Attr));
> +    }
> +
> +    DS.AddAttributes(Attr);
> +  }
> +
>   ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
>
>   // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum  
> { X };"
> @@ -726,7 +744,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 =




More information about the cfe-dev mailing list