Skip to content

Commit 3282e7e

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 (cherry picked from commit 901cc4a)
1 parent e3721d3 commit 3282e7e

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
@@ -2569,8 +2569,8 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
25692569
SourceLocation Loc = PD->getLocation();
25702570
llvm::DIFile *PUnit = getOrCreateFile(Loc);
25712571
unsigned PLine = getLineNumber(Loc);
2572-
ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
2573-
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
2572+
ObjCMethodDecl *Getter = PImpD->getGetterMethodDecl();
2573+
ObjCMethodDecl *Setter = PImpD->getSetterMethodDecl();
25742574
PropertyNode = DBuilder.createObjCProperty(
25752575
PD->getName(), PUnit, PLine,
25762576
hasDefaultGetterName(PD, Getter)
@@ -3445,6 +3445,38 @@ llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) {
34453445
return nullptr;
34463446
}
34473447

3448+
llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration(
3449+
const Decl *D, llvm::DISubroutineType *FnType, unsigned LineNo,
3450+
llvm::DINode::DIFlags Flags, llvm::DISubprogram::DISPFlags SPFlags) {
3451+
if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly)
3452+
return nullptr;
3453+
3454+
if (CGM.getCodeGenOpts().DwarfVersion < 5)
3455+
return nullptr;
3456+
3457+
// Starting with DWARF V5 method declarations are emitted as children of
3458+
// the interface type.
3459+
const auto *OMD = dyn_cast<ObjCMethodDecl>(D);
3460+
if (!OMD)
3461+
return nullptr;
3462+
auto *ID = dyn_cast_or_null<ObjCInterfaceDecl>(D->getDeclContext());
3463+
if (!ID)
3464+
ID = OMD->getClassInterface();
3465+
if (!ID)
3466+
return nullptr;
3467+
QualType QTy(ID->getTypeForDecl(), 0);
3468+
auto It = TypeCache.find(QTy.getAsOpaquePtr());
3469+
if (It == TypeCache.end())
3470+
return nullptr;
3471+
auto *InterfaceType = cast<llvm::DICompositeType>(It->second);
3472+
llvm::DISubprogram *FD = DBuilder.createFunction(
3473+
InterfaceType, getObjCMethodName(OMD), StringRef(),
3474+
InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags);
3475+
DBuilder.finalizeSubprogram(FD);
3476+
ObjCMethodCache[ID].push_back(FD);
3477+
return FD;
3478+
}
3479+
34483480
// getOrCreateFunctionType - Construct type. If it is a c++ method, include
34493481
// implicit parameter "this".
34503482
llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
@@ -3587,43 +3619,28 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
35873619

35883620
unsigned LineNo = getLineNumber(Loc);
35893621
unsigned ScopeLine = getLineNumber(ScopeLoc);
3622+
llvm::DISubroutineType *DIFnType = getOrCreateFunctionType(D, FnType, Unit);
3623+
llvm::DISubprogram *Decl = nullptr;
3624+
if (D)
3625+
Decl = isa<ObjCMethodDecl>(D)
3626+
? getObjCMethodDeclaration(D, DIFnType, LineNo, Flags, SPFlags)
3627+
: getFunctionDeclaration(D);
35903628

35913629
// FIXME: The function declaration we're constructing here is mostly reusing
35923630
// declarations from CXXMethodDecl and not constructing new ones for arbitrary
35933631
// FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for
35943632
// all subprograms instead of the actual context since subprogram definitions
35953633
// are emitted as CU level entities by the backend.
35963634
llvm::DISubprogram *SP = DBuilder.createFunction(
3597-
FDContext, Name, LinkageName, Unit, LineNo,
3598-
getOrCreateFunctionType(D, FnType, Unit), ScopeLine, FlagsForDef,
3599-
SPFlagsForDef, TParamsArray.get(), getFunctionDeclaration(D));
3635+
FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine,
3636+
FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl);
36003637
Fn->setSubprogram(SP);
36013638
// We might get here with a VarDecl in the case we're generating
36023639
// code for the initialization of globals. Do not record these decls
36033640
// as they will overwrite the actual VarDecl Decl in the cache.
36043641
if (HasDecl && isa<FunctionDecl>(D))
36053642
DeclCache[D->getCanonicalDecl()].reset(SP);
36063643

3607-
if (CGM.getCodeGenOpts().DwarfVersion >= 5) {
3608-
// Starting with DWARF V5 method declarations are emitted as children of
3609-
// the interface type.
3610-
if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
3611-
const ObjCInterfaceDecl *ID = OMD->getClassInterface();
3612-
QualType QTy(ID->getTypeForDecl(), 0);
3613-
auto It = TypeCache.find(QTy.getAsOpaquePtr());
3614-
if (It != TypeCache.end()) {
3615-
llvm::DICompositeType *InterfaceDecl =
3616-
cast<llvm::DICompositeType>(It->second);
3617-
llvm::DISubprogram *FD = DBuilder.createFunction(
3618-
InterfaceDecl, Name, LinkageName, Unit, LineNo,
3619-
getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
3620-
TParamsArray.get());
3621-
DBuilder.finalizeSubprogram(FD);
3622-
ObjCMethodCache[ID].push_back(FD);
3623-
}
3624-
}
3625-
}
3626-
36273644
// Push the function onto the lexical block stack.
36283645
LexicalBlockStack.emplace_back(SP);
36293646

clang/lib/CodeGen/CGDebugInfo.h

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

590+
/// \return debug info descriptor to the describe method declaration
591+
/// for the given method definition.
592+
/// \param FnType For Objective-C methods, their type.
593+
/// \param LineNo The declaration's line number.
594+
/// \param Flags The DIFlags for the method declaration.
595+
/// \param SPFlags The subprogram-spcific flags for the method declaration.
596+
llvm::DISubprogram *
597+
getObjCMethodDeclaration(const Decl *D, llvm::DISubroutineType *FnType,
598+
unsigned LineNo, llvm::DINode::DIFlags Flags,
599+
llvm::DISubprogram::DISPFlags SPFlags);
600+
590601
/// \return debug info descriptor to describe in-class static data
591602
/// member declaration for the given out-of-class definition. If D
592603
/// 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)