diff options
author | Alexis Hunt <alercah@gmail.com> | 2009-11-21 08:43:09 +0000 |
---|---|---|
committer | Alexis Hunt <alercah@gmail.com> | 2009-11-21 08:43:09 +0000 |
commit | 96d5c76498b26bdf6e6ded4f166085a11c1738a4 (patch) | |
tree | 780685d28c9cf8c2e472913f98b85ff4a941bbc4 | |
parent | a33fc86be3855165bc41e355378fb27acb327930 (diff) | |
download | bcm5719-llvm-96d5c76498b26bdf6e6ded4f166085a11c1738a4.tar.gz bcm5719-llvm-96d5c76498b26bdf6e6ded4f166085a11c1738a4.zip |
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)
llvm-svn: 89543
26 files changed, 802 insertions, 164 deletions
diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index b36ff122937..35f9b330ddd 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -59,6 +59,7 @@ public: Deprecated, Destructor, FastCall, + Final, Format, FormatArg, GNUInline, @@ -184,12 +185,24 @@ public: class AlignedAttr : public Attr { unsigned Alignment; public: - AlignedAttr(unsigned alignment) : Attr(Aligned), Alignment(alignment) {} + AlignedAttr(unsigned alignment) + : Attr(Aligned), Alignment(alignment) {} /// getAlignment - The specified alignment in bits. unsigned getAlignment() const { return Alignment; } + + /// getMaxAlignment - Get the maximum alignment of attributes on this list. + unsigned getMaxAlignment() const { + const AlignedAttr *Next = getNext<AlignedAttr>(); + if (Next) + return std::max(Next->getMaxAlignment(), Alignment); + else + return Alignment; + } - virtual Attr* clone(ASTContext &C) const { return ::new (C) AlignedAttr(Alignment); } + virtual Attr* clone(ASTContext &C) const { + return ::new (C) AlignedAttr(Alignment); + } // Implement isa/cast/dyncast/etc. static bool classof(const Attr *A) { @@ -304,6 +317,7 @@ DEF_SIMPLE_ATTR(Malloc); DEF_SIMPLE_ATTR(NoReturn); DEF_SIMPLE_ATTR(AnalyzerNoReturn); DEF_SIMPLE_ATTR(Deprecated); +DEF_SIMPLE_ATTR(Final); class SectionAttr : public Attr { std::string Name; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 3a8c5bf8f1b..890c6394317 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -75,6 +75,7 @@ def err_expected_ident_lbrace : Error<"expected identifier or '{'">; 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 '>'">; @@ -245,6 +246,11 @@ def err_operator_missing_type_specifier : Error< def err_anon_type_definition : Error< "declaration of anonymous %0 must be a definition">; +def err_cxx0x_attribute_forbids_arguments : Error< + "C++0x attribute '%0' cannot have an argument list">; +def err_cxx0x_attribute_requires_arguments : Error< + "C++0x attribute '%0' must have an argument list">; +def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; /// C++ Templates def err_expected_template : Error<"expected template">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a864d8ab9e7..7ca011986b6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -551,6 +551,12 @@ def err_auto_not_allowed : Error< "|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 'final' function">; +def err_final_base : Error< + "derivation from 'final' %0">; // Objective-C++ def err_objc_decls_may_only_appear_in_global_scope : Error< @@ -638,8 +644,14 @@ def warn_attribute_weak_import_invalid_on_definition : Warning< "'weak_import' attribute cannot be specified on a definition">; def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{function|union|" - "variable and function|function or method|parameter|parameter or Objective-C method |" - "function, method or block}1 types">; + "variable and function|function or method|parameter|" + "parameter or Objective-C method |function, method or block|" + "virtual method or class|function, method, or parameter}1 types">; +def err_attribute_wrong_decl_type : Error< + "%0 attribute only applies to %select{function|union|" + "variable and function|function or method|parameter|" + "parameter or Objective-C method |function, method or block|" + "virtual method or class|function, method, or parameter}1 types">; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">; diff --git a/clang/include/clang/Parse/AttributeList.h b/clang/include/clang/Parse/AttributeList.h index 81bb3007bae..e273cadff1d 100644 --- a/clang/include/clang/Parse/AttributeList.h +++ b/clang/include/clang/Parse/AttributeList.h @@ -33,19 +33,22 @@ namespace clang { 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 @@ public: AT_analyzer_noreturn, AT_annotate, AT_blocks, + AT_carries_dependency, AT_cdecl, AT_cleanup, AT_const, @@ -67,6 +71,7 @@ public: AT_dllimport, AT_ext_vector_type, AT_fastcall, + AT_final, AT_format, AT_format_arg, AT_gnu_inline, @@ -106,8 +111,15 @@ public: 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); @@ -181,6 +193,22 @@ inline AttributeList* addAttributeLists (AttributeList *Left, return Left; } +/// CXX0XAttributeList - A wrapper around a C++0x attribute list. +/// Stores, in addition to the list proper, whether or not an actual list was +/// (as opposed to an empty list, which may be ill-formed in some places) and +/// the source range of the list. +struct CXX0XAttributeList { + AttributeList *AttrList; + SourceRange Range; + bool HasAttr; + CXX0XAttributeList (AttributeList *attrList, SourceRange range, bool hasAttr) + : AttrList(attrList), Range(range), HasAttr (hasAttr) { + } + CXX0XAttributeList () + : AttrList(0), Range(), HasAttr(false) { + } +}; + } // end namespace clang #endif diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 814064a79ee..b1375d7d653 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -24,6 +24,7 @@ namespace clang { class AttributeList; + struct CXX0XAttributeList; class PragmaHandler; class Scope; class DiagnosticBuilder; @@ -753,10 +754,10 @@ private: //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. - DeclGroupPtrTy ParseExternalDeclaration(); + DeclGroupPtrTy ParseExternalDeclaration(CXX0XAttributeList Attr); bool isDeclarationAfterDeclarator(); bool isStartOfFunctionDefinition(); - DeclGroupPtrTy ParseDeclarationOrFunctionDefinition( + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(AttributeList *Attr, AccessSpecifier AS = AS_none); DeclPtrTy ParseFunctionDefinition(ParsingDeclarator &D, @@ -994,24 +995,25 @@ private: return ParseStatementOrDeclaration(true); } OwningStmtResult ParseStatementOrDeclaration(bool OnlyStatement = false); - OwningStmtResult ParseLabeledStatement(); - OwningStmtResult ParseCaseStatement(); - OwningStmtResult ParseDefaultStatement(); - OwningStmtResult ParseCompoundStatement(bool isStmtExpr = false); + OwningStmtResult ParseLabeledStatement(AttributeList *Attr); + OwningStmtResult ParseCaseStatement(AttributeList *Attr); + OwningStmtResult ParseDefaultStatement(AttributeList *Attr); + OwningStmtResult ParseCompoundStatement(AttributeList *Attr, + bool isStmtExpr = false); OwningStmtResult ParseCompoundStatementBody(bool isStmtExpr = false); bool ParseParenExprOrCondition(OwningExprResult &CondExp, bool OnlyAllowCondition = false, SourceLocation *LParenLoc = 0, SourceLocation *RParenLoc = 0); - OwningStmtResult ParseIfStatement(); - OwningStmtResult ParseSwitchStatement(); - OwningStmtResult ParseWhileStatement(); - OwningStmtResult ParseDoStatement(); - OwningStmtResult ParseForStatement(); - OwningStmtResult ParseGotoStatement(); - OwningStmtResult ParseContinueStatement(); - OwningStmtResult ParseBreakStatement(); - OwningStmtResult ParseReturnStatement(); + OwningStmtResult ParseIfStatement(AttributeList *Attr); + OwningStmtResult ParseSwitchStatement(AttributeList *Attr); + OwningStmtResult ParseWhileStatement(AttributeList *Attr); + OwningStmtResult ParseDoStatement(AttributeList *Attr); + OwningStmtResult ParseForStatement(AttributeList *Attr); + OwningStmtResult ParseGotoStatement(AttributeList *Attr); + OwningStmtResult ParseContinueStatement(AttributeList *Attr); + OwningStmtResult ParseBreakStatement(AttributeList *Attr); + OwningStmtResult ParseReturnStatement(AttributeList *Attr); OwningStmtResult ParseAsmStatement(bool &msAsm); OwningStmtResult FuzzyParseMicrosoftAsmStatement(); bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names, @@ -1021,7 +1023,7 @@ private: //===--------------------------------------------------------------------===// // C++ 6: Statements and Blocks - OwningStmtResult ParseCXXTryBlock(); + OwningStmtResult ParseCXXTryBlock(AttributeList *Attr); OwningStmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc); OwningStmtResult ParseCXXCatchBlock(); @@ -1045,9 +1047,11 @@ private: DSC_class // class context, enables 'friend' }; - DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd); + DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd, + CXX0XAttributeList Attr); DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + AttributeList *Attr); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, bool AllowFunctionDefinitions, SourceLocation *DeclEnd = 0); @@ -1217,11 +1221,14 @@ private: void ParseBlockId(); // EndLoc, if non-NULL, is filled with the location of the last token of // the attribute list. - AttributeList *ParseAttributes(SourceLocation *EndLoc = 0); + CXX0XAttributeList ParseCXX0XAttributes(SourceLocation *EndLoc = 0); + AttributeList *ParseGNUAttributes(SourceLocation *EndLoc = 0); AttributeList *ParseMicrosoftDeclSpec(AttributeList* CurrAttr = 0); AttributeList *ParseMicrosoftTypeAttributes(AttributeList* CurrAttr = 0); void ParseTypeofSpecifier(DeclSpec &DS); void ParseDecltypeSpecifier(DeclSpec &DS); + + OwningExprResult ParseCXX0XAlignArgument(SourceLocation Start); /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to /// enter a new C++ declarator scope and exit it when the function is @@ -1265,7 +1272,8 @@ private: typedef void (Parser::*DirectDeclParseFunction)(Declarator&); void ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser); - void ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed = true); + void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true, + bool CXX0XAttributesAllowed = true); void ParseDirectDeclarator(Declarator &D); void ParseParenDeclarator(Declarator &D); void ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, @@ -1278,12 +1286,17 @@ private: //===--------------------------------------------------------------------===// // C++ 7: Declarations [dcl.dcl] + bool isCXX0XAttributeSpecifier(bool FullLookahead = false, + tok::TokenKind *After = 0); + DeclPtrTy ParseNamespace(unsigned Context, SourceLocation &DeclEnd); DeclPtrTy ParseLinkage(unsigned Context); DeclPtrTy ParseUsingDirectiveOrDeclaration(unsigned Context, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + CXX0XAttributeList Attrs); DeclPtrTy ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, - SourceLocation &DeclEnd); + SourceLocation &DeclEnd, + AttributeList *Attr); DeclPtrTy ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, AccessSpecifier AS = AS_none); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index aced8c7623f..6121580bab8 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -521,7 +521,7 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { unsigned Align = Target.getCharWidth(); if (const AlignedAttr* AA = D->getAttr<AlignedAttr>()) - Align = std::max(Align, AA->getAlignment()); + Align = std::max(Align, AA->getMaxAlignment()); if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); @@ -761,7 +761,8 @@ ASTContext::getTypeInfo(const Type *T) { case Type::Typedef: { const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl(); if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) { - Align = Aligned->getAlignment(); + Align = std::max(Aligned->getMaxAlignment(), + getTypeAlign(Typedef->getUnderlyingType().getTypePtr())); Width = getTypeSize(Typedef->getUnderlyingType().getTypePtr()); } else return getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index b9cfcfec74f..c084ba6f515 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -448,7 +448,7 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { MaxFieldAlignment = PPA->getAlignment(); if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - UpdateAlignment(AA->getAlignment()); + UpdateAlignment(AA->getMaxAlignment()); // If this is a C++ class, lay out the vtable and the non-virtual bases. const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D); @@ -498,7 +498,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, MaxFieldAlignment = PPA->getAlignment(); if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - UpdateAlignment(AA->getAlignment()); + UpdateAlignment(AA->getMaxAlignment()); // Layout each ivar sequentially. llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; @@ -539,8 +539,9 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { if (FieldPacked) FieldAlign = 1; - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) { + FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); + } // The maximum field alignment overrides the aligned attribute. if (MaxFieldAlignment) FieldAlign = std::min(FieldAlign, MaxFieldAlignment); @@ -574,8 +575,9 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { if (FieldPacked) FieldAlign = 8; - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) { + FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); + } // The maximum field alignment overrides the aligned attribute. if (MaxFieldAlignment) FieldAlign = std::min(FieldAlign, MaxFieldAlignment); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 1fbd3b92735..b8027d8314d 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -353,8 +353,12 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, else if (Features.getStackProtectorMode() == LangOptions::SSPReq) F->addFnAttr(llvm::Attribute::StackProtectReq); - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - F->setAlignment(AA->getAlignment()/8); + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) { + unsigned width = Context.Target.getCharWidth(); + F->setAlignment(AA->getAlignment() / width); + while ((AA = AA->getNext<AlignedAttr>())) + F->setAlignment(std::max(F->getAlignment(), AA->getAlignment() / width)); + } // C++ ABI requires 2-byte alignment for member functions. if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D)) F->setAlignment(2); diff --git a/clang/lib/Frontend/PCHReaderDecl.cpp b/clang/lib/Frontend/PCHReaderDecl.cpp index 6a92a2db51a..328bb611bad 100644 --- a/clang/lib/Frontend/PCHReaderDecl.cpp +++ b/clang/lib/Frontend/PCHReaderDecl.cpp @@ -461,6 +461,7 @@ Attr *PCHReader::ReadAttributes() { SIMPLE_ATTR(Deprecated); UNSIGNED_ATTR(Destructor); SIMPLE_ATTR(FastCall); + SIMPLE_ATTR(Final); case Attr::Format: { std::string Type = ReadString(Record, Idx); diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index 8a45ebce1b9..e3f6c62c2d0 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -1792,6 +1792,7 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { break; case Attr::FastCall: + case Attr::Final: break; case Attr::Format: { diff --git a/clang/lib/Parse/AttributeList.cpp b/clang/lib/Parse/AttributeList.cpp index dde4bc866ac..7e2935c2e02 100644 --- a/clang/lib/Parse/AttributeList.cpp +++ b/clang/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 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .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 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .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/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 2bfda30a951..b13dc733567 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1,3 +1,4 @@ + //===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// // // The LLVM Compiler Infrastructure @@ -45,7 +46,7 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) { 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 @@ Action::TypeResult Parser::ParseTypeName(SourceRange *Range) { /// 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 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { 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 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { } 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 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // 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 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { // 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 @@ AttributeList *Parser::ParseAttributes(SourceLocation *EndLoc) { 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 @@ AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) { 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 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { 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 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { /// 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 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, /// 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 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // 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 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, // 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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // GNU attributes support. case tok::kw___attribute: - DS.AddAttributes(ParseAttributes()); + DS.AddAttributes(ParseGNUAttributes()); continue; // Microsoft declspec support. @@ -1522,7 +1539,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // 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 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { // 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 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, 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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, 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 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { 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 @@ bool Parser::isDeclarationSpecifier() { /// [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 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool AttributesAllowed) { 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 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // // [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 @@ void Parser::ParseDirectDeclarator(Declarator &D) { 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 @@ void Parser::ParseParenDeclarator(Declarator &D) { 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 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // 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 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, 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 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // 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 @@ void Parser::ParseBracketDeclarator(Declarator &D) { 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 @@ void Parser::ParseBracketDeclarator(Declarator &D) { 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/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 914bfc9db89..a21f0344272 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -69,7 +69,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, attrTok = Tok; // FIXME: save these somewhere. - AttrList = ParseAttributes(); + AttrList = ParseGNUAttributes(); } if (Tok.is(tok::equal)) { @@ -97,8 +97,12 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, 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 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { 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 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { /// 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 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, 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::ParseUsingDirectiveOrDeclaration(unsigned Context, /// 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 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, // Parse (optional) nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); - AttributeList *AttrList = 0; IdentifierInfo *NamespcName = 0; SourceLocation IdentLoc = SourceLocation(); @@ -257,17 +279,20 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, 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 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, // 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, - Attr); + AttrList); } else if (TUK == Action::TUK_Reference) { TypeResult = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), @@ -775,7 +805,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, - Attr, + AttrList, Action::MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); @@ -793,7 +823,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // 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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, 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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // 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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, bool Deleted = false; while (1) { - // member-declarator: // declarator pure-specifier[opt] // declarator constant-initializer[opt] @@ -1177,7 +1217,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // 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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // 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 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, 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 @@ void Parser::PopParsingClass() { 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/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index d2b3b84eb7f..bb6dfcebb57 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1315,7 +1315,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, 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 @@ void Parser::ParseBlockId() { if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); DeclaratorInfo.AddAttributes(AttrList, Loc); } @@ -1565,7 +1565,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); ParamInfo.AddAttributes(AttrList, Loc); } @@ -1586,7 +1586,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { if (Tok.is(tok::kw___attribute)) { SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); + AttributeList *AttrList = ParseGNUAttributes(&Loc); ParamInfo.AddAttributes(AttrList, Loc); } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 992211dad75..a57d718d482 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -568,7 +568,7 @@ Parser::OwningExprResult Parser::ParseCXXCondition() { // 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/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 5ba1dd17bdf..295625ae272 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -282,7 +282,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // 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 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // 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 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // 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 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // 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/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index ff08ebbe873..66e61dd949f 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -78,6 +78,10 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { 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 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { 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 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { return StmtError(); } + // FIXME: Use the attributes // expression[opt] ';' OwningExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { @@ -129,47 +135,50 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } 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 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } 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 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { /// 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 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() { 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 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement() { /// '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 @@ Parser::OwningStmtResult Parser::ParseCaseStatement() { /// '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 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement() { /// [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 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { 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 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { 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 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { 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 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &CondExp, /// [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 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { /// 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 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement() { /// 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 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() { /// 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 @@ Parser::OwningStmtResult Parser::ParseDoStatement() { /// [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 @@ Parser::OwningStmtResult Parser::ParseForStatement() { 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 @@ Parser::OwningStmtResult Parser::ParseForStatement() { /// /// 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 @@ Parser::OwningStmtResult Parser::ParseGotoStatement() { /// /// 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 @@ Parser::OwningStmtResult Parser::ParseContinueStatement() { /// /// 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 @@ Parser::OwningStmtResult Parser::ParseBreakStatement() { /// 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 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { } 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 @@ Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) { /// 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::ParseCXXTryBlock() { 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 @@ Parser::OwningStmtResult Parser::ParseCXXCatchBlock() { 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/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index e655dedab43..d2f13f24793 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -192,6 +192,10 @@ Parser::ParseSingleDeclarationAfterTemplate( // 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/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 7ac29771096..dabd065a979 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -55,12 +55,11 @@ bool Parser::isCXXDeclarationStatement() { // 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 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) { 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/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index a9152745b3f..e321564336f 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -355,7 +355,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { return true; } - Result = ParseExternalDeclaration(); + CXX0XAttributeList Attr; + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) + Attr = ParseCXX0XAttributes(); + Result = ParseExternalDeclaration(Attr); return false; } @@ -396,7 +399,7 @@ void Parser::ParseTranslationUnit() { /// ';' /// /// [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 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { // __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 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { 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 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { // 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 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { 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 @@ bool Parser::isStartOfFunctionDefinition() { /// [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 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { // 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 = diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 2d3f9fc8cb2..e0c3f135766 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2149,6 +2149,11 @@ public: 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 // diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 27c491c8820..f8ebe1624a8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2613,7 +2613,8 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { E = Paths.found_decls_end(); I != E; ++I) { if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { if (!CheckOverridingFunctionReturnType(MD, OldMD) && - !CheckOverridingFunctionExceptionSpec(MD, OldMD)) + !CheckOverridingFunctionExceptionSpec(MD, OldMD) && + !CheckOverridingFunctionAttributes(MD, OldMD)) MD->addOverriddenMethod(OldMD); } } @@ -2883,7 +2884,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD->setAccess(AS_public); } - if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) AddOverriddenMethods(cast<CXXRecordDecl>(DC), NewMD); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index c96ab4681cc..3fa7d9cddeb 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -464,7 +464,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) { ValueDecl *VD = dyn_cast<ValueDecl>(d); if (VD == 0 || !VD->getType()->isBlockPointerType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return false; } @@ -484,6 +486,15 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, d->addAttr(::new (S.Context) AnalyzerNoReturnAttr()); } +static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << 8; /*function, method, or parameter*/ + return; + } + // FIXME: Actually store the attribute on the declaration +} + static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 0) { @@ -1516,6 +1527,10 @@ static void HandleAlignedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } + + //FIXME: The C++0x version of this attribute has more limited applicabilty + // than GNU's, and should error out when it is used to specify a + // weaker alignment, rather than being silently ignored. unsigned Align = 0; if (Attr.getNumArgs() == 0) { @@ -1794,6 +1809,29 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) { 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; + } + + if (!isa<CXXRecordDecl>(d) + && (!isa<CXXMethodDecl>(d) || !cast<CXXMethodDecl>(d)->isVirtual())) { + S.Diag(Attr.getLoc(), + Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 7 /*virtual method or class*/; + return; + } + + // FIXME: Check that it's not specified more than once in an attribute- + // specifier and that it conforms to the C++0x rules for + // redeclarations. + + d->addAttr(::new (S.Context) FinalAttr()); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -1841,7 +1879,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, /// 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()) @@ -1861,6 +1900,8 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_analyzer_noreturn: HandleAnalyzerNoReturnAttr (D, Attr, S); break; case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; + case AttributeList::AT_carries_dependency: + HandleDependencyAttr (D, Attr, S); break; case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break; case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break; case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break; @@ -1871,9 +1912,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, 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_malloc: HandleMallocAttr (D, Attr, S); break; case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index bda1a699393..45870a19e4c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -489,6 +489,13 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, Class->setEmpty(false); if (CXXBaseDecl->isPolymorphic()) Class->setPolymorphic(true); + // C++0x CWG Issue #817 indicates that [[final]] classes shouldn't be bases. + if (CXXBaseDecl->hasAttr<FinalAttr>()) { + Diag(BaseLoc, diag::err_final_base) << BaseType.getAsString(); + Diag(CXXBaseDecl->getLocation(), diag::note_previous_class_decl) + << BaseType.getAsString(); + return 0; + } // C++ [dcl.init.aggr]p1: // An aggregate is [...] a class with [...] no base classes [...]. @@ -4896,6 +4903,19 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return false; } +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 diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp new file mode 100644 index 00000000000..a66e3e05976 --- /dev/null +++ b/clang/test/Parser/cxx0x-attributes.cpp @@ -0,0 +1,61 @@ +// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s + +// Declaration syntax checks +[[]] int before_attr; +int after_attr [[]]; +int * [[]] ptr_attr; +int array_attr [1] [[]]; +[[align(8)]] int aligned_attr; +[[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]] + int garbage_attr; +void fn_attr () [[]]; +class [[]] class_attr {}; +extern "C++" [[]] int extern_attr; +template <typename T> [[]] void template_attr (); + +int comma_attr [[,]]; // expected-error {{expected identifier}} +int scope_attr [[foo::]]; // expected-error {{expected identifier}} +int & [[]] ref_attr = after_attr; // expected-error {{an attribute list cannot appear here}} +class foo { + void after_const_attr () const [[]]; // expected-error {{expected expression}} +}; +extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}} +[[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}} +[[]] namespace ns { int i; } // expected-error {{an attribute list cannot appear here}} +[[]] static_assert(true, ""); //expected-error {{an attribute list cannot appear here}} +[[]] asm(""); // expected-error {{an attribute list cannot appear here}} + +[[]] using ns::i; // expected-error {{an attribute list cannot appear here}} +[[]] using namespace ns; + +// Argument tests +[[final()]] int final_params; // expected-error {{C++0x attribute 'final' cannot have an argument list}} +[[align]] int aligned_no_params; // expected-error {{C++0x attribute 'align' must have an argument list}} +[[align(i)]] int aligned_nonconst; // expected-error {{'aligned' attribute requires integer constant}} + +// Statement tests +void foo () { + [[]] ; + [[]] { } + [[]] if (0) { } + [[]] for (;;); + [[]] do { + [[]] continue; + } while (0); + [[]] while (0); + + [[]] switch (i) { + [[]] case 0: + [[]] default: + [[]] break; + } + + [[]] goto there; + [[]] there: + + [[]] try { + } [[]] catch (...) { // expected-error {{an attribute list cannot appear here}} + } + + [[]] return; +} diff --git a/clang/test/SemaCXX/attr-cxx0x.cpp b/clang/test/SemaCXX/attr-cxx0x.cpp new file mode 100644 index 00000000000..fed0ad42d83 --- /dev/null +++ b/clang/test/SemaCXX/attr-cxx0x.cpp @@ -0,0 +1,24 @@ +// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s + +int final_fail [[final]]; //expected-error {{'final' attribute only applies to virtual method or class types}} + +struct [[final]] final_base { }; // expected-note {{struct final_base declared here}} +struct final_child : final_base { }; // expected-error {{derivation from 'final' struct final_base}} + +struct final_member { virtual void quux [[final]] (); }; // expected-note {{overridden virtual function is here}} +struct final_override : final_member { virtual void quux (); }; // expected-error {{declaration of 'quux' overrides a 'final' function}} + +int align_illegal [[align(3)]]; //expected-error {{requested alignment is not a power of 2}} +char align_big [[align(int)]]; +int align_small [[align(1)]]; +int align_multiple [[align(1), align(8), align(1)]]; + +struct align_member { + int member [[align(8)]]; +}; + +static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong"); +static_assert(alignof(align_small) == alignof(int), "j's alignment is wrong"); +static_assert(alignof(align_multiple) == 8, "l's alignment is wrong"); +static_assert(alignof(align_member) == 8, "quuux's alignment is wrong"); +static_assert(sizeof(align_member) == 8, "quuux's size is wrong"); |