https://github.com/Qixi-1 updated https://github.com/llvm/llvm-project/pull/207644
>From f5e826cebd22588460984cdec0fcd9dd0c8028f1 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 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 | 23 +++++++ clang/test/SemaTemplate/GH136813.cpp | 64 +++++++++++++++++++ 2 files changed, 87 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..2a413439f1e65 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -152,6 +152,28 @@ class ExtractTypeForDeductionGuide Keyword, TemplateName(NewTATD), TemplateNameLoc, TemplateArgs); } + QualType TransformInjectedClassNameType(TypeLocBuilder &TLB, + InjectedClassNameTypeLoc TL) { + if (!OuterInstantiationArgs) + return Base::TransformInjectedClassNameType(TLB, TL); + + auto *ICN = TL.getTypePtr(); + ASTContext &Ctx = SemaRef.getASTContext(); + + // Expand InjectedClassNameType to TemplateSpecializationType (e.g. C<T,U>) + QualType TST = ICN->getDecl()->getCanonicalTemplateSpecializationType(Ctx); + + // Substitute outer template parameters (e.g. T->int, U->int) + TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(TST, TL.getNameLoc()); + TypeSourceInfo *SubstTSI = SemaRef.SubstType( + TSI, *OuterInstantiationArgs, TL.getNameLoc(), DeclarationName()); + if (!SubstTSI) + return QualType(); + + TLB.pushFullCopy(SubstTSI->getTypeLoc()); + return SubstTSI->getType(); + } + QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { ASTContext &Context = SemaRef.getASTContext(); TypedefNameDecl *OrigDecl = TL.getDecl(); @@ -839,6 +861,7 @@ struct ConvertConstructorToDeductionGuideTransform { } else NewTSI = SemaRef.SubstType(OldTSI, Args, OldParam->getLocation(), OldParam->getDeclName()); + if (!NewTSI) return nullptr; diff --git a/clang/test/SemaTemplate/GH136813.cpp b/clang/test/SemaTemplate/GH136813.cpp new file mode 100644 index 0000000000000..687858ab396d4 --- /dev/null +++ b/clang/test/SemaTemplate/GH136813.cpp @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s + +// Original crash case: CTAD fails gracefully (no crash), error expected. +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}} +} + +// Success cases: U is deducible from constructor args. +namespace DeducibleCases { + +// Direct +template <class T> struct Outer1 { + template <class U> struct Inner { + Inner(Outer1, U) {} + }; + void f() { Inner(*this, 42); } +}; + +// Pointer +template <class T> struct Outer2 { + template <class U> struct Inner { + Inner(Outer2*, U) {} + }; + void f() { Inner(this, 42); } +}; + +// Const lvalue reference +template <class T> struct Outer3 { + template <class U> struct Inner { + Inner(const Outer3&, U) {} + }; + void f() { Inner(*this, 42); } +}; + +// Rvalue reference +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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
