summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorVolodymyr Sapsai <vsapsai@apple.com>2019-02-16 01:01:08 +0000
committerVolodymyr Sapsai <vsapsai@apple.com>2019-02-16 01:01:08 +0000
commitbcb4f7208dac24bfeac1d4a9071eb19c8c2ccd27 (patch)
treeef79d1eb54aa4aaaef875e3f92b3f515d5357fd5 /clang
parent70ca752ccf6a8f362aea25ccd3ee2bbceca93b20 (diff)
downloadbcm5719-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.cpp36
-rw-r--r--clang/test/SemaObjC/kindof.m52
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
OpenPOWER on IntegriCloud