summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.cpp44
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.h4
-rw-r--r--clang/test/CodeGenObjC/debug-info-category.m52
3 files changed, 100 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index a0d5fd62360..5a527cbde37 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -3346,6 +3346,27 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
if (HasDecl && isa<FunctionDecl>(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<ObjCMethodDecl>(D)) {
+ const ObjCInterfaceDecl *ID = OMD->getClassInterface();
+ QualType QTy(ID->getTypeForDecl(), 0);
+ auto It = TypeCache.find(QTy.getAsOpaquePtr());
+ if (It != TypeCache.end()) {
+ llvm::DICompositeType *InterfaceDecl =
+ cast<llvm::DICompositeType>(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(FD);
+ }
+ }
+ }
+
// Push the function onto the lexical block stack.
LexicalBlockStack.emplace_back(SP);
@@ -4213,6 +4234,29 @@ void CGDebugInfo::finalize() {
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());
+ assert(It != TypeCache.end());
+
+ llvm::DICompositeType *InterfaceDecl =
+ cast<llvm::DICompositeType>(It->second);
+
+ SmallVector<llvm::Metadata *, 16> 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);
+ }
+ }
+
for (auto p : ReplaceMap) {
assert(p.second);
auto *Ty = cast<llvm::DIType>(p.second);
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index a692babef53..9f5e639d98e 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -98,6 +98,10 @@ class CGDebugInfo {
/// Cache of previously constructed interfaces which may change.
llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache;
+ /// Cache of forward declarations for methods belonging to the interface.
+ llvm::DenseMap<const ObjCInterfaceDecl *, std::vector<llvm::DISubprogram *>>
+ ObjCMethodCache;
+
/// Cache of references to clang modules and precompiled headers.
llvm::DenseMap<const Module *, llvm::TrackingMDRef> ModuleCache;
diff --git a/clang/test/CodeGenObjC/debug-info-category.m b/clang/test/CodeGenObjC/debug-info-category.m
new file mode 100644
index 00000000000..faca3a49c23
--- /dev/null
+++ b/clang/test/CodeGenObjC/debug-info-category.m
@@ -0,0 +1,52 @@
+// 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)zero:(Foo *)zeroend;
+- (id)add:(Foo *)addend;
+@end
+
+@implementation Foo (Bar)
++ (id)zero:(Foo *)zeroend {
+ return [self integer:0];
+}
+- (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) zero:]", 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) zero:]", 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) zero:]"{{.*}}isDefinition: true
+// CHECK: = distinct !DISubprogram(name: "-[Foo(Bar) add:]"{{.*}}isDefinition: true
OpenPOWER on IntegriCloud