-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Clang][Sema] Handle invalid variable template specialization whose type depends on itself #134522
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
@llvm/pr-subscribers-clang Author: Yanzuo Liu (zwuis) ChangesFixes #51347 Full diff: https://github.com/llvm/llvm-project/pull/134522.diff 4 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5217e04b5e83f..9e0fe8a94729b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -414,6 +414,8 @@ Bug Fixes to C++ Support
- Clang now issues an error when placement new is used to modify a const-qualified variable
in a ``constexpr`` function. (#GH131432)
- Clang now emits a warning when class template argument deduction for alias templates is used in C++17. (#GH133806)
+- No longer crashes when instantiating invalid variable template specialization
+ whose type depends on itself. (#GH51347)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 393bfecf9a36b..0c1da40dba388 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5259,6 +5259,9 @@ def err_template_member_noparams : Error<
"extraneous 'template<>' in declaration of member %0">;
def err_template_tag_noparams : Error<
"extraneous 'template<>' in declaration of %0 %1">;
+def err_var_template_spec_type_depends_on_self : Error<
+ "the type of variable template specialization %0 declared with deduced type "
+ "%1 depends on itself">;
def warn_unqualified_call_to_std_cast_function : Warning<
"unqualified call to '%0'">, InGroup<DiagGroup<"unqualified-std-cast-call">>;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 153f44f8ec67a..ce54dbbb3b9fe 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4377,6 +4377,13 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
if (VarTemplateSpecializationDecl *Spec =
Template->findSpecialization(CTAI.CanonicalConverted, InsertPos)) {
checkSpecializationReachability(TemplateNameLoc, Spec);
+ if (Spec->getType()->isUndeducedType()) {
+ // We are substituting the initializer of this variable template
+ // specialization.
+ Diag(TemplateNameLoc, diag::err_var_template_spec_type_depends_on_self)
+ << Spec << Spec->getType();
+ return true;
+ }
// If we already have a variable template specialization, return it.
return Spec;
}
diff --git a/clang/test/SemaTemplate/instantiate-var-template.cpp b/clang/test/SemaTemplate/instantiate-var-template.cpp
index 60d3bd3b59f53..34a1b9710814b 100644
--- a/clang/test/SemaTemplate/instantiate-var-template.cpp
+++ b/clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -47,3 +47,21 @@ namespace InvalidInsertPos {
template<> int v<int, 0>;
int k = v<int, 500>;
}
+
+namespace GH51347 {
+ template <typename T>
+ auto p = p<T>; // expected-error {{the type of variable template specialization 'p<int>'}}
+
+ auto x = p<int>; // expected-note {{in instantiation of variable template specialization 'GH51347::p'}}
+}
+
+namespace GH97881_comment {
+ template <bool B>
+ auto g = sizeof(g<!B>);
+ // expected-error@-1 {{the type of variable template specialization 'g<false>'}}
+ // expected-note@-2 {{in instantiation of variable template specialization 'GH97881_comment::g'}}
+
+ void test() {
+ (void)sizeof(g<false>); // expected-note {{in instantiation of variable template specialization 'GH97881_comment::g'}}
+ }
+}
|
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
|
||
namespace GH51347 { | ||
template <typename T> | ||
auto p = p<T>; // expected-error {{the type of variable template specialization 'p<int>'}} |
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.
Are there cases where this pattern is legal and we should allow this anyway? If not, should we diagnose this not at instantiation, but earlier at definition of the variable template?
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 think this pattern is always illegal. But it's a big work (compared with this PR) to recognize this pattern (as something like current instantiation).
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.
It should be the same/similar as when we recognize the auto x= x +1
or int x = x + 1;
(one is an error, the other is a warning).
This is probably fine if this isn't a primary template, right?
Generally, Clang templates try to diagnose things as absolute early as possible so we get ONE error instead of one-per-instantiation.
That said, it is perhaps worth spending some time to see if there is a reason we can't, or, by language rule, shouldn't diagnose this on auto p = p <T>;
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.
It seems that [temp.res.general]/6 allows us to eagerly diagnose this...
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, it looks much better
clang/lib/Sema/SemaTemplate.cpp
Outdated
Diag(TemplateNameLoc, | ||
diag::err_auto_variable_cannot_appear_in_own_initializer) | ||
<< diag::ParsingInitFor::VarTemplate << Var << Var->getType() | ||
<< SourceRange(TemplateNameLoc, TemplateArgs.getRAngleLoc()); |
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'm also wondering if it is necessary to draw underlines under the RHS of the declaration - would that be noisy if the declaration is too long?
…diagnostic messages, and add test
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! This looks nice
@erichkeane are you happy with the current state?
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
@zwuis Do you need me to merge that for you? |
Yes. Please help me merge this PR. Thank you for your review! |
…ype depends on itself (llvm#134522)
This was flagged in the following issue: #139067 (comment) |
… whose type depends on itself (llvm#134522)" This reverts commit 91f1830.
…primary variable template `std::format_kind` with libstdc++ (#139560) #134522 triggers compilation error with libstdc++, in which primary variable template `std::format_kind` is defined like ```cpp template <typename R> constexpr auto format_kind = __primary_template_not_defined( format_kind<R> ); ``` See #139067 or <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120190>. This PR disables checking template id in initializer of primary variable template `std::format_kind` in libstdc++ (by checking `__GLIBCXX__`). Fixes #139067
Fixes #51347
Fixes #55872