diff options
| author | James Y Knight <jyknight@google.com> | 2019-10-17 15:27:04 +0000 |
|---|---|---|
| committer | James Y Knight <jyknight@google.com> | 2019-10-17 15:27:04 +0000 |
| commit | ccc4d83cda16bea1d9dfd0967dc7d2cfb24b8e75 (patch) | |
| tree | 7730dd616da7b04af72b36b95cd7c7e4c9311ad0 /clang/lib/AST | |
| parent | 1c982af0599781bdb049f898a2d512656c807485 (diff) | |
| download | bcm5719-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.cpp | 26 |
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)); |

