[clang] [clang][Sema] Fix crash on nested CTAD with InjectedClassNameType (#1… (PR #207644)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 11 05:12:33 PDT 2026
https://github.com/Qixi-1 updated https://github.com/llvm/llvm-project/pull/207644
>From 83ff721cb0435bec90516d967540e87fb8a708aa Mon Sep 17 00:00:00 2001
From: Qixi-1 <tjx2361869673 at gmail.com>
Date: Mon, 6 Jul 2026 11:30:39 +0800
Subject: [PATCH] [clang][Sema] Fix crash on nested CTAD with
InjectedClassNameType
When generating implicit deduction guides for a nested class template,
an InjectedClassNameType in a constructor parameter can retain template
parameters from the enclosing class.
Expand the injected-class-name to its canonical
TemplateSpecializationType and substitute the outer instantiation
arguments before rebuilding the deduction guide type.
This prevents dangling outer template parameters from reaching
MarkUsedTemplateParameters and causing an out-of-bounds SmallBitVector
access.
Fixes #136813.
Assisted-by: ChatGPT (OpenAI)
---
clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 19 +++++
clang/test/SemaTemplate/GH136813.cpp | 75 +++++++++++++++++++
2 files changed, 94 insertions(+)
create mode 100644 clang/test/SemaTemplate/GH136813.cpp
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 15b6aea749584..12f96bb314cb1 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -100,6 +100,25 @@ class ExtractTypeForDeductionGuide
TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); }
+ QualType TransformInjectedClassNameType(TypeLocBuilder &TLB,
+ InjectedClassNameTypeLoc TL) {
+ if (!OuterInstantiationArgs)
+ return Base::TransformInjectedClassNameType(TLB, TL);
+
+ ASTContext &Context = SemaRef.getASTContext();
+ const InjectedClassNameType *ICNT = TL.getTypePtr();
+
+ QualType TST =
+ ICNT->getDecl()->getCanonicalTemplateSpecializationType(Context);
+ QualType Result = SemaRef.SubstType(TST, *OuterInstantiationArgs,
+ TL.getNameLoc(), DeclarationName());
+ if (Result.isNull())
+ return QualType();
+
+ TLB.pushTrivial(Context, Result, TL.getNameLoc());
+ return Result;
+ }
+
/// Returns true if it's safe to substitute \p Typedef with
/// \p OuterInstantiationArgs.
bool mightReferToOuterTemplateParameters(TypedefNameDecl *Typedef) {
diff --git a/clang/test/SemaTemplate/GH136813.cpp b/clang/test/SemaTemplate/GH136813.cpp
new file mode 100644
index 0000000000000..c76fd06654d77
--- /dev/null
+++ b/clang/test/SemaTemplate/GH136813.cpp
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+namespace GH136813 {
+
+template <typename, typename>
+class C {
+public:
+ template <typename>
+ class C2 { // expected-note {{candidate template ignored}} \
+ // expected-note {{implicit deduction guide declared as}}
+ public:
+ C2(C &) {} // expected-note {{candidate template ignored}} \
+ // expected-note {{implicit deduction guide declared as}}
+ };
+
+ void f() {
+ C2(*this); // expected-error {{no viable constructor or deduction guide}}
+ }
+};
+
+void test_original() {
+ C<int, int>().f(); // expected-note {{in instantiation of member function}}
+}
+
+namespace DeducibleCases {
+
+template <class T>
+struct Outer1 {
+ template <class U>
+ struct Inner {
+ Inner(Outer1, U) {}
+ };
+
+ void f() { Inner(*this, 42); }
+};
+
+template <class T>
+struct Outer2 {
+ template <class U>
+ struct Inner {
+ Inner(Outer2 *, U) {}
+ };
+
+ void f() { Inner(this, 42); }
+};
+
+template <class T>
+struct Outer3 {
+ template <class U>
+ struct Inner {
+ Inner(const Outer3 &, U) {}
+ };
+
+ void f() { Inner(*this, 42); }
+};
+
+template <class T>
+struct Outer4 {
+ template <class U>
+ struct Inner {
+ Inner(Outer4 &&, U) {}
+ };
+
+ void f() { Inner(Outer4{}, 42); }
+};
+
+void test() {
+ Outer1<int>().f();
+ Outer2<int>().f();
+ Outer3<int>().f();
+ Outer4<int>().f();
+}
+
+} // namespace DeducibleCases
+} // namespace GH136813
More information about the cfe-commits
mailing list