
The layout and the size of an ObjC interface can change after its corresponding implementation is parsed when synthesized ivars or ivars declared in categories are added to the interface's list of ivars. This can cause clang to mis-compile if the optimization that emits fixed offsets for ivars (see 923ddf65f4e21ec67018cf56e823895de18d83bc) uses an ObjC class layout that is outdated and no longer reflects the current state of the class. For example, when compiling `constant-non-fragile-ivar-offset.m`, clang emits 20 instead of 24 as the offset for `IntermediateClass2Property` as the class layout for `SuperClass2`, which is created when the implementation of IntermediateClass3 is parsed, is outdated when the implementation of `IntermediateClass2` is parsed. This commit invalidates the stale layout information of the class and its subclasses if new ivars are added to the interface. With this change, we can also stop using ObjC implementation decls as the key to retrieve ObjC class layouts information as the layout retrieved using the ObjC interface as the key will always be up to date. rdar://139531391
162 lines
4.1 KiB
Objective-C
162 lines
4.1 KiB
Objective-C
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck %s
|
|
// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-gc -emit-llvm -o - %s | FileCheck %s
|
|
|
|
/*
|
|
|
|
Here is a handy command for looking at llvm-gcc's output:
|
|
llvm-gcc -m64 -fobjc-gc -emit-llvm -S -o - ivar-layout-64.m | \
|
|
grep 'OBJC_CLASS_NAME.* =.*global' | \
|
|
sed -e 's#, section.*# ...#' | \
|
|
sed -e 's#_[0-9]*"#_NNN#' | \
|
|
sort
|
|
|
|
*/
|
|
|
|
@interface B @end
|
|
|
|
@interface A {
|
|
struct s0 {
|
|
int f0;
|
|
int f1;
|
|
} f0;
|
|
id f1;
|
|
__weak B *f2;
|
|
int f3 : 5;
|
|
struct s1 {
|
|
int *f0;
|
|
int *f1;
|
|
} f4[2][1];
|
|
}
|
|
@end
|
|
|
|
@interface C : A
|
|
@property int p3;
|
|
@end
|
|
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"C\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"\11p\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"!`\00"
|
|
|
|
|
|
@implementation C
|
|
@synthesize p3 = _p3;
|
|
@end
|
|
|
|
@interface A()
|
|
@property int p0;
|
|
@property (assign) __strong id p1;
|
|
@property (assign) __weak id p2;
|
|
@end
|
|
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"A\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"\11q\10\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"!q\00"
|
|
|
|
@implementation A
|
|
@synthesize p0 = _p0;
|
|
@synthesize p1 = _p1;
|
|
@synthesize p2 = _p2;
|
|
@end
|
|
|
|
@interface D : A
|
|
@property int p3;
|
|
@end
|
|
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"D\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"\11\A0\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"!\90\00"
|
|
|
|
@implementation D
|
|
@synthesize p3 = _p3;
|
|
@end
|
|
|
|
typedef unsigned short UInt16;
|
|
|
|
|
|
typedef signed char BOOL;
|
|
typedef unsigned int FSCatalogInfoBitmap;
|
|
|
|
@interface NSFileLocationComponent {
|
|
@private
|
|
|
|
id _specifierOrStandardizedPath;
|
|
BOOL _carbonCatalogInfoAndNameAreValid;
|
|
FSCatalogInfoBitmap _carbonCatalogInfoMask;
|
|
id _name;
|
|
id _containerComponent;
|
|
id _presentableName;
|
|
id _iconAsAttributedString;
|
|
}
|
|
@end
|
|
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"NSFileLocationComponent\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"\01\14\00"
|
|
|
|
@implementation NSFileLocationComponent @end
|
|
|
|
@interface NSObject {
|
|
id isa;
|
|
}
|
|
@end
|
|
|
|
@interface Foo : NSObject {
|
|
id ivar;
|
|
|
|
unsigned long bitfield :31;
|
|
unsigned long bitfield2 :1;
|
|
unsigned long bitfield3 :32;
|
|
}
|
|
@end
|
|
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"Foo\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"\02\10\00"
|
|
|
|
@implementation Foo @end
|
|
|
|
// GC layout strings aren't capable of expressing __strong ivars at
|
|
// non-word alignments.
|
|
struct __attribute__((packed)) PackedStruct {
|
|
char c;
|
|
__strong id x;
|
|
};
|
|
@interface Packed : NSObject {
|
|
struct PackedStruct _packed;
|
|
}
|
|
@end
|
|
@implementation Packed @end
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"Packed\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"\01 \00"
|
|
// ' ' == 0x20
|
|
|
|
// Ensure that layout descends into anonymous unions and structs.
|
|
// Hilariously, anonymous unions and structs that appear directly as ivars
|
|
// are completely ignored by layout.
|
|
|
|
@interface AnonymousUnion : NSObject {
|
|
struct {
|
|
union {
|
|
id _object;
|
|
void *_ptr;
|
|
};
|
|
} a;
|
|
}
|
|
@end
|
|
@implementation AnonymousUnion @end
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"AnonymousUnion\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"\02\00"
|
|
|
|
@interface AnonymousStruct : NSObject {
|
|
struct {
|
|
struct {
|
|
id _object;
|
|
__weak id _weakref;
|
|
};
|
|
} a;
|
|
}
|
|
@end
|
|
@implementation AnonymousStruct @end
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"AnonymousStruct\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"\02\10\00"
|
|
// CHECK: @OBJC_CLASS_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"!\00"
|
|
// '!' == 0x21
|