Skip to content

Commit 5640d40

Browse files
clayborgMichael137
authored andcommitted
[lldb] Fix expressions that involve nested structs/classes/unions. (llvm#77029)
The LLDB expression parser relies on using the external AST source support in LLDB. This allows us to find a class at the root namespace level, but it wouldn't allow us to find nested classes all of the time. When LLDB finds a class via this mechanism, it would be able to complete this class when needed, but during completion, we wouldn't populate nested types within this class which would prevent us from finding contained types when needed as clang would expect them to be present if a class was completed. When we parse a type for a class, struct or union, we make a forward declaration to the class which can be completed. Now when the class is completed, we also add any contained types to the class' declaration context which now allows these types to be found. If we have a struct that contains a struct, we will add the forward declaration of the contained structure which can be c ompleted later. Having this forward declaration makes it possible for LLDB to find everything it needs now. This should fix an existing issue: llvm#53904 Previously, contained types could be parsed by accident and allow expression to complete successfully. Other times we would have to run an expression multiple times because our old type lookup from our expressions would cau se a type to be parsed, but not used in the current expression, but this would have parsed a type into the containing decl context and the expression might succeed if it is run again. (cherry picked from commit e42edb5)
1 parent 548a338 commit 5640d40

File tree

5 files changed

+117
-1
lines changed

5 files changed

+117
-1
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2126,6 +2126,7 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
21262126
SymbolFileDWARF *dwarf = die.GetDWARF();
21272127

21282128
ClangASTImporter::LayoutInfo layout_info;
2129+
std::vector<DWARFDIE> contained_type_dies;
21292130

21302131
if (die.HasChildren()) {
21312132
const bool type_is_objc_object_or_interface =
@@ -2151,7 +2152,8 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
21512152

21522153
DelayedPropertyList delayed_properties;
21532154
ParseChildMembers(die, clang_type, bases, member_function_dies,
2154-
delayed_properties, default_accessibility, layout_info);
2155+
contained_type_dies, delayed_properties,
2156+
default_accessibility, layout_info);
21552157

21562158
// Now parse any methods if there were any...
21572159
for (const DWARFDIE &die : member_function_dies)
@@ -2204,6 +2206,12 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
22042206
if (record_decl)
22052207
GetClangASTImporter().SetRecordLayout(record_decl, layout_info);
22062208
}
2209+
// Now parse all contained types inside of the class. We make forward
2210+
// declarations to all classes, but we need the CXXRecordDecl to have decls
2211+
// for all contained types because we don't get asked for them via the
2212+
// external AST support.
2213+
for (const DWARFDIE &die : contained_type_dies)
2214+
dwarf->ResolveType(die);
22072215

22082216
return (bool)clang_type;
22092217
}
@@ -3167,6 +3175,7 @@ bool DWARFASTParserClang::ParseChildMembers(
31673175
const DWARFDIE &parent_die, CompilerType &class_clang_type,
31683176
std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes,
31693177
std::vector<DWARFDIE> &member_function_dies,
3178+
std::vector<DWARFDIE> &contained_type_dies,
31703179
DelayedPropertyList &delayed_properties,
31713180
const AccessType default_accessibility,
31723181
ClangASTImporter::LayoutInfo &layout_info) {
@@ -3212,6 +3221,8 @@ bool DWARFASTParserClang::ParseChildMembers(
32123221
break;
32133222

32143223
default:
3224+
if (llvm::dwarf::isType(tag))
3225+
contained_type_dies.push_back(die);
32153226
break;
32163227
}
32173228
}

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
175175
lldb_private::CompilerType &class_compiler_type,
176176
std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes,
177177
std::vector<lldb_private::plugin::dwarf::DWARFDIE> &member_function_dies,
178+
std::vector<lldb_private::plugin::dwarf::DWARFDIE> &contained_type_dies,
178179
DelayedPropertyList &delayed_properties,
179180
const lldb::AccessType default_accessibility,
180181
lldb_private::ClangASTImporter::LayoutInfo &layout_info);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := main.cpp
2+
3+
include Makefile.rules
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""
2+
Test calling an expression with errors that a FixIt can fix.
3+
"""
4+
5+
import lldb
6+
from lldbsuite.test.decorators import *
7+
from lldbsuite.test.lldbtest import *
8+
from lldbsuite.test import lldbutil
9+
10+
11+
class NestedExpressions(TestBase):
12+
13+
def test_enum_in_nested_structs(self):
14+
"""
15+
Test expressions that references an enumeration in nested structs.
16+
"""
17+
self.build()
18+
exe_path = self.getBuildArtifact("a.out")
19+
target = self.dbg.CreateTarget(exe_path)
20+
self.assertTrue(target, "Target: %s is not valid." % (exe_path))
21+
self.expect_expr("A::B::C::EnumType::Eleven",
22+
result_type="A::B::C::EnumType",
23+
result_value="Eleven")
24+
25+
def test_struct_in_nested_structs(self):
26+
"""
27+
Test expressions that references a struct in nested structs.
28+
"""
29+
self.build()
30+
exe_path = self.getBuildArtifact("a.out")
31+
target = self.dbg.CreateTarget(exe_path)
32+
self.assertTrue(target, "Target: %s is not valid." % (exe_path))
33+
self.expect_expr("sizeof(A::B::C)", result_value="1")
34+
self.expect_expr("sizeof(A::B)", result_value="2")
35+
36+
def test_static_in_nested_structs(self):
37+
"""
38+
Test expressions that references a static variable in nested structs.
39+
"""
40+
self.build()
41+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
42+
self, "Stop here to evaluate expressions", lldb.SBFileSpec("main.cpp")
43+
)
44+
self.expect_expr("A::B::C::enum_static",
45+
result_type="A::B::C::EnumType",
46+
result_value="Eleven")
47+
48+
def test_enum_in_nested_namespaces(self):
49+
"""
50+
Test expressions that references an enumeration in nested namespaces.
51+
"""
52+
self.build()
53+
exe_path = self.getBuildArtifact("a.out")
54+
target = self.dbg.CreateTarget(exe_path)
55+
self.assertTrue(target, "Target: %s is not valid." % (exe_path))
56+
self.expect_expr("a::b::c::Color::Blue",
57+
result_type="a::b::c::Color",
58+
result_value="Blue")
59+
60+
def test_static_in_nested_namespaces(self):
61+
"""
62+
Test expressions that references an enumeration in nested namespaces.
63+
"""
64+
self.build()
65+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
66+
self, "Stop here to evaluate expressions", lldb.SBFileSpec("main.cpp")
67+
)
68+
self.expect_expr("a::b::c::d",
69+
result_type="int",
70+
result_value="12")
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
namespace a {
2+
namespace b {
3+
namespace c {
4+
static int d = 12;
5+
enum Color { Red, Green, Blue };
6+
} // namespace c
7+
} // namespace b
8+
} // namespace a
9+
10+
struct A {
11+
int _a = 'a';
12+
struct B {
13+
short _b = 'b';
14+
struct C {
15+
char _c = 'c';
16+
enum EnumType : int { Eleven = 11 };
17+
static EnumType enum_static;
18+
};
19+
};
20+
};
21+
22+
A::B::C::EnumType A::B::C::enum_static = A::B::C::Eleven;
23+
24+
int foo() {
25+
a::b::c::Color color = a::b::c::Blue;
26+
return A::B::C::enum_static == a::b::c::d && ((int)color == 0);
27+
}
28+
29+
int main() {
30+
return foo(); // Stop here to evaluate expressions
31+
}

0 commit comments

Comments
 (0)