forked from OSchip/llvm-project
Rework parsing of pure-specifiers. Perform the grammar matching and
disambiguation in the parser rather than trying to do it in Sema. llvm-svn: 241032
This commit is contained in:
parent
a5cb389337
commit
9ba0fec83e
clang
include/clang
lib
test/SemaCXX
|
@ -1051,6 +1051,7 @@ def ext_friend_tag_redecl_outside_namespace : ExtWarn<
|
|||
"unqualified friend declaration referring to type outside of the nearest "
|
||||
"enclosing namespace is a Microsoft extension; add a nested name specifier">,
|
||||
InGroup<Microsoft>;
|
||||
def err_pure_friend : Error<"friend declaration cannot have a pure-specifier">;
|
||||
|
||||
def err_invalid_member_in_interface : Error<
|
||||
"%select{data member |non-public member function |static member function |"
|
||||
|
|
|
@ -1182,7 +1182,7 @@ private:
|
|||
ParsingDeclarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo,
|
||||
const VirtSpecifiers& VS,
|
||||
ExprResult& Init);
|
||||
SourceLocation PureSpecLoc);
|
||||
void ParseCXXNonStaticMemberInitializer(Decl *VarD);
|
||||
void ParseLexedAttributes(ParsingClass &Class);
|
||||
void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
|
||||
|
|
|
@ -1690,6 +1690,7 @@ public:
|
|||
bool TypeMayContainAuto);
|
||||
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
|
||||
void ActOnInitializerError(Decl *Dcl);
|
||||
void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc);
|
||||
void ActOnCXXForRangeDecl(Decl *D);
|
||||
StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
|
||||
IdentifierInfo *Ident,
|
||||
|
|
|
@ -27,7 +27,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
|
|||
ParsingDeclarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo,
|
||||
const VirtSpecifiers& VS,
|
||||
ExprResult& Init) {
|
||||
SourceLocation PureSpecLoc) {
|
||||
assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
|
||||
assert(Tok.isOneOf(tok::l_brace, tok::colon, tok::kw_try, tok::equal) &&
|
||||
"Current token not a '{', ':', '=', or 'try'!");
|
||||
|
@ -47,12 +47,8 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
|
|||
VS, ICIS_NoInit);
|
||||
if (FnD) {
|
||||
Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs);
|
||||
bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType();
|
||||
if (Init.isUsable())
|
||||
Actions.AddInitializerToDecl(FnD, Init.get(), false,
|
||||
TypeSpecContainsAuto);
|
||||
else
|
||||
Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto);
|
||||
if (PureSpecLoc.isValid())
|
||||
Actions.ActOnPureSpecifier(FnD, PureSpecLoc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2372,8 +2372,28 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
LateParsedAttrList LateParsedAttrs;
|
||||
|
||||
SourceLocation EqualLoc;
|
||||
bool HasInitializer = false;
|
||||
ExprResult Init;
|
||||
SourceLocation PureSpecLoc;
|
||||
|
||||
auto TryConsumePureSpecifier = [&] (bool AllowDefinition = false) {
|
||||
if (Tok.isNot(tok::equal))
|
||||
return false;
|
||||
|
||||
auto &Zero = NextToken();
|
||||
SmallString<8> Buffer;
|
||||
if (Zero.isNot(tok::numeric_constant) || Zero.getLength() != 1 ||
|
||||
PP.getSpelling(Zero, Buffer) != "0")
|
||||
return false;
|
||||
|
||||
auto &After = GetLookAheadToken(2);
|
||||
if (!After.isOneOf(tok::semi, tok::comma) &&
|
||||
!(AllowDefinition &&
|
||||
After.isOneOf(tok::l_brace, tok::colon, tok::kw_try)))
|
||||
return false;
|
||||
|
||||
EqualLoc = ConsumeToken();
|
||||
PureSpecLoc = ConsumeToken();
|
||||
return true;
|
||||
};
|
||||
|
||||
SmallVector<Decl *, 8> DeclsInGroup;
|
||||
ExprResult BitfieldSize;
|
||||
|
@ -2390,16 +2410,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
if (BitfieldSize.isUnset()) {
|
||||
// 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() &&
|
||||
NextToken().is(tok::numeric_constant)) {
|
||||
EqualLoc = ConsumeToken();
|
||||
Init = ParseInitializer();
|
||||
if (Init.isInvalid())
|
||||
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
|
||||
else
|
||||
HasInitializer = true;
|
||||
}
|
||||
if (getLangOpts().MicrosoftExt && DeclaratorInfo.isDeclarationOfFunction())
|
||||
TryConsumePureSpecifier(/*AllowDefinition*/ true);
|
||||
|
||||
FunctionDefinitionKind DefinitionKind = FDK_Declaration;
|
||||
// function-definition:
|
||||
|
@ -2453,7 +2465,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
|
||||
Decl *FunDecl =
|
||||
ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
|
||||
VS, Init);
|
||||
VS, PureSpecLoc);
|
||||
|
||||
if (FunDecl) {
|
||||
for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
|
||||
|
@ -2479,16 +2491,25 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
|
||||
while (1) {
|
||||
InClassInitStyle HasInClassInit = ICIS_NoInit;
|
||||
if (Tok.isOneOf(tok::equal, tok::l_brace) && !HasInitializer) {
|
||||
bool HasStaticInitializer = false;
|
||||
if (Tok.isOneOf(tok::equal, tok::l_brace) && PureSpecLoc.isInvalid()) {
|
||||
if (BitfieldSize.get()) {
|
||||
Diag(Tok, diag::err_bitfield_member_init);
|
||||
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
|
||||
} else if (DeclaratorInfo.isDeclarationOfFunction()) {
|
||||
// It's a pure-specifier.
|
||||
if (!TryConsumePureSpecifier(/*AllowFunctionDefinition*/ false))
|
||||
// Parse it as an expression so that Sema can diagnose it.
|
||||
HasStaticInitializer = true;
|
||||
} else if (DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
|
||||
DeclSpec::SCS_static &&
|
||||
DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
|
||||
DeclSpec::SCS_typedef &&
|
||||
!DS.isFriendSpecified()) {
|
||||
// It's a default member initializer.
|
||||
HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit;
|
||||
} else {
|
||||
HasInitializer = true;
|
||||
if (!DeclaratorInfo.isDeclarationOfFunction() &&
|
||||
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
|
||||
!= DeclSpec::SCS_typedef)
|
||||
HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit;
|
||||
HasStaticInitializer = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2528,10 +2549,20 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs);
|
||||
}
|
||||
|
||||
// Handle the initializer.
|
||||
// Error recovery might have converted a non-static member into a static
|
||||
// member.
|
||||
if (HasInClassInit != ICIS_NoInit &&
|
||||
DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
|
||||
DeclSpec::SCS_static) {
|
||||
DeclaratorInfo.getDeclSpec().getStorageClassSpec() ==
|
||||
DeclSpec::SCS_static) {
|
||||
HasInClassInit = ICIS_NoInit;
|
||||
HasStaticInitializer = true;
|
||||
}
|
||||
|
||||
if (ThisDecl && PureSpecLoc.isValid())
|
||||
Actions.ActOnPureSpecifier(ThisDecl, PureSpecLoc);
|
||||
|
||||
// Handle the initializer.
|
||||
if (HasInClassInit != ICIS_NoInit) {
|
||||
// The initializer was deferred; parse it and cache the tokens.
|
||||
Diag(Tok, getLangOpts().CPlusPlus11
|
||||
? diag::warn_cxx98_compat_nonstatic_member_init
|
||||
|
@ -2551,11 +2582,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
ThisDecl->setInvalidDecl();
|
||||
} else
|
||||
ParseCXXNonStaticMemberInitializer(ThisDecl);
|
||||
} else if (HasInitializer) {
|
||||
} else if (HasStaticInitializer) {
|
||||
// Normal initializer.
|
||||
if (!Init.isUsable())
|
||||
Init = ParseCXXMemberInitializer(
|
||||
ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
|
||||
ExprResult Init = ParseCXXMemberInitializer(
|
||||
ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc);
|
||||
|
||||
if (Init.isInvalid())
|
||||
SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
|
||||
|
@ -2608,8 +2638,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
DeclaratorInfo.clear();
|
||||
VS.clear();
|
||||
BitfieldSize = ExprResult(/*Invalid=*/false);
|
||||
Init = ExprResult(/*Invalid=*/false);
|
||||
HasInitializer = false;
|
||||
EqualLoc = PureSpecLoc = SourceLocation();
|
||||
DeclaratorInfo.setCommaLoc(CommaLoc);
|
||||
|
||||
// GNU attributes are allowed before the second and subsequent declarator.
|
||||
|
@ -2632,13 +2661,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
|
||||
}
|
||||
|
||||
/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or
|
||||
/// pure-specifier. Also detect and reject any attempted defaulted/deleted
|
||||
/// function definition. The location of the '=', if any, will be placed in
|
||||
/// EqualLoc.
|
||||
/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer.
|
||||
/// Also detect and reject any attempted defaulted/deleted function definition.
|
||||
/// The location of the '=', if any, will be placed in EqualLoc.
|
||||
///
|
||||
/// pure-specifier:
|
||||
/// '= 0'
|
||||
/// This does not check for a pure-specifier; that's handled elsewhere.
|
||||
///
|
||||
/// brace-or-equal-initializer:
|
||||
/// '=' initializer-expression
|
||||
|
|
|
@ -8783,19 +8783,6 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
/// Determine whether the given expression was formed from the token '0'. This
|
||||
/// test is necessary to determine whether an initializer is really a
|
||||
/// pure-specifier.
|
||||
static bool isZeroToken(Sema &S, Expr *E) {
|
||||
auto *IL = dyn_cast<IntegerLiteral>(E);
|
||||
if (!IL || !!IL->getValue() ||
|
||||
!IL->getType()->isSpecificBuiltinType(BuiltinType::Int))
|
||||
return false;
|
||||
|
||||
SmallString<8> Buffer;
|
||||
return S.PP.getSpelling(E->getLocStart(), Buffer) == "0";
|
||||
}
|
||||
|
||||
/// AddInitializerToDecl - Adds the initializer Init to the
|
||||
/// declaration dcl. If DirectInit is true, this is C++ direct
|
||||
/// initialization rather than copy initialization.
|
||||
|
@ -8809,20 +8796,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
}
|
||||
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
|
||||
// With declarators parsed the way they are, the parser cannot
|
||||
// distinguish between a normal initializer and a pure-specifier.
|
||||
// Thus this grotesque test.
|
||||
//
|
||||
// FIXME: The parser should instead treat anything that looks like a
|
||||
// pure-specifier as a pure-specifier, and Sema should convert it to an
|
||||
// initializer when necessary, rather than doing things this way around.
|
||||
if (!DirectInit && isZeroToken(*this, Init))
|
||||
CheckPureMethod(Method, Init->getSourceRange());
|
||||
else {
|
||||
Diag(Method->getLocation(), diag::err_member_function_initialization)
|
||||
<< Method->getDeclName() << Init->getSourceRange();
|
||||
Method->setInvalidDecl();
|
||||
}
|
||||
// Pure-specifiers are handled in ActOnPureSpecifier.
|
||||
Diag(Method->getLocation(), diag::err_member_function_initialization)
|
||||
<< Method->getDeclName() << Init->getSourceRange();
|
||||
Method->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2186,9 +2186,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
|||
assert(Member && "HandleField never returns null");
|
||||
}
|
||||
} else {
|
||||
assert(InitStyle == ICIS_NoInit ||
|
||||
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static);
|
||||
|
||||
Member = HandleDeclarator(S, D, TemplateParameterLists);
|
||||
if (!Member)
|
||||
return nullptr;
|
||||
|
@ -13060,6 +13057,15 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) {
|
||||
if (D->getFriendObjectKind())
|
||||
Diag(D->getLocation(), diag::err_pure_friend);
|
||||
else if (auto *M = dyn_cast<CXXMethodDecl>(D))
|
||||
CheckPureMethod(M, ZeroLoc);
|
||||
else
|
||||
Diag(D->getLocation(), diag::err_illegal_initializer);
|
||||
}
|
||||
|
||||
/// \brief Determine whether the given declaration is a static data member.
|
||||
static bool isStaticDataMember(const Decl *D) {
|
||||
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D))
|
||||
|
|
|
@ -51,3 +51,13 @@ namespace pr8264 {
|
|||
virtual virtual void func(); // expected-warning {{duplicate 'virtual' declaration specifier}}
|
||||
};
|
||||
}
|
||||
|
||||
namespace VirtualFriend {
|
||||
// DR (filed but no number yet): reject meaningless pure-specifier on a friend declaration.
|
||||
struct A { virtual int f(); };
|
||||
struct B { friend int A::f() = 0; }; // expected-error {{friend declaration cannot have a pure-specifier}}
|
||||
struct C {
|
||||
virtual int f();
|
||||
friend int C::f() = 0; // expected-error {{friend declaration cannot have a pure-specifier}}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue