https://github.com/Michael137 updated 
https://github.com/llvm/llvm-project/pull/133249

>From 0875195a7ed39c21e9b639bf66d56b48e9869e51 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Tue, 11 Mar 2025 08:57:13 +0000
Subject: [PATCH 1/2] [llvm][ItaniumDemangle] Add function name location
 tracking

---
 libcxxabi/src/demangle/ItaniumDemangle.h      |  21 ++++
 libcxxabi/src/demangle/Utility.cpp            | 112 ++++++++++++++++++
 libcxxabi/src/demangle/Utility.h              |  91 +++++++++++---
 libcxxabi/src/demangle/cp-to-llvm.sh          |  62 +++++++---
 llvm/include/llvm/Demangle/ItaniumDemangle.h  |  21 ++++
 llvm/include/llvm/Demangle/Utility.h          |  91 +++++++++++---
 llvm/lib/Demangle/CMakeLists.txt              |   1 +
 llvm/lib/Demangle/README.txt                  |  61 ++++++++++
 llvm/lib/Demangle/Utility.cpp                 | 112 ++++++++++++++++++
 .../Demangle/ItaniumDemangleTest.cpp          | 112 ++++++++++++++++++
 10 files changed, 635 insertions(+), 49 deletions(-)
 create mode 100644 libcxxabi/src/demangle/Utility.cpp
 create mode 100644 llvm/lib/Demangle/README.txt
 create mode 100644 llvm/lib/Demangle/Utility.cpp

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h 
b/libcxxabi/src/demangle/ItaniumDemangle.h
index 3df41b5f4d7d0..b5a0a86b119f4 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -851,11 +851,13 @@ class FunctionType final : public Node {
   // by printing out the return types's left, then print our parameters, then
   // finally print right of the return type.
   void printLeft(OutputBuffer &OB) const override {
+    auto Scoped = OB.enterFunctionTypePrinting();
     Ret->printLeft(OB);
     OB += " ";
   }
 
   void printRight(OutputBuffer &OB) const override {
+    auto Scoped = OB.enterFunctionTypePrinting();
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
@@ -971,18 +973,32 @@ class FunctionEncoding final : public Node {
   const Node *getName() const { return Name; }
 
   void printLeft(OutputBuffer &OB) const override {
+    // Nested FunctionEncoding parsing can happen with following productions:
+    // * <local-name>
+    // * <expr-primary>
+    auto Scoped = OB.enterFunctionTypePrinting();
+
     if (Ret) {
       Ret->printLeft(OB);
       if (!Ret->hasRHSComponent(OB))
         OB += " ";
     }
+
+    OB.FunctionInfo.updateScopeStart(OB);
+
     Name->print(OB);
   }
 
   void printRight(OutputBuffer &OB) const override {
+    auto Scoped = OB.enterFunctionTypePrinting();
+    OB.FunctionInfo.finalizeStart(OB);
+
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
+
+    OB.FunctionInfo.finalizeArgumentEnd(OB);
+
     if (Ret)
       Ret->printRight(OB);
 
@@ -1005,6 +1021,8 @@ class FunctionEncoding final : public Node {
       OB += " requires ";
       Requires->print(OB);
     }
+
+    OB.FunctionInfo.finalizeEnd(OB);
   }
 };
 
@@ -1072,7 +1090,9 @@ struct NestedName : Node {
   void printLeft(OutputBuffer &OB) const override {
     Qual->print(OB);
     OB += "::";
+    OB.FunctionInfo.updateScopeEnd(OB);
     Name->print(OB);
+    OB.FunctionInfo.updateBasenameEnd(OB);
   }
 };
 
@@ -1633,6 +1653,7 @@ struct NameWithTemplateArgs : Node {
 
   void printLeft(OutputBuffer &OB) const override {
     Name->print(OB);
+    OB.FunctionInfo.updateBasenameEnd(OB);
     TemplateArgs->print(OB);
   }
 };
diff --git a/libcxxabi/src/demangle/Utility.cpp 
b/libcxxabi/src/demangle/Utility.cpp
new file mode 100644
index 0000000000000..04516082b3443
--- /dev/null
+++ b/libcxxabi/src/demangle/Utility.cpp
@@ -0,0 +1,112 @@
+//===--- Utility.cpp 
------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Provide some utility classes for use in the demangler.
+// There are two copies of this file in the source tree.  The one in libcxxabi
+// is the original and the one in llvm is the copy.  Use cp-to-llvm.sh to 
update
+// the copy.  See README.txt for more details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Utility.h"
+#include "DemangleConfig.h"
+
+DEMANGLE_NAMESPACE_BEGIN
+
+bool FunctionNameInfo::startedPrintingArguments() const {
+  return ArgumentLocs.first > 0;
+}
+
+bool FunctionNameInfo::shouldTrack(OutputBuffer &OB) const {
+  if (!OB.isPrintingTopLevelFunctionType())
+    return false;
+
+  if (OB.isGtInsideTemplateArgs())
+    return false;
+
+  if (startedPrintingArguments())
+    return false;
+
+  return true;
+}
+
+bool FunctionNameInfo::canFinalize(OutputBuffer &OB) const {
+  if (!OB.isPrintingTopLevelFunctionType())
+    return false;
+
+  if (OB.isGtInsideTemplateArgs())
+    return false;
+
+  if (!startedPrintingArguments())
+    return false;
+
+  return true;
+}
+
+void FunctionNameInfo::updateBasenameEnd(OutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  BasenameLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::updateScopeStart(OutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  ScopeLocs.first = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::updateScopeEnd(OutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  ScopeLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::finalizeArgumentEnd(OutputBuffer &OB) {
+  if (!canFinalize(OB))
+    return;
+
+  OB.FunctionInfo.ArgumentLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::finalizeStart(OutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  OB.FunctionInfo.ArgumentLocs.first = OB.getCurrentPosition();
+
+  // If nothing has set the end of the basename yet (for example when
+  // printing templates), then the beginning of the arguments is the end of
+  // the basename.
+  if (BasenameLocs.second == 0)
+    OB.FunctionInfo.BasenameLocs.second = OB.getCurrentPosition();
+
+  DEMANGLE_ASSERT(!shouldTrack(OB), "");
+  DEMANGLE_ASSERT(canFinalize(OB), "");
+}
+
+void FunctionNameInfo::finalizeEnd(OutputBuffer &OB) {
+  if (!canFinalize(OB))
+    return;
+
+  if (ScopeLocs.first > OB.FunctionInfo.ScopeLocs.second)
+    ScopeLocs.second = OB.FunctionInfo.ScopeLocs.first;
+  BasenameLocs.first = OB.FunctionInfo.ScopeLocs.second;
+}
+
+bool FunctionNameInfo::hasBasename() const {
+  return BasenameLocs.first != BasenameLocs.second && BasenameLocs.second > 0;
+}
+
+ScopedOverride<unsigned> OutputBuffer::enterFunctionTypePrinting() {
+  return {FunctionPrintingDepth, FunctionPrintingDepth + 1};
+}
+
+DEMANGLE_NAMESPACE_END
diff --git a/libcxxabi/src/demangle/Utility.h b/libcxxabi/src/demangle/Utility.h
index f1fad35d60d98..3b9ff8ea1f82b 100644
--- a/libcxxabi/src/demangle/Utility.h
+++ b/libcxxabi/src/demangle/Utility.h
@@ -27,6 +27,66 @@
 
 DEMANGLE_NAMESPACE_BEGIN
 
+template <class T> class ScopedOverride {
+  T &Loc;
+  T Original;
+
+public:
+  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
+
+  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
+    Loc_ = std::move(NewVal);
+  }
+  ~ScopedOverride() { Loc = std::move(Original); }
+
+  ScopedOverride(const ScopedOverride &) = delete;
+  ScopedOverride &operator=(const ScopedOverride &) = delete;
+};
+
+class OutputBuffer;
+
+// Stores information about parts of a demangled function name.
+struct FunctionNameInfo {
+  /// A [start, end) pair for the function basename.
+  /// The basename is the name without scope qualifiers
+  /// and without template parameters. E.g.,
+  /// \code{.cpp}
+  ///    void foo::bar<int>::someFunc<float>(int) const &&
+  ///                        ^       ^
+  ///                      Start    End
+  /// \endcode
+  std::pair<size_t, size_t> BasenameLocs;
+
+  /// A [start, end) pair for the function scope qualifiers.
+  /// E.g., for
+  /// \code{.cpp}
+  ///    void foo::bar<int>::qux<float>(int) const &&
+  ///         ^              ^
+  ///       Start           End
+  /// \endcode
+  std::pair<size_t, size_t> ScopeLocs;
+
+  /// Indicates the [start, end) of the function argument lits.
+  /// E.g.,
+  /// \code{.cpp}
+  ///    int (*getFunc<float>(float, double))(int, int)
+  ///                        ^              ^
+  ///                      start           end
+  /// \endcode
+  std::pair<size_t, size_t> ArgumentLocs;
+
+  bool startedPrintingArguments() const;
+  bool shouldTrack(OutputBuffer &OB) const;
+  bool canFinalize(OutputBuffer &OB) const;
+  void updateBasenameEnd(OutputBuffer &OB);
+  void updateScopeStart(OutputBuffer &OB);
+  void updateScopeEnd(OutputBuffer &OB);
+  void finalizeArgumentEnd(OutputBuffer &OB);
+  void finalizeStart(OutputBuffer &OB);
+  void finalizeEnd(OutputBuffer &OB);
+  bool hasBasename() const;
+};
+
 // Stream that AST nodes write their string representation into after the AST
 // has been parsed.
 class OutputBuffer {
@@ -34,6 +94,10 @@ class OutputBuffer {
   size_t CurrentPosition = 0;
   size_t BufferCapacity = 0;
 
+  /// When a function type is being printed this value is incremented.
+  /// When printing of the type is finished the value is decremented.
+  unsigned FunctionPrintingDepth = 0;
+
   // Ensure there are at least N more positions in the buffer.
   void grow(size_t N) {
     size_t Need = N + CurrentPosition;
@@ -92,8 +156,19 @@ class OutputBuffer {
   /// Use a counter so we can simply increment inside parentheses.
   unsigned GtIsGt = 1;
 
+  /// When printing the mangle tree, this object will hold information about
+  /// the function name being printed (if any).
+  FunctionNameInfo FunctionInfo;
+
+  /// Called when we start printing a function type.
+  [[nodiscard]] ScopedOverride<unsigned> enterFunctionTypePrinting();
+
   bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
 
+  bool isPrintingTopLevelFunctionType() const {
+    return FunctionPrintingDepth == 1;
+  }
+
   void printOpen(char Open = '(') {
     GtIsGt++;
     *this += Open;
@@ -182,22 +257,6 @@ class OutputBuffer {
   size_t getBufferCapacity() const { return BufferCapacity; }
 };
 
-template <class T> class ScopedOverride {
-  T &Loc;
-  T Original;
-
-public:
-  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
-
-  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
-    Loc_ = std::move(NewVal);
-  }
-  ~ScopedOverride() { Loc = std::move(Original); }
-
-  ScopedOverride(const ScopedOverride &) = delete;
-  ScopedOverride &operator=(const ScopedOverride &) = delete;
-};
-
 DEMANGLE_NAMESPACE_END
 
 #endif
diff --git a/libcxxabi/src/demangle/cp-to-llvm.sh 
b/libcxxabi/src/demangle/cp-to-llvm.sh
index f8b3585a5fa37..4d76a1e110687 100755
--- a/libcxxabi/src/demangle/cp-to-llvm.sh
+++ b/libcxxabi/src/demangle/cp-to-llvm.sh
@@ -7,30 +7,58 @@ set -e
 
 cd $(dirname $0)
 HDRS="ItaniumDemangle.h ItaniumNodes.def StringViewExtras.h Utility.h"
-LLVM_DEMANGLE_DIR=$1
+SRCS="Utility.cpp"
+LLVM_DEMANGLE_INCLUDE_DIR=$1
+LLVM_DEMANGLE_SOURCE_DIR=$2
 
-if [[ -z "$LLVM_DEMANGLE_DIR" ]]; then
-    LLVM_DEMANGLE_DIR="../../../llvm/include/llvm/Demangle"
+if [[ -z "$LLVM_DEMANGLE_INCLUDE_DIR" ]]; then
+    LLVM_DEMANGLE_INCLUDE_DIR="../../../llvm/include/llvm/Demangle"
 fi
 
-if [[ ! -d "$LLVM_DEMANGLE_DIR" ]]; then
-    echo "No such directory: $LLVM_DEMANGLE_DIR" >&2
+if [[ -z "$LLVM_DEMANGLE_SOURCE_DIR" ]]; then
+    LLVM_DEMANGLE_SOURCE_DIR="../../../llvm/lib/Demangle"
+fi
+
+if [[ ! -d "$LLVM_DEMANGLE_INCLUDE_DIR" ]]; then
+    echo "No such directory: $LLVM_DEMANGLE_INCLUDE_DIR" >&2
+    exit 1
+fi
+
+if [[ ! -d "$LLVM_DEMANGLE_SOURCE_DIR" ]]; then
+    echo "No such directory: $LLVM_DEMANGLE_SOURCE_DIR" >&2
     exit 1
 fi
 
-read -p "This will overwrite the copies of $HDRS in $LLVM_DEMANGLE_DIR; are 
you sure? [y/N]" -n 1 -r ANSWER
+read -p "This will overwrite the copies of $HDRS in $LLVM_DEMANGLE_INCLUDE_DIR 
and $SRCS in $LLVM_DEMANGLE_SOURCE_DIR; are you sure? [y/N]" -n 1 -r ANSWER
 echo
 
-if [[ $ANSWER =~ ^[Yy]$ ]]; then
-    cp -f README.txt $LLVM_DEMANGLE_DIR
-    chmod -w $LLVM_DEMANGLE_DIR/README.txt
-    for I in $HDRS ; do
-       rm -f $LLVM_DEMANGLE_DIR/$I
-       dash=$(echo "$I---------------------------" | cut -c -27 |\
-                  sed 's|[^-]*||')
-       sed -e '1s|^//=*-* .*\..* -*.*=*// *$|//===--- '"$I $dash"'-*- 
mode:c++;eval:(read-only-mode) -*-===//|' \
-           -e '2s|^// *$|//       Do not edit! See README.txt.|' \
-           $I >$LLVM_DEMANGLE_DIR/$I
-       chmod -w $LLVM_DEMANGLE_DIR/$I
+function copy_files() {
+    local dest_dir=$1
+    local files=$2
+    local adjust_include_paths=$3
+
+    cp -f README.txt $dest_dir
+    chmod -w $dest_dir/README.txt
+    for I in $files ; do
+    rm -f $dest_dir/$I
+    dash=$(echo "$I---------------------------" | cut -c -27 |\
+          sed 's|[^-]*||')
+    sed -e '1s|^//=*-* .*\..* -*.*=*// *$|//===--- '"$I $dash"'-*- 
mode:c++;eval:(read-only-mode) -*-===//|' \
+        -e '2s|^// *$|//       Do not edit! See README.txt.|' \
+        $I >$dest_dir/$I
+
+    if [[ "$adjust_include_paths" = true ]]; then
+        sed -i '' \
+            -e 's|#include "DemangleConfig.h"|#include 
"llvm/Demangle/DemangleConfig.h"|' \
+            -e 's|#include "Utility.h"|#include "llvm/Demangle/Utility.h"|' \
+            $dest_dir/$I
+    fi
+
+    chmod -w $dest_dir/$I
     done
+}
+
+if [[ $ANSWER =~ ^[Yy]$ ]]; then
+  copy_files $LLVM_DEMANGLE_INCLUDE_DIR "$HDRS" false
+  copy_files $LLVM_DEMANGLE_SOURCE_DIR "$SRCS" true
 fi
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h 
b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index b0363c1a7a786..2b51be306203d 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -851,11 +851,13 @@ class FunctionType final : public Node {
   // by printing out the return types's left, then print our parameters, then
   // finally print right of the return type.
   void printLeft(OutputBuffer &OB) const override {
+    auto Scoped = OB.enterFunctionTypePrinting();
     Ret->printLeft(OB);
     OB += " ";
   }
 
   void printRight(OutputBuffer &OB) const override {
+    auto Scoped = OB.enterFunctionTypePrinting();
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
@@ -971,18 +973,32 @@ class FunctionEncoding final : public Node {
   const Node *getName() const { return Name; }
 
   void printLeft(OutputBuffer &OB) const override {
+    // Nested FunctionEncoding parsing can happen with following productions:
+    // * <local-name>
+    // * <expr-primary>
+    auto Scoped = OB.enterFunctionTypePrinting();
+
     if (Ret) {
       Ret->printLeft(OB);
       if (!Ret->hasRHSComponent(OB))
         OB += " ";
     }
+
+    OB.FunctionInfo.updateScopeStart(OB);
+
     Name->print(OB);
   }
 
   void printRight(OutputBuffer &OB) const override {
+    auto Scoped = OB.enterFunctionTypePrinting();
+    OB.FunctionInfo.finalizeStart(OB);
+
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
+
+    OB.FunctionInfo.finalizeArgumentEnd(OB);
+
     if (Ret)
       Ret->printRight(OB);
 
@@ -1005,6 +1021,8 @@ class FunctionEncoding final : public Node {
       OB += " requires ";
       Requires->print(OB);
     }
+
+    OB.FunctionInfo.finalizeEnd(OB);
   }
 };
 
@@ -1072,7 +1090,9 @@ struct NestedName : Node {
   void printLeft(OutputBuffer &OB) const override {
     Qual->print(OB);
     OB += "::";
+    OB.FunctionInfo.updateScopeEnd(OB);
     Name->print(OB);
+    OB.FunctionInfo.updateBasenameEnd(OB);
   }
 };
 
@@ -1633,6 +1653,7 @@ struct NameWithTemplateArgs : Node {
 
   void printLeft(OutputBuffer &OB) const override {
     Name->print(OB);
+    OB.FunctionInfo.updateBasenameEnd(OB);
     TemplateArgs->print(OB);
   }
 };
diff --git a/llvm/include/llvm/Demangle/Utility.h 
b/llvm/include/llvm/Demangle/Utility.h
index e893cceea2cdc..4e69c3623b480 100644
--- a/llvm/include/llvm/Demangle/Utility.h
+++ b/llvm/include/llvm/Demangle/Utility.h
@@ -27,6 +27,66 @@
 
 DEMANGLE_NAMESPACE_BEGIN
 
+template <class T> class ScopedOverride {
+  T &Loc;
+  T Original;
+
+public:
+  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
+
+  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
+    Loc_ = std::move(NewVal);
+  }
+  ~ScopedOverride() { Loc = std::move(Original); }
+
+  ScopedOverride(const ScopedOverride &) = delete;
+  ScopedOverride &operator=(const ScopedOverride &) = delete;
+};
+
+class OutputBuffer;
+
+// Stores information about parts of a demangled function name.
+struct FunctionNameInfo {
+  /// A [start, end) pair for the function basename.
+  /// The basename is the name without scope qualifiers
+  /// and without template parameters. E.g.,
+  /// \code{.cpp}
+  ///    void foo::bar<int>::someFunc<float>(int) const &&
+  ///                        ^       ^
+  ///                      Start    End
+  /// \endcode
+  std::pair<size_t, size_t> BasenameLocs;
+
+  /// A [start, end) pair for the function scope qualifiers.
+  /// E.g., for
+  /// \code{.cpp}
+  ///    void foo::bar<int>::qux<float>(int) const &&
+  ///         ^              ^
+  ///       Start           End
+  /// \endcode
+  std::pair<size_t, size_t> ScopeLocs;
+
+  /// Indicates the [start, end) of the function argument lits.
+  /// E.g.,
+  /// \code{.cpp}
+  ///    int (*getFunc<float>(float, double))(int, int)
+  ///                        ^              ^
+  ///                      start           end
+  /// \endcode
+  std::pair<size_t, size_t> ArgumentLocs;
+
+  bool startedPrintingArguments() const;
+  bool shouldTrack(OutputBuffer &OB) const;
+  bool canFinalize(OutputBuffer &OB) const;
+  void updateBasenameEnd(OutputBuffer &OB);
+  void updateScopeStart(OutputBuffer &OB);
+  void updateScopeEnd(OutputBuffer &OB);
+  void finalizeArgumentEnd(OutputBuffer &OB);
+  void finalizeStart(OutputBuffer &OB);
+  void finalizeEnd(OutputBuffer &OB);
+  bool hasBasename() const;
+};
+
 // Stream that AST nodes write their string representation into after the AST
 // has been parsed.
 class OutputBuffer {
@@ -34,6 +94,10 @@ class OutputBuffer {
   size_t CurrentPosition = 0;
   size_t BufferCapacity = 0;
 
+  /// When a function type is being printed this value is incremented.
+  /// When printing of the type is finished the value is decremented.
+  unsigned FunctionPrintingDepth = 0;
+
   // Ensure there are at least N more positions in the buffer.
   void grow(size_t N) {
     size_t Need = N + CurrentPosition;
@@ -92,8 +156,19 @@ class OutputBuffer {
   /// Use a counter so we can simply increment inside parentheses.
   unsigned GtIsGt = 1;
 
+  /// When printing the mangle tree, this object will hold information about
+  /// the function name being printed (if any).
+  FunctionNameInfo FunctionInfo;
+
+  /// Called when we start printing a function type.
+  [[nodiscard]] ScopedOverride<unsigned> enterFunctionTypePrinting();
+
   bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
 
+  bool isPrintingTopLevelFunctionType() const {
+    return FunctionPrintingDepth == 1;
+  }
+
   void printOpen(char Open = '(') {
     GtIsGt++;
     *this += Open;
@@ -182,22 +257,6 @@ class OutputBuffer {
   size_t getBufferCapacity() const { return BufferCapacity; }
 };
 
-template <class T> class ScopedOverride {
-  T &Loc;
-  T Original;
-
-public:
-  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
-
-  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
-    Loc_ = std::move(NewVal);
-  }
-  ~ScopedOverride() { Loc = std::move(Original); }
-
-  ScopedOverride(const ScopedOverride &) = delete;
-  ScopedOverride &operator=(const ScopedOverride &) = delete;
-};
-
 DEMANGLE_NAMESPACE_END
 
 #endif
diff --git a/llvm/lib/Demangle/CMakeLists.txt b/llvm/lib/Demangle/CMakeLists.txt
index eb7d212a02449..0da6f6b89ad54 100644
--- a/llvm/lib/Demangle/CMakeLists.txt
+++ b/llvm/lib/Demangle/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_llvm_component_library(LLVMDemangle
+  Utility.cpp
   Demangle.cpp
   ItaniumDemangle.cpp
   MicrosoftDemangle.cpp
diff --git a/llvm/lib/Demangle/README.txt b/llvm/lib/Demangle/README.txt
new file mode 100644
index 0000000000000..c3f49e57b8d16
--- /dev/null
+++ b/llvm/lib/Demangle/README.txt
@@ -0,0 +1,61 @@
+Itanium Name Demangler Library
+==============================
+
+Introduction
+------------
+
+This directory contains the generic itanium name demangler
+library. The main purpose of the library is to demangle C++ symbols,
+i.e. convert the string "_Z1fv" into "f()". You can also use the CRTP
+base ManglingParser to perform some simple analysis on the mangled
+name, or (in LLVM) use the opaque ItaniumPartialDemangler to query the
+demangled AST.
+
+Why are there multiple copies of the this library in the source tree?
+---------------------------------------------------------------------
+
+The canonical sources are in libcxxabi/src/demangle and some of the
+files are copied to llvm/include/llvm/Demangle.  The simple reason for
+this comes from before the monorepo, and both [sub]projects need to
+demangle symbols, but neither can depend on each other.
+
+* libcxxabi needs the demangler to implement __cxa_demangle, which is
+  part of the itanium ABI spec.
+
+* LLVM needs a copy for a bunch of places, and cannot rely on the
+  system's __cxa_demangle because it a) might not be available (i.e.,
+  on Windows), and b) may not be up-to-date on the latest language
+  features.
+
+The copy of the demangler in LLVM has some extra stuff that aren't
+needed in libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler),
+which depend on the shared generic components. Despite these
+differences, we want to keep the "core" generic demangling library
+identical between both copies to simplify development and testing.
+
+If you're working on the generic library, then do the work first in
+libcxxabi, then run libcxxabi/src/demangle/cp-to-llvm.sh. This
+script takes as an optional argument the path to llvm, and copies the
+changes you made to libcxxabi over.  Note that this script just
+blindly overwrites all changes to the generic library in llvm, so be
+careful.
+
+Because the core demangler needs to work in libcxxabi, everything
+needs to be declared in an anonymous namespace (see
+DEMANGLE_NAMESPACE_BEGIN), and you can't introduce any code that
+depends on the libcxx dylib.
+
+FIXME: Now that LLVM is a monorepo, it should be possible to
+de-duplicate this code, and have both LLVM and libcxxabi depend on a
+shared demangler library.
+
+Testing
+-------
+
+The tests are split up between libcxxabi/test/{unit,}test_demangle.cpp, and
+llvm/unittests/Demangle. The llvm directory should only get tests for stuff not
+included in the core library. In the future though, we should probably move all
+the tests to LLVM.
+
+It is also a really good idea to run libFuzzer after non-trivial changes, see
+libcxxabi/fuzz/cxa_demangle_fuzzer.cpp and 
https://llvm.org/docs/LibFuzzer.html.
diff --git a/llvm/lib/Demangle/Utility.cpp b/llvm/lib/Demangle/Utility.cpp
new file mode 100644
index 0000000000000..1eab251581c9e
--- /dev/null
+++ b/llvm/lib/Demangle/Utility.cpp
@@ -0,0 +1,112 @@
+//===--- Utility.cpp -----------------*- mode:c++;eval:(read-only-mode) 
-*-===//
+//       Do not edit! See README.txt.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Provide some utility classes for use in the demangler.
+// There are two copies of this file in the source tree.  The one in libcxxabi
+// is the original and the one in llvm is the copy.  Use cp-to-llvm.sh to 
update
+// the copy.  See README.txt for more details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Demangle/Utility.h"
+#include "llvm/Demangle/DemangleConfig.h"
+
+DEMANGLE_NAMESPACE_BEGIN
+
+bool FunctionNameInfo::startedPrintingArguments() const {
+  return ArgumentLocs.first > 0;
+}
+
+bool FunctionNameInfo::shouldTrack(OutputBuffer &OB) const {
+  if (!OB.isPrintingTopLevelFunctionType())
+    return false;
+
+  if (OB.isGtInsideTemplateArgs())
+    return false;
+
+  if (startedPrintingArguments())
+    return false;
+
+  return true;
+}
+
+bool FunctionNameInfo::canFinalize(OutputBuffer &OB) const {
+  if (!OB.isPrintingTopLevelFunctionType())
+    return false;
+
+  if (OB.isGtInsideTemplateArgs())
+    return false;
+
+  if (!startedPrintingArguments())
+    return false;
+
+  return true;
+}
+
+void FunctionNameInfo::updateBasenameEnd(OutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  BasenameLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::updateScopeStart(OutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  ScopeLocs.first = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::updateScopeEnd(OutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  ScopeLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::finalizeArgumentEnd(OutputBuffer &OB) {
+  if (!canFinalize(OB))
+    return;
+
+  OB.FunctionInfo.ArgumentLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::finalizeStart(OutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  OB.FunctionInfo.ArgumentLocs.first = OB.getCurrentPosition();
+
+  // If nothing has set the end of the basename yet (for example when
+  // printing templates), then the beginning of the arguments is the end of
+  // the basename.
+  if (BasenameLocs.second == 0)
+    OB.FunctionInfo.BasenameLocs.second = OB.getCurrentPosition();
+
+  DEMANGLE_ASSERT(!shouldTrack(OB), "");
+  DEMANGLE_ASSERT(canFinalize(OB), "");
+}
+
+void FunctionNameInfo::finalizeEnd(OutputBuffer &OB) {
+  if (!canFinalize(OB))
+    return;
+
+  if (ScopeLocs.first > OB.FunctionInfo.ScopeLocs.second)
+    ScopeLocs.second = OB.FunctionInfo.ScopeLocs.first;
+  BasenameLocs.first = OB.FunctionInfo.ScopeLocs.second;
+}
+
+bool FunctionNameInfo::hasBasename() const {
+  return BasenameLocs.first != BasenameLocs.second && BasenameLocs.second > 0;
+}
+
+ScopedOverride<unsigned> OutputBuffer::enterFunctionTypePrinting() {
+  return {FunctionPrintingDepth, FunctionPrintingDepth + 1};
+}
+
+DEMANGLE_NAMESPACE_END
diff --git a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp 
b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp
index bc6ccc2e16e65..8e88f52dbc9b4 100644
--- a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp
+++ b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp
@@ -114,3 +114,115 @@ TEST(ItaniumDemangle, HalfType) {
   ASSERT_NE(nullptr, Parser.parse());
   EXPECT_THAT(Parser.Types, testing::ElementsAre("_Float16", "A", "_Float16"));
 }
+
+struct DemanglingPartsTestCase {
+  const char *mangled;
+  itanium_demangle::FunctionNameInfo expected_info;
+  llvm::StringRef basename;
+  llvm::StringRef scope;
+  bool valid_basename = true;
+};
+
+DemanglingPartsTestCase g_demangling_parts_test_cases[] = {
+    // clang-format off
+  { 
"_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_",
+    { .BasenameLocs = {92, 98}, .ScopeLocs = {36, 92}, .ArgumentLocs = { 108, 
158 } },
+    .basename = "method",
+    .scope = "Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::"
+  },
+  { "_Z7getFuncIfEPFiiiET_",
+    { .BasenameLocs = {6, 13}, .ScopeLocs = {6, 6}, .ArgumentLocs = { 20, 27 } 
},
+    .basename = "getFunc",
+    .scope = ""
+  },
+  { "_ZN1f1b1c1gEv",
+    { .BasenameLocs = {9, 10}, .ScopeLocs = {0, 9}, .ArgumentLocs = { 10, 12 } 
},
+    .basename = "g",
+    .scope = "f::b::c::"
+  },
+  { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_",
+    { .BasenameLocs = {45, 48}, .ScopeLocs = {38, 45}, .ArgumentLocs = { 53, 
58 } },
+    .basename = "fD1",
+    .scope = "test7::"
+  },
+  { 
"_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvE5parseIRA29_KcEESE_OT_NS2_8functionIFbiNS0_6detail13parse_event_tERSE_EEEbb",
+    { .BasenameLocs = {687, 692}, .ScopeLocs = {343, 687}, .ArgumentLocs = { 
713, 1174 } },
+    .basename = "parse",
+    .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, 
std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char>>, bool, long long, unsigned long long, double, 
std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, 
std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
+  },
+  { 
"_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvEC1EDn",
+    { .BasenameLocs = {344, 354}, .ScopeLocs = {0, 344}, .ArgumentLocs = { 
354, 370 } },
+    .basename = "basic_json",
+    .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, 
std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char>>, bool, long long, unsigned long long, double, 
std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, 
std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
+  },
+  { "_Z3fppIiEPFPFvvEiEf",
+    { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
+    .basename = "fpp",
+    .scope = ""
+  },
+  { "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf",
+    { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
+    .basename = "fpp",
+    .scope = ""
+  },
+  { "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf",
+    { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
+    .basename = "fpp",
+    .scope = ""
+  },
+  { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf",
+    { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
+    .basename = "fpp",
+    .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+  },
+  { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef",
+    { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
+    .basename = "fpp",
+    .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+  },
+  { 
"_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvPFS2_S5_EEPFS2_S2_EEf",
+    { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
+    .basename = "fpp",
+    .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+  },
+  { "_ZTV11ImageLoader",
+    { .BasenameLocs = {0, 0}, .ScopeLocs = {0, 0}, .ArgumentLocs = { 0, 0 } },
+    .basename = "",
+    .scope = "",
+    .valid_basename = false
+  }
+    // clang-format on
+};
+
+struct DemanglingPartsTestFixture
+    : public ::testing::TestWithParam<DemanglingPartsTestCase> {};
+
+TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
+  const auto &[mangled, info, basename, scope, valid_basename] = GetParam();
+
+  ManglingParser<TestAllocator> Parser(mangled, mangled + ::strlen(mangled));
+
+  const auto *Root = Parser.parse();
+
+  ASSERT_NE(nullptr, Root);
+
+  OutputBuffer OB;
+  Root->print(OB);
+  auto demangled = toString(OB);
+
+  ASSERT_EQ(OB.FunctionInfo.hasBasename(), valid_basename);
+
+  EXPECT_EQ(OB.FunctionInfo.BasenameLocs, info.BasenameLocs);
+  EXPECT_EQ(OB.FunctionInfo.ScopeLocs, info.ScopeLocs);
+  EXPECT_EQ(OB.FunctionInfo.ArgumentLocs, info.ArgumentLocs);
+
+  auto get_part = [&](const std::pair<size_t, size_t> &loc) {
+    return demangled.substr(loc.first, loc.second - loc.first);
+  };
+
+  EXPECT_EQ(get_part(OB.FunctionInfo.BasenameLocs), basename);
+  EXPECT_EQ(get_part(OB.FunctionInfo.ScopeLocs), scope);
+}
+
+INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture,
+                         ::testing::ValuesIn(g_demangling_parts_test_cases));

>From 46455c5ecfeacbc0022f293d0c47768878baee30 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuc...@gmail.com>
Date: Tue, 1 Apr 2025 15:20:34 +0100
Subject: [PATCH 2/2] fixup! Add location tracking version of OutputBuffer in
 LLDB

---
 libcxxabi/src/demangle/ItaniumDemangle.h      |  81 +++----
 libcxxabi/src/demangle/Utility.cpp            | 112 ---------
 libcxxabi/src/demangle/Utility.h              |  96 ++------
 libcxxabi/src/demangle/cp-to-llvm.sh          |  62 ++---
 lldb/include/lldb/Core/Demangle.h             |  90 +++++++
 lldb/source/Core/CMakeLists.txt               |   1 +
 lldb/source/Core/Demangle.cpp                 | 221 ++++++++++++++++++
 lldb/unittests/Core/MangledTest.cpp           | 143 ++++++++++++
 llvm/include/llvm/Demangle/ItaniumDemangle.h  |  81 +++----
 llvm/include/llvm/Demangle/Utility.h          |  96 ++------
 llvm/lib/Demangle/CMakeLists.txt              |   1 -
 llvm/lib/Demangle/ItaniumDemangle.cpp         |   6 +-
 llvm/lib/Demangle/Utility.cpp                 | 112 ---------
 .../Demangle/ItaniumDemangleTest.cpp          | 112 ---------
 14 files changed, 589 insertions(+), 625 deletions(-)
 delete mode 100644 libcxxabi/src/demangle/Utility.cpp
 create mode 100644 lldb/include/lldb/Core/Demangle.h
 create mode 100644 lldb/source/Core/Demangle.cpp
 delete mode 100644 llvm/lib/Demangle/Utility.cpp

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h 
b/libcxxabi/src/demangle/ItaniumDemangle.h
index b5a0a86b119f4..89a24def830f2 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -281,9 +281,9 @@ class Node {
   }
 
   void print(OutputBuffer &OB) const {
-    printLeft(OB);
+    OB.printLeft(*this);
     if (RHSComponentCache != Cache::No)
-      printRight(OB);
+      OB.printRight(*this);
   }
 
   // Print the "left" side of this Node into OutputBuffer.
@@ -458,11 +458,11 @@ class QualType final : public Node {
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    Child->printLeft(OB);
+    OB.printLeft(*Child);
     printQuals(OB);
   }
 
-  void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
+  void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
 };
 
 class ConversionOperatorType final : public Node {
@@ -491,7 +491,7 @@ class PostfixQualifiedType final : public Node {
   template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Ty->printLeft(OB);
+    OB.printLeft(*Ty);
     OB += Postfix;
   }
 };
@@ -577,7 +577,7 @@ struct AbiTagAttr : Node {
   std::string_view getBaseName() const override { return Base->getBaseName(); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Base->printLeft(OB);
+    OB.printLeft(*Base);
     OB += "[abi:";
     OB += Tag;
     OB += "]";
@@ -644,7 +644,7 @@ class PointerType final : public Node {
     // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
     if (Pointee->getKind() != KObjCProtoName ||
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
-      Pointee->printLeft(OB);
+      OB.printLeft(*Pointee);
       if (Pointee->hasArray(OB))
         OB += " ";
       if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@@ -663,7 +663,7 @@ class PointerType final : public Node {
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
       if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
         OB += ")";
-      Pointee->printRight(OB);
+      OB.printRight(*Pointee);
     }
   }
 };
@@ -729,7 +729,7 @@ class ReferenceType : public Node {
     std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
     if (!Collapsed.second)
       return;
-    Collapsed.second->printLeft(OB);
+    OB.printLeft(*Collapsed.second);
     if (Collapsed.second->hasArray(OB))
       OB += " ";
     if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@@ -746,7 +746,7 @@ class ReferenceType : public Node {
       return;
     if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
       OB += ")";
-    Collapsed.second->printRight(OB);
+    OB.printRight(*Collapsed.second);
   }
 };
 
@@ -766,7 +766,7 @@ class PointerToMemberType final : public Node {
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    MemberType->printLeft(OB);
+    OB.printLeft(*MemberType);
     if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
       OB += "(";
     else
@@ -778,7 +778,7 @@ class PointerToMemberType final : public Node {
   void printRight(OutputBuffer &OB) const override {
     if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
       OB += ")";
-    MemberType->printRight(OB);
+    OB.printRight(*MemberType);
   }
 };
 
@@ -798,7 +798,7 @@ class ArrayType final : public Node {
   bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
   bool hasArraySlow(OutputBuffer &) const override { return true; }
 
-  void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
+  void printLeft(OutputBuffer &OB) const override { OB.printLeft(*Base); }
 
   void printRight(OutputBuffer &OB) const override {
     if (OB.back() != ']')
@@ -807,7 +807,7 @@ class ArrayType final : public Node {
     if (Dimension)
       Dimension->print(OB);
     OB += "]";
-    Base->printRight(OB);
+    OB.printRight(*Base);
   }
 
   bool printInitListAsType(OutputBuffer &OB,
@@ -851,17 +851,15 @@ class FunctionType final : public Node {
   // by printing out the return types's left, then print our parameters, then
   // finally print right of the return type.
   void printLeft(OutputBuffer &OB) const override {
-    auto Scoped = OB.enterFunctionTypePrinting();
-    Ret->printLeft(OB);
+    OB.printLeft(*Ret);
     OB += " ";
   }
 
   void printRight(OutputBuffer &OB) const override {
-    auto Scoped = OB.enterFunctionTypePrinting();
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
-    Ret->printRight(OB);
+    OB.printRight(*Ret);
 
     if (CVQuals & QualConst)
       OB += " const";
@@ -966,6 +964,8 @@ class FunctionEncoding final : public Node {
   FunctionRefQual getRefQual() const { return RefQual; }
   NodeArray getParams() const { return Params; }
   const Node *getReturnType() const { return Ret; }
+  const Node *getAttrs() const { return Attrs; }
+  const Node *getRequires() const { return Requires; }
 
   bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
   bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@@ -973,34 +973,22 @@ class FunctionEncoding final : public Node {
   const Node *getName() const { return Name; }
 
   void printLeft(OutputBuffer &OB) const override {
-    // Nested FunctionEncoding parsing can happen with following productions:
-    // * <local-name>
-    // * <expr-primary>
-    auto Scoped = OB.enterFunctionTypePrinting();
-
     if (Ret) {
-      Ret->printLeft(OB);
+      OB.printLeft(*Ret);
       if (!Ret->hasRHSComponent(OB))
         OB += " ";
     }
 
-    OB.FunctionInfo.updateScopeStart(OB);
-
     Name->print(OB);
   }
 
   void printRight(OutputBuffer &OB) const override {
-    auto Scoped = OB.enterFunctionTypePrinting();
-    OB.FunctionInfo.finalizeStart(OB);
-
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
 
-    OB.FunctionInfo.finalizeArgumentEnd(OB);
-
     if (Ret)
-      Ret->printRight(OB);
+      OB.printRight(*Ret);
 
     if (CVQuals & QualConst)
       OB += " const";
@@ -1021,8 +1009,6 @@ class FunctionEncoding final : public Node {
       OB += " requires ";
       Requires->print(OB);
     }
-
-    OB.FunctionInfo.finalizeEnd(OB);
   }
 };
 
@@ -1090,9 +1076,7 @@ struct NestedName : Node {
   void printLeft(OutputBuffer &OB) const override {
     Qual->print(OB);
     OB += "::";
-    OB.FunctionInfo.updateScopeEnd(OB);
     Name->print(OB);
-    OB.FunctionInfo.updateBasenameEnd(OB);
   }
 };
 
@@ -1344,14 +1328,14 @@ class NonTypeTemplateParamDecl final : public Node {
   template<typename Fn> void match(Fn F) const { F(Name, Type); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Type->printLeft(OB);
+    OB.printLeft(*Type);
     if (!Type->hasRHSComponent(OB))
       OB += " ";
   }
 
   void printRight(OutputBuffer &OB) const override {
     Name->print(OB);
-    Type->printRight(OB);
+    OB.printRight(*Type);
   }
 };
 
@@ -1396,11 +1380,11 @@ class TemplateParamPackDecl final : public Node {
   template<typename Fn> void match(Fn F) const { F(Param); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Param->printLeft(OB);
+    OB.printLeft(*Param);
     OB += "...";
   }
 
-  void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
+  void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
 };
 
 /// An unexpanded parameter pack (either in the expression or type context). If
@@ -1465,13 +1449,13 @@ class ParameterPack final : public Node {
     initializePackExpansion(OB);
     size_t Idx = OB.CurrentPackIndex;
     if (Idx < Data.size())
-      Data[Idx]->printLeft(OB);
+      OB.printLeft(*Data[Idx]);
   }
   void printRight(OutputBuffer &OB) const override {
     initializePackExpansion(OB);
     size_t Idx = OB.CurrentPackIndex;
     if (Idx < Data.size())
-      Data[Idx]->printRight(OB);
+      OB.printRight(*Data[Idx]);
   }
 };
 
@@ -1629,13 +1613,13 @@ struct ForwardTemplateReference : Node {
     if (Printing)
       return;
     ScopedOverride<bool> SavePrinting(Printing, true);
-    Ref->printLeft(OB);
+    OB.printLeft(*Ref);
   }
   void printRight(OutputBuffer &OB) const override {
     if (Printing)
       return;
     ScopedOverride<bool> SavePrinting(Printing, true);
-    Ref->printRight(OB);
+    OB.printRight(*Ref);
   }
 };
 
@@ -1653,7 +1637,6 @@ struct NameWithTemplateArgs : Node {
 
   void printLeft(OutputBuffer &OB) const override {
     Name->print(OB);
-    OB.FunctionInfo.updateBasenameEnd(OB);
     TemplateArgs->print(OB);
   }
 };
@@ -1788,7 +1771,7 @@ class DtorName : public Node {
 
   void printLeft(OutputBuffer &OB) const override {
     OB += "~";
-    Base->printLeft(OB);
+    OB.printLeft(*Base);
   }
 };
 
@@ -2068,7 +2051,7 @@ class CastExpr : public Node {
     {
       ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
       OB += "<";
-      To->printLeft(OB);
+      OB.printLeft(*To);
       OB += ">";
     }
     OB.printOpen();
@@ -6197,6 +6180,10 @@ struct ManglingParser : 
AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
                                Alloc>::AbstractManglingParser;
 };
 
+inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
+
+inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
+
 DEMANGLE_NAMESPACE_END
 
 #if defined(__clang__)
diff --git a/libcxxabi/src/demangle/Utility.cpp 
b/libcxxabi/src/demangle/Utility.cpp
deleted file mode 100644
index 04516082b3443..0000000000000
--- a/libcxxabi/src/demangle/Utility.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-//===--- Utility.cpp 
------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Provide some utility classes for use in the demangler.
-// There are two copies of this file in the source tree.  The one in libcxxabi
-// is the original and the one in llvm is the copy.  Use cp-to-llvm.sh to 
update
-// the copy.  See README.txt for more details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Utility.h"
-#include "DemangleConfig.h"
-
-DEMANGLE_NAMESPACE_BEGIN
-
-bool FunctionNameInfo::startedPrintingArguments() const {
-  return ArgumentLocs.first > 0;
-}
-
-bool FunctionNameInfo::shouldTrack(OutputBuffer &OB) const {
-  if (!OB.isPrintingTopLevelFunctionType())
-    return false;
-
-  if (OB.isGtInsideTemplateArgs())
-    return false;
-
-  if (startedPrintingArguments())
-    return false;
-
-  return true;
-}
-
-bool FunctionNameInfo::canFinalize(OutputBuffer &OB) const {
-  if (!OB.isPrintingTopLevelFunctionType())
-    return false;
-
-  if (OB.isGtInsideTemplateArgs())
-    return false;
-
-  if (!startedPrintingArguments())
-    return false;
-
-  return true;
-}
-
-void FunctionNameInfo::updateBasenameEnd(OutputBuffer &OB) {
-  if (!shouldTrack(OB))
-    return;
-
-  BasenameLocs.second = OB.getCurrentPosition();
-}
-
-void FunctionNameInfo::updateScopeStart(OutputBuffer &OB) {
-  if (!shouldTrack(OB))
-    return;
-
-  ScopeLocs.first = OB.getCurrentPosition();
-}
-
-void FunctionNameInfo::updateScopeEnd(OutputBuffer &OB) {
-  if (!shouldTrack(OB))
-    return;
-
-  ScopeLocs.second = OB.getCurrentPosition();
-}
-
-void FunctionNameInfo::finalizeArgumentEnd(OutputBuffer &OB) {
-  if (!canFinalize(OB))
-    return;
-
-  OB.FunctionInfo.ArgumentLocs.second = OB.getCurrentPosition();
-}
-
-void FunctionNameInfo::finalizeStart(OutputBuffer &OB) {
-  if (!shouldTrack(OB))
-    return;
-
-  OB.FunctionInfo.ArgumentLocs.first = OB.getCurrentPosition();
-
-  // If nothing has set the end of the basename yet (for example when
-  // printing templates), then the beginning of the arguments is the end of
-  // the basename.
-  if (BasenameLocs.second == 0)
-    OB.FunctionInfo.BasenameLocs.second = OB.getCurrentPosition();
-
-  DEMANGLE_ASSERT(!shouldTrack(OB), "");
-  DEMANGLE_ASSERT(canFinalize(OB), "");
-}
-
-void FunctionNameInfo::finalizeEnd(OutputBuffer &OB) {
-  if (!canFinalize(OB))
-    return;
-
-  if (ScopeLocs.first > OB.FunctionInfo.ScopeLocs.second)
-    ScopeLocs.second = OB.FunctionInfo.ScopeLocs.first;
-  BasenameLocs.first = OB.FunctionInfo.ScopeLocs.second;
-}
-
-bool FunctionNameInfo::hasBasename() const {
-  return BasenameLocs.first != BasenameLocs.second && BasenameLocs.second > 0;
-}
-
-ScopedOverride<unsigned> OutputBuffer::enterFunctionTypePrinting() {
-  return {FunctionPrintingDepth, FunctionPrintingDepth + 1};
-}
-
-DEMANGLE_NAMESPACE_END
diff --git a/libcxxabi/src/demangle/Utility.h b/libcxxabi/src/demangle/Utility.h
index 3b9ff8ea1f82b..a38bef762dd57 100644
--- a/libcxxabi/src/demangle/Utility.h
+++ b/libcxxabi/src/demangle/Utility.h
@@ -27,65 +27,7 @@
 
 DEMANGLE_NAMESPACE_BEGIN
 
-template <class T> class ScopedOverride {
-  T &Loc;
-  T Original;
-
-public:
-  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
-
-  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
-    Loc_ = std::move(NewVal);
-  }
-  ~ScopedOverride() { Loc = std::move(Original); }
-
-  ScopedOverride(const ScopedOverride &) = delete;
-  ScopedOverride &operator=(const ScopedOverride &) = delete;
-};
-
-class OutputBuffer;
-
-// Stores information about parts of a demangled function name.
-struct FunctionNameInfo {
-  /// A [start, end) pair for the function basename.
-  /// The basename is the name without scope qualifiers
-  /// and without template parameters. E.g.,
-  /// \code{.cpp}
-  ///    void foo::bar<int>::someFunc<float>(int) const &&
-  ///                        ^       ^
-  ///                      Start    End
-  /// \endcode
-  std::pair<size_t, size_t> BasenameLocs;
-
-  /// A [start, end) pair for the function scope qualifiers.
-  /// E.g., for
-  /// \code{.cpp}
-  ///    void foo::bar<int>::qux<float>(int) const &&
-  ///         ^              ^
-  ///       Start           End
-  /// \endcode
-  std::pair<size_t, size_t> ScopeLocs;
-
-  /// Indicates the [start, end) of the function argument lits.
-  /// E.g.,
-  /// \code{.cpp}
-  ///    int (*getFunc<float>(float, double))(int, int)
-  ///                        ^              ^
-  ///                      start           end
-  /// \endcode
-  std::pair<size_t, size_t> ArgumentLocs;
-
-  bool startedPrintingArguments() const;
-  bool shouldTrack(OutputBuffer &OB) const;
-  bool canFinalize(OutputBuffer &OB) const;
-  void updateBasenameEnd(OutputBuffer &OB);
-  void updateScopeStart(OutputBuffer &OB);
-  void updateScopeEnd(OutputBuffer &OB);
-  void finalizeArgumentEnd(OutputBuffer &OB);
-  void finalizeStart(OutputBuffer &OB);
-  void finalizeEnd(OutputBuffer &OB);
-  bool hasBasename() const;
-};
+class Node;
 
 // Stream that AST nodes write their string representation into after the AST
 // has been parsed.
@@ -94,10 +36,6 @@ class OutputBuffer {
   size_t CurrentPosition = 0;
   size_t BufferCapacity = 0;
 
-  /// When a function type is being printed this value is incremented.
-  /// When printing of the type is finished the value is decremented.
-  unsigned FunctionPrintingDepth = 0;
-
   // Ensure there are at least N more positions in the buffer.
   void grow(size_t N) {
     size_t Need = N + CurrentPosition;
@@ -143,10 +81,15 @@ class OutputBuffer {
   OutputBuffer(const OutputBuffer &) = delete;
   OutputBuffer &operator=(const OutputBuffer &) = delete;
 
+  virtual ~OutputBuffer() {}
+
   operator std::string_view() const {
     return std::string_view(Buffer, CurrentPosition);
   }
 
+  virtual void printLeft(const Node &N);
+  virtual void printRight(const Node &N);
+
   /// If a ParameterPackExpansion (or similar type) is encountered, the offset
   /// into the pack that we're currently printing.
   unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
@@ -156,19 +99,8 @@ class OutputBuffer {
   /// Use a counter so we can simply increment inside parentheses.
   unsigned GtIsGt = 1;
 
-  /// When printing the mangle tree, this object will hold information about
-  /// the function name being printed (if any).
-  FunctionNameInfo FunctionInfo;
-
-  /// Called when we start printing a function type.
-  [[nodiscard]] ScopedOverride<unsigned> enterFunctionTypePrinting();
-
   bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
 
-  bool isPrintingTopLevelFunctionType() const {
-    return FunctionPrintingDepth == 1;
-  }
-
   void printOpen(char Open = '(') {
     GtIsGt++;
     *this += Open;
@@ -257,6 +189,22 @@ class OutputBuffer {
   size_t getBufferCapacity() const { return BufferCapacity; }
 };
 
+template <class T> class ScopedOverride {
+  T &Loc;
+  T Original;
+
+public:
+  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
+
+  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
+    Loc_ = std::move(NewVal);
+  }
+  ~ScopedOverride() { Loc = std::move(Original); }
+
+  ScopedOverride(const ScopedOverride &) = delete;
+  ScopedOverride &operator=(const ScopedOverride &) = delete;
+};
+
 DEMANGLE_NAMESPACE_END
 
 #endif
diff --git a/libcxxabi/src/demangle/cp-to-llvm.sh 
b/libcxxabi/src/demangle/cp-to-llvm.sh
index 4d76a1e110687..f8b3585a5fa37 100755
--- a/libcxxabi/src/demangle/cp-to-llvm.sh
+++ b/libcxxabi/src/demangle/cp-to-llvm.sh
@@ -7,58 +7,30 @@ set -e
 
 cd $(dirname $0)
 HDRS="ItaniumDemangle.h ItaniumNodes.def StringViewExtras.h Utility.h"
-SRCS="Utility.cpp"
-LLVM_DEMANGLE_INCLUDE_DIR=$1
-LLVM_DEMANGLE_SOURCE_DIR=$2
+LLVM_DEMANGLE_DIR=$1
 
-if [[ -z "$LLVM_DEMANGLE_INCLUDE_DIR" ]]; then
-    LLVM_DEMANGLE_INCLUDE_DIR="../../../llvm/include/llvm/Demangle"
+if [[ -z "$LLVM_DEMANGLE_DIR" ]]; then
+    LLVM_DEMANGLE_DIR="../../../llvm/include/llvm/Demangle"
 fi
 
-if [[ -z "$LLVM_DEMANGLE_SOURCE_DIR" ]]; then
-    LLVM_DEMANGLE_SOURCE_DIR="../../../llvm/lib/Demangle"
-fi
-
-if [[ ! -d "$LLVM_DEMANGLE_INCLUDE_DIR" ]]; then
-    echo "No such directory: $LLVM_DEMANGLE_INCLUDE_DIR" >&2
-    exit 1
-fi
-
-if [[ ! -d "$LLVM_DEMANGLE_SOURCE_DIR" ]]; then
-    echo "No such directory: $LLVM_DEMANGLE_SOURCE_DIR" >&2
+if [[ ! -d "$LLVM_DEMANGLE_DIR" ]]; then
+    echo "No such directory: $LLVM_DEMANGLE_DIR" >&2
     exit 1
 fi
 
-read -p "This will overwrite the copies of $HDRS in $LLVM_DEMANGLE_INCLUDE_DIR 
and $SRCS in $LLVM_DEMANGLE_SOURCE_DIR; are you sure? [y/N]" -n 1 -r ANSWER
+read -p "This will overwrite the copies of $HDRS in $LLVM_DEMANGLE_DIR; are 
you sure? [y/N]" -n 1 -r ANSWER
 echo
 
-function copy_files() {
-    local dest_dir=$1
-    local files=$2
-    local adjust_include_paths=$3
-
-    cp -f README.txt $dest_dir
-    chmod -w $dest_dir/README.txt
-    for I in $files ; do
-    rm -f $dest_dir/$I
-    dash=$(echo "$I---------------------------" | cut -c -27 |\
-          sed 's|[^-]*||')
-    sed -e '1s|^//=*-* .*\..* -*.*=*// *$|//===--- '"$I $dash"'-*- 
mode:c++;eval:(read-only-mode) -*-===//|' \
-        -e '2s|^// *$|//       Do not edit! See README.txt.|' \
-        $I >$dest_dir/$I
-
-    if [[ "$adjust_include_paths" = true ]]; then
-        sed -i '' \
-            -e 's|#include "DemangleConfig.h"|#include 
"llvm/Demangle/DemangleConfig.h"|' \
-            -e 's|#include "Utility.h"|#include "llvm/Demangle/Utility.h"|' \
-            $dest_dir/$I
-    fi
-
-    chmod -w $dest_dir/$I
-    done
-}
-
 if [[ $ANSWER =~ ^[Yy]$ ]]; then
-  copy_files $LLVM_DEMANGLE_INCLUDE_DIR "$HDRS" false
-  copy_files $LLVM_DEMANGLE_SOURCE_DIR "$SRCS" true
+    cp -f README.txt $LLVM_DEMANGLE_DIR
+    chmod -w $LLVM_DEMANGLE_DIR/README.txt
+    for I in $HDRS ; do
+       rm -f $LLVM_DEMANGLE_DIR/$I
+       dash=$(echo "$I---------------------------" | cut -c -27 |\
+                  sed 's|[^-]*||')
+       sed -e '1s|^//=*-* .*\..* -*.*=*// *$|//===--- '"$I $dash"'-*- 
mode:c++;eval:(read-only-mode) -*-===//|' \
+           -e '2s|^// *$|//       Do not edit! See README.txt.|' \
+           $I >$LLVM_DEMANGLE_DIR/$I
+       chmod -w $LLVM_DEMANGLE_DIR/$I
+    done
 fi
diff --git a/lldb/include/lldb/Core/Demangle.h 
b/lldb/include/lldb/Core/Demangle.h
new file mode 100644
index 0000000000000..27f0cacbdd48f
--- /dev/null
+++ b/lldb/include/lldb/Core/Demangle.h
@@ -0,0 +1,90 @@
+//===-- Demangle.h ----------------------------------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_CORE_DEMANGLE_H
+#define LLDB_CORE_DEMANGLE_H
+
+#include "llvm/Demangle/ItaniumDemangle.h"
+#include "llvm/Demangle/Utility.h"
+
+#include <cstddef>
+#include <utility>
+
+namespace lldb_private {
+
+struct TrackingOutputBuffer;
+
+// Stores information about parts of a demangled function name.
+struct FunctionNameInfo {
+  /// A [start, end) pair for the function basename.
+  /// The basename is the name without scope qualifiers
+  /// and without template parameters. E.g.,
+  /// \code{.cpp}
+  ///    void foo::bar<int>::someFunc<float>(int) const &&
+  ///                        ^       ^
+  ///                      start    end
+  /// \endcode
+  std::pair<size_t, size_t> BasenameLocs;
+
+  /// A [start, end) pair for the function scope qualifiers.
+  /// E.g., for
+  /// \code{.cpp}
+  ///    void foo::bar<int>::qux<float>(int) const &&
+  ///         ^              ^
+  ///       start           end
+  /// \endcode
+  std::pair<size_t, size_t> ScopeLocs;
+
+  /// Indicates the [start, end) of the function argument lits.
+  /// E.g.,
+  /// \code{.cpp}
+  ///    int (*getFunc<float>(float, double))(int, int)
+  ///                        ^              ^
+  ///                      start           end
+  /// \endcode
+  std::pair<size_t, size_t> ArgumentLocs;
+
+  bool startedPrintingArguments() const;
+  bool shouldTrack(TrackingOutputBuffer &OB) const;
+  bool canFinalize(TrackingOutputBuffer &OB) const;
+  void updateBasenameEnd(TrackingOutputBuffer &OB);
+  void updateScopeStart(TrackingOutputBuffer &OB);
+  void updateScopeEnd(TrackingOutputBuffer &OB);
+  void finalizeArgumentEnd(TrackingOutputBuffer &OB);
+  void finalizeStart(TrackingOutputBuffer &OB);
+  void finalizeEnd(TrackingOutputBuffer &OB);
+  bool hasBasename() const;
+};
+
+struct TrackingOutputBuffer : public llvm::itanium_demangle::OutputBuffer {
+  using OutputBuffer::OutputBuffer;
+
+  FunctionNameInfo FunctionInfo;
+  unsigned FunctionPrintingDepth = 0;
+
+  [[nodiscard]] llvm::itanium_demangle::ScopedOverride<unsigned>
+  enterFunctionTypePrinting();
+
+  bool isPrintingTopLevelFunctionType() const;
+
+  void printLeft(const llvm::itanium_demangle::Node &N) override;
+  void printRight(const llvm::itanium_demangle::Node &N) override;
+
+private:
+  void printLeftImpl(const llvm::itanium_demangle::FunctionType &N);
+  void printRightImpl(const llvm::itanium_demangle::FunctionType &N);
+
+  void printLeftImpl(const llvm::itanium_demangle::FunctionEncoding &N);
+  void printRightImpl(const llvm::itanium_demangle::FunctionEncoding &N);
+
+  void printLeftImpl(const llvm::itanium_demangle::NestedName &N);
+  void printLeftImpl(const llvm::itanium_demangle::NameWithTemplateArgs &N);
+};
+} // namespace lldb_private
+
+#endif // LLDB_CORE_DEMANGLE_H
diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt
index e8bdb0613b3ff..f01686866c75f 100644
--- a/lldb/source/Core/CMakeLists.txt
+++ b/lldb/source/Core/CMakeLists.txt
@@ -28,6 +28,7 @@ add_lldb_library(lldbCore
   Debugger.cpp
   DebuggerEvents.cpp
   Declaration.cpp
+  Demangle.cpp
   Disassembler.cpp
   DumpDataExtractor.cpp
   DumpRegisterValue.cpp
diff --git a/lldb/source/Core/Demangle.cpp b/lldb/source/Core/Demangle.cpp
new file mode 100644
index 0000000000000..122e006409816
--- /dev/null
+++ b/lldb/source/Core/Demangle.cpp
@@ -0,0 +1,221 @@
+//===-- Demangle.cpp 
------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Demangle.h"
+
+using namespace llvm::itanium_demangle;
+
+namespace lldb_private {
+
+bool FunctionNameInfo::startedPrintingArguments() const {
+  return ArgumentLocs.first > 0;
+}
+
+bool FunctionNameInfo::shouldTrack(TrackingOutputBuffer &OB) const {
+  if (!OB.isPrintingTopLevelFunctionType())
+    return false;
+
+  if (OB.isGtInsideTemplateArgs())
+    return false;
+
+  if (startedPrintingArguments())
+    return false;
+
+  return true;
+}
+
+bool FunctionNameInfo::canFinalize(TrackingOutputBuffer &OB) const {
+  if (!OB.isPrintingTopLevelFunctionType())
+    return false;
+
+  if (OB.isGtInsideTemplateArgs())
+    return false;
+
+  if (!startedPrintingArguments())
+    return false;
+
+  return true;
+}
+
+void FunctionNameInfo::updateBasenameEnd(TrackingOutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  BasenameLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::updateScopeStart(TrackingOutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  ScopeLocs.first = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::updateScopeEnd(TrackingOutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  ScopeLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::finalizeArgumentEnd(TrackingOutputBuffer &OB) {
+  if (!canFinalize(OB))
+    return;
+
+  OB.FunctionInfo.ArgumentLocs.second = OB.getCurrentPosition();
+}
+
+void FunctionNameInfo::finalizeStart(TrackingOutputBuffer &OB) {
+  if (!shouldTrack(OB))
+    return;
+
+  OB.FunctionInfo.ArgumentLocs.first = OB.getCurrentPosition();
+
+  // If nothing has set the end of the basename yet (for example when
+  // printing templates), then the beginning of the arguments is the end of
+  // the basename.
+  if (BasenameLocs.second == 0)
+    OB.FunctionInfo.BasenameLocs.second = OB.getCurrentPosition();
+
+  DEMANGLE_ASSERT(!shouldTrack(OB), "");
+  DEMANGLE_ASSERT(canFinalize(OB), "");
+}
+
+void FunctionNameInfo::finalizeEnd(TrackingOutputBuffer &OB) {
+  if (!canFinalize(OB))
+    return;
+
+  if (ScopeLocs.first > OB.FunctionInfo.ScopeLocs.second)
+    ScopeLocs.second = OB.FunctionInfo.ScopeLocs.first;
+  BasenameLocs.first = OB.FunctionInfo.ScopeLocs.second;
+}
+
+bool FunctionNameInfo::hasBasename() const {
+  return BasenameLocs.first != BasenameLocs.second && BasenameLocs.second > 0;
+}
+
+ScopedOverride<unsigned> TrackingOutputBuffer::enterFunctionTypePrinting() {
+  return {FunctionPrintingDepth, FunctionPrintingDepth + 1};
+}
+
+bool TrackingOutputBuffer::isPrintingTopLevelFunctionType() const {
+  return FunctionPrintingDepth == 1;
+}
+
+void TrackingOutputBuffer::printLeft(const Node &N) {
+  switch (N.getKind()) {
+  case Node::KFunctionType:
+    printLeftImpl(static_cast<const FunctionType &>(N));
+    break;
+  case Node::KFunctionEncoding:
+    printLeftImpl(static_cast<const FunctionEncoding &>(N));
+    break;
+  case Node::KNestedName:
+    printLeftImpl(static_cast<const NestedName &>(N));
+    break;
+  case Node::KNameWithTemplateArgs:
+    printLeftImpl(static_cast<const NameWithTemplateArgs &>(N));
+    break;
+  default:
+    N.printLeft(*this);
+  }
+}
+
+void TrackingOutputBuffer::printRight(const Node &N) {
+  switch (N.getKind()) {
+  case Node::KFunctionType:
+    printRightImpl(static_cast<const FunctionType &>(N));
+    break;
+  case Node::KFunctionEncoding:
+    printRightImpl(static_cast<const FunctionEncoding &>(N));
+    break;
+  default:
+    N.printRight(*this);
+  }
+}
+
+void TrackingOutputBuffer::printLeftImpl(const FunctionType &N) {
+  auto Scoped = enterFunctionTypePrinting();
+  N.printLeft(*this);
+}
+
+void TrackingOutputBuffer::printRightImpl(const FunctionType &N) {
+  auto Scoped = enterFunctionTypePrinting();
+  N.printRight(*this);
+}
+
+void TrackingOutputBuffer::printLeftImpl(const FunctionEncoding &N) {
+  auto Scoped = enterFunctionTypePrinting();
+
+  const Node *Ret = N.getReturnType();
+  if (Ret) {
+    printLeft(*Ret);
+    if (!Ret->hasRHSComponent(*this))
+      *this += " ";
+  }
+
+  FunctionInfo.updateScopeStart(*this);
+
+  N.getName()->print(*this);
+}
+
+void TrackingOutputBuffer::printRightImpl(const FunctionEncoding &N) {
+  auto Scoped = enterFunctionTypePrinting();
+  FunctionInfo.finalizeStart(*this);
+
+  printOpen();
+  N.getParams().printWithComma(*this);
+  printClose();
+
+  FunctionInfo.finalizeArgumentEnd(*this);
+
+  const Node *Ret = N.getReturnType();
+
+  if (Ret)
+    printRight(*Ret);
+
+  auto CVQuals = N.getCVQuals();
+  auto RefQual = N.getRefQual();
+  auto *Attrs = N.getAttrs();
+  auto *Requires = N.getRequires();
+
+  if (CVQuals & QualConst)
+    *this += " const";
+  if (CVQuals & QualVolatile)
+    *this += " volatile";
+  if (CVQuals & QualRestrict)
+    *this += " restrict";
+  if (RefQual == FrefQualLValue)
+    *this += " &";
+  else if (RefQual == FrefQualRValue)
+    *this += " &&";
+  if (Attrs != nullptr)
+    Attrs->print(*this);
+  if (Requires != nullptr) {
+    *this += " requires ";
+    Requires->print(*this);
+  }
+
+  FunctionInfo.finalizeEnd(*this);
+}
+
+void TrackingOutputBuffer::printLeftImpl(const NestedName &N) {
+  N.Qual->print(*this);
+  *this += "::";
+  FunctionInfo.updateScopeEnd(*this);
+  N.Name->print(*this);
+  FunctionInfo.updateBasenameEnd(*this);
+}
+
+void TrackingOutputBuffer::printLeftImpl(const NameWithTemplateArgs &N) {
+  N.Name->print(*this);
+  FunctionInfo.updateBasenameEnd(*this);
+  N.TemplateArgs->print(*this);
+}
+
+} // namespace lldb_private
diff --git a/lldb/unittests/Core/MangledTest.cpp 
b/lldb/unittests/Core/MangledTest.cpp
index a3760ba43b3c9..2f4e1755a4074 100644
--- a/lldb/unittests/Core/MangledTest.cpp
+++ b/lldb/unittests/Core/MangledTest.cpp
@@ -11,6 +11,7 @@
 #include "TestingSupport/SubsystemRAII.h"
 #include "TestingSupport/TestUtilities.h"
 
+#include "lldb/Core/Demangle.h"
 #include "lldb/Core/Mangled.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
@@ -319,3 +320,145 @@ TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
   EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeBase));
   EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
 }
+
+struct DemanglingPartsTestCase {
+  const char *mangled;
+  FunctionNameInfo expected_info;
+  std::string_view basename;
+  std::string_view scope;
+  bool valid_basename = true;
+};
+
+DemanglingPartsTestCase g_demangling_parts_test_cases[] = {
+    // clang-format off
+   { 
"_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_",
+     { .BasenameLocs = {92, 98}, .ScopeLocs = {36, 92}, .ArgumentLocs = { 108, 
158 } },
+     .basename = "method",
+     .scope = "Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::"
+   },
+   { "_Z7getFuncIfEPFiiiET_",
+     { .BasenameLocs = {6, 13}, .ScopeLocs = {6, 6}, .ArgumentLocs = { 20, 27 
} },
+     .basename = "getFunc",
+     .scope = ""
+   },
+   { "_ZN1f1b1c1gEv",
+     { .BasenameLocs = {9, 10}, .ScopeLocs = {0, 9}, .ArgumentLocs = { 10, 12 
} },
+     .basename = "g",
+     .scope = "f::b::c::"
+   },
+   { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_",
+     { .BasenameLocs = {45, 48}, .ScopeLocs = {38, 45}, .ArgumentLocs = { 53, 
58 } },
+     .basename = "fD1",
+     .scope = "test7::"
+   },
+   { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
+     { .BasenameLocs = {61, 64}, .ScopeLocs = {54, 61}, .ArgumentLocs = { 69, 
79 } },
+     .basename = "fD1",
+     .scope = "test7::"
+   },
+   { 
"_ZN5test7INDT1cE1dINDT1cE1dEEEE3fD1INDT1cE1dINDT1cE1dEEEEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
+     { .BasenameLocs = {120, 123}, .ScopeLocs = {81, 120}, .ArgumentLocs = { 
155, 168 } },
+     .basename = "fD1",
+     .scope = "test7<decltype(c)::d<decltype(c)::d>>::"
+   },
+   { 
"_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvE5parseIRA29_KcEESE_OT_NS2_8functionIFbiNS0_6detail13parse_event_tERSE_EEEbb",
+     { .BasenameLocs = {687, 692}, .ScopeLocs = {343, 687}, .ArgumentLocs = { 
713, 1174 } },
+     .basename = "parse",
+     .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, 
std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char>>, bool, long long, unsigned long long, double, 
std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, 
std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
+   },
+   { 
"_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvEC1EDn",
+     { .BasenameLocs = {344, 354}, .ScopeLocs = {0, 344}, .ArgumentLocs = { 
354, 370 } },
+     .basename = "basic_json",
+     .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, 
std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char>>, bool, long long, unsigned long long, double, 
std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, 
std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
+   },
+   { "_Z3fppIiEPFPFvvEiEf",
+     { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
+     .basename = "fpp",
+     .scope = ""
+   },
+   { "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf",
+     { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
+     .basename = "fpp",
+     .scope = ""
+   },
+   { "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf",
+     { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
+     .basename = "fpp",
+     .scope = ""
+   },
+   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf",
+     { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
+     .basename = "fpp",
+     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+   },
+   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef",
+     { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
+     .basename = "fpp",
+     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+   },
+   { 
"_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvPFS2_S5_EEPFS2_S2_EEf",
+     { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
+     .basename = "fpp",
+     .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
+   },
+   { "_ZTV11ImageLoader",
+     { .BasenameLocs = {0, 0}, .ScopeLocs = {0, 0}, .ArgumentLocs = { 0, 0 } },
+     .basename = "",
+     .scope = "",
+     .valid_basename = false
+   }
+    // clang-format on
+};
+
+struct DemanglingPartsTestFixture
+    : public ::testing::TestWithParam<DemanglingPartsTestCase> {};
+
+namespace {
+class TestAllocator {
+  llvm::BumpPtrAllocator Alloc;
+
+public:
+  void reset() { Alloc.Reset(); }
+
+  template <typename T, typename... Args> T *makeNode(Args &&...args) {
+    return new (Alloc.Allocate(sizeof(T), alignof(T)))
+        T(std::forward<Args>(args)...);
+  }
+
+  void *allocateNodeArray(size_t sz) {
+    return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
+                          alignof(llvm::itanium_demangle::Node *));
+  }
+};
+} // namespace
+
+TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
+  const auto &[mangled, info, basename, scope, valid_basename] = GetParam();
+
+  llvm::itanium_demangle::ManglingParser<TestAllocator> Parser(
+      mangled, mangled + ::strlen(mangled));
+
+  const auto *Root = Parser.parse();
+
+  ASSERT_NE(nullptr, Root);
+
+  TrackingOutputBuffer OB;
+  Root->print(OB);
+  auto demangled = std::string_view(OB);
+
+  ASSERT_EQ(OB.FunctionInfo.hasBasename(), valid_basename);
+
+  EXPECT_EQ(OB.FunctionInfo.BasenameLocs, info.BasenameLocs);
+  EXPECT_EQ(OB.FunctionInfo.ScopeLocs, info.ScopeLocs);
+  EXPECT_EQ(OB.FunctionInfo.ArgumentLocs, info.ArgumentLocs);
+
+  auto get_part = [&](const std::pair<size_t, size_t> &loc) {
+    return demangled.substr(loc.first, loc.second - loc.first);
+  };
+
+  EXPECT_EQ(get_part(OB.FunctionInfo.BasenameLocs), basename);
+  EXPECT_EQ(get_part(OB.FunctionInfo.ScopeLocs), scope);
+}
+
+INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture,
+                         ::testing::ValuesIn(g_demangling_parts_test_cases));
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h 
b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 2b51be306203d..aab45f351e070 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -281,9 +281,9 @@ class Node {
   }
 
   void print(OutputBuffer &OB) const {
-    printLeft(OB);
+    OB.printLeft(*this);
     if (RHSComponentCache != Cache::No)
-      printRight(OB);
+      OB.printRight(*this);
   }
 
   // Print the "left" side of this Node into OutputBuffer.
@@ -458,11 +458,11 @@ class QualType final : public Node {
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    Child->printLeft(OB);
+    OB.printLeft(*Child);
     printQuals(OB);
   }
 
-  void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
+  void printRight(OutputBuffer &OB) const override { OB.printRight(*Child); }
 };
 
 class ConversionOperatorType final : public Node {
@@ -491,7 +491,7 @@ class PostfixQualifiedType final : public Node {
   template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Ty->printLeft(OB);
+    OB.printLeft(*Ty);
     OB += Postfix;
   }
 };
@@ -577,7 +577,7 @@ struct AbiTagAttr : Node {
   std::string_view getBaseName() const override { return Base->getBaseName(); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Base->printLeft(OB);
+    OB.printLeft(*Base);
     OB += "[abi:";
     OB += Tag;
     OB += "]";
@@ -644,7 +644,7 @@ class PointerType final : public Node {
     // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
     if (Pointee->getKind() != KObjCProtoName ||
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
-      Pointee->printLeft(OB);
+      OB.printLeft(*Pointee);
       if (Pointee->hasArray(OB))
         OB += " ";
       if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
@@ -663,7 +663,7 @@ class PointerType final : public Node {
         !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
       if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
         OB += ")";
-      Pointee->printRight(OB);
+      OB.printRight(*Pointee);
     }
   }
 };
@@ -729,7 +729,7 @@ class ReferenceType : public Node {
     std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
     if (!Collapsed.second)
       return;
-    Collapsed.second->printLeft(OB);
+    OB.printLeft(*Collapsed.second);
     if (Collapsed.second->hasArray(OB))
       OB += " ";
     if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
@@ -746,7 +746,7 @@ class ReferenceType : public Node {
       return;
     if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
       OB += ")";
-    Collapsed.second->printRight(OB);
+    OB.printRight(*Collapsed.second);
   }
 };
 
@@ -766,7 +766,7 @@ class PointerToMemberType final : public Node {
   }
 
   void printLeft(OutputBuffer &OB) const override {
-    MemberType->printLeft(OB);
+    OB.printLeft(*MemberType);
     if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
       OB += "(";
     else
@@ -778,7 +778,7 @@ class PointerToMemberType final : public Node {
   void printRight(OutputBuffer &OB) const override {
     if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
       OB += ")";
-    MemberType->printRight(OB);
+    OB.printRight(*MemberType);
   }
 };
 
@@ -798,7 +798,7 @@ class ArrayType final : public Node {
   bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
   bool hasArraySlow(OutputBuffer &) const override { return true; }
 
-  void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
+  void printLeft(OutputBuffer &OB) const override { OB.printLeft(*Base); }
 
   void printRight(OutputBuffer &OB) const override {
     if (OB.back() != ']')
@@ -807,7 +807,7 @@ class ArrayType final : public Node {
     if (Dimension)
       Dimension->print(OB);
     OB += "]";
-    Base->printRight(OB);
+    OB.printRight(*Base);
   }
 
   bool printInitListAsType(OutputBuffer &OB,
@@ -851,17 +851,15 @@ class FunctionType final : public Node {
   // by printing out the return types's left, then print our parameters, then
   // finally print right of the return type.
   void printLeft(OutputBuffer &OB) const override {
-    auto Scoped = OB.enterFunctionTypePrinting();
-    Ret->printLeft(OB);
+    OB.printLeft(*Ret);
     OB += " ";
   }
 
   void printRight(OutputBuffer &OB) const override {
-    auto Scoped = OB.enterFunctionTypePrinting();
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
-    Ret->printRight(OB);
+    OB.printRight(*Ret);
 
     if (CVQuals & QualConst)
       OB += " const";
@@ -966,6 +964,8 @@ class FunctionEncoding final : public Node {
   FunctionRefQual getRefQual() const { return RefQual; }
   NodeArray getParams() const { return Params; }
   const Node *getReturnType() const { return Ret; }
+  const Node *getAttrs() const { return Attrs; }
+  const Node *getRequires() const { return Requires; }
 
   bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
   bool hasFunctionSlow(OutputBuffer &) const override { return true; }
@@ -973,34 +973,22 @@ class FunctionEncoding final : public Node {
   const Node *getName() const { return Name; }
 
   void printLeft(OutputBuffer &OB) const override {
-    // Nested FunctionEncoding parsing can happen with following productions:
-    // * <local-name>
-    // * <expr-primary>
-    auto Scoped = OB.enterFunctionTypePrinting();
-
     if (Ret) {
-      Ret->printLeft(OB);
+      OB.printLeft(*Ret);
       if (!Ret->hasRHSComponent(OB))
         OB += " ";
     }
 
-    OB.FunctionInfo.updateScopeStart(OB);
-
     Name->print(OB);
   }
 
   void printRight(OutputBuffer &OB) const override {
-    auto Scoped = OB.enterFunctionTypePrinting();
-    OB.FunctionInfo.finalizeStart(OB);
-
     OB.printOpen();
     Params.printWithComma(OB);
     OB.printClose();
 
-    OB.FunctionInfo.finalizeArgumentEnd(OB);
-
     if (Ret)
-      Ret->printRight(OB);
+      OB.printRight(*Ret);
 
     if (CVQuals & QualConst)
       OB += " const";
@@ -1021,8 +1009,6 @@ class FunctionEncoding final : public Node {
       OB += " requires ";
       Requires->print(OB);
     }
-
-    OB.FunctionInfo.finalizeEnd(OB);
   }
 };
 
@@ -1090,9 +1076,7 @@ struct NestedName : Node {
   void printLeft(OutputBuffer &OB) const override {
     Qual->print(OB);
     OB += "::";
-    OB.FunctionInfo.updateScopeEnd(OB);
     Name->print(OB);
-    OB.FunctionInfo.updateBasenameEnd(OB);
   }
 };
 
@@ -1344,14 +1328,14 @@ class NonTypeTemplateParamDecl final : public Node {
   template<typename Fn> void match(Fn F) const { F(Name, Type); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Type->printLeft(OB);
+    OB.printLeft(*Type);
     if (!Type->hasRHSComponent(OB))
       OB += " ";
   }
 
   void printRight(OutputBuffer &OB) const override {
     Name->print(OB);
-    Type->printRight(OB);
+    OB.printRight(*Type);
   }
 };
 
@@ -1396,11 +1380,11 @@ class TemplateParamPackDecl final : public Node {
   template<typename Fn> void match(Fn F) const { F(Param); }
 
   void printLeft(OutputBuffer &OB) const override {
-    Param->printLeft(OB);
+    OB.printLeft(*Param);
     OB += "...";
   }
 
-  void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
+  void printRight(OutputBuffer &OB) const override { OB.printRight(*Param); }
 };
 
 /// An unexpanded parameter pack (either in the expression or type context). If
@@ -1465,13 +1449,13 @@ class ParameterPack final : public Node {
     initializePackExpansion(OB);
     size_t Idx = OB.CurrentPackIndex;
     if (Idx < Data.size())
-      Data[Idx]->printLeft(OB);
+      OB.printLeft(*Data[Idx]);
   }
   void printRight(OutputBuffer &OB) const override {
     initializePackExpansion(OB);
     size_t Idx = OB.CurrentPackIndex;
     if (Idx < Data.size())
-      Data[Idx]->printRight(OB);
+      OB.printRight(*Data[Idx]);
   }
 };
 
@@ -1629,13 +1613,13 @@ struct ForwardTemplateReference : Node {
     if (Printing)
       return;
     ScopedOverride<bool> SavePrinting(Printing, true);
-    Ref->printLeft(OB);
+    OB.printLeft(*Ref);
   }
   void printRight(OutputBuffer &OB) const override {
     if (Printing)
       return;
     ScopedOverride<bool> SavePrinting(Printing, true);
-    Ref->printRight(OB);
+    OB.printRight(*Ref);
   }
 };
 
@@ -1653,7 +1637,6 @@ struct NameWithTemplateArgs : Node {
 
   void printLeft(OutputBuffer &OB) const override {
     Name->print(OB);
-    OB.FunctionInfo.updateBasenameEnd(OB);
     TemplateArgs->print(OB);
   }
 };
@@ -1788,7 +1771,7 @@ class DtorName : public Node {
 
   void printLeft(OutputBuffer &OB) const override {
     OB += "~";
-    Base->printLeft(OB);
+    OB.printLeft(*Base);
   }
 };
 
@@ -2068,7 +2051,7 @@ class CastExpr : public Node {
     {
       ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
       OB += "<";
-      To->printLeft(OB);
+      OB.printLeft(*To);
       OB += ">";
     }
     OB.printOpen();
@@ -6197,6 +6180,10 @@ struct ManglingParser : 
AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
                                Alloc>::AbstractManglingParser;
 };
 
+inline void OutputBuffer::printLeft(const Node &N) { N.printLeft(*this); }
+
+inline void OutputBuffer::printRight(const Node &N) { N.printRight(*this); }
+
 DEMANGLE_NAMESPACE_END
 
 #if defined(__clang__)
diff --git a/llvm/include/llvm/Demangle/Utility.h 
b/llvm/include/llvm/Demangle/Utility.h
index 4e69c3623b480..6a1bf6d0e6b63 100644
--- a/llvm/include/llvm/Demangle/Utility.h
+++ b/llvm/include/llvm/Demangle/Utility.h
@@ -27,65 +27,7 @@
 
 DEMANGLE_NAMESPACE_BEGIN
 
-template <class T> class ScopedOverride {
-  T &Loc;
-  T Original;
-
-public:
-  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
-
-  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
-    Loc_ = std::move(NewVal);
-  }
-  ~ScopedOverride() { Loc = std::move(Original); }
-
-  ScopedOverride(const ScopedOverride &) = delete;
-  ScopedOverride &operator=(const ScopedOverride &) = delete;
-};
-
-class OutputBuffer;
-
-// Stores information about parts of a demangled function name.
-struct FunctionNameInfo {
-  /// A [start, end) pair for the function basename.
-  /// The basename is the name without scope qualifiers
-  /// and without template parameters. E.g.,
-  /// \code{.cpp}
-  ///    void foo::bar<int>::someFunc<float>(int) const &&
-  ///                        ^       ^
-  ///                      Start    End
-  /// \endcode
-  std::pair<size_t, size_t> BasenameLocs;
-
-  /// A [start, end) pair for the function scope qualifiers.
-  /// E.g., for
-  /// \code{.cpp}
-  ///    void foo::bar<int>::qux<float>(int) const &&
-  ///         ^              ^
-  ///       Start           End
-  /// \endcode
-  std::pair<size_t, size_t> ScopeLocs;
-
-  /// Indicates the [start, end) of the function argument lits.
-  /// E.g.,
-  /// \code{.cpp}
-  ///    int (*getFunc<float>(float, double))(int, int)
-  ///                        ^              ^
-  ///                      start           end
-  /// \endcode
-  std::pair<size_t, size_t> ArgumentLocs;
-
-  bool startedPrintingArguments() const;
-  bool shouldTrack(OutputBuffer &OB) const;
-  bool canFinalize(OutputBuffer &OB) const;
-  void updateBasenameEnd(OutputBuffer &OB);
-  void updateScopeStart(OutputBuffer &OB);
-  void updateScopeEnd(OutputBuffer &OB);
-  void finalizeArgumentEnd(OutputBuffer &OB);
-  void finalizeStart(OutputBuffer &OB);
-  void finalizeEnd(OutputBuffer &OB);
-  bool hasBasename() const;
-};
+class Node;
 
 // Stream that AST nodes write their string representation into after the AST
 // has been parsed.
@@ -94,10 +36,6 @@ class OutputBuffer {
   size_t CurrentPosition = 0;
   size_t BufferCapacity = 0;
 
-  /// When a function type is being printed this value is incremented.
-  /// When printing of the type is finished the value is decremented.
-  unsigned FunctionPrintingDepth = 0;
-
   // Ensure there are at least N more positions in the buffer.
   void grow(size_t N) {
     size_t Need = N + CurrentPosition;
@@ -143,10 +81,15 @@ class OutputBuffer {
   OutputBuffer(const OutputBuffer &) = delete;
   OutputBuffer &operator=(const OutputBuffer &) = delete;
 
+  virtual ~OutputBuffer() {}
+
   operator std::string_view() const {
     return std::string_view(Buffer, CurrentPosition);
   }
 
+  virtual void printLeft(const Node &N);
+  virtual void printRight(const Node &N);
+
   /// If a ParameterPackExpansion (or similar type) is encountered, the offset
   /// into the pack that we're currently printing.
   unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
@@ -156,19 +99,8 @@ class OutputBuffer {
   /// Use a counter so we can simply increment inside parentheses.
   unsigned GtIsGt = 1;
 
-  /// When printing the mangle tree, this object will hold information about
-  /// the function name being printed (if any).
-  FunctionNameInfo FunctionInfo;
-
-  /// Called when we start printing a function type.
-  [[nodiscard]] ScopedOverride<unsigned> enterFunctionTypePrinting();
-
   bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
 
-  bool isPrintingTopLevelFunctionType() const {
-    return FunctionPrintingDepth == 1;
-  }
-
   void printOpen(char Open = '(') {
     GtIsGt++;
     *this += Open;
@@ -257,6 +189,22 @@ class OutputBuffer {
   size_t getBufferCapacity() const { return BufferCapacity; }
 };
 
+template <class T> class ScopedOverride {
+  T &Loc;
+  T Original;
+
+public:
+  ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
+
+  ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
+    Loc_ = std::move(NewVal);
+  }
+  ~ScopedOverride() { Loc = std::move(Original); }
+
+  ScopedOverride(const ScopedOverride &) = delete;
+  ScopedOverride &operator=(const ScopedOverride &) = delete;
+};
+
 DEMANGLE_NAMESPACE_END
 
 #endif
diff --git a/llvm/lib/Demangle/CMakeLists.txt b/llvm/lib/Demangle/CMakeLists.txt
index 0da6f6b89ad54..eb7d212a02449 100644
--- a/llvm/lib/Demangle/CMakeLists.txt
+++ b/llvm/lib/Demangle/CMakeLists.txt
@@ -1,5 +1,4 @@
 add_llvm_component_library(LLVMDemangle
-  Utility.cpp
   Demangle.cpp
   ItaniumDemangle.cpp
   MicrosoftDemangle.cpp
diff --git a/llvm/lib/Demangle/ItaniumDemangle.cpp 
b/llvm/lib/Demangle/ItaniumDemangle.cpp
index 5c21b06a1d095..1626f9314e977 100644
--- a/llvm/lib/Demangle/ItaniumDemangle.cpp
+++ b/llvm/lib/Demangle/ItaniumDemangle.cpp
@@ -412,8 +412,12 @@ bool ItaniumPartialDemangler::partialDemangle(const char 
*MangledName) {
   return RootNode == nullptr;
 }
 
+struct TrackingOutputBuffer : public OutputBuffer {
+  using OutputBuffer::OutputBuffer;
+};
+
 static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
-  OutputBuffer OB(Buf, N);
+  TrackingOutputBuffer OB(Buf, N);
   RootNode->print(OB);
   OB += '\0';
   if (N != nullptr)
diff --git a/llvm/lib/Demangle/Utility.cpp b/llvm/lib/Demangle/Utility.cpp
deleted file mode 100644
index 1eab251581c9e..0000000000000
--- a/llvm/lib/Demangle/Utility.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-//===--- Utility.cpp -----------------*- mode:c++;eval:(read-only-mode) 
-*-===//
-//       Do not edit! See README.txt.
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Provide some utility classes for use in the demangler.
-// There are two copies of this file in the source tree.  The one in libcxxabi
-// is the original and the one in llvm is the copy.  Use cp-to-llvm.sh to 
update
-// the copy.  See README.txt for more details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Demangle/Utility.h"
-#include "llvm/Demangle/DemangleConfig.h"
-
-DEMANGLE_NAMESPACE_BEGIN
-
-bool FunctionNameInfo::startedPrintingArguments() const {
-  return ArgumentLocs.first > 0;
-}
-
-bool FunctionNameInfo::shouldTrack(OutputBuffer &OB) const {
-  if (!OB.isPrintingTopLevelFunctionType())
-    return false;
-
-  if (OB.isGtInsideTemplateArgs())
-    return false;
-
-  if (startedPrintingArguments())
-    return false;
-
-  return true;
-}
-
-bool FunctionNameInfo::canFinalize(OutputBuffer &OB) const {
-  if (!OB.isPrintingTopLevelFunctionType())
-    return false;
-
-  if (OB.isGtInsideTemplateArgs())
-    return false;
-
-  if (!startedPrintingArguments())
-    return false;
-
-  return true;
-}
-
-void FunctionNameInfo::updateBasenameEnd(OutputBuffer &OB) {
-  if (!shouldTrack(OB))
-    return;
-
-  BasenameLocs.second = OB.getCurrentPosition();
-}
-
-void FunctionNameInfo::updateScopeStart(OutputBuffer &OB) {
-  if (!shouldTrack(OB))
-    return;
-
-  ScopeLocs.first = OB.getCurrentPosition();
-}
-
-void FunctionNameInfo::updateScopeEnd(OutputBuffer &OB) {
-  if (!shouldTrack(OB))
-    return;
-
-  ScopeLocs.second = OB.getCurrentPosition();
-}
-
-void FunctionNameInfo::finalizeArgumentEnd(OutputBuffer &OB) {
-  if (!canFinalize(OB))
-    return;
-
-  OB.FunctionInfo.ArgumentLocs.second = OB.getCurrentPosition();
-}
-
-void FunctionNameInfo::finalizeStart(OutputBuffer &OB) {
-  if (!shouldTrack(OB))
-    return;
-
-  OB.FunctionInfo.ArgumentLocs.first = OB.getCurrentPosition();
-
-  // If nothing has set the end of the basename yet (for example when
-  // printing templates), then the beginning of the arguments is the end of
-  // the basename.
-  if (BasenameLocs.second == 0)
-    OB.FunctionInfo.BasenameLocs.second = OB.getCurrentPosition();
-
-  DEMANGLE_ASSERT(!shouldTrack(OB), "");
-  DEMANGLE_ASSERT(canFinalize(OB), "");
-}
-
-void FunctionNameInfo::finalizeEnd(OutputBuffer &OB) {
-  if (!canFinalize(OB))
-    return;
-
-  if (ScopeLocs.first > OB.FunctionInfo.ScopeLocs.second)
-    ScopeLocs.second = OB.FunctionInfo.ScopeLocs.first;
-  BasenameLocs.first = OB.FunctionInfo.ScopeLocs.second;
-}
-
-bool FunctionNameInfo::hasBasename() const {
-  return BasenameLocs.first != BasenameLocs.second && BasenameLocs.second > 0;
-}
-
-ScopedOverride<unsigned> OutputBuffer::enterFunctionTypePrinting() {
-  return {FunctionPrintingDepth, FunctionPrintingDepth + 1};
-}
-
-DEMANGLE_NAMESPACE_END
diff --git a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp 
b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp
index 8e88f52dbc9b4..bc6ccc2e16e65 100644
--- a/llvm/unittests/Demangle/ItaniumDemangleTest.cpp
+++ b/llvm/unittests/Demangle/ItaniumDemangleTest.cpp
@@ -114,115 +114,3 @@ TEST(ItaniumDemangle, HalfType) {
   ASSERT_NE(nullptr, Parser.parse());
   EXPECT_THAT(Parser.Types, testing::ElementsAre("_Float16", "A", "_Float16"));
 }
-
-struct DemanglingPartsTestCase {
-  const char *mangled;
-  itanium_demangle::FunctionNameInfo expected_info;
-  llvm::StringRef basename;
-  llvm::StringRef scope;
-  bool valid_basename = true;
-};
-
-DemanglingPartsTestCase g_demangling_parts_test_cases[] = {
-    // clang-format off
-  { 
"_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_",
-    { .BasenameLocs = {92, 98}, .ScopeLocs = {36, 92}, .ArgumentLocs = { 108, 
158 } },
-    .basename = "method",
-    .scope = "Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::"
-  },
-  { "_Z7getFuncIfEPFiiiET_",
-    { .BasenameLocs = {6, 13}, .ScopeLocs = {6, 6}, .ArgumentLocs = { 20, 27 } 
},
-    .basename = "getFunc",
-    .scope = ""
-  },
-  { "_ZN1f1b1c1gEv",
-    { .BasenameLocs = {9, 10}, .ScopeLocs = {0, 9}, .ArgumentLocs = { 10, 12 } 
},
-    .basename = "g",
-    .scope = "f::b::c::"
-  },
-  { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_",
-    { .BasenameLocs = {45, 48}, .ScopeLocs = {38, 45}, .ArgumentLocs = { 53, 
58 } },
-    .basename = "fD1",
-    .scope = "test7::"
-  },
-  { 
"_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvE5parseIRA29_KcEESE_OT_NS2_8functionIFbiNS0_6detail13parse_event_tERSE_EEEbb",
-    { .BasenameLocs = {687, 692}, .ScopeLocs = {343, 687}, .ArgumentLocs = { 
713, 1174 } },
-    .basename = "parse",
-    .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, 
std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char>>, bool, long long, unsigned long long, double, 
std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, 
std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
-  },
-  { 
"_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvEC1EDn",
-    { .BasenameLocs = {344, 354}, .ScopeLocs = {0, 344}, .ArgumentLocs = { 
354, 370 } },
-    .basename = "basic_json",
-    .scope = "nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, 
std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, 
std::__1::allocator<char>>, bool, long long, unsigned long long, double, 
std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, 
std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::"
-  },
-  { "_Z3fppIiEPFPFvvEiEf",
-    { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
-    .basename = "fpp",
-    .scope = ""
-  },
-  { "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf",
-    { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
-    .basename = "fpp",
-    .scope = ""
-  },
-  { "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf",
-    { .BasenameLocs = {10, 13}, .ScopeLocs = {10, 10}, .ArgumentLocs = { 18, 
25 } },
-    .basename = "fpp",
-    .scope = ""
-  },
-  { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf",
-    { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
-    .basename = "fpp",
-    .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
-  },
-  { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef",
-    { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
-    .basename = "fpp",
-    .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
-  },
-  { 
"_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvPFS2_S5_EEPFS2_S2_EEf",
-    { .BasenameLocs = {64, 67}, .ScopeLocs = {10, 64}, .ArgumentLocs = { 72, 
79 } },
-    .basename = "fpp",
-    .scope = "ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::"
-  },
-  { "_ZTV11ImageLoader",
-    { .BasenameLocs = {0, 0}, .ScopeLocs = {0, 0}, .ArgumentLocs = { 0, 0 } },
-    .basename = "",
-    .scope = "",
-    .valid_basename = false
-  }
-    // clang-format on
-};
-
-struct DemanglingPartsTestFixture
-    : public ::testing::TestWithParam<DemanglingPartsTestCase> {};
-
-TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
-  const auto &[mangled, info, basename, scope, valid_basename] = GetParam();
-
-  ManglingParser<TestAllocator> Parser(mangled, mangled + ::strlen(mangled));
-
-  const auto *Root = Parser.parse();
-
-  ASSERT_NE(nullptr, Root);
-
-  OutputBuffer OB;
-  Root->print(OB);
-  auto demangled = toString(OB);
-
-  ASSERT_EQ(OB.FunctionInfo.hasBasename(), valid_basename);
-
-  EXPECT_EQ(OB.FunctionInfo.BasenameLocs, info.BasenameLocs);
-  EXPECT_EQ(OB.FunctionInfo.ScopeLocs, info.ScopeLocs);
-  EXPECT_EQ(OB.FunctionInfo.ArgumentLocs, info.ArgumentLocs);
-
-  auto get_part = [&](const std::pair<size_t, size_t> &loc) {
-    return demangled.substr(loc.first, loc.second - loc.first);
-  };
-
-  EXPECT_EQ(get_part(OB.FunctionInfo.BasenameLocs), basename);
-  EXPECT_EQ(get_part(OB.FunctionInfo.ScopeLocs), scope);
-}
-
-INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture,
-                         ::testing::ValuesIn(g_demangling_parts_test_cases));

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to