[clang] 901cc4a - Debug Info: Nest Objective-C property function decls inside their container.
Adrian Prantl via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 8 15:14:08 PST 2019
Author: Adrian Prantl
Date: 2019-11-08T15:14:00-08:00
New Revision: 901cc4a4bc5257d100338e6c318b96b022d554ee
URL: https://github.com/llvm/llvm-project/commit/901cc4a4bc5257d100338e6c318b96b022d554ee
DIFF: https://github.com/llvm/llvm-project/commit/901cc4a4bc5257d100338e6c318b96b022d554ee.diff
LOG: Debug Info: Nest Objective-C property function decls inside their container.
This has the nice side-effect of also fixing a crash in Clang.
Starting with DWARF 5 we are emitting ObjC method declarations as
children of their containing entity. This worked for interfaces, but
didn't consider the case of synthessized properties. When a property
of a protocol is synthesized in an interface implementation the
ObjCMethodDecl that was passed to CGF::StartFunction was the property
*declaration* which obviously couldn't have a containing
interface. This patch passes the containing interface all the way
through to CGDebugInfo, so the function declaration can be created
with the correct parent (= the class implementing the protocol).
rdar://problem/53782400
Differential Revision: https://reviews.llvm.org/D66121
Added:
clang/test/CodeGenObjC/debug-info-objc-property-dwarf5.m
Modified:
clang/lib/CodeGen/CGDebugInfo.cpp
clang/lib/CodeGen/CGDebugInfo.h
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index e0bb3fda7acf..75c4b2ae2339 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2600,8 +2600,8 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
SourceLocation Loc = PD->getLocation();
llvm::DIFile *PUnit = getOrCreateFile(Loc);
unsigned PLine = getLineNumber(Loc);
- ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
- ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
+ ObjCMethodDecl *Getter = PImpD->getGetterMethodDecl();
+ ObjCMethodDecl *Setter = PImpD->getSetterMethodDecl();
PropertyNode = DBuilder.createObjCProperty(
PD->getName(), PUnit, PLine,
hasDefaultGetterName(PD, Getter)
@@ -3490,6 +3490,38 @@ llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) {
return nullptr;
}
+llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration(
+ const Decl *D, llvm::DISubroutineType *FnType, unsigned LineNo,
+ llvm::DINode::DIFlags Flags, llvm::DISubprogram::DISPFlags SPFlags) {
+ if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly)
+ return nullptr;
+
+ if (CGM.getCodeGenOpts().DwarfVersion < 5)
+ return nullptr;
+
+ // Starting with DWARF V5 method declarations are emitted as children of
+ // the interface type.
+ const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
+ if (!OMD)
+ return nullptr;
+ auto *ID = dyn_cast_or_null<ObjCInterfaceDecl>(D->getDeclContext());
+ if (!ID)
+ ID = OMD->getClassInterface();
+ if (!ID)
+ return nullptr;
+ QualType QTy(ID->getTypeForDecl(), 0);
+ auto It = TypeCache.find(QTy.getAsOpaquePtr());
+ if (It == TypeCache.end())
+ return nullptr;
+ auto *InterfaceType = cast<llvm::DICompositeType>(It->second);
+ llvm::DISubprogram *FD = DBuilder.createFunction(
+ InterfaceType, getObjCMethodName(OMD), StringRef(),
+ InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags);
+ DBuilder.finalizeSubprogram(FD);
+ ObjCMethodCache[ID].push_back(FD);
+ return FD;
+}
+
// getOrCreateFunctionType - Construct type. If it is a c++ method, include
// implicit parameter "this".
llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
@@ -3632,6 +3664,12 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
unsigned LineNo = getLineNumber(Loc);
unsigned ScopeLine = getLineNumber(ScopeLoc);
+ llvm::DISubroutineType *DIFnType = getOrCreateFunctionType(D, FnType, Unit);
+ llvm::DISubprogram *Decl = nullptr;
+ if (D)
+ Decl = isa<ObjCMethodDecl>(D)
+ ? getObjCMethodDeclaration(D, DIFnType, LineNo, Flags, SPFlags)
+ : getFunctionDeclaration(D);
// FIXME: The function declaration we're constructing here is mostly reusing
// declarations from CXXMethodDecl and not constructing new ones for arbitrary
@@ -3639,9 +3677,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
// all subprograms instead of the actual context since subprogram definitions
// are emitted as CU level entities by the backend.
llvm::DISubprogram *SP = DBuilder.createFunction(
- FDContext, Name, LinkageName, Unit, LineNo,
- getOrCreateFunctionType(D, FnType, Unit), ScopeLine, FlagsForDef,
- SPFlagsForDef, TParamsArray.get(), getFunctionDeclaration(D));
+ FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine,
+ FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl);
Fn->setSubprogram(SP);
// We might get here with a VarDecl in the case we're generating
// code for the initialization of globals. Do not record these decls
@@ -3658,26 +3695,6 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
if (FD->hasBody() && !FD->param_empty())
SPDefCache[FD].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), ScopeLine, Flags, SPFlags,
- TParamsArray.get());
- DBuilder.finalizeSubprogram(FD);
- ObjCMethodCache[ID].push_back(FD);
- }
- }
- }
-
// Push the function onto the lexical block stack.
LexicalBlockStack.emplace_back(SP);
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 5e26af4a4f75..9a097615b4b4 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -613,6 +613,17 @@ class CGDebugInfo {
/// declaration for the given method definition.
llvm::DISubprogram *getFunctionDeclaration(const Decl *D);
+ /// \return debug info descriptor to the describe method declaration
+ /// for the given method definition.
+ /// \param FnType For Objective-C methods, their type.
+ /// \param LineNo The declaration's line number.
+ /// \param Flags The DIFlags for the method declaration.
+ /// \param SPFlags The subprogram-spcific flags for the method declaration.
+ llvm::DISubprogram *
+ getObjCMethodDeclaration(const Decl *D, llvm::DISubroutineType *FnType,
+ unsigned LineNo, llvm::DINode::DIFlags Flags,
+ llvm::DISubprogram::DISPFlags SPFlags);
+
/// \return debug info descriptor to describe in-class static data
/// member declaration for the given out-of-class definition. If D
/// is an out-of-class definition of a static data member of a
diff --git a/clang/test/CodeGenObjC/debug-info-objc-property-dwarf5.m b/clang/test/CodeGenObjC/debug-info-objc-property-dwarf5.m
new file mode 100644
index 000000000000..2b3a86fe3997
--- /dev/null
+++ b/clang/test/CodeGenObjC/debug-info-objc-property-dwarf5.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=standalone -dwarf-version=5 %s -o - | FileCheck %s
+
+ at protocol NSObject
+ at end
+
+ at interface NSObject <NSObject> {}
+ at end
+
+struct Bar {};
+
+ at protocol BarProto
+ at property struct Bar *bar;
+ at end
+
+ at interface Foo <BarProto>
+ at end
+
+ at implementation Foo {}
+ at synthesize bar = _bar;
+- (void)f {}
+ at end
+
+// CHECK: ![[FOO:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo"
+
+// CHECK: ![[DECL:[0-9]+]] = !DISubprogram(name: "-[Foo setBar:]",
+// CHECK-SAME: scope: ![[FOO]]
+
+// CHECK: distinct !DISubprogram(name: "-[Foo setBar:]",
+// CHECK-SAME: declaration: ![[DECL:[0-9]+]]
More information about the cfe-commits
mailing list