Skip to content

Commit 434ac46

Browse files
authored
Improve the -Wundefined-func-template diagnostic note for invisible template functions (#129031)
See discussion in #125071. Makes the note clearer for the 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. ```
1 parent 1f84495 commit 434ac46

File tree

6 files changed

+70
-17
lines changed

6 files changed

+70
-17
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ Improvements to Clang's diagnostics
278278

279279
- Improve the diagnostics for shadows template parameter to report correct location (#GH129060).
280280

281+
- Improve the ``-Wundefined-func-template`` warning when a function template is not instantiated due to being unreachable in modules.
282+
281283
Improvements to Clang's time-trace
282284
----------------------------------
283285

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5700,6 +5700,8 @@ def warn_func_template_missing : Warning<"instantiation of function %q0 "
57005700
InGroup<UndefinedFuncTemplate>, DefaultIgnore;
57015701
def note_forward_template_decl : Note<
57025702
"forward declaration of template entity is here">;
5703+
def note_unreachable_template_decl
5704+
: Note<"unreachable declaration of template entity is here">;
57035705
def note_inst_declaration_hint : Note<"add an explicit instantiation "
57045706
"declaration to suppress this warning if %q0 is explicitly instantiated in "
57055707
"another translation unit">;

clang/include/clang/Sema/Sema.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11268,13 +11268,11 @@ class Sema final : public SemaBase {
1126811268

1126911269
/// Determine whether we would be unable to instantiate this template (because
1127011270
/// it either has no definition, or is in the process of being instantiated).
11271-
bool DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
11272-
NamedDecl *Instantiation,
11273-
bool InstantiatedFromMember,
11274-
const NamedDecl *Pattern,
11275-
const NamedDecl *PatternDef,
11276-
TemplateSpecializationKind TSK,
11277-
bool Complain = true);
11271+
bool DiagnoseUninstantiableTemplate(
11272+
SourceLocation PointOfInstantiation, NamedDecl *Instantiation,
11273+
bool InstantiatedFromMember, const NamedDecl *Pattern,
11274+
const NamedDecl *PatternDef, TemplateSpecializationKind TSK,
11275+
bool Complain = true, bool *Unreachable = nullptr);
1127811276

1127911277
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
1128011278
/// that the template parameter 'PrevDecl' is being shadowed by a new

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
765765
const NamedDecl *Pattern,
766766
const NamedDecl *PatternDef,
767767
TemplateSpecializationKind TSK,
768-
bool Complain /*= true*/) {
768+
bool Complain, bool *Unreachable) {
769769
assert(isa<TagDecl>(Instantiation) || isa<FunctionDecl>(Instantiation) ||
770770
isa<VarDecl>(Instantiation));
771771

@@ -778,6 +778,8 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
778778
if (!hasReachableDefinition(const_cast<NamedDecl *>(PatternDef),
779779
&SuggestedDef,
780780
/*OnlyNeedComplete*/ false)) {
781+
if (Unreachable)
782+
*Unreachable = true;
781783
// If we're allowed to diagnose this and recover, do so.
782784
bool Recover = Complain && !isSFINAEContext();
783785
if (Complain)

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5386,12 +5386,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
53865386
PatternDef = nullptr;
53875387
}
53885388

5389+
// True is the template definition is unreachable, otherwise false.
5390+
bool Unreachable = false;
53895391
// FIXME: We need to track the instantiation stack in order to know which
53905392
// definitions should be visible within this instantiation.
5391-
if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Function,
5392-
Function->getInstantiatedFromMemberFunction(),
5393-
PatternDecl, PatternDef, TSK,
5394-
/*Complain*/DefinitionRequired)) {
5393+
if (DiagnoseUninstantiableTemplate(
5394+
PointOfInstantiation, Function,
5395+
Function->getInstantiatedFromMemberFunction(), PatternDecl,
5396+
PatternDef, TSK,
5397+
/*Complain*/ DefinitionRequired, &Unreachable)) {
53955398
if (DefinitionRequired)
53965399
Function->setInvalidDecl();
53975400
else if (TSK == TSK_ExplicitInstantiationDefinition ||
@@ -5416,11 +5419,18 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
54165419
if (AtEndOfTU && !getDiagnostics().hasErrorOccurred() &&
54175420
!getSourceManager().isInSystemHeader(PatternDecl->getBeginLoc())) {
54185421
Diag(PointOfInstantiation, diag::warn_func_template_missing)
5419-
<< Function;
5420-
Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
5421-
if (getLangOpts().CPlusPlus11)
5422-
Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
5423-
<< Function;
5422+
<< Function;
5423+
if (Unreachable) {
5424+
// FIXME: would be nice to mention which module the function template
5425+
// comes from.
5426+
Diag(PatternDecl->getLocation(),
5427+
diag::note_unreachable_template_decl);
5428+
} else {
5429+
Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
5430+
if (getLangOpts().CPlusPlus11)
5431+
Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
5432+
<< Function;
5433+
}
54245434
}
54255435
}
54265436

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %clang_cc1 -std=c++20 -fmodules -fmodules-cache-path=%t -I%t \
4+
// RUN: -Wundefined-func-template \
5+
// RUN: -fimplicit-module-maps %t/main.cpp 2>&1 | grep "unreachable declaration of template entity is here"
6+
7+
// Note that the diagnostics are triggered when building the 'hoge' module, which is imported from the main file.
8+
// The "-verify" flag doesn't work in this case. Instead, we grep the expected text to verify the test.
9+
10+
//--- shared_ptr2.h
11+
#pragma once
12+
13+
template<class T>
14+
void x() { }
15+
16+
//--- hoge.h
17+
#pragma once
18+
19+
#include "shared_ptr2.h"
20+
21+
inline void f() {
22+
x<int>();
23+
}
24+
25+
//--- module.modulemap
26+
module hoge {
27+
header "hoge.h"
28+
}
29+
30+
module shared_ptr2 {
31+
header "shared_ptr2.h"
32+
}
33+
34+
//--- main.cpp
35+
#include "hoge.h"
36+
37+
int main() {
38+
f();
39+
}

0 commit comments

Comments
 (0)