Skip to content

Commit 901cc4a

Browse files
committed
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
1 parent e1b07aa commit 901cc4a

File tree

3 files changed

+82
-25
lines changed

3 files changed

+82
-25
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,8 +2600,8 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
26002600
SourceLocation Loc = PD->getLocation();
26012601
llvm::DIFile *PUnit = getOrCreateFile(Loc);
26022602
unsigned PLine = getLineNumber(Loc);
2603-
ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
2604-
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
2603+
ObjCMethodDecl *Getter = PImpD->getGetterMethodDecl();
2604+
ObjCMethodDecl *Setter = PImpD->getSetterMethodDecl();
26052605
PropertyNode = DBuilder.createObjCProperty(
26062606
PD->getName(), PUnit, PLine,
26072607
hasDefaultGetterName(PD, Getter)
@@ -3490,6 +3490,38 @@ llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) {
34903490
return nullptr;
34913491
}
34923492

3493+
llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration(
3494+
const Decl *D, llvm::DISubroutineType *FnType, unsigned LineNo,
3495+
llvm::DINode::DIFlags Flags, llvm::DISubprogram::DISPFlags SPFlags) {
3496+
if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly)
3497+
return nullptr;
3498+
3499+
if (CGM.getCodeGenOpts().DwarfVersion < 5)
3500+
return nullptr;
3501+
3502+
// Starting with DWARF V5 method declarations are emitted as children of
3503+
// the interface type.
3504+
const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
3505+
if (!OMD)
3506+
return nullptr;
3507+
auto *ID = dyn_cast_or_null<ObjCInterfaceDecl>(D->getDeclContext());
3508+
if (!ID)
3509+
ID = OMD->getClassInterface();
3510+
if (!ID)
3511+
return nullptr;
3512+
QualType QTy(ID->getTypeForDecl(), 0);
3513+
auto It = TypeCache.find(QTy.getAsOpaquePtr());
3514+
if (It == TypeCache.end())
3515+
return nullptr;
3516+
auto *InterfaceType = cast<llvm::DICompositeType>(It->second);
3517+
llvm::DISubprogram *FD = DBuilder.createFunction(
3518+
InterfaceType, getObjCMethodName(OMD), StringRef(),
3519+
InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags);
3520+
DBuilder.finalizeSubprogram(FD);
3521+
ObjCMethodCache[ID].push_back(FD);
3522+
return FD;
3523+
}
3524+
34933525
// getOrCreateFunctionType - Construct type. If it is a c++ method, include
34943526
// implicit parameter "this".
34953527
llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
@@ -3632,16 +3664,21 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
36323664

36333665
unsigned LineNo = getLineNumber(Loc);
36343666
unsigned ScopeLine = getLineNumber(ScopeLoc);
3667+
llvm::DISubroutineType *DIFnType = getOrCreateFunctionType(D, FnType, Unit);
3668+
llvm::DISubprogram *Decl = nullptr;
3669+
if (D)
3670+
Decl = isa<ObjCMethodDecl>(D)
3671+
? getObjCMethodDeclaration(D, DIFnType, LineNo, Flags, SPFlags)
3672+
: getFunctionDeclaration(D);
36353673

36363674
// FIXME: The function declaration we're constructing here is mostly reusing
36373675
// declarations from CXXMethodDecl and not constructing new ones for arbitrary
36383676
// FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for
36393677
// all subprograms instead of the actual context since subprogram definitions
36403678
// are emitted as CU level entities by the backend.
36413679
llvm::DISubprogram *SP = DBuilder.createFunction(
3642-
FDContext, Name, LinkageName, Unit, LineNo,
3643-
getOrCreateFunctionType(D, FnType, Unit), ScopeLine, FlagsForDef,
3644-
SPFlagsForDef, TParamsArray.get(), getFunctionDeclaration(D));
3680+
FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine,
3681+
FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl);
36453682
Fn->setSubprogram(SP);
36463683
// We might get here with a VarDecl in the case we're generating
36473684
// code for the initialization of globals. Do not record these decls
@@ -3658,26 +3695,6 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
36583695
if (FD->hasBody() && !FD->param_empty())
36593696
SPDefCache[FD].reset(SP);
36603697

3661-
if (CGM.getCodeGenOpts().DwarfVersion >= 5) {
3662-
// Starting with DWARF V5 method declarations are emitted as children of
3663-
// the interface type.
3664-
if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
3665-
const ObjCInterfaceDecl *ID = OMD->getClassInterface();
3666-
QualType QTy(ID->getTypeForDecl(), 0);
3667-
auto It = TypeCache.find(QTy.getAsOpaquePtr());
3668-
if (It != TypeCache.end()) {
3669-
llvm::DICompositeType *InterfaceDecl =
3670-
cast<llvm::DICompositeType>(It->second);
3671-
llvm::DISubprogram *FD = DBuilder.createFunction(
3672-
InterfaceDecl, Name, LinkageName, Unit, LineNo,
3673-
getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
3674-
TParamsArray.get());
3675-
DBuilder.finalizeSubprogram(FD);
3676-
ObjCMethodCache[ID].push_back(FD);
3677-
}
3678-
}
3679-
}
3680-
36813698
// Push the function onto the lexical block stack.
36823699
LexicalBlockStack.emplace_back(SP);
36833700

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,17 @@ class CGDebugInfo {
613613
/// declaration for the given method definition.
614614
llvm::DISubprogram *getFunctionDeclaration(const Decl *D);
615615

616+
/// \return debug info descriptor to the describe method declaration
617+
/// for the given method definition.
618+
/// \param FnType For Objective-C methods, their type.
619+
/// \param LineNo The declaration's line number.
620+
/// \param Flags The DIFlags for the method declaration.
621+
/// \param SPFlags The subprogram-spcific flags for the method declaration.
622+
llvm::DISubprogram *
623+
getObjCMethodDeclaration(const Decl *D, llvm::DISubroutineType *FnType,
624+
unsigned LineNo, llvm::DINode::DIFlags Flags,
625+
llvm::DISubprogram::DISPFlags SPFlags);
626+
616627
/// \return debug info descriptor to describe in-class static data
617628
/// member declaration for the given out-of-class definition. If D
618629
/// is an out-of-class definition of a static data member of a
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -emit-llvm -debug-info-kind=standalone -dwarf-version=5 %s -o - | FileCheck %s
2+
3+
@protocol NSObject
4+
@end
5+
6+
@interface NSObject <NSObject> {}
7+
@end
8+
9+
struct Bar {};
10+
11+
@protocol BarProto
12+
@property struct Bar *bar;
13+
@end
14+
15+
@interface Foo <BarProto>
16+
@end
17+
18+
@implementation Foo {}
19+
@synthesize bar = _bar;
20+
- (void)f {}
21+
@end
22+
23+
// CHECK: ![[FOO:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo"
24+
25+
// CHECK: ![[DECL:[0-9]+]] = !DISubprogram(name: "-[Foo setBar:]",
26+
// CHECK-SAME: scope: ![[FOO]]
27+
28+
// CHECK: distinct !DISubprogram(name: "-[Foo setBar:]",
29+
// CHECK-SAME: declaration: ![[DECL:[0-9]+]]

0 commit comments

Comments
 (0)