diff options
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CodeGenObjC/arc.m | 16 | ||||
-rw-r--r-- | clang/test/SemaObjC/instancetype.m | 38 | ||||
-rw-r--r-- | clang/test/SemaObjC/related-result-type-inference.m | 2 | ||||
-rw-r--r-- | clang/test/SemaObjCXX/instancetype.mm | 216 |
4 files changed, 261 insertions, 11 deletions
diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m index 0ef3d895105..3778625aa97 100644 --- a/clang/test/CodeGenObjC/arc.m +++ b/clang/test/CodeGenObjC/arc.m @@ -621,7 +621,9 @@ void test21(unsigned n) { // CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]] // CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8* -// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST27]]* +// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST27]]* [[T3]] to i8* // CHECK-NEXT: store i32 {{[0-9]+}}, i32* [[DEST]] // CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8* @@ -685,7 +687,9 @@ static id _test29_allocator = 0; // Return statement. // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[CALL]] // CHECK-NEXT: [[CALL:%.*]] = bitcast -// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[CALL]]) [[NUW]] +// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[CALL]]) [[NUW]] +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST29]]* +// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST29]]* [[T1]] to i8* // CHECK-NEXT: store i32 1, i32* [[CLEANUP]] // Cleanup. @@ -739,7 +743,9 @@ static id _test29_allocator = 0; // Return statement. // CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8* -// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]] +// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]] +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST29]]* +// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST29]]* [[T1]] to i8* // CHECK-NEXT: store i32 1, i32* [[CLEANUP]] // Cleanup. @@ -794,7 +800,9 @@ char *helper; // Return. // CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]] // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8* -// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST30]]* +// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST30]]* [[T1]] to i8* // CHECK-NEXT: store i32 1 // Cleanup. diff --git a/clang/test/SemaObjC/instancetype.m b/clang/test/SemaObjC/instancetype.m index 40f35d93b2b..8137964737e 100644 --- a/clang/test/SemaObjC/instancetype.m +++ b/clang/test/SemaObjC/instancetype.m @@ -5,9 +5,9 @@ #endif @interface Root -+ (instancetype)alloc; ++ (instancetype)alloc; // expected-note {{explicitly declared 'instancetype'}} - (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}} -- (instancetype)self; +- (instancetype)self; // expected-note {{explicitly declared 'instancetype'}} - (Class)class; @property (assign) Root *selfProp; @@ -143,7 +143,7 @@ void test_instancetype_narrow_method_search() { @implementation Subclass4 + (id)alloc { - return self; // expected-warning{{incompatible pointer types casting 'Class' to type 'Subclass4 *'}} + return self; // expected-warning{{incompatible pointer types returning 'Class' from a function with result type 'Subclass4 *'}} } - (Subclass3 *)init { return 0; } // don't complain: we lost the related return type @@ -164,14 +164,14 @@ void test_instancetype_inherited() { // Check that related return types tighten up the semantics of // Objective-C method implementations. @implementation Subclass2 -- (instancetype)initSubclass2 { +- (instancetype)initSubclass2 { // expected-note {{explicitly declared 'instancetype'}} Subclass1 *sc1 = [[Subclass1 alloc] init]; - return sc1; // expected-warning{{incompatible pointer types casting 'Subclass1 *' to type 'Subclass2 *'}} + return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}} } - (void)methodOnSubclass2 {} - (id)self { Subclass1 *sc1 = [[Subclass1 alloc] init]; - return sc1; // expected-warning{{incompatible pointer types casting 'Subclass1 *' to type 'Subclass2 *'}} + return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}} } @end @@ -188,3 +188,29 @@ void test_instancetype_inherited() { @end +// rdar://12493140 +@protocol P4 +- (instancetype) foo; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}} +@end +@interface A4 : Root <P4> +- (instancetype) bar; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}} +- (instancetype) baz; // expected-note {{overridden method returns an instance of its class type}} expected-note {{previous definition is here}} +@end +@interface B4 : Root @end + +@implementation A4 { + B4 *_b; +} +- (id) foo { + return _b; // expected-warning {{incompatible pointer types returning 'B4 *' from a function with result type 'A4 *'}} +} +- (id) bar { + return _b; // expected-warning {{incompatible pointer types returning 'B4 *' from a function with result type 'A4 *'}} +} + +// This is really just to ensure that we don't crash. +// FIXME: only one diagnostic, please +- (float) baz { // expected-warning {{method is expected to return an instance of its class type 'A4', but is declared to return 'float'}} expected-warning {{conflicting return type in implementation}} + return 0; +} +@end diff --git a/clang/test/SemaObjC/related-result-type-inference.m b/clang/test/SemaObjC/related-result-type-inference.m index b1d77dc1727..50aaf2da4d9 100644 --- a/clang/test/SemaObjC/related-result-type-inference.m +++ b/clang/test/SemaObjC/related-result-type-inference.m @@ -175,7 +175,7 @@ void test_inference() { @implementation Fail - (id<X>) initWithX { - return (id)self; // expected-warning {{returning 'Fail *' from a function with incompatible result type 'id<X>'}} + return (id)self; // expected-warning {{casting 'Fail *' to incompatible type 'id<X>'}} } @end diff --git a/clang/test/SemaObjCXX/instancetype.mm b/clang/test/SemaObjCXX/instancetype.mm new file mode 100644 index 00000000000..bbf100ef045 --- /dev/null +++ b/clang/test/SemaObjCXX/instancetype.mm @@ -0,0 +1,216 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +#if !__has_feature(objc_instancetype) +# error Missing 'instancetype' feature macro. +#endif + +@interface Root ++ (instancetype)alloc; +- (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}} +- (instancetype)self; // expected-note {{explicitly declared 'instancetype'}} +- (Class)class; + +@property (assign) Root *selfProp; +- (instancetype)selfProp; +@end + +@protocol Proto1 +@optional +- (instancetype)methodInProto1; +@end + +@protocol Proto2 +@optional +- (instancetype)methodInProto2; // expected-note{{overridden method returns an instance of its class type}} +- (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}} +@end + +@interface Subclass1 : Root +- (instancetype)initSubclass1; +- (void)methodOnSubclass1; ++ (instancetype)allocSubclass1; +@end + +@interface Subclass2 : Root +- (instancetype)initSubclass2; +- (void)methodOnSubclass2; +@end + +// Sanity check: the basic initialization pattern. +void test_instancetype_alloc_init_simple() { + Root *r1 = [[Root alloc] init]; + Subclass1 *sc1 = [[Subclass1 alloc] init]; +} + +// Test that message sends to instancetype methods have the right type. +void test_instancetype_narrow_method_search() { + // instancetype on class methods + Subclass1 *sc1 = [[Subclass1 alloc] initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}} + Subclass2 *sc2 = [[Subclass2 alloc] initSubclass2]; // okay + + // instancetype on instance methods + [[[Subclass1 alloc] init] methodOnSubclass2]; // expected-warning{{'Subclass1' may not respond to 'methodOnSubclass2'}} + [[[Subclass2 alloc] init] methodOnSubclass2]; + + // instancetype on class methods using protocols + typedef Subclass1<Proto1> SC1Proto1; + typedef Subclass1<Proto2> SC1Proto2; + [[SC1Proto1 alloc] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}} + [[SC1Proto2 alloc] methodInProto2]; + + // instancetype on instance methods + Subclass1<Proto1> *sc1proto1 = 0; + [[sc1proto1 self] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}} + Subclass1<Proto2> *sc1proto2 = 0; + [[sc1proto2 self] methodInProto2]; + + // Exact type checks + typeof([[Subclass1 alloc] init]) *ptr1 = (Subclass1 **)0; + typeof([[Subclass2 alloc] init]) *ptr2 = (Subclass2 **)0; + + // Message sends to Class. + Subclass1<Proto1> *sc1proto1_2 = [[[sc1proto1 class] alloc] init]; + + // Property access + [sc1proto1.self methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}} + [sc1proto2.self methodInProto2]; + [Subclass1.alloc initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}} + [Subclass2.alloc initSubclass2]; + + [sc1proto1.selfProp methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}} + [sc1proto2.selfProp methodInProto2]; +} + +// Test that message sends to super methods have the right type. +@interface Subsubclass1 : Subclass1 +- (instancetype)initSubclass1; ++ (instancetype)allocSubclass1; + +- (void)onlyInSubsubclass1; +@end + +@implementation Subsubclass1 +- (instancetype)initSubclass1 { + // Check based on method search. + [[super initSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}} + [super.initSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}} + + self = [super init]; // common pattern + + // Exact type check. + typeof([super initSubclass1]) *ptr1 = (Subsubclass1**)0; + + return self; +} + ++ (instancetype)allocSubclass1 { + // Check based on method search. + [[super allocSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}} + + // The ASTs don't model super property accesses well enough to get this right + [super.allocSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}} + + // Exact type check. + typeof([super allocSubclass1]) *ptr1 = (Subsubclass1**)0; + + return [super allocSubclass1]; +} + +- (void)onlyInSubsubclass1 {} +@end + +// Check compatibility rules for inheritance of related return types. +@class Subclass4; + +@interface Subclass3 <Proto1, Proto2> +- (Subclass3 *)methodInProto1; +- (Subclass4 *)methodInProto2; // expected-warning{{method is expected to return an instance of its class type 'Subclass3', but is declared to return 'Subclass4 *'}} +@end + +@interface Subclass4 : Root ++ (Subclass4 *)alloc; // okay +- (Subclass3 *)init; // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}} +- (id)self; // expected-note{{overridden method is part of the 'self' method family}} +- (instancetype)initOther; +@end + +@protocol Proto3 <Proto1, Proto2> +@optional +- (id)methodInProto1; +- (Subclass1 *)methodInProto2; +- (int)otherMethodInProto2; // expected-warning{{protocol method is expected to return an instance of the implementing class, but is declared to return 'int'}} +@end + +@implementation Subclass4 ++ (id)alloc { + return self; // FIXME: we accept this in ObjC++ but not ObjC? +} + +- (Subclass3 *)init { return 0; } // don't complain: we lost the related return type + +- (Subclass3 *)self { return 0; } // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}} + +- (Subclass4 *)initOther { return 0; } + +@end + +// Check that inherited related return types influence the types of +// message sends. +void test_instancetype_inherited() { + [[Subclass4 alloc] initSubclass1]; // expected-warning{{'Subclass4' may not respond to 'initSubclass1'}} + [[Subclass4 alloc] initOther]; +} + +// Check that related return types tighten up the semantics of +// Objective-C method implementations. +@implementation Subclass2 +- (instancetype)initSubclass2 { // expected-note {{explicitly declared 'instancetype'}} + Subclass1 *sc1 = [[Subclass1 alloc] init]; + return sc1; // expected-error{{cannot initialize return object of type 'Subclass2 *' with an lvalue of type 'Subclass1 *'}} +} +- (void)methodOnSubclass2 {} +- (id)self { + Subclass1 *sc1 = [[Subclass1 alloc] init]; + return sc1; // expected-error{{cannot initialize return object of type 'Subclass2 *' with an lvalue of type 'Subclass1 *'}} +} +@end + +@interface MyClass : Root ++ (int)myClassMethod; +@end + +@implementation MyClass ++ (int)myClassMethod { return 0; } + +- (void)blah { + int i = [[MyClass self] myClassMethod]; +} + +@end + +// rdar://12493140 +@protocol P4 +- (instancetype) foo; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}} +@end +@interface A4 : Root <P4> +- (instancetype) bar; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}} +- (instancetype) baz; // expected-note {{overridden method returns an instance of its class type}} expected-note {{previous definition is here}} +@end +@interface B4 : Root @end + +@implementation A4 { + B4 *_b; +} +- (id) foo { + return _b; // expected-error {{cannot initialize return object of type 'A4 *' with an lvalue of type 'B4 *'}} +} +- (id) bar { + return _b; // expected-error {{cannot initialize return object of type 'A4 *' with an lvalue of type 'B4 *'}} +} + +// This is really just to ensure that we don't crash. +// FIXME: only one diagnostic, please +- (float) baz { // expected-warning {{method is expected to return an instance of its class type 'A4', but is declared to return 'float'}} expected-warning {{conflicting return type in implementation}} + return 0; +} +@end |