[Lldb-commits] [lldb] [lldb] Support new libc++ __compressed_pair layout (PR #96538)

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Thu Jul 4 14:46:09 PDT 2024


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

>From 0d39f1ecfb9643f944aa1352d4a307e5638ab08f Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 29 Jan 2024 16:23:16 +0000
Subject: [PATCH 1/2] [lldb] Support new libc++ __compressed_pair layout

This patch is in preparation for the `__compressed_pair`
refactor in https://github.com/llvm/llvm-project/pull/76756.

This gets the formatter tests to at least pass.

Currently in draft because there's still some cleanup to be done.
---
 lldb/examples/synthetic/libcxx.py             | 26 ++++--
 .../Plugins/Language/CPlusPlus/LibCxx.cpp     | 61 ++++++++++----
 .../Plugins/Language/CPlusPlus/LibCxxList.cpp | 83 ++++++++++++-------
 .../Plugins/Language/CPlusPlus/LibCxxMap.cpp  | 68 +++++++++++----
 .../Language/CPlusPlus/LibCxxUnorderedMap.cpp | 62 +++++++++-----
 .../Language/CPlusPlus/LibCxxVector.cpp       | 40 +++++----
 .../list/TestDataFormatterGenericList.py      |  3 +-
 .../libcxx/string/simulator/main.cpp          |  1 +
 .../TestDataFormatterLibcxxUniquePtr.py       |  7 +-
 9 files changed, 246 insertions(+), 105 deletions(-)

diff --git a/lldb/examples/synthetic/libcxx.py b/lldb/examples/synthetic/libcxx.py
index 474aaa428fa23a..060ff901008497 100644
--- a/lldb/examples/synthetic/libcxx.py
+++ b/lldb/examples/synthetic/libcxx.py
@@ -721,6 +721,12 @@ def _get_value_of_compressed_pair(self, pair):
     def update(self):
         logger = lldb.formatters.Logger.Logger()
         try:
+            has_compressed_pair_layout = True
+            alloc_valobj = self.valobj.GetChildMemberWithName("__alloc_")
+            size_valobj = self.valobj.GetChildMemberWithName("__size_")
+            if alloc_valobj.IsValid() and size_valobj.IsValid():
+                has_compressed_pair_layout = False
+
             # A deque is effectively a two-dim array, with fixed width.
             # 'map' contains pointers to the rows of this array. The
             # full memory area allocated by the deque is delimited
@@ -734,9 +740,13 @@ def update(self):
             # variable tells which element in this NxM array is the 0th
             # one, and the 'size' element gives the number of elements
             # in the deque.
-            count = self._get_value_of_compressed_pair(
-                self.valobj.GetChildMemberWithName("__size_")
-            )
+            if has_compressed_pair_layout:
+                count = self._get_value_of_compressed_pair(
+                    self.valobj.GetChildMemberWithName("__size_")
+                )
+            else:
+                count = size_valobj.GetValueAsUnsigned(0)
+
             # give up now if we cant access memory reliably
             if self.block_size < 0:
                 logger.write("block_size < 0")
@@ -748,9 +758,13 @@ def update(self):
             self.map_begin = map_.GetChildMemberWithName("__begin_")
             map_begin = self.map_begin.GetValueAsUnsigned(0)
             map_end = map_.GetChildMemberWithName("__end_").GetValueAsUnsigned(0)
-            map_endcap = self._get_value_of_compressed_pair(
-                map_.GetChildMemberWithName("__end_cap_")
-            )
+
+            if has_compressed_pair_layout:
+                map_endcap = self._get_value_of_compressed_pair(
+                    map_.GetChildMemberWithName("__end_cap_")
+                )
+            else:
+                map_endcap = map_.GetChildMemberWithName("__end_cap_").GetValueAsUnsigned(0)
 
             # check consistency
             if not map_first <= map_begin <= map_end <= map_endcap:
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index 0f9f93b727ce86..1eee1d9cec7e82 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -27,6 +27,7 @@
 #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
 #include <optional>
 #include <tuple>
 
@@ -176,9 +177,9 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
   if (!ptr_sp)
     return false;
 
-  ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
-  if (!ptr_sp)
-    return false;
+  if (ValueObjectSP compressed_pair_value__sp =
+          GetFirstValueOfLibCXXCompressedPair(*ptr_sp))
+    ptr_sp = std::move(compressed_pair_value__sp);
 
   if (ptr_sp->GetValueAsUnsigned(0) == 0) {
     stream.Printf("nullptr");
@@ -701,15 +702,28 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
   if (!ptr_sp)
     return lldb::ChildCacheState::eRefetch;
 
+  bool has_compressed_pair_layout = true;
+  ValueObjectSP deleter_sp(valobj_sp->GetChildMemberWithName("__deleter_"));
+  if (deleter_sp)
+    has_compressed_pair_layout = false;
+
   // Retrieve the actual pointer and the deleter, and clone them to give them
   // user-friendly names.
-  ValueObjectSP value_pointer_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
-  if (value_pointer_sp)
-    m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
-
-  ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);
-  if (deleter_sp)
+  if (has_compressed_pair_layout) {
+    ValueObjectSP value_pointer_sp =
+        GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
+    if (value_pointer_sp)
+      m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
+
+    ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);
+    if (deleter_sp)
+      m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
+  } else {
+    // TODO: with the new layout, deleter is always a member, so empty deleters
+    // will be displayed
+    m_value_ptr_sp = ptr_sp->Clone(ConstString("pointer"));
     m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
+  }
 
   return lldb::ChildCacheState::eRefetch;
 }
@@ -747,11 +761,7 @@ namespace {
 enum class StringLayout { CSD, DSC };
 }
 
-/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
-/// extract its data payload. Return the size + payload pair.
-// TODO: Support big-endian architectures.
-static std::optional<std::pair<uint64_t, ValueObjectSP>>
-ExtractLibcxxStringInfo(ValueObject &valobj) {
+static ValueObjectSP ExtractLibCxxStringDataV1(ValueObject &valobj) {
   ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
   if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
     return {};
@@ -767,6 +777,29 @@ ExtractLibcxxStringInfo(ValueObject &valobj) {
   if (!valobj_rep_sp)
     return {};
 
+  return valobj_rep_sp;
+}
+
+static ValueObjectSP ExtractLibCxxStringDataV2(ValueObject &valobj) {
+  return valobj.GetChildMemberWithName("__rep_");
+}
+
+static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {
+  if (ValueObjectSP ret = ExtractLibCxxStringDataV1(valobj))
+    return ret;
+
+  return ExtractLibCxxStringDataV2(valobj);
+}
+
+/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
+/// extract its data payload. Return the size + payload pair.
+// TODO: Support big-endian architectures.
+static std::optional<std::pair<uint64_t, ValueObjectSP>>
+ExtractLibcxxStringInfo(ValueObject &valobj) {
+  ValueObjectSP valobj_rep_sp = ExtractLibCxxStringData(valobj);
+  if (!valobj_rep_sp || !valobj_rep_sp->GetError().Success())
+    return {};
+
   ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName("__l");
   if (!l)
     return {};
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
index d7cfeb30557c36..0013ccb1bab60b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
@@ -17,6 +17,7 @@
 #include "lldb/Utility/Endian.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/Stream.h"
+#include "lldb/lldb-enumerations.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -294,12 +295,19 @@ lldb::ChildCacheState ForwardListFrontEnd::Update() {
 
   ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_"));
   if (!impl_sp)
-    return lldb::ChildCacheState::eRefetch;
-  impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
-  if (!impl_sp)
-    return lldb::ChildCacheState::eRefetch;
+    return ChildCacheState::eRefetch;
+
   m_head = impl_sp->GetChildMemberWithName("__next_").get();
-  return lldb::ChildCacheState::eRefetch;
+
+  // TODO: we have to do this in this order because __before_begin_ has a
+  // __value_ member, as does compressed_pair. Is this a problem elsewhere too?
+  if (!m_head) {
+    impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
+    if (impl_sp)
+      m_head = impl_sp->GetChildMemberWithName("__next_").get();
+  }
+
+  return ChildCacheState::eRefetch;
 }
 
 ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp)
@@ -313,34 +321,49 @@ llvm::Expected<uint32_t> ListFrontEnd::CalculateNumChildren() {
     return m_count;
   if (!m_head || !m_tail || m_node_address == 0)
     return 0;
-  ValueObjectSP size_alloc(m_backend.GetChildMemberWithName("__size_alloc_"));
-  if (size_alloc) {
-    ValueObjectSP value = GetFirstValueOfLibCXXCompressedPair(*size_alloc);
-    if (value) {
-      m_count = value->GetValueAsUnsigned(UINT32_MAX);
-    }
+
+  bool has_compressed_pair_layout = false;
+  // ValueObjectSP
+  // node_alloc(m_backend.GetChildMemberWithName("__node_alloc_")); if
+  // (!node_alloc)
+  //   has_compressed_pair_layout = true;
+
+  ValueObjectSP size_node(m_backend.GetChildMemberWithName("__size_"));
+  if (!size_node) {
+    size_node = m_backend.GetChildMemberWithName(
+        "__size_alloc_"); // pre-compressed_pair rework
+    if (size_node)
+      has_compressed_pair_layout = true;
   }
-  if (m_count != UINT32_MAX) {
+
+  if (size_node) {
+    if (has_compressed_pair_layout)
+      if (ValueObjectSP value = GetFirstValueOfLibCXXCompressedPair(*size_node))
+        size_node = std::move(value);
+
+    m_count = size_node->GetValueAsUnsigned(UINT32_MAX);
+  }
+
+  if (m_count != UINT32_MAX)
     return m_count;
-  } else {
-    uint64_t next_val = m_head->GetValueAsUnsigned(0);
-    uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
-    if (next_val == 0 || prev_val == 0)
-      return 0;
-    if (next_val == m_node_address)
-      return 0;
-    if (next_val == prev_val)
-      return 1;
-    uint64_t size = 2;
-    ListEntry current(m_head);
-    while (current.next() && current.next().value() != m_node_address) {
-      size++;
-      current = current.next();
-      if (size > m_list_capping_size)
-        break;
-    }
-    return m_count = (size - 1);
+
+  uint64_t next_val = m_head->GetValueAsUnsigned(0);
+  uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
+  if (next_val == 0 || prev_val == 0)
+    return 0;
+  if (next_val == m_node_address)
+    return 0;
+  if (next_val == prev_val)
+    return 1;
+  uint64_t size = 2;
+  ListEntry current(m_head);
+  while (current.next() && current.next().value() != m_node_address) {
+    size++;
+    current = current.next();
+    if (size > m_list_capping_size)
+      break;
   }
+  return m_count = (size - 1);
 }
 
 lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(uint32_t idx) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
index 6c2bc1a34137ab..d3069e35aad7ec 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -181,6 +181,9 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
   size_t GetIndexOfChildWithName(ConstString name) override;
 
 private:
+  size_t CalculateNumChildrenV1();
+  size_t CalculateNumChildrenV2();
+
   bool GetDataType();
 
   void GetValueOffset(const lldb::ValueObjectSP &node);
@@ -207,6 +210,7 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
   uint32_t m_skip_size = UINT32_MAX;
   size_t m_count = UINT32_MAX;
   std::map<size_t, MapIterator> m_iterators;
+  bool m_has_compressed_pair_layout = false;
 };
 } // namespace formatters
 } // namespace lldb_private
@@ -218,6 +222,31 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
     Update();
 }
 
+size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
+    CalculateNumChildrenV2() {
+  ValueObjectSP node(m_tree->GetChildMemberWithName("__size_"));
+  if (!node)
+    return 0;
+
+  m_count = node->GetValueAsUnsigned(0);
+  return m_count;
+}
+
+size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
+    CalculateNumChildrenV1() {
+  ValueObjectSP node(m_tree->GetChildMemberWithName("__pair3_"));
+  if (!node)
+    return 0;
+
+  node = formatters::GetFirstValueOfLibCXXCompressedPair(*node);
+
+  if (!node)
+    return 0;
+
+  m_count = node->GetValueAsUnsigned(0);
+  return m_count;
+}
+
 llvm::Expected<uint32_t> lldb_private::formatters::
     LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren() {
   if (m_count != UINT32_MAX)
@@ -226,17 +255,10 @@ llvm::Expected<uint32_t> lldb_private::formatters::
   if (m_tree == nullptr)
     return 0;
 
-  ValueObjectSP size_node(m_tree->GetChildMemberWithName("__pair3_"));
-  if (!size_node)
-    return 0;
+  if (m_has_compressed_pair_layout)
+    return CalculateNumChildrenV1();
 
-  size_node = GetFirstValueOfLibCXXCompressedPair(*size_node);
-
-  if (!size_node)
-    return 0;
-
-  m_count = size_node->GetValueAsUnsigned(0);
-  return m_count;
+  return CalculateNumChildrenV2();
 }
 
 bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() {
@@ -253,12 +275,22 @@ bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() {
     m_element_type = deref->GetCompilerType();
     return true;
   }
-  deref = m_backend.GetChildAtNamePath({"__tree_", "__pair3_"});
-  if (!deref)
-    return false;
-  m_element_type = deref->GetCompilerType()
-                       .GetTypeTemplateArgument(1)
-                       .GetTypeTemplateArgument(1);
+
+  if (m_has_compressed_pair_layout) {
+    deref = m_backend.GetChildAtNamePath({"__tree_", "__pair3_"});
+
+    if (!deref)
+      return false;
+    m_element_type = deref->GetCompilerType()
+                         .GetTypeTemplateArgument(1)
+                         .GetTypeTemplateArgument(1);
+  } else {
+    deref = m_backend.GetChildAtNamePath({"__tree_", "__value_comp_"});
+    if (!deref)
+      return false;
+    m_element_type = deref->GetCompilerType().GetTypeTemplateArgument(1);
+  }
+
   if (m_element_type) {
     std::string name;
     uint64_t bit_offset_ptr;
@@ -437,6 +469,10 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
   m_tree = m_backend.GetChildMemberWithName("__tree_").get();
   if (!m_tree)
     return lldb::ChildCacheState::eRefetch;
+
+  m_has_compressed_pair_layout =
+      m_tree->GetChildMemberWithName("__pair1_") != nullptr;
+
   m_root_node = m_tree->GetChildMemberWithName("__begin_node_").get();
   return lldb::ChildCacheState::eRefetch;
 }
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index af29fdb6d00109..0ab7e1afffaa7b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -18,6 +18,7 @@
 #include "lldb/Utility/Endian.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/Stream.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/StringRef.h"
 
 using namespace lldb;
@@ -112,19 +113,29 @@ lldb::ValueObjectSP lldb_private::formatters::
     ValueObjectSP hash_sp = node_sp->GetChildMemberWithName("__hash_");
     if (!hash_sp || !value_sp) {
       if (!m_element_type) {
+        auto compressed_pair_layout_getter = [this](ValueObject &node) {
+          m_element_type = node.GetCompilerType();
+          m_element_type = m_element_type.GetTypeTemplateArgument(0);
+          m_element_type = m_element_type.GetPointeeType();
+          m_node_type = m_element_type;
+          m_element_type = m_element_type.GetTypeTemplateArgument(0);
+
+          return true;
+        };
+
         auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
-        if (!p1_sp)
-          return nullptr;
+        if (p1_sp) {
+          ValueObjectSP first_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
 
-        ValueObjectSP first_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
-        if (!first_sp)
-          return nullptr;
+          if (!first_sp)
+            return {};
+
+          compressed_pair_layout_getter(*p1_sp);
+        } else {
+          p1_sp = m_backend.GetChildAtNamePath({"__table_", "__first_node_"});
+          compressed_pair_layout_getter(*p1_sp);
+        }
 
-        m_element_type = first_sp->GetCompilerType();
-        m_element_type = m_element_type.GetTypeTemplateArgument(0);
-        m_element_type = m_element_type.GetPointeeType();
-        m_node_type = m_element_type;
-        m_element_type = m_element_type.GetTypeTemplateArgument(0);
         // This synthetic provider is used for both unordered_(multi)map and
         // unordered_(multi)set. For unordered_map, the element type has an
         // additional type layer, an internal struct (`__hash_value_type`)
@@ -202,24 +213,35 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() {
   if (!table_sp)
     return lldb::ChildCacheState::eRefetch;
 
+  bool has_compressed_pair_layout = true;
+  ValueObjectSP p1_sp = table_sp->GetChildMemberWithName("__p1_");
   ValueObjectSP p2_sp = table_sp->GetChildMemberWithName("__p2_");
-  if (!p2_sp)
-    return lldb::ChildCacheState::eRefetch;
+  if (!p1_sp || !p2_sp) {
+    has_compressed_pair_layout = false;
+  }
+
+  ValueObjectSP num_elements_sp = nullptr;
+  if (has_compressed_pair_layout) {
+    num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
+  } else {
+    num_elements_sp = table_sp->GetChildMemberWithName("__size_");
+  }
 
-  ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
   if (!num_elements_sp)
     return lldb::ChildCacheState::eRefetch;
 
-  ValueObjectSP p1_sp = table_sp->GetChildMemberWithName("__p1_");
-  if (!p1_sp)
-    return lldb::ChildCacheState::eRefetch;
+  ValueObjectSP tree_sp = nullptr;
+  if (has_compressed_pair_layout) {
+    tree_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
+  } else {
+    tree_sp = table_sp->GetChildMemberWithName("__first_node_");
+  }
 
-  ValueObjectSP value_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
-  if (!value_sp)
+  if (!tree_sp)
     return lldb::ChildCacheState::eRefetch;
 
-  m_tree = value_sp->GetChildMemberWithName("__next_").get();
-  if (m_tree == nullptr)
+  m_tree = tree_sp->GetChildMemberWithName("__next_").get();
+  if (!m_tree)
     return lldb::ChildCacheState::eRefetch;
 
   m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index 461fed35164b4d..dde23a78b42023 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -11,6 +11,8 @@
 #include "lldb/Core/ValueObject.h"
 #include "lldb/DataFormatters/FormattersHelpers.h"
 #include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
 #include <optional>
 
 using namespace lldb;
@@ -116,16 +118,31 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
                                       m_element_type);
 }
 
+static ValueObjectSP ExtractDataTypeFinderV1(ValueObject &valobj) {
+  ValueObjectSP data_type_finder_sp(
+      valobj.GetChildMemberWithName("__end_cap_"));
+  if (!data_type_finder_sp)
+    return {};
+
+  return GetFirstValueOfLibCXXCompressedPair(*data_type_finder_sp);
+}
+
+static ValueObjectSP ExtractDataTypeFinderV2(ValueObject &valobj) {
+  return valobj.GetChildMemberWithName("__cap_");
+}
+
+static ValueObjectSP ExtractDataTypeFinder(ValueObject &valobj) {
+  if (auto ret = ExtractDataTypeFinderV1(valobj))
+    return ret;
+
+  return ExtractDataTypeFinderV2(valobj);
+}
+
 lldb::ChildCacheState
 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() {
   m_start = m_finish = nullptr;
-  ValueObjectSP data_type_finder_sp(
-      m_backend.GetChildMemberWithName("__end_cap_"));
-  if (!data_type_finder_sp)
-    return lldb::ChildCacheState::eRefetch;
+  ValueObjectSP data_type_finder_sp(ExtractDataTypeFinder(m_backend));
 
-  data_type_finder_sp =
-      GetFirstValueOfLibCXXCompressedPair(*data_type_finder_sp);
   if (!data_type_finder_sp)
     return lldb::ChildCacheState::eRefetch;
 
@@ -216,17 +233,6 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex(
   return retval_sp;
 }
 
-/*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
- __begin_ = 0x00000001001000e0
- __size_ = 56
- __cap_alloc_ = {
- std::__1::__libcpp_compressed_pair_imp<unsigned long,
- std::__1::allocator<unsigned long> > = {
- __first_ = 1
- }
- }
- }*/
-
 lldb::ChildCacheState
 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() {
   m_children.clear();
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
index 270aab1b75122f..af6183766301e6 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
@@ -62,7 +62,8 @@ def cleanup():
         self.expect(
             "frame variable numbers_list --raw",
             matching=False,
-            substrs=["size=0", "{}"],
+            #substrs=["size=0", "{}"], # TODO: if __padding_ members aren't added this isn't needed
+            substrs=["size=0"]
         )
 
         if stdlib_type == USE_LIBSTDCPP:
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp
index 33e71044482a75..6d4200e19c2469 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp
@@ -212,6 +212,7 @@ template <class _CharT, class _Traits, class _Allocator> class basic_string {
     };
   };
 
+  // TODO: support the new non-compressed_pair layout
   __compressed_pair<__rep, allocator_type> __r_;
 
 public:
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
index 6a726e0253482a..153c507a45b875 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
@@ -45,6 +45,7 @@ def test_unique_ptr_variables(self):
             "up_empty",
             type=self.make_expected_type("int"),
             summary="nullptr",
+            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
             children=[ValueCheck(name="pointer")],
         )
         self.assertEqual(
@@ -59,6 +60,7 @@ def test_unique_ptr_variables(self):
             "up_int",
             type=self.make_expected_type("int"),
             summary="10",
+            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
             children=[ValueCheck(name="pointer")],
         )
         self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -67,6 +69,7 @@ def test_unique_ptr_variables(self):
             "up_int_ref",
             type=self.make_expected_type("int", qualifiers="&"),
             summary="10",
+            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
             children=[ValueCheck(name="pointer")],
         )
         self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -75,6 +78,7 @@ def test_unique_ptr_variables(self):
             "up_int_ref_ref",
             type=self.make_expected_type("int", qualifiers="&&"),
             summary="10",
+            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
             children=[ValueCheck(name="pointer")],
         )
         self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -83,7 +87,8 @@ def test_unique_ptr_variables(self):
             "up_str",
             type=self.make_expected_basic_string_ptr(),
             summary='"hello"',
