[clang] Improve the -Wundefined-func-template diagnostic note for invisible template functions (PR #129031)

via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 28 06:24:00 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-modules

Author: Haojian Wu (hokein)

<details>
<summary>Changes</summary>

See discussion in https://github.com/llvm/llvm-project/issues/125071.

Makes the note clear for unreachable case:

Before:
```
./hoge.h:5:12: warning: instantiation of function 'x<int>' required here, but no definition is available [-Wundefined-func-template]
    5 | void f() { x<int>(); }
      |            ^
./shared_ptr2.h:4:6: note: forward declaration of template entity is here
    4 | void x() { T t; (void)t; }
      |      ^
./hoge.h:5:12: note: add an explicit instantiation declaration to suppress this warning if 'x<int>' is explicitly instantiated in another translation unit
    5 | void f() { x<int>(); }
      |    
```

After:

```
./hoge.h:5:12: warning: instantiation of function 'x<int>' required here, but no definition is available [-Wundefined-func-template]
    5 | void f() { x<int>(); }
      |            ^
./shared_ptr2.h:4:6: note: declaration of template entity is unreachable here
    4 | void x() { T t; (void)t; }
      |      ^
1 warning generated.
```

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


8 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) 
- (modified) clang/include/clang/Sema/Sema.h (+5-7) 
- (modified) clang/lib/Sema/SemaTemplate.cpp (+7-7) 
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+19-9) 
- (added) clang/test/Modules/Inputs/undefined-template/hoge.h (+7) 
- (added) clang/test/Modules/Inputs/undefined-template/module.modulemap (+7) 
- (added) clang/test/Modules/Inputs/undefined-template/shared_ptr2.h (+4) 
- (added) clang/test/Modules/diag-undefined-template.cpp (+10) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f10af8f5bd6b2..80f2d54c8a893 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5654,6 +5654,8 @@ def warn_func_template_missing : Warning<"instantiation of function %q0 "
   InGroup<UndefinedFuncTemplate>, DefaultIgnore;
 def note_forward_template_decl : Note<
   "forward declaration of template entity is here">;
+def note_unreachable_template_decl
+    : Note<"unreachable declaration of template entity is here">;
 def note_inst_declaration_hint : Note<"add an explicit instantiation "
   "declaration to suppress this warning if %q0 is explicitly instantiated in "
   "another translation unit">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index a501b901862b6..dfe1c0342252f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11183,13 +11183,11 @@ class Sema final : public SemaBase {
 
   /// Determine whether we would be unable to instantiate this template (because
   /// it either has no definition, or is in the process of being instantiated).
-  bool DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
-                                      NamedDecl *Instantiation,
-                                      bool InstantiatedFromMember,
-                                      const NamedDecl *Pattern,
-                                      const NamedDecl *PatternDef,
-                                      TemplateSpecializationKind TSK,
-                                      bool Complain = true);
+  bool DiagnoseUninstantiableTemplate(
+      SourceLocation PointOfInstantiation, NamedDecl *Instantiation,
+      bool InstantiatedFromMember, const NamedDecl *Pattern,
+      const NamedDecl *PatternDef, TemplateSpecializationKind TSK,
+      bool Complain = true, bool *Unreachable = nullptr);
 
   /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
   /// that the template parameter 'PrevDecl' is being shadowed by a new
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 38fa3ff3ab5b4..9a0e37f344287 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -759,13 +759,11 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
       TemplateArgs);
 }
 
-bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
-                                          NamedDecl *Instantiation,
-                                          bool InstantiatedFromMember,
-                                          const NamedDecl *Pattern,
-                                          const NamedDecl *PatternDef,
-                                          TemplateSpecializationKind TSK,
-                                          bool Complain /*= true*/) {
+bool Sema::DiagnoseUninstantiableTemplate(
+    SourceLocation PointOfInstantiation, NamedDecl *Instantiation,
+    bool InstantiatedFromMember, const NamedDecl *Pattern,
+    const NamedDecl *PatternDef, TemplateSpecializationKind TSK,
+    bool Complain /*= true*/, bool *Unreachable) {
   assert(isa<TagDecl>(Instantiation) || isa<FunctionDecl>(Instantiation) ||
          isa<VarDecl>(Instantiation));
 
@@ -778,6 +776,8 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
     if (!hasReachableDefinition(const_cast<NamedDecl *>(PatternDef),
                                 &SuggestedDef,
                                 /*OnlyNeedComplete*/ false)) {
+      if (Unreachable)
+        *Unreachable = true;
       // If we're allowed to diagnose this and recover, do so.
       bool Recover = Complain && !isSFINAEContext();
       if (Complain)
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1f42f9500959e..398e41b236ae4 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5052,12 +5052,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
       PatternDef = nullptr;
   }
 
+  // True is the template definition is unreachable, otherwise false.
+  bool Unreachable = false;
   // FIXME: We need to track the instantiation stack in order to know which
   // definitions should be visible within this instantiation.
-  if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Function,
-                                Function->getInstantiatedFromMemberFunction(),
-                                     PatternDecl, PatternDef, TSK,
-                                     /*Complain*/DefinitionRequired)) {
+  if (DiagnoseUninstantiableTemplate(
+          PointOfInstantiation, Function,
+          Function->getInstantiatedFromMemberFunction(), PatternDecl,
+          PatternDef, TSK,
+          /*Complain*/ DefinitionRequired, &Unreachable)) {
     if (DefinitionRequired)
       Function->setInvalidDecl();
     else if (TSK == TSK_ExplicitInstantiationDefinition ||
@@ -5082,11 +5085,18 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
       if (AtEndOfTU && !getDiagnostics().hasErrorOccurred() &&
           !getSourceManager().isInSystemHeader(PatternDecl->getBeginLoc())) {
         Diag(PointOfInstantiation, diag::warn_func_template_missing)
-          << Function;
-        Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
-        if (getLangOpts().CPlusPlus11)
-          Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
-              << Function;
+            << Function;
+        if (Unreachable) {
+          // FIXME: would be nice to mention which module the function template
+          // comes from. 
+          Diag(PatternDecl->getLocation(),
+               diag::note_unreachable_template_decl);
+        } else {
+          Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
+          if (getLangOpts().CPlusPlus11)
+            Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
+                << Function;
+        }
       }
     }
 
diff --git a/clang/test/Modules/Inputs/undefined-template/hoge.h b/clang/test/Modules/Inputs/undefined-template/hoge.h
new file mode 100644
index 0000000000000..c67e85ed06734
--- /dev/null
+++ b/clang/test/Modules/Inputs/undefined-template/hoge.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "shared_ptr2.h"
+
+inline void f() {
+  x<int>();
+}
diff --git a/clang/test/Modules/Inputs/undefined-template/module.modulemap b/clang/test/Modules/Inputs/undefined-template/module.modulemap
new file mode 100644
index 0000000000000..89cc78cd5a2de
--- /dev/null
+++ b/clang/test/Modules/Inputs/undefined-template/module.modulemap
@@ -0,0 +1,7 @@
+module hoge {
+  header "hoge.h"
+}
+
+module shared_ptr2 {
+  header "shared_ptr2.h"
+}
diff --git a/clang/test/Modules/Inputs/undefined-template/shared_ptr2.h b/clang/test/Modules/Inputs/undefined-template/shared_ptr2.h
new file mode 100644
index 0000000000000..495cc6fe539c1
--- /dev/null
+++ b/clang/test/Modules/Inputs/undefined-template/shared_ptr2.h
@@ -0,0 +1,4 @@
+#pragma once
+
+template<class T>
+void x() { }
diff --git a/clang/test/Modules/diag-undefined-template.cpp b/clang/test/Modules/diag-undefined-template.cpp
new file mode 100644
index 0000000000000..027984c3125f3
--- /dev/null
+++ b/clang/test/Modules/diag-undefined-template.cpp
@@ -0,0 +1,10 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -std=c++20 -fmodules -fmodules-cache-path=%t -I%S/Inputs/undefined-template \
+// RUN:   -Wundefined-func-template \
+// RUN:   -fimplicit-module-maps  %s 2>&1 | grep "unreachable declaration of template entity is her"
+
+#include "hoge.h"
+
+int main() {
+  f();
+}

``````````

</details>


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


More information about the cfe-commits mailing list