Author: vsapsai Date: Fri Feb 15 17:01:08 2019 New Revision: 354189 URL: http://llvm.org/viewvc/llvm-project?rev=354189&view=rev Log: [ObjC generics] Fix applying `__kindof` to the type parameter.
Fixes the warning about incompatible pointer types on assigning to a subclass of type argument an expression of type `__kindof TypeParam`. We already have a mechanism in `ASTContext::canAssignObjCInterfaces` that handles `ObjCObjectType` with `__kindof`. But it wasn't triggered because during type substitution `__kindof TypeParam` was represented as `AttributedType` with attribute `ObjCKindOf` and equivalent type `TypeArg`. For assignment type checking we use canonical types so attributed type was desugared and the attribute was ignored. The fix is in checking transformed `AttributedType` and pushing `__kindof` down into `ObjCObjectType` when necessary. rdar://problem/38514910 Reviewers: ahatanak, erik.pilkington, doug.gregor Reviewed By: doug.gregor Subscribers: jkorous, dexonsmith, manmanren, jordan_rose, doug.gregor, cfe-commits Differential Revision: https://reviews.llvm.org/D57076 Modified: cfe/trunk/lib/AST/Type.cpp cfe/trunk/test/SemaObjC/kindof.m Modified: cfe/trunk/lib/AST/Type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=354189&r1=354188&r2=354189&view=diff ============================================================================== --- cfe/trunk/lib/AST/Type.cpp (original) +++ cfe/trunk/lib/AST/Type.cpp Fri Feb 15 17:01:08 2019 @@ -1297,6 +1297,42 @@ struct SubstObjCTypeArgsVisitor return BaseType::VisitObjCObjectType(objcObjectType); } + + QualType VisitAttributedType(const AttributedType *attrType) { + QualType newType = BaseType::VisitAttributedType(attrType); + if (newType.isNull()) + return {}; + + const auto *newAttrType = dyn_cast<AttributedType>(newType.getTypePtr()); + if (!newAttrType || 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<ObjCObjectPointerType>(); + const ObjCObjectType *objType = ptrType + ? ptrType->getObjectType() + : newEquivType->getAs<ObjCObjectType>(); + 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 Modified: cfe/trunk/test/SemaObjC/kindof.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/kindof.m?rev=354189&r1=354188&r2=354189&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/kindof.m (original) +++ cfe/trunk/test/SemaObjC/kindof.m Fri Feb 15 17:01:08 2019 @@ -384,9 +384,17 @@ void testNullability() { } @end +// --------------------------------------------------------------------------- +// __kindof on type parameters +// --------------------------------------------------------------------------- + @interface NSGeneric<ObjectType> : 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 @@ void testNullability() { } @end +@interface NSDefaultGeneric<ObjectType : NSString *> : NSObject +@property (copy) ObjectType object; +@property (copy) __kindof ObjectType kindof_object; +@end + void testGeneric(NSGeneric<NSString*> *generic) { NSObject *NSObject_obj; // Assign from NSObject_obj to __kindof NSString*. @@ -403,6 +416,45 @@ void testGeneric(NSGeneric<NSString*> *g [generic test:NSString_str]; } +void testGenericAssignment() { + NSMutableString *NSMutableString_str; + NSNumber *NSNumber_obj; + + NSGeneric<NSString*> *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_NSString> *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<BlockType> *generic; +} + +void testKindofNullability(NSGeneric<NSString*> *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<T> : NSObject @end _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits