diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index a9b3831aa0b53f..a8d4ed12808e79 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3495,14 +3495,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(); @@ -3517,7 +3518,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; } @@ -4713,27 +4714,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 5341bfa7f3504a..13e9c7a38fccd8 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 00000000000000..f822088f946ca8 --- /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]",