Author: Ilia Kuklin Date: 2025-05-12T16:46:58+05:00 New Revision: 3aacd74594b1f8ab04904d277b6a106c98904b29
URL: https://github.com/llvm/llvm-project/commit/3aacd74594b1f8ab04904d277b6a106c98904b29 DIFF: https://github.com/llvm/llvm-project/commit/3aacd74594b1f8ab04904d277b6a106c98904b29.diff LOG: [lldb][TypeSystemClang] Allow arrays to be dereferenced in C/C++. (#135843) Add a function `GetDereferencedType` to `CompilerType` and allow `TypeSystemClang` to dereference arrays. Added: Modified: lldb/include/lldb/Symbol/CompilerType.h lldb/include/lldb/Symbol/TypeSystem.h lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h lldb/source/Symbol/CompilerType.cpp lldb/source/ValueObject/ValueObject.cpp lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py Removed: ################################################################################ diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index fdbc2057ac10f..b8badfda92cf3 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -433,6 +433,11 @@ class CompilerType { CompilerDecl GetStaticFieldWithName(llvm::StringRef name) const; + llvm::Expected<CompilerType> + GetDereferencedType(ExecutionContext *exe_ctx, std::string &deref_name, + uint32_t &deref_byte_size, int32_t &deref_byte_offset, + ValueObject *valobj, uint64_t &language_flags) const; + llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex( ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index df87fea32b72a..1f1a3ac4bc56b 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -364,6 +364,12 @@ class TypeSystem : public PluginInterface, return CompilerDecl(); } + virtual llvm::Expected<CompilerType> + GetDereferencedType(lldb::opaque_compiler_type_t type, + ExecutionContext *exe_ctx, std::string &deref_name, + uint32_t &deref_byte_size, int32_t &deref_byte_offset, + ValueObject *valobj, uint64_t &language_flags) = 0; + virtual llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex( lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 3b286885cc37f..d24f3726b1d25 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6184,6 +6184,24 @@ uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) { return 0; } +llvm::Expected<CompilerType> TypeSystemClang::GetDereferencedType( + lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, + std::string &deref_name, uint32_t &deref_byte_size, + int32_t &deref_byte_offset, ValueObject *valobj, uint64_t &language_flags) { + bool type_valid = IsPointerOrReferenceType(type, nullptr) || + IsArrayType(type, nullptr, nullptr, nullptr); + if (!type_valid) + return llvm::createStringError("not a pointer, reference or array type"); + uint32_t child_bitfield_bit_size = 0; + uint32_t child_bitfield_bit_offset = 0; + bool child_is_base_class; + bool child_is_deref_of_parent; + return GetChildCompilerTypeAtIndex( + type, exe_ctx, 0, false, true, false, deref_name, deref_byte_size, + deref_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, valobj, language_flags); +} + llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex( lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 93933846d114d..f918cb017f51b 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -889,6 +889,12 @@ class TypeSystemClang : public TypeSystem { static uint32_t GetNumPointeeChildren(clang::QualType type); + llvm::Expected<CompilerType> + GetDereferencedType(lldb::opaque_compiler_type_t type, + ExecutionContext *exe_ctx, std::string &deref_name, + uint32_t &deref_byte_size, int32_t &deref_byte_offset, + ValueObject *valobj, uint64_t &language_flags) override; + llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex( lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 90c4dbf0c6206..dd81fc2361f88 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -893,6 +893,18 @@ CompilerDecl CompilerType::GetStaticFieldWithName(llvm::StringRef name) const { return CompilerDecl(); } +llvm::Expected<CompilerType> CompilerType::GetDereferencedType( + ExecutionContext *exe_ctx, std::string &deref_name, + uint32_t &deref_byte_size, int32_t &deref_byte_offset, ValueObject *valobj, + uint64_t &language_flags) const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->GetDereferencedType( + m_type, exe_ctx, deref_name, deref_byte_size, deref_byte_offset, + valobj, language_flags); + return CompilerType(); +} + llvm::Expected<CompilerType> CompilerType::GetChildCompilerTypeAtIndex( ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index e1c66763ff0b8..6f0fe9a5b83f9 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -2794,74 +2794,60 @@ ValueObjectSP ValueObject::Dereference(Status &error) { if (m_deref_valobj) return m_deref_valobj->GetSP(); - const bool is_pointer_or_reference_type = IsPointerOrReferenceType(); - if (is_pointer_or_reference_type) { - bool omit_empty_base_classes = true; - bool ignore_array_bounds = false; - - std::string child_name_str; - uint32_t child_byte_size = 0; - int32_t child_byte_offset = 0; - uint32_t child_bitfield_bit_size = 0; - uint32_t child_bitfield_bit_offset = 0; - bool child_is_base_class = false; - bool child_is_deref_of_parent = false; - const bool transparent_pointers = false; - CompilerType compiler_type = GetCompilerType(); - uint64_t language_flags = 0; + std::string deref_name_str; + uint32_t deref_byte_size = 0; + int32_t deref_byte_offset = 0; + CompilerType compiler_type = GetCompilerType(); + uint64_t language_flags = 0; - ExecutionContext exe_ctx(GetExecutionContextRef()); + ExecutionContext exe_ctx(GetExecutionContextRef()); - CompilerType child_compiler_type; - auto child_compiler_type_or_err = compiler_type.GetChildCompilerTypeAtIndex( - &exe_ctx, 0, transparent_pointers, omit_empty_base_classes, - ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset, - child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, - child_is_deref_of_parent, this, language_flags); - if (!child_compiler_type_or_err) - LLDB_LOG_ERROR(GetLog(LLDBLog::Types), - child_compiler_type_or_err.takeError(), - "could not find child: {0}"); - else - child_compiler_type = *child_compiler_type_or_err; - - if (child_compiler_type && child_byte_size) { - ConstString child_name; - if (!child_name_str.empty()) - child_name.SetCString(child_name_str.c_str()); - - m_deref_valobj = new ValueObjectChild( - *this, child_compiler_type, child_name, child_byte_size, - child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, - child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid, - language_flags); + CompilerType deref_compiler_type; + auto deref_compiler_type_or_err = compiler_type.GetDereferencedType( + &exe_ctx, deref_name_str, deref_byte_size, deref_byte_offset, this, + language_flags); + + std::string deref_error; + if (deref_compiler_type_or_err) { + deref_compiler_type = *deref_compiler_type_or_err; + if (deref_compiler_type && deref_byte_size) { + ConstString deref_name; + if (!deref_name_str.empty()) + deref_name.SetCString(deref_name_str.c_str()); + + m_deref_valobj = + new ValueObjectChild(*this, deref_compiler_type, deref_name, + deref_byte_size, deref_byte_offset, 0, 0, false, + true, eAddressTypeInvalid, language_flags); } - // In case of incomplete child compiler type, use the pointee type and try + // In case of incomplete deref compiler type, use the pointee type and try // to recreate a new ValueObjectChild using it. if (!m_deref_valobj) { // FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g. // `std::vector<int> &`). Remove ObjC restriction once that's resolved. if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) && HasSyntheticValue()) { - child_compiler_type = compiler_type.GetPointeeType(); + deref_compiler_type = compiler_type.GetPointeeType(); - if (child_compiler_type) { - ConstString child_name; - if (!child_name_str.empty()) - child_name.SetCString(child_name_str.c_str()); + if (deref_compiler_type) { + ConstString deref_name; + if (!deref_name_str.empty()) + deref_name.SetCString(deref_name_str.c_str()); m_deref_valobj = new ValueObjectChild( - *this, child_compiler_type, child_name, child_byte_size, - child_byte_offset, child_bitfield_bit_size, - child_bitfield_bit_offset, child_is_base_class, - child_is_deref_of_parent, eAddressTypeInvalid, language_flags); + *this, deref_compiler_type, deref_name, deref_byte_size, + deref_byte_offset, 0, 0, false, true, eAddressTypeInvalid, + language_flags); } } } - - } else if (IsSynthetic()) { - m_deref_valobj = GetChildMemberWithName("$$dereference$$").get(); + } else { + deref_error = llvm::toString(deref_compiler_type_or_err.takeError()); + LLDB_LOG(GetLog(LLDBLog::Types), "could not find child: {0}", deref_error); + if (IsSynthetic()) { + m_deref_valobj = GetChildMemberWithName("$$dereference$$").get(); + } } if (m_deref_valobj) { @@ -2871,13 +2857,13 @@ ValueObjectSP ValueObject::Dereference(Status &error) { StreamString strm; GetExpressionPath(strm); - if (is_pointer_or_reference_type) + if (deref_error.empty()) error = Status::FromErrorStringWithFormat( "dereference failed: (%s) %s", GetTypeName().AsCString("<invalid type>"), strm.GetData()); else error = Status::FromErrorStringWithFormat( - "not a pointer or reference type: (%s) %s", + "dereference failed: %s: (%s) %s", deref_error.c_str(), GetTypeName().AsCString("<invalid type>"), strm.GetData()); return ValueObjectSP(); } diff --git a/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py b/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py index d36c5fce6d43d..6753f988c4187 100644 --- a/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py +++ b/lldb/test/API/commands/frame/var-dil/basics/PointerArithmetic/TestFrameVarDILPointerArithmetic.py @@ -33,11 +33,7 @@ def test_dereference(self): self.expect_var_path("*offset_pref", True, type="int *") self.expect_var_path("**pp_int0", value="0") self.expect_var_path("&**pp_int0", type="int *") - self.expect( - "frame var '*array'", - error=True, - substrs=["not a pointer or reference type"], - ) + self.expect_var_path("*array", value="0") self.expect( "frame var '&*p_null'", error=True, diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py index 7dc656a7ae225..99d79a9f125b1 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/optional/TestDataFormatterGenericOptional.py @@ -88,7 +88,7 @@ def cleanup(): self.expect( "frame variable *number_not_engaged", error=True, - substrs=["not a pointer or reference type"], + substrs=["dereference failed: not a pointer, reference or array type"], ) @add_test_categories(["libc++"]) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits