[Lldb-commits] [lldb] fd0ecac - [lldb] Surface GetIndexOfChildWithName errors instead of dropping them (#224059)

via lldb-commits lldb-commits at lists.llvm.org
Thu Sep 17 08:57:16 PDT 2026


Author: Charles Zablit
Date: 2026-09-17T16:57:10+01:00
New Revision: fd0ecaccdc131ae3e541be4d1eb83d85758bf104

URL: https://github.com/llvm/llvm-project/commit/fd0ecaccdc131ae3e541be4d1eb83d85758bf104
DIFF: https://github.com/llvm/llvm-project/commit/fd0ecaccdc131ae3e541be4d1eb83d85758bf104.diff

LOG: [lldb] Surface GetIndexOfChildWithName errors instead of dropping them (#224059)

`ValueObjectSynthetic::GetChildMemberWithName` and
`SBValue::GetIndexOfChildWithName` called `llvm::consumeError` on the
`llvm::Expected` returned by `GetIndexOfChildWithName` and reported the
failure as a null `ValueObjectSP` / `UINT32_MAX`, so the reason a lookup
failed never reached anyone. Log them instead: `LLDBLog::DataFormatters`
from ValueObject and formatter code, `LLDBLog::API` at the SB boundary.
That is the convention `BlockPointer.cpp` and `LibCxx.cpp` already
follow.

Also, in `ValueObjectSynthetic::GetIndexOfChildWithName`:

- A front-end with `TypeOptions::eTypeOptionCustomSubscripting` that
failed to find the child left `index` at its `SIZE_MAX` initializer,
dropped the front-end's error unread, then cached `SIZE_MAX` in
`m_name_toindex` and returned it as a valid index. Return the
front-end's error instead.
- Call `GetNumChildren(max)` rather than
`GetNumChildrenIgnoringErrors(max)` for the `"[N]"` subscript bounds
check and propagate the error, so a child count that fails to compute is
no longer reported as a subscript that is out of range.
- Return early on a cache hit rather than falling through a chain of
else-if branches that retested `found_index`.

Lower-cases the two `"Type has no child named"` messages in
`TypeSynthetic.h` for consistency with every other instance of that
string.

Follow-up to the review on #136693.

rdar://150281004
rdar://150281080

Added: 
    

Modified: 
    lldb/include/lldb/DataFormatters/TypeSynthetic.h
    lldb/include/lldb/ValueObject/ValueObject.h
    lldb/source/API/SBValue.cpp
    lldb/source/ValueObject/ValueObjectSynthetic.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
index 6eb06ba8dda7f..07d3f68f4849e 100644
--- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h
+++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h
@@ -53,7 +53,7 @@ class SyntheticChildrenFrontEnd {
   /// subscripting behavior - for example a sparse array, disable automatic
   /// subscripting with TypeOptions::eTypeOptionCustomSubscripting.
   virtual llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) {
-    return llvm::createStringErrorV("Type has no child named '{0}'", name);
+    return llvm::createStringErrorV("type has no child named '{0}'", name);
   }
 
   /// This function is assumed to always succeed and if it fails, the front-end
@@ -121,7 +121,7 @@ class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd {
   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { return nullptr; }
 
   llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
-    return llvm::createStringErrorV("Type has no child named '{0}'", name);
+    return llvm::createStringErrorV("type has no child named '{0}'", name);
   }
 
   lldb::ChildCacheState Update() override {

diff  --git a/lldb/include/lldb/ValueObject/ValueObject.h b/lldb/include/lldb/ValueObject/ValueObject.h
index de69cf3882fd6..c336213c84e25 100644
--- a/lldb/include/lldb/ValueObject/ValueObject.h
+++ b/lldb/include/lldb/ValueObject/ValueObject.h
@@ -496,6 +496,11 @@ class ValueObject {
   virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name,
                                                      bool can_create = true);
 
+  /// Return the index of the child named \c name.
+  ///
+  /// The error is for LLDB developers, not for the user: a missing child is the
+  /// ordinary negative answer to a lookup. Callers that cannot propagate it
+  /// should log it rather than call \c llvm::consumeError.
   virtual llvm::Expected<size_t> GetIndexOfChildWithName(llvm::StringRef name);
 
   llvm::Expected<uint32_t> GetNumChildren(uint32_t max = UINT32_MAX);

diff  --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index 449cafb85ef64..d2e2dc7e9646d 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -646,7 +646,7 @@ uint32_t SBValue::GetIndexOfChildWithName(const char *name) {
     if (auto idx_or_err = value_sp->GetIndexOfChildWithName(name))
       return *idx_or_err;
     else
-      llvm::consumeError(idx_or_err.takeError());
+      LLDB_LOG_ERROR(GetLog(LLDBLog::API), idx_or_err.takeError(), "{0}");
   }
   return UINT32_MAX;
 }

diff  --git a/lldb/source/ValueObject/ValueObjectSynthetic.cpp b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
index 74a3cfa4cc0f5..385ef0ca7c2a4 100644
--- a/lldb/source/ValueObject/ValueObjectSynthetic.cpp
+++ b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
@@ -332,7 +332,8 @@ ValueObjectSynthetic::GetChildMemberWithName(llvm::StringRef name,
   auto index_or_err = GetIndexOfChildWithName(name);
 
   if (!index_or_err) {
-    llvm::consumeError(index_or_err.takeError());
+    LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), index_or_err.takeError(),
+                   "{0}");
     return lldb::ValueObjectSP();
   }
 
@@ -345,45 +346,48 @@ ValueObjectSynthetic::GetIndexOfChildWithName(llvm::StringRef name_ref) {
 
   ConstString name(name_ref);
 
-  std::optional<uint32_t> found_index = std::nullopt;
   {
     std::lock_guard<std::mutex> guard(m_child_mutex);
     auto name_to_index = m_name_toindex.find(name.GetCString());
     if (name_to_index != m_name_toindex.end())
-      found_index = name_to_index->second;
+      return name_to_index->second;
   }
 
-  if (!found_index && m_synth_filter_up != nullptr) {
-    size_t index = SIZE_MAX;
-    if (auto index_or_err = m_synth_filter_up->GetIndexOfChildWithName(name)) {
-      index = *index_or_err;
-    } else if (!m_synth_sp->CustomSubscripting()) {
-      // Provide automatic support for subscript child names ("[N]").
-      auto maybe_index = formatters::ExtractIndexFromString(name.GetCString());
-      if (!maybe_index)
-        // The child name was not of the form "[N]", return the original error.
-        return index_or_err.takeError();
-
-      // Subscripting succeeded, ignore the original error.
-      llvm::consumeError(index_or_err.takeError());
-      index = *maybe_index;
-
-      // Prevent unnecessary work by limiting max to one past the index.
-      uint32_t max = index + 1;
-      auto num_children = GetNumChildrenIgnoringErrors(max);
-      if (index >= num_children)
-        return llvm::createStringErrorV("subscript index out of range: {0}",
-                                        index);
-    }
-    std::lock_guard<std::mutex> guard(m_child_mutex);
-    m_name_toindex[name.GetCString()] = index;
-    return index;
-  } else if (!found_index && m_synth_filter_up == nullptr) {
+  if (!m_synth_filter_up)
     return llvm::createStringErrorV("type has no child named '{0}'", name);
-  } else if (found_index)
-    return *found_index;
 
-  return llvm::createStringErrorV("type has no child named '{0}'", name);
+  size_t index;
+  auto index_or_err = m_synth_filter_up->GetIndexOfChildWithName(name);
+  if (index_or_err) {
+    index = *index_or_err;
+  } else {
+    // The front-end does its own subscripting, so its answer is final.
+    if (m_synth_sp->CustomSubscripting())
+      return index_or_err.takeError();
+
+    // Provide automatic support for subscript child names ("[N]").
+    auto maybe_index = formatters::ExtractIndexFromString(name.GetCString());
+    if (!maybe_index)
+      // The child name was not of the form "[N]", return the original error.
+      return index_or_err.takeError();
+
+    // Subscripting succeeded, ignore the original error.
+    llvm::consumeError(index_or_err.takeError());
+    index = *maybe_index;
+
+    // Prevent unnecessary work by limiting max to one past the index.
+    uint32_t max = index + 1;
+    auto num_children = GetNumChildren(max);
+    if (!num_children)
+      return num_children.takeError();
+    if (index >= *num_children)
+      return llvm::createStringErrorV("subscript index out of range: {0}",
+                                      index);
+  }
+
+  std::lock_guard<std::mutex> guard(m_child_mutex);
+  m_name_toindex[name.GetCString()] = index;
+  return index;
 }
 
 bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }


        


More information about the lldb-commits mailing list