forked from OSchip/llvm-project
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:
parent
50b75dbf1a
commit
72553fc19b
|
@ -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);
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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 ';'}}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue