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);
|
Decl *TagDecl);
|
||||||
ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
|
ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
|
||||||
SourceLocation &EqualLoc);
|
SourceLocation &EqualLoc);
|
||||||
|
void ParseCXXMemberDeclaratorBeforeInitializer(Declarator &DeclaratorInfo,
|
||||||
|
VirtSpecifiers &VS,
|
||||||
|
ExprResult &BitfieldSize,
|
||||||
|
LateParsedAttrList &LateAttrs);
|
||||||
void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr,
|
void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr,
|
||||||
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
|
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
|
||||||
ParsingDeclRAIIObject *DiagsFromTParams = 0);
|
ParsingDeclRAIIObject *DiagsFromTParams = 0);
|
||||||
|
|
|
@ -1888,6 +1888,46 @@ bool Parser::isCXX11FinalKeyword() const {
|
||||||
Specifier == VirtSpecifiers::VS_Sealed;
|
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.
|
/// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration.
|
||||||
///
|
///
|
||||||
/// member-declaration:
|
/// member-declaration:
|
||||||
|
@ -2013,10 +2053,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
TemplateInfo, TemplateDiags);
|
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 attrs(AttrFactory);
|
||||||
ParsedAttributesWithRange FnAttrs(AttrFactory);
|
ParsedAttributesWithRange FnAttrs(AttrFactory);
|
||||||
// Optional C++11 attribute-specifier
|
// Optional C++11 attribute-specifier
|
||||||
|
@ -2055,8 +2091,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
DS.takeAttributesFrom(attrs);
|
DS.takeAttributesFrom(attrs);
|
||||||
if (MalformedTypeSpec)
|
if (MalformedTypeSpec)
|
||||||
DS.SetTypeSpecError();
|
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
|
// If we had a free-standing type definition with a missing semicolon, we
|
||||||
// may get this far before the problem becomes obvious.
|
// may get this far before the problem becomes obvious.
|
||||||
|
@ -2089,26 +2131,28 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
SourceLocation EqualLoc;
|
SourceLocation EqualLoc;
|
||||||
bool HasInitializer = false;
|
bool HasInitializer = false;
|
||||||
ExprResult Init;
|
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.
|
SmallVector<Decl *, 8> DeclsInGroup;
|
||||||
ParseDeclarator(DeclaratorInfo);
|
ExprResult BitfieldSize;
|
||||||
// Error parsing the declarator?
|
bool ExpectSemi = true;
|
||||||
if (!DeclaratorInfo.hasName()) {
|
|
||||||
// If so, skip until the semi-colon or a }.
|
|
||||||
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
|
||||||
TryConsumeToken(tok::semi);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
|
// Parse the first declarator.
|
||||||
|
ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize,
|
||||||
|
LateParsedAttrs);
|
||||||
|
|
||||||
// If attributes exist after the declarator, but before an '{', parse them.
|
// If this has neither a name nor a bit width, something has gone seriously
|
||||||
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
|
// 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.
|
// Hence check for =0 before checking for function definition.
|
||||||
if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) &&
|
if (getLangOpts().MicrosoftExt && Tok.is(tok::equal) &&
|
||||||
DeclaratorInfo.isFunctionDeclarator() &&
|
DeclaratorInfo.isFunctionDeclarator() &&
|
||||||
|
@ -2196,39 +2240,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
// member-declarator
|
// member-declarator
|
||||||
// member-declarator-list ',' member-declarator
|
// member-declarator-list ',' member-declarator
|
||||||
|
|
||||||
SmallVector<Decl *, 8> DeclsInGroup;
|
|
||||||
ExprResult BitfieldSize;
|
|
||||||
bool ExpectSemi = true;
|
|
||||||
|
|
||||||
while (1) {
|
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;
|
InClassInitStyle HasInClassInit = ICIS_NoInit;
|
||||||
if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
|
if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
|
||||||
if (BitfieldSize.get()) {
|
if (BitfieldSize.get()) {
|
||||||
|
@ -2252,19 +2264,15 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
// 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.
|
// to a friend declaration, that declaration shall be a definition.
|
||||||
//
|
//
|
||||||
// Diagnose attributes appear after friend member function declarator:
|
// Diagnose attributes that appear in a friend member function declarator:
|
||||||
// foo [[]] ();
|
// friend int foo [[]] ();
|
||||||
SmallVector<SourceRange, 4> Ranges;
|
SmallVector<SourceRange, 4> Ranges;
|
||||||
DeclaratorInfo.getCXX11AttributeRanges(Ranges);
|
DeclaratorInfo.getCXX11AttributeRanges(Ranges);
|
||||||
if (!Ranges.empty()) {
|
for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
|
||||||
for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
|
E = Ranges.end(); I != E; ++I)
|
||||||
E = Ranges.end(); I != E; ++I) {
|
Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *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,
|
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
|
||||||
TemplateParams);
|
TemplateParams);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2368,11 +2376,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
HasInitializer = false;
|
HasInitializer = false;
|
||||||
DeclaratorInfo.setCommaLoc(CommaLoc);
|
DeclaratorInfo.setCommaLoc(CommaLoc);
|
||||||
|
|
||||||
// Attributes are only allowed on the second declarator.
|
// GNU attributes are allowed before the second and subsequent declarator.
|
||||||
MaybeParseGNUAttributes(DeclaratorInfo);
|
MaybeParseGNUAttributes(DeclaratorInfo);
|
||||||
|
|
||||||
if (Tok.isNot(tok::colon))
|
ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize,
|
||||||
ParseDeclarator(DeclaratorInfo);
|
LateParsedAttrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ExpectSemi &&
|
if (ExpectSemi &&
|
||||||
|
|
|
@ -115,3 +115,9 @@ namespace DuplicateSpecifier {
|
||||||
friend struct A friend; // expected-warning {{duplicate 'friend'}} expected-error {{'friend' must appear first}}
|
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