https://github.com/Michael137 created 
https://github.com/llvm/llvm-project/pull/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 https://github.com/llvm/llvm-project/pull/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 really 
isn't. We want to treat the synthesised method like any other, where explicitly 
passed parameters aren't artificial.

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.

rdar://163063569

>From 48540bd7c3951ff9d994ff9c120b82faf9f38ead Mon Sep 17 00:00:00 2001
From: Michael Buch <[email protected]>
Date: Fri, 24 Oct 2025 09:02:12 +0100
Subject: [PATCH] [clang][DebugInfo] Don't mark parameters of synthesized ObjC
 property accessors artificial

---
 clang/lib/CodeGen/CGDebugInfo.cpp             | 34 +++++++++-
 .../ObjC/property-synthesized-accessors.m     | 63 +++++++++++++++++++
 2 files changed, 96 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/DebugInfo/ObjC/property-synthesized-accessors.m

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 12e2813ef2ec7..6af806686a3b9 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -110,6 +110,33 @@ static bool IsArtificial(VarDecl const *VD) {
                               cast<Decl>(VD->getDeclContext())->isImplicit());
 }
 
+/// Returns \c true if the specified variable \c VD is an explicit parameter of
+/// a synthesized Objective-C property accessor. E.g., a synthesized property
+/// setter method will have a single explicit parameter which is the property 
to
+/// set.
+static bool IsObjCSynthesizedPropertyExplicitParameter(VarDecl const *VD) {
+  assert(VD);
+
+  if (!llvm::isa<ParmVarDecl>(VD))
+    return false;
+
+  // Not a property method.
+  const auto *Method =
+      llvm::dyn_cast_or_null<ObjCMethodDecl>(VD->getDeclContext());
+  if (!Method)
+    return false;
+
+  // Not a synthesized property accessor.
+  if (!Method->isImplicit() || !Method->isPropertyAccessor())
+    return false;
+
+  // Not an explicit parameter.
+  if (VD->isImplicit())
+    return false;
+
+  return true;
+}
+
 CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
     : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
       DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
@@ -5158,7 +5185,12 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const 
VarDecl *VD,
   }
   SmallVector<uint64_t, 13> Expr;
   llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
-  if (VarIsArtificial)
+
+  // While synthesized Objective-C property setters are "artificial" (i.e., 
they
+  // are not spelled out in source), we want to pretend they are just like a
+  // regular non-compiler generated method. Hence, don't mark explicitly passed
+  // parameters of such methods as artificial.
+  if (VarIsArtificial && !IsObjCSynthesizedPropertyExplicitParameter(VD))
     Flags |= llvm::DINode::FlagArtificial;
 
   auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
diff --git a/clang/test/DebugInfo/ObjC/property-synthesized-accessors.m 
b/clang/test/DebugInfo/ObjC/property-synthesized-accessors.m
new file mode 100644
index 0000000000000..6ed2885024c48
--- /dev/null
+++ b/clang/test/DebugInfo/ObjC/property-synthesized-accessors.m
@@ -0,0 +1,63 @@
+// Test that synthesized accessors get treated like regular method 
declarations/defeinitions.
+// I.e.:
+// 1. explicitly passed parameter are not marked artificial.
+// 2. Each property accessor has a method declaration and definition.
+
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -dwarf-version=5 
-debug-info-kind=limited %s -o - | FileCheck %s --implicit-check-not 
"DIFlagArtificial"
+
+@interface Foo
+@property int p1;
+@end
+
+@implementation Foo
+@end
+
+int main(void) {
+  Foo *f;
+  f.p1 = 2;
+  return f.p1;
+}
+
+// CHECK: ![[P1_TYPE:[0-9]+]] = !DIBasicType(name: "int"
+// CHECK: ![[GETTER_DECL:[0-9]+]] = !DISubprogram(name: "-[Foo p1]"
+// CHECK-SAME:                                    type: ![[GETTER_TYPE:[0-9]+]]
+// CHECK-SAME:                                    flags: DIFlagArtificial | 
DIFlagPrototyped
+// CHECK-SAME:                                    spFlags: DISPFlagLocalToUnit)
+
+// CHECK: ![[GETTER_TYPE]] = !DISubroutineType(types: 
![[GETTER_PARAMS:[0-9]+]])
+// CHECK: ![[GETTER_PARAMS]] = !{![[P1_TYPE]], ![[ID_TYPE:[0-9]+]], 
![[SEL_TYPE:[0-9]+]]}
+// CHECK: ![[ID_TYPE]] = !DIDerivedType(tag: DW_TAG_pointer_type
+// CHECK-SAME:                          flags: DIFlagArtificial | 
DIFlagObjectPointer)
+// CHECK: ![[SEL_TYPE]] = !DIDerivedType(tag: DW_TAG_typedef, name: "SEL"
+// CHECK-SAME:                           flags: DIFlagArtificial)
+
+// CHECK: ![[SETTER_DECL:[0-9]+]] = !DISubprogram(name: "-[Foo setP1:]"
+// CHECK-SAME:                                    type: ![[SETTER_TYPE:[0-9]+]]
+// CHECK-SAME:                                    flags: DIFlagArtificial | 
DIFlagPrototyped
+// CHECK-SAME:                                    spFlags: DISPFlagLocalToUnit)
+// CHECK: ![[SETTER_TYPE]] = !DISubroutineType(types: 
![[SETTER_PARAMS:[0-9]+]])
+// CHECK: ![[SETTER_PARAMS]] = !{null, ![[ID_TYPE]], ![[SEL_TYPE]], 
![[P1_TYPE]]}
+
+// CHECK: ![[GETTER_DEF:[0-9]+]] = distinct !DISubprogram(name: "-[Foo p1]"
+// CHECK-SAME:                                            type: 
![[GETTER_TYPE]]
+// CHECK-SAME:                                            flags: 
DIFlagArtificial | DIFlagPrototyped
+// CHECK-SAME:                                            spFlags: 
DISPFlagLocalToUnit | DISPFlagDefinition
+// CHECK-SAME:                                            declaration: 
![[GETTER_DECL]]
+
+// CHECK: !DILocalVariable(name: "self", arg: 1, scope: ![[GETTER_DEF]]
+// CHECK-SAME:             flags: DIFlagArtificial | DIFlagObjectPointer)
+//
+// CHECK: !DILocalVariable(name: "_cmd", arg: 2, scope: ![[GETTER_DEF]],
+// CHECK-SAME:             flags: DIFlagArtificial)
+
+// CHECK: ![[SETTER_DEF:[0-9]+]] = distinct !DISubprogram(name: "-[Foo 
setP1:]",
+// CHECK-SAME:                                            type: 
![[SETTER_TYPE]]
+// CHECK-SAME:                                            flags: 
DIFlagArtificial | DIFlagPrototyped
+// CHECK-SAME:                                            spFlags: 
DISPFlagLocalToUnit | DISPFlagDefinition
+// CHECK-SAME:                                            declaration: 
![[SETTER_DECL]]
+
+// CHECK: !DILocalVariable(name: "self", arg: 1, scope: ![[SETTER_DEF]]
+// CHECK-SAME:             flags: DIFlagArtificial | DIFlagObjectPointer
+// CHECK: !DILocalVariable(name: "_cmd", arg: 2, scope: ![[SETTER_DEF]]
+// CHECK-SAME:             flags: DIFlagArtificial
+// CHECK: !DILocalVariable(name: "p1", arg: 3, scope: ![[SETTER_DEF]]

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to