https://github.com/imkiva updated https://github.com/llvm/llvm-project/pull/158256
>From 8e00d31ce15eb3255c7bafe924754752dd563fd3 Mon Sep 17 00:00:00 2001 From: imkiva <[email protected]> Date: Fri, 12 Sep 2025 16:14:23 +0800 Subject: [PATCH 01/11] [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 <[email protected]> Date: Fri, 12 Sep 2025 17:12:37 +0800 Subject: [PATCH 02/11] [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 <[email protected]> Date: Fri, 12 Sep 2025 17:40:07 +0800 Subject: [PATCH 03/11] [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 <[email protected]> Date: Fri, 12 Sep 2025 17:47:15 +0800 Subject: [PATCH 04/11] [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 <[email protected]> Date: Wed, 17 Sep 2025 13:52:15 +0800 Subject: [PATCH 05/11] [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 <[email protected]> Date: Wed, 17 Sep 2025 14:00:54 +0800 Subject: [PATCH 06/11] [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")) >From 1c05ce0a54ec8d630c5589840687211abcb0d307 Mon Sep 17 00:00:00 2001 From: imkiva <[email protected]> Date: Fri, 17 Oct 2025 13:29:52 +0800 Subject: [PATCH 07/11] Revert "[LLDB] format code" This reverts commit d8652d3e13ed1c3c5e12589b80a7ec7ca4d1266a. --- .../TypeSystem/Clang/TypeSystemClang.cpp | 26 ++++++++----------- .../TypeSystem/Clang/TypeSystemClang.h | 3 ++- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 414349a919721..43d956a2e7088 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,8 +6739,7 @@ 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; @@ -6823,10 +6822,8 @@ 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); } @@ -6840,10 +6837,9 @@ 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 8a6b364269f82..62e6d831440b2 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -321,7 +321,8 @@ 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 616f91681617d246c1aec3512d5f6bfcd0a8601e Mon Sep 17 00:00:00 2001 From: imkiva <[email protected]> Date: Fri, 17 Oct 2025 13:29:55 +0800 Subject: [PATCH 08/11] Revert "[LLDB] Extract `FindInAnonRecordFields` for traversing anonymous records, and fix `type_lookup_anon_struct` test" This reverts commit cb332933cd6ec6d0bae0ad8a01216a07587e9c1a. --- .../TypeSystem/Clang/TypeSystemClang.cpp | 71 +++---------------- .../TypeSystem/Clang/TypeSystemClang.h | 5 -- 2 files changed, 10 insertions(+), 66 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 43d956a2e7088..1cf73dab2e724 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6707,52 +6707,6 @@ 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. @@ -6812,21 +6766,16 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName( field_end = record_decl->field_end(); field != field_end; ++field, ++child_idx) { llvm::StringRef field_name = field->getName(); - 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); - } + 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); } 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 62e6d831440b2..709f89590ba3b 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -320,11 +320,6 @@ 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 6d0f8cc3acce8c01a5029edb40cef4bf0a3b0c15 Mon Sep 17 00:00:00 2001 From: imkiva <[email protected]> Date: Fri, 17 Oct 2025 13:29:58 +0800 Subject: [PATCH 09/11] Revert "[LLDB] Fix `GetIndexOfChildMemberWithName` to handle anonymous structs in base classes" This reverts commit 8e00d31ce15eb3255c7bafe924754752dd563fd3. --- .../TypeSystem/Clang/TypeSystemClang.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 1cf73dab2e724..39aacdb58e694 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6786,23 +6786,6 @@ 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 51d65e32df8c6d64ba32a9a2c4052749b9c8cbca Mon Sep 17 00:00:00 2001 From: imkiva <[email protected]> Date: Fri, 17 Oct 2025 14:58:31 +0800 Subject: [PATCH 10/11] Revert "[LLDB] removed two `expectedFailure` from tests, as they actually passed now" This reverts commit f70ada7b258d92ad964529c420cf288b8dc09c5f. --- lldb/test/API/lang/cpp/diamond/TestCppDiamond.py | 1 + .../cpp/reference-to-outer-type/TestCppReferenceToOuterClass.py | 1 + 2 files changed, 2 insertions(+) diff --git a/lldb/test/API/lang/cpp/diamond/TestCppDiamond.py b/lldb/test/API/lang/cpp/diamond/TestCppDiamond.py index 13ab8cc742551..27062c0666a1a 100644 --- a/lldb/test/API/lang/cpp/diamond/TestCppDiamond.py +++ b/lldb/test/API/lang/cpp/diamond/TestCppDiamond.py @@ -107,6 +107,7 @@ 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 cb28e2b31fad1..a6e419b7fcdfa 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,6 +6,7 @@ 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")) >From 0a001b049c158f1a6923d75b14f9a7b141e67175 Mon Sep 17 00:00:00 2001 From: imkiva <[email protected]> Date: Fri, 17 Oct 2025 15:00:18 +0800 Subject: [PATCH 11/11] [LLDB] check for `IndirectFieldDecl` in `GetIndexForRecordChild` --- .../TypeSystem/Clang/TypeSystemClang.cpp | 80 ++++++++++++++++--- .../TypeSystem/Clang/TypeSystemClang.h | 17 +++- .../TestCppTypeLookupAnonBaseMember.py | 5 ++ .../cpp/type_lookup_anon_base_member/main.cpp | 2 + 4 files changed, 92 insertions(+), 12 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 39aacdb58e694..2784f62cb99db 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6690,9 +6690,9 @@ uint32_t TypeSystemClang::GetIndexForRecordBase( return UINT32_MAX; } -uint32_t TypeSystemClang::GetIndexForRecordChild( +bool TypeSystemClang::GetIndexForRecordChild( const clang::RecordDecl *record_decl, clang::NamedDecl *canonical_decl, - bool omit_empty_base_classes) { + bool omit_empty_base_classes, RecordChildResult &out) { uint32_t child_idx = TypeSystemClang::GetNumBaseClasses( llvm::dyn_cast<clang::CXXRecordDecl>(record_decl), omit_empty_base_classes); @@ -6700,11 +6700,70 @@ uint32_t TypeSystemClang::GetIndexForRecordChild( clang::RecordDecl::field_iterator field, field_end; for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++child_idx) { - if (field->getCanonicalDecl() == canonical_decl) - return child_idx; + out = RecordChildResult{}; + + // If finding an `IndirectFieldDecl x` from `struct { int x; ... };` + if (auto *IFD = llvm::dyn_cast<clang::IndirectFieldDecl>(canonical_decl)) { + // Only meaningful is the field is an anonymous struct/union. + if (!field->isAnonymousStructOrUnion()) + continue; + + // Find the anonymous aggregate record that is a direct field of + // `record_decl`, and the target field inside that aggregate, we need the + // latter to compute the correct child index to the anonymous field. + const clang::FieldDecl *anon_aggregate = nullptr; + const clang::FieldDecl *target_field_in_anon = nullptr; + + for (clang::NamedDecl *ND : IFD->chain()) { + if (auto *FD = llvm::dyn_cast<clang::FieldDecl>(ND)) { + if (FD->isAnonymousStructOrUnion() && + FD->getDeclContext() == record_decl) + anon_aggregate = FD; + if (!FD->isAnonymousStructOrUnion()) + target_field_in_anon = FD; + } + } + if (!anon_aggregate || !target_field_in_anon) + continue; + + // If this field is not the anonymous aggregate, skip. + if (field->getCanonicalDecl() != anon_aggregate->getCanonicalDecl()) + continue; + + // the child_idx now points to the anonymous aggregate. + out.index = child_idx; + + // Compute inner slot: within the anonymous aggregate's record. + auto inner_rd = anon_aggregate->getType() + ->getAsCXXRecordDecl() + ->getDefinitionOrSelf(); + if (!inner_rd) { + out.has_inner = false; + return true; + } + + uint32_t inner_idx = + TypeSystemClang::GetNumBaseClasses(inner_rd, omit_empty_base_classes); + + for (auto inner_f = inner_rd->field_begin(), + inner_e = inner_rd->field_end(); + inner_f != inner_e; ++inner_f, ++inner_idx) { + if (inner_f->getCanonicalDecl() == + target_field_in_anon->getCanonicalDecl()) { + out.has_inner = true; + out.inner_index = inner_idx; + return true; + } + } + + } else if (field->getCanonicalDecl() == canonical_decl) { + out.index = child_idx; + out.has_inner = false; + return true; + } } - return UINT32_MAX; + return false; } // Look for a child member (doesn't include base classes, but it does include @@ -6825,13 +6884,16 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName( } for (clang::DeclContext::lookup_iterator I = path->Decls, E; I != E; ++I) { - child_idx = GetIndexForRecordChild( - parent_record_decl, *I, omit_empty_base_classes); - if (child_idx == UINT32_MAX) { + RecordChildResult result{}; + bool success = GetIndexForRecordChild( + parent_record_decl, *I, omit_empty_base_classes, result); + if (!success) { child_indexes.clear(); return 0; } else { - child_indexes.push_back(child_idx); + child_indexes.push_back(result.index); + if (result.has_inner) + child_indexes.push_back(result.inner_index); } } } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 709f89590ba3b..156706ac84535 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -98,6 +98,16 @@ class TypePayloadClang { /// \} }; +/// Return result of GetIndexForRecordChild +struct RecordChildResult { + /// child index in `record_decl` + uint32_t index = UINT32_MAX; + /// true if canonical_decl is an IndirectFieldDecl via an anonymous aggregate + bool has_inner = false; + /// if has_inner is true, this is the index within the anonymous aggregate + uint32_t inner_index = UINT32_MAX; +}; + /// A TypeSystem implementation based on Clang. /// /// This class uses a single clang::ASTContext as the backend for storing @@ -312,9 +322,10 @@ class TypeSystemClang : public TypeSystem { uint32_t GetNumBaseClasses(const clang::CXXRecordDecl *cxx_record_decl, bool omit_empty_base_classes); - uint32_t GetIndexForRecordChild(const clang::RecordDecl *record_decl, - clang::NamedDecl *canonical_decl, - bool omit_empty_base_classes); + bool GetIndexForRecordChild(const clang::RecordDecl *record_decl, + clang::NamedDecl *canonical_decl, + bool omit_empty_base_classes, + RecordChildResult &result); uint32_t GetIndexForRecordBase(const clang::RecordDecl *record_decl, const clang::CXXBaseSpecifier *base_spec, 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 dc538885c32dd..d2cf4a71fbc86 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 @@ -31,6 +31,11 @@ def test_lookup_anon_base_member(self): self.assertTrue(x.IsValid()) self.assertEqual(x.GetValueAsSigned(), 2) + # y from anonymous struct (inside Base) + x = d.GetChildMemberWithName("y") + self.assertTrue(x.IsValid()) + self.assertEqual(x.GetValueAsSigned(), 4) + # d from Derived dd = d.GetChildMemberWithName("d") self.assertTrue(dd.IsValid()) 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 a0b71e8a72237..bff34a5895737 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 @@ -2,6 +2,7 @@ struct Base { int b; struct { int x; + int y; }; }; @@ -14,5 +15,6 @@ int main() { d.b = 1; d.x = 2; d.d = 3; + d.y = 4; return 0; // Set breakpoint here } _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
