https://github.com/oToToT created 
https://github.com/llvm/llvm-project/pull/182667

During lambda numbering, ItaniumNumberingContext::getManglingNumber() computes
the lambda’s <lambda-sig> by mangling the call operator type. If that type
contains decltype(init-capture), mangling re-enters the init-capture VarDecl.
For problematic cases, this recurses back into operator() mangling.

Make init-capture handling in mangleLocalName() explicit:
* If the init-capture belongs to a lambda that has a closure-prefix context,
  mangle it directly with mangleNestedNameWithClosurePrefix().
* Otherwise keep local-name mangling, but for local lambdas use the parent
  local container as the function-encoding base to avoid self-recursion.

Also publish lambda ContextDecl early in Sema::handleLambdaNumbering() before
calling getManglingNumber(Method), via a dedicated
CXXRecordDecl::setLambdaContextDecl() helper. This provides the needed context
for context-sensitive mangling without publishing provisional numbering state.

Add non-local regression tests in mangle-lambdas.cpp for:
* variable-template lambda init-capture used in decltype(x)
* static inline member lambda init-capture used in decltype(x)

This PR
* Fixes https://github.com/llvm/llvm-project/issues/63271
* Fixes https://github.com/llvm/llvm-project/issues/86240
* Fixes https://github.com/llvm/llvm-project/issues/139089

>From 95f808bf460eb8f9eebc2e295dae56800a73f2cf Mon Sep 17 00:00:00 2001
From: Tommy Chiang <[email protected]>
Date: Fri, 20 Feb 2026 15:50:53 +0800
Subject: [PATCH 1/2] [NFC][ItaniumMangle] Format code and fix
 `llvm-else-after-return`

Run `clang-format -i clang/lib/AST/ItaniumMangle.cpp`
and fix the `llvm-else-after-return` clang-tidy warning manually.
---
 clang/lib/AST/ItaniumMangle.cpp | 717 ++++++++++++++++++--------------
 1 file changed, 416 insertions(+), 301 deletions(-)

diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 70acc8a78ed52..4618fc58c886a 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -68,9 +68,9 @@ static bool isLambda(const NamedDecl *ND) {
 static const unsigned UnknownArity = ~0U;
 
 class ItaniumMangleContextImpl : public ItaniumMangleContext {
-  typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy;
+  typedef std::pair<const DeclContext *, IdentifierInfo *> DiscriminatorKeyTy;
   llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
-  llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
+  llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
   const DiscriminatorOverrideTy DiscriminatorOverride = nullptr;
   NamespaceDecl *StdNamespace = nullptr;
 
@@ -162,7 +162,7 @@ class ItaniumMangleContextImpl : public 
ItaniumMangleContext {
     }
     if (discriminator == 1)
       return false;
-    disc = discriminator-2;
+    disc = discriminator - 2;
     return true;
   }
 
@@ -249,14 +249,10 @@ class CXXNameMangler {
     FunctionTypeDepthState() = default;
 
     /// The number of function types we're inside.
-    unsigned getDepth() const {
-      return Bits >> 1;
-    }
+    unsigned getDepth() const { return Bits >> 1; }
 
     /// True if we're in the return type of the innermost function type.
-    bool isInResultType() const {
-      return Bits & InResultTypeMask;
-    }
+    bool isInResultType() const { return Bits & InResultTypeMask; }
 
     FunctionTypeDepthState push() {
       FunctionTypeDepthState tmp = *this;
@@ -264,13 +260,9 @@ class CXXNameMangler {
       return tmp;
     }
 
-    void enterResultType() {
-      Bits |= InResultTypeMask;
-    }
+    void enterResultType() { Bits |= InResultTypeMask; }
 
-    void leaveResultType() {
-      Bits &= ~InResultTypeMask;
-    }
+    void leaveResultType() { Bits &= ~InResultTypeMask; }
 
     void pop(FunctionTypeDepthState saved) {
       assert(getDepth() == saved.getDepth() + 1);
@@ -334,13 +326,9 @@ class CXXNameMangler {
     }
 
     const AbiTagList &getUsedAbiTags() const { return UsedAbiTags; }
-    void setUsedAbiTags(const AbiTagList &AbiTags) {
-      UsedAbiTags = AbiTags;
-    }
+    void setUsedAbiTags(const AbiTagList &AbiTags) { UsedAbiTags = AbiTags; }
 
-    const AbiTagList &getEmittedAbiTags() const {
-      return EmittedAbiTags;
-    }
+    const AbiTagList &getEmittedAbiTags() const { return EmittedAbiTags; }
 
     const AbiTagList &getSortedUniqueUsedAbiTags() {
       llvm::sort(UsedAbiTags);
@@ -406,8 +394,7 @@ class CXXNameMangler {
       : Context(C), Out(Out_), NullOut(NullOut_), Structor(getStructor(D)),
         AbiTagsRoot(AbiTags) {
     // These can't be mangled without a ctor type or dtor type.
-    assert(!D || (!isa<CXXDestructorDecl>(D) &&
-                  !isa<CXXConstructorDecl>(D)));
+    assert(!D || (!isa<CXXDestructorDecl>(D) && !isa<CXXConstructorDecl>(D)));
   }
   CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
                  const CXXConstructorDecl *D, CXXCtorType Type)
@@ -434,7 +421,9 @@ class CXXNameMangler {
     NullOut = true;
   }
 
-  struct WithTemplateDepthOffset { unsigned Offset; };
+  struct WithTemplateDepthOffset {
+    unsigned Offset;
+  };
   CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out,
                  WithTemplateDepthOffset Offset)
       : CXXNameMangler(C, Out) {
@@ -481,7 +470,7 @@ class CXXNameMangler {
   void addSubstitution(TemplateName Template);
   void addSubstitution(uintptr_t Ptr);
   // Destructive copy substitutions from other mangler.
-  void extendSubstitutions(CXXNameMangler* Other);
+  void extendSubstitutions(CXXNameMangler *Other);
 
   void mangleUnresolvedPrefix(NestedNameSpecifier Qualifier,
                               bool recursive = false);
@@ -513,10 +502,10 @@ class CXXNameMangler {
   void mangleRegCallName(const IdentifierInfo *II);
   void mangleDeviceStubName(const IdentifierInfo *II);
   void mangleOCLDeviceStubName(const IdentifierInfo *II);
-  void mangleSourceNameWithAbiTags(
-      const NamedDecl *ND, const AbiTagList *AdditionalAbiTags = nullptr);
-  void mangleLocalName(GlobalDecl GD,
-                       const AbiTagList *AdditionalAbiTags);
+  void
+  mangleSourceNameWithAbiTags(const NamedDecl *ND,
+                              const AbiTagList *AdditionalAbiTags = nullptr);
+  void mangleLocalName(GlobalDecl GD, const AbiTagList *AdditionalAbiTags);
   void mangleBlockForPrefix(const BlockDecl *Block);
   void mangleUnqualifiedBlock(const BlockDecl *Block);
   void mangleTemplateParamDecl(const NamedDecl *Decl);
@@ -528,16 +517,16 @@ class CXXNameMangler {
   void mangleLambda(const CXXRecordDecl *Lambda);
   void mangleNestedName(GlobalDecl GD, const DeclContext *DC,
                         const AbiTagList *AdditionalAbiTags,
-                        bool NoFunction=false);
+                        bool NoFunction = false);
   void mangleNestedName(const TemplateDecl *TD,
                         ArrayRef<TemplateArgument> Args);
   void mangleNestedNameWithClosurePrefix(GlobalDecl GD,
                                          const NamedDecl *PrefixND,
                                          const AbiTagList *AdditionalAbiTags);
   void manglePrefix(NestedNameSpecifier Qualifier);
-  void manglePrefix(const DeclContext *DC, bool NoFunction=false);
+  void manglePrefix(const DeclContext *DC, bool NoFunction = false);
   void manglePrefix(QualType type);
-  void mangleTemplatePrefix(GlobalDecl GD, bool NoFunction=false);
+  void mangleTemplatePrefix(GlobalDecl GD, bool NoFunction = false);
   void mangleTemplatePrefix(TemplateName Template);
   const NamedDecl *getClosurePrefix(const Decl *ND);
   void mangleClosurePrefix(const NamedDecl *ND, bool NoFunction = false);
@@ -545,7 +534,8 @@ class CXXNameMangler {
                                       StringRef Prefix = "");
   void mangleOperatorName(DeclarationName Name, unsigned Arity);
   void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
-  void mangleQualifiers(Qualifiers Quals, const DependentAddressSpaceType 
*DAST = nullptr);
+  void mangleQualifiers(Qualifiers Quals,
+                        const DependentAddressSpaceType *DAST = nullptr);
   void mangleRefQualifier(RefQualifierKind RefQualifier);
 
   void mangleObjCMethodName(const ObjCMethodDecl *MD);
@@ -556,7 +546,7 @@ class CXXNameMangler {
 #define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
 #include "clang/AST/TypeNodes.inc"
 
-  void mangleType(const TagType*);
+  void mangleType(const TagType *);
   void mangleType(TemplateName);
   static StringRef getCallingConvQualifierName(CallingConv CC);
   void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
@@ -610,8 +600,7 @@ class CXXNameMangler {
 
   void mangleFunctionParam(const ParmVarDecl *parm);
 
-  void writeAbiTags(const NamedDecl *ND,
-                    const AbiTagList *AdditionalAbiTags);
+  void writeAbiTags(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags);
 
   // Returns sorted unique list of ABI tags.
   AbiTagList makeFunctionReturnTypeTags(const FunctionDecl *FD);
@@ -619,7 +608,7 @@ class CXXNameMangler {
   AbiTagList makeVariableTypeTags(const VarDecl *VD);
 };
 
-}
+} // namespace
 
 NamespaceDecl *ItaniumMangleContextImpl::getStdNamespace() {
   if (!StdNamespace) {
@@ -962,8 +951,8 @@ bool CXXNameMangler::isStdNamespace(const DeclContext *DC) {
   return isStd(cast<NamespaceDecl>(DC));
 }
 
-static const GlobalDecl
-isTemplate(GlobalDecl GD, const TemplateArgumentList *&TemplateArgs) {
+static const GlobalDecl isTemplate(GlobalDecl GD,
+                                   const TemplateArgumentList *&TemplateArgs) {
   const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
   // Check if we have a function template.
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
@@ -975,7 +964,7 @@ isTemplate(GlobalDecl GD, const TemplateArgumentList 
*&TemplateArgs) {
 
   // Check if we have a class template.
   if (const ClassTemplateSpecializationDecl *Spec =
-        dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+          dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
     TemplateArgs = &Spec->getTemplateArgs();
     return GD.getWithDecl(Spec->getSpecializedTemplate());
   }
@@ -992,7 +981,7 @@ isTemplate(GlobalDecl GD, const TemplateArgumentList 
*&TemplateArgs) {
 
 static TemplateName asTemplateName(GlobalDecl GD) {
   const TemplateDecl *TD = dyn_cast_or_null<TemplateDecl>(GD.getDecl());
-  return TemplateName(const_cast<TemplateDecl*>(TD));
+  return TemplateName(const_cast<TemplateDecl *>(TD));
 }
 
 void CXXNameMangler::mangleName(GlobalDecl GD) {
@@ -1040,8 +1029,8 @@ const RecordDecl *CXXNameMangler::GetLocalClassDecl(const 
Decl *D) {
   return nullptr;
 }
 
-void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
-                                           const AbiTagList 
*AdditionalAbiTags) {
+void CXXNameMangler::mangleNameWithAbiTags(
+    GlobalDecl GD, const AbiTagList *AdditionalAbiTags) {
   const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
   //  <name> ::= [<module-name>] <nested-name>
   //         ::= [<module-name>] <unscoped-name>
@@ -1230,10 +1219,8 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) 
{
     hexDigit &= 0xF;
 
     // Map that over to a lowercase hex digit.
-    static const char charForHex[16] = {
-      '0', '1', '2', '3', '4', '5', '6', '7',
-      '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
-    };
+    static const char charForHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                                        '8', '9', 'a', 'b', 'c', 'd', 'e', 
'f'};
     buffer[stringIndex] = charForHex[hexDigit];
   }
 
@@ -1420,32 +1407,32 @@ void CXXNameMangler::mangleUnresolvedName(
   if (Qualifier)
     mangleUnresolvedPrefix(Qualifier);
   switch (name.getNameKind()) {
-    // <base-unresolved-name> ::= <simple-id>
-    case DeclarationName::Identifier:
-      mangleSourceName(name.getAsIdentifierInfo());
-      break;
-    // <base-unresolved-name> ::= dn <destructor-name>
-    case DeclarationName::CXXDestructorName:
-      Out << "dn";
-      mangleUnresolvedTypeOrSimpleId(name.getCXXNameType());
-      break;
-    // <base-unresolved-name> ::= on <operator-name>
-    case DeclarationName::CXXConversionFunctionName:
-    case DeclarationName::CXXLiteralOperatorName:
-    case DeclarationName::CXXOperatorName:
-      Out << "on";
-      mangleOperatorName(name, knownArity);
-      break;
-    case DeclarationName::CXXConstructorName:
-      llvm_unreachable("Can't mangle a constructor name!");
-    case DeclarationName::CXXUsingDirective:
-      llvm_unreachable("Can't mangle a using directive name!");
-    case DeclarationName::CXXDeductionGuideName:
-      llvm_unreachable("Can't mangle a deduction guide name!");
-    case DeclarationName::ObjCMultiArgSelector:
-    case DeclarationName::ObjCOneArgSelector:
-    case DeclarationName::ObjCZeroArgSelector:
-      llvm_unreachable("Can't mangle Objective-C selector names here!");
+  // <base-unresolved-name> ::= <simple-id>
+  case DeclarationName::Identifier:
+    mangleSourceName(name.getAsIdentifierInfo());
+    break;
+  // <base-unresolved-name> ::= dn <destructor-name>
+  case DeclarationName::CXXDestructorName:
+    Out << "dn";
+    mangleUnresolvedTypeOrSimpleId(name.getCXXNameType());
+    break;
+  // <base-unresolved-name> ::= on <operator-name>
+  case DeclarationName::CXXConversionFunctionName:
+  case DeclarationName::CXXLiteralOperatorName:
+  case DeclarationName::CXXOperatorName:
+    Out << "on";
+    mangleOperatorName(name, knownArity);
+    break;
+  case DeclarationName::CXXConstructorName:
+    llvm_unreachable("Can't mangle a constructor name!");
+  case DeclarationName::CXXUsingDirective:
+    llvm_unreachable("Can't mangle a using directive name!");
+  case DeclarationName::CXXDeductionGuideName:
+    llvm_unreachable("Can't mangle a deduction guide name!");
+  case DeclarationName::ObjCMultiArgSelector:
+  case DeclarationName::ObjCOneArgSelector:
+  case DeclarationName::ObjCZeroArgSelector:
+    llvm_unreachable("Can't mangle Objective-C selector names here!");
   }
 
   // The <simple-id> and on <operator-name> productions end in an optional
@@ -1531,9 +1518,9 @@ void CXXNameMangler::mangleUnqualifiedName(
       if (Context.isInternalLinkageDecl(ND))
         Out << 'L';
 
-      bool IsRegCall = FD &&
-                       FD->getType()->castAs<FunctionType>()->getCallConv() ==
-                           clang::CC_X86RegCall;
+      bool IsRegCall =
+          FD && FD->getType()->castAs<FunctionType>()->getCallConv() ==
+                    clang::CC_X86RegCall;
       bool IsDeviceStub =
           FD && FD->hasAttr<CUDAGlobalAttr>() &&
           GD.getKernelReferenceKind() == KernelReferenceKind::Stub;
@@ -1578,14 +1565,15 @@ void CXXNameMangler::mangleUnqualifiedName(
       //   the data members in the union are unnamed), then there is no way for
       //   a program to refer to the anonymous union, and there is therefore no
       //   need to mangle its name.
-      assert(RD->isAnonymousStructOrUnion()
-             && "Expected anonymous struct or union!");
+      assert(RD->isAnonymousStructOrUnion() &&
+             "Expected anonymous struct or union!");
       const FieldDecl *FD = RD->findFirstNamedDataMember();
 
       // It's actually possible for various reasons for us to get here
       // with an empty anonymous struct / union.  Fortunately, it
       // doesn't really matter what name we generate.
-      if (!FD) break;
+      if (!FD)
+        break;
       assert(FD->getIdentifier() && "Data member name isn't an identifier!");
 
       mangleSourceName(FD->getIdentifier());
@@ -1778,8 +1766,7 @@ void CXXNameMangler::mangleSourceName(const 
IdentifierInfo *II) {
   Out << II->getLength() << II->getName();
 }
 
-void CXXNameMangler::mangleNestedName(GlobalDecl GD,
-                                      const DeclContext *DC,
+void CXXNameMangler::mangleNestedName(GlobalDecl GD, const DeclContext *DC,
                                       const AbiTagList *AdditionalAbiTags,
                                       bool NoFunction) {
   const NamedDecl *ND = cast<NamedDecl>(GD.getDecl());
@@ -1898,10 +1885,10 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
     // -- other default arguments do not affect its encoding.
     const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD);
     if (CXXRD && CXXRD->isLambda()) {
-      if (const ParmVarDecl *Parm
-              = dyn_cast_or_null<ParmVarDecl>(CXXRD->getLambdaContextDecl())) {
-        if (const FunctionDecl *Func
-              = dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
+      if (const ParmVarDecl *Parm =
+              dyn_cast_or_null<ParmVarDecl>(CXXRD->getLambdaContextDecl())) {
+        if (const FunctionDecl *Func =
+                dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
           Out << 'd';
           unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex();
           if (Num > 1)
@@ -1913,7 +1900,7 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
 
     // Mangle the name relative to the closest enclosing function.
     // equality ok because RD derived from ND above
-    if (D == RD)  {
+    if (D == RD) {
       mangleUnqualifiedName(RD, DC, AdditionalAbiTags);
     } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
       if (const NamedDecl *PrefixND = getClosurePrefix(BD))
@@ -1930,10 +1917,10 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
   } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
     // Mangle a block in a default parameter; see above explanation for
     // lambdas.
-    if (const ParmVarDecl *Parm
-            = 
dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl())) {
-      if (const FunctionDecl *Func
-            = dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
+    if (const ParmVarDecl *Parm =
+            dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl())) {
+      if (const FunctionDecl *Func =
+              dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
         Out << 'd';
         unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex();
         if (Num > 1)
@@ -2101,8 +2088,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl 
*Lambda) {
     if (isCompatibleWith(LangOptions::ClangABI::Ver12) &&
         (isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
         !isa<ParmVarDecl>(Context)) {
-      if (const IdentifierInfo *Name
-            = cast<NamedDecl>(Context)->getIdentifier()) {
+      if (const IdentifierInfo *Name =
+              cast<NamedDecl>(Context)->getIdentifier()) {
         mangleSourceName(Name);
         const TemplateArgumentList *TemplateArgs = nullptr;
         if (GlobalDecl TD = isTemplate(cast<NamedDecl>(Context), TemplateArgs))
@@ -2242,8 +2229,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName 
Template) {
   addSubstitution(Template);
 }
 
-void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD,
-                                          bool NoFunction) {
+void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD, bool NoFunction) {
   const TemplateDecl *ND = cast<TemplateDecl>(GD.getDecl());
   // <template-prefix> ::= <prefix> <template unqualified-name>
   //                   ::= <template-param>
@@ -2360,8 +2346,8 @@ void CXXNameMangler::mangleType(TemplateName TN) {
     // template.  This will check for the substitution twice, which is
     // fine, but we have to return early so that we don't try to *add*
     // the substitution twice.
-    SubstTemplateTemplateParmStorage *subst
-      = TN.getAsSubstTemplateTemplateParm();
+    SubstTemplateTemplateParmStorage *subst =
+        TN.getAsSubstTemplateTemplateParm();
     mangleType(subst->getReplacement());
     return;
   }
@@ -2484,8 +2470,7 @@ bool 
CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
     break;
 
   case Type::UnresolvedUsing:
-    mangleSourceNameWithAbiTags(
-        cast<UnresolvedUsingType>(Ty)->getDecl());
+    mangleSourceNameWithAbiTags(cast<UnresolvedUsingType>(Ty)->getDecl());
     break;
 
   case Type::Enum:
@@ -2601,113 +2586,199 @@ void 
CXXNameMangler::mangleOperatorName(DeclarationName Name, unsigned Arity) {
   }
 }
 
-void
-CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
+void CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
+                                        unsigned Arity) {
   switch (OO) {
   // <operator-name> ::= nw     # new
-  case OO_New: Out << "nw"; break;
+  case OO_New:
+    Out << "nw";
+    break;
   //              ::= na        # new[]
-  case OO_Array_New: Out << "na"; break;
+  case OO_Array_New:
+    Out << "na";
+    break;
   //              ::= dl        # delete
-  case OO_Delete: Out << "dl"; break;
+  case OO_Delete:
+    Out << "dl";
+    break;
   //              ::= da        # delete[]
-  case OO_Array_Delete: Out << "da"; break;
+  case OO_Array_Delete:
+    Out << "da";
+    break;
   //              ::= ps        # + (unary)
   //              ::= pl        # + (binary or unknown)
   case OO_Plus:
-    Out << (Arity == 1? "ps" : "pl"); break;
+    Out << (Arity == 1 ? "ps" : "pl");
+    break;
   //              ::= ng        # - (unary)
   //              ::= mi        # - (binary or unknown)
   case OO_Minus:
-    Out << (Arity == 1? "ng" : "mi"); break;
+    Out << (Arity == 1 ? "ng" : "mi");
+    break;
   //              ::= ad        # & (unary)
   //              ::= an        # & (binary or unknown)
   case OO_Amp:
-    Out << (Arity == 1? "ad" : "an"); break;
+    Out << (Arity == 1 ? "ad" : "an");
+    break;
   //              ::= de        # * (unary)
   //              ::= ml        # * (binary or unknown)
   case OO_Star:
     // Use binary when unknown.
-    Out << (Arity == 1? "de" : "ml"); break;
+    Out << (Arity == 1 ? "de" : "ml");
+    break;
   //              ::= co        # ~
-  case OO_Tilde: Out << "co"; break;
+  case OO_Tilde:
+    Out << "co";
+    break;
   //              ::= dv        # /
-  case OO_Slash: Out << "dv"; break;
+  case OO_Slash:
+    Out << "dv";
+    break;
   //              ::= rm        # %
-  case OO_Percent: Out << "rm"; break;
+  case OO_Percent:
+    Out << "rm";
+    break;
   //              ::= or        # |
-  case OO_Pipe: Out << "or"; break;
+  case OO_Pipe:
+    Out << "or";
+    break;
   //              ::= eo        # ^
-  case OO_Caret: Out << "eo"; break;
+  case OO_Caret:
+    Out << "eo";
+    break;
   //              ::= aS        # =
-  case OO_Equal: Out << "aS"; break;
+  case OO_Equal:
+    Out << "aS";
+    break;
   //              ::= pL        # +=
-  case OO_PlusEqual: Out << "pL"; break;
+  case OO_PlusEqual:
+    Out << "pL";
+    break;
   //              ::= mI        # -=
-  case OO_MinusEqual: Out << "mI"; break;
+  case OO_MinusEqual:
+    Out << "mI";
+    break;
   //              ::= mL        # *=
-  case OO_StarEqual: Out << "mL"; break;
+  case OO_StarEqual:
+    Out << "mL";
+    break;
   //              ::= dV        # /=
-  case OO_SlashEqual: Out << "dV"; break;
+  case OO_SlashEqual:
+    Out << "dV";
+    break;
   //              ::= rM        # %=
-  case OO_PercentEqual: Out << "rM"; break;
+  case OO_PercentEqual:
+    Out << "rM";
+    break;
   //              ::= aN        # &=
-  case OO_AmpEqual: Out << "aN"; break;
+  case OO_AmpEqual:
+    Out << "aN";
+    break;
   //              ::= oR        # |=
-  case OO_PipeEqual: Out << "oR"; break;
+  case OO_PipeEqual:
+    Out << "oR";
+    break;
   //              ::= eO        # ^=
-  case OO_CaretEqual: Out << "eO"; break;
+  case OO_CaretEqual:
+    Out << "eO";
+    break;
   //              ::= ls        # <<
-  case OO_LessLess: Out << "ls"; break;
+  case OO_LessLess:
+    Out << "ls";
+    break;
   //              ::= rs        # >>
-  case OO_GreaterGreater: Out << "rs"; break;
+  case OO_GreaterGreater:
+    Out << "rs";
+    break;
   //              ::= lS        # <<=
-  case OO_LessLessEqual: Out << "lS"; break;
+  case OO_LessLessEqual:
+    Out << "lS";
+    break;
   //              ::= rS        # >>=
-  case OO_GreaterGreaterEqual: Out << "rS"; break;
+  case OO_GreaterGreaterEqual:
+    Out << "rS";
+    break;
   //              ::= eq        # ==
-  case OO_EqualEqual: Out << "eq"; break;
+  case OO_EqualEqual:
+    Out << "eq";
+    break;
   //              ::= ne        # !=
-  case OO_ExclaimEqual: Out << "ne"; break;
+  case OO_ExclaimEqual:
+    Out << "ne";
+    break;
   //              ::= lt        # <
-  case OO_Less: Out << "lt"; break;
+  case OO_Less:
+    Out << "lt";
+    break;
   //              ::= gt        # >
-  case OO_Greater: Out << "gt"; break;
+  case OO_Greater:
+    Out << "gt";
+    break;
   //              ::= le        # <=
-  case OO_LessEqual: Out << "le"; break;
+  case OO_LessEqual:
+    Out << "le";
+    break;
   //              ::= ge        # >=
-  case OO_GreaterEqual: Out << "ge"; break;
+  case OO_GreaterEqual:
+    Out << "ge";
+    break;
   //              ::= nt        # !
-  case OO_Exclaim: Out << "nt"; break;
+  case OO_Exclaim:
+    Out << "nt";
+    break;
   //              ::= aa        # &&
-  case OO_AmpAmp: Out << "aa"; break;
+  case OO_AmpAmp:
+    Out << "aa";
+    break;
   //              ::= oo        # ||
-  case OO_PipePipe: Out << "oo"; break;
+  case OO_PipePipe:
+    Out << "oo";
+    break;
   //              ::= pp        # ++
-  case OO_PlusPlus: Out << "pp"; break;
+  case OO_PlusPlus:
+    Out << "pp";
+    break;
   //              ::= mm        # --
-  case OO_MinusMinus: Out << "mm"; break;
+  case OO_MinusMinus:
+    Out << "mm";
+    break;
   //              ::= cm        # ,
-  case OO_Comma: Out << "cm"; break;
+  case OO_Comma:
+    Out << "cm";
+    break;
   //              ::= pm        # ->*
-  case OO_ArrowStar: Out << "pm"; break;
+  case OO_ArrowStar:
+    Out << "pm";
+    break;
   //              ::= pt        # ->
-  case OO_Arrow: Out << "pt"; break;
+  case OO_Arrow:
+    Out << "pt";
+    break;
   //              ::= cl        # ()
-  case OO_Call: Out << "cl"; break;
+  case OO_Call:
+    Out << "cl";
+    break;
   //              ::= ix        # []
-  case OO_Subscript: Out << "ix"; break;
+  case OO_Subscript:
+    Out << "ix";
+    break;
 
   //              ::= qu        # ?
   // The conditional operator can't be overloaded, but we still handle it when
   // mangling expressions.
-  case OO_Conditional: Out << "qu"; break;
+  case OO_Conditional:
+    Out << "qu";
+    break;
   // Proposal on cxx-abi-dev, 2015-10-21.
   //              ::= aw        # co_await
-  case OO_Coawait: Out << "aw"; break;
+  case OO_Coawait:
+    Out << "aw";
+    break;
   // Proposed in cxx-abi github issue 43.
   //              ::= ss        # <=>
-  case OO_Spaceship: Out << "ss"; break;
+  case OO_Spaceship:
+    Out << "ss";
+    break;
 
   case OO_None:
   case NUM_OVERLOADED_OPERATORS:
@@ -2715,7 +2786,8 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind 
OO, unsigned Arity) {
   }
 }
 
-void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const 
DependentAddressSpaceType *DAST) {
+void CXXNameMangler::mangleQualifiers(Qualifiers Quals,
+                                      const DependentAddressSpaceType *DAST) {
   // Vendor qualifiers come first and if they are order-insensitive they must
   // be emitted in reversed alphabetical order, see Itanium ABI 5.1.5.
 
@@ -2745,7 +2817,8 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, 
const DependentAddressSp
         ASString = "AS" + llvm::utostr(TargetAS);
     } else {
       switch (AS) {
-      default: llvm_unreachable("Not a language specific address space");
+      default:
+        llvm_unreachable("Not a language specific address space");
       //  <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" |
       //                                "private"| "generic" | "device" |
       //                                "host" ]
@@ -2987,8 +3060,8 @@ void CXXNameMangler::mangleType(QualType T) {
     do {
       // Don't desugar through template specialization types that aren't
       // type aliases. We need to mangle the template arguments as written.
-      if (const TemplateSpecializationType *TST
-                                      = 
dyn_cast<TemplateSpecializationType>(T))
+      if (const TemplateSpecializationType *TST =
+              dyn_cast<TemplateSpecializationType>(T))
         if (!TST->isTypeAlias())
           break;
 
@@ -2996,8 +3069,8 @@ void CXXNameMangler::mangleType(QualType T) {
       // instantation-dependent qualifiers. See
       // https://github.com/itanium-cxx-abi/cxx-abi/issues/114.
 
-      QualType Desugared
-        = T.getSingleStepDesugaredType(Context.getASTContext());
+      QualType Desugared =
+          T.getSingleStepDesugaredType(Context.getASTContext());
       if (Desugared == T)
         break;
 
@@ -3009,7 +3082,7 @@ void CXXNameMangler::mangleType(QualType T) {
   const Type *ty = split.Ty;
 
   bool isSubstitutable =
-    isTypeSubstitutable(quals, ty, Context.getASTContext());
+      isTypeSubstitutable(quals, ty, Context.getASTContext());
   if (isSubstitutable && mangleSubstitution(T))
     return;
 
@@ -3025,7 +3098,7 @@ void CXXNameMangler::mangleType(QualType T) {
 
   if (quals || ty->isDependentAddressSpaceType()) {
     if (const DependentAddressSpaceType *DAST =
-        dyn_cast<DependentAddressSpaceType>(ty)) {
+            dyn_cast<DependentAddressSpaceType>(ty)) {
       SplitQualType splitDAST = DAST->getPointeeType().split();
       mangleQualifiers(splitDAST.Quals, DAST);
       mangleType(QualType(splitDAST.Ty, 0));
@@ -3039,14 +3112,14 @@ void CXXNameMangler::mangleType(QualType T) {
   } else {
     switch (ty->getTypeClass()) {
 #define ABSTRACT_TYPE(CLASS, PARENT)
-#define NON_CANONICAL_TYPE(CLASS, PARENT) \
-    case Type::CLASS: \
-      llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
-      return;
-#define TYPE(CLASS, PARENT) \
-    case Type::CLASS: \
-      mangleType(static_cast<const CLASS##Type*>(ty)); \
-      break;
+#define NON_CANONICAL_TYPE(CLASS, PARENT)                                      
\
+  case Type::CLASS:                                                            
\
+    llvm_unreachable("can't mangle non-canonical type " #CLASS "Type");        
\
+    return;
+#define TYPE(CLASS, PARENT)                                                    
\
+  case Type::CLASS:                                                            
\
+    mangleType(static_cast<const CLASS##Type *>(ty));                          
\
+    break;
 #include "clang/AST/TypeNodes.inc"
     }
   }
@@ -3093,7 +3166,8 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
   // UNSUPPORTED:    ::= De # IEEE 754r decimal floating point (128 bits)
   // UNSUPPORTED:    ::= Df # IEEE 754r decimal floating point (32 bits)
   //                 ::= Dh # IEEE 754r half-precision floating point (16 bits)
-  //                 ::= DF <number> _ # ISO/IEC TS 18661 binary floating 
point type _FloatN (N bits);
+  //                 ::= DF <number> _ # ISO/IEC TS 18661 binary floating point
+  //                 type _FloatN (N bits);
   //                 ::= Di # char32_t
   //                 ::= Ds # char16_t
   //                 ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
@@ -3370,8 +3444,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
     break;
 
 #define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) \
-  case BuiltinType::Id:
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
 #include "clang/AST/BuiltinTypes.def"
   case BuiltinType::Dependent:
     if (!NullOut)
@@ -3386,10 +3459,10 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
   case BuiltinType::ObjCSel:
     Out << "13objc_selector";
     break;
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
-  case BuiltinType::Id: \
-    type_name = "ocl_" #ImgType "_" #Suffix; \
-    Out << type_name.size() << type_name; \
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix)                   
\
+  case BuiltinType::Id:                                                        
\
+    type_name = "ocl_" #ImgType "_" #Suffix;                                   
\
+    Out << type_name.size() << type_name;                                      
\
     break;
 #include "clang/Basic/OpenCLImageTypes.def"
   case BuiltinType::OCLSampler:
@@ -3407,15 +3480,15 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
   case BuiltinType::OCLReserveID:
     Out << "13ocl_reserveid";
     break;
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
-  case BuiltinType::Id: \
-    type_name = "ocl_" #ExtType; \
-    Out << type_name.size() << type_name; \
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext)                                      
\
+  case BuiltinType::Id:                                                        
\
+    type_name = "ocl_" #ExtType;                                               
\
+    Out << type_name.size() << type_name;                                      
\
     break;
 #include "clang/Basic/OpenCLExtensionTypes.def"
-  // The SVE types are effectively target-specific.  The mangling scheme
-  // is defined in the appendices to the Procedure Call Standard for the
-  // Arm Architecture.
+    // The SVE types are effectively target-specific.  The mangling scheme
+    // is defined in the appendices to the Procedure Call Standard for the
+    // Arm Architecture.
 #define SVE_VECTOR_TYPE(Name, MangledName, Id, SingletonId)                    
\
   case BuiltinType::Id:                                                        
\
     if (T->getKind() == BuiltinType::SveBFloat16 &&                            
\
@@ -3615,8 +3688,8 @@ void CXXNameMangler::mangleSMEAttrs(unsigned SMEAttrs) {
   Out << "Lj" << static_cast<unsigned>(Bitmask) << "EE";
 }
 
-void
-CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) 
{
+void CXXNameMangler::mangleExtParameterInfo(
+    FunctionProtoType::ExtParameterInfo PI) {
   // Vendor-specific qualifiers are emitted in reverse alphabetical order.
 
   // Note that these are *not* substitution candidates.  Demanglers might
@@ -3788,10 +3861,10 @@ void CXXNameMangler::mangleType(const 
UnresolvedUsingType *T) {
 // <type>            ::= <class-enum-type>
 // <class-enum-type> ::= <name>
 void CXXNameMangler::mangleType(const EnumType *T) {
-  mangleType(static_cast<const TagType*>(T));
+  mangleType(static_cast<const TagType *>(T));
 }
 void CXXNameMangler::mangleType(const RecordType *T) {
-  mangleType(static_cast<const TagType*>(T));
+  mangleType(static_cast<const TagType *>(T));
 }
 void CXXNameMangler::mangleType(const TagType *T) {
   mangleName(T->getDecl()->getDefinitionOrSelf());
@@ -3931,22 +4004,47 @@ void CXXNameMangler::mangleNeonVectorType(const 
VectorType *T) {
     case BuiltinType::ULongLong:
       EltName = "poly64_t";
       break;
-    default: llvm_unreachable("unexpected Neon polynomial vector element 
type");
+    default:
+      llvm_unreachable("unexpected Neon polynomial vector element type");
     }
   } else {
     switch (cast<BuiltinType>(EltType)->getKind()) {
-    case BuiltinType::SChar:     EltName = "int8_t"; break;
-    case BuiltinType::UChar:     EltName = "uint8_t"; break;
-    case BuiltinType::Short:     EltName = "int16_t"; break;
-    case BuiltinType::UShort:    EltName = "uint16_t"; break;
-    case BuiltinType::Int:       EltName = "int32_t"; break;
-    case BuiltinType::UInt:      EltName = "uint32_t"; break;
-    case BuiltinType::LongLong:  EltName = "int64_t"; break;
-    case BuiltinType::ULongLong: EltName = "uint64_t"; break;
-    case BuiltinType::Double:    EltName = "float64_t"; break;
-    case BuiltinType::Float:     EltName = "float32_t"; break;
-    case BuiltinType::Half:      EltName = "float16_t"; break;
-    case BuiltinType::BFloat16:  EltName = "bfloat16_t"; break;
+    case BuiltinType::SChar:
+      EltName = "int8_t";
+      break;
+    case BuiltinType::UChar:
+      EltName = "uint8_t";
+      break;
+    case BuiltinType::Short:
+      EltName = "int16_t";
+      break;
+    case BuiltinType::UShort:
+      EltName = "uint16_t";
+      break;
+    case BuiltinType::Int:
+      EltName = "int32_t";
+      break;
+    case BuiltinType::UInt:
+      EltName = "uint32_t";
+      break;
+    case BuiltinType::LongLong:
+      EltName = "int64_t";
+      break;
+    case BuiltinType::ULongLong:
+      EltName = "uint64_t";
+      break;
+    case BuiltinType::Double:
+      EltName = "float64_t";
+      break;
+    case BuiltinType::Float:
+      EltName = "float32_t";
+      break;
+    case BuiltinType::Half:
+      EltName = "float16_t";
+      break;
+    case BuiltinType::BFloat16:
+      EltName = "bfloat16_t";
+      break;
     case BuiltinType::MFloat8:
       EltName = "mfloat8_t";
       break;
@@ -3955,8 +4053,8 @@ void CXXNameMangler::mangleNeonVectorType(const 
VectorType *T) {
     }
   }
   const char *BaseName = nullptr;
-  unsigned BitSize = (T->getNumElements() *
-                      getASTContext().getTypeSize(EltType));
+  unsigned BitSize =
+      (T->getNumElements() * getASTContext().getTypeSize(EltType));
   if (BitSize == 64)
     BaseName = "__simd64_";
   else {
@@ -4274,21 +4372,23 @@ void CXXNameMangler::mangleType(const VectorType *T) {
     llvm::Triple Target = getASTContext().getTargetInfo().getTriple();
     llvm::Triple::ArchType Arch =
         getASTContext().getTargetInfo().getTriple().getArch();
-    if ((Arch == llvm::Triple::aarch64 ||
-         Arch == llvm::Triple::aarch64_be) && !Target.isOSDarwin())
+    if ((Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be) &&
+        !Target.isOSDarwin())
       mangleAArch64NeonVectorType(T);
     else
       mangleNeonVectorType(T);
     return;
-  } else if (T->getVectorKind() == VectorKind::SveFixedLengthData ||
-             T->getVectorKind() == VectorKind::SveFixedLengthPredicate) {
+  }
+  if (T->getVectorKind() == VectorKind::SveFixedLengthData ||
+      T->getVectorKind() == VectorKind::SveFixedLengthPredicate) {
     mangleAArch64FixedSveVectorType(T);
     return;
-  } else if (T->getVectorKind() == VectorKind::RVVFixedLengthData ||
-             T->getVectorKind() == VectorKind::RVVFixedLengthMask ||
-             T->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
-             T->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
-             T->getVectorKind() == VectorKind::RVVFixedLengthMask_4) {
+  }
+  if (T->getVectorKind() == VectorKind::RVVFixedLengthData ||
+      T->getVectorKind() == VectorKind::RVVFixedLengthMask ||
+      T->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
+      T->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
+      T->getVectorKind() == VectorKind::RVVFixedLengthMask_4) {
     mangleRISCVFixedRVVVectorType(T);
     return;
   }
@@ -4313,11 +4413,13 @@ void CXXNameMangler::mangleType(const 
DependentVectorType *T) {
     else
       mangleNeonVectorType(T);
     return;
-  } else if (T->getVectorKind() == VectorKind::SveFixedLengthData ||
-             T->getVectorKind() == VectorKind::SveFixedLengthPredicate) {
+  }
+  if (T->getVectorKind() == VectorKind::SveFixedLengthData ||
+      T->getVectorKind() == VectorKind::SveFixedLengthPredicate) {
     mangleAArch64FixedSveVectorType(T);
     return;
-  } else if (T->getVectorKind() == VectorKind::RVVFixedLengthData) {
+  }
+  if (T->getVectorKind() == VectorKind::RVVFixedLengthData) {
     mangleRISCVFixedRVVVectorType(T);
     return;
   }
@@ -4334,7 +4436,7 @@ void CXXNameMangler::mangleType(const DependentVectorType 
*T) {
 }
 
 void CXXNameMangler::mangleType(const ExtVectorType *T) {
-  mangleType(static_cast<const VectorType*>(T));
+  mangleType(static_cast<const VectorType *>(T));
 }
 void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
   Out << "Dv";
@@ -4510,12 +4612,9 @@ void CXXNameMangler::mangleType(const DecltypeType *T) {
   // class member accesses.  Note that we do not ignore parentheses;
   // parentheses change the semantics of decltype for these
   // expressions (and cause the mangler to use the other form).
-  if (isa<DeclRefExpr>(E) ||
-      isa<MemberExpr>(E) ||
-      isa<UnresolvedLookupExpr>(E) ||
-      isa<DependentScopeDeclRefExpr>(E) ||
-      isa<CXXDependentScopeMemberExpr>(E) ||
-      isa<UnresolvedMemberExpr>(E))
+  if (isa<DeclRefExpr>(E) || isa<MemberExpr>(E) ||
+      isa<UnresolvedLookupExpr>(E) || isa<DependentScopeDeclRefExpr>(E) ||
+      isa<CXXDependentScopeMemberExpr>(E) || isa<UnresolvedMemberExpr>(E))
     Out << "Dt";
   else
     Out << "DT";
@@ -4741,28 +4840,31 @@ static bool isParenthesizedADLCallee(const CallExpr 
*call) {
   // Must be parenthesized.  IgnoreParens() skips __extension__ nodes,
   // too, but for those to appear in the callee, it would have to be
   // parenthesized.
-  if (callee == fn) return false;
+  if (callee == fn)
+    return false;
 
   // Must be an unresolved lookup.
   const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn);
-  if (!lookup) return false;
+  if (!lookup)
+    return false;
 
   assert(!lookup->requiresADL());
 
   // Must be an unqualified lookup.
-  if (lookup->getQualifier()) return false;
+  if (lookup->getQualifier())
+    return false;
 
   // Must not have found a class member.  Note that if one is a class
   // member, they're all class members.
-  if (lookup->getNumDecls() > 0 &&
-      (*lookup->decls_begin())->isCXXClassMember())
+  if (lookup->getNumDecls() > 0 && 
(*lookup->decls_begin())->isCXXClassMember())
     return false;
 
   // Otherwise, ADL would have been triggered.
   return true;
 }
 
-void CXXNameMangler::mangleCastExpression(const Expr *E, StringRef 
CastEncoding) {
+void CXXNameMangler::mangleCastExpression(const Expr *E,
+                                          StringRef CastEncoding) {
   const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E);
   Out << CastEncoding;
   mangleType(ECE->getType());
@@ -4783,15 +4885,14 @@ void CXXNameMangler::mangleRequirement(SourceLocation 
RequiresExprLoc,
   // TODO: We can't mangle the result of a failed substitution. It's not clear
   // whether we should be mangling the original form prior to any substitution
   // instead. See https://lists.isocpp.org/core/2023/04/14118.php
-  auto HandleSubstitutionFailure =
-      [&](SourceLocation Loc) {
-        DiagnosticsEngine &Diags = Context.getDiags();
-        unsigned DiagID = Diags.getCustomDiagID(
-            DiagnosticsEngine::Error, "cannot mangle this requires-expression "
-                                      "containing a substitution failure");
-        Diags.Report(Loc, DiagID);
-        Out << 'F';
-      };
+  auto HandleSubstitutionFailure = [&](SourceLocation Loc) {
+    DiagnosticsEngine &Diags = Context.getDiags();
+    unsigned DiagID = Diags.getCustomDiagID(
+        DiagnosticsEngine::Error, "cannot mangle this requires-expression "
+                                  "containing a substitution failure");
+    Diags.Report(Loc, DiagID);
+    Out << 'F';
+  };
 
   switch (Req->getKind()) {
   case Requirement::RK_Type: {
@@ -4848,31 +4949,46 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
                                       bool AsTemplateArg) {
   // <expression> ::= <unary operator-name> <expression>
   //              ::= <binary operator-name> <expression> <expression>
-  //              ::= <trinary operator-name> <expression> <expression> 
<expression>
-  //              ::= cv <type> expression           # conversion with one 
argument
-  //              ::= cv <type> _ <expression>* E # conversion with a 
different number of arguments
-  //              ::= dc <type> <expression>         # dynamic_cast<type> 
(expression)
-  //              ::= sc <type> <expression>         # static_cast<type> 
(expression)
-  //              ::= cc <type> <expression>         # const_cast<type> 
(expression)
-  //              ::= rc <type> <expression>         # reinterpret_cast<type> 
(expression)
+  //              ::= <trinary operator-name> <expression> <expression>
+  //              <expression>
+  //              ::= cv <type> expression           # conversion with one
+  //              argument
+  //              ::= cv <type> _ <expression>* E # conversion with a different
+  //              number of arguments
+  //              ::= dc <type> <expression>         # dynamic_cast<type>
+  //              (expression)
+  //              ::= sc <type> <expression>         # static_cast<type>
+  //              (expression)
+  //              ::= cc <type> <expression>         # const_cast<type>
+  //              (expression)
+  //              ::= rc <type> <expression>         # reinterpret_cast<type>
+  //              (expression)
   //              ::= st <type>                      # sizeof (a type)
   //              ::= at <type>                      # alignof (a type)
   //              ::= <template-param>
   //              ::= <function-param>
-  //              ::= fpT                            # 'this' expression (part 
of <function-param>)
-  //              ::= sr <type> <unqualified-name>                   # 
dependent name
-  //              ::= sr <type> <unqualified-name> <template-args>   # 
dependent template-id
-  //              ::= ds <expression> <expression>                   # 
expr.*expr
-  //              ::= sZ <template-param>                            # size of 
a parameter pack
+  //              ::= fpT                            # 'this' expression (part
+  //              of <function-param>)
+  //              ::= sr <type> <unqualified-name>                   # 
dependent
+  //              name
+  //              ::= sr <type> <unqualified-name> <template-args>   # 
dependent
+  //              template-id
+  //              ::= ds <expression> <expression>                   #
+  //              expr.*expr
+  //              ::= sZ <template-param>                            # size of 
a
+  //              parameter pack
   //              ::= sZ <function-param>    # size of a function parameter 
pack
-  //              ::= u <source-name> <template-arg>* E # vendor extended 
expression
+  //              ::= u <source-name> <template-arg>* E # vendor extended
+  //              expression
   //              ::= <expr-primary>
   // <expr-primary> ::= L <type> <value number> E    # integer literal
   //                ::= L <type> <value float> E     # floating literal
   //                ::= L <type> <string type> E     # string literal
   //                ::= L <nullptr type> E           # nullptr literal "LDnE"
-  //                ::= L <pointer type> 0 E         # null pointer template 
argument
-  //                ::= L <type> <real-part float> _ <imag-part float> E    # 
complex floating point literal (C99); not used by clang
+  //                ::= L <pointer type> 0 E         # null pointer template
+  //                argument
+  //                ::= L <type> <real-part float> _ <imag-part float> E    #
+  //                complex floating point literal (C99); not used by clang
   //                ::= L <mangled-name> E           # external name
   QualType ImplicitlyConvertedToType;
 
@@ -4922,8 +5038,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
   case Expr::NoStmtClass:
 #define ABSTRACT_STMT(Type)
 #define EXPR(Type, Base)
-#define STMT(Type, Base) \
-  case Expr::Type##Class:
+#define STMT(Type, Base) case Expr::Type##Class:
 #include "clang/AST/StmtNodes.inc"
     // fallthrough
 
@@ -4997,10 +5112,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
     if (!NullOut) {
       // As bad as this diagnostic is, it's better than crashing.
       DiagnosticsEngine &Diags = Context.getDiags();
-      unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
-                                       "cannot yet mangle expression type %0");
+      unsigned DiagID = Diags.getCustomDiagID(
+          DiagnosticsEngine::Error, "cannot yet mangle expression type %0");
       Diags.Report(E->getExprLoc(), DiagID)
-        << E->getStmtClassName() << E->getSourceRange();
+          << E->getStmtClassName() << E->getSourceRange();
       return;
     }
     break;
@@ -5036,11 +5151,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
   case Expr::BinaryConditionalOperatorClass: {
     NotPrimaryExpr();
     DiagnosticsEngine &Diags = Context.getDiags();
-    unsigned DiagID =
-      Diags.getCustomDiagID(DiagnosticsEngine::Error,
-                "?: operator with omitted middle operand cannot be mangled");
+    unsigned DiagID = Diags.getCustomDiagID(
+        DiagnosticsEngine::Error,
+        "?: operator with omitted middle operand cannot be mangled");
     Diags.Report(E->getExprLoc(), DiagID)
-      << E->getStmtClassName() << E->getSourceRange();
+        << E->getStmtClassName() << E->getSourceRange();
     return;
   }
 
@@ -5126,7 +5241,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
       // no qualifier and should always get mangled as a <simple-id>
       // anyway.
 
-    // <expression> ::= cl <expression>* E
+      // <expression> ::= cl <expression>* E
     } else {
       Out << "cl";
     }
@@ -5146,10 +5261,12 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
   case Expr::CXXNewExprClass: {
     NotPrimaryExpr();
     const CXXNewExpr *New = cast<CXXNewExpr>(E);
-    if (New->isGlobalNew()) Out << "gs";
+    if (New->isGlobalNew())
+      Out << "gs";
     Out << (New->isArray() ? "na" : "nw");
     for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(),
-           E = New->placement_arg_end(); I != E; ++I)
+                                        E = New->placement_arg_end();
+         I != E; ++I)
       mangleExpression(*I);
     Out << '_';
     mangleType(New->getAllocatedType());
@@ -5210,11 +5327,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
   case Expr::MemberExprClass: {
     NotPrimaryExpr();
     const MemberExpr *ME = cast<MemberExpr>(E);
-    mangleMemberExpr(ME->getBase(), ME->isArrow(),
-                     ME->getQualifier(), nullptr,
-                     ME->getMemberDecl()->getDeclName(),
-                     ME->getTemplateArgs(), ME->getNumTemplateArgs(),
-                     Arity);
+    mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(), nullptr,
+                     ME->getMemberDecl()->getDeclName(), ME->getTemplateArgs(),
+                     ME->getNumTemplateArgs(), Arity);
     break;
   }
 
@@ -5223,22 +5338,19 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
     const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
     mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
                      ME->isArrow(), ME->getQualifier(), nullptr,
-                     ME->getMemberName(),
-                     ME->getTemplateArgs(), ME->getNumTemplateArgs(),
-                     Arity);
+                     ME->getMemberName(), ME->getTemplateArgs(),
+                     ME->getNumTemplateArgs(), Arity);
     break;
   }
 
   case Expr::CXXDependentScopeMemberExprClass: {
     NotPrimaryExpr();
-    const CXXDependentScopeMemberExpr *ME
-      = cast<CXXDependentScopeMemberExpr>(E);
+    const CXXDependentScopeMemberExpr *ME =
+        cast<CXXDependentScopeMemberExpr>(E);
     mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
                      ME->isArrow(), ME->getQualifier(),
-                     ME->getFirstQualifierFoundInScope(),
-                     ME->getMember(),
-                     ME->getTemplateArgs(), ME->getNumTemplateArgs(),
-                     Arity);
+                     ME->getFirstQualifierFoundInScope(), ME->getMember(),
+                     ME->getTemplateArgs(), ME->getNumTemplateArgs(), Arity);
     break;
   }
 
@@ -5268,9 +5380,12 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
 
     Out << "cv";
     mangleType(CE->getType());
-    if (N != 1) Out << '_';
-    for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
-    if (N != 1) Out << 'E';
+    if (N != 1)
+      Out << '_';
+    for (unsigned I = 0; I != N; ++I)
+      mangleExpression(CE->getArg(I));
+    if (N != 1)
+      Out << 'E';
     break;
   }
 
@@ -5278,10 +5393,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
     // An implicit cast is silent, thus may contain <expr-primary>.
     const auto *CE = cast<CXXConstructExpr>(E);
     if (!CE->isListInitialization() || CE->isStdInitListInitialization()) {
-      assert(
-          CE->getNumArgs() >= 1 &&
-          (CE->getNumArgs() == 1 || isa<CXXDefaultArgExpr>(CE->getArg(1))) &&
-          "implicit CXXConstructExpr must have one argument");
+      assert(CE->getNumArgs() >= 1 &&
+             (CE->getNumArgs() == 1 || isa<CXXDefaultArgExpr>(CE->getArg(1))) 
&&
+             "implicit CXXConstructExpr must have one argument");
       E = cast<CXXConstructExpr>(E)->getArg(0);
       goto recurse;
     }
@@ -5354,8 +5468,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
       // can lead to mangling collisions between function templates that we
       // consider to be different.
       QualType T = (ImplicitlyConvertedToType.isNull() ||
-                    !ImplicitlyConvertedToType->isIntegerType())? 
SAE->getType()
-                                                    : 
ImplicitlyConvertedToType;
+                    !ImplicitlyConvertedToType->isIntegerType())
+                       ? SAE->getType()
+                       : ImplicitlyConvertedToType;
       llvm::APSInt V = SAE->EvaluateKnownConstInt(Context.getASTContext());
       mangleIntegerLiteral(T, V);
       break;
@@ -5467,7 +5582,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
     const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E);
     //  <expression> ::= [gs] dl <expression>  # [::] delete expr
     //               ::= [gs] da <expression>  # [::] delete [] expr
-    if (DE->isGlobalDelete()) Out << "gs";
+    if (DE->isGlobalDelete())
+      Out << "gs";
     Out << (DE->isArrayForm() ? "da" : "dl");
     mangleExpression(DE->getArgument());
     break;
@@ -5776,7 +5892,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
     Out << 'L';
     mangleType(E->getType());
     if (const FloatingLiteral *Imag =
-          dyn_cast<FloatingLiteral>(IE->getSubExpr())) {
+            dyn_cast<FloatingLiteral>(IE->getSubExpr())) {
       // Mangle a floating-point zero of the appropriate type.
       mangleFloat(llvm::APFloat(Imag->getValue().getSemantics()));
       Out << '_';
@@ -5846,11 +5962,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
     const NamedDecl *Pack = SPE->getPack();
     if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
       mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
-    else if (const NonTypeTemplateParmDecl *NTTP
-                = dyn_cast<NonTypeTemplateParmDecl>(Pack))
+    else if (const NonTypeTemplateParmDecl *NTTP =
+                 dyn_cast<NonTypeTemplateParmDecl>(Pack))
       mangleTemplateParameter(NTTP->getDepth(), NTTP->getIndex());
-    else if (const TemplateTemplateParmDecl *TempTP
-                                    = dyn_cast<TemplateTemplateParmDecl>(Pack))
+    else if (const TemplateTemplateParmDecl *TempTP =
+                 dyn_cast<TemplateTemplateParmDecl>(Pack))
       mangleTemplateParameter(TempTP->getDepth(), TempTP->getIndex());
     else
       mangleFunctionParam(cast<ParmVarDecl>(Pack));
@@ -5986,11 +6102,11 @@ void CXXNameMangler::mangleFunctionParam(const 
ParmVarDecl *parm) {
   // because parameters declared as arrays should already have been
   // transformed to have pointer type. FIXME: apparently these don't
   // get mangled if used as an rvalue of a known non-class type?
-  assert(!parm->getType()->isArrayType()
-         && "parameter's type is still an array type?");
+  assert(!parm->getType()->isArrayType() &&
+         "parameter's type is still an array type?");
 
   if (const DependentAddressSpaceType *DAST =
-      dyn_cast<DependentAddressSpaceType>(parm->getType())) {
+          dyn_cast<DependentAddressSpaceType>(parm->getType())) {
     mangleQualifiers(DAST->getPointeeType().getQualifiers(), DAST);
   } else {
     mangleQualifiers(parm->getType().getQualifiers());
@@ -6819,11 +6935,11 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType 
T, const APValue &V,
     }
 
     QualType TypeSoFar = B.getType();
-    if (auto *VD = B.dyn_cast<const ValueDecl*>()) {
+    if (auto *VD = B.dyn_cast<const ValueDecl *>()) {
       Out << 'L';
       mangle(VD);
       Out << 'E';
-    } else if (auto *E = B.dyn_cast<const Expr*>()) {
+    } else if (auto *E = B.dyn_cast<const Expr *>()) {
       NotPrimaryExpr();
       mangleExpression(E);
     } else if (auto TI = B.dyn_cast<TypeInfoLValue>()) {
@@ -6968,7 +7084,7 @@ void CXXNameMangler::mangleSeqID(unsigned SeqID) {
 void CXXNameMangler::mangleExistingSubstitution(TemplateName tname) {
   bool result = mangleSubstitution(tname);
   assert(result && "no existing substitution for template name");
-  (void) result;
+  (void)result;
 }
 
 // <substitution> ::= S <seq-id> _
@@ -7006,7 +7122,7 @@ bool CXXNameMangler::mangleSubstitution(TemplateName 
Template) {
 
   Template = Context.getASTContext().getCanonicalTemplateName(Template);
   return mangleSubstitution(
-                      
reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
+      reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
 }
 
 bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
@@ -7118,7 +7234,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const 
NamedDecl *ND) {
   }
 
   if (const ClassTemplateSpecializationDecl *SD =
-        dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+          dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
     if (!isStdNamespace(Context.getEffectiveDeclContext(SD)))
       return false;
 
@@ -7184,7 +7300,7 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
   Substitutions[Ptr] = SeqID++;
 }
 
-void CXXNameMangler::extendSubstitutions(CXXNameMangler* Other) {
+void CXXNameMangler::extendSubstitutions(CXXNameMangler *Other) {
   assert(Other->SeqID >= SeqID && "Must be superset of substitutions!");
   if (Other->SeqID > SeqID) {
     Substitutions.swap(Other->Substitutions);
@@ -7246,8 +7362,7 @@ bool 
CXXNameMangler::shouldHaveAbiTags(ItaniumMangleContextImpl &C,
 /// and this routine will return false. In this case, the caller should just
 /// emit the identifier of the declaration (\c D->getIdentifier()) as its
 /// name.
-void ItaniumMangleContextImpl::mangleCXXName(GlobalDecl GD,
-                                             raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXName(GlobalDecl GD, raw_ostream &Out) {
   const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
   assert((isa<FunctionDecl, VarDecl, TemplateParamObjectDecl>(D)) &&
          "Invalid mangleName() call, argument is not a variable or function!");
@@ -7459,8 +7574,8 @@ void ItaniumMangleContextImpl::mangleSEHFilterExpression(
     Mangler.getStream() << EnclosingFD->getName();
 }
 
-void ItaniumMangleContextImpl::mangleSEHFinallyBlock(
-    GlobalDecl EnclosingDecl, raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleSEHFinallyBlock(GlobalDecl EnclosingDecl,
+                                                     raw_ostream &Out) {
   CXXNameMangler Mangler(*this, Out);
   Mangler.getStream() << "__fin_";
   auto *EnclosingFD = cast<FunctionDecl>(EnclosingDecl.getDecl());
@@ -7478,9 +7593,8 @@ void 
ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
   Mangler.mangleName(D);
 }
 
-void
-ItaniumMangleContextImpl::mangleItaniumThreadLocalWrapper(const VarDecl *D,
-                                                          raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleItaniumThreadLocalWrapper(
+    const VarDecl *D, raw_ostream &Out) {
   //  <special-name> ::= TW <object name>
   CXXNameMangler Mangler(*this, Out);
   Mangler.getStream() << "_ZTW";
@@ -7554,7 +7668,8 @@ void ItaniumMangleContextImpl::mangleCanonicalTypeName(
   mangleCXXRTTIName(Ty, Out, NormalizeIntegers);
 }
 
-void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, 
raw_ostream &) {
+void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *,
+                                                   raw_ostream &) {
   llvm_unreachable("Can't mangle string literals");
 }
 

>From 7baf23020bde8f227ffa5c2d23c054151700b03b Mon Sep 17 00:00:00 2001
From: Tommy Chiang <[email protected]>
Date: Fri, 20 Feb 2026 02:40:57 +0800
Subject: [PATCH 2/2] [Clang][ItaniumMangle] Fix recursive mangling for lambda
 init-captures
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

During lambda numbering, ItaniumNumberingContext::getManglingNumber() computes
the lambda’s <lambda-sig> by mangling the call operator type. If that type
contains decltype(init-capture), mangling re-enters the init-capture VarDecl.
For problematic cases, this recurses back into operator() mangling.

Make init-capture handling in mangleLocalName() explicit:
* If the init-capture belongs to a lambda that has a closure-prefix context,
  mangle it directly with mangleNestedNameWithClosurePrefix().
* Otherwise keep local-name mangling, but for local lambdas use the parent
  local container as the function-encoding base to avoid self-recursion.

Also publish lambda ContextDecl early in Sema::handleLambdaNumbering() before
calling getManglingNumber(Method), via a dedicated
CXXRecordDecl::setLambdaContextDecl() helper. This provides the needed context
for context-sensitive mangling without publishing provisional numbering state.

Add non-local regression tests in mangle-lambdas.cpp for:
* variable-template lambda init-capture used in decltype(x)
* static inline member lambda init-capture used in decltype(x)

* Fixes https://github.com/llvm/llvm-project/issues/63271
* Fixes https://github.com/llvm/llvm-project/issues/86240
* Fixes https://github.com/llvm/llvm-project/issues/139089
---
 clang/include/clang/AST/DeclCXX.h        |  3 ++
 clang/lib/AST/DeclCXX.cpp                |  5 ++
 clang/lib/AST/ItaniumMangle.cpp          | 31 +++++++++--
 clang/lib/Sema/SemaLambda.cpp            |  7 +++
 clang/test/CodeGenCXX/mangle-lambdas.cpp | 66 ++++++++++++++++++++++++
 5 files changed, 108 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/AST/DeclCXX.h 
b/clang/include/clang/AST/DeclCXX.h
index 5c4ad3c45da19..0c9bba17d09ef 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1785,6 +1785,9 @@ class CXXRecordDecl : public RecordDecl {
   /// the declaration context suffices.
   Decl *getLambdaContextDecl() const;
 
+  /// Set the context declaration for a lambda class.
+  void setLambdaContextDecl(Decl *ContextDecl);
+
   /// Retrieve the index of this lambda within the context declaration returned
   /// by getLambdaContextDecl().
   unsigned getLambdaIndexInContext() const {
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index c16b1bb7a3453..55c34605f7513 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1831,6 +1831,11 @@ Decl *CXXRecordDecl::getLambdaContextDecl() const {
   return getLambdaData().ContextDecl.get(Source);
 }
 
+void CXXRecordDecl::setLambdaContextDecl(Decl *ContextDecl) {
+  assert(isLambda() && "Not a lambda closure type!");
+  getLambdaData().ContextDecl = ContextDecl;
+}
+
 void CXXRecordDecl::setLambdaNumbering(LambdaNumbering Numbering) {
   assert(isLambda() && "Not a lambda closure type!");
   getLambdaData().ManglingNumber = Numbering.ManglingNumber;
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 4618fc58c886a..6017f3bb3cd5f 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -1855,17 +1855,40 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
   const RecordDecl *RD = GetLocalClassDecl(D);
   const DeclContext *DC = Context.getEffectiveDeclContext(RD ? RD : D);
 
+  if (const auto *VD = dyn_cast<VarDecl>(D); VD && VD->isInitCapture()) {
+    if (const auto *MethodDC = dyn_cast<CXXMethodDecl>(DC)) {
+      // Init-captures in non-local lambdas should be mangled in the lambda's
+      // closure-prefix context, not as local entities of operator().
+      if (const NamedDecl *PrefixND = getClosurePrefix(MethodDC->getParent())) 
{
+        mangleNestedNameWithClosurePrefix(GD, PrefixND, AdditionalAbiTags);
+        return;
+      }
+    }
+  }
+
   Out << 'Z';
 
   {
     AbiTagState LocalAbiTags(AbiTags);
 
-    if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC))
+    if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
       mangleObjCMethodName(MD);
-    else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC))
+    } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
       mangleBlockForPrefix(BD);
-    else
-      mangleFunctionEncoding(getParentOfLocalEntity(DC));
+    } else {
+      const DeclContext *MangleDC = DC;
+      if (const auto *VD = dyn_cast<VarDecl>(D); VD && VD->isInitCapture()) {
+        if (const auto *MethodDC = dyn_cast<CXXMethodDecl>(DC)) {
+          const DeclContext *ParentDC =
+              Context.getEffectiveParentContext(MethodDC->getDeclContext());
+          // For local lambdas, use the parent context as the local-name base
+          // to avoid recursively mangling the lambda call operator.
+          if (isLocalContainerContext(ParentDC))
+            MangleDC = ParentDC;
+        }
+      }
+      mangleFunctionEncoding(getParentOfLocalEntity(MangleDC));
+    }
 
     // Implicit ABI tags (from namespace) are not available in the following
     // entity; reset to actually emitted tags, which are available.
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index e74fe02bd0cf5..f3f108873ef74 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -503,6 +503,13 @@ void Sema::handleLambdaNumbering(
   MangleNumberingContext *MCtx;
   std::tie(MCtx, Numbering.ContextDecl) =
       getCurrentMangleNumberContext(Class->getDeclContext());
+  // getManglingNumber(Method) below may trigger mangling of dependent types
+  // that reference init-captures. Publish the lambda context declaration early
+  // so such mangling can resolve the surrounding context without recursing
+  // through the lambda call operator. This avoids publishing provisional
+  // numbering state before final numbering is assigned below.
+  if (Numbering.ContextDecl)
+    Class->setLambdaContextDecl(Numbering.ContextDecl);
   if (!MCtx && (getLangOpts().CUDA || getLangOpts().SYCLIsDevice ||
                 getLangOpts().SYCLIsHost)) {
     // Force lambda numbering in CUDA/HIP as we need to name lambdas following
diff --git a/clang/test/CodeGenCXX/mangle-lambdas.cpp 
b/clang/test/CodeGenCXX/mangle-lambdas.cpp
index 5a7de97c91858..d9ac0d39956e9 100644
--- a/clang/test/CodeGenCXX/mangle-lambdas.cpp
+++ b/clang/test/CodeGenCXX/mangle-lambdas.cpp
@@ -301,6 +301,70 @@ void test_StaticInlineMember() {
   StaticInlineMember::x();
 }
 
+template <typename L>
+auto pr63271foo(L l_) {
+  return [l = l_](decltype(l)) -> void {};
+}
+
+// CHECK-LABEL: define{{.*}} @_Z10pr63271usev
+// CHECK: call void @_ZZ10pr63271fooIiEDaT_ENKUliE_clEi
+void pr63271use() {
+  pr63271foo(0)(0);
+}
+
+template <typename T>
+struct pr139089_vlambda {
+  pr139089_vlambda() {
+    [&m = m_args](decltype(m) args) { (void)args; }(m_args);
+  }
+  int m_args = 0;
+};
+
+// CHECK-LABEL: define{{.*}} @_Z11pr139089usev
+// CHECK: call void @_ZN16pr139089_vlambdaIiEC1Ev
+void pr139089use() {
+  (void)pr139089_vlambda<int>{};
+}
+
+
+template <class RET> struct pr86240_context {
+  using Ptr = pr86240_context<RET> *;
+};
+
+template <typename Callable>
+void pr86240_schedule_coro(Callable &&coro_function) {
+  [coro_function{coro_function}](
+      typename pr86240_context<decltype(coro_function())>::Ptr ctx) -> int {
+    return ctx != nullptr;
+  }(nullptr);
+}
+
+// CHECK-LABEL: define{{.*}} @_Z10pr86240usev
+// CHECK: call noundef i32 
@"_ZZ21pr86240_schedule_coroIZ10pr86240usevE3$_0EvOT_ENKUlP15pr86240_contextIiEE_clES5_"
+void pr86240use() {
+  pr86240_schedule_coro([] { return 0; });
+}
+
+template <typename T>
+auto nonLocalVarTemplate = [x = T{}](decltype(x) y) { return y; };
+
+// CHECK-LABEL: define{{.*}} @_Z22nonLocalVarTemplateUsev
+// CHECK: call noundef i32 @_ZNK19nonLocalVarTemplateIiEMUliE_clEi
+int nonLocalVarTemplateUse() {
+  return nonLocalVarTemplate<int>(2);
+}
+
+template <typename T>
+struct nonLocalStaticInlineMember {
+  static inline auto l = [x = T{}](decltype(x) y) { return y; };
+};
+
+// CHECK-LABEL: define{{.*}} @_Z29nonLocalStaticInlineMemberUsev
+// CHECK: call noundef i32 @_ZNK26nonLocalStaticInlineMemberIiE1lMUliE_clEi
+int nonLocalStaticInlineMemberUse() {
+  return nonLocalStaticInlineMember<int>::l(2);
+}
+
 // Check linkage of the various lambdas.
 // CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ11inline_funciENKUlvE_clEv
 // CHECK: ret i32 1
@@ -331,6 +395,8 @@ void test_StaticInlineMember() {
 
 // CHECK-LABEL: define linkonce_odr void 
@_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_
 
+// CHECK-LABEL: define linkonce_odr void 
@_ZZN16pr139089_vlambdaIiEC1EvENKUlRiE_clES1_
+
 
 namespace PR12808 {
   template <typename> struct B {

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

Reply via email to