https://github.com/imkiva updated https://github.com/llvm/llvm-project/pull/158256
>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/6] [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/6] [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/6] [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, >From fcc45162b3cc0f15b9003f2039d3f52c8327f75a Mon Sep 17 00:00:00 2001 From: imkiva <zeng...@iscas.ac.cn> Date: Fri, 12 Sep 2025 17:47:15 +0800 Subject: [PATCH 4/6] [LLDB] Update tests --- .../TestCppTypeLookupAnonBaseMember.py | 6 +++--- .../test/API/lang/cpp/type_lookup_anon_base_member/main.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) 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 index 8f38403acfc34..dc538885c32dd 100644 --- 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 @@ -32,6 +32,6 @@ def test_lookup_anon_base_member(self): self.assertEqual(x.GetValueAsSigned(), 2) # d from Derived - a = d.GetChildMemberWithName("a") - self.assertTrue(a.IsValid()) - self.assertEqual(a.GetValueAsSigned(), 3) + dd = d.GetChildMemberWithName("d") + self.assertTrue(dd.IsValid()) + self.assertEqual(dd.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 index f27cf4ce163f9..a0b71e8a72237 100644 --- 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 @@ -6,13 +6,13 @@ struct Base { }; struct Derived : public Base { - int a; + int d; }; int main() { Derived d; d.b = 1; d.x = 2; - d.a = 3; + d.d = 3; return 0; // Set breakpoint here } >From d8652d3e13ed1c3c5e12589b80a7ec7ca4d1266a Mon Sep 17 00:00:00 2001 From: imkiva <zeng...@iscas.ac.cn> Date: Wed, 17 Sep 2025 13:52:15 +0800 Subject: [PATCH 5/6] [LLDB] format code --- .../TypeSystem/Clang/TypeSystemClang.cpp | 26 +++++++++++-------- .../TypeSystem/Clang/TypeSystemClang.h | 3 +-- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 43d956a2e7088..414349a919721 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6714,14 +6714,14 @@ bool TypeSystemClang::FindInAnonRecordFields(const clang::RecordDecl *rd, 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 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) { + // 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(); @@ -6739,7 +6739,8 @@ bool TypeSystemClang::FindInAnonRecordFields(const clang::RecordDecl *rd, continue; const auto *inner_rt = it->getType()->castAs<clang::RecordType>(); - const clang::RecordDecl *inner_rd = inner_rt->getOriginalDecl()->getDefinitionOrSelf(); + const clang::RecordDecl *inner_rd = + inner_rt->getOriginalDecl()->getDefinitionOrSelf(); if (!inner_rd) continue; @@ -6822,8 +6823,10 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName( 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)) + 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); } @@ -6837,9 +6840,10 @@ 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); + 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; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 62e6d831440b2..8a6b364269f82 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -321,8 +321,7 @@ class TypeSystemClang : public TypeSystem { bool omit_empty_base_classes); bool FindInAnonRecordFields(const clang::RecordDecl *rd, - std::vector<uint32_t> &path, - llvm::StringRef name, + 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. >From f70ada7b258d92ad964529c420cf288b8dc09c5f Mon Sep 17 00:00:00 2001 From: imkiva <zeng...@iscas.ac.cn> Date: Wed, 17 Sep 2025 14:00:54 +0800 Subject: [PATCH 6/6] [LLDB] removed two `expectedFailure` from tests, as they actually passed now --- lldb/test/API/lang/cpp/diamond/TestCppDiamond.py | 1 - .../cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py | 1 - 2 files changed, 2 deletions(-) diff --git a/lldb/test/API/lang/cpp/diamond/TestCppDiamond.py b/lldb/test/API/lang/cpp/diamond/TestCppDiamond.py index 27062c0666a1a..13ab8cc742551 100644 --- a/lldb/test/API/lang/cpp/diamond/TestCppDiamond.py +++ b/lldb/test/API/lang/cpp/diamond/TestCppDiamond.py @@ -107,7 +107,6 @@ def test(self): # Use variable paths to access the members. self.expect_var_path("j1.x", type="long", value="1") - @expectedFailureAll @no_debug_info_test def test_invalid_member(self): self.build() diff --git a/lldb/test/API/lang/cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py b/lldb/test/API/lang/cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py index a6e419b7fcdfa..cb28e2b31fad1 100644 --- a/lldb/test/API/lang/cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py +++ b/lldb/test/API/lang/cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py @@ -6,7 +6,6 @@ class TestCase(TestBase): - @unittest.expectedFailure # The fix for this was reverted due to llvm.org/PR52257 def test(self): self.build() self.dbg.CreateTarget(self.getBuildArtifact("a.out")) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits