diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 37ea963bf337d..5098e5e983103 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -264,6 +264,8 @@ Bug Fixes to C++ Support - Clang is now better at keeping track of friend function template instance contexts. (#GH55509) - Clang now prints the correct instantiation context for diagnostics suppressed by template argument deduction. +- Clang is now better at instantiating the function definition after its use inside + of a constexpr lambda. (#GH125747) - The initialization kind of elements of structured bindings direct-list-initialized from an array is corrected to direct-initialization. - Clang no longer crashes when a coroutine is declared ``[[noreturn]]``. (#GH127327) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 2da5f5e311fc7..80177996b48b0 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -13657,12 +13657,16 @@ class Sema final : public SemaBase { class LocalEagerInstantiationScope { public: - LocalEagerInstantiationScope(Sema &S) : S(S) { + LocalEagerInstantiationScope(Sema &S, bool AtEndOfTU) + : S(S), AtEndOfTU(AtEndOfTU) { SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } - void perform() { S.PerformPendingInstantiations(/*LocalOnly=*/true); } + void perform() { + S.PerformPendingInstantiations(/*LocalOnly=*/true, + /*AtEndOfTU=*/AtEndOfTU); + } ~LocalEagerInstantiationScope() { assert(S.PendingLocalImplicitInstantiations.empty() && @@ -13673,6 +13677,7 @@ class Sema final : public SemaBase { private: Sema &S; + bool AtEndOfTU; std::deque SavedPendingLocalImplicitInstantiations; }; @@ -13695,8 +13700,8 @@ class Sema final : public SemaBase { class GlobalEagerInstantiationScope { public: - GlobalEagerInstantiationScope(Sema &S, bool Enabled) - : S(S), Enabled(Enabled) { + GlobalEagerInstantiationScope(Sema &S, bool Enabled, bool AtEndOfTU) + : S(S), Enabled(Enabled), AtEndOfTU(AtEndOfTU) { if (!Enabled) return; @@ -13710,7 +13715,8 @@ class Sema final : public SemaBase { void perform() { if (Enabled) { S.DefineUsedVTables(); - S.PerformPendingInstantiations(); + S.PerformPendingInstantiations(/*LocalOnly=*/false, + /*AtEndOfTU=*/AtEndOfTU); } } @@ -13725,7 +13731,8 @@ class Sema final : public SemaBase { S.SavedVTableUses.pop_back(); // Restore the set of pending implicit instantiations. - if (S.TUKind != TU_Prefix || !S.LangOpts.PCHInstantiateTemplates) { + if ((S.TUKind != TU_Prefix || !S.LangOpts.PCHInstantiateTemplates) && + AtEndOfTU) { assert(S.PendingInstantiations.empty() && "PendingInstantiations should be empty before it is discarded."); S.PendingInstantiations.swap(S.SavedPendingInstantiations.back()); @@ -13744,6 +13751,7 @@ class Sema final : public SemaBase { private: Sema &S; bool Enabled; + bool AtEndOfTU; }; ExplicitSpecifier instantiateExplicitSpecifier( @@ -13929,7 +13937,8 @@ class Sema final : public SemaBase { /// Performs template instantiation for all implicit template /// instantiations we have seen until this point. - void PerformPendingInstantiations(bool LocalOnly = false); + void PerformPendingInstantiations(bool LocalOnly = false, + bool AtEndOfTU = true); TemplateParameterList * SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index e43cea1baf43a..41d6304bd5f65 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -41,8 +41,9 @@ llvm::Expected IncrementalParser::ParseOrWrapTopLevelDecl() { // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar CleanupSema(&S); - Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); - Sema::LocalEagerInstantiationScope LocalInstantiations(S); + Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true, + /*AtEndOfTU=*/true); + Sema::LocalEagerInstantiationScope LocalInstantiations(S, /*AtEndOfTU=*/true); // Add a new PTU. ASTContext &C = S.getASTContext(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index dd894df851488..82e049c9c13b9 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2362,7 +2362,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { // DR1484 clarifies that the members of a local class are instantiated as part // of the instantiation of their enclosing entity. if (D->isCompleteDefinition() && D->isLocalClass()) { - Sema::LocalEagerInstantiationScope LocalInstantiations(SemaRef); + Sema::LocalEagerInstantiationScope LocalInstantiations(SemaRef, + /*AtEndOfTU=*/false); SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs, TSK_ImplicitInstantiation, @@ -5344,8 +5345,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // This has to happen before LateTemplateParser below is called, so that // it marks vtables used in late parsed templates as used. GlobalEagerInstantiationScope GlobalInstantiations(*this, - /*Enabled=*/Recursive); - LocalEagerInstantiationScope LocalInstantiations(*this); + /*Enabled=*/Recursive, + /*AtEndOfTU=*/AtEndOfTU); + LocalEagerInstantiationScope LocalInstantiations(*this, + /*AtEndOfTU=*/AtEndOfTU); // Call the LateTemplateParser callback if there is a need to late parse // a templated function definition. @@ -5919,10 +5922,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate // later, while we're still within our own instantiation context. - GlobalEagerInstantiationScope GlobalInstantiations(*this, - /*Enabled=*/Recursive); + GlobalEagerInstantiationScope GlobalInstantiations( + *this, + /*Enabled=*/Recursive, /*AtEndOfTU=*/AtEndOfTU); LocalInstantiationScope Local(*this); - LocalEagerInstantiationScope LocalInstantiations(*this); + LocalEagerInstantiationScope LocalInstantiations(*this, + /*AtEndOfTU=*/AtEndOfTU); // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. @@ -6019,14 +6024,16 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. GlobalEagerInstantiationScope GlobalInstantiations(*this, - /*Enabled=*/Recursive); + /*Enabled=*/Recursive, + /*AtEndOfTU=*/AtEndOfTU); // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. ContextRAII PreviousContext(*this, Var->getDeclContext()); LocalInstantiationScope Local(*this); - LocalEagerInstantiationScope LocalInstantiations(*this); + LocalEagerInstantiationScope LocalInstantiations(*this, + /*AtEndOfTU=*/AtEndOfTU); VarDecl *OldVar = Var; if (Def->isStaticDataMember() && !Def->isOutOfLine()) { @@ -6774,18 +6781,20 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, return D; } -void Sema::PerformPendingInstantiations(bool LocalOnly) { - std::deque delayedPCHInstantiations; +void Sema::PerformPendingInstantiations(bool LocalOnly, bool AtEndOfTU) { + std::deque DelayedImplicitInstantiations; while (!PendingLocalImplicitInstantiations.empty() || (!LocalOnly && !PendingInstantiations.empty())) { PendingImplicitInstantiation Inst; + bool LocalInstantiation = false; if (PendingLocalImplicitInstantiations.empty()) { Inst = PendingInstantiations.front(); PendingInstantiations.pop_front(); } else { Inst = PendingLocalImplicitInstantiations.front(); PendingLocalImplicitInstantiations.pop_front(); + LocalInstantiation = true; } // Instantiate function definitions @@ -6794,22 +6803,26 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; if (Function->isMultiVersion()) { getASTContext().forEachMultiversionedFunctionVersion( - Function, [this, Inst, DefinitionRequired](FunctionDecl *CurFD) { + Function, + [this, Inst, DefinitionRequired, AtEndOfTU](FunctionDecl *CurFD) { InstantiateFunctionDefinition(/*FIXME:*/ Inst.second, CurFD, true, - DefinitionRequired, true); + DefinitionRequired, AtEndOfTU); if (CurFD->isDefined()) CurFD->setInstantiationIsPending(false); }); } else { InstantiateFunctionDefinition(/*FIXME:*/ Inst.second, Function, true, - DefinitionRequired, true); + DefinitionRequired, AtEndOfTU); if (Function->isDefined()) Function->setInstantiationIsPending(false); } // Definition of a PCH-ed template declaration may be available only in the TU. if (!LocalOnly && LangOpts.PCHInstantiateTemplates && TUKind == TU_Prefix && Function->instantiationIsPending()) - delayedPCHInstantiations.push_back(Inst); + DelayedImplicitInstantiations.push_back(Inst); + else if (!AtEndOfTU && Function->instantiationIsPending() && + !LocalInstantiation) + DelayedImplicitInstantiations.push_back(Inst); continue; } @@ -6853,11 +6866,11 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // Instantiate static data member definitions or variable template // specializations. InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true, - DefinitionRequired, true); + DefinitionRequired, AtEndOfTU); } - if (!LocalOnly && LangOpts.PCHInstantiateTemplates) - PendingInstantiations.swap(delayedPCHInstantiations); + if (!DelayedImplicitInstantiations.empty()) + PendingInstantiations.swap(DelayedImplicitInstantiations); } void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, diff --git a/clang/test/CodeGenCXX/function-template-specialization.cpp b/clang/test/CodeGenCXX/function-template-specialization.cpp index 7728f3dc74624..31c78358d014c 100644 --- a/clang/test/CodeGenCXX/function-template-specialization.cpp +++ b/clang/test/CodeGenCXX/function-template-specialization.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple %s -o - | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -Wundefined-func-template -verify -triple %itanium_abi_triple %s -o - | FileCheck %s +// expected-no-diagnostics // CHECK-DAG: _ZZN7PR219047GetDataIiEERKibE1i = internal global i32 4 // CHECK-DAG: _ZZN7PR219047GetDataIiEERKibE1i_0 = internal global i32 2 @@ -43,3 +44,19 @@ const int &GetData(bool b) { return i; } } + +namespace GH125747 { + +template constexpr int visit(F f) { return f(0); } + +template int G(T t); + +int main() { return visit([](auto s) -> int { return G(s); }); } + +template int G(T t) { + return 0; +} + +// CHECK: define {{.*}} @_ZN8GH1257471GIiEEiT_ + +}