ObjC kindof: set the type of a conditional expression when involving kindof.

When either LHS or RHS is a kindof type, we return a kindof type.

rdar://problem/20513780

llvm-svn: 268781
This commit is contained in:
Manman Ren 2016-05-06 19:35:02 +00:00
parent f0b6b40fa4
commit c46f7d1883
2 changed files with 46 additions and 5 deletions

View File

@ -7163,6 +7163,11 @@ QualType ASTContext::areCommonBaseCompatible(
if (!LDecl || !RDecl) if (!LDecl || !RDecl)
return QualType(); return QualType();
// When either LHS or RHS is a kindof type, we should return a kindof type.
// For example, for common base of kindof(ASub1) and kindof(ASub2), we return
// kindof(A).
bool anyKindOf = LHS->isKindOfType() || RHS->isKindOfType();
// Follow the left-hand side up the class hierarchy until we either hit a // Follow the left-hand side up the class hierarchy until we either hit a
// root or find the RHS. Record the ancestors in case we don't find it. // root or find the RHS. Record the ancestors in case we don't find it.
llvm::SmallDenseMap<const ObjCInterfaceDecl *, const ObjCObjectType *, 4> llvm::SmallDenseMap<const ObjCInterfaceDecl *, const ObjCObjectType *, 4>
@ -7197,10 +7202,12 @@ QualType ASTContext::areCommonBaseCompatible(
anyChanges = true; anyChanges = true;
// If anything in the LHS will have changed, build a new result type. // If anything in the LHS will have changed, build a new result type.
if (anyChanges) { // If we need to return a kindof type but LHS is not a kindof type, we
// build a new result type.
if (anyChanges || LHS->isKindOfType() != anyKindOf) {
QualType Result = getObjCInterfaceType(LHS->getInterface()); QualType Result = getObjCInterfaceType(LHS->getInterface());
Result = getObjCObjectType(Result, LHSTypeArgs, Protocols, Result = getObjCObjectType(Result, LHSTypeArgs, Protocols,
LHS->isKindOfType()); anyKindOf || LHS->isKindOfType());
return getObjCObjectPointerType(Result); return getObjCObjectPointerType(Result);
} }
@ -7245,10 +7252,12 @@ QualType ASTContext::areCommonBaseCompatible(
if (!Protocols.empty()) if (!Protocols.empty())
anyChanges = true; anyChanges = true;
if (anyChanges) { // If we need to return a kindof type but RHS is not a kindof type, we
// build a new result type.
if (anyChanges || RHS->isKindOfType() != anyKindOf) {
QualType Result = getObjCInterfaceType(RHS->getInterface()); QualType Result = getObjCInterfaceType(RHS->getInterface());
Result = getObjCObjectType(Result, RHSTypeArgs, Protocols, Result = getObjCObjectType(Result, RHSTypeArgs, Protocols,
RHS->isKindOfType()); anyKindOf || RHS->isKindOfType());
return getObjCObjectPointerType(Result); return getObjCObjectPointerType(Result);
} }

View File

@ -187,6 +187,39 @@ void test_crosscast_conversions(void) {
NSString_obj = kindof_NSNumber_obj; // expected-warning{{from '__kindof NSNumber *'}} NSString_obj = kindof_NSNumber_obj; // expected-warning{{from '__kindof NSNumber *'}}
} }
@interface NSCell : NSObject
@end
@interface NSCellSub : NSCell
@end
@interface NSCellSub2 : NSCell
@end
@interface NSCellSubSub : NSCellSub
@end
typedef signed char BOOL;
void test_conditional(BOOL flag) {
NSCellSubSub *result;
__kindof NSCellSub *kindof_Sub;
NSCell *cell;
NSCellSub *sub;
NSCellSub2 *sub2;
NSCellSubSub *subsub;
// LHS is kindof NSCellSub, RHS is NSCell --> kindof NSCell
// LHS is kindof NSCellSub, RHS is NSCellSub --> kindof NSCellSub
// LHS is kindof NSCellSub, RHS is NSCellSub2 --> kindof NSCell
// LHS is kindof NSCellSub, RHS is NSCellSubSub --> kindof NSCellSub
result = flag ? kindof_Sub : cell;
result = flag ? kindof_Sub : sub;
result = flag ? kindof_Sub : sub2;
result = flag ? kindof_Sub : subsub;
result = flag ? cell : kindof_Sub;
result = flag ? sub : kindof_Sub;
result = flag ? sub2 : kindof_Sub;
result = flag ? subsub : kindof_Sub;
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Blocks // Blocks
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -277,7 +310,6 @@ void test(__kindof Bar *kBar) {
} }
// Make sure we don't emit warning about no method found. // Make sure we don't emit warning about no method found.
typedef signed char BOOL;
@interface A : NSObject @interface A : NSObject
@property (readonly, getter=isActive) BOOL active; @property (readonly, getter=isActive) BOOL active;
@end @end