diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1460,6 +1460,8 @@ if (!result) return; + const clang::CXXBaseSpecifier *prev_base = + base_classes.empty() ? nullptr : base_classes.back().get(); base_classes.push_back(std::move(result)); if (is_virtual) { @@ -1476,6 +1478,20 @@ // be removed from LayoutRecordType() in the external // AST source in clang. } else { + if (prev_base) { + clang::CXXRecordDecl *prev_base_decl = + prev_base->getType()->getAsCXXRecordDecl(); + if (prev_base_decl && !prev_base_decl->isEmpty()) { + auto it = layout_info.base_offsets.find(prev_base_decl); + assert(it != layout_info.base_offsets.end()); + if (it->second.getQuantity() == member_byte_offset) { + prev_base_decl->markEmpty(); + for (auto *field : prev_base_decl->fields()) + field->addAttr(clang::NoUniqueAddressAttr::Create( + ast->getASTContext(), clang::SourceRange())); + } + } + } layout_info.base_offsets.insert(std::make_pair( ast->GetAsCXXRecordDecl(base_class_clang_type.GetOpaqueQualType()), clang::CharUnits::fromQuantity(member_byte_offset))); diff --git a/lldb/test/API/types/TestEmptyBase.py b/lldb/test/API/types/TestEmptyBase.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/types/TestEmptyBase.py @@ -0,0 +1,42 @@ +""" +Test that recursive types are handled correctly. +""" + + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + + +class EmptyBaseTestCase(TestBase): + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + # Find the line number to break for main.c. + self.line = line_number('empty_base_type.cpp', + '// Set breakpoint here.') + + self.sources = { + 'CXX_SOURCES': 'empty_base_type.cpp'} + + def test(self): + """Test that recursive structs are displayed correctly.""" + self.build(dictionary=self.sources) + self.setTearDownCleanup(dictionary=self.sources) + self.run_expr() + + def run_expr(self): + self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line( + self, + "empty_base_type.cpp", + self.line, + num_expected_locations=-1, + loc_exact=True) + + self.runCmd("run", RUN_SUCCEEDED) + self.runCmd("expression _a") diff --git a/lldb/test/API/types/empty_base_type.cpp b/lldb/test/API/types/empty_base_type.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/types/empty_base_type.cpp @@ -0,0 +1,23 @@ +struct C +{ + long c,d; +}; + +struct D +{ +}; + +struct B +{ + [[no_unique_address]] D x; +}; + +struct A : B,C +{ + long a,b; +} _a; + + +int main() { + return _a.a; // Set breakpoint here. +}