[Lldb-commits] [lldb] [LLDB] Fix GetIndexOfChildMemberWithName to handle anonymous struct in base classes (PR #158256)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 12 02:47:09 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Kiva (imkiva)
<details>
<summary>Changes</summary>
Fixes https://github.com/llvm/llvm-project/issues/158131
Similar to https://github.com/llvm/llvm-project/pull/138487 but also search for child indices in the base classes.
---
Full diff: https://github.com/llvm/llvm-project/pull/158256.diff
5 Files Affected:
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+78-10)
- (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h (+5)
- (added) lldb/test/API/lang/cpp/type_lookup_anon_base_member/Makefile (+3)
- (added) lldb/test/API/lang/cpp/type_lookup_anon_base_member/TestCppTypeLookupAnonBaseMember.py (+37)
- (added) lldb/test/API/lang/cpp/type_lookup_anon_base_member/main.cpp (+18)
``````````diff
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 39aacdb58e694..43d956a2e7088 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -6707,6 +6707,52 @@ uint32_t TypeSystemClang::GetIndexForRecordChild(
return UINT32_MAX;
}
+bool TypeSystemClang::FindInAnonRecordFields(const clang::RecordDecl *rd,
+ std::vector<uint32_t> &path,
+ llvm::StringRef name,
+ bool omit_empty_base_classes) {
+ uint32_t local_idx = 0;
+
+ // We need the visible base count to compute the child index offset
+ const clang::CXXRecordDecl *crd =
+ llvm::dyn_cast<clang::CXXRecordDecl>(rd);
+ const uint32_t bases =
+ TypeSystemClang::GetNumBaseClasses(crd, omit_empty_base_classes);
+
+ // We only treat anonymous record fields as transparent containers for further lookup.
+ for (auto it = rd->field_begin(), ie = rd->field_end();
+ it != ie; ++it, ++local_idx) {
+ llvm::StringRef fname = it->getName();
+ const bool is_anon = it->isAnonymousStructOrUnion() || fname.empty();
+
+ // named field, check for a match
+ if (!is_anon) {
+ if (fname == name) {
+ path.push_back(bases + local_idx);
+ return true;
+ }
+ continue;
+ }
+
+ // anonymous field, look inside only if it is a record type
+ if (!it->getType()->isRecordType())
+ continue;
+
+ const auto *inner_rt = it->getType()->castAs<clang::RecordType>();
+ const clang::RecordDecl *inner_rd = inner_rt->getOriginalDecl()->getDefinitionOrSelf();
+ if (!inner_rd)
+ continue;
+
+ // only descend into the "fields" of the anonymous record
+ // (do not traverse its bases here)
+ path.push_back(bases + local_idx);
+ if (FindInAnonRecordFields(inner_rd, path, name, omit_empty_base_classes))
+ return true;
+ path.pop_back();
+ }
+ return false;
+}
+
// Look for a child member (doesn't include base classes, but it does include
// their members) in the type hierarchy. Returns an index path into
// "clang_type" on how to reach the appropriate member.
@@ -6766,16 +6812,21 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
field_end = record_decl->field_end();
field != field_end; ++field, ++child_idx) {
llvm::StringRef field_name = field->getName();
- if (field_name.empty()) {
- CompilerType field_type = GetType(field->getType());
- std::vector<uint32_t> save_indices = child_indexes;
- child_indexes.push_back(
- child_idx + TypeSystemClang::GetNumBaseClasses(
- cxx_record_decl, omit_empty_base_classes));
- if (field_type.GetIndexOfChildMemberWithName(
- name, omit_empty_base_classes, child_indexes))
- return child_indexes.size();
- child_indexes = std::move(save_indices);
+ const bool is_anon =
+ field->isAnonymousStructOrUnion() || field_name.empty();
+ if (is_anon) {
+ if (field->getType()->isRecordType()) {
+ const uint32_t this_slot =
+ child_idx + TypeSystemClang::GetNumBaseClasses(
+ cxx_record_decl, omit_empty_base_classes);
+ std::vector<uint32_t> save_indices = child_indexes;
+ child_indexes.push_back(this_slot);
+ const auto *rt = field->getType()->castAs<clang::RecordType>();
+ const clang::RecordDecl *rd = rt->getOriginalDecl()->getDefinitionOrSelf();
+ if (rd && FindInAnonRecordFields(rd, child_indexes, name, omit_empty_base_classes))
+ return child_indexes.size();
+ child_indexes = std::move(save_indices);
+ }
} else if (field_name == name) {
// We have to add on the number of base classes to this index!
child_indexes.push_back(
@@ -6786,6 +6837,23 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
}
if (cxx_record_decl) {
+ for (const clang::CXXBaseSpecifier &base_spec : cxx_record_decl->bases()) {
+ uint32_t base_slot =
+ GetIndexForRecordBase(record_decl, &base_spec, omit_empty_base_classes);
+ if (base_slot == UINT32_MAX)
+ continue;
+
+ std::vector<uint32_t> save = child_indexes;
+ child_indexes.push_back(base_slot);
+ CompilerType base_type = GetType(base_spec.getType());
+ if (GetIndexOfChildMemberWithName(base_type.GetOpaqueQualType(),
+ name, omit_empty_base_classes,
+ child_indexes)) {
+ return child_indexes.size();
+ }
+ child_indexes = std::move(save);
+ }
+
const clang::RecordDecl *parent_record_decl = cxx_record_decl;
// Didn't find things easily, lets let clang do its thang...
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 709f89590ba3b..62e6d831440b2 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -320,6 +320,11 @@ class TypeSystemClang : public TypeSystem {
const clang::CXXBaseSpecifier *base_spec,
bool omit_empty_base_classes);
+ bool FindInAnonRecordFields(const clang::RecordDecl *rd,
+ std::vector<uint32_t> &path,
+ llvm::StringRef name,
+ bool omit_empty_base_classes);
+
/// Synthesize a clang::Module and return its ID or a default-constructed ID.
OptionalClangModuleID GetOrCreateClangModule(llvm::StringRef name,
OptionalClangModuleID parent,
diff --git a/lldb/test/API/lang/cpp/type_lookup_anon_base_member/Makefile b/lldb/test/API/lang/cpp/type_lookup_anon_base_member/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/lang/cpp/type_lookup_anon_base_member/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/type_lookup_anon_base_member/TestCppTypeLookupAnonBaseMember.py b/lldb/test/API/lang/cpp/type_lookup_anon_base_member/TestCppTypeLookupAnonBaseMember.py
new file mode 100644
index 0000000000000..8f38403acfc34
--- /dev/null
+++ b/lldb/test/API/lang/cpp/type_lookup_anon_base_member/TestCppTypeLookupAnonBaseMember.py
@@ -0,0 +1,37 @@
+"""
+Test that we properly print anonymous members in a base class.
+"""
+
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import decorators
+
+
+class TestTypeLookupAnonBaseMember(TestBase):
+ def test_lookup_anon_base_member(self):
+ self.build()
+ (target, process, thread, bp1) = lldbutil.run_to_source_breakpoint(
+ self, "// Set breakpoint here", lldb.SBFileSpec("main.cpp")
+ )
+
+ thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+ frame = thread.GetFrameAtIndex(0)
+
+ d = frame.FindVariable("d")
+ self.assertTrue(d.IsValid())
+
+ # b from Base
+ b = d.GetChildMemberWithName("b")
+ self.assertTrue(b.IsValid())
+ self.assertEqual(b.GetValueAsSigned(), 1)
+
+ # x from anonymous struct (inside Base)
+ x = d.GetChildMemberWithName("x")
+ self.assertTrue(x.IsValid())
+ self.assertEqual(x.GetValueAsSigned(), 2)
+
+ # d from Derived
+ a = d.GetChildMemberWithName("a")
+ self.assertTrue(a.IsValid())
+ self.assertEqual(a.GetValueAsSigned(), 3)
diff --git a/lldb/test/API/lang/cpp/type_lookup_anon_base_member/main.cpp b/lldb/test/API/lang/cpp/type_lookup_anon_base_member/main.cpp
new file mode 100644
index 0000000000000..f27cf4ce163f9
--- /dev/null
+++ b/lldb/test/API/lang/cpp/type_lookup_anon_base_member/main.cpp
@@ -0,0 +1,18 @@
+struct Base {
+ int b;
+ struct {
+ int x;
+ };
+};
+
+struct Derived : public Base {
+ int a;
+};
+
+int main() {
+ Derived d;
+ d.b = 1;
+ d.x = 2;
+ d.a = 3;
+ return 0; // Set breakpoint here
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/158256
More information about the lldb-commits
mailing list