[clang] [Clang] Improve error recovery for indexed template names (PR #222328)
Corentin Jabot via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 9 06:03:59 PDT 2026
https://github.com/cor3ntin created https://github.com/llvm/llvm-project/pull/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
>From 72df3adf241326b150e6d38d343512c0de3dd925 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 9 Sep 2026 14:41:45 +0200
Subject: [PATCH] [Clang] Improve error recovery for indexed template names
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>
---
clang/lib/Parse/ParseDeclCXX.cpp | 20 +++++++++++++------
clang/lib/Sema/SemaTemplateVariadic.cpp | 5 +++++
.../SemaCXX/cxx2d-pack-indexing-template.cpp | 20 +++++++++++++++++--
3 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d701cbaa43bdd..14adeeaad7a4d 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1251,8 +1251,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:
@@ -1273,11 +1278,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 {
@@ -1292,7 +1300,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 fb03591f70583..9b30832dc9d12 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1406,6 +1406,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 0298be66b1a86..3ccdcb9bb59b9 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