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;
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:
Decl *FunDecl =
ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo,
- VS, Init);
+ VS, PureSpecLoc);
if (FunDecl) {
for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) {
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;
}
}
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
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);
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.
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
}
}
-/// 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.
}
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;
}