https://github.com/imkiva created https://github.com/llvm/llvm-project/pull/158256
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. >From 8e00d31ce15eb3255c7bafe924754752dd563fd3 Mon Sep 17 00:00:00 2001 From: imkiva <zeng...@iscas.ac.cn> Date: Fri, 12 Sep 2025 16:14:23 +0800 Subject: [PATCH 1/3] [LLDB] Fix `GetIndexOfChildMemberWithName` to handle anonymous structs in base classes Fixes #158131 Similar to #138487 but also search for child indexes in the base classes --- .../TypeSystem/Clang/TypeSystemClang.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 39aacdb58e694..1cf73dab2e724 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6786,6 +6786,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... >From 3c8ce49a705f4fd1dfc304e76704a9294beb4158 Mon Sep 17 00:00:00 2001 From: imkiva <zeng...@iscas.ac.cn> Date: Fri, 12 Sep 2025 17:12:37 +0800 Subject: [PATCH 2/3] [LLDB] Add tests --- .../cpp/type_lookup_anon_base_member/Makefile | 3 ++ .../TestCppTypeLookupAnonBaseMember.py | 37 +++++++++++++++++++ .../cpp/type_lookup_anon_base_member/main.cpp | 18 +++++++++ 3 files changed, 58 insertions(+) create mode 100644 lldb/test/API/lang/cpp/type_lookup_anon_base_member/Makefile create mode 100644 lldb/test/API/lang/cpp/type_lookup_anon_base_member/TestCppTypeLookupAnonBaseMember.py create mode 100644 lldb/test/API/lang/cpp/type_lookup_anon_base_member/main.cpp 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 +} >From cb332933cd6ec6d0bae0ad8a01216a07587e9c1a Mon Sep 17 00:00:00 2001 From: imkiva <zeng...@iscas.ac.cn> Date: Fri, 12 Sep 2025 17:40:07 +0800 Subject: [PATCH 3/3] [LLDB] Extract `FindInAnonRecordFields` for traversing anonymous records, and fix `type_lookup_anon_struct` test --- .../TypeSystem/Clang/TypeSystemClang.cpp | 71 ++++++++++++++++--- .../TypeSystem/Clang/TypeSystemClang.h | 5 ++ 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 1cf73dab2e724..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( 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, _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits