diff options
| author | Volodymyr Sapsai <vsapsai@apple.com> | 2019-02-16 01:01:08 +0000 |
|---|---|---|
| committer | Volodymyr Sapsai <vsapsai@apple.com> | 2019-02-16 01:01:08 +0000 |
| commit | bcb4f7208dac24bfeac1d4a9071eb19c8c2ccd27 (patch) | |
| tree | ef79d1eb54aa4aaaef875e3f92b3f515d5357fd5 /clang | |
| parent | 70ca752ccf6a8f362aea25ccd3ee2bbceca93b20 (diff) | |
| download | bcm5719-llvm-bcb4f7208dac24bfeac1d4a9071eb19c8c2ccd27.tar.gz bcm5719-llvm-bcb4f7208dac24bfeac1d4a9071eb19c8c2ccd27.zip | |
[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
llvm-svn: 354189
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/AST/Type.cpp | 36 | ||||
| -rw-r--r-- | clang/test/SemaObjC/kindof.m | 52 |
2 files changed, 88 insertions, 0 deletions
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 5edb68d6992..aca82e2e63e 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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 diff --git a/clang/test/SemaObjC/kindof.m b/clang/test/SemaObjC/kindof.m index 9d758d3cfb2..b2c32051820 100644 --- a/clang/test/SemaObjC/kindof.m +++ b/clang/test/SemaObjC/kindof.m @@ -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*> *generic) { [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 |

