[libcxx-commits] [clang] [libcxxabi] [llvm] [Clang] Mangling of pack indexing type and expression for itanium (PR #123513)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jan 26 13:14:48 PST 2025


https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/123513

>From 021dd65bb55249f49b80a005096a9baf08d64031 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Sun, 19 Jan 2025 15:08:52 +0100
Subject: [PATCH] [Clang] Mangling of pack indexing type and expression for
 itanium

---
 clang/docs/ReleaseNotes.rst                  |  1 +
 clang/lib/AST/ItaniumMangle.cpp              | 89 +++++++++++++-------
 clang/test/CodeGenCXX/mangle-cxx2c.cpp       | 11 +++
 libcxxabi/src/demangle/ItaniumDemangle.h     | 43 ++++++++++
 libcxxabi/src/demangle/ItaniumNodes.def      |  2 +-
 libcxxabi/test/test_demangle.pass.cpp        |  5 ++
 llvm/include/llvm/Demangle/ItaniumDemangle.h | 43 ++++++++++
 llvm/include/llvm/Demangle/ItaniumNodes.def  |  2 +-
 8 files changed, 163 insertions(+), 33 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/mangle-cxx2c.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b63bd366cfe884..e5946fc71c56a6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1003,6 +1003,7 @@ Bug Fixes to C++ Support
   lambda functions or inline friend functions defined inside templates (#GH122493).
 - Clang now rejects declaring an alias template with the same name as its template parameter. (#GH123423)
 - Correctly determine the implicit constexprness of lambdas in dependent contexts. (#GH97958) (#GH114234)
+- Implement Itanium mangling for pack indexing. (#GH112003)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 1dd936cf4fb518..4b2cb630e16f87 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -603,6 +603,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);
@@ -4348,10 +4349,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) {
@@ -4785,35 +4786,63 @@ void CXXNameMangler::mangleRequirement(SourceLocation RequiresExprLoc,
   }
 }
 
+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));
+}
+
 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
+  //              ::= sy <expression> <expression>                   # pack
+  //              indexing expression
+  //              ::= 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;
 
@@ -4886,7 +4915,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:
@@ -5788,17 +5816,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;
   }
 
@@ -5828,6 +5846,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";
diff --git a/clang/test/CodeGenCXX/mangle-cxx2c.cpp b/clang/test/CodeGenCXX/mangle-cxx2c.cpp
new file mode 100644
index 00000000000000..3e4689948a7a7e
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-cxx2c.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-linux-gnu -std=c++2a | FileCheck %s
+
+namespace spaceship {
+  struct X {};
+  struct Y {};
+  int operator<=>(X, Y);
+
+  // CHECK-LABEL: define {{.*}} @_ZN9spaceship1fIiEEvDTcmltcvNS_1YE_EcvNS_1XE_EcvT__EE
+  template<typename T> void f(decltype(Y() < X(), T()) x) {}
+  template void f<int>(int);
+}
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 3df41b5f4d7d07..4cda6514bfac35 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -1521,6 +1521,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('[');
+    Index->printLeft(OB);
+    OB.printClose(']');
+  }
+};
+
 class TemplateArgs final : public Node {
   NodeArray Params;
   Node *Requires;
@@ -4510,6 +4531,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':
@@ -5354,6 +5387,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 18f5d52b47e911..2c183ec5d23f86 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/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp
index e9c74f70a094b5..e0a84de5e8cef9 100644
--- a/libcxxabi/test/test_demangle.pass.cpp
+++ b/libcxxabi/test/test_demangle.pass.cpp
@@ -30220,6 +30220,11 @@ const char* cases[][2] = {
     {"_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 b0363c1a7a7863..f567bfea37dbc8 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -1521,6 +1521,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('[');
+    Index->printLeft(OB);
+    OB.printClose(']');
+  }
+};
+
 class TemplateArgs final : public Node {
   NodeArray Params;
   Node *Requires;
@@ -4510,6 +4531,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':
@@ -5354,6 +5387,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 330552663ee658..3a28b1f1759247 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



More information about the libcxx-commits mailing list