Index: clang/lib/CodeGen/CGDebugInfo.h =================================================================== --- clang/lib/CodeGen/CGDebugInfo.h +++ clang/lib/CodeGen/CGDebugInfo.h @@ -98,6 +98,15 @@ /// Cache of previously constructed interfaces which may change. llvm::SmallVector ObjCInterfaceCache; + struct ObjCMethodCacheEntry { + const ObjCMethodDecl *MD; + llvm::DISubprogram *DIMethodDecl; + }; + + /// Cache of forward declarations for methods belonging to the interface. + llvm::DenseMap> + ObjCMethodCache; + /// Cache of references to clang modules and precompiled headers. llvm::DenseMap ModuleCache; Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -3346,6 +3346,26 @@ if (HasDecl && isa(D)) DeclCache[D->getCanonicalDecl()].reset(SP); + if (CGM.getCodeGenOpts().DwarfVersion >= 5) { + // Starting with DWARF V5 method declarations are emitted as children of + // the interface type. + if (const auto *OMD = dyn_cast_or_null(D)) { + const ObjCInterfaceDecl *ID = OMD->getClassInterface(); + QualType QTy(ID->getTypeForDecl(), 0); + auto it = TypeCache.find(QTy.getAsOpaquePtr()); + assert(it != TypeCache.end()); + llvm::DICompositeType *InterfaceDecl = + cast(it->second); + llvm::DISubprogram *FD = DBuilder.createFunction( + InterfaceDecl, Name, LinkageName, Unit, LineNo, + getOrCreateFunctionType(D, FnType, Unit), Fn->hasLocalLinkage(), + false /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize, + TParamsArray.get()); + DBuilder.finalizeSubprogram(FD); + ObjCMethodCache[ID].push_back({OMD, FD}); + } + } + // Push the function onto the lexical block stack. LexicalBlockStack.emplace_back(SP); @@ -4213,6 +4233,30 @@ DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty); } + if (CGM.getCodeGenOpts().DwarfVersion >= 5) { + // Add methods to interface. + for (auto p : ObjCMethodCache) { + if (p.second.empty()) + continue; + + QualType QTy(p.first->getTypeForDecl(), 0); + auto it = TypeCache.find(QTy.getAsOpaquePtr()); + if (it == TypeCache.end()) + continue; + + llvm::DICompositeType *InterfaceDecl = + cast(it->second); + + SmallVector EltTys; + auto &Elements = InterfaceDecl->getElements(); + EltTys.append(Elements.begin(), Elements.end()); + for (auto &M : p.second) + EltTys.push_back(M.DIMethodDecl); + llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); + DBuilder.replaceArrays(InterfaceDecl, Elements); + } + } + for (auto p : ReplaceMap) { assert(p.second); auto *Ty = cast(p.second); Index: clang/test/CodeGenObjC/debug-info-category.m =================================================================== --- /dev/null +++ clang/test/CodeGenObjC/debug-info-category.m @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -dwarf-version=5 -emit-llvm -debug-info-kind=limited -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefix CHECK --check-prefix DWARF5 +// RUN: %clang_cc1 -dwarf-version=4 -emit-llvm -debug-info-kind=limited -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefix CHECK --check-prefix DWARF4 + +@interface Foo { + int integer; +} + +- (int)integer; +- (id)integer:(int)_integer; +@end + +@implementation Foo +- (int)integer { + return integer; +} + +- (id)integer:(int)_integer { + integer = _integer; + return self; +} +@end + +@interface Foo (Bar) +- (id)add:(Foo *)addend; +@end + +@implementation Foo (Bar) +- (id)add:(Foo *)addend { + return [self integer:[self integer] + [addend integer]]; +} +@end + +// CHECK: ![[STRUCT:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo" + +// DWARF5: !DISubprogram(name: "-[Foo integer]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF5: !DISubprogram(name: "-[Foo integer:]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF5: !DISubprogram(name: "-[Foo(Bar) add:]", scope: ![[STRUCT]], {{.*}}isDefinition: false + +// DWARF4-NOT: !DISubprogram(name: "-[Foo integer]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF4-NOT: !DISubprogram(name: "-[Foo integer:]", scope: ![[STRUCT]], {{.*}}isDefinition: false +// DWARF4-NOT: !DISubprogram(name: "-[Foo(Bar) add:]", scope: ![[STRUCT]], {{.*}}isDefinition: false + +// CHECK: = distinct !DISubprogram(name: "-[Foo integer]"{{.*}}isDefinition: true +// CHECK: = distinct !DISubprogram(name: "-[Foo integer:]"{{.*}}isDefinition: true +// CHECK: = distinct !DISubprogram(name: "-[Foo(Bar) add:]"{{.*}}isDefinition: true