-            children=[ValueCheck(name="pointer", summary='"hello"')],
+            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
+            children=[ValueCheck(name="pointer")],
         )
 
         valobj = self.expect_var_path("up_user", type=self.make_expected_type("User"))

>From 2822172a27a5d41ef3335f7438cb894490d56ecd Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 4 Jul 2024 22:45:49 +0100
Subject: [PATCH 2/2] fixup! fix libc++ unique_ptr formatter

---
 lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp            | 5 ++---
 .../libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py    | 5 -----
 2 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index 1eee1d9cec7e82..e68cdab545f403 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -719,10 +719,9 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
     if (deleter_sp)
       m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
   } else {
-    // TODO: with the new layout, deleter is always a member, so empty deleters
-    // will be displayed
     m_value_ptr_sp = ptr_sp->Clone(ConstString("pointer"));
-    m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
+    if (deleter_sp->GetNumChildrenIgnoringErrors() > 0)
+      m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
   }
 
   return lldb::ChildCacheState::eRefetch;
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
index 153c507a45b875..4aad9221fcf151 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
@@ -45,7 +45,6 @@ def test_unique_ptr_variables(self):
             "up_empty",
             type=self.make_expected_type("int"),
             summary="nullptr",
-            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
             children=[ValueCheck(name="pointer")],
         )
         self.assertEqual(
@@ -60,7 +59,6 @@ def test_unique_ptr_variables(self):
             "up_int",
             type=self.make_expected_type("int"),
             summary="10",
-            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
             children=[ValueCheck(name="pointer")],
         )
         self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -69,7 +67,6 @@ def test_unique_ptr_variables(self):
             "up_int_ref",
             type=self.make_expected_type("int", qualifiers="&"),
             summary="10",
-            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
             children=[ValueCheck(name="pointer")],
         )
         self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -78,7 +75,6 @@ def test_unique_ptr_variables(self):
             "up_int_ref_ref",
             type=self.make_expected_type("int", qualifiers="&&"),
             summary="10",
-            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
             children=[ValueCheck(name="pointer")],
         )
         self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -87,7 +83,6 @@ def test_unique_ptr_variables(self):
             "up_str",
             type=self.make_expected_basic_string_ptr(),
             summary='"hello"',
-            #children=[ValueCheck(name="pointer"), ValueCheck(name="deleter")], # TODO: shouldn't be printing deleter
             children=[ValueCheck(name="pointer")],
         )
 



More information about the lldb-commits mailing list