From ddc016d4d798bf5e6957798ae5b377a58b299468 Mon Sep 17 00:00:00 2001 From: Michael Han Date: Wed, 28 Nov 2012 23:17:40 +0000 Subject: [PATCH] Implement C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains to a friend declaration, that declaration shall be a definition. llvm-svn: 168826 --- clang/include/clang/Sema/DeclSpec.h | 11 ++++++++ clang/lib/Parse/ParseDeclCXX.cpp | 36 +++++++++++++++++++++++++- clang/test/Parser/cxx0x-attributes.cpp | 8 +++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index c1cf30e45f0e..280ac8476734 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1897,6 +1897,17 @@ public: return false; } + /// \brief Return a source range list of C++11 attributes associated + /// with the declarator. + void getCXX11AttributeRanges(SmallVector &Ranges) { + AttributeList *AttrList = Attrs.getList(); + while (AttrList) { + if (AttrList->isCXX0XAttribute()) + Ranges.push_back(AttrList->getRange()); + AttrList = AttrList->getNext(); + } + } + void setAsmLabel(Expr *E) { AsmLabel = E; } Expr *getAsmLabel() const { return AsmLabel; } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 700cf4e4afd4..bf12ee690020 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1915,8 +1915,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ColonProtectionRAIIObject X(*this); ParsedAttributesWithRange attrs(AttrFactory); + ParsedAttributesWithRange FnAttrs(AttrFactory); // Optional C++0x attribute-specifier MaybeParseCXX0XAttributes(attrs); + // We need to keep these attributes for future diagnostic + // before they are taken over by declaration specifier. + FnAttrs.addAll(attrs.getList()); + FnAttrs.Range = attrs.Range; + MaybeParseMicrosoftAttributes(attrs); if (Tok.is(tok::kw_using)) { @@ -1955,6 +1961,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::semi)) { ConsumeToken(); + + if (DS.isFriendSpecified()) + ProhibitAttributes(FnAttrs); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams); DS.complete(TheDecl); @@ -2023,12 +2033,21 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } } + // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains + // to a friend declaration, that declaration shall be a definition. + if (DeclaratorInfo.isFunctionDeclarator() && + DefinitionKind != FDK_Definition && DS.isFriendSpecified()) { + // Diagnose attributes that appear before decl specifier: + // [[]] friend int foo(); + ProhibitAttributes(FnAttrs); + } + if (DefinitionKind) { if (!DeclaratorInfo.isFunctionDeclarator()) { Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params); ConsumeBrace(); SkipUntil(tok::r_brace, /*StopAtSemi*/false); - + // Consume the optional ';' if (Tok.is(tok::semi)) ConsumeToken(); @@ -2123,6 +2142,21 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Decl *ThisDecl = 0; if (DS.isFriendSpecified()) { + // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains + // to a friend declaration, that declaration shall be a definition. + // + // Diagnose attributes appear after friend member function declarator: + // foo [[]] (); + SmallVector Ranges; + DeclaratorInfo.getCXX11AttributeRanges(Ranges); + if (!Ranges.empty()) { + for (SmallVector::iterator I = Ranges.begin(), + E = Ranges.end(); I != E; ++I) { + Diag((*I).getBegin(), diag::err_attributes_not_allowed) + << *I; + } + } + // TODO: handle initializers, bitfields, 'delete' ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, TemplateParams); diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp index 54baaedfd39b..90e73004f620 100644 --- a/clang/test/Parser/cxx0x-attributes.cpp +++ b/clang/test/Parser/cxx0x-attributes.cpp @@ -151,10 +151,16 @@ enum struct [[]] E5; struct S { friend int f [[]] (); // expected-FIXME{{an attribute list cannot appear here}} - [[]] friend int g(); // expected-FIXME{{an attribute list cannot appear here}} + friend int f1 [[noreturn]] (); //expected-error{{an attribute list cannot appear here}} + friend int f2 [[]] [[noreturn]] () {} + [[]] friend int g(); // expected-error{{an attribute list cannot appear here}} [[]] friend int h() { } + [[]] friend int f3(), f4(), f5(); // expected-error{{an attribute list cannot appear here}} + friend int f6 [[noreturn]] (), f7 [[noreturn]] (), f8 [[noreturn]] (); // expected-error3 {{an attribute list cannot appear here}} friend class [[]] C; // expected-error{{an attribute list cannot appear here}} + [[]] friend class D; // expected-error{{an attribute list cannot appear here}} + [[]] friend int; // expected-error{{an attribute list cannot appear here}} }; template void tmpl(T) {} template void tmpl [[]] (int); // expected-FIXME {{an attribute list cannot appear here}}