Skip to content

Commit 8f67312

Browse files
labathGeorgeARM
authored andcommitted
[lldb] Fix dynamic type resolution for types parsed from declarations (llvm#137974)
This fixes a regression caused by us starting to parse types from declarations. The code in TypeSystemClang was assuming that the value held in ClangASTMetadata was authoritative, but this isn't (and cannot) be the case when the type is parsed from a forward-declaration. For the fix, I add a new "don't know" state to ClangASTMetadata, and make sure DWARFASTParserClang sets it only when it encounters a forward declaration. In this case, the type system will fall back to completing the type. This does mean that we will be completing more types than before, but I'm hoping this will offset by the fact that we don't search for definition DIEs eagerly. In particular, I don't expect it to make a difference in -fstandalone-debug scenarios, since types will nearly always be present as definitions. To avoid this cost, we'd need to create some sort of a back channel to query the DWARFASTParser about the dynamicness of the type without actually completing it. I'd like to avoid that if it is not necessary.
1 parent b7b1dec commit 8f67312

File tree

9 files changed

+58
-15
lines changed

9 files changed

+58
-15
lines changed

lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,22 @@
1111

1212
using namespace lldb_private;
1313

14+
std::optional<bool> ClangASTMetadata::GetIsDynamicCXXType() const {
15+
switch (m_is_dynamic_cxx) {
16+
case 0:
17+
return std::nullopt;
18+
case 1:
19+
return false;
20+
case 2:
21+
return true;
22+
}
23+
llvm_unreachable("Invalid m_is_dynamic_cxx value");
24+
}
25+
26+
void ClangASTMetadata::SetIsDynamicCXXType(std::optional<bool> b) {
27+
m_is_dynamic_cxx = b ? *b + 1 : 0;
28+
}
29+
1430
void ClangASTMetadata::Dump(Stream *s) {
1531
lldb::user_id_t uid = GetUserID();
1632

lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h

+9-6
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,22 @@
1212
#include "lldb/Core/dwarf.h"
1313
#include "lldb/lldb-defines.h"
1414
#include "lldb/lldb-enumerations.h"
15+
#include "lldb/lldb-private-enumerations.h"
1516

1617
namespace lldb_private {
1718

1819
class ClangASTMetadata {
1920
public:
2021
ClangASTMetadata()
2122
: m_user_id(0), m_union_is_user_id(false), m_union_is_isa_ptr(false),
22-
m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true),
23-
m_is_forcefully_completed(false) {}
23+
m_has_object_ptr(false), m_is_self(false),
24+
m_is_forcefully_completed(false) {
25+
SetIsDynamicCXXType(std::nullopt);
26+
}
2427

25-
bool GetIsDynamicCXXType() const { return m_is_dynamic_cxx; }
28+
std::optional<bool> GetIsDynamicCXXType() const;
2629

27-
void SetIsDynamicCXXType(bool b) { m_is_dynamic_cxx = b; }
30+
void SetIsDynamicCXXType(std::optional<bool> b);
2831

2932
void SetUserID(lldb::user_id_t user_id) {
3033
m_user_id = user_id;
@@ -101,8 +104,8 @@ class ClangASTMetadata {
101104
uint64_t m_isa_ptr;
102105
};
103106

104-
bool m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1,
105-
m_is_self : 1, m_is_dynamic_cxx : 1, m_is_forcefully_completed : 1;
107+
unsigned m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1,
108+
m_is_self : 1, m_is_dynamic_cxx : 2, m_is_forcefully_completed : 1;
106109
};
107110

108111
} // namespace lldb_private

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -1837,7 +1837,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
18371837

18381838
ClangASTMetadata metadata;
18391839
metadata.SetUserID(die.GetID());
1840-
metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die));
1840+
if (!attrs.is_forward_declaration)
1841+
metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die));
18411842

18421843
TypeSystemClang::TemplateParameterInfos template_param_infos;
18431844
if (ParseTemplateParameterInfos(die, template_param_infos)) {

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

+11-7
Original file line numberDiff line numberDiff line change
@@ -3657,13 +3657,17 @@ bool TypeSystemClang::IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
36573657
bool success;
36583658
if (cxx_record_decl->isCompleteDefinition())
36593659
success = cxx_record_decl->isDynamicClass();
3660-
else if (std::optional<ClangASTMetadata> metadata =
3661-
GetMetadata(cxx_record_decl))
3662-
success = metadata->GetIsDynamicCXXType();
3663-
else if (GetType(pointee_qual_type).GetCompleteType())
3664-
success = cxx_record_decl->isDynamicClass();
3665-
else
3666-
success = false;
3660+
else {
3661+
std::optional<ClangASTMetadata> metadata = GetMetadata(cxx_record_decl);
3662+
std::optional<bool> is_dynamic =
3663+
metadata ? metadata->GetIsDynamicCXXType() : std::nullopt;
3664+
if (is_dynamic)
3665+
success = *is_dynamic;
3666+
else if (GetType(pointee_qual_type).GetCompleteType())
3667+
success = cxx_record_decl->isDynamicClass();
3668+
else
3669+
success = false;
3670+
}
36673671

36683672
if (success)
36693673
set_dynamic_pointee_type(pointee_qual_type);
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
CXX_SOURCES := pass-to-base.cpp anonymous-b.cpp
1+
CXX_SOURCES := pass-to-base.cpp anonymous-b.cpp forward-a.cpp
22

33
include Makefile.rules

lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py

+12
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,15 @@ def examine_value_object_of_this_ptr(
266266
contained_b_static_addr = int(contained_b_static.GetValue(), 16)
267267

268268
self.assertLess(contained_b_addr, contained_b_static_addr)
269+
270+
@no_debug_info_test
271+
def test_from_forward_decl(self):
272+
"""Test fetching C++ dynamic values forward-declared types. It's
273+
imperative that this is a separate test so that we don't end up parsing
274+
a definition of A from somewhere else."""
275+
self.build()
276+
lldbutil.run_to_name_breakpoint(self, "take_A")
277+
self.expect(
278+
"frame var -d run-target --ptr-depth=1 --show-types a",
279+
substrs=["(B *) a", "m_b_value = 10"],
280+
)

lldb/test/API/lang/cpp/dynamic-value/a.h

+2
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ class A {
2222

2323
A *make_anonymous_B();
2424

25+
A *take_A(A *a);
26+
2527
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class A;
2+
3+
A *take_A(A *a) { return a; }

lldb/test/API/lang/cpp/dynamic-value/pass-to-base.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,7 @@ main (int argc, char **argv)
4545

4646
myB.doSomething(*make_anonymous_B());
4747

48+
take_A(&myB);
49+
4850
return 0;
4951
}

0 commit comments

Comments
 (0)