[libcxx-commits] [libcxxabi] [llvm] [libc++abi] Enable demangling of `cp` expression production (PR #114882)

Hubert Tong via libcxx-commits libcxx-commits at lists.llvm.org
Wed Dec 4 18:22:13 PST 2024


https://github.com/hubert-reinterpretcast updated https://github.com/llvm/llvm-project/pull/114882

>From 167a0dc00d5845f246789ff63528172cdfc1ef82 Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Sat, 19 Oct 2024 01:57:52 -0400
Subject: [PATCH 01/10] WIP: Enable demangling of `cp` expression production

---
 libcxxabi/src/demangle/ItaniumDemangle.h     | 1 +
 llvm/include/llvm/Demangle/ItaniumDemangle.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 501d0b6fdfcd16..b44077fd9c9916 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -3357,6 +3357,7 @@ const typename AbstractManglingParser<
     {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
     {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
     {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
+    {"cp", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
     {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
     {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
     {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 56ff3cfb148f09..2e677a0e0f1490 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -3357,6 +3357,7 @@ const typename AbstractManglingParser<
     {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
     {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
     {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
+    {"cp", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
     {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
     {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
     {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,

>From 0e07c770d77f9e4960b28e504a50c0f132f0869d Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Sat, 2 Nov 2024 21:56:40 -0400
Subject: [PATCH 02/10] Update `cp` demangling to display parentheses; update
 test

---
 libcxxabi/src/demangle/ItaniumDemangle.h | 22 +++++++++++++++-------
 libcxxabi/test/test_demangle.pass.cpp    | 14 ++++++--------
 2 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index b44077fd9c9916..3b23ae4e35dea6 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -2077,17 +2077,25 @@ class SizeofParamPackExpr : public Node {
 class CallExpr : public Node {
   const Node *Callee;
   NodeArray Args;
+  bool IsParen; // (func)(args ...) ?
 
 public:
-  CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_)
-      : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {}
+  CallExpr(const Node *Callee_, NodeArray Args_, bool IsParen_, Prec Prec_)
+      : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_),
+        IsParen(IsParen_) {}
 
   template <typename Fn> void match(Fn F) const {
     F(Callee, Args, getPrecedence());
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    Callee->print(OB);
+    if (IsParen) {
+      OB.printOpen();
+      Callee->print(OB);
+      OB.printClose();
+    } else {
+      Callee->print(OB);
+    }
     OB.printOpen();
     Args.printWithComma(OB);
     OB.printClose();
@@ -3354,10 +3362,10 @@ const typename AbstractManglingParser<
      "operator co_await"},
     {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
     {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
-    {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
+    {"cl", OperatorInfo::Call, /*Paren*/ false, Node::Prec::Postfix, "operator()"},
     {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
     {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
-    {"cp", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
+    {"cp", OperatorInfo::Call, /*Paren*/ true, Node::Prec::Postfix, "operator()"},
     {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
     {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
     {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,
@@ -5140,7 +5148,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
         Names.push_back(E);
       }
       return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin),
-                            Op->getPrecedence());
+                            /*IsParen=*/Op->getFlag(), Op->getPrecedence());
     }
     case OperatorInfo::CCast: {
       // C Cast: (type)expr
@@ -5327,7 +5335,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
       }
     }
     return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin),
-                          Node::Prec::Postfix);
+                          /*IsParen=*/false, Node::Prec::Postfix);
   }
 
   // Only unresolved names remain.
diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp
index ad131bb3a8a7b1..60292ae280eb7d 100644
--- a/libcxxabi/test/test_demangle.pass.cpp
+++ b/libcxxabi/test/test_demangle.pass.cpp
@@ -29834,6 +29834,7 @@ const char* cases[][2] =
     {"_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE", "void Casts::auto_<int>(decltype(new auto((int)())))"},
     {"_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE", "void Casts::scalar_<int>(decltype((int)(), (int)()))"},
     {"_ZN5test11aIsEEDTcl3foocvT__EEES1_", "decltype(foo((short)())) test1::a<short>(short)"},
+    {"_ZN5test11bIsEEDTcp3foocvT__EEES1_", "decltype((foo)((short)())) test1::b<short>(short)"},
     {"_ZN5test21aIPFfvEEEvT_DTclfL0p_EE", "void test2::a<float (*)()>(float (*)(), decltype(fp()))"},
     {"_ZN5test21bIPFfvEEEDTclfp_EET_", "decltype(fp()) test2::b<float (*)()>(float (*)())"},
     {"_ZN5test21cIPFfvEEEvT_PFvDTclfL1p_EEE", "void test2::c<float (*)()>(float (*)(), void (*)(decltype(fp())))"},
@@ -30371,24 +30372,21 @@ void test_invalid_cases()
     assert(!passed && "demangle did not fail");
 }
 
-const char *xfail_cases[] = {
-    // FIXME: Why does clang generate the "cp" expr?
-    "_ZN5test11bIsEEDTcp3foocvT__EEES1_",
+const char *const xfail_cases[] = {
+    nullptr
 };
 
-const size_t num_xfails = sizeof(xfail_cases) / sizeof(xfail_cases[0]);
-
 void test_xfail_cases()
 {
     std::size_t len = 0;
     char* buf = nullptr;
-    for (std::size_t i = 0; i < num_xfails; ++i)
+    for (const char *const *it = xfail_cases; *it; ++it)
     {
         int status;
-        char* demang = __cxxabiv1::__cxa_demangle(xfail_cases[i], buf, &len, &status);
+        char* demang = __cxxabiv1::__cxa_demangle(*it, buf, &len, &status);
         if (status != -2)
         {
-            std::printf("%s was documented as xfail but passed\n", xfail_cases[i]);
+            std::printf("%s was documented as xfail but passed\n", *it);
             std::printf("Got status = %d\n", status);
             assert(status == -2);
         }

>From 58ab15048ddb17432da68d491806640505e97a92 Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Sat, 2 Nov 2024 22:04:28 -0400
Subject: [PATCH 03/10] Add `cp` production to grammar in comment

---
 libcxxabi/src/demangle/ItaniumDemangle.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 3b23ae4e35dea6..d4fb71ce21529a 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -5013,6 +5013,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseRequiresExpr() {
 //              ::= <binary operator-name> <expression> <expression>
 //              ::= <ternary operator-name> <expression> <expression> <expression>
 //              ::= cl <expression>+ E                                   # call
+//              ::= cp <base-unresolved-name> <expression>* E            # (name) (expr-list), call that would use argument-dependent lookup but for the parentheses
 //              ::= cv <type> <expression>                               # conversion with one argument
 //              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments
 //              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type

>From f9bcd02ad5e0cc6e7a309ce20c6f29ee1f9f9664 Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Sat, 2 Nov 2024 22:07:04 -0400
Subject: [PATCH 04/10] Apply libcxxabi/src/demangle/cp-to-llvm.sh

---
 llvm/include/llvm/Demangle/ItaniumDemangle.h | 23 ++++++++++++++------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 2e677a0e0f1490..f3995e1ea73e7d 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -2077,17 +2077,25 @@ class SizeofParamPackExpr : public Node {
 class CallExpr : public Node {
   const Node *Callee;
   NodeArray Args;
+  bool IsParen; // (func)(args ...) ?
 
 public:
-  CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_)
-      : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {}
+  CallExpr(const Node *Callee_, NodeArray Args_, bool IsParen_, Prec Prec_)
+      : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_),
+        IsParen(IsParen_) {}
 
   template <typename Fn> void match(Fn F) const {
     F(Callee, Args, getPrecedence());
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    Callee->print(OB);
+    if (IsParen) {
+      OB.printOpen();
+      Callee->print(OB);
+      OB.printClose();
+    } else {
+      Callee->print(OB);
+    }
     OB.printOpen();
     Args.printWithComma(OB);
     OB.printClose();
@@ -3354,10 +3362,10 @@ const typename AbstractManglingParser<
      "operator co_await"},
     {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
     {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
-    {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
+    {"cl", OperatorInfo::Call, /*Paren*/ false, Node::Prec::Postfix, "operator()"},
     {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
     {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
-    {"cp", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
+    {"cp", OperatorInfo::Call, /*Paren*/ true, Node::Prec::Postfix, "operator()"},
     {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
     {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
     {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,
@@ -5005,6 +5013,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseRequiresExpr() {
 //              ::= <binary operator-name> <expression> <expression>
 //              ::= <ternary operator-name> <expression> <expression> <expression>
 //              ::= cl <expression>+ E                                   # call
+//              ::= cp <base-unresolved-name> <expression>* E            # (name) (expr-list), call that would use argument-dependent lookup but for the parentheses
 //              ::= cv <type> <expression>                               # conversion with one argument
 //              ::= cv <type> _ <expression>* E                          # conversion with a different number of arguments
 //              ::= [gs] nw <expression>* _ <type> E                     # new (expr-list) type
@@ -5140,7 +5149,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
         Names.push_back(E);
       }
       return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin),
-                            Op->getPrecedence());
+                            /*IsParen=*/Op->getFlag(), Op->getPrecedence());
     }
     case OperatorInfo::CCast: {
       // C Cast: (type)expr
@@ -5327,7 +5336,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
       }
     }
     return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin),
-                          Node::Prec::Postfix);
+                          /*IsParen=*/false, Node::Prec::Postfix);
   }
 
   // Only unresolved names remain.

>From 8ffe8dddf44546005fbd9b6aae0842b391829619 Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Sat, 2 Nov 2024 22:58:51 -0400
Subject: [PATCH 05/10] Fix CallExpr matcher to account for new IsParen
 property

---
 libcxxabi/src/demangle/ItaniumDemangle.h     | 2 +-
 llvm/include/llvm/Demangle/ItaniumDemangle.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index d4fb71ce21529a..239d79952be2e1 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -2085,7 +2085,7 @@ class CallExpr : public Node {
         IsParen(IsParen_) {}
 
   template <typename Fn> void match(Fn F) const {
-    F(Callee, Args, getPrecedence());
+    F(Callee, Args, IsParen, getPrecedence());
   }
 
   void printLeft(OutputBuffer &OB) const override {
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index f3995e1ea73e7d..21d18a5a145178 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -2085,7 +2085,7 @@ class CallExpr : public Node {
         IsParen(IsParen_) {}
 
   template <typename Fn> void match(Fn F) const {
-    F(Callee, Args, getPrecedence());
+    F(Callee, Args, IsParen, getPrecedence());
   }
 
   void printLeft(OutputBuffer &OB) const override {

>From e12e8a0b3444dcf787da2bc5ca8b0aa82a8ddefb Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Mon, 4 Nov 2024 22:59:34 -0500
Subject: [PATCH 06/10] Fix line wrapping for new/changed entries of Ops array

---
 libcxxabi/src/demangle/ItaniumDemangle.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 239d79952be2e1..dfc62a6ceb083d 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -3362,10 +3362,12 @@ const typename AbstractManglingParser<
      "operator co_await"},
     {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
     {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
-    {"cl", OperatorInfo::Call, /*Paren*/ false, Node::Prec::Postfix, "operator()"},
+    {"cl", OperatorInfo::Call, /*Paren*/ false, Node::Prec::Postfix,
+     "operator()"},
     {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
     {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
-    {"cp", OperatorInfo::Call, /*Paren*/ true, Node::Prec::Postfix, "operator()"},
+    {"cp", OperatorInfo::Call, /*Paren*/ true, Node::Prec::Postfix,
+     "operator()"},
     {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
     {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
     {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,

>From 69d6cdb67ecfa3a7daeaa0c5d22fbe6d2f375edd Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Mon, 4 Nov 2024 23:06:53 -0500
Subject: [PATCH 07/10] Add comment for use of `nullptr` in `xfail_cases` array

---
 libcxxabi/test/test_demangle.pass.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp
index 60292ae280eb7d..6d01373858d27e 100644
--- a/libcxxabi/test/test_demangle.pass.cpp
+++ b/libcxxabi/test/test_demangle.pass.cpp
@@ -30373,6 +30373,7 @@ void test_invalid_cases()
 }
 
 const char *const xfail_cases[] = {
+    // Sentinel value
     nullptr
 };
 

>From 518bb59f11c1a6c884ad86062ac849f3c7175925 Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Mon, 4 Nov 2024 23:11:54 -0500
Subject: [PATCH 08/10] Follow "left" PointerAlignment of code within function

---
 libcxxabi/test/test_demangle.pass.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp
index 6d01373858d27e..db7da1dffa0d4d 100644
--- a/libcxxabi/test/test_demangle.pass.cpp
+++ b/libcxxabi/test/test_demangle.pass.cpp
@@ -30381,7 +30381,7 @@ void test_xfail_cases()
 {
     std::size_t len = 0;
     char* buf = nullptr;
-    for (const char *const *it = xfail_cases; *it; ++it)
+    for (const char* const* it = xfail_cases; *it; ++it)
     {
         int status;
         char* demang = __cxxabiv1::__cxa_demangle(*it, buf, &len, &status);

>From b5df56e86c1fd3d887b0b71e0bc9b5c579eb6f45 Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Mon, 4 Nov 2024 23:16:58 -0500
Subject: [PATCH 09/10] Apply libcxxabi/src/demangle/cp-to-llvm.sh (again)

---
 llvm/include/llvm/Demangle/ItaniumDemangle.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 21d18a5a145178..bb1591cf75157b 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -3362,10 +3362,12 @@ const typename AbstractManglingParser<
      "operator co_await"},
     {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
     {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
-    {"cl", OperatorInfo::Call, /*Paren*/ false, Node::Prec::Postfix, "operator()"},
+    {"cl", OperatorInfo::Call, /*Paren*/ false, Node::Prec::Postfix,
+     "operator()"},
     {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
     {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
-    {"cp", OperatorInfo::Call, /*Paren*/ true, Node::Prec::Postfix, "operator()"},
+    {"cp", OperatorInfo::Call, /*Paren*/ true, Node::Prec::Postfix,
+     "operator()"},
     {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
     {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
     {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,

>From d55e03650ba350c9f557e2d1f6fe0b56c64692ea Mon Sep 17 00:00:00 2001
From: Hubert Tong <hubert.reinterpretcast at gmail.com>
Date: Wed, 4 Dec 2024 22:22:00 -0400
Subject: [PATCH 10/10] Apply code suggestion from review

Share common code between the true and false paths re: `IsParen`

Co-authored-by: Nick Desaulniers <nickdesaulniers at users.noreply.github.com>
---
 libcxxabi/src/demangle/ItaniumDemangle.h | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index dfc62a6ceb083d..23dc0ea297536d 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -2089,13 +2089,11 @@ class CallExpr : public Node {
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    if (IsParen) {
+    if (IsParen)
       OB.printOpen();
-      Callee->print(OB);
+    Callee->print(OB);
+    if (IsParen)
       OB.printClose();
-    } else {
-      Callee->print(OB);
-    }
     OB.printOpen();
     Args.printWithComma(OB);
     OB.printClose();



More information about the libcxx-commits mailing list