Author: Corentin Jabot
Date: 2026-05-15T16:50:30+02:00
New Revision: 68e8dd698dc6ac96f26d9144bd3117f2bc6bca49

URL: 
https://github.com/llvm/llvm-project/commit/68e8dd698dc6ac96f26d9144bd3117f2bc6bca49
DIFF: 
https://github.com/llvm/llvm-project/commit/68e8dd698dc6ac96f26d9144bd3117f2bc6bca49.diff

LOG: [Clang] Mangling of pack indexing type and expression for itanium (#123513)

See  https://github.com/itanium-cxx-abi/cxx-abi/pull/198
and #112003

Added: 
    clang/test/CodeGenCXX/mangle-cxx2c.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/AST/ItaniumMangle.cpp
    libcxxabi/src/demangle/ItaniumDemangle.h
    libcxxabi/src/demangle/ItaniumNodes.def
    libcxxabi/test/DemangleTestCases.inc
    llvm/include/llvm/Demangle/ItaniumDemangle.h
    llvm/include/llvm/Demangle/ItaniumNodes.def
    llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c54b6e5a1757e..f5660f9670eae 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -155,6 +155,8 @@ C++2c Feature Support
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
+- Partially implement Itanium mangling for pack indexing. Partially 
substituted packs are not yet supported. (#GH112003)
+
 C++20 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 

diff  --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 7ff9513dbe6ef..4f9ba1ccd4f79 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -593,6 +593,7 @@ class CXXNameMangler {
   void mangleInitListElements(const InitListExpr *InitList);
   void mangleRequirement(SourceLocation RequiresExprLoc,
                          const concepts::Requirement *Req);
+  void mangleReferenceToPack(const NamedDecl *ND);
   void mangleExpression(const Expr *E, unsigned Arity = UnknownArity,
                         bool AsTemplateArg = false);
   void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom);
@@ -4430,10 +4431,10 @@ void CXXNameMangler::mangleType(const PackExpansionType 
*T) {
 }
 
 void CXXNameMangler::mangleType(const PackIndexingType *T) {
-  if (!T->hasSelectedType())
-    mangleType(T->getPattern());
-  else
-    mangleType(T->getSelectedType());
+  // <type>  ::= Dy <type> <expression>  # pack indexing type (C++23)
+  Out << "Dy";
+  mangleType(T->getPattern());
+  mangleExpression(T->getIndexExpr());
 }
 
 void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
@@ -4899,6 +4900,7 @@ void CXXNameMangler::mangleRequirement(SourceLocation 
RequiresExprLoc,
 
 void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
                                       bool AsTemplateArg) {
+  // clang-format off
   // <expression> ::= <unary operator-name> <expression>
   //              ::= <binary operator-name> <expression> <expression>
   //              ::= <trinary operator-name> <expression> <expression> 
<expression>
@@ -4918,6 +4920,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
   //              ::= ds <expression> <expression>                   # 
expr.*expr
   //              ::= sZ <template-param>                            # size of 
a parameter pack
   //              ::= sZ <function-param>    # size of a function parameter 
pack
+  //              ::= sy <template-param> <expression>               # pack 
indexing expression
+  //              ::= sy <function-param> <expression>               # pack 
indexing expression
   //              ::= u <source-name> <template-arg>* E # vendor extended 
expression
   //              ::= <expr-primary>
   // <expr-primary> ::= L <type> <value number> E    # integer literal
@@ -4927,6 +4931,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
   //                ::= 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
+  // clang-format on
   QualType ImplicitlyConvertedToType;
 
   // A top-level expression that's not <expr-primary> needs to be wrapped in
@@ -4997,7 +5002,6 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
   case Expr::OMPIteratorExprClass:
   case Expr::CXXInheritedCtorInitExprClass:
   case Expr::CXXParenListInitExprClass:
-  case Expr::PackIndexingExprClass:
     llvm_unreachable("unexpected statement kind");
 
   case Expr::ConstantExprClass:
@@ -5891,17 +5895,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
     }
 
     Out << "sZ";
-    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))
-      mangleTemplateParameter(NTTP->getDepth(), NTTP->getIndex());
-    else if (const TemplateTemplateParmDecl *TempTP
-                                    = dyn_cast<TemplateTemplateParmDecl>(Pack))
-      mangleTemplateParameter(TempTP->getDepth(), TempTP->getIndex());
-    else
-      mangleFunctionParam(cast<ParmVarDecl>(Pack));
+    mangleReferenceToPack(SPE->getPack());
     break;
   }
 
@@ -5931,6 +5925,15 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
     break;
   }
 
+  case Expr::PackIndexingExprClass: {
+    auto *PE = cast<PackIndexingExpr>(E);
+    NotPrimaryExpr();
+    Out << "sy";
+    mangleReferenceToPack(PE->getPackDecl());
+    mangleExpression(PE->getIndexExpr());
+    break;
+  }
+
   case Expr::CXXThisExprClass:
     NotPrimaryExpr();
     Out << "fpT";
@@ -6112,6 +6115,17 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
   }
 }
 
+void CXXNameMangler::mangleReferenceToPack(const NamedDecl *Pack) {
+  if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
+    mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
+  else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Pack))
+    mangleTemplateParameter(NTTP->getDepth(), NTTP->getIndex());
+  else if (const auto *TempTP = dyn_cast<TemplateTemplateParmDecl>(Pack))
+    mangleTemplateParameter(TempTP->getDepth(), TempTP->getIndex());
+  else
+    mangleFunctionParam(cast<ParmVarDecl>(Pack));
+}
+
 // Helper to provide ancillary information on a template used to mangle its
 // arguments.
 struct CXXNameMangler::TemplateArgManglingInfo {

diff  --git a/clang/test/CodeGenCXX/mangle-cxx2c.cpp 
b/clang/test/CodeGenCXX/mangle-cxx2c.cpp
new file mode 100644
index 0000000000000..1dd5c7e4af264
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-cxx2c.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=%itanium_abi_triple -std=c++2c | 
FileCheck %s
+
+namespace GH112003 {
+
+// CHECK-LABEL: define {{.*}} 
@_ZN8GH1120033fooILi0ETpTnDaJLi0ELi0EEEEDTsyT0_T_Ev
+// CHECK-LABEL: define {{.*}} 
@_ZN8GH1120033fooILi1ETpTnDaJLi0ELi0EEEEDTsyT0_T_Ev
+// CHECK-LABEL: define {{.*}} @_ZN8GH1120033fooILi0ETpTnDaJLl1EEEEDTsyT0_T_Ev
+template <int I, auto...V>
+decltype(V...[I]) foo() {return {};}
+
+// CHECK-LABEL: define {{.*}} @_ZN8GH1120033barILi0EJilEEEDyT0_T_v
+// CHECK-LABEL: define {{.*}} @_ZN8GH1120033barILi1EJilEEEDyT0_T_v
+template <int I, typename...V>
+V...[I] bar() {return {};}
+
+
+template <int I, typename... T>
+using First = T...[0];
+
+// CHECK-LABEL: define {{.*}} @_ZN8GH1120033bazILi0EJiEEEvDy_SUBSTPACK_Li0E
+// FIXME: handle indexing of partially substituted packs
+template <int I, typename...V>
+void baz(First<I, int, V...>){};
+
+
+void fn() {
+    foo<0, 0, 0>();
+    foo<1, 0, 0>();
+    foo<0, 1L>();
+    bar<0, int, long>();
+    bar<1, int, long>();
+    baz<0, int>(0);
+}
+}

diff  --git a/libcxxabi/src/demangle/ItaniumDemangle.h 
b/libcxxabi/src/demangle/ItaniumDemangle.h
index c001a8d33f227..94d780e229631 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -1537,6 +1537,27 @@ class ParameterPackExpansion final : public Node {
   }
 };
 
