llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Michael Buch (Michael137) <details> <summary>Changes</summary> WebKit does things like the following: ``` @<!-- -->class NSString; class NSString; ``` This would produce DWARF where `NSString` is a C++ forward declaration in a C++ CU, and an Objective-C forward declaration in an Objective-C++ CU. But the type really is only ever used as an Objective-C type, so it's not a "problematic" ODR violation. This confuses LLDB, however, because when we parse a this in the context of a C++ CU, we cannot tell whether to create a `clang::RecordType` or `clang::ObjCInterfaceType`. If we create a `RecordType` from this, we run into all sort of issues later down the line. This is an unfortunate use-case, which no longer works after https://github.com/llvm/llvm-project/pull/90663 (previously we would've just found the Objective-C definition for this forward declaration). This is similar to what motivated https://github.com/llvm/llvm-project/pull/119860, though in that case there was a way to disambiguate the forward declarations in DWARF by fixing it on the compiler side. In this case, we really can't do anything because we're dealing with CUs of different languages. This patch attempts to fix this by doing a `FindTypes` lookup for the forward declaration in question, and checking whether all the types we found were in fact Objective-C types, in which case, it's an Objective-C++ forward declaration. --- Full diff: https://github.com/llvm/llvm-project/pull/130768.diff 2 Files Affected: - (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp (+38) - (added) lldb/test/Shell/SymbolFile/DWARF/objcxx-forward-decls.test (+70) ``````````diff diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 0b632751574ad..8a32d8f4aa35b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -351,6 +351,41 @@ static void PrepareContextToReceiveMembers(TypeSystemClang &ast, } } +/// Returns \c true if a forward declaration in C or C++ is actually an +/// Objective-C++ forward declaration. Otherwise, or on error, returns +/// \c false. +static bool IsCppForwardDeclObjC(SymbolFileDWARF &dwarf, + const ParsedDWARFTypeAttributes &attrs) { + assert(attrs.is_forward_declaration); + + if (Language::LanguageIsObjC(attrs.class_language)) + return false; + + TypeQuery query(attrs.name); + TypeResults results; + + if (SymbolFileDWARFDebugMap *debug_map_symfile = dwarf.GetDebugMapSymfile()) + debug_map_symfile->FindTypes(query, results); + else + dwarf.FindTypes(query, results); + + // Check that all types we found are Objective-C++ types. + // Otherwise we're dealing with an actual ODR violation and + // we can't say for sure what language this forward declaration + // referred to. + bool all_objc_types = true; + results.GetTypeMap().ForEach([&](const lldb::TypeSP &t) -> bool { + assert(t); + + all_objc_types &= Language::LanguageIsObjC( + t->GetForwardCompilerType().GetMinimumLanguage()); + + return true; + }); + + return all_objc_types; +} + ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { DWARFAttributes attributes = die.GetAttributes(); for (size_t i = 0; i < attributes.Size(); ++i) { @@ -1810,6 +1845,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, } if (attrs.is_forward_declaration) { + if (IsCppForwardDeclObjC(*dwarf, attrs)) + attrs.class_language = eLanguageTypeObjC_plus_plus; + // See if the type comes from a Clang module and if so, track down // that type. TypeSP type_sp = ParseTypeFromClangModule(sc, die, log); diff --git a/lldb/test/Shell/SymbolFile/DWARF/objcxx-forward-decls.test b/lldb/test/Shell/SymbolFile/DWARF/objcxx-forward-decls.test new file mode 100644 index 0000000000000..30109c2943c9b --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/objcxx-forward-decls.test @@ -0,0 +1,70 @@ +# REQUIRES: system-darwin + +# In this test we have two CUs with conflicting forward declaration +# depending on the CU language (one is C++ and the other is Objective-C++). +# We are then stopped in the C++ CU and try to print the type, at which +# point LLDB will try to make it into an Clang AST node. If LLDB were to +# interpret the type as C++ instead of Objective-C, we'd violate Clang +# invariants and crash. +# +# RUN: split-file %s %t +# RUN: %clangxx_host -c -g -x objective-c++ %t/request.m -o %t/request_objc.o +# RUN: %clangxx_host -c -g %t/main.cpp -o %t/main.o +# RUN: %clangxx_host %t/main.o %t/request_objc.o -framework Foundation -o %t/a.out +# +# RUN: %lldb %t/a.out \ +# RUN: -o "breakpoint set -p return -X main" \ +# RUN: -o run \ +# RUN: -o "frame variable r" \ +# RUN: -o exit | FileCheck %s +# +# RUN: dsymutil %t/a.out +# +# RUN: %lldb %t/a.out \ +# RUN: -o "breakpoint set -p return -X main" \ +# RUN: -o run \ +# RUN: -o "frame variable r" \ +# RUN: -o exit | FileCheck %s --check-prefix=CHECK-DSYM + +# CHECK: (lldb) frame variable r +# CHECK-NEXT: (Request) ::r = (m_request = "Hello, World!") + +# CHECK-DSYM: (lldb) frame variable r +# CHECK-DSYM-NEXT: (Request) ::r = (m_request = "Hello, World!") + +#--- lib.h +#ifndef LIB_H_IN +#define LIB_H_IN + +#ifdef __OBJC__ +@class NSString; +#else +class NSString; +#endif + +struct Request { + NSString * m_request = nullptr; +}; + +#endif // _H_IN + +#--- main.cpp +#include "lib.h" + +void process(Request *); + +Request r; + +int main() { + process(&r); + return 0; +} + +#--- request.m +#import <Foundation/Foundation.h> + +#include "lib.h" + +void process(Request * r) { + r->m_request = @"Hello, World!"; +} `````````` </details> https://github.com/llvm/llvm-project/pull/130768 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits