summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ASTContext.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2015-07-07 03:58:42 +0000
committerDouglas Gregor <dgregor@apple.com>2015-07-07 03:58:42 +0000
commitab209d83be5dadff4f17364a71f323b89e3c63f8 (patch)
tree5e97315685c9476095deef062e53e98e525d78e5 /clang/lib/AST/ASTContext.cpp
parent10dc9d80cbb47675be0c6ea8481e12ec197e1637 (diff)
downloadbcm5719-llvm-ab209d83be5dadff4f17364a71f323b89e3c63f8.tar.gz
bcm5719-llvm-ab209d83be5dadff4f17364a71f323b89e3c63f8.zip
Implement the Objective-C __kindof type qualifier.
The __kindof type qualifier can be applied to Objective-C object (pointer) types to indicate id-like behavior, which includes implicit "downcasting" of __kindof types to subclasses and id-like message-send behavior. __kindof types provide better type bounds for substitutions into unspecified generic types, which preserves more type information. llvm-svn: 241548
Diffstat (limited to 'clang/lib/AST/ASTContext.cpp')
-rw-r--r--clang/lib/AST/ASTContext.cpp111
1 files changed, 82 insertions, 29 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a92f0052f0c..58d703a67ed 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3615,21 +3615,24 @@ QualType ASTContext::getObjCObjectType(QualType BaseType,
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols) const {
return getObjCObjectType(BaseType, { },
- llvm::makeArrayRef(Protocols, NumProtocols));
+ llvm::makeArrayRef(Protocols, NumProtocols),
+ /*isKindOf=*/false);
}
QualType ASTContext::getObjCObjectType(
QualType baseType,
ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols) const {
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf) const {
// If the base type is an interface and there aren't any protocols or
// type arguments to add, then the interface type will do just fine.
- if (typeArgs.empty() && protocols.empty() && isa<ObjCInterfaceType>(baseType))
+ if (typeArgs.empty() && protocols.empty() && !isKindOf &&
+ isa<ObjCInterfaceType>(baseType))
return baseType;
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
- ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols);
+ ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols, isKindOf);
void *InsertPos = nullptr;
if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
@@ -3681,7 +3684,7 @@ QualType ASTContext::getObjCObjectType(
}
canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs,
- canonProtocols);
+ canonProtocols, isKindOf);
// Regenerate InsertPos.
ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -3692,7 +3695,8 @@ QualType ASTContext::getObjCObjectType(
size += protocols.size() * sizeof(ObjCProtocolDecl *);
void *mem = Allocate(size, TypeAlignment);
ObjCObjectTypeImpl *T =
- new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols);
+ new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols,
+ isKindOf);
Types.push_back(T);
ObjCObjectTypes.InsertNode(T, InsertPos);
@@ -6775,18 +6779,36 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
RHS->isObjCUnqualifiedIdOrClass())
return true;
- if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId())
- return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0),
- false);
+ // Function object that propagates a successful result or handles
+ // __kindof types.
+ auto finish = [&](bool succeeded) -> bool {
+ if (succeeded)
+ return true;
+
+ if (!RHS->isKindOfType())
+ return false;
+
+ // Strip off __kindof and protocol qualifiers, then check whether
+ // we can assign the other way.
+ return canAssignObjCInterfaces(RHSOPT->stripObjCKindOfTypeAndQuals(*this),
+ LHSOPT->stripObjCKindOfTypeAndQuals(*this));
+ };
+
+ if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) {
+ return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
+ QualType(RHSOPT,0),
+ false));
+ }
- if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass())
- return ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0));
+ if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) {
+ return finish(ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0),
+ QualType(RHSOPT,0)));
+ }
// If we have 2 user-defined types, fall into that path.
- if (LHS->getInterface() && RHS->getInterface())
- return canAssignObjCInterfaces(LHS, RHS);
+ if (LHS->getInterface() && RHS->getInterface()) {
+ return finish(canAssignObjCInterfaces(LHS, RHS));
+ }
return false;
}
@@ -6800,26 +6822,46 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
const ObjCObjectPointerType *LHSOPT,
const ObjCObjectPointerType *RHSOPT,
bool BlockReturnType) {
+
+ // Function object that propagates a successful result or handles
+ // __kindof types.
+ auto finish = [&](bool succeeded) -> bool {
+ if (succeeded)
+ return true;
+
+ const ObjCObjectPointerType *Expected = BlockReturnType ? RHSOPT : LHSOPT;
+ if (!Expected->isKindOfType())
+ return false;
+
+ // Strip off __kindof and protocol qualifiers, then check whether
+ // we can assign the other way.
+ return canAssignObjCInterfacesInBlockPointer(
+ RHSOPT->stripObjCKindOfTypeAndQuals(*this),
+ LHSOPT->stripObjCKindOfTypeAndQuals(*this),
+ BlockReturnType);
+ };
+
if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType())
return true;
if (LHSOPT->isObjCBuiltinType()) {
- return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType();
+ return finish(RHSOPT->isObjCBuiltinType() ||
+ RHSOPT->isObjCQualifiedIdType());
}
if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
- return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0),
- false);
+ return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
+ QualType(RHSOPT,0),
+ false));
const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
if (LHS && RHS) { // We have 2 user-defined types.
if (LHS != RHS) {
if (LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
- return BlockReturnType;
+ return finish(BlockReturnType);
if (RHS->getDecl()->isSuperClassOf(LHS->getDecl()))
- return !BlockReturnType;
+ return finish(!BlockReturnType);
}
else
return true;
@@ -6903,13 +6945,19 @@ void getIntersectionOfProtocols(ASTContext &Context,
// Check that the given Objective-C type argument lists are equivalent.
static bool sameObjCTypeArgs(const ASTContext &ctx, ArrayRef<QualType> lhsArgs,
- ArrayRef<QualType> rhsArgs) {
+ ArrayRef<QualType> rhsArgs,
+ bool stripKindOf) {
if (lhsArgs.size() != rhsArgs.size())
return false;
for (unsigned i = 0, n = lhsArgs.size(); i != n; ++i) {
- if (!ctx.hasSameType(lhsArgs[i], rhsArgs[i]))
- return false;
+ if (!ctx.hasSameType(lhsArgs[i], rhsArgs[i])) {
+ if (!stripKindOf ||
+ !ctx.hasSameType(lhsArgs[i].stripObjCKindOfType(ctx),
+ rhsArgs[i].stripObjCKindOfType(ctx))) {
+ return false;
+ }
+ }
}
return true;
@@ -6941,7 +6989,8 @@ QualType ASTContext::areCommonBaseCompatible(
bool anyChanges = false;
if (LHS->isSpecialized() && RHS->isSpecialized()) {
// Both have type arguments, compare them.
- if (!sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHS->getTypeArgs()))
+ if (!sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHS->getTypeArgs(),
+ /*stripKindOf=*/true))
return QualType();
} else if (LHS->isSpecialized() != RHS->isSpecialized()) {
// If only one has type arguments, the result will not have type
@@ -6960,7 +7009,8 @@ QualType ASTContext::areCommonBaseCompatible(
// If anything in the LHS will have changed, build a new result type.
if (anyChanges) {
QualType Result = getObjCInterfaceType(LHS->getInterface());
- Result = getObjCObjectType(Result, LHSTypeArgs, Protocols);
+ Result = getObjCObjectType(Result, LHSTypeArgs, Protocols,
+ LHS->isKindOfType());
return getObjCObjectPointerType(Result);
}
@@ -6987,7 +7037,8 @@ QualType ASTContext::areCommonBaseCompatible(
bool anyChanges = false;
if (LHS->isSpecialized() && RHS->isSpecialized()) {
// Both have type arguments, compare them.
- if (!sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHS->getTypeArgs()))
+ if (!sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHS->getTypeArgs(),
+ /*stripKindOf=*/true))
return QualType();
} else if (LHS->isSpecialized() != RHS->isSpecialized()) {
// If only one has type arguments, the result will not have type
@@ -7005,7 +7056,8 @@ QualType ASTContext::areCommonBaseCompatible(
if (anyChanges) {
QualType Result = getObjCInterfaceType(RHS->getInterface());
- Result = getObjCObjectType(Result, RHSTypeArgs, Protocols);
+ Result = getObjCObjectType(Result, RHSTypeArgs, Protocols,
+ RHS->isKindOfType());
return getObjCObjectPointerType(Result);
}
@@ -7075,7 +7127,8 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS,
// If the RHS is specializd, compare type arguments.
if (RHSSuper->isSpecialized() &&
- !sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHSSuper->getTypeArgs())) {
+ !sameObjCTypeArgs(*this, LHS->getTypeArgs(), RHSSuper->getTypeArgs(),
+ /*stripKindOf=*/true)) {
return false;
}
}
OpenPOWER on IntegriCloud