Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -1284,6 +1284,42 @@ return BaseType::VisitObjCObjectType(objcObjectType); } + + QualType VisitAttributedType(const AttributedType *attrType) { + QualType newType = BaseType::VisitAttributedType(attrType); + if (newType.isNull()) + return {}; + + const auto *newAttrType = dyn_cast(newType.getTypePtr()); + if (newAttrType->getAttrKind() != attr::ObjCKindOf) + return newType; + + // Find out if it's an Objective-C object or object pointer type; + QualType newEquivType = newAttrType->getEquivalentType(); + const ObjCObjectPointerType *ptrType = + newEquivType->getAs(); + const ObjCObjectType *objType = ptrType + ? ptrType->getObjectType() + : newEquivType->getAs(); + if (!objType) + return newType; + + // Rebuild the "equivalent" type, which pushes __kindof down into + // the object type. + newEquivType = Ctx.getObjCObjectType( + objType->getBaseType(), objType->getTypeArgsAsWritten(), + objType->getProtocols(), + // There is no need to apply kindof on an unqualified id type. + /*isKindOf=*/objType->isObjCUnqualifiedId() ? false : true); + + // If we started with an object pointer type, rebuild it. + if (ptrType) + newEquivType = Ctx.getObjCObjectPointerType(newEquivType); + + // Rebuild the attributed type. + return Ctx.getAttributedType(newAttrType->getAttrKind(), + newAttrType->getModifiedType(), newEquivType); + } }; struct StripObjCKindOfTypeVisitor Index: clang/test/SemaObjC/kindof.m =================================================================== --- clang/test/SemaObjC/kindof.m +++ clang/test/SemaObjC/kindof.m @@ -384,9 +384,17 @@ } @end +// --------------------------------------------------------------------------- +// __kindof on type parameters +// --------------------------------------------------------------------------- + @interface NSGeneric : NSObject - (void)test:(__kindof ObjectType)T; // expected-note{{passing argument to parameter 'T' here}} - (void)mapUsingBlock:(id (^)(__kindof ObjectType))block; +@property (copy) ObjectType object; +@property (copy) __kindof ObjectType kindof_object; + +@property (copy) __kindof ObjectType _Nonnull nonnull_kindof_object; @end @implementation NSGeneric - (void)test:(id)T { @@ -395,6 +403,11 @@ } @end +@interface NSDefaultGeneric : NSObject +@property (copy) ObjectType object; +@property (copy) __kindof ObjectType kindof_object; +@end + void testGeneric(NSGeneric *generic) { NSObject *NSObject_obj; // Assign from NSObject_obj to __kindof NSString*. @@ -403,6 +416,45 @@ [generic test:NSString_str]; } +void testGenericAssignment() { + NSMutableString *NSMutableString_str; + NSNumber *NSNumber_obj; + + NSGeneric *generic; + NSMutableString_str = generic.object; // expected-warning{{incompatible pointer types}} + NSNumber_obj = generic.object; // expected-warning{{incompatible pointer types}} + NSMutableString_str = generic.kindof_object; + NSNumber_obj = generic.kindof_object; // expected-warning{{incompatible pointer types assigning to 'NSNumber *' from '__kindof NSString *'}} + + NSGeneric<__kindof NSString*> *kindof_generic; + NSMutableString_str = kindof_generic.object; + NSNumber_obj = kindof_generic.object; // expected-warning{{incompatible pointer types assigning to 'NSNumber *' from '__kindof NSString *'}} + NSMutableString_str = kindof_generic.kindof_object; + NSNumber_obj = kindof_generic.kindof_object; // expected-warning{{incompatible pointer types assigning to 'NSNumber *' from '__kindof __kindof NSString *'}} + + NSDefaultGeneric *default_generic; + NSMutableString_str = default_generic.object; + NSNumber_obj = default_generic.object; // expected-warning{{incompatible pointer types}} + NSMutableString_str = default_generic.kindof_object; + NSNumber_obj = default_generic.kindof_object; // expected-warning{{incompatible pointer types assigning to 'NSNumber *' from '__kindof __kindof NSString *'}} + + typedef NSString *Typedef_NSString; + NSGeneric *typedef_generic; + NSMutableString_str = typedef_generic.object; // expected-warning{{incompatible pointer types}} + NSNumber_obj = typedef_generic.object; // expected-warning{{incompatible pointer types}} + NSMutableString_str = typedef_generic.kindof_object; + NSNumber_obj = typedef_generic.kindof_object; // expected-warning{{incompatible pointer types assigning to 'NSNumber *' from '__kindof Typedef_NSString'}} +} + +void testKindofNonObjectType() { + typedef void (^BlockType)(int); + NSGeneric *generic; +} + +void testKindofNullability(NSGeneric *generic) { + generic.nonnull_kindof_object = 0; // expected-warning{{null passed to a callee that requires a non-null argument}} +} + // Check that clang doesn't crash when a type parameter is illegal. @interface Array1 : NSObject @end