diff options
author | John McCall <rjmccall@apple.com> | 2019-05-30 04:09:01 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2019-05-30 04:09:01 +0000 |
commit | 2c91c3b7af7cd4da64f1babde3798d65522a21e4 (patch) | |
tree | 0be9af0287a5fa41bb097a1bae0d3fa0a8626e07 /clang/test | |
parent | 1f67d9427931f61585d2392c3b958cd2b459af54 (diff) | |
download | bcm5719-llvm-2c91c3b7af7cd4da64f1babde3798d65522a21e4.tar.gz bcm5719-llvm-2c91c3b7af7cd4da64f1babde3798d65522a21e4.zip |
Add the `objc_class_stub` attribute.
Swift requires certain classes to be not just initialized lazily on first
use, but actually allocated lazily using information that is only available
at runtime. This is incompatible with ObjC class initialization, or at least
not efficiently compatible, because there is no meaningful class symbol
that can be put in a class-ref variable at load time. This leaves ObjC
code unable to access such classes, which is undesirable.
objc_class_stub says that class references should be resolved by calling
a new ObjC runtime function with a pointer to a new "class stub" structure.
Non-ObjC compilers (like Swift) can simply emit this structure when ObjC
interop is required for a class that cannot be statically allocated,
then apply this attribute to the `@interface` in the generated ObjC header
for the class.
This attribute can be thought of as a generalization of the existing
`objc_runtime_visible` attribute which permits more efficient class
resolution as well as supporting the additon of categories to the class.
Subclassing these classes from ObjC is currently not allowed.
Patch by Slava Pestov!
llvm-svn: 362054
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CodeGenObjC/class-stubs.m | 84 | ||||
-rw-r--r-- | clang/test/Misc/pragma-attribute-supported-attributes-list.test | 1 | ||||
-rw-r--r-- | clang/test/SemaObjC/class-stub-attr-unsupported.m | 10 | ||||
-rw-r--r-- | clang/test/SemaObjC/class-stub-attr.m | 27 |
4 files changed, 122 insertions, 0 deletions
diff --git a/clang/test/CodeGenObjC/class-stubs.m b/clang/test/CodeGenObjC/class-stubs.m new file mode 100644 index 00000000000..fadb4433b80 --- /dev/null +++ b/clang/test/CodeGenObjC/class-stubs.m @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -emit-llvm -o - %s | FileCheck %s + +// -- classref for the message send in main() +// +// The class is declared with objc_class_stub, so LSB of the class pointer +// must be set to 1. +// +// CHECK-LABEL: @"OBJC_CLASSLIST_REFERENCES_$_" = internal global i8* getelementptr (i8, i8* bitcast (%struct._class_t* @"OBJC_CLASS_$_Base" to i8*), i32 1), align 8 + +// -- classref for the super message send in anotherClassMethod() +// +// Metaclasses do not use the "stub" mechanism and are referenced statically. +// +// CHECK-LABEL: @"OBJC_CLASSLIST_SUP_REFS_$_" = internal global %struct._class_t* @"OBJC_METACLASS_$_Derived", section "__DATA,__objc_superrefs,regular,no_dead_strip", align 8 + +// -- classref for the super message send in anotherInstanceMethod() +// +// The class is declared with objc_class_stub, so LSB of the class pointer +// must be set to 1. +// +// CHECK-LABEL: @"OBJC_CLASSLIST_SUP_REFS_$_.1" = internal global i8* getelementptr (i8, i8* bitcast (%struct._class_t* @"OBJC_CLASS_$_Derived" to i8*), i32 1), section "__DATA,__objc_superrefs,regular,no_dead_strip", align 8 + +// -- category list for class stubs goes in __objc_catlist2. +// +// CHECK-LABEL: @"OBJC_LABEL_STUB_CATEGORY_$" = internal global [1 x i8*] [i8* bitcast (%struct._category_t* @"_OBJC_$_CATEGORY_Derived_$_MyCategory" to i8*)], section "__DATA,__objc_catlist2,regular,no_dead_strip", align 8 + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface Base ++ (void) classMethod; +- (void) instanceMethod; +@end + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface Derived : Base +@end + +int main() { + [Base classMethod]; +} +// CHECK-LABEL: define i32 @main() +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CLASS:%.*]] = call %struct._class_t* @objc_loadClassref(i8** @"OBJC_CLASSLIST_REFERENCES_$_") +// CHECK-NEXT: [[SELECTOR:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_ +// CHECK-NEXT: [[RECEIVER:%.*]] = bitcast %struct._class_t* [[CLASS]] to i8* +// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*)*)(i8* [[RECEIVER]], i8* [[SELECTOR]]) +// CHECK-NEXT: ret i32 0 + +// CHECK-LABEL: declare extern_weak %struct._class_t* @objc_loadClassref(i8**) +// CHECK-SAME: [[ATTRLIST:#.*]] + +@implementation Derived (MyCategory) + ++ (void) anotherClassMethod { + [super classMethod]; +} +// CHECK-LABEL: define internal void @"\01+[Derived(MyCategory) anotherClassMethod]"(i8* %self, i8* %_cmd) #0 { +// CHECK-NEXT: entry: +// CHECK: [[SUPER:%.*]] = alloca %struct._objc_super, align 8 +// CHECK: [[METACLASS_REF:%.*]] = load %struct._class_t*, %struct._class_t** @"OBJC_CLASSLIST_SUP_REFS_$_", align 8 +// CHECK: [[CAST_METACLASS_REF:%.*]] = bitcast %struct._class_t* [[METACLASS_REF]] to i8* +// CHECK: [[DEST:%.*]] = getelementptr inbounds %struct._objc_super, %struct._objc_super* [[SUPER]], i32 0, i32 1 +// CHECK: store i8* [[CAST_METACLASS_REF]], i8** [[DEST]], align 8 +// CHECK: call void bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper2 to void (%struct._objc_super*, i8*)*)(%struct._objc_super* [[SUPER]], i8* {{%.*}}) +// CHECK: ret void + +- (void) anotherInstanceMethod { + [super instanceMethod]; +} +// CHECK-LABEL: define internal void @"\01-[Derived(MyCategory) anotherInstanceMethod]"(%0* %self, i8* %_cmd) #0 { +// CHECK-NEXT: entry: +// CHECK: [[SUPER:%.*]] = alloca %struct._objc_super, align 8 +// CHECK: [[CLASS_REF:%.*]] = call %struct._class_t* @objc_loadClassref(i8** @"OBJC_CLASSLIST_SUP_REFS_$_.1") +// CHECK: [[CAST_CLASS_REF:%.*]] = bitcast %struct._class_t* [[CLASS_REF]] to i8* +// CHECK: [[DEST:%.*]] = getelementptr inbounds %struct._objc_super, %struct._objc_super* [[SUPER]], i32 0, i32 1 +// CHECK: store i8* [[CAST_CLASS_REF]], i8** [[DEST]], align 8 +// CHECK: call void bitcast (i8* (%struct._objc_super*, i8*, ...)* @objc_msgSendSuper2 to void (%struct._objc_super*, i8*)*)(%struct._objc_super* [[SUPER]], i8* {{%.*}}) +// CHECK: ret void + +@end + +// -- calls to objc_loadClassRef() are readnone +// CHECK: attributes [[ATTRLIST]] = { nounwind nonlazybind readnone } diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index f138deac57e..f85c89ae015 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -97,6 +97,7 @@ // CHECK-NEXT: ObjCBridge (SubjectMatchRule_record, SubjectMatchRule_type_alias) // CHECK-NEXT: ObjCBridgeMutable (SubjectMatchRule_record) // CHECK-NEXT: ObjCBridgeRelated (SubjectMatchRule_record) +// CHECK-NEXT: ObjCClassStub (SubjectMatchRule_objc_interface) // CHECK-NEXT: ObjCDesignatedInitializer (SubjectMatchRule_objc_method) // CHECK-NEXT: ObjCException (SubjectMatchRule_objc_interface) // CHECK-NEXT: ObjCExplicitProtocolImpl (SubjectMatchRule_objc_protocol) diff --git a/clang/test/SemaObjC/class-stub-attr-unsupported.m b/clang/test/SemaObjC/class-stub-attr-unsupported.m new file mode 100644 index 00000000000..cc5243fac6e --- /dev/null +++ b/clang/test/SemaObjC/class-stub-attr-unsupported.m @@ -0,0 +1,10 @@ +// RUN: %clang -target i386-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target i386-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) // expected-warning {{'objc_class_stub' attribute ignored}} +__attribute__((objc_subclassing_restricted)) +@interface StubClass : NSObject +@end diff --git a/clang/test/SemaObjC/class-stub-attr.m b/clang/test/SemaObjC/class-stub-attr.m new file mode 100644 index 00000000000..46c07d8b5f7 --- /dev/null +++ b/clang/test/SemaObjC/class-stub-attr.m @@ -0,0 +1,27 @@ +// RUN: %clang -target x86_64-apple-darwin -fsyntax-only -Xclang -verify %s +// RUN: %clang -target x86_64-apple-darwin -x objective-c++ -fsyntax-only -Xclang -verify %s + +@interface NSObject +@end + +__attribute__((objc_class_stub)) +@interface MissingSubclassingRestrictedAttribute : NSObject // expected-error {{'objc_class_stub' attribute cannot be specified on a class that does not have the 'objc_subclassing_restricted' attribute}} +@end + +__attribute__((objc_class_stub)) +__attribute__((objc_subclassing_restricted)) +@interface ValidClassStubAttribute : NSObject +@end + +@implementation ValidClassStubAttribute // expected-error {{cannot declare implementation of a class declared with the 'objc_class_stub' attribute}} +@end + +@implementation ValidClassStubAttribute (MyCategory) +@end + +__attribute__((objc_class_stub(123))) // expected-error {{'objc_class_stub' attribute takes no arguments}} +@interface InvalidClassStubAttribute : NSObject +@end + +__attribute__((objc_class_stub)) // expected-error {{'objc_class_stub' attribute only applies to Objective-C interfaces}} +int cannotHaveObjCClassStubAttribute() {} |