https://github.com/aokblast updated https://github.com/llvm/llvm-project/pull/227501
>From 8630009e9826c731dabcdc1bcb6136870762672a Mon Sep 17 00:00:00 2001 From: ShengYi Hung <[email protected]> Date: Tue, 29 Sep 2026 17:27:05 -0500 Subject: [PATCH 1/3] [Clang] Do not assume existing substition for template specialization Mangled symbol is not always available when having template specialization. For example, a template alias mangled the type when actually doing substitution. In previous code, B in A<B>::foo() is always mangled when reaching A<B>. When doing substition insides A<T>, B is always available. Alias is not the case here, B is mangled when reaching A<T> inside. As now, TemplateName::SubstTemplateTemplateParm might needs to be resolved further as B is not always defined, we remove it from the switch case and find recursively like the origianl path. Assisted-by: Claude # Tests, ReleaseNotes --- clang/docs/ReleaseNotes.md | 4 + clang/lib/AST/ItaniumMangle.cpp | 111 +++++++++++----------- clang/test/CodeGenCXX/mangle-template.cpp | 15 +++ 3 files changed, 77 insertions(+), 53 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index b71758e4b9647..e6d0cab0b5072 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -806,6 +806,10 @@ features cannot lower the translation-unit ABI level; - Fixed an assertion failure when a method or function definition follows an Objective-C `@implementation` that was ended by a nested `@interface`, `@protocol` or `@implementation` before its `@end`. (#GH209503) +- Fixed an assertion failure in the Itanium mangler when a template template + parameter substituted through an alias template is used as the base of an + unresolved name, such as `TT<T>::value` in a non-type template parameter's + type. (#GH88592) ### OpenACC Specific Changes diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 9b3589a527d03..507472db1e299 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -462,8 +462,6 @@ class CXXNameMangler { bool mangleSubstitution(TemplateName Template); bool mangleSubstitution(uintptr_t Ptr); - void mangleExistingSubstitution(TemplateName name); - bool mangleStandardSubstitution(const NamedDecl *ND); void addSubstitution(const NamedDecl *ND) { @@ -2590,57 +2588,70 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(Ty); TemplateName TN = TST->getTemplateName(); - switch (TN.getKind()) { - case TemplateName::Template: - case TemplateName::QualifiedTemplate: { - TemplateDecl *TD = TN.getAsTemplateDecl(); - - // If the base is a template template parameter, this is an - // unresolved type. - assert(TD && "no template for template specialization type"); - if (isa<TemplateTemplateParmDecl>(TD)) - goto unresolvedType; - - mangleSourceNameWithAbiTags(TD); - break; - } - case TemplateName::DependentTemplate: { - const DependentTemplateStorage *S = TN.getAsDependentTemplateName(); - mangleSourceName(S->getName().getIdentifier()); - break; + + // It is possible that a name doesn't mangled when reaching a substitution + // like alias template. + bool MangledAsSubstitution = false; + while (TN.getKind() == TemplateName::SubstTemplateTemplateParm) { + TemplateName Replacement = + TN.getAsSubstTemplateTemplateParm()->getReplacement(); + if (mangleSubstitution(Replacement)) { + MangledAsSubstitution = true; + break; + } + TN = Replacement; } - case TemplateName::OverloadedTemplate: - case TemplateName::AssumedTemplate: - case TemplateName::DeducedTemplate: - llvm_unreachable("invalid base for a template specialization type"); + if (!MangledAsSubstitution) { + switch (TN.getKind()) { + case TemplateName::Template: + case TemplateName::QualifiedTemplate: { + TemplateDecl *TD = TN.getAsTemplateDecl(); - case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *subst = - TN.getAsSubstTemplateTemplateParm(); - mangleExistingSubstitution(subst->getReplacement()); - break; - } + // If the base is a template template parameter, this is an + // unresolved type. + assert(TD && "no template for template specialization type"); + if (isa<TemplateTemplateParmDecl>(TD)) + goto unresolvedType; - case TemplateName::SubstTemplateTemplateParmPack: { - // FIXME: not clear how to mangle this! - // template <template <class U> class T...> class A { - // template <class U...> void foo(decltype(T<U>::foo) x...); - // }; - Out << "_SUBSTPACK_"; - break; - } + mangleSourceNameWithAbiTags(TD); + break; + } + case TemplateName::DependentTemplate: { + const DependentTemplateStorage *S = TN.getAsDependentTemplateName(); + mangleSourceName(S->getName().getIdentifier()); + break; + } - case TemplateName::PackIndexingTemplate: - DiagnoseUnsupportedPackIndexTemplateName(); - return false; + case TemplateName::OverloadedTemplate: + case TemplateName::AssumedTemplate: + case TemplateName::DeducedTemplate: + llvm_unreachable("invalid base for a template specialization type"); + + case TemplateName::SubstTemplateTemplateParm: + llvm_unreachable( + "substituted template template parameter handled above"); + + case TemplateName::SubstTemplateTemplateParmPack: { + // FIXME: not clear how to mangle this! + // template <template <class U> class T...> class A { + // template <class U...> void foo(decltype(T<U>::foo) x...); + // }; + Out << "_SUBSTPACK_"; + break; + } - case TemplateName::UsingTemplate: { - TemplateDecl *TD = TN.getAsTemplateDecl(); - assert(TD && !isa<TemplateTemplateParmDecl>(TD)); - mangleSourceNameWithAbiTags(TD); - break; - } + case TemplateName::PackIndexingTemplate: + DiagnoseUnsupportedPackIndexTemplateName(); + return false; + + case TemplateName::UsingTemplate: { + TemplateDecl *TD = TN.getAsTemplateDecl(); + assert(TD && !isa<TemplateTemplateParmDecl>(TD)); + mangleSourceNameWithAbiTags(TD); + break; + } + } } // Note: we don't pass in the template name here. We are mangling the @@ -7095,12 +7106,6 @@ void CXXNameMangler::mangleSeqID(unsigned SeqID) { Out << '_'; } -void CXXNameMangler::mangleExistingSubstitution(TemplateName tname) { - bool result = mangleSubstitution(tname); - assert(result && "no existing substitution for template name"); - (void) result; -} - // <substitution> ::= S <seq-id> _ // ::= S_ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp index 2fca98faadb16..0eb956d8965ac 100644 --- a/clang/test/CodeGenCXX/mangle-template.cpp +++ b/clang/test/CodeGenCXX/mangle-template.cpp @@ -433,3 +433,18 @@ namespace GH133610 { } // CHECK: @_ZN8GH1336101kINS_1CENS_1AIiEENS_1DEEEDtdtfp_sr1U1BIT1_EE3MEMET_T0_S5_ } // namespace GH133610 + +namespace GH88592 { + template <bool> struct A; + template <typename> struct B { static constexpr bool value = false; }; + + template <class T, template <class> class TT> + using C = A<TT<T>::value>; + + // The alias substitutes B for TT without B having been mangled earlier, so + // the substituted template template parameter can't be a substitution and + // must be mangled as the replacement template itself. + template <class T, C<T, B> * = nullptr> void f() {} + template void f<int>(); + // CHECK: @_ZN7GH885921fIiTnPNS_1AIXsr1BIT_EE5valueEEELPNS1_ILb0EEE0EEEvv +} // namespace GH88592 >From df0ef8eb8a7bbee80f932611c4ed55633f237835 Mon Sep 17 00:00:00 2001 From: ShengYi Hung <[email protected]> Date: Tue, 29 Sep 2026 20:24:13 -0500 Subject: [PATCH 2/3] fixup! [Clang] Do not assume existing substition for template specialization --- clang/lib/AST/ItaniumMangle.cpp | 114 +++++++++++++++----------------- 1 file changed, 55 insertions(+), 59 deletions(-) diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 507472db1e299..f8d7250d7279e 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -462,6 +462,8 @@ class CXXNameMangler { bool mangleSubstitution(TemplateName Template); bool mangleSubstitution(uintptr_t Ptr); + TemplateName mangleExistingSubstitution(TemplateName name); + bool mangleStandardSubstitution(const NamedDecl *ND); void addSubstitution(const NamedDecl *ND) { @@ -2587,71 +2589,55 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::TemplateSpecialization: { const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(Ty); - TemplateName TN = TST->getTemplateName(); - - // It is possible that a name doesn't mangled when reaching a substitution - // like alias template. - bool MangledAsSubstitution = false; - while (TN.getKind() == TemplateName::SubstTemplateTemplateParm) { - TemplateName Replacement = - TN.getAsSubstTemplateTemplateParm()->getReplacement(); - if (mangleSubstitution(Replacement)) { - MangledAsSubstitution = true; - break; - } - TN = Replacement; + TemplateName TN = mangleExistingSubstitution(TST->getTemplateName()); + switch (TN.getKind()) { + case TemplateName::Template: + case TemplateName::QualifiedTemplate: { + TemplateDecl *TD = TN.getAsTemplateDecl(); + + // If the base is a template template parameter, this is an + // unresolved type. + assert(TD && "no template for template specialization type"); + if (isa<TemplateTemplateParmDecl>(TD)) + goto unresolvedType; + + mangleSourceNameWithAbiTags(TD); + break; + } + case TemplateName::DependentTemplate: { + const DependentTemplateStorage *S = TN.getAsDependentTemplateName(); + mangleSourceName(S->getName().getIdentifier()); + break; } - if (!MangledAsSubstitution) { - switch (TN.getKind()) { - case TemplateName::Template: - case TemplateName::QualifiedTemplate: { - TemplateDecl *TD = TN.getAsTemplateDecl(); - - // If the base is a template template parameter, this is an - // unresolved type. - assert(TD && "no template for template specialization type"); - if (isa<TemplateTemplateParmDecl>(TD)) - goto unresolvedType; + case TemplateName::OverloadedTemplate: + case TemplateName::AssumedTemplate: + case TemplateName::DeducedTemplate: + llvm_unreachable("invalid base for a template specialization type"); - mangleSourceNameWithAbiTags(TD); - break; - } - case TemplateName::DependentTemplate: { - const DependentTemplateStorage *S = TN.getAsDependentTemplateName(); - mangleSourceName(S->getName().getIdentifier()); - break; - } + case TemplateName::SubstTemplateTemplateParm: + // mangleExistingSubstitution already mangled a substitution for it. + break; - case TemplateName::OverloadedTemplate: - case TemplateName::AssumedTemplate: - case TemplateName::DeducedTemplate: - llvm_unreachable("invalid base for a template specialization type"); - - case TemplateName::SubstTemplateTemplateParm: - llvm_unreachable( - "substituted template template parameter handled above"); - - case TemplateName::SubstTemplateTemplateParmPack: { - // FIXME: not clear how to mangle this! - // template <template <class U> class T...> class A { - // template <class U...> void foo(decltype(T<U>::foo) x...); - // }; - Out << "_SUBSTPACK_"; - break; - } + case TemplateName::SubstTemplateTemplateParmPack: { + // FIXME: not clear how to mangle this! + // template <template <class U> class T...> class A { + // template <class U...> void foo(decltype(T<U>::foo) x...); + // }; + Out << "_SUBSTPACK_"; + break; + } - case TemplateName::PackIndexingTemplate: - DiagnoseUnsupportedPackIndexTemplateName(); - return false; + case TemplateName::PackIndexingTemplate: + DiagnoseUnsupportedPackIndexTemplateName(); + return false; - case TemplateName::UsingTemplate: { - TemplateDecl *TD = TN.getAsTemplateDecl(); - assert(TD && !isa<TemplateTemplateParmDecl>(TD)); - mangleSourceNameWithAbiTags(TD); - break; - } - } + case TemplateName::UsingTemplate: { + TemplateDecl *TD = TN.getAsTemplateDecl(); + assert(TD && !isa<TemplateTemplateParmDecl>(TD)); + mangleSourceNameWithAbiTags(TD); + break; + } } // Note: we don't pass in the template name here. We are mangling the @@ -7106,6 +7092,16 @@ void CXXNameMangler::mangleSeqID(unsigned SeqID) { Out << '_'; } +TemplateName CXXNameMangler::mangleExistingSubstitution(TemplateName tname) { + while (SubstTemplateTemplateParmStorage *subst = + tname.getAsSubstTemplateTemplateParm()) { + if (mangleSubstitution(subst->getReplacement())) + return tname; + tname = subst->getReplacement(); + } + return tname; +} + // <substitution> ::= S <seq-id> _ // ::= S_ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { >From 6c43b4fcd7b6dca088dd4047c958d7c8504e0100 Mon Sep 17 00:00:00 2001 From: ShengYi Hung <[email protected]> Date: Tue, 13 Oct 2026 00:07:39 -0500 Subject: [PATCH 3/3] fixup! [Clang] Do not assume existing substition for template specialization --- clang/docs/ReleaseNotes.md | 8 ++++++-- clang/lib/AST/ItaniumMangle.cpp | 2 ++ ...e-subst-template-template-parm-gh88592.cpp | 20 +++++++++++++++++++ clang/test/CodeGenCXX/mangle-template.cpp | 15 -------------- 4 files changed, 28 insertions(+), 17 deletions(-) create mode 100644 clang/test/CodeGenCXX/mangle-subst-template-template-parm-gh88592.cpp diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 3257e5894c2e1..9d200294530c5 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -64,6 +64,11 @@ in a future version of Clang. ### ABI Changes in This Version +- Clang now mangles a template template parameter that was substituted through + an alias template and is used as the base of an unresolved name, such as + `TT<T>::value` in a non-type template parameter's type, as the substituted + template. Previous versions emitted an ill-formed symbol with no name in that + position. `-fclang-abi-compat=23` restores the previous behavior. (#GH88592) - Except on PlayStation, Clang now derives the x86-64 System V AVX ABI level for 256- and 512-bit vector arguments and returns from effective per-function target features. Features and `arch=` CPUs that imply AVX or AVX512F are @@ -999,12 +1004,11 @@ features cannot lower the translation-unit ABI level; - Fixed an assertion failure when a method or function definition follows an Objective-C `@implementation` that was ended by a nested `@interface`, `@protocol` or `@implementation` before its `@end`. (#GH209503) +- Fixed use-after-free with annotate attribute on a C++ class method with a this-adjusting thunk. - Fixed an assertion failure in the Itanium mangler when a template template parameter substituted through an alias template is used as the base of an unresolved name, such as `TT<T>::value` in a non-type template parameter's type. (#GH88592) -- Fixed use-after-free with annotate attribute on a C++ class method with a this-adjusting thunk. ->>>>>>> main ### OpenACC Specific Changes diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 2150eb3ccfc77..3485825e30327 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -7173,6 +7173,8 @@ TemplateName CXXNameMangler::mangleExistingSubstitution(TemplateName tname) { tname.getAsSubstTemplateTemplateParm()) { if (mangleSubstitution(subst->getReplacement())) return tname; + if (isCompatibleWith(LangOptions::ClangABI::Ver23)) + return tname; tname = subst->getReplacement(); } return tname; diff --git a/clang/test/CodeGenCXX/mangle-subst-template-template-parm-gh88592.cpp b/clang/test/CodeGenCXX/mangle-subst-template-template-parm-gh88592.cpp new file mode 100644 index 0000000000000..2fd34d58d0ba7 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-subst-template-template-parm-gh88592.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++20 -fclang-abi-compat=latest -emit-llvm -triple x86_64-linux-gnu -o - %s | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -fclang-abi-compat=23 -emit-llvm -triple x86_64-linux-gnu -o - %s | FileCheck --check-prefix=ABICOMPAT23 %s + +namespace GH88592 { + template <bool> struct A; + template <typename> struct B { static constexpr bool value = false; }; + + template <class T, template <class> class TT> + using C = A<TT<T>::value>; + + // The alias substitutes B for TT without B having been mangled earlier, so + // the substituted template template parameter can't be a substitution and + // must be mangled as the replacement template itself. + template <class T, C<T, B> * = nullptr> void f() {} + template void f<int>(); + // CHECK: @_ZN7GH885921fIiTnPNS_1AIXsr1BIT_EE5valueEEELPNS1_ILb0EEE0EEEvv + // Clang 23 and before mangled nothing for the template name, producing an + // ill-formed symbol. + // ABICOMPAT23: @_ZN7GH885921fIiTnPNS_1AIXsrIT_EE5valueEEELPNS1_ILb0EEE0EEEvv +} // namespace GH88592 diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp index 0eb956d8965ac..2fca98faadb16 100644 --- a/clang/test/CodeGenCXX/mangle-template.cpp +++ b/clang/test/CodeGenCXX/mangle-template.cpp @@ -433,18 +433,3 @@ namespace GH133610 { } // CHECK: @_ZN8GH1336101kINS_1CENS_1AIiEENS_1DEEEDtdtfp_sr1U1BIT1_EE3MEMET_T0_S5_ } // namespace GH133610 - -namespace GH88592 { - template <bool> struct A; - template <typename> struct B { static constexpr bool value = false; }; - - template <class T, template <class> class TT> - using C = A<TT<T>::value>; - - // The alias substitutes B for TT without B having been mangled earlier, so - // the substituted template template parameter can't be a substitution and - // must be mangled as the replacement template itself. - template <class T, C<T, B> * = nullptr> void f() {} - template void f<int>(); - // CHECK: @_ZN7GH885921fIiTnPNS_1AIXsr1BIT_EE5valueEEELPNS1_ILb0EEE0EEEvv -} // namespace GH88592 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
