-
Notifications
You must be signed in to change notification settings - Fork 15.4k
Improve the -Wundefined-func-template diagnostic note for invisible template functions #129031
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
ccd5da1 to
5bf873e
Compare
| def note_forward_template_decl : Note< | ||
| "forward declaration of template entity is here">; | ||
| def note_unreachable_template_decl | ||
| : Note<"declaration of template entity is unreachable here">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess "unreachable declaration of template entity is here" is a more natural choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-modules Author: Haojian Wu (hokein) ChangesSee discussion in #125071. Makes the note clear for unreachable case: Before: After: Full diff: https://github.com/llvm/llvm-project/pull/129031.diff 8 Files Affected:
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();
+}
|
ilya-biryukov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with a few caveats (see the comments)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hokein I think we could also mention the point of instantiation here too.
There are two kinds of problems we can't distinguish:
- it is used intentionally and users want to make it reachable/visible (so imported and declared modules would be relevant),
- unreachable declaration is used unintentionally and users want to remove the use (in which case instantiation point is relevant).
So I think we want both.
If we pick that path, I think we could probably simplify the code a little too:
Diag(PatternDecl->getLocation(),
Unreachable ? diag::note_unreachable_template_decl
: diag::note_forward_template_decl);
if (getLangOpts().CPlusPlus11)
Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
<< Function;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The note_inst_declaration_hint is about a fix hint which suggests to add an explicit instantiation declaration to suppress this warning, it is not feasible to the unreachable-template-decl case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be talking about "visibility" for Clang header modules and reachability for C++20 modules?
I am a little fuzzy on the terminology, but I think there was some distinction between the two we are making for the users.
@ChuanqiXu9, could you advise on the correct wording here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, "unreachable" is a formal definition for C++20 modules. But it looks like the method to judge unreachable decl in this patch is the same for C++20 modules. So I feel it might be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! If you are okay with this, let's keep as is.
Just a follow-up question for a better understanding: I somehow thought we would only check for reachability (as opposed to visibility) only since C++20.
Or should we expect Clang to sometimes complain about reachability in C++17 and below with -fmodules enabled? (The added test uses C++20, but I believe it can also be C++17; but I'm not 100% sure)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we expect Clang to sometimes complain about reachability in C++17 and below with -fmodules enabled?
I think yes. Clang already does this — in Sema::DiagnoseUninstantiableTemplate, when a reachable function definition is missing, Clang may emit a "missing-import" diagnostic.
However, for this particular testcase, the issue is only triggered with the C++20 standard module feature
But it looks like the method to judge unreachable decl in this patch is the same for C++20 modules.
Yes, this aligns with my reading of the code. The same code is shared between header modules and C++20 modules.
ilya-biryukov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even more NITs, but still LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: could we get the split-file-based test for this?
It's pretty hard to read those tests that happen to depend on many files otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: Maybe use -verify and expected-note@* {{unreachable declaration}}?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried this initially, but it didn't work. The reason is that the diagnostics are triggered when building the hoge module, which is imported from the main file. I suspect the module is built in a separate compiler invocation from the main file, and the -verify flag is not propagated to it.
I added a note in the lit test for clarification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! If you are okay with this, let's keep as is.
Just a follow-up question for a better understanding: I somehow thought we would only check for reachability (as opposed to visibility) only since C++20.
Or should we expect Clang to sometimes complain about reachability in C++17 and below with -fmodules enabled? (The added test uses C++20, but I believe it can also be C++17; but I'm not 100% sure)
clang/lib/Sema/SemaTemplate.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AaronBallman I don't think I have seen annotation before, annotating the default value in a function definition.
Are there tools that verify this like we have for argument comments?
Otherwise I don't think these make as much sense, although I sympathize with the sentiment behind them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a tangental note, I think having Clangd show the default argument would help to workaround the lack of these annotations, so I filed #130571.
I don't think we have any tools to check these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, might as well drop it here otherwise it is a potential to get out of sync in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the default-argument comment here.
AaronBallman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this come with a release note as well?
clang/lib/Sema/SemaTemplate.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, might as well drop it here otherwise it is a potential to get out of sync in the future.
Yeah, I think so. Done. |
aaaffe7 to
7a98e78
Compare
See discussion in #125071.
Makes the note clear for unreachable case:
Before:
After: