-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[Clang] Mangling of pack indexing type and expression for itanium #123513
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
@llvm/pr-subscribers-libcxxabi @llvm/pr-subscribers-clang Author: cor3ntin (cor3ntin) ChangesSee itanium-cxx-abi/cxx-abi#198 Full diff: https://github.com/llvm/llvm-project/pull/123513.diff 8 Files Affected:
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
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm unfamiliar with the libcxx/LLVM demangler part, but it does look like we're duplicating something. Can anyone explain why we have to do that?
@@ -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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should live in C++2c support
section, as this isn't strictly a bug.
@@ -4787,6 +4788,7 @@ void CXXNameMangler::mangleRequirement(SourceLocation RequiresExprLoc, | |||
|
|||
void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, | |||
bool AsTemplateArg) { | |||
// clang-format off |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Why turning it off?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-format
initially completely destroy the comment below, which has been neatly aligned
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't related to what this patch proposes or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oups
https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/Demangle/README.txt It's... not great ( guess how many times i modified the wrong copy?!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CFE changes seem fine to me. The demangler ones look correct, but I've not debugged in there for quite a while.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense but let's make sure we cover all the added branches in the test suite.
@@ -5828,6 +5822,15 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, | |||
break; | |||
} | |||
|
|||
case Expr::PackIndexingExprClass: { | |||
auto *PE = cast<PackIndexingExpr>(E); | |||
NotPrimaryExpr(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am looking at the test cases and I don't see the X
, can we make sure we cover that branch in NotPrimaryExpr
e.g. if (AsTemplateArg && IsPrimaryExpr)
. We should make sure we cover that in the demangling as well.
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add invalid cases as well see invalid_cases
and make sure we cover each case that can return a nullptr
in AbstractManglingParser
(I think)
See itanium-cxx-abi/cxx-abi#198
and #112003