From 72553fc19b1e57c08d77ccde1a6a6f7bcf22c08f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 23 Jan 2014 23:53:27 +0000 Subject: [PATCH] Factor out repeated parsing of a member-declarator when parsing a member-declaration. In the process, fix a couple of bugs that had crept in where we would parse the first and subsequent member-declarators differently (in particular, we didn't accept an asm-label on a member function definition within a class, and we would accept virt-specifiers and attributes in the wrong order on the first declarator but not on subsequent ones). llvm-svn: 199957 --- clang/include/clang/Parse/Parser.h | 4 + clang/lib/Parse/ParseDeclCXX.cpp | 146 +++++++++++++++-------------- clang/test/Parser/cxx0x-decl.cpp | 6 ++ 3 files changed, 87 insertions(+), 69 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index f7aa05eefa4b..baa890a5408f 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2222,6 +2222,10 @@ private: Decl *TagDecl); ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction, SourceLocation &EqualLoc); + void ParseCXXMemberDeclaratorBeforeInitializer(Declarator &DeclaratorInfo, + VirtSpecifiers &VS, + ExprResult &BitfieldSize, + LateParsedAttrList &LateAttrs); void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), ParsingDeclRAIIObject *DiagsFromTParams = 0); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 2361bc1774e8..86db40b28d8d 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1888,6 +1888,46 @@ bool Parser::isCXX11FinalKeyword() const { Specifier == VirtSpecifiers::VS_Sealed; } +/// \brief Parse a C++ member-declarator up to, but not including, the optional +/// brace-or-equal-initializer or pure-specifier. +void Parser::ParseCXXMemberDeclaratorBeforeInitializer( + Declarator &DeclaratorInfo, VirtSpecifiers &VS, ExprResult &BitfieldSize, + LateParsedAttrList &LateParsedAttrs) { + // member-declarator: + // declarator pure-specifier[opt] + // declarator brace-or-equal-initializer[opt] + // identifier[opt] ':' constant-expression + if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it + // is a bitfield. + // FIXME: This should only apply when parsing the id-expression (see + // PR18587). + ColonProtectionRAIIObject X(*this); + ParseDeclarator(DeclaratorInfo); + } + + if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) { + BitfieldSize = ParseConstantExpression(); + if (BitfieldSize.isInvalid()) + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); + } else + ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface); + + // If a simple-asm-expr is present, parse it. + if (Tok.is(tok::kw_asm)) { + SourceLocation Loc; + ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + if (AsmLabel.isInvalid()) + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); + + DeclaratorInfo.setAsmLabel(AsmLabel.release()); + DeclaratorInfo.SetRangeEnd(Loc); + } + + // If attributes exist after the declarator, but before an '{', parse them. + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); +} + /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. /// /// member-declaration: @@ -2013,10 +2053,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, TemplateInfo, TemplateDiags); } - // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it - // is a bitfield. - ColonProtectionRAIIObject X(*this); - ParsedAttributesWithRange attrs(AttrFactory); ParsedAttributesWithRange FnAttrs(AttrFactory); // Optional C++11 attribute-specifier @@ -2055,8 +2091,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DS.takeAttributesFrom(attrs); if (MalformedTypeSpec) DS.SetTypeSpecError(); - ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, - &CommonLateParsedAttrs); + + { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it + // is a bitfield. + ColonProtectionRAIIObject X(*this); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, + &CommonLateParsedAttrs); + } // If we had a free-standing type definition with a missing semicolon, we // may get this far before the problem becomes obvious. @@ -2089,29 +2131,31 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SourceLocation EqualLoc; bool HasInitializer = false; ExprResult Init; - if (Tok.isNot(tok::colon)) { - // Don't parse FOO:BAR as if it were a typo for FOO::BAR. - ColonProtectionRAIIObject X(*this); - // Parse the first declarator. - ParseDeclarator(DeclaratorInfo); - // Error parsing the declarator? - if (!DeclaratorInfo.hasName()) { - // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); - TryConsumeToken(tok::semi); - return; - } + SmallVector DeclsInGroup; + ExprResult BitfieldSize; + bool ExpectSemi = true; - ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface); + // Parse the first declarator. + ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize, + LateParsedAttrs); - // If attributes exist after the declarator, but before an '{', parse them. - MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + // If this has neither a name nor a bit width, something has gone seriously + // wrong. Skip until the semi-colon or }. + if (!DeclaratorInfo.hasName() && !BitfieldSize.isInvalid() && + !BitfieldSize.isUsable()) { + // If so, skip until the semi-colon or a }. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + TryConsumeToken(tok::semi); + return; + } - // MSVC permits pure specifier on inline functions declared at class scope. + // Check for a member function definition. + if (!BitfieldSize.isInvalid() && !BitfieldSize.isUsable()) { + // MSVC permits pure specifier on inline functions defined at class scope. // Hence check for =0 before checking for function definition. if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) && - DeclaratorInfo.isFunctionDeclarator() && + DeclaratorInfo.isFunctionDeclarator() && NextToken().is(tok::numeric_constant)) { EqualLoc = ConsumeToken(); Init = ParseInitializer(); @@ -2196,39 +2240,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // member-declarator // member-declarator-list ',' member-declarator - SmallVector DeclsInGroup; - ExprResult BitfieldSize; - bool ExpectSemi = true; - while (1) { - // member-declarator: - // declarator pure-specifier[opt] - // declarator brace-or-equal-initializer[opt] - // identifier[opt] ':' constant-expression - if (TryConsumeToken(tok::colon)) { - BitfieldSize = ParseConstantExpression(); - if (BitfieldSize.isInvalid()) - SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); - } - - // If a simple-asm-expr is present, parse it. - if (Tok.is(tok::kw_asm)) { - SourceLocation Loc; - ExprResult AsmLabel(ParseSimpleAsm(&Loc)); - if (AsmLabel.isInvalid()) - SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); - - DeclaratorInfo.setAsmLabel(AsmLabel.release()); - DeclaratorInfo.SetRangeEnd(Loc); - } - - // If attributes exist after the declarator, parse them. - MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); - - // FIXME: When g++ adds support for this, we'll need to check whether it - // goes before or after the GNU attributes and __asm__. - ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface); - InClassInitStyle HasInClassInit = ICIS_NoInit; if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { if (BitfieldSize.get()) { @@ -2249,22 +2261,18 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, NamedDecl *ThisDecl = 0; if (DS.isFriendSpecified()) { - // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains + // 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 [[]] (); + // Diagnose attributes that appear in a friend member function declarator: + // friend int foo [[]] (); SmallVector Ranges; DeclaratorInfo.getCXX11AttributeRanges(Ranges); - if (!Ranges.empty()) { - for (SmallVectorImpl::iterator I = Ranges.begin(), - E = Ranges.end(); I != E; ++I) { - Diag((*I).getBegin(), diag::err_attributes_not_allowed) - << *I; - } - } + for (SmallVectorImpl::iterator I = Ranges.begin(), + E = Ranges.end(); I != E; ++I) + Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I; - // TODO: handle initializers, bitfields, 'delete' + // TODO: handle initializers, VS, bitfields, 'delete' ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, TemplateParams); } else { @@ -2368,11 +2376,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, HasInitializer = false; DeclaratorInfo.setCommaLoc(CommaLoc); - // Attributes are only allowed on the second declarator. + // GNU attributes are allowed before the second and subsequent declarator. MaybeParseGNUAttributes(DeclaratorInfo); - if (Tok.isNot(tok::colon)) - ParseDeclarator(DeclaratorInfo); + ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize, + LateParsedAttrs); } if (ExpectSemi && diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp index f91ed311788e..84eaafeee592 100644 --- a/clang/test/Parser/cxx0x-decl.cpp +++ b/clang/test/Parser/cxx0x-decl.cpp @@ -115,3 +115,9 @@ namespace DuplicateSpecifier { friend struct A friend; // expected-warning {{duplicate 'friend'}} expected-error {{'friend' must appear first}} }; } + +struct Base { virtual void f() = 0; virtual void g() = 0; virtual void h() = 0; }; +struct MemberComponentOrder : Base { + void f() override __asm__("foobar") __attribute__(( )) {} + void g() __attribute__(( )) override; // expected-error {{expected ';'}} +};