From 4fc7e5f7ea9b0f258cc37a6e909cc1474c24e247 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 21 Nov 2019 09:56:01 -0800 Subject: [PATCH] Debug info: Emit objc_direct methods as members of their containing class even in DWARF 4 and earlier. This allows the debugger to recognize them as direct functions as opposed to Objective-C methods. Differential Revision: https://reviews.llvm.org/D70544 (cherry picked from commit e0cabe280b80ab71045d90b2d6f1a70e5d4c5d05) --- clang/lib/CodeGen/CGDebugInfo.cpp | 48 ++++++++++--------- clang/lib/CodeGen/CGDebugInfo.h | 5 +- .../CodeGenObjC/debug-info-direct-method.m | 21 ++++++++ 3 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 clang/test/CodeGenObjC/debug-info-direct-method.m diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 8ab84fd08b1f1..c9e26bd59b839 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3504,14 +3504,15 @@ llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration( if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly) return nullptr; - if (CGM.getCodeGenOpts().DwarfVersion < 5) + const auto *OMD = dyn_cast(D); + if (!OMD) + return nullptr; + + if (CGM.getCodeGenOpts().DwarfVersion < 5 && !OMD->isDirectMethod()) return nullptr; // Starting with DWARF V5 method declarations are emitted as children of // the interface type. - const auto *OMD = dyn_cast(D); - if (!OMD) - return nullptr; auto *ID = dyn_cast_or_null(D->getDeclContext()); if (!ID) ID = OMD->getClassInterface(); @@ -3526,7 +3527,7 @@ llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration( InterfaceType, getObjCMethodName(OMD), StringRef(), InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags); DBuilder.finalizeSubprogram(FD); - ObjCMethodCache[ID].push_back(FD); + ObjCMethodCache[ID].push_back({FD, OMD->isDirectMethod()}); return FD; } @@ -4751,27 +4752,28 @@ void CGDebugInfo::finalize() { DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty); } - if (CGM.getCodeGenOpts().DwarfVersion >= 5) { - // Add methods to interface. - for (const auto &P : ObjCMethodCache) { - if (P.second.empty()) - continue; + // Add methods to interface. + for (const auto &P : ObjCMethodCache) { + if (P.second.empty()) + continue; - QualType QTy(P.first->getTypeForDecl(), 0); - auto It = TypeCache.find(QTy.getAsOpaquePtr()); - assert(It != TypeCache.end()); + QualType QTy(P.first->getTypeForDecl(), 0); + auto It = TypeCache.find(QTy.getAsOpaquePtr()); + assert(It != TypeCache.end()); - llvm::DICompositeType *InterfaceDecl = - cast(It->second); + llvm::DICompositeType *InterfaceDecl = + cast(It->second); - SmallVector EltTys; - auto CurrenetElts = InterfaceDecl->getElements(); - EltTys.append(CurrenetElts.begin(), CurrenetElts.end()); - for (auto &MD : P.second) - EltTys.push_back(MD); - llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); - DBuilder.replaceArrays(InterfaceDecl, Elements); - } + auto CurElts = InterfaceDecl->getElements(); + SmallVector EltTys(CurElts.begin(), CurElts.end()); + + // For DWARF v4 or earlier, only add objc_direct methods. + for (auto &SubprogramDirect : P.second) + if (CGM.getCodeGenOpts().DwarfVersion >= 5 || SubprogramDirect.getInt()) + EltTys.push_back(SubprogramDirect.getPointer()); + + llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); + DBuilder.replaceArrays(InterfaceDecl, Elements); } for (const auto &P : ReplaceMap) { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 9a097615b4b43..fa7b213413c6e 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -114,7 +114,10 @@ class CGDebugInfo { llvm::SmallVector ObjCInterfaceCache; /// Cache of forward declarations for methods belonging to the interface. - llvm::DenseMap> + /// The extra bit on the DISubprogram specifies whether a method is + /// "objc_direct". + llvm::DenseMap>> ObjCMethodCache; /// Cache of references to clang modules and precompiled headers. diff --git a/clang/test/CodeGenObjC/debug-info-direct-method.m b/clang/test/CodeGenObjC/debug-info-direct-method.m new file mode 100644 index 0000000000000..f822088f946ca --- /dev/null +++ b/clang/test/CodeGenObjC/debug-info-direct-method.m @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -dwarf-version=5 -emit-llvm -debug-info-kind=limited -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s +// RUN: %clang_cc1 -dwarf-version=4 -emit-llvm -debug-info-kind=limited -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s + +__attribute__((objc_root_class)) +@interface Root +@end + +@implementation Root +- (int)getInt __attribute__((objc_direct)) { + return 42; +} +@end + +// Test that objc_direct methods are always (even in DWARF < 5) emitted +// as members of their containing class. + +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Root", +// CHECK-SAME: elements: ![[MEMBERS:[0-9]+]], +// CHECK-SAME: runtimeLang: DW_LANG_ObjC) +// CHECK: ![[MEMBERS]] = !{![[GETTER:[0-9]+]]} +// CHECK: ![[GETTER]] = !DISubprogram(name: "-[Root getInt]",