[clang] 5e64eb8 - [Clang] Improve error recovery for indexed template names (#222328)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 00:50:24 PDT 2026
Author: Corentin Jabot
Date: 2026-09-11T09:50:19+02:00
New Revision: 5e64eb8ffffa3e845ca01d81c1e45ef68d07d306
URL: https://github.com/llvm/llvm-project/commit/5e64eb8ffffa3e845ca01d81c1e45ef68d07d306
DIFF: https://github.com/llvm/llvm-project/commit/5e64eb8ffffa3e845ca01d81c1e45ef68d07d306.diff
LOG: [Clang] Improve error recovery for indexed template names (#222328)
There were a few issues here:
- Names that are not templates were not diagnosed and led to a crash (in
part because clang think they can be template names that will be later
resolved by ADL)
- Names that refer to a variable template decl, etc also led to a crash.
Fixes #220502
Co-authored-by: Cursor <cursoragent at cursor.com>
Added:
Modified:
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Sema/SemaTemplateVariadic.cpp
clang/test/SemaCXX/cxx2d-pack-indexing-template.cpp
Removed:
################################################################################
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index ed995398f597d..dbc1b85acd143 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1225,8 +1225,13 @@ bool Parser::AnnotatePackIndexingTemplateName(CXXScopeSpec &SS,
TemplateName Indexed = Actions.ActOnPackIndexingTemplateName(
Template.get(), NameLoc, IndexExpr.get());
+
+ // If we are unable to index a template name, treat is as a non
+ // template and recover by eating the arguments and producing a
+ // TypeError annotation.
if (Indexed.isNull())
- return true;
+ TNK = TNK_Non_template;
+
Template = TemplateTy::make(Indexed);
// C++29 [temp.names]p7:
@@ -1247,11 +1252,14 @@ bool Parser::AnnotatePackIndexingTemplateName(CXXScopeSpec &SS,
// C++29 [dcl.type.simple]p1:
// A type specifier is a placeholder for a deduced class type if [...] it
// is of the form typename pack-index-template-name.
- if ((TNK == TNK_Type_template || TNK == TNK_Dependent_template_name) &&
- getLangOpts().CPlusPlus17) {
+ if (Indexed.isNull() ||
+ ((TNK == TNK_Type_template || TNK == TNK_Dependent_template_name) &&
+ getLangOpts().CPlusPlus17)) {
TypeResult Type =
- Actions.ActOnPackIndexingDeducedTemplateSpecializationType(Indexed,
- NameLoc);
+ Indexed.isNull()
+ ? TypeError()
+ : Actions.ActOnPackIndexingDeducedTemplateSpecializationType(
+ Indexed, NameLoc);
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type);
} else {
@@ -1266,7 +1274,7 @@ bool Parser::AnnotatePackIndexingTemplateName(CXXScopeSpec &SS,
Tok.setLocation(NameLoc);
Tok.setAnnotationEndLoc(T.getCloseLocation());
PP.AnnotateCachedTokens(Tok);
- return false;
+ return Indexed.isNull();
}
void Parser::AnnotateExistingIndexedTypeNamePack(ParsedType T,
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 625aa198c2ea1..0f5c4d41c3295 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1404,6 +1404,11 @@ TemplateName Sema::ActOnPackIndexingTemplateName(TemplateName Pattern,
// C++29 [temp.names]p3:
// The simple-template-name P in a pack-index-template-name shall denote a
// pack.
+ if (!Pattern.getAsTemplateTemplateParmDecl()) {
+ Diag(NameLoc, diag::err_expected_name_of_pack) << Pattern;
+ return TemplateName();
+ }
+
bool DenotesPack = Pattern.containsUnexpandedParameterPack();
if (!DenotesPack)
Diag(NameLoc, diag::err_expected_name_of_pack) << Pattern;
diff --git a/clang/test/SemaCXX/cxx2d-pack-indexing-template.cpp b/clang/test/SemaCXX/cxx2d-pack-indexing-template.cpp
index f1d9b1b8ce3d0..83fb5e94071a9 100644
--- a/clang/test/SemaCXX/cxx2d-pack-indexing-template.cpp
+++ b/clang/test/SemaCXX/cxx2d-pack-indexing-template.cpp
@@ -18,6 +18,24 @@ template <template <class> auto VV>
constexpr int X = VV...[0]<int>; // expected-error {{'VV' does not refer to the name of a parameter pack}}
}
+namespace GH220502 {
+void fn() {}
+void nontemplate(fn...[0]) {} // expected-error {{'fn' does not refer to the name of a parameter pack}}
+
+template <class T> concept Concept = true;
+template <class T> constexpr int Variable = 0;
+template <class T> void Function();
+template <class T> void Overloaded(T);
+template <class T> void Overloaded(T *);
+
+void f() {
+ (void)Concept...[0]<int>; // expected-error {{'Concept' does not refer to the name of a parameter pack}}
+ (void)Variable...[0]<int>; // expected-error {{'Variable' does not refer to the name of a parameter pack}}
+ Function...[0]<int>(); // expected-error {{'Function' does not refer to the name of a parameter pack}}
+ Overloaded...[0]<int>(0); // expected-error {{'Overloaded' does not refer to the name of a parameter pack}}
+}
+}
+
namespace index {
template <template <class> class... TT>
struct S {
@@ -32,12 +50,10 @@ using E1 = OutOfBounds<A, B>; // expected-note {{in instantiation of templa
template <template <class> class... TT>
using Negative = TT...[-1]<int>;
// expected-error at -1 {{pack index evaluates to -1, which cannot be narrowed to type '__size_t'}}
-// expected-error at -2 {{expected ';' after alias declaration}}
template <template <class> class... TT>
using Narrowing = TT...[1.0]<int>;
// expected-error at -1 {{conversion from 'double' to '__size_t' (aka 'unsigned long') is not allowed in a converted constant expression}}
-// expected-error at -2 {{expected ';' after alias declaration}}
template <template <class> class... TT>
using NonConstant = TT...[x]<int>;
More information about the cfe-commits
mailing list