https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/166578
Depends on: * https://github.com/llvm/llvm-project/pull/166577 The `isGtInsideTemplateArgs` wasn't the correct API to use for answering whether we are currently printing template arugments. One example is: ``` void func<(foo::Enum)1>() ``` Here `OutputBuffer::GtIsGt > 0` despite us being inside template arguments (because we incremented it when seeing '('). This patch now uses the correct API and adds the above as a test-case. >From 35e239cc0f7349a82af5efd7b5937ec0a189e23d Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Wed, 5 Nov 2025 16:07:12 +0000 Subject: [PATCH 1/2] [libcxxabi][ItaniumDemangle] Separate GtIsGt counter into more states Currently `OutputBuffer::GtIsGt` is used to tell us if we're inside template arguments and have printed a '(' without a closing ')'. If so, we don't need to quote '<' when printing it as part of a binary expression inside a template argument. Otherwise we need to. E.g., ``` foo<a<(b < c)>> // Quotes around binary expression needed. ``` LLDB's `TrackingOutputBuffer` has heuristics that rely on checking whether we are inside template arguments, regardless of the current parentheses depth. We've been using `isGtInsideTemplateArgs` for this, but that isn't correct. Resulting in us incorrectly tracking the basename of function like: ``` void func<(foo::Enum)1>() ``` Here `GtIsGt > 0` despite us being inside template arguments (because we incremented it when seeing '('). This patch adds a `isInsideTemplateArgs` API which LLDB will use to more accurately track parts of the demangled name. To make sure this API doesn't go untested in the actual libcxxabi test-suite, I changed the existing `GtIsGt` logic to use it. Also renamed the various variables/APIs involved to make it (in my opinion) more straightforward to understand what's going on. But happy to rename it back if people disagree. --- libcxxabi/src/demangle/ItaniumDemangle.h | 12 +++++---- libcxxabi/src/demangle/Utility.h | 26 +++++++++++++++----- llvm/include/llvm/Demangle/ItaniumDemangle.h | 12 +++++---- llvm/include/llvm/Demangle/Utility.h | 26 +++++++++++++++----- 4 files changed, 54 insertions(+), 22 deletions(-) diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h index 6f27da7b9cadf..b999438ff2ca8 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -1366,7 +1366,7 @@ class TemplateTemplateParamDecl final : public Node { template <typename Fn> void match(Fn F) const { F(Name, Params, Requires); } void printLeft(OutputBuffer &OB) const override { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + ScopedOverride<bool> LT(OB.TemplateTracker.InsideTemplate, true); OB += "template<"; Params.printWithComma(OB); OB += "> typename "; @@ -1550,7 +1550,7 @@ class TemplateArgs final : public Node { NodeArray getParams() { return Params; } void printLeft(OutputBuffer &OB) const override { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + ScopedOverride<bool> LT(OB.TemplateTracker.InsideTemplate, true); OB += "<"; Params.printWithComma(OB); OB += ">"; @@ -1824,7 +1824,7 @@ class ClosureTypeName : public Node { void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + ScopedOverride<bool> LT(OB.TemplateTracker.InsideTemplate, true); OB += "<"; TemplateParams.printWithComma(OB); OB += ">"; @@ -1885,7 +1885,9 @@ class BinaryExpr : public Node { } void printLeft(OutputBuffer &OB) const override { - bool ParenAll = OB.isGtInsideTemplateArgs() && + // If we're printing a '<' inside of a template argument, and we haven't + // yet parenthesized the expression, do so now. + bool ParenAll = !OB.isInParensInTemplateArgs() && (InfixOperator == ">" || InfixOperator == ">>"); if (ParenAll) OB.printOpen(); @@ -2061,7 +2063,7 @@ class CastExpr : public Node { void printLeft(OutputBuffer &OB) const override { OB += CastKind; { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + ScopedOverride<bool> LT(OB.TemplateTracker.InsideTemplate, true); OB += "<"; OB.printLeft(*To); OB += ">"; diff --git a/libcxxabi/src/demangle/Utility.h b/libcxxabi/src/demangle/Utility.h index 76243f5d3280c..df5b54dca492d 100644 --- a/libcxxabi/src/demangle/Utility.h +++ b/libcxxabi/src/demangle/Utility.h @@ -104,18 +104,32 @@ class OutputBuffer { unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); - /// When zero, we're printing template args and '>' needs to be parenthesized. - /// Use a counter so we can simply increment inside parentheses. - unsigned GtIsGt = 1; + struct { + /// The depth of '(' and ')' inside the currently printed template + /// arguments. + unsigned ParenDepth = 0; - bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } + /// True if we're currently printing a template argument. + bool InsideTemplate = false; + } TemplateTracker; + + /// Returns true if we're currently between a '(' and ')' when printing + /// template args. + bool isInParensInTemplateArgs() const { + return TemplateTracker.ParenDepth > 0; + } + + /// Returns true if we're printing template args. + bool isInsideTemplateArgs() const { return TemplateTracker.InsideTemplate; } void printOpen(char Open = '(') { - GtIsGt++; + if (isInsideTemplateArgs()) + TemplateTracker.ParenDepth++; *this += Open; } void printClose(char Close = ')') { - GtIsGt--; + if (isInsideTemplateArgs()) + TemplateTracker.ParenDepth--; *this += Close; } diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h index 62d427c3966bb..67de123fdbad5 100644 --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -1366,7 +1366,7 @@ class TemplateTemplateParamDecl final : public Node { template <typename Fn> void match(Fn F) const { F(Name, Params, Requires); } void printLeft(OutputBuffer &OB) const override { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + ScopedOverride<bool> LT(OB.TemplateTracker.InsideTemplate, true); OB += "template<"; Params.printWithComma(OB); OB += "> typename "; @@ -1550,7 +1550,7 @@ class TemplateArgs final : public Node { NodeArray getParams() { return Params; } void printLeft(OutputBuffer &OB) const override { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + ScopedOverride<bool> LT(OB.TemplateTracker.InsideTemplate, true); OB += "<"; Params.printWithComma(OB); OB += ">"; @@ -1824,7 +1824,7 @@ class ClosureTypeName : public Node { void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + ScopedOverride<bool> LT(OB.TemplateTracker.InsideTemplate, true); OB += "<"; TemplateParams.printWithComma(OB); OB += ">"; @@ -1885,7 +1885,9 @@ class BinaryExpr : public Node { } void printLeft(OutputBuffer &OB) const override { - bool ParenAll = OB.isGtInsideTemplateArgs() && + // If we're printing a '<' inside of a template argument, and we haven't + // yet parenthesized the expression, do so now. + bool ParenAll = !OB.isInParensInTemplateArgs() && (InfixOperator == ">" || InfixOperator == ">>"); if (ParenAll) OB.printOpen(); @@ -2061,7 +2063,7 @@ class CastExpr : public Node { void printLeft(OutputBuffer &OB) const override { OB += CastKind; { - ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + ScopedOverride<bool> LT(OB.TemplateTracker.InsideTemplate, true); OB += "<"; OB.printLeft(*To); OB += ">"; diff --git a/llvm/include/llvm/Demangle/Utility.h b/llvm/include/llvm/Demangle/Utility.h index 6e6203d716e7a..afdc1a397ca6f 100644 --- a/llvm/include/llvm/Demangle/Utility.h +++ b/llvm/include/llvm/Demangle/Utility.h @@ -104,18 +104,32 @@ class OutputBuffer { unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); - /// When zero, we're printing template args and '>' needs to be parenthesized. - /// Use a counter so we can simply increment inside parentheses. - unsigned GtIsGt = 1; + struct { + /// The depth of '(' and ')' inside the currently printed template + /// arguments. + unsigned ParenDepth = 0; - bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } + /// True if we're currently printing a template argument. + bool InsideTemplate = false; + } TemplateTracker; + + /// Returns true if we're currently between a '(' and ')' when printing + /// template args. + bool isInParensInTemplateArgs() const { + return TemplateTracker.ParenDepth > 0; + } + + /// Returns true if we're printing template args. + bool isInsideTemplateArgs() const { return TemplateTracker.InsideTemplate; } void printOpen(char Open = '(') { - GtIsGt++; + if (isInsideTemplateArgs()) + TemplateTracker.ParenDepth++; *this += Open; } void printClose(char Close = ')') { - GtIsGt--; + if (isInsideTemplateArgs()) + TemplateTracker.ParenDepth--; *this += Close; } >From fe949989de7b5db75b6555c90ee41ba0085c64cd Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Wed, 5 Nov 2025 16:09:08 +0000 Subject: [PATCH 2/2] [lldb][DemangledNameInfo] Fix tracking of template arugments Depends on: * https://github.com/llvm/llvm-project/pull/166577 The `isGtInsideTemplateArgs` wasn't the correct API to use for answering whether we are currently printing template arugments. One example is: ``` void func<(foo::Enum)1>() ``` Here `OutputBuffer::GtIsGt > 0` despite us being inside template arguments (because we incremented it when seeing '('). This patch now uses the correct API and adds the above as a test-case. --- lldb/source/Core/DemangledNameInfo.cpp | 4 ++-- lldb/unittests/Core/MangledTest.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lldb/source/Core/DemangledNameInfo.cpp b/lldb/source/Core/DemangledNameInfo.cpp index 76f8987c5149c..16fbfda299b21 100644 --- a/lldb/source/Core/DemangledNameInfo.cpp +++ b/lldb/source/Core/DemangledNameInfo.cpp @@ -16,7 +16,7 @@ bool TrackingOutputBuffer::shouldTrack() const { if (!isPrintingTopLevelFunctionType()) return false; - if (isGtInsideTemplateArgs()) + if (isInsideTemplateArgs()) return false; if (NameInfo.ArgumentsRange.first > 0) @@ -29,7 +29,7 @@ bool TrackingOutputBuffer::canFinalize() const { if (!isPrintingTopLevelFunctionType()) return false; - if (isGtInsideTemplateArgs()) + if (isInsideTemplateArgs()) return false; if (NameInfo.ArgumentsRange.first == 0) diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/MangledTest.cpp index cbc0c5d951b99..706e67801e01a 100644 --- a/lldb/unittests/Core/MangledTest.cpp +++ b/lldb/unittests/Core/MangledTest.cpp @@ -636,6 +636,16 @@ DemanglingPartsTestCase g_demangling_parts_test_cases[] = { /*.basename=*/"operator()", /*.scope=*/"dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::", /*.qualifiers=*/" const", + }, + {"_Z4funcILN3foo4EnumE1EEvv", + { + /*.BasenameRange=*/{5, 9}, /*.TemplateArgumentsRange=*/{9, 23}, /*.ScopeRange=*/{5, 5}, + /*.ArgumentsRange=*/{23, 25}, /*.QualifiersRange=*/{25, 25}, /*.NameQualifiersRange=*/{0, 0}, + /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} + }, + /*.basename=*/"func", + /*.scope=*/"", + /*.qualifiers=*/"", } // clang-format on }; _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
