Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 78 additions & 10 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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(
Expand All @@ -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...
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -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
dd = d.GetChildMemberWithName("d")
self.assertTrue(dd.IsValid())
self.assertEqual(dd.GetValueAsSigned(), 3)
18 changes: 18 additions & 0 deletions lldb/test/API/lang/cpp/type_lookup_anon_base_member/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
struct Base {
int b;
struct {
int x;
};
};

struct Derived : public Base {
int d;
};

int main() {
Derived d;
d.b = 1;
d.x = 2;
d.d = 3;
return 0; // Set breakpoint here
}
Loading