diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index fc0721ceee7663e91074b954372213654f664856..272b504d1e05281db659ca12359aa7266e853871 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1236,6 +1236,7 @@ private: ParsingDeclSpec &DS, AccessSpecifier AS); + void SkipFunctionBody(); Decl *ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), LateParsedAttrList *LateParsedAttrs = nullptr); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 7d8d5ad81dd5ecf893ff8e5f380ecea9b5b4b958..fd7df65cccc5eba14b8e898a5537e9760d8795b3 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1440,6 +1440,12 @@ public: // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // + struct SkipBodyInfo { + SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {} + bool ShouldSkip; + NamedDecl *Previous; + }; + /// List of decls defined in a function prototype. This contains EnumConstants /// that incorrectly end up in translation unit scope because there is no /// function to pin them on. ActOnFunctionDeclarator reads this list and patches @@ -1705,11 +1711,14 @@ public: void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls); - void CheckForFunctionRedefinition(FunctionDecl *FD, - const FunctionDecl *EffectiveDefinition = - nullptr); - Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D); - Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D); + void CheckForFunctionRedefinition( + FunctionDecl *FD, const FunctionDecl *EffectiveDefinition = nullptr, + SkipBodyInfo *SkipBody = nullptr); + Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParamLists, + SkipBodyInfo *SkipBody = nullptr); + Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D, + SkipBodyInfo *SkipBody = nullptr); void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); bool isObjCMethodDecl(Decl *D) { return D && isa<ObjCMethodDecl>(D); @@ -1851,12 +1860,6 @@ public: TUK_Friend // Friend declaration: 'friend struct foo;' }; - struct SkipBodyInfo { - SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {} - bool ShouldSkip; - NamedDecl *Previous; - }; - Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, @@ -5630,10 +5633,6 @@ public: MultiTemplateParamsArg TemplateParameterLists, Declarator &D); - Decl *ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, - MultiTemplateParamsArg TemplateParameterLists, - Declarator &D); - bool CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, TemplateSpecializationKind NewTSK, diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index ed6090453daa954791129cd4357e2386b3e2220e..ab097661f8b81285c2d94c8a35f938430fd2836a 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -2614,6 +2614,7 @@ void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) { } else if (Tok.is(tok::colon)) { ConsumeToken(); + // FIXME: This is wrong, due to C++11 braced initialization. while (Tok.isNot(tok::l_brace)) { ConsumeAndStoreUntil(tok::l_paren, Toks, /*StopAtSemi=*/false); ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 0acd828d7c1302fd5c9442d43821be91402cdd30..35e853f64fc450898f2489ca41c73784d6a1f670 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1067,10 +1067,17 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. - Decl *Res = TemplateInfo.TemplateParams? - Actions.ActOnStartOfFunctionTemplateDef(getCurScope(), - *TemplateInfo.TemplateParams, D) - : Actions.ActOnStartOfFunctionDef(getCurScope(), D); + Sema::SkipBodyInfo SkipBody; + Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D, + TemplateInfo.TemplateParams + ? *TemplateInfo.TemplateParams + : MultiTemplateParamsArg(), + &SkipBody); + + if (SkipBody.ShouldSkip) { + SkipFunctionBody(); + return Res; + } // Break out of the ParsingDeclarator context before we parse the body. D.complete(Res); @@ -1137,6 +1144,28 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, return ParseFunctionStatementBody(Res, BodyScope); } +void Parser::SkipFunctionBody() { + if (Tok.is(tok::equal)) { + SkipUntil(tok::semi); + return; + } + + bool IsFunctionTryBlock = Tok.is(tok::kw_try); + if (IsFunctionTryBlock) + ConsumeToken(); + + CachedTokens Skipped; + if (ConsumeAndStoreFunctionPrologue(Skipped)) + SkipMalformedDecl(); + else { + SkipUntil(tok::r_brace); + while (IsFunctionTryBlock && Tok.is(tok::kw_catch)) { + SkipUntil(tok::l_brace); + SkipUntil(tok::r_brace); + } + } +} + /// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides /// types for a function with a K&R-style identifier list for arguments. void Parser::ParseKNRParamDeclarations(Declarator &D) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a8d1e1203e45a1fce7afb2a1d55cf2a1238dce6c..63093b9fddd101cab1c8f68915524c4ec4e826fd 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2272,9 +2272,17 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { const Attr *NewAttribute = NewAttributes[I]; if (isa<AliasAttr>(NewAttribute)) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) - S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def)); - else { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) { + Sema::SkipBodyInfo SkipBody; + S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def), &SkipBody); + + // If we're skipping this definition, drop the "alias" attribute. + if (SkipBody.ShouldSkip) { + NewAttributes.erase(NewAttributes.begin() + I); + --E; + continue; + } + } else { VarDecl *VD = cast<VarDecl>(New); unsigned Diag = cast<VarDecl>(Def)->isThisDeclarationADefinition() == VarDecl::TentativeDefinition @@ -10398,14 +10406,17 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, } } -Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { +Decl * +Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, + SkipBodyInfo *SkipBody) { assert(getCurFunctionDecl() == nullptr && "Function parsing confused"); assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); D.setFunctionDefinitionKind(FDK_Definition); - Decl *DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg()); - return ActOnStartOfFunctionDef(FnBodyScope, DP); + Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); + return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); } void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) { @@ -10469,7 +10480,8 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, void Sema::CheckForFunctionRedefinition(FunctionDecl *FD, - const FunctionDecl *EffectiveDefinition) { + const FunctionDecl *EffectiveDefinition, + SkipBodyInfo *SkipBody) { // Don't complain if we're in GNU89 mode and the previous definition // was an extern inline function. const FunctionDecl *Definition = EffectiveDefinition; @@ -10481,17 +10493,20 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, return; // If we don't have a visible definition of the function, and it's inline or - // a template, it's OK to form another definition of it. - // - // FIXME: Should we skip the body of the function and use the old definition - // in this case? That may be necessary for functions that return local types - // through a deduced return type, or instantiate templates with local types. - if (!hasVisibleDefinition(Definition) && + // a template, skip the new definition. + if (SkipBody && !hasVisibleDefinition(Definition) && (Definition->getFormalLinkage() == InternalLinkage || Definition->isInlined() || Definition->getDescribedFunctionTemplate() || - Definition->getNumTemplateParameterLists())) + Definition->getNumTemplateParameterLists())) { + SkipBody->ShouldSkip = true; + if (auto *TD = Definition->getDescribedFunctionTemplate()) + makeMergedDefinitionVisible(TD, FD->getLocation()); + else + makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition), + FD->getLocation()); return; + } if (getLangOpts().GNUMode && Definition->isInlineSpecified() && Definition->getStorageClass() == SC_Extern) @@ -10552,7 +10567,8 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, } } -Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { +Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, + SkipBodyInfo *SkipBody) { // Clear the last template instantiation error context. LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); @@ -10564,6 +10580,16 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { FD = FunTmpl->getTemplatedDecl(); else FD = cast<FunctionDecl>(D); + + // See if this is a redefinition. + if (!FD->isLateTemplateParsed()) { + CheckForFunctionRedefinition(FD, nullptr, SkipBody); + + // If we're skipping the body, we're done. Don't enter the scope. + if (SkipBody && SkipBody->ShouldSkip) + return D; + } + // If we are instantiating a generic lambda call operator, push // a LambdaScopeInfo onto the function stack. But use the information // that's already been calculated (ActOnLambdaExpr) to prime the current @@ -10583,10 +10609,6 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // Enter a new function scope PushFunctionScope(); - // See if this is a redefinition. - if (!FD->isLateTemplateParsed()) - CheckForFunctionRedefinition(FD); - // Builtin functions cannot be defined. if (unsigned BuiltinID = FD->getBuiltinID()) { if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID) && diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 85e8e318959621323fd3f7b9f1c8e98b6b0f3f64..527005094c9b4bbfb0d2ba2e7b1a829e6c285571 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -6472,24 +6472,6 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S, return NewDecl; } -Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, - MultiTemplateParamsArg TemplateParameterLists, - Declarator &D) { - assert(getCurFunctionDecl() == nullptr && "Function parsing confused"); - DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); - - if (FTI.hasPrototype) { - // FIXME: Diagnose arguments without names in C. - } - - Scope *ParentScope = FnBodyScope->getParent(); - - D.setFunctionDefinitionKind(FDK_Definition); - Decl *DP = HandleDeclarator(ParentScope, D, - TemplateParameterLists); - return ActOnStartOfFunctionDef(FnBodyScope, DP); -} - /// \brief Strips various properties off an implicit instantiation /// that has just been explicitly specialized. static void StripImplicitInstantiation(NamedDecl *D) { diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 440ca6d74bf8c99dc480ca2af94f0f091e14b4a3..6fa1765bc4389b41a84e1ffe4910fe26aa2a0a86 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -8238,9 +8238,8 @@ void ASTReader::finishPendingActions() { // Load the bodies of any functions or methods we've encountered. We do // this now (delayed) so that we can be sure that the declaration chains - // have been fully wired up. - // FIXME: There seems to be no point in delaying this, it does not depend - // on the redecl chains having been wired up. + // have been fully wired up (hasBody relies on this). + // FIXME: We shouldn't require complete redeclaration chains here. for (PendingBodiesMap::iterator PB = PendingBodies.begin(), PBEnd = PendingBodies.end(); PB != PBEnd; ++PB) {