https://github.com/Qixi-1 created 
https://github.com/llvm/llvm-project/pull/207644

…36813)

When generating implicit deduction guides for nested template classes, 
transformFunctionTypeParam calls SubstType to substitute outer template 
parameters. However, SubstType fails to substitute through 
InjectedClassNameType because TreeTransform does not reach TransformTagType for 
it in this context, leaving outer template parameters unsubstituted in the 
deduction guide parameter type.

Later, MarkUsedTemplateParameters traverses the unsubstituted parameter type 
and encounters template parameter indices that exceed the SmallBitVector size 
(allocated for the inner template), causing an out-of-bounds access.

Fix by expanding InjectedClassNameType to its canonical 
TemplateSpecializationType before calling SubstType when transforming outer 
patterns, so that the outer template parameters can be properly substituted.

Fixes #136813.

>From 4097416744561a3af0b7f41807ceb619ce780a7c Mon Sep 17 00:00:00 2001
From: Qixi-1 <[email protected]>
Date: Mon, 6 Jul 2026 11:30:39 +0800
Subject: [PATCH] [clang][Sema] Fix crash on nested CTAD with
 InjectedClassNameType (#136813)

When generating implicit deduction guides for nested template classes,
transformFunctionTypeParam calls SubstType to substitute outer template
parameters. However, SubstType fails to substitute through
InjectedClassNameType because TreeTransform does not reach
TransformTagType for it in this context, leaving outer template
parameters unsubstituted in the deduction guide parameter type.

Later, MarkUsedTemplateParameters traverses the unsubstituted parameter
type and encounters template parameter indices that exceed the
SmallBitVector size (allocated for the inner template), causing an
out-of-bounds access.

Fix by expanding InjectedClassNameType to its canonical
TemplateSpecializationType before calling SubstType when transforming
outer patterns, so that the outer template parameters can be properly
substituted.

Fixes #136813.
---
 clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 22 ++++++++++++++++++-
 ...nested-implicit-deduction-guides-crash.cpp | 22 +++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
 create mode 100644 
clang/test/SemaTemplate/nested-implicit-deduction-guides-crash.cpp

diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp 
b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 15b6aea749584..36ecf664c71fc 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -836,9 +836,29 @@ struct ConvertConstructorToDeductionGuideTransform {
       NewTSI =
           SemaRef.CheckPackExpansion(NewTSI, PackTL.getEllipsisLoc(),
                                      PackTL.getTypePtr()->getNumExpansions());
-    } else
+    } else{
+         // When transforming outer patterns, InjectedClassNameType may not be
+      // substituted by SubstType because TreeTransform does not always
+      // reach TransformTagType for nested InjectedClassNameType. Expand it
+      // to TemplateSpecializationType first so substitution can proceed.
+      if (TransformingOuterPatterns) {
+        QualType OldType = OldTSI->getType().getNonReferenceType();
+        if (const auto *ICNT = dyn_cast<InjectedClassNameType>(OldType)) {
+          QualType Expanded =
+              ICNT->getDecl()->getCanonicalTemplateSpecializationType(
+                  SemaRef.Context);
+          // Rebuild the type with the expanded form
+          if (OldTSI->getType()->isLValueReferenceType())
+            Expanded = SemaRef.Context.getLValueReferenceType(Expanded);
+          else if (OldTSI->getType()->isRValueReferenceType())
+            Expanded = SemaRef.Context.getRValueReferenceType(Expanded);
+          OldTSI = SemaRef.Context.getTrivialTypeSourceInfo(
+              Expanded, OldParam->getLocation());
+        }
+      }
       NewTSI = SemaRef.SubstType(OldTSI, Args, OldParam->getLocation(),
                                  OldParam->getDeclName());
+       }
     if (!NewTSI)
       return nullptr;
 
diff --git a/clang/test/SemaTemplate/nested-implicit-deduction-guides-crash.cpp 
b/clang/test/SemaTemplate/nested-implicit-deduction-guides-crash.cpp
new file mode 100644
index 0000000000000..66be88b495d69
--- /dev/null
+++ b/clang/test/SemaTemplate/nested-implicit-deduction-guides-crash.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+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}}
+    }
+};
+
+int main() {
+    C<int, int>().f(); // expected-note {{in instantiation of member function}}
+    return 0;
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to