Skip to content

Commit d75c329

Browse files
Michael137Lukacma
authored andcommitted
[clang][DebugInfo] Don't mark explicit parameter of synthesized ObjC property accessors artificial (llvm#164998)
In the past we used to only mark variables artificial that were `isImplicit`. We would also omit the location information if the variable's parent was implicit. Since llvm#100355 we made the logic to mark variables as artificial the same as determining whether to omit its location or not. This was to support binding variable declarations, which we would like to have line information for (and don't want to mark artificial as they are explicitly named in source). However, this doesn't quite do the expected for parameters of Objective-C synthesised property accessors. An Objective-C setter will have an explicit parameter, which is the ivar to write to. However, because the parent (i.e., the synthesised method) is artificial, we now mark that parameter artificial. This is example debug-info for such an accessor: ``` 0x00000118: DW_TAG_subprogram DW_AT_low_pc (0x0000000000000044) DW_AT_high_pc (0x0000000000000078) DW_AT_frame_base (DW_OP_reg29 W29) DW_AT_object_pointer (0x00000128) DW_AT_specification (0x00000068 "-[Foo setFooProp:]") 0x00000128: DW_TAG_formal_parameter DW_AT_location (DW_OP_fbreg -8) DW_AT_name ("self") DW_AT_type (0x00000186 "Foo *") DW_AT_artificial (true) 0x00000131: DW_TAG_formal_parameter DW_AT_location (DW_OP_breg31 WSP+16) DW_AT_name ("_cmd") DW_AT_type (0x0000018b "SEL") DW_AT_artificial (true) 0x0000013a: DW_TAG_formal_parameter DW_AT_location (DW_OP_breg31 WSP+8) DW_AT_name ("fooProp") DW_AT_type (0x000000aa "id") DW_AT_artificial (true) ``` Note how the `fooProp` parameter is marked artificial, although it technically is an explicitly passed parameter. We want to treat the synthesised method like any other, where explicitly passed parameters aren't artificial. But we do want to omit the file/line info because it doesn't exist in the source. This patch prevents such parameters from being marked artificial. We could probably generalise this to any kind of synthesised method, not just Objective-C. But I'm currently not aware of such synthesised functions, so made it Objective-C specific for now for testability. *Motivator* Marking such parameters artificial makes LLDB fail to parse the ObjC method and emit an error such as: ``` error: Foo.o [0x00000000000009d7]: invalid Objective-C method DW_TAG_subprogram (DW_TAG_subprogram), please file a bug and attach the file at the start of this error message ``` rdar://163063569
1 parent 5080bb3 commit d75c329

File tree

2 files changed

+96
-1
lines changed

2 files changed

+96
-1
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,33 @@ static bool IsArtificial(VarDecl const *VD) {
110110
cast<Decl>(VD->getDeclContext())->isImplicit());
111111
}
112112

113+
/// Returns \c true if the specified variable \c VD is an explicit parameter of
114+
/// a synthesized Objective-C property accessor. E.g., a synthesized property
115+
/// setter method will have a single explicit parameter which is the property to
116+
/// set.
117+
static bool IsObjCSynthesizedPropertyExplicitParameter(VarDecl const *VD) {
118+
assert(VD);
119+
120+
if (!llvm::isa<ParmVarDecl>(VD))
121+
return false;
122+
123+
// Not a property method.
124+
const auto *Method =
125+
llvm::dyn_cast_or_null<ObjCMethodDecl>(VD->getDeclContext());
126+
if (!Method)
127+
return false;
128+
129+
// Not a synthesized property accessor.
130+
if (!Method->isImplicit() || !Method->isPropertyAccessor())
131+
return false;
132+
133+
// Not an explicit parameter.
134+
if (VD->isImplicit())
135+
return false;
136+
137+
return true;
138+
}
139+
113140
CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
114141
: CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
115142
DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
@@ -5158,7 +5185,12 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
51585185
}
51595186
SmallVector<uint64_t, 13> Expr;
51605187
llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
5161-
if (VarIsArtificial)
5188+
5189+
// While synthesized Objective-C property setters are "artificial" (i.e., they
5190+
// are not spelled out in source), we want to pretend they are just like a
5191+
// regular non-compiler generated method. Hence, don't mark explicitly passed
5192+
// parameters of such methods as artificial.
5193+
if (VarIsArtificial && !IsObjCSynthesizedPropertyExplicitParameter(VD))
51625194
Flags |= llvm::DINode::FlagArtificial;
51635195

