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
This commit is contained in:
Richard Smith 2014-01-23 23:53:27 +00:00
parent 50b75dbf1a
commit 72553fc19b
3 changed files with 87 additions and 69 deletions

View File

@ -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);

View File

@ -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<Decl *, 8> 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<Decl *, 8> 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<SourceRange, 4> Ranges;
DeclaratorInfo.getCXX11AttributeRanges(Ranges);
if (!Ranges.empty()) {
for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
E = Ranges.end(); I != E; ++I) {
Diag((*I).getBegin(), diag::err_attributes_not_allowed)
<< *I;
}
}
for (SmallVectorImpl<SourceRange>::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 &&

View File

@ -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 ';'}}
};