https://github.com/piotrekjeremicz updated https://github.com/llvm/llvm-project/pull/227771
>From dbe5d08dee8e86d1eac52e65739acc3bcc81f02c Mon Sep 17 00:00:00 2001 From: Piotrek Jeremicz <[email protected]> Date: Mon, 28 Sep 2026 14:22:13 +0200 Subject: [PATCH 1/2] [clang][ObjC] Only describe a property's ivar as backing storage when accessors are synthesized stubs --- clang/lib/CodeGen/CGDebugInfo.cpp | 6 +++- .../DebugInfo/ObjC/property-backing-storage.m | 35 +++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 93428777b9b24..e192d0cfaf2ba 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3826,12 +3826,16 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, if (ObjCPropertyImplDecl *PImpD = ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) { if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) { - SynthesizedProperty = PD; SourceLocation Loc = PD->getLocation(); PUnit = getOrCreateFile(Loc); PLine = getLineNumber(Loc); ObjCMethodDecl *Getter = PImpD->getGetterMethodDecl(); ObjCMethodDecl *Setter = PImpD->getSetterMethodDecl(); + bool GetterIsStub = !Getter || Getter->isSynthesizedAccessorStub(); + bool SetterIsStub = PD->isReadOnly() || !Setter || + Setter->isSynthesizedAccessorStub(); + if (GetterIsStub && SetterIsStub) + SynthesizedProperty = PD; PropertyNode = DBuilder.createObjCProperty( PD->getName(), PUnit, PLine, hasDefaultGetterName(PD, Getter) diff --git a/clang/test/DebugInfo/ObjC/property-backing-storage.m b/clang/test/DebugInfo/ObjC/property-backing-storage.m index 456926e3a9dd4..76117aca3b854 100644 --- a/clang/test/DebugInfo/ObjC/property-backing-storage.m +++ b/clang/test/DebugInfo/ObjC/property-backing-storage.m @@ -9,8 +9,14 @@ // 3. implicitBacking - no @synthesize at all; the compiler // auto-synthesizes both the accessors and a // default-named ivar (_implicitBacking). +// It also verifies that no DIProperty is emitted when an accessor is +// hand-written (class HandwrittenAccessor), because such an accessor may do +// more than forward to the ivar, so a debugger must not bypass it. The legacy +// DIObjCProperty is still emitted in that case. -// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited %s -o %t.ll +// RUN: FileCheck %s < %t.ll +// RUN: FileCheck %s --check-prefix=NO-DIPROPERTY < %t.ll // 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]]) @@ -25,6 +31,19 @@ // 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]]) +// +// Hand-written accessors: the legacy DIObjCProperty is still emitted and +// linked from the ivar... +// CHECK-DAG: ![[COMPUTED_PROP:[0-9]+]] = !DIObjCProperty(name: "computed", file: ![[FILE]], line: {{[0-9]+}}, attributes: 2124, type: ![[INT_TY]]) +// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_computed", {{.*}}file: ![[FILE]], {{.*}}extraData: ![[COMPUTED_PROP]]) +// CHECK-DAG: ![[CLAMPED_PROP:[0-9]+]] = !DIObjCProperty(name: "clamped", file: ![[FILE]], line: {{[0-9]+}}, attributes: 2124, type: ![[INT_TY]]) +// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_clamped", {{.*}}file: ![[FILE]], {{.*}}extraData: ![[CLAMPED_PROP]]) +// +// ...but no DIProperty is. These use a separate prefix with only NOT lines so +// they scan the whole output, not just the text after the last CHECK-DAG match. +// NO-DIPROPERTY-NOT: !DIProperty(name: "computed" +// NO-DIPROPERTY-NOT: !DIProperty(name: "clamped" + @interface C { int _customDeclaredIvar; } @@ -38,4 +57,16 @@ @implementation C @synthesize undeclaredBacking = _customUndeclaredIvar; @end -void foo(C *cptr) {} +@interface HandwrittenAccessor +// Hand-written getter, synthesized setter. +@property(nonatomic) int computed; +// Synthesized getter, hand-written setter. +@property(nonatomic) int clamped; +@end + +@implementation HandwrittenAccessor +- (int)computed { return _computed * 100; } +- (void)setClamped:(int)clamped { _clamped = clamped > 10 ? 10 : clamped; } +@end + +void foo(C *cptr, HandwrittenAccessor *hptr) {} >From b397fad0c2949662b02a8e72efa1560e45ae17a3 Mon Sep 17 00:00:00 2001 From: Piotrek Jeremicz <[email protected]> Date: Sat, 10 Oct 2026 17:23:51 +0200 Subject: [PATCH 2/2] Removed comments --- clang/test/DebugInfo/ObjC/property-backing-storage.m | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/clang/test/DebugInfo/ObjC/property-backing-storage.m b/clang/test/DebugInfo/ObjC/property-backing-storage.m index 76117aca3b854..71be8121d3bdc 100644 --- a/clang/test/DebugInfo/ObjC/property-backing-storage.m +++ b/clang/test/DebugInfo/ObjC/property-backing-storage.m @@ -9,10 +9,6 @@ // 3. implicitBacking - no @synthesize at all; the compiler // auto-synthesizes both the accessors and a // default-named ivar (_implicitBacking). -// It also verifies that no DIProperty is emitted when an accessor is -// hand-written (class HandwrittenAccessor), because such an accessor may do -// more than forward to the ivar, so a debugger must not bypass it. The legacy -// DIObjCProperty is still emitted in that case. // RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited %s -o %t.ll // RUN: FileCheck %s < %t.ll @@ -31,16 +27,11 @@ // 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]]) -// -// Hand-written accessors: the legacy DIObjCProperty is still emitted and -// linked from the ivar... // CHECK-DAG: ![[COMPUTED_PROP:[0-9]+]] = !DIObjCProperty(name: "computed", file: ![[FILE]], line: {{[0-9]+}}, attributes: 2124, type: ![[INT_TY]]) // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_computed", {{.*}}file: ![[FILE]], {{.*}}extraData: ![[COMPUTED_PROP]]) // CHECK-DAG: ![[CLAMPED_PROP:[0-9]+]] = !DIObjCProperty(name: "clamped", file: ![[FILE]], line: {{[0-9]+}}, attributes: 2124, type: ![[INT_TY]]) // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_clamped", {{.*}}file: ![[FILE]], {{.*}}extraData: ![[CLAMPED_PROP]]) -// -// ...but no DIProperty is. These use a separate prefix with only NOT lines so -// they scan the whole output, not just the text after the last CHECK-DAG match. + // NO-DIPROPERTY-NOT: !DIProperty(name: "computed" // NO-DIPROPERTY-NOT: !DIProperty(name: "clamped" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
