[clang] 9741e25 - [clang][DebugInfo] Emit DIProperty for synthesized Objective-C properties (#220362)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 3 14:07:16 PDT 2026


Author: Piotr Jeremicz
Date: 2026-09-03T14:07:11-07:00
New Revision: 9741e25af3cecae45327c8adab6b7234f767df67

URL: https://github.com/llvm/llvm-project/commit/9741e25af3cecae45327c8adab6b7234f767df67
DIFF: https://github.com/llvm/llvm-project/commit/9741e25af3cecae45327c8adab6b7234f767df67.diff

LOG: [clang][DebugInfo] Emit DIProperty for synthesized Objective-C properties (#220362)

Follow-up to #215776, which added `DW_TAG_property` / `DIProperty`
support to LLVM's DebugInfo. This patch teaches Clang's CodeGen to emit
the new `DIProperty` node.

In addition to the legacy `DIObjCProperty` node, `CGDebugInfo` now also
emits a `DIProperty` node whose `backing_storage` points at the ivar a
synthesized property forwards to.

Covered in `clang/test/DebugInfo/ObjC/property-backing-storage.m`:
- `declaredBacking`: `@synthesize` binds to a custom ivar name that IS
declared in the `@interface`.
- `undeclaredBacking`: `@synthesize` binds to a custom ivar name that is
NOT declared; the compiler creates the ivar itself.
- `implicitBacking`: no `@synthesize` at all; the compiler
auto-synthesizes both the accessors and a default-named ivar.

Added: 
    clang/test/DebugInfo/ObjC/property-backing-storage.m

Modified: 
    clang/lib/CodeGen/CGDebugInfo.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index fdb5d869c441b..02864621d60a3 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -3748,13 +3748,17 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
       Flags |= llvm::DINode::FlagBitField;
 
     llvm::MDNode *PropertyNode = nullptr;
+    ObjCPropertyDecl *SynthesizedProperty = nullptr;
+    llvm::DIFile *PUnit = nullptr;
+    unsigned PLine = 0;
     if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
       if (ObjCPropertyImplDecl *PImpD =
               ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
         if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
+          SynthesizedProperty = PD;
           SourceLocation Loc = PD->getLocation();
-          llvm::DIFile *PUnit = getOrCreateFile(Loc);
-          unsigned PLine = getLineNumber(Loc);
+          PUnit = getOrCreateFile(Loc);
+          PLine = getLineNumber(Loc);
           ObjCMethodDecl *Getter = PImpD->getGetterMethodDecl();
           ObjCMethodDecl *Setter = PImpD->getSetterMethodDecl();
           PropertyNode = DBuilder.createObjCProperty(
@@ -3770,10 +3774,17 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
         }
       }
     }
-    FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, FieldLine,
-                                      FieldSize, FieldAlign, FieldOffset, Flags,
-                                      FieldTy, PropertyNode);
-    EltTys.push_back(FieldTy);
+    auto *IvarTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, FieldLine,
+                                           FieldSize, FieldAlign, FieldOffset,
+                                           Flags, FieldTy, PropertyNode);
+    EltTys.push_back(IvarTy);
+
+    if (SynthesizedProperty) {
+      assert(PUnit && "SynthesizedProperty implies PUnit");
+      EltTys.push_back(DBuilder.createProperty(
+          SynthesizedProperty->getName(), PUnit, PLine,
+          getOrCreateType(SynthesizedProperty->getType(), PUnit), IvarTy));
+    }
   }
 
   llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys);

diff  --git a/clang/test/DebugInfo/ObjC/property-backing-storage.m b/clang/test/DebugInfo/ObjC/property-backing-storage.m
new file mode 100644
index 0000000000000..456926e3a9dd4
--- /dev/null
+++ b/clang/test/DebugInfo/ObjC/property-backing-storage.m
@@ -0,0 +1,41 @@
+// Verifies that, in addition to the legacy DIObjCProperty node, Clang also
+// emits a new DIProperty node whose backing_storage points at the ivar a
+// synthesized property forwards to. Covers the three ways a property can be
+// backed by an ivar:
+//   1. declaredBacking   - @synthesize with a custom ivar name that IS
+//                           declared in the @interface.
+//   2. undeclaredBacking - @synthesize with a custom ivar name that is NOT
+//                           declared; the compiler creates the ivar itself.
+//   3. implicitBacking   - no @synthesize at all; the compiler
+//                           auto-synthesizes both the accessors and a
+//                           default-named ivar (_implicitBacking).
+
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s
+
+// CHECK-DAG: ![[DECLARED_PROP:[0-9]+]] = !DIObjCProperty(name: "declaredBacking", file: ![[FILE:[0-9]+]], line: {{[0-9]+}}, attributes: 2316, type: ![[INT_TY:[0-9]+]])
+// CHECK-DAG: ![[UNDECLARED_PROP:[0-9]+]] = !DIObjCProperty(name: "undeclaredBacking", file: ![[FILE]], line: {{[0-9]+}}, attributes: 2316, type: ![[INT_TY]])
+// CHECK-DAG: ![[IMPLICIT_PROP:[0-9]+]] = !DIObjCProperty(name: "implicitBacking", file: ![[FILE]], line: {{[0-9]+}}, attributes: 2316, type: ![[INT_TY]])
+//
+// CHECK-DAG: ![[DECLARED_IVAR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "_customDeclaredIvar", {{.*}}file: ![[FILE]], {{.*}}extraData: ![[DECLARED_PROP]])
+// CHECK-DAG: !DIProperty(name: "declaredBacking", file: ![[FILE]], line: {{[0-9]+}}, type: ![[INT_TY]], backing_storage: ![[DECLARED_IVAR]])
+//
+// CHECK-DAG: ![[UNDECLARED_IVAR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "_customUndeclaredIvar", {{.*}}file: ![[FILE]], {{.*}}extraData: ![[UNDECLARED_PROP]])
+// CHECK-DAG: !DIProperty(name: "undeclaredBacking", file: ![[FILE]], line: {{[0-9]+}}, type: ![[INT_TY]], backing_storage: ![[UNDECLARED_IVAR]])
+//
+// CHECK-DAG: ![[IMPLICIT_IVAR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "_implicitBacking", {{.*}}file: ![[FILE]], {{.*}}extraData: ![[IMPLICIT_PROP]])
+// CHECK-DAG: !DIProperty(name: "implicitBacking", file: ![[FILE]], line: {{[0-9]+}}, type: ![[INT_TY]], backing_storage: ![[IMPLICIT_IVAR]])
+
+ at interface C {
+  int _customDeclaredIvar;
+}
+ at property int declaredBacking;
+ at property int undeclaredBacking;
+ at property int implicitBacking;
+ at end
+
+ at implementation C
+ at synthesize declaredBacking = _customDeclaredIvar;
+ at synthesize undeclaredBacking = _customUndeclaredIvar;
+ at end
+
+void foo(C *cptr) {}


        


More information about the cfe-commits mailing list