441 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			441 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
// RUN: %clang_cc1 -fblocks -fsyntax-only -std=c++11 %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 NSMutableString : NSString
 | 
						|
@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;
 | 
						|
@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> // expected-note 2{{type parameter 'K' declared here}} \
 | 
						|
// expected-note 2{{'NSMutableDictionary' declared here}}
 | 
						|
- (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
 | 
						|
 | 
						|
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
// 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-error{{from incompatible type 'NSString *'}}
 | 
						|
  ip = [mutStringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}}
 | 
						|
  ip = [widgetSet firstObject]; // expected-error{{from incompatible type 'Widget *'}}
 | 
						|
  ip = [untypedMutSet firstObject]; // expected-error{{from incompatible type 'id'}}
 | 
						|
  ip = [mutStringArraySet firstObject]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
  ip = [set firstObject]; // expected-error{{from incompatible type 'id'}}
 | 
						|
  ip = [mutSet firstObject]; // expected-error{{from incompatible type 'id'}}
 | 
						|
  ip = [mutArraySet firstObject]; // expected-error{{from incompatible type 'id'}}
 | 
						|
  ip = [block firstObject]; // expected-error{{from incompatible type 'id'}}
 | 
						|
 | 
						|
  ip = [stringSet findObject:@"blah"]; // expected-error{{from incompatible type 'NSString *'}}
 | 
						|
 | 
						|
  // Class messages.
 | 
						|
  ip = [NSSet<NSString *> alloc]; // expected-error{{from incompatible type 'NSSet<NSString *> *'}}
 | 
						|
  ip = [NSSet alloc]; // expected-error{{from incompatible type 'NSSet *'}}
 | 
						|
  ip = [MutableSetOfArrays<NSString *> alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays<NSString *> *'}}
 | 
						|
  ip = [MutableSetOfArrays alloc];  // expected-error{{from incompatible type 'MutableSetOfArrays *'}}
 | 
						|
  ip = [NSArray<NSString *> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
  ip = [NSArray<NSString *><NSCopying> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
 | 
						|
  ip = [[NSMutableArray<NSString *> alloc] init];  // expected-error{{from incompatible type 'NSMutableArray<NSString *> *'}}
 | 
						|
 | 
						|
  [[NSMutableArray alloc] initWithArray: stringArray]; // okay
 | 
						|
  [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay
 | 
						|
  [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-error{{parameter of type 'NSArray<NSNumber *> *' with an lvalue of type 'NSArray<NSString *> *'}}
 | 
						|
}
 | 
						|
 | 
						|
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-error{{parameter of type 'NSString *'}}
 | 
						|
  [widgetSet addObject: window]; // expected-error{{parameter of type 'Widget *'}}
 | 
						|
  [untypedMutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
 | 
						|
  [mutStringArraySet addObject: window]; // expected-error{{parameter of type 'NSArray<NSString *> *'}}
 | 
						|
  [mutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
 | 
						|
  [mutArraySet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
 | 
						|
  [block addObject: window]; // expected-error{{parameter of 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-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
  ip = mutStringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
  ip = widgetSet.allObjects; // expected-error{{from incompatible type 'NSArray<Widget *> *'}}
 | 
						|
  ip = untypedMutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
 | 
						|
  ip = mutStringArraySet.allObjects; // expected-error{{from incompatible type 'NSArray<NSArray<NSString *> *> *'}}
 | 
						|
  ip = set.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
 | 
						|
  ip = mutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
 | 
						|
  ip = mutArraySet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
 | 
						|
 | 
						|
  ip = mutDict.someRandomKey; // expected-error{{from incompatible type '__kindof id<NSCopying>'}}
 | 
						|
}
 | 
						|
 | 
						|
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-error{{to 'NSArray<NSString *> *'}}
 | 
						|
  widgetSet.allObjects = ip; // expected-error{{to 'NSArray<Widget *> *'}}
 | 
						|
  untypedMutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}
 | 
						|
  mutStringArraySet.allObjects = ip; // expected-error{{to 'NSArray<NSArray<NSString *> *> *'}}
 | 
						|
  mutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}
 | 
						|
  mutArraySet.allObjects = ip; // expected-error{{to 'NSArray *'}}
 | 
						|
 | 
						|
  mutDict.someRandomKey = ip; // expected-error{{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-error{{from incompatible type 'NSString *'}}
 | 
						|
 | 
						|
  ip = mutStringArray[0]; // expected-error{{from incompatible type 'NSString *'}}
 | 
						|
  mutStringArray[0] = ip; // expected-error{{parameter of type 'NSString *'}}
 | 
						|
 | 
						|
  ip = array[0]; // expected-error{{from incompatible type 'id'}}
 | 
						|
 | 
						|
  ip = mutArray[0]; // expected-error{{from incompatible type 'id'}}
 | 
						|
  mutArray[0] = ip; // expected-error{{parameter of type 'id'}}
 | 
						|
 | 
						|
  ip = stringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}}
 | 
						|
  widget = stringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}}
 | 
						|
 | 
						|
  ip = mutStringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}}
 | 
						|
  widget = mutStringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}}
 | 
						|
  mutStringWidgetDict[string] = ip; // expected-error{{parameter of type 'Widget *'}}
 | 
						|
  mutStringWidgetDict[widget] = widget; // expected-error{{parameter of type 'NSString *'}}
 | 
						|
 | 
						|
  ip = dict[string]; // expected-error{{from incompatible type 'id'}}
 | 
						|
 | 
						|
  ip = mutDict[string]; // expected-error{{incompatible type 'id'}}
 | 
						|
  mutDict[string] = ip; // expected-error{{parameter of type 'id'}}
 | 
						|
 | 
						|
  widget = mutDict[window];
 | 
						|
  mutDict[window] = widget; // expected-error{{parameter of type 'id<NSCopying>'}}
 | 
						|
}
 | 
						|
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
// Instance variable access.
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
void test_instance_variable(NSArray<NSString *> *stringArray,
 | 
						|
                            NSArray *array) {
 | 
						|
  int *ip;
 | 
						|
 | 
						|
  ip = stringArray->data; // expected-error{{from incompatible type 'NSString **'}}
 | 
						|
  ip = array->data; // expected-error{{from incompatible type 'id *'}}
 | 
						|
}
 | 
						|
 | 
						|
@implementation WindowArray
 | 
						|
- (void)testInstanceVariable {
 | 
						|
  int *ip;
 | 
						|
 | 
						|
  ip = data; // expected-error{{from incompatible type '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-error{{assigning to 'NSArray<NSString *> *' from incompatible type 'NSArray<NSNumber *> *'}}
 | 
						|
 | 
						|
  // Specialized -> specialized (different levels).
 | 
						|
  stringArray = mutStringArray;
 | 
						|
 | 
						|
  // Specialized -> specialized failure (different levels).
 | 
						|
  numberArray = mutStringArray; // expected-error{{assigning to 'NSArray<NSNumber *> *' from incompatible type 'NSMutableArray<NSString *> *'}}
 | 
						|
 | 
						|
  // Unspecialized -> specialized (different levels).
 | 
						|
  stringArray = mutArray;
 | 
						|
 | 
						|
  // Specialized -> unspecialized (different levels).
 | 
						|
  array = mutStringArray;
 | 
						|
}
 | 
						|
 | 
						|
@interface NSCovariant1<__covariant T>
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSContravariant1<__contravariant T>
 | 
						|
@end
 | 
						|
 | 
						|
void test_variance(NSCovariant1<NSString *> *covariant1,
 | 
						|
                   NSCovariant1<NSMutableString *> *covariant2,
 | 
						|
                   NSCovariant1<NSString *(^)(void)> *covariant3,
 | 
						|
                   NSCovariant1<NSMutableString *(^)(void)> *covariant4,
 | 
						|
                   NSCovariant1<id> *covariant5,
 | 
						|
                   NSCovariant1<id<NSCopying>> *covariant6,
 | 
						|
                   NSContravariant1<NSString *> *contravariant1,
 | 
						|
                   NSContravariant1<NSMutableString *> *contravariant2) {
 | 
						|
  covariant1 = covariant2; // okay
 | 
						|
  covariant2 = covariant1; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *> *' from 'NSCovariant1<NSString *> *'}}
 | 
						|
 | 
						|
  covariant3 = covariant4; // okay
 | 
						|
  covariant4 = covariant3; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *(^)()> *' from 'NSCovariant1<NSString *(^)()> *'}}
 | 
						|
 | 
						|
  covariant5 = covariant1; // okay
 | 
						|
  covariant1 = covariant5; // okay: id is promiscuous
 | 
						|
 | 
						|
  covariant5 = covariant3; // okay
 | 
						|
  covariant3 = covariant5; // okay
 | 
						|
 | 
						|
  contravariant1 = contravariant2; // expected-warning{{incompatible pointer types assigning to 'NSContravariant1<NSString *> *' from 'NSContravariant1<NSMutableString *> *'}}
 | 
						|
  contravariant2 = contravariant1; // okay
 | 
						|
}
 | 
						|
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
// 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-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
  ip = cond ? mutStringArray : stringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
 | 
						|
  ip = cond ? stringArray2 : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
  ip = cond ? mutStringArray : stringArray2; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
 | 
						|
  ip = cond ? stringArray : mutArray; // expected-error{{from incompatible type 'NSArray *'}}
 | 
						|
 | 
						|
  ip = cond ? stringArray2 : mutArray; // expected-error{{from incompatible type 'NSArray *'}}
 | 
						|
 | 
						|
  ip = cond ? mutArray : stringArray; // expected-error{{from incompatible type 'NSArray *'}}
 | 
						|
 | 
						|
  ip = cond ? mutArray : stringArray2; // expected-error{{from incompatible type 'NSArray *'}}
 | 
						|
 | 
						|
  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-error{{from incompatible type 'NSString *'}}
 | 
						|
  ip = [super objectAtIndexedSubscript:0]; // expected-error{{from incompatible type 'NSString *'}}
 | 
						|
}
 | 
						|
 | 
						|
+ (void)useSuperMethod {
 | 
						|
  int *ip;
 | 
						|
  ip = super.array; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
  ip = [super array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
 | 
						|
}
 | 
						|
@end
 | 
						|
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
// Template instantiation
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
template<typename K, typename V>
 | 
						|
struct NSMutableDictionaryOf {
 | 
						|
  typedef NSMutableDictionary<K, V> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}}
 | 
						|
};
 | 
						|
 | 
						|
template<typename ...Args>
 | 
						|
struct VariadicNSMutableDictionaryOf {
 | 
						|
  typedef NSMutableDictionary<Args...> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}}
 | 
						|
  // expected-error@-1{{too many type arguments for class 'NSMutableDictionary' (have 3, expected 2)}}
 | 
						|
  // expected-error@-2{{too few type arguments for class 'NSMutableDictionary' (have 1, expected 2)}}
 | 
						|
};
 | 
						|
 | 
						|
void testInstantiation() {
 | 
						|
  int *ip;
 | 
						|
 | 
						|
  typedef NSMutableDictionaryOf<NSString *, NSObject *>::type Dict1;
 | 
						|
  Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}}
 | 
						|
 | 
						|
  typedef NSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}}
 | 
						|
}
 | 
						|
 | 
						|
void testVariadicInstantiation() {
 | 
						|
  int *ip;
 | 
						|
 | 
						|
  typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *>::type Dict1;
 | 
						|
  Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}}
 | 
						|
 | 
						|
  typedef VariadicNSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}}
 | 
						|
 | 
						|
  typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *, NSObject *>::type Dict3; // expected-note{{in instantiation of template}}
 | 
						|
 | 
						|
  typedef VariadicNSMutableDictionaryOf<NSString *>::type Dict3; // expected-note{{in instantiation of template}}
 | 
						|
}
 | 
						|
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
// Parameterized classes are not templates
 | 
						|
// --------------------------------------------------------------------------
 | 
						|
template<template<typename T, typename U> class TT>
 | 
						|
struct AcceptsTemplateTemplate { };
 | 
						|
 | 
						|
typedef AcceptsTemplateTemplate<NSMutableDictionary> TemplateTemplateFail1; // expected-error{{template argument for template template parameter must be a class template or type alias template}}
 | 
						|
 | 
						|
template<typename T>
 | 
						|
struct DependentTemplate {
 | 
						|
  typedef typename T::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}}
 | 
						|
};
 | 
						|
 | 
						|
struct NSMutableDictionaryBuilder {
 | 
						|
  typedef NSMutableDictionary apply;
 | 
						|
};
 | 
						|
 | 
						|
typedef DependentTemplate<NSMutableDictionaryBuilder>::type DependentTemplateFail1; // expected-note{{in instantiation of template class}}
 | 
						|
 | 
						|
template<typename K, typename V>
 | 
						|
struct NonDependentTemplate {
 | 
						|
  typedef NSMutableDictionaryBuilder::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}}
 | 
						|
  // expected-error@-1{{expected member name or }}
 | 
						|
};
 | 
						|
 | 
						|
// However, one can use an alias template to turn a parameterized
 | 
						|
// class into a template.
 | 
						|
template<typename K, typename V>
 | 
						|
using NSMutableDictionaryAlias = NSMutableDictionary<K, V>;
 | 
						|
 | 
						|
typedef AcceptsTemplateTemplate<NSMutableDictionaryAlias> TemplateTemplateAlias1; // okay
 | 
						|
 | 
						|
 |