diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp index 42933c78b0277..2c5dacb60a9b8 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp @@ -11,6 +11,22 @@ using namespace lldb_private; +std::optional ClangASTMetadata::GetIsDynamicCXXType() const { + switch (m_is_dynamic_cxx) { + case 0: + return std::nullopt; + case 1: + return false; + case 2: + return true; + } + llvm_unreachable("Invalid m_is_dynamic_cxx value"); +} + +void ClangASTMetadata::SetIsDynamicCXXType(std::optional b) { + m_is_dynamic_cxx = b ? *b + 1 : 0; +} + void ClangASTMetadata::Dump(Stream *s) { lldb::user_id_t uid = GetUserID(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h index d3bcde2ced799..ecaa2e0ddf97c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h @@ -12,6 +12,7 @@ #include "lldb/Core/dwarf.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-private-enumerations.h" namespace lldb_private { @@ -19,12 +20,14 @@ class ClangASTMetadata { public: ClangASTMetadata() : m_user_id(0), m_union_is_user_id(false), m_union_is_isa_ptr(false), - m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true), - m_is_forcefully_completed(false) {} + m_has_object_ptr(false), m_is_self(false), + m_is_forcefully_completed(false) { + SetIsDynamicCXXType(std::nullopt); + } - bool GetIsDynamicCXXType() const { return m_is_dynamic_cxx; } + std::optional GetIsDynamicCXXType() const; - void SetIsDynamicCXXType(bool b) { m_is_dynamic_cxx = b; } + void SetIsDynamicCXXType(std::optional b); void SetUserID(lldb::user_id_t user_id) { m_user_id = user_id; @@ -101,8 +104,8 @@ class ClangASTMetadata { uint64_t m_isa_ptr; }; - bool m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1, - m_is_self : 1, m_is_dynamic_cxx : 1, m_is_forcefully_completed : 1; + unsigned m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1, + m_is_self : 1, m_is_dynamic_cxx : 2, m_is_forcefully_completed : 1; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index f22fcbab557a0..a3e809f44ed23 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1837,7 +1837,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, ClangASTMetadata metadata; metadata.SetUserID(die.GetID()); - metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die)); + if (!attrs.is_forward_declaration) + metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die)); TypeSystemClang::TemplateParameterInfos template_param_infos; if (ParseTemplateParameterInfos(die, template_param_infos)) { diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index cb0ecd6ebd406..1a2b3d4133e51 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -3657,13 +3657,17 @@ bool TypeSystemClang::IsPossibleDynamicType(lldb::opaque_compiler_type_t type, bool success; if (cxx_record_decl->isCompleteDefinition()) success = cxx_record_decl->isDynamicClass(); - else if (std::optional metadata = - GetMetadata(cxx_record_decl)) - success = metadata->GetIsDynamicCXXType(); - else if (GetType(pointee_qual_type).GetCompleteType()) - success = cxx_record_decl->isDynamicClass(); - else - success = false; + else { + std::optional metadata = GetMetadata(cxx_record_decl); + std::optional is_dynamic = + metadata ? metadata->GetIsDynamicCXXType() : std::nullopt; + if (is_dynamic) + success = *is_dynamic; + else if (GetType(pointee_qual_type).GetCompleteType()) + success = cxx_record_decl->isDynamicClass(); + else + success = false; + } if (success) set_dynamic_pointee_type(pointee_qual_type); diff --git a/lldb/test/API/lang/cpp/dynamic-value/Makefile b/lldb/test/API/lang/cpp/dynamic-value/Makefile index ce91dc63f473f..24346ccfae510 100644 --- a/lldb/test/API/lang/cpp/dynamic-value/Makefile +++ b/lldb/test/API/lang/cpp/dynamic-value/Makefile @@ -1,3 +1,3 @@ -CXX_SOURCES := pass-to-base.cpp anonymous-b.cpp +CXX_SOURCES := pass-to-base.cpp anonymous-b.cpp forward-a.cpp include Makefile.rules diff --git a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py index 32ef009279713..3952b88a6c28e 100644 --- a/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py +++ b/lldb/test/API/lang/cpp/dynamic-value/TestDynamicValue.py @@ -266,3 +266,15 @@ def examine_value_object_of_this_ptr( contained_b_static_addr = int(contained_b_static.GetValue(), 16) self.assertLess(contained_b_addr, contained_b_static_addr) + + @no_debug_info_test + def test_from_forward_decl(self): + """Test fetching C++ dynamic values forward-declared types. It's + imperative that this is a separate test so that we don't end up parsing + a definition of A from somewhere else.""" + self.build() + lldbutil.run_to_name_breakpoint(self, "take_A") + self.expect( + "frame var -d run-target --ptr-depth=1 --show-types a", + substrs=["(B *) a", "m_b_value = 10"], + ) diff --git a/lldb/test/API/lang/cpp/dynamic-value/a.h b/lldb/test/API/lang/cpp/dynamic-value/a.h index 708cbb79fee5c..c8895ab095d82 100644 --- a/lldb/test/API/lang/cpp/dynamic-value/a.h +++ b/lldb/test/API/lang/cpp/dynamic-value/a.h @@ -22,4 +22,6 @@ class A { A *make_anonymous_B(); +A *take_A(A *a); + #endif diff --git a/lldb/test/API/lang/cpp/dynamic-value/forward-a.cpp b/lldb/test/API/lang/cpp/dynamic-value/forward-a.cpp new file mode 100644 index 0000000000000..8a212d928d5c5 --- /dev/null +++ b/lldb/test/API/lang/cpp/dynamic-value/forward-a.cpp @@ -0,0 +1,3 @@ +class A; + +A *take_A(A *a) { return a; } diff --git a/lldb/test/API/lang/cpp/dynamic-value/pass-to-base.cpp b/lldb/test/API/lang/cpp/dynamic-value/pass-to-base.cpp index be763390cc6f9..9b601084cdc57 100644 --- a/lldb/test/API/lang/cpp/dynamic-value/pass-to-base.cpp +++ b/lldb/test/API/lang/cpp/dynamic-value/pass-to-base.cpp @@ -45,5 +45,7 @@ main (int argc, char **argv) myB.doSomething(*make_anonymous_B()); + take_A(&myB); + return 0; }