51645196
auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Test that synthesized accessors get treated like regular method declarations/definitions.
2+
// I.e.:
3+
// 1. explicitly passed parameter are not marked artificial.
4+
// 2. Each property accessor has a method declaration and definition.
5+
6+
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -dwarf-version=5 -debug-info-kind=limited %s -o - | FileCheck %s --implicit-check-not "DIFlagArtificial"
7+
8+
@interface Foo
9+
@property int p1;
10+
@end
11+
12+
@implementation Foo
13+
@end
14+
15+
int main(void) {
16+
Foo *f;
17+
f.p1 = 2;
18+
return f.p1;
19+
}
20+
21+
// CHECK: ![[P1_TYPE:[0-9]+]] = !DIBasicType(name: "int"
22+
// CHECK: ![[GETTER_DECL:[0-9]+]] = !DISubprogram(name: "-[Foo p1]"
23+
// CHECK-SAME: type: ![[GETTER_TYPE:[0-9]+]]
24+
// CHECK-SAME: flags: DIFlagArtificial | DIFlagPrototyped
25+
// CHECK-SAME: spFlags: DISPFlagLocalToUnit)
26+
27+
// CHECK: ![[GETTER_TYPE]] = !DISubroutineType(types: ![[GETTER_PARAMS:[0-9]+]])
28+
// CHECK: ![[GETTER_PARAMS]] = !{![[P1_TYPE]], ![[ID_TYPE:[0-9]+]], ![[SEL_TYPE:[0-9]+]]}
29+
// CHECK: ![[ID_TYPE]] = !DIDerivedType(tag: DW_TAG_pointer_type
30+
// CHECK-SAME: flags: DIFlagArtificial | DIFlagObjectPointer)
31+
// CHECK: ![[SEL_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "SEL"
32+
// CHECK-SAME: flags: DIFlagArtificial)
33+
34+
// CHECK: ![[SETTER_DECL:[0-9]+]] = !DISubprogram(name: "-[Foo setP1:]"
35+
// CHECK-SAME: type: ![[SETTER_TYPE:[0-9]+]]
36+
// CHECK-SAME: flags: DIFlagArtificial | DIFlagPrototyped
37+
// CHECK-SAME: spFlags: DISPFlagLocalToUnit)
38+
// CHECK: ![[SETTER_TYPE]] = !DISubroutineType(types: ![[SETTER_PARAMS:[0-9]+]])
39+
// CHECK: ![[SETTER_PARAMS]] = !{null, ![[ID_TYPE]], ![[SEL_TYPE]], ![[P1_TYPE]]}
40+
41+
// CHECK: ![[GETTER_DEF:[0-9]+]] = distinct !DISubprogram(name: "-[Foo p1]"
42+
// CHECK-SAME: type: ![[GETTER_TYPE]]
43+
// CHECK-SAME: flags: DIFlagArtificial | DIFlagPrototyped
44+
// CHECK-SAME: spFlags: DISPFlagLocalToUnit | DISPFlagDefinition
45+
// CHECK-SAME: declaration: ![[GETTER_DECL]]
46+
47+
// CHECK: !DILocalVariable(name: "self", arg: 1, scope: ![[GETTER_DEF]]
48+
// CHECK-SAME: flags: DIFlagArtificial | DIFlagObjectPointer)
49+
//
50+
// CHECK: !DILocalVariable(name: "_cmd", arg: 2, scope: ![[GETTER_DEF]],
51+
// CHECK-SAME: flags: DIFlagArtificial)
52+
53+
// CHECK: ![[SETTER_DEF:[0-9]+]] = distinct !DISubprogram(name: "-[Foo setP1:]",
54+
// CHECK-SAME: type: ![[SETTER_TYPE]]
55+
// CHECK-SAME: flags: DIFlagArtificial | DIFlagPrototyped
56+
// CHECK-SAME: spFlags: DISPFlagLocalToUnit | DISPFlagDefinition
57+
// CHECK-SAME: declaration: ![[SETTER_DECL]]
58+
59+
// CHECK: !DILocalVariable(name: "self", arg: 1, scope: ![[SETTER_DEF]]
60+
// CHECK-SAME: flags: DIFlagArtificial | DIFlagObjectPointer
61+
// CHECK: !DILocalVariable(name: "_cmd", arg: 2, scope: ![[SETTER_DEF]]
62+
// CHECK-SAME: flags: DIFlagArtificial
63+
// CHECK: !DILocalVariable(name: "p1", arg: 3, scope: ![[SETTER_DEF]]

0 commit comments

Comments
 (0)