+class PackIndexing final : public Node {
+  const Node *Pattern;
+  const Node *Index;
+
+public:
+  PackIndexing(const Node *Pattern_, const Node *Index_)
+      : Node(KPackIndexing), Pattern(Pattern_), Index(Index_) {}
+
+  template <typename Fn> void match(Fn F) const { F(Pattern, Index); }
+
+  void printLeft(OutputBuffer &OB) const override {
+    OB.printOpen('(');
+    ParameterPackExpansion PPE(Pattern);
+    PPE.printLeft(OB);
+    OB.printClose(')');
+    OB.printOpen('[');
+    OB.printLeft(*Index);
+    OB.printClose(']');
+  }
+};
+
 class TemplateArgs final : public Node {
   NodeArray Params;
   Node *Requires;
@@ -4531,6 +4552,18 @@ Node *AbstractManglingParser<Derived, 
Alloc>::parseType() {
       Result = make<ParameterPackExpansion>(Child);
       break;
     }
+    //           ::= Dy <type> <expression> # pack indexing (C++26)
+    case 'y': {
+      First += 2;
+      Node *Pattern = getDerived().parseType();
+      if (!Pattern)
+        return nullptr;
+      Node *Index = getDerived().parseExpr();
+      if (!Index)
+        return nullptr;
+      Result = make<PackIndexing>(Pattern, Index);
+      break;
+    }
     // Exception specifier on a function type.
     case 'o':
     case 'O':
@@ -5375,6 +5408,16 @@ Node *AbstractManglingParser<Derived, 
Alloc>::parseExpr() {
       return nullptr;
     return make<ParameterPackExpansion>(Child);
   }
+  if (consumeIf("sy")) {
+    Node *Pattern = look() == 'T' ? getDerived().parseTemplateParam()
+                                  : getDerived().parseFunctionParam();
+    if (Pattern == nullptr)
+      return nullptr;
+    Node *Index = getDerived().parseExpr();
+    if (Index == nullptr)
+      return nullptr;
+    return make<PackIndexing>(Pattern, Index);
+  }
   if (consumeIf("sZ")) {
     if (look() == 'T') {
       Node *R = getDerived().parseTemplateParam();

diff  --git a/libcxxabi/src/demangle/ItaniumNodes.def 
b/libcxxabi/src/demangle/ItaniumNodes.def
index 18f5d52b47e91..2c183ec5d23f8 100644
--- a/libcxxabi/src/demangle/ItaniumNodes.def
+++ b/libcxxabi/src/demangle/ItaniumNodes.def
@@ -100,5 +100,5 @@ NODE(ExprRequirement)
 NODE(TypeRequirement)
 NODE(NestedRequirement)
 NODE(ExplicitObjectParameter)
-
+NODE(PackIndexing)
 #undef NODE

diff  --git a/libcxxabi/test/DemangleTestCases.inc 
b/libcxxabi/test/DemangleTestCases.inc
index 307d0a8c02a41..6b7a99d849a94 100644
--- a/libcxxabi/test/DemangleTestCases.inc
+++ b/libcxxabi/test/DemangleTestCases.inc
@@ -30187,6 +30187,10 @@
 {"_ZZNH3Foo3fooES_iENK4Foo24foo2Ev", "Foo::foo(this Foo, int)::Foo2::foo2() 
const" },
 {"_ZNH3FooclERKS_", "Foo::operator()(this Foo const&)"},
 
+// C++26 pack indexing
+{"_Z3fooILi0ETpTnDaJLi1ELi2EEEDTsyT0_T_Ev", "decltype((1, 2...)[0]) foo<0, 1, 
2>()"},
+{"_Z1gILi0EJciEEDyT0_T_v", "(char, int)[0] g<0, char, int>()"},
+
 // fixed-point types as defined in the N1169 draft of ISO/IEC DTR 18037
 {"_Z1fDAs", "f(short _Accum)"},
 {"_Z1fDAt", "f(unsigned short _Accum)"},

diff  --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h 
b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 6d7f189a6e44c..04338e1d7cb51 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -1537,6 +1537,27 @@ class ParameterPackExpansion final : public Node {
   }
 };
 
+class PackIndexing final : public Node {
+  const Node *Pattern;
+  const Node *Index;
+
+public:
+  PackIndexing(const Node *Pattern_, const Node *Index_)
+      : Node(KPackIndexing), Pattern(Pattern_), Index(Index_) {}
+
+  template <typename Fn> void match(Fn F) const { F(Pattern, Index); }
+
+  void printLeft(OutputBuffer &OB) const override {
+    OB.printOpen('(');
+    ParameterPackExpansion PPE(Pattern);
+    PPE.printLeft(OB);
+    OB.printClose(')');
+    OB.printOpen('[');
+    OB.printLeft(*Index);
+    OB.printClose(']');
+  }
+};
+
 class TemplateArgs final : public Node {
   NodeArray Params;
   Node *Requires;
@@ -4531,6 +4552,18 @@ Node *AbstractManglingParser<Derived, 
Alloc>::parseType() {
       Result = make<ParameterPackExpansion>(Child);
       break;
     }
+    //           ::= Dy <type> <expression> # pack indexing (C++26)
+    case 'y': {
+      First += 2;
+      Node *Pattern = getDerived().parseType();
+      if (!Pattern)
+        return nullptr;
+      Node *Index = getDerived().parseExpr();
+      if (!Index)
+        return nullptr;
+      Result = make<PackIndexing>(Pattern, Index);
+      break;
+    }
     // Exception specifier on a function type.
     case 'o':
     case 'O':
@@ -5375,6 +5408,16 @@ Node *AbstractManglingParser<Derived, 
Alloc>::parseExpr() {
       return nullptr;
     return make<ParameterPackExpansion>(Child);
   }
+  if (consumeIf("sy")) {
+    Node *Pattern = look() == 'T' ? getDerived().parseTemplateParam()
+                                  : getDerived().parseFunctionParam();
+    if (Pattern == nullptr)
+      return nullptr;
+    Node *Index = getDerived().parseExpr();
+    if (Index == nullptr)
+      return nullptr;
+    return make<PackIndexing>(Pattern, Index);
+  }
   if (consumeIf("sZ")) {
     if (look() == 'T') {
       Node *R = getDerived().parseTemplateParam();

diff  --git a/llvm/include/llvm/Demangle/ItaniumNodes.def 
b/llvm/include/llvm/Demangle/ItaniumNodes.def
index 330552663ee65..3a28b1f175924 100644
--- a/llvm/include/llvm/Demangle/ItaniumNodes.def
+++ b/llvm/include/llvm/Demangle/ItaniumNodes.def
@@ -100,5 +100,5 @@ NODE(ExprRequirement)
 NODE(TypeRequirement)
 NODE(NestedRequirement)
 NODE(ExplicitObjectParameter)
-
+NODE(PackIndexing)
 #undef NODE

diff  --git a/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc 
b/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
index 307d0a8c02a41..6b7a99d849a94 100644
--- a/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
+++ b/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
@@ -30187,6 +30187,10 @@
 {"_ZZNH3Foo3fooES_iENK4Foo24foo2Ev", "Foo::foo(this Foo, int)::Foo2::foo2() 
const" },
 {"_ZNH3FooclERKS_", "Foo::operator()(this Foo const&)"},
 
+// C++26 pack indexing
+{"_Z3fooILi0ETpTnDaJLi1ELi2EEEDTsyT0_T_Ev", "decltype((1, 2...)[0]) foo<0, 1, 
2>()"},
+{"_Z1gILi0EJciEEDyT0_T_v", "(char, int)[0] g<0, char, int>()"},
+
 // fixed-point types as defined in the N1169 draft of ISO/IEC DTR 18037
 {"_Z1fDAs", "f(short _Accum)"},
 {"_Z1fDAt", "f(unsigned short _Accum)"},


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

Reply via email to