summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/CodeGenObjC/parameterized_classes.m63
-rw-r--r--clang/test/PCH/objc_parameterized_classes.m5
-rw-r--r--clang/test/SemaObjC/parameterized_classes.m18
-rw-r--r--clang/test/SemaObjC/parameterized_classes_subst.m372
-rw-r--r--clang/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h21
-rw-r--r--clang/test/SemaObjCXX/nullability-pragmas.mm12
6 files changed, 475 insertions, 16 deletions
diff --git a/clang/test/CodeGenObjC/parameterized_classes.m b/clang/test/CodeGenObjC/parameterized_classes.m
new file mode 100644
index 00000000000..1d8e9a25993
--- /dev/null
+++ b/clang/test/CodeGenObjC/parameterized_classes.m
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fobjc-arc -emit-llvm -o - %s | FileCheck %s
+
+// Parameterized classes have no effect on code generation; this test
+// mainly verifies that CodeGen doesn't assert when substituted types
+// in uses of methods don't line up exactly with the parameterized
+// types in the method declarations due to type erasure. "Not crash"
+// is the only interesting criteria here.
+
+@protocol NSObject
+@end
+
+@protocol NSCopying
+@end
+
+__attribute__((objc_root_class))
+@interface NSObject <NSObject>
+@end
+
+@interface NSString : NSObject <NSCopying>
+@end
+
+@interface NSMutableArray<T> : NSObject <NSCopying>
+@property (copy,nonatomic) T firstObject;
+- (void)addObject:(T)object;
+- (void)sortWithFunction:(int (*)(T, T))function;
+- (void)getObjects:(T __strong *)objects length:(unsigned*)length;
+@end
+
+NSString *getFirstObjectProp(NSMutableArray<NSString *> *array) {
+ return array.firstObject;
+}
+
+NSString *getFirstObjectMethod(NSMutableArray<NSString *> *array) {
+ return [array firstObject];
+}
+
+void addObject(NSMutableArray<NSString *> *array, NSString *obj) {
+ [array addObject: obj];
+}
+
+int compareStrings(NSString *x, NSString *y) { return 0; }
+int compareBlocks(NSString * (^x)(NSString *),
+ NSString * (^y)(NSString *)) { return 0; }
+
+void sortTest(NSMutableArray<NSString *> *array,
+ NSMutableArray<NSString * (^)(NSString *)> *array2) {
+ [array sortWithFunction: &compareStrings];
+ [array2 sortWithFunction: &compareBlocks];
+}
+
+void getObjectsTest(NSMutableArray<NSString *> *array) {
+ NSString * __strong *objects;
+ unsigned length;
+ [array getObjects: objects length: &length];
+}
+
+void printMe(NSString *name) { }
+
+// CHECK-LABEL: define void @blockTest
+void blockTest(NSMutableArray<void (^)(void)> *array, NSString *name) {
+ // CHECK: call i8* @objc_retainBlock
+ [array addObject: ^ { printMe(name); }];
+}
diff --git a/clang/test/PCH/objc_parameterized_classes.m b/clang/test/PCH/objc_parameterized_classes.m
index f4fd0926be3..616d4a2659d 100644
--- a/clang/test/PCH/objc_parameterized_classes.m
+++ b/clang/test/PCH/objc_parameterized_classes.m
@@ -21,6 +21,7 @@ __attribute__((objc_root_class))
typedef PC1<id, NSObject *> PC1Specialization1;
+typedef PC1Specialization1 <NSObject> PC1Specialization2;
#else
@interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id}}
@@ -29,6 +30,8 @@ typedef PC1<id, NSObject *> PC1Specialization1;
// expected-note@15{{type parameter 'U' declared here}}
@end
-typedef PC1Specialization1<id, NSObject *> PC1Specialization2; // expected-error{{type arguments cannot be applied to already-specialized class type 'PC1Specialization1' (aka 'PC1<id,NSObject *>')}}
+typedef PC1Specialization1<id, NSObject *> PC1Specialization3; // expected-error{{type arguments cannot be applied to already-specialized class type 'PC1Specialization1' (aka 'PC1<id,NSObject *>')}}
+
+typedef PC1Specialization2<id, NSObject *> PC1Specialization4; // expected-error{{already-specialized class type 'PC1Specialization2' (aka 'PC1Specialization1<NSObject>')}}
#endif
diff --git a/clang/test/SemaObjC/parameterized_classes.m b/clang/test/SemaObjC/parameterized_classes.m
index bf81ad9a078..9834f7cd11f 100644
--- a/clang/test/SemaObjC/parameterized_classes.m
+++ b/clang/test/SemaObjC/parameterized_classes.m
@@ -173,29 +173,17 @@ __attribute__((objc_root_class))
T object;
}
-- (U)method:(V)param; // expected-note{{passing argument to parameter 'param' here}}
+- (U)method:(V)param;
@end
@interface PC20<T, U, V> (Cat1)
-- (U)catMethod:(V)param; // expected-note{{passing argument to parameter 'param' here}}
+- (U)catMethod:(V)param;
@end
@interface PC20<X, Y, Z>()
-- (X)extMethod:(Y)param; // expected-note{{passing argument to parameter 'param' here}}
+- (X)extMethod:(Y)param;
@end
-void test_PC20_unspecialized(PC20 *pc20) {
- // FIXME: replace type parameters with underlying types?
- int *ip = [pc20 method: 0]; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'U' (aka 'NSObject *')}}
- [pc20 method: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
-
- ip = [pc20 catMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'U' (aka 'NSObject *')}}
- [pc20 catMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
-
- ip = [pc20 extMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'X' (aka 'id')}}
- [pc20 extMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'Y' (aka 'NSObject *')}}
-}
-
// --------------------------------------------------------------------------
// Parsing type arguments.
// --------------------------------------------------------------------------
diff --git a/clang/test/SemaObjC/parameterized_classes_subst.m b/clang/test/SemaObjC/parameterized_classes_subst.m
new file mode 100644
index 00000000000..186800cddd7
--- /dev/null
+++ b/clang/test/SemaObjC/parameterized_classes_subst.m
@@ -0,0 +1,372 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -Wnullable-to-nonnull-conversion %s -verify
+//
+// Test the substitution of type arguments for type parameters when
+// using parameterized classes in Objective-C.
+
+__attribute__((objc_root_class))
+@interface NSObject
++ (instancetype)alloc;
+- (instancetype)init;
+@end
+
+@protocol NSCopying
+@end
+
+@interface NSString : NSObject <NSCopying>
+@end
+
+@interface NSNumber : NSObject <NSCopying>
+@end
+
+@interface NSArray<T> : NSObject <NSCopying> {
+@public
+ T *data; // don't try this at home
+}
+- (T)objectAtIndexedSubscript:(int)index;
++ (NSArray<T> *)array;
++ (void)setArray:(NSArray <T> *)array;
+@property (copy,nonatomic) T lastObject;
+@end
+
+@interface NSMutableArray<T> : NSArray<T>
+-(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}}
+- (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}}
+@end
+
+@interface NSStringArray : NSArray<NSString *>
+@end
+
+@interface NSSet<T> : NSObject <NSCopying>
+- (T)firstObject;
+@property (nonatomic, copy) NSArray<T> *allObjects;
+@end
+
+// Parameterized inheritance (simple case)
+@interface NSMutableSet<U : id<NSCopying>> : NSSet<U>
+- (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}}
+@end
+
+@interface Widget : NSObject <NSCopying>
+@end
+
+// Non-parameterized class inheriting from a specialization of a
+// parameterized class.
+@interface WidgetSet : NSMutableSet<Widget *>
+@end
+
+// Parameterized inheritance with a more interesting transformation in
+// the specialization.
+@interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*>
+@end
+
+// Inheriting from an unspecialized form of a parameterized type.
+@interface UntypedMutableSet : NSMutableSet
+@end
+
+@interface Window : NSObject
+@end
+
+@interface NSDictionary<K, V> : NSObject <NSCopying>
+- (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}}
+@end
+
+@interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V>
+- (void)setObject:(V)object forKeyedSubscript:(K)key;
+// expected-note@-1 {{parameter 'object' here}}
+// expected-note@-2 {{parameter 'object' here}}
+// expected-note@-3 {{parameter 'key' here}}
+// expected-note@-4 {{parameter 'key' here}}
+
+@property (strong) K someRandomKey;
+@end
+
+@interface WindowArray : NSArray<Window *>
+@end
+
+@interface NSSet<T> (Searching)
+- (T)findObject:(T)object;
+@end
+
+@interface NSView : NSObject
+@end
+
+@interface NSControl : NSView
+- (void)toggle;
+@end
+
+@interface NSViewController<ViewType : NSView *> : NSObject
+@property (nonatomic,retain) ViewType view;
+@end
+
+// --------------------------------------------------------------------------
+// Nullability
+// --------------------------------------------------------------------------
+typedef NSControl * _Nonnull Nonnull_NSControl;
+
+@interface NSNullableTest<ViewType : NSView *> : NSObject
+- (ViewType)view;
+- (nullable ViewType)maybeView;
+@end
+
+@interface NSNullableTest2<ViewType : NSView * _Nullable> : NSObject // expected-error{{type parameter 'ViewType' bound 'NSView * _Nullable' cannot explicitly specify nullability}}
+@end
+
+void test_nullability(void) {
+ NSControl * _Nonnull nonnull_NSControl;
+
+ // Nullability introduced by substitution.
+ NSNullableTest<NSControl *> *unspecifiedControl;
+ nonnull_NSControl = [unspecifiedControl view];
+ nonnull_NSControl = [unspecifiedControl maybeView]; // expected-warning{{from nullable pointer 'NSControl * _Nullable' to non-nullable pointer type 'NSControl * _Nonnull'}}
+
+ // Nullability overridden by substitution.
+ NSNullableTest<Nonnull_NSControl> *nonnullControl;
+ nonnull_NSControl = [nonnullControl view];
+ nonnull_NSControl = [nonnullControl maybeView]; // expected-warning{{from nullable pointer 'Nonnull_NSControl _Nullable' (aka 'NSControl *') to non-nullable pointer type 'NSControl * _Nonnull'}}
+
+ // Nullability cannot be specified directly on a type argument.
+ NSNullableTest<NSControl * _Nonnull> *nonnullControl2; // expected-error{{type argument 'NSControl *' cannot explicitly specify nullability}}
+}
+
+// --------------------------------------------------------------------------
+// Message sends.
+// --------------------------------------------------------------------------
+void test_message_send_result(
+ NSSet<NSString *> *stringSet,
+ NSMutableSet<NSString *> *mutStringSet,
+ WidgetSet *widgetSet,
+ UntypedMutableSet *untypedMutSet,
+ MutableSetOfArrays<NSString *> *mutStringArraySet,
+ NSSet *set,
+ NSMutableSet *mutSet,
+ MutableSetOfArrays *mutArraySet,
+ NSArray<NSString *> *stringArray,
+ void (^block)(void)) {
+ int *ip;
+ ip = [stringSet firstObject]; // expected-warning{{from 'NSString *'}}
+ ip = [mutStringSet firstObject]; // expected-warning{{from 'NSString *'}}
+ ip = [widgetSet firstObject]; // expected-warning{{from 'Widget *'}}
+ ip = [untypedMutSet firstObject]; // expected-warning{{from 'id'}}
+ ip = [mutStringArraySet firstObject]; // expected-warning{{from 'NSArray<NSString *> *'}}
+ ip = [set firstObject]; // expected-warning{{from 'id'}}
+ ip = [mutSet firstObject]; // expected-warning{{from 'id'}}
+ ip = [mutArraySet firstObject]; // expected-warning{{from 'id'}}
+ ip = [block firstObject]; // expected-warning{{from 'id'}}
+
+ ip = [stringSet findObject:@"blah"]; // expected-warning{{from 'NSString *'}}
+
+ // Class messages.
+ ip = [NSSet<NSString *> alloc]; // expected-warning{{from 'NSSet<NSString *> *'}}
+ ip = [NSSet alloc]; // expected-warning{{from 'NSSet *'}}
+ ip = [MutableSetOfArrays<NSString *> alloc]; // expected-warning{{from 'MutableSetOfArrays<NSString *> *'}}
+ ip = [MutableSetOfArrays alloc]; // expected-warning{{from 'MutableSetOfArrays *'}}
+ ip = [NSArray<NSString *> array]; // expected-warning{{from 'NSArray<NSString *> *'}}
+ ip = [NSArray<NSString *><NSCopying> array]; // expected-warning{{from 'NSArray<NSString *> *'}}
+
+ ip = [[NSMutableArray<NSString *> alloc] init]; // expected-warning{{from 'NSMutableArray<NSString *> *'}}
+
+ [[NSMutableArray alloc] initWithArray: stringArray]; // okay
+ [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay
+ [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-warning{{sending 'NSArray<NSString *> *' to parameter of type 'NSArray<NSNumber *> *'}}
+}
+
+void test_message_send_param(
+ NSMutableSet<NSString *> *mutStringSet,
+ WidgetSet *widgetSet,
+ UntypedMutableSet *untypedMutSet,
+ MutableSetOfArrays<NSString *> *mutStringArraySet,
+ NSMutableSet *mutSet,
+ MutableSetOfArrays *mutArraySet,
+ void (^block)(void)) {
+ Window *window;
+
+ [mutStringSet addObject: window]; // expected-warning{{parameter of type 'NSString *'}}
+ [widgetSet addObject: window]; // expected-warning{{parameter of type 'Widget *'}}
+ [untypedMutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}
+ [mutStringArraySet addObject: window]; // expected-warning{{parameter of type 'NSArray<NSString *> *'}}
+ [mutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}
+ [mutArraySet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}
+ [block addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Property accesses.
+// --------------------------------------------------------------------------
+void test_property_read(
+ NSSet<NSString *> *stringSet,
+ NSMutableSet<NSString *> *mutStringSet,
+ WidgetSet *widgetSet,
+ UntypedMutableSet *untypedMutSet,
+ MutableSetOfArrays<NSString *> *mutStringArraySet,
+ NSSet *set,
+ NSMutableSet *mutSet,
+ MutableSetOfArrays *mutArraySet,
+ NSMutableDictionary *mutDict) {
+ int *ip;
+ ip = stringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}}
+ ip = mutStringSet.allObjects; // expected-warning{{from 'NSArray<NSString *> *'}}
+ ip = widgetSet.allObjects; // expected-warning{{from 'NSArray<Widget *> *'}}
+ ip = untypedMutSet.allObjects; // expected-warning{{from 'NSArray *'}}
+ ip = mutStringArraySet.allObjects; // expected-warning{{from 'NSArray<NSArray<NSString *> *> *'}}
+ ip = set.allObjects; // expected-warning{{from 'NSArray *'}}
+ ip = mutSet.allObjects; // expected-warning{{from 'NSArray *'}}
+ ip = mutArraySet.allObjects; // expected-warning{{from 'NSArray *'}}
+
+ ip = mutDict.someRandomKey; // expected-warning{{from 'id'}}
+}
+
+void test_property_write(
+ NSMutableSet<NSString *> *mutStringSet,
+ WidgetSet *widgetSet,
+ UntypedMutableSet *untypedMutSet,
+ MutableSetOfArrays<NSString *> *mutStringArraySet,
+ NSMutableSet *mutSet,
+ MutableSetOfArrays *mutArraySet,
+ NSMutableDictionary *mutDict) {
+ int *ip;
+
+ mutStringSet.allObjects = ip; // expected-warning{{to 'NSArray<NSString *> *'}}
+ widgetSet.allObjects = ip; // expected-warning{{to 'NSArray<Widget *> *'}}
+ untypedMutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}}
+ mutStringArraySet.allObjects = ip; // expected-warning{{to 'NSArray<NSArray<NSString *> *> *'}}
+ mutSet.allObjects = ip; // expected-warning{{to 'NSArray *'}}
+ mutArraySet.allObjects = ip; // expected-warning{{to 'NSArray *'}}
+
+ mutDict.someRandomKey = ip; // expected-warning{{to 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Subscripting
+// --------------------------------------------------------------------------
+void test_subscripting(
+ NSArray<NSString *> *stringArray,
+ NSMutableArray<NSString *> *mutStringArray,
+ NSArray *array,
+ NSMutableArray *mutArray,
+ NSDictionary<NSString *, Widget *> *stringWidgetDict,
+ NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict,
+ NSDictionary *dict,
+ NSMutableDictionary *mutDict) {
+ int *ip;
+ NSString *string;
+ Widget *widget;
+ Window *window;
+
+ ip = stringArray[0]; // expected-warning{{from 'NSString *'}}
+
+ ip = mutStringArray[0]; // expected-warning{{from 'NSString *'}}
+ mutStringArray[0] = ip; // expected-warning{{parameter of type 'NSString *'}}
+
+ ip = array[0]; // expected-warning{{from 'id'}}
+
+ ip = mutArray[0]; // expected-warning{{from 'id'}}
+ mutArray[0] = ip; // expected-warning{{parameter of type 'id'}}
+
+ ip = stringWidgetDict[string]; // expected-warning{{from 'Widget *'}}
+ widget = stringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}}
+
+ ip = mutStringWidgetDict[string]; // expected-warning{{from 'Widget *'}}
+ widget = mutStringWidgetDict[widget]; // expected-warning{{to parameter of type 'NSString *'}}
+ mutStringWidgetDict[string] = ip; // expected-warning{{to parameter of type 'Widget *'}}
+ mutStringWidgetDict[widget] = widget; // expected-warning{{to parameter of type 'NSString *'}}
+
+ ip = dict[string]; // expected-warning{{from 'id'}}
+
+ ip = mutDict[string]; // expected-warning{{from 'id'}}
+ mutDict[string] = ip; // expected-warning{{to parameter of type 'id'}}
+
+ widget = mutDict[window];
+ mutDict[window] = widget; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Instance variable access.
+// --------------------------------------------------------------------------
+void test_instance_variable(NSArray<NSString *> *stringArray,
+ NSArray *array) {
+ int *ip;
+
+ ip = stringArray->data; // expected-warning{{from 'NSString **'}}
+ ip = array->data; // expected-warning{{from 'id *'}}
+}
+
+@implementation WindowArray
+- (void)testInstanceVariable {
+ int *ip;
+
+ ip = data; // expected-warning{{from 'Window **'}}
+}
+@end
+
+// --------------------------------------------------------------------------
+// Implicit conversions.
+// --------------------------------------------------------------------------
+void test_implicit_conversions(NSArray<NSString *> *stringArray,
+ NSArray<NSNumber *> *numberArray,
+ NSMutableArray<NSString *> *mutStringArray,
+ NSArray *array,
+ NSMutableArray *mutArray) {
+ // Specialized -> unspecialized (same level)
+ array = stringArray;
+
+ // Unspecialized -> specialized (same level)
+ stringArray = array;
+
+ // Specialized -> specialized failure (same level).
+ stringArray = numberArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSString *> *' from 'NSArray<NSNumber *> *'}}
+
+ // Specialized -> specialized (different levels).
+ stringArray = mutStringArray;
+
+ // Specialized -> specialized failure (different levels).
+ numberArray = mutStringArray; // expected-warning{{incompatible pointer types assigning to 'NSArray<NSNumber *> *' from 'NSMutableArray<NSString *> *'}}
+
+ // Unspecialized -> specialized (different levels).
+ stringArray = mutArray;
+
+ // Specialized -> unspecialized (different levels).
+ array = mutStringArray;
+}
+
+// --------------------------------------------------------------------------
+// Ternary operator
+// --------------------------------------------------------------------------
+void test_ternary_operator(NSArray<NSString *> *stringArray,
+ NSArray<NSNumber *> *numberArray,
+ NSMutableArray<NSString *> *mutStringArray,
+ NSStringArray *stringArray2,
+ NSArray *array,
+ NSMutableArray *mutArray,
+ int cond) {
+ int *ip;
+ id object;
+
+ ip = cond ? stringArray : mutStringArray; // expected-warning{{from 'NSArray<NSString *> *'}}
+ ip = cond ? mutStringArray : stringArray; // expected-warning{{from 'NSArray<NSString *> *'}}
+
+ ip = cond ? stringArray2 : mutStringArray; // expected-warning{{from 'NSArray<NSString *><NSCopying> *'}}
+ ip = cond ? mutStringArray : stringArray2; // expected-warning{{from 'NSArray<NSString *><NSCopying> *'}}
+
+ ip = cond ? stringArray : mutArray; // FIXME: expected-warning{{from 'NSArray<NSString *> *'}}
+
+ object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}}
+}
+
+// --------------------------------------------------------------------------
+// super
+// --------------------------------------------------------------------------
+@implementation NSStringArray
+- (void)useSuperMethod {
+ int *ip;
+ ip = super.lastObject; // expected-warning{{from 'NSString *'}}
+ super.lastObject = ip; // expected-warning{{to 'NSString *'}}
+ ip = [super objectAtIndexedSubscript:0]; // expected-warning{{from 'NSString *'}}
+}
+
++ (void)useSuperMethod {
+ int *ip;
+ ip = super.array; // expected-warning{{from 'NSArray<NSString *> *'}}
+ super.array = ip; // expected-warning{{to 'NSArray<NSString *> *'}}
+ ip = [super array]; // expected-warning{{from 'NSArray<NSString *> *'}}
+}
+@end
diff --git a/clang/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h b/clang/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h
new file mode 100644
index 00000000000..9a51fa1e990
--- /dev/null
+++ b/clang/test/SemaObjCXX/Inputs/nullability-pragmas-generics-1.h
@@ -0,0 +1,21 @@
+#pragma clang assume_nonnull begin
+
+__attribute__((objc_root_class))
+@interface B
+@end
+
+@interface C : B
+@end
+
+__attribute__((objc_root_class))
+@interface NSGeneric<T : B *> // expected-note{{type parameter 'T' declared here}}
+- (T)tee;
+- (nullable T)maybeTee;
+@end
+
+typedef NSGeneric<C *> *Generic_with_C;
+
+#pragma clang assume_nonnull end
+
+@interface NSGeneric<T : C *>(Blah) // expected-error{{type bound 'C *' for type parameter 'T' conflicts with previous bound 'B *'}}
+@end
diff --git a/clang/test/SemaObjCXX/nullability-pragmas.mm b/clang/test/SemaObjCXX/nullability-pragmas.mm
index dbf4f37f401..817d056a14a 100644
--- a/clang/test/SemaObjCXX/nullability-pragmas.mm
+++ b/clang/test/SemaObjCXX/nullability-pragmas.mm
@@ -2,6 +2,7 @@
#include "nullability-pragmas-1.h"
#include "nullability-pragmas-2.h"
+#include "nullability-pragmas-generics-1.h"
#if !__has_feature(assume_nonnull)
# error assume_nonnull feature is not set
@@ -43,3 +44,14 @@ void test_pragmas_1(A * _Nonnull a, AA * _Nonnull aa) {
ptr = aa->ivar1; // expected-error{{from incompatible type 'id'}}
ptr = aa->ivar2; // expected-error{{from incompatible type 'id _Nonnull'}}
}
+
+void test_pragmas_generics(void) {
+ float *fp;
+
+ NSGeneric<C *> *genC;
+ fp = [genC tee]; // expected-error{{from incompatible type 'C *'}}
+ fp = [genC maybeTee]; // expected-error{{from incompatible type 'C * _Nullable'}}
+
+ Generic_with_C genC2;
+ fp = genC2; // expected-error{{from incompatible type 'Generic_with_C' (aka 'NSGeneric<C *> *')}}
+}
OpenPOWER on IntegriCloud