Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -1839,7 +1839,7 @@ /// that this returns false for a defaulted function unless that function /// has been implicitly defined (possibly as deleted). bool isThisDeclarationADefinition() const { - return IsDeleted || Body || IsLateTemplateParsed; + return IsDeleted || Body || IsLateTemplateParsed || WillHaveBody; } /// doesThisDeclarationHaveABody - Returns whether this specific Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1873,6 +1873,7 @@ bool canSkipFunctionBody(Decl *D); void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); + void ActOnStartFunctionBody(Decl *Decl); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); Decl *ActOnSkippedFunctionBody(Decl *Decl); Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -2529,7 +2529,7 @@ bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const { for (auto I : redecls()) { if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed || - I->hasDefiningAttr()) { + I->WillHaveBody || I->hasDefiningAttr()) { Definition = I->IsDeleted ? I->getCanonicalDecl() : I; return true; } Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -1194,6 +1194,8 @@ return Actions.ActOnFinishFunctionBody(Res, nullptr, false); } + Actions.ActOnStartFunctionBody(Res); + if (Tok.is(tok::kw_try)) return ParseFunctionTryBlock(Res, BodyScope); Index: lib/Sema/SemaCUDA.cpp =================================================================== --- lib/Sema/SemaCUDA.cpp +++ lib/Sema/SemaCUDA.cpp @@ -629,12 +629,6 @@ // emitted, because (say) the definition could include "inline". FunctionDecl *Def = FD->getDefinition(); - // We may currently be parsing the body of FD, in which case - // FD->getDefinition() will be null, but we still want to treat FD as though - // it's a definition. - if (!Def && FD->willHaveBody()) - Def = FD; - if (Def && !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def))) return true; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -11804,11 +11804,6 @@ return D; } - // Mark this function as "will have a body eventually". This lets users to - // call e.g. isInlineDefinitionExternallyVisible while we're still parsing - // this function. - FD->setWillHaveBody(); - // 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 @@ -11978,6 +11973,19 @@ return Decl; } +/// Semantic action called by parser when it expects that the current function +/// definition will have a body statement. +void Sema::ActOnStartFunctionBody(Decl *D) { + if (!D) + return; + if (FunctionDecl *FD = dyn_cast(D)) { + // Mark this function as "will have a body eventually". This lets users to + // call e.g. isInlineDefinitionExternallyVisible while we're still parsing + // this function. + FD->setWillHaveBody(); + } +} + Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) { return ActOnFinishFunctionBody(D, BodyArg, false); } Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3832,6 +3832,7 @@ SubstQualifier(*this, PatternDecl, Function, TemplateArgs); ActOnStartOfFunctionDef(nullptr, Function); + ActOnStartFunctionBody(Function); // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. Index: test/SemaCXX/friend2.cpp =================================================================== --- test/SemaCXX/friend2.cpp +++ test/SemaCXX/friend2.cpp @@ -170,3 +170,15 @@ template class Test; } + +namespace pr14785 { +template +struct Somewhat { + void internal() const { } + friend void operator+(int const &, Somewhat const &) {} // expected-error{{redefinition of 'operator+'}} +}; + +void operator+(int const &, Somewhat const &x) { // expected-note {{previous definition is here}} + x.internal(); // expected-note{{in instantiation of template class 'pr14785::Somewhat' requested here}} +} +}