[clang] [clang] Allow delayed function instantiation at TU end if initial instantiation fails (PR #117167)

via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 21 06:40:07 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (StefanPaulet)

<details>
<summary>Changes</summary>

Some eager instantiations may try to instantiate a forward declared templated function before it is defined. This introduces one more attempt to instantiate at the end of the TU.
Resolves #<!-- -->115731 

---
Full diff: https://github.com/llvm/llvm-project/pull/117167.diff


4 Files Affected:

- (modified) clang/include/clang/Sema/Sema.h (+7-4) 
- (modified) clang/lib/Sema/Sema.cpp (+1-1) 
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+8-6) 
- (added) clang/test/SemaTemplate/instantiate-function-delayed.cpp (+26) 


``````````diff
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ea6c67447b6f0..ce27260bc78801 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13523,7 +13523,9 @@ class Sema final : public SemaBase {
           S.PendingLocalImplicitInstantiations);
     }
 
-    void perform() { S.PerformPendingInstantiations(/*LocalOnly=*/true); }
+    void perform(bool AtEndOfTU = false) {
+      S.PerformPendingInstantiations(/*LocalOnly=*/true, AtEndOfTU);
+    }
 
     ~LocalEagerInstantiationScope() {
       assert(S.PendingLocalImplicitInstantiations.empty() &&
@@ -13568,10 +13570,10 @@ class Sema final : public SemaBase {
       S.SavedVTableUses.back().swap(S.VTableUses);
     }
 
-    void perform() {
+    void perform(bool AtEndOfTU = false) {
       if (Enabled) {
         S.DefineUsedVTables();
-        S.PerformPendingInstantiations();
+        S.PerformPendingInstantiations(false, AtEndOfTU);
       }
     }
 
@@ -13790,7 +13792,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 = false);
 
   TemplateParameterList *
   SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 942e7ece4283e3..c97a253239df2b 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1138,7 +1138,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
 
   {
     llvm::TimeTraceScope TimeScope("PerformPendingInstantiations");
-    PerformPendingInstantiations();
+    PerformPendingInstantiations(false, true);
   }
 
   emitDeferredDiags();
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 10efde7c3fe540..0f9a39062750bc 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5267,9 +5267,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
 
   // This class may have local implicit instantiations that need to be
   // instantiation within this scope.
-  LocalInstantiations.perform();
+  LocalInstantiations.perform(AtEndOfTU);
   Scope.Exit();
-  GlobalInstantiations.perform();
+  GlobalInstantiations.perform(AtEndOfTU);
 }
 
 VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
@@ -5612,9 +5612,9 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
 
       // This variable may have local implicit instantiations that need to be
       // instantiated within this scope.
-      LocalInstantiations.perform();
+      LocalInstantiations.perform(AtEndOfTU);
       Local.Exit();
-      GlobalInstantiations.perform();
+      GlobalInstantiations.perform(AtEndOfTU);
     }
   } else {
     assert(Var->isStaticDataMember() && PatternDecl->isStaticDataMember() &&
@@ -6448,7 +6448,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
   return D;
 }
 
-void Sema::PerformPendingInstantiations(bool LocalOnly) {
+void Sema::PerformPendingInstantiations(bool LocalOnly, bool AtEndOfTU) {
   std::deque<PendingImplicitInstantiation> delayedPCHInstantiations;
   while (!PendingLocalImplicitInstantiations.empty() ||
          (!LocalOnly && !PendingInstantiations.empty())) {
@@ -6476,9 +6476,11 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
             });
       } else {
         InstantiateFunctionDefinition(/*FIXME:*/ Inst.second, Function, true,
-                                      DefinitionRequired, true);
+                                      DefinitionRequired, AtEndOfTU);
         if (Function->isDefined())
           Function->setInstantiationIsPending(false);
+        else if (!AtEndOfTU)
+          LateParsedInstantiations.push_back(Inst);
       }
       // Definition of a PCH-ed template declaration may be available only in the TU.
       if (!LocalOnly && LangOpts.PCHInstantiateTemplates &&
diff --git a/clang/test/SemaTemplate/instantiate-function-delayed.cpp b/clang/test/SemaTemplate/instantiate-function-delayed.cpp
new file mode 100644
index 00000000000000..286248b48603b7
--- /dev/null
+++ b/clang/test/SemaTemplate/instantiate-function-delayed.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+template <typename T>
+auto foo(T const& arg) -> T;
+
+template <typename Fp, typename Vis>
+auto dispatch(Fp fp, Vis vis) {
+  return fp(vis);
+}
+
+auto baz(int v) {
+  auto callable = []<typename Arg>(Arg const& arg) -> int {
+    return foo(arg);
+  };
+  return dispatch(callable, v);
+}
+
+template <typename T>
+auto foo(T const& arg) -> T {
+  return arg;
+}
+
+int main() {
+  return baz(5);
+}
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/117167


More information about the cfe-commits mailing list