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 <[email protected]> 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 <[email protected]> --- 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@-1 {{pack index evaluates to -1, which cannot be narrowed to type '__size_t'}} -// expected-error@-2 {{expected ';' after alias declaration}} template <template <class> class... TT> using Narrowing = TT...[1.0]<int>; // expected-error@-1 {{conversion from 'double' to '__size_t' (aka 'unsigned long') is not allowed in a converted constant expression}} -// expected-error@-2 {{expected ';' after alias declaration}} template <template <class> class... TT> using NonConstant = TT...[x]<int>; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
