Index: clang/lib/CodeGen/CGDebugInfo.h =================================================================== --- clang/lib/CodeGen/CGDebugInfo.h +++ clang/lib/CodeGen/CGDebugInfo.h @@ -98,6 +98,27 @@ /// Cache of previously constructed interfaces which may change. llvm::SmallVector ObjCInterfaceCache; + struct ObjCMethodCacheEntry { + struct MethodData { + const ObjCMethodDecl *MD; + llvm::DISubprogram *DIMethodDecl; + MethodData(const ObjCMethodDecl *MD, llvm::DISubprogram *DIMethodDecl) + : MD(MD), DIMethodDecl(DIMethodDecl) {} + }; + + // Keep track of the interface so we can update its elements with its + // methods. + llvm::DICompositeType *DIInterfaceDecl; + std::vector Methods; + + ObjCMethodCacheEntry(llvm::DICompositeType *DIInterfaceDecl = nullptr) + : DIInterfaceDecl(DIInterfaceDecl) {} + }; + + /// Cache of forward declarations for method + 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 @@ -2231,6 +2231,13 @@ Mod ? Mod : Unit, ID->getName(), DefUnit, Line, Size, Align, Flags, nullptr, llvm::DINodeArray(), RuntimeLang); + if (CGM.getCodeGenOpts().DwarfVersion >= 5) { + // Remember the DICompositeType in the ObjCMethodCache. + assert(ObjCMethodCache[ID].DIInterfaceDecl == nullptr || + ObjCMethodCache[ID].DIInterfaceDecl == RealDecl); + ObjCMethodCache[ID].DIInterfaceDecl = RealDecl; + } + QualType QTy(Ty, 0); TypeCache[QTy.getAsOpaquePtr()].reset(RealDecl); @@ -3346,6 +3353,21 @@ if (HasDecl && isa(D)) DeclCache[D->getCanonicalDecl()].reset(SP); + if (CGM.getCodeGenOpts().DwarfVersion >= 5) { + // Starting with DWARF5, we create declarations for the interface's + // methods. + if (const auto *OMD = dyn_cast_or_null(D)) { + const ObjCInterfaceDecl *ID = OMD->getClassInterface(); + llvm::DISubprogram *FD = DBuilder.createFunction( + ObjCMethodCache[ID].DIInterfaceDecl, Name, LinkageName, Unit, LineNo, + getOrCreateFunctionType(D, FnType, Unit), Fn->hasLocalLinkage(), + false /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize, + TParamsArray.get()); + DBuilder.finalizeSubprogram(FD); + ObjCMethodCache[ID].Methods.emplace_back(OMD, FD); + } + } + // Push the function onto the lexical block stack. LexicalBlockStack.emplace_back(SP); @@ -4213,6 +4235,27 @@ DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty); } + if (CGM.getCodeGenOpts().DwarfVersion >= 5) { + // Add methods to interface. + for (auto p : ObjCMethodCache) { + llvm::DICompositeType *RealDecl = p.second.DIInterfaceDecl; + if (!RealDecl) + continue; + if (p.second.Methods.empty()) + continue; + + SmallVector EltTys; + for (auto *E : RealDecl->getElements()) { + EltTys.push_back(E); + } + for (auto &M : p.second.Methods) { + EltTys.push_back(M.DIMethodDecl); + } + llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); + DBuilder.replaceArrays(RealDecl, Elements); + } + } + for (auto p : ReplaceMap) { assert(p.second); auto *Ty = cast(p.second); Index: clang/test/CodeGenObjC/debug-info-synthesis.m =================================================================== --- clang/test/CodeGenObjC/debug-info-synthesis.m +++ clang/test/CodeGenObjC/debug-info-synthesis.m @@ -1,4 +1,6 @@ // RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s +// 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 + # 1 "foo.m" 1 # 1 "foo.m" 2 # 1 "./foo.h" 1 @@ -30,8 +32,13 @@ } } +// DWARF5: ![[STRUCT:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo" // CHECK: ![[FILE:.*]] = !DIFile(filename: "{{[^"]+}}foo.h" -// CHECK: !DISubprogram(name: "-[Foo setDict:]" +// DWARF5: !DISubprogram(name: "-[Foo setDict:]" +// DWARF5-SAME: scope: ![[STRUCT]], +// DWARF5-SAME: line: 8, +// DWARF5-SAME: isLocal: true, isDefinition: false +// CHECK: distinct !DISubprogram(name: "-[Foo setDict:]" // CHECK-SAME: file: ![[FILE]], // CHECK-SAME: line: 8, // CHECK-SAME: isLocal: true, isDefinition: true