r241032 - Rework parsing of pure-specifiers. Perform the grammar matching and
Richard Smith
richard-llvm at metafoo.co.uk
Mon Jun 29 18:28:56 PDT 2015
Author: rsmith
Date: Mon Jun 29 20:28:56 2015
New Revision: 241032
URL: http://llvm.org/viewvc/llvm-project?rev=241032&view=rev
Log:
Rework parsing of pure-specifiers. Perform the grammar matching and
disambiguation in the parser rather than trying to do it in Sema.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/test/SemaCXX/virtuals.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=241032&r1=241031&r2=241032&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jun 29 20:28:56 2015
@@ -1051,6 +1051,7 @@ def ext_friend_tag_redecl_outside_namesp
"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 |"
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=241032&r1=241031&r2=241032&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jun 29 20:28:56 2015
@@ -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,
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=241032&r1=241031&r2=241032&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jun 29 20:28:56 2015
@@ -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,
Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=241032&r1=241031&r2=241032&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Mon Jun 29 20:28:56 2015
@@ -27,7 +27,7 @@ NamedDecl *Parser::ParseCXXInlineMethodD
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::ParseCXXInlineMethodD
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);
}
}
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=241032&r1=241031&r2=241032&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Jun 29 20:28:56 2015
@@ -2372,8 +2372,28 @@ void Parser::ParseCXXClassMemberDeclarat
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::ParseCXXClassMemberDeclarat
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::ParseCXXClassMemberDeclarat
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::ParseCXXClassMemberDeclarat
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::ParseCXXClassMemberDeclarat
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::ParseCXXClassMemberDeclarat
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::ParseCXXClassMemberDeclarat
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::ParseCXXClassMemberDeclarat
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
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=241032&r1=241031&r2=241032&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jun 29 20:28:56 2015
@@ -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 *Re
}
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;
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=241032&r1=241031&r2=241032&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Jun 29 20:28:56 2015
@@ -2186,9 +2186,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S,
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
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))
Modified: cfe/trunk/test/SemaCXX/virtuals.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/virtuals.cpp?rev=241032&r1=241031&r2=241032&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/virtuals.cpp (original)
+++ cfe/trunk/test/SemaCXX/virtuals.cpp Mon Jun 29 20:28:56 2015
@@ -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}}
+ };
+}
More information about the cfe-commits
mailing list