summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST
diff options
context:
space:
mode:
authorJames Y Knight <jyknight@google.com>2019-10-17 15:27:04 +0000
committerJames Y Knight <jyknight@google.com>2019-10-17 15:27:04 +0000
commitccc4d83cda16bea1d9dfd0967dc7d2cfb24b8e75 (patch)
tree7730dd616da7b04af72b36b95cd7c7e4c9311ad0 /clang/lib/AST
parent1c982af0599781bdb049f898a2d512656c807485 (diff)
downloadbcm5719-llvm-ccc4d83cda16bea1d9dfd0967dc7d2cfb24b8e75.tar.gz
bcm5719-llvm-ccc4d83cda16bea1d9dfd0967dc7d2cfb24b8e75.zip
[ObjC] Diagnose implicit type coercion from ObjC 'Class' to object
pointer types. For example, in Objective-C mode, the initialization of 'x' in: ``` @implementation MyType + (void)someClassMethod { MyType *x = self; } @end ``` is correctly diagnosed with an incompatible-pointer-types warning, but in Objective-C++ mode, it is not diagnosed at all -- even though incompatible pointer conversions generally become an error in C++. This patch fixes that oversight, allowing implicit conversions involving Class only to/from unqualified-id, and between qualified and unqualified Class, where the protocols are compatible. Note that this does change some behaviors in Objective-C, as well, as shown by the modified tests. Of particular note is that assignment from from 'Class<MyProtocol>' to 'id<MyProtocol>' now warns. (Despite appearances, those are not compatible types. 'Class<MyProtocol>' is not expected to have instance methods defined by 'MyProtocol', while 'id<MyProtocol>' is.) Differential Revision: https://reviews.llvm.org/D67983 llvm-svn: 375125
Diffstat (limited to 'clang/lib/AST')
-rw-r--r--clang/lib/AST/ASTContext.cpp26
1 files changed, 17 insertions, 9 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 1a3bde00eec..cda51ec755a 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -8025,14 +8025,15 @@ bool ASTContext::ObjCQualifiedClassTypesAreCompatible(
bool ASTContext::ObjCQualifiedIdTypesAreCompatible(
const ObjCObjectPointerType *lhs, const ObjCObjectPointerType *rhs,
bool compare) {
- // Allow id<P..> and an 'id' or void* type in all cases.
- if (lhs->isVoidPointerType() ||
- lhs->isObjCIdType() || lhs->isObjCClassType())
- return true;
- else if (rhs->isVoidPointerType() ||
- rhs->isObjCIdType() || rhs->isObjCClassType())
+ // Allow id<P..> and an 'id' in all cases.
+ if (lhs->isObjCIdType() || rhs->isObjCIdType())
return true;
+ // Don't allow id<P..> to convert to Class or Class<P..> in either direction.
+ if (lhs->isObjCClassType() || lhs->isObjCQualifiedClassType() ||
+ rhs->isObjCClassType() || rhs->isObjCQualifiedClassType())
+ return false;
+
if (lhs->isObjCQualifiedIdType()) {
if (rhs->qual_empty()) {
// If the RHS is a unqualified interface pointer "NSString*",
@@ -8142,9 +8143,8 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectType* LHS = LHSOPT->getObjectType();
const ObjCObjectType* RHS = RHSOPT->getObjectType();
- // If either type represents the built-in 'id' or 'Class' types, return true.
- if (LHS->isObjCUnqualifiedIdOrClass() ||
- RHS->isObjCUnqualifiedIdOrClass())
+ // If either type represents the built-in 'id' type, return true.
+ if (LHS->isObjCUnqualifiedId() || RHS->isObjCUnqualifiedId())
return true;
// Function object that propagates a successful result or handles
@@ -8162,14 +8162,22 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
LHSOPT->stripObjCKindOfTypeAndQuals(*this));
};
+ // Casts from or to id<P> are allowed when the other side has compatible
+ // protocols.
if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) {
return finish(ObjCQualifiedIdTypesAreCompatible(LHSOPT, RHSOPT, false));
}
+ // Verify protocol compatibility for casts from Class<P1> to Class<P2>.
if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) {
return finish(ObjCQualifiedClassTypesAreCompatible(LHSOPT, RHSOPT));
}
+ // Casts from Class to Class<Foo>, or vice-versa, are allowed.
+ if (LHS->isObjCClass() && RHS->isObjCClass()) {
+ return true;
+ }
+
// If we have 2 user-defined types, fall into that path.
if (LHS->getInterface() && RHS->getInterface()) {
return finish(canAssignObjCInterfaces(LHS, RHS));
OpenPOWER on IntegriCloud