[clang] [clang][Sema] fix crash on __type_pack_element with dependent packs (GH180307) (PR #180407)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Feb 28 04:57:45 PST 2026
https://github.com/Serosh-commits updated https://github.com/llvm/llvm-project/pull/180407
>From cf731e642abeece29ee5f397123b28a84bd2a428 Mon Sep 17 00:00:00 2001
From: Serosh-commits <janmejayapanda400 at gmail.com>
Date: Sun, 8 Feb 2026 17:40:06 +0530
Subject: [PATCH 1/3] [clang][sema] fix crash on builtin template ids with
dependent packs (gh180307)
---
clang/lib/Sema/SemaTemplate.cpp | 28 ++++++-------
.../builtin_templates_invalid_parameters.cpp | 41 +++++++++++++++++++
2 files changed, 53 insertions(+), 16 deletions(-)
create mode 100644 clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 3497ff7856eed..c54392418e25e 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3406,10 +3406,22 @@ static QualType checkBuiltinTemplateIdType(
Sema &SemaRef, ElaboratedTypeKeyword Keyword, BuiltinTemplateDecl *BTD,
ArrayRef<TemplateArgument> Converted, SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
+ TemplateParameterList *Params = BTD->getTemplateParameters();
+ unsigned RequiredArgs = Params->size();
+ if (Params->hasParameterPack()) {
+ if (Converted.size() < RequiredArgs)
+ return QualType();
+ } else {
+ if (Converted.size() != RequiredArgs)
+ return QualType();
+ }
+
ASTContext &Context = SemaRef.getASTContext();
switch (BTD->getBuiltinTemplateKind()) {
case BTK__make_integer_seq: {
+ if (Converted[2].isDependent())
+ return QualType();
// Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>.
@@ -3423,8 +3435,6 @@ static QualType checkBuiltinTemplateIdType(
}
TemplateArgument NumArgsArg = Converted[2];
- if (NumArgsArg.isDependent())
- return QualType();
TemplateArgumentListInfo SyntheticTemplateArgs;
// The type argument, wrapped in substitution sugar, gets reused as the
@@ -3459,12 +3469,6 @@ static QualType checkBuiltinTemplateIdType(
}
case BTK__type_pack_element: {
- // Specializations of
- // __type_pack_element<Index, T_1, ..., T_N>
- // are treated like T_Index.
- assert(Converted.size() == 2 &&
- "__type_pack_element should be given an index and a parameter pack");
-
TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
if (IndexArg.isDependent() || Ts.isDependent())
return QualType();
@@ -3485,7 +3489,6 @@ static QualType checkBuiltinTemplateIdType(
}
case BTK__builtin_common_type: {
- assert(Converted.size() == 4);
if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); }))
return QualType();
@@ -3508,8 +3511,6 @@ static QualType checkBuiltinTemplateIdType(
}
case BTK__hlsl_spirv_type: {
- assert(Converted.size() == 4);
-
if (!Context.getTargetInfo().getTriple().isSPIRV()) {
SemaRef.Diag(TemplateLoc, diag::err_hlsl_spirv_only) << BTD;
}
@@ -3537,12 +3538,7 @@ static QualType checkBuiltinTemplateIdType(
return Context.getHLSLInlineSpirvType(Opcode, Size, Alignment, Operands);
}
case BTK__builtin_dedup_pack: {
- assert(Converted.size() == 1 && "__builtin_dedup_pack should be given "
- "a parameter pack");
TemplateArgument Ts = Converted[0];
- // Delay the computation until we can compute the final result. We choose
- // not to remove the duplicates upfront before substitution to keep the code
- // simple.
if (Ts.isDependent())
return QualType();
assert(Ts.getKind() == clang::TemplateArgument::Pack);
diff --git a/clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp b/clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp
new file mode 100644
index 0000000000000..dd74bbd1d900d
--- /dev/null
+++ b/clang/test/SemaCXX/builtin_templates_invalid_parameters.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// expected-error@* 2 {{template argument for non-type template parameter must be an expression}}
+
+using SizeT = decltype(sizeof(int));
+
+// Dependent cases that previously crashed but now return QualType() gracefully.
+template <SizeT... Seq> // expected-note {{template parameter is declared here}}
+using gh180307 = __type_pack_element<Seq...>;
+
+template <typename T>
+using gh180307_bis = __make_integer_seq<gh180307, T>;
+// expected-note at -1 {{template template argument has different template parameters than its corresponding template template parameter}}
+
+// Eager expansion checks: Built-in templates should expand even if the
+// destination template OR the type argument is dependent, provided the size is known.
+template <template <typename T, T... Ints> class Seq>
+using test_make_integer_seq_eager = __make_integer_seq<Seq, int, 2>;
+
+template <typename T, T... Ints> struct MySeq;
+using check_eager = test_make_integer_seq_eager<MySeq>;
+using check_eager = MySeq<int, 0, 1>;
+
+template <typename T>
+using test_make_integer_seq_type_dependent = __make_integer_seq<MySeq, T, 2>;
+using check_type_eager = test_make_integer_seq_type_dependent<int>;
+using check_type_eager = MySeq<int, 0, 1>;
+
+// Too many arguments tests
+template <int N> struct S; // expected-note {{template parameter is declared here}}
+using too_many_args = __make_integer_seq<S, int, 10, int>;
+// expected-note at -1 {{template template argument has different template parameters than its corresponding template template parameter}}
+
+// Too few arguments tests
+template <SizeT Index>
+using too_few_args = __type_pack_element<Index>;
+
+// Verify that too_few_args doesn't crash on instantiation either
+// (It should just be an invalid type)
+template <SizeT I> struct Wrap {
+ using type = too_few_args<I>;
+};
>From 533718dd5cdc35aefed75eeee5f6a0dafe030069 Mon Sep 17 00:00:00 2001
From: Serosh-commits <janmejayapanda400 at gmail.com>
Date: Sun, 22 Feb 2026 19:07:35 +0530
Subject: [PATCH 2/3] [clang] address reviewer feedback
---
.../clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Sema/SemaTemplate.cpp | 27 +++++++++++--------
2 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f999c362307af..d75ca7a933e6e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6099,7 +6099,7 @@ def note_template_declared_here : Note<
"%1 declared here">;
def err_template_expansion_into_fixed_list : Error<
"pack expansion used as argument for non-pack parameter of %select{alias "
- "template|concept}0">;
+ "template|concept|builtin template}0">;
def note_parameter_type : Note<
"parameter of type %0 is declared here">;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index c54392418e25e..f094fcbd51dfd 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3408,20 +3408,19 @@ static QualType checkBuiltinTemplateIdType(
TemplateArgumentListInfo &TemplateArgs) {
TemplateParameterList *Params = BTD->getTemplateParameters();
unsigned RequiredArgs = Params->size();
- if (Params->hasParameterPack()) {
- if (Converted.size() < RequiredArgs)
- return QualType();
- } else {
- if (Converted.size() != RequiredArgs)
- return QualType();
+
+ if (Converted.size() != RequiredArgs) {
+ // If we have a different number of arguments than parameters, it's either
+ // an error or we have a dependent pack expansion that hasn't been expanded
+ // and partitioned yet. In either case, we can't proceed with instantiation,
+ // so we return an empty QualType (staying dependent or signaling an error).
+ return QualType();
}
ASTContext &Context = SemaRef.getASTContext();
switch (BTD->getBuiltinTemplateKind()) {
case BTK__make_integer_seq: {
- if (Converted[2].isDependent())
- return QualType();
// Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>.
@@ -3435,6 +3434,9 @@ static QualType checkBuiltinTemplateIdType(
}
TemplateArgument NumArgsArg = Converted[2];
+ if (NumArgsArg.isDependent())
+ return QualType();
+
TemplateArgumentListInfo SyntheticTemplateArgs;
// The type argument, wrapped in substitution sugar, gets reused as the
@@ -5979,11 +5981,14 @@ bool Sema::CheckTemplateArgumentList(
// CWG1430/CWG2686: we have a pack expansion as an argument to an
// alias template or concept, and it's not part of a parameter pack.
// This can't be canonicalized, so reject it now.
- if (isa<TypeAliasTemplateDecl, ConceptDecl>(Template)) {
+ if (isa<TypeAliasTemplateDecl, ConceptDecl, BuiltinTemplateDecl>(
+ Template)) {
+ unsigned DiagSelect = isa<ConceptDecl>(Template) ? 1
+ : isa<BuiltinTemplateDecl>(Template) ? 2
+ : 0;
Diag(ArgLoc.getLocation(),
diag::err_template_expansion_into_fixed_list)
- << (isa<ConceptDecl>(Template) ? 1 : 0)
- << ArgLoc.getSourceRange();
+ << DiagSelect << ArgLoc.getSourceRange();
NoteTemplateParameterLocation(**Param);
return true;
}
>From 19017972573ae5bb92d01e591a0e650ed724c74b Mon Sep 17 00:00:00 2001
From: Serosh <janmejayapanda400 at gmail.com>
Date: Sat, 28 Feb 2026 18:27:36 +0530
Subject: [PATCH 3/3] Apply suggestion from @mizvekov
Co-authored-by: Matheus Izvekov <mizvekov at gmail.com>
---
clang/lib/Sema/SemaTemplate.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f094fcbd51dfd..f9d0e2f97b866 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5979,7 +5979,7 @@ bool Sema::CheckTemplateArgumentList(
Params->getDepth()));
if (ArgIsExpansion && NonPackParameter) {
// CWG1430/CWG2686: we have a pack expansion as an argument to an
- // alias template or concept, and it's not part of a parameter pack.
+ // alias template, builtin template, or concept, and it's not part of a parameter pack.
// This can't be canonicalized, so reject it now.
if (isa<TypeAliasTemplateDecl, ConceptDecl, BuiltinTemplateDecl>(
Template)) {
More information about the cfe-commits
mailing list