https://github.com/Qixi-1 updated https://github.com/llvm/llvm-project/pull/207644
>From 8e60976e6066b544d2214eac4d63991a8b4b067f 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..794f99b37e924 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
