diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 27d77e9a8a551..e815e097e1fb4 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -1593,12 +1593,20 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac { } bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) { - // NSObject is a fixed size. If we can see the @implementation of a class - // which inherits from NSObject then we know that all it's offsets also must - // be fixed. FIXME: Can we do this if see a chain of super classes with - // implementations leading to NSObject? - return ID->getImplementation() && ID->getSuperClass() && - ID->getSuperClass()->getName() == "NSObject"; + // Test a class by checking its superclasses up to + // its base class if it has one. + for (; ID; ID = ID->getSuperClass()) { + // The layout of base class NSObject + // is guaranteed to be statically known + if (ID->getIdentifier()->getName() == "NSObject") + return true; + + // If we cannot see the @implementation of a class, + // we cannot statically know the class layout. + if (!ID->getImplementation()) + return false; + } + return false; } public: diff --git a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m index 788b3220af306..8d55e6c7d2308 100644 --- a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m +++ b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m @@ -1,6 +1,13 @@ // RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 -emit-llvm %s -o - | FileCheck %s // CHECK: @"OBJC_IVAR_$_StaticLayout.static_layout_ivar" = hidden constant i64 20 +// CHECK: @"OBJC_IVAR_$_SuperClass.superClassIvar" = hidden constant i64 20 +// CHECK: @"OBJC_IVAR_$_SuperClass._superClassProperty" = hidden constant i64 24 +// CHECK: @"OBJC_IVAR_$_IntermediateClass.intermediateClassIvar" = constant i64 32 +// CHECK: @"OBJC_IVAR_$_IntermediateClass.intermediateClassIvar2" = constant i64 40 +// CHECK: @"OBJC_IVAR_$_IntermediateClass._intermediateProperty" = hidden constant i64 48 +// CHECK: @"OBJC_IVAR_$_SubClass.subClassIvar" = constant i64 56 +// CHECK: @"OBJC_IVAR_$_SubClass._subClassProperty" = hidden constant i64 64 // CHECK: @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar" = hidden global i64 12 @interface NSObject { @@ -14,12 +21,105 @@ @interface StaticLayout : NSObject @implementation StaticLayout { int static_layout_ivar; } + +// CHECK-LABEL: define internal void @"\01-[StaticLayout meth]" -(void)meth { static_layout_ivar = 0; // CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_StaticLayout + // CHECK: getelementptr inbounds i8, ptr %0, i64 20 +} +@end + +@interface SuperClass : NSObject +@property (nonatomic, assign) int superClassProperty; +@end + +@implementation SuperClass { + int superClassIvar; // Declare an ivar +} + +// CHECK-LABEL: define internal void @"\01-[SuperClass superClassMethod]" +- (void)superClassMethod { + _superClassProperty = 42; + superClassIvar = 10; + // CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_SuperClass + // CHECK: getelementptr inbounds i8, ptr %1, i64 20 +} + +// Implicitly synthesized method here +// CHECK-LABEL: define internal i32 @"\01-[SuperClass superClassProperty]" +// CHECK: getelementptr inbounds i8, ptr %0, i64 24 + +// CHECK-LABEL: define internal void @"\01-[SuperClass setSuperClassProperty:]" +// CHECK: getelementptr inbounds i8, ptr %1, i64 24 +@end + +@interface IntermediateClass : SuperClass { + double intermediateClassIvar; + + @protected + int intermediateClassIvar2; +} +@property (nonatomic, strong) SuperClass *intermediateProperty; +@end + +@implementation IntermediateClass +@synthesize intermediateProperty = _intermediateProperty; + +// CHECK-LABEL: define internal void @"\01-[IntermediateClass intermediateClassMethod]" +- (void)intermediateClassMethod { + intermediateClassIvar = 3.14; + // CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_IntermediateClass + // CHECK: getelementptr inbounds i8, ptr %0, i64 32 +} + +// CHECK-LABEL: define internal void @"\01-[IntermediateClass intermediateClassPropertyMethod]" +- (void)intermediateClassPropertyMethod { + self.intermediateProperty = 0; + // CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_ + // CHECK: call void @objc_msgSend(ptr noundef %0, ptr noundef %1, ptr noundef null) +} + +// CHECK-LABEL: define internal void @"\01-[IntermediateClass intermediateClassPropertyMethodDirect]" +- (void)intermediateClassPropertyMethodDirect { + _intermediateProperty = 0; + // CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_IntermediateClass._intermediateProperty" + // CHECK: getelementptr inbounds i8, ptr %0, i64 48 } @end +@interface SubClass : IntermediateClass { + double subClassIvar; +} +@property (nonatomic, assign) SubClass *subClassProperty; +@end + +@implementation SubClass + +// CHECK-LABEL: define internal void @"\01-[SubClass subclassVar]" +- (void)subclassVar { + subClassIvar = 6.28; + // CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_SubClass + // CHECK: getelementptr inbounds i8, ptr %0, i64 56 +} + +// CHECK-LABEL: define internal void @"\01-[SubClass intermediateSubclassVar]" +-(void)intermediateSubclassVar { + intermediateClassIvar = 3.14; + // CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_IntermediateClass + // CHECK: getelementptr inbounds i8, ptr %0, i64 32 +} + +// Implicit synthesized method here: +// CHECK-LABEL: define internal ptr @"\01-[SubClass subClassProperty]" +// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_SubClass._subClassProperty" +// CHECK: getelementptr inbounds i8, ptr %0, i64 64 + +// CHECK-LABEL: define internal void @"\01-[SubClass setSubClassProperty:]" +// CHECK-NOT: load i64, ptr @"OBJC_IVAR_$_SubClass._subClassProperty" +// CHECK: getelementptr inbounds i8, ptr %1, i64 64 +@end + @interface NotNSObject { int these, might, change; } @@ -31,6 +131,8 @@ @interface NotStaticLayout : NotNSObject @implementation NotStaticLayout { int not_static_layout_ivar; } + +// CHECK-LABEL: define internal void @"\01-[NotStaticLayout meth]" -(void)meth { not_static_layout_ivar = 0; // CHECK: load i64, ptr @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar