Author: jyknight Date: Thu Oct 17 08:27:04 2019 New Revision: 375125 URL: http://llvm.org/viewvc/llvm-project?rev=375125&view=rev Log: [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 Modified: cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/SemaObjC/comptypes-1.m cfe/trunk/test/SemaObjCXX/class-method-self.mm cfe/trunk/test/SemaObjCXX/comptypes-1.mm cfe/trunk/test/SemaObjCXX/comptypes-7.mm cfe/trunk/test/SemaObjCXX/instancetype.mm Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=375125&r1=375124&r2=375125&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Thu Oct 17 08:27:04 2019 @@ -8025,14 +8025,15 @@ bool ASTContext::ObjCQualifiedClassTypes 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 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 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)); Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=375125&r1=375124&r2=375125&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Oct 17 08:27:04 2019 @@ -10068,8 +10068,8 @@ static bool convertPointersToCompositeTy QualType T = S.FindCompositePointerType(Loc, LHS, RHS); if (T.isNull()) { - if ((LHSType->isPointerType() || LHSType->isMemberPointerType()) && - (RHSType->isPointerType() || RHSType->isMemberPointerType())) + if ((LHSType->isAnyPointerType() || LHSType->isMemberPointerType()) && + (RHSType->isAnyPointerType() || RHSType->isMemberPointerType())) diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true); else S.InvalidOperands(Loc, LHS, RHS); Modified: cfe/trunk/test/SemaObjC/comptypes-1.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/comptypes-1.m?rev=375125&r1=375124&r2=375125&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/comptypes-1.m (original) +++ cfe/trunk/test/SemaObjC/comptypes-1.m Thu Oct 17 08:27:04 2019 @@ -49,7 +49,7 @@ int main() obj_p = obj_c; // expected-warning {{assigning to 'id<MyProtocol>' from incompatible type 'MyClass *'}} obj_p = obj_cp; /* Ok */ obj_p = obj_C; // expected-warning {{incompatible pointer types assigning to 'id<MyProtocol>' from 'Class'}} - obj_p = obj_CP; // FIXME -- should warn {{assigning to 'id<MyProtocol>' from incompatible type 'Class<MyProtocol>'}} + obj_p = obj_CP; // expected-warning {{assigning to 'id<MyProtocol>' from incompatible type 'Class<MyProtocol>'}} /* Assigning to a 'MyOtherClass *' variable should always generate a warning, unless done from an 'id' or an 'id<MyProtocol>' (since @@ -92,8 +92,8 @@ int main() if (obj_c == obj_cp) foo(); // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'MyOtherClass *')}} if (obj_cp == obj_c) foo(); // expected-warning {{comparison of distinct pointer types ('MyOtherClass *' and 'MyClass *')}} - if (obj_c == obj_C) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('MyClass *' and 'Class')}} - if (obj_C == obj_c) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('Class' and 'MyClass *')}} + if (obj_c == obj_C) foo(); // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'Class')}} + if (obj_C == obj_c) foo(); // expected-warning {{comparison of distinct pointer types ('Class' and 'MyClass *')}} if (obj_c == obj_CP) foo(); // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'Class<MyProtocol>')}} if (obj_CP == obj_c) foo(); // expected-warning {{comparison of distinct pointer types ('Class<MyProtocol>' and 'MyClass *')}} @@ -103,15 +103,15 @@ int main() if (obj_p == obj_cp) foo(); /* Ok */ if (obj_cp == obj_p) foo(); /* Ok */ - if (obj_p == obj_C) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('id<MyProtocol>' and 'Class')}} - if (obj_C == obj_p) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('Class' and 'id<MyProtocol>')}} + if (obj_p == obj_C) foo(); // expected-warning {{comparison of distinct pointer types ('id<MyProtocol>' and 'Class')}} + if (obj_C == obj_p) foo(); // expected-warning {{comparison of distinct pointer types ('Class' and 'id<MyProtocol>')}} - if (obj_p == obj_CP) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('id<MyProtocol>' and 'Class<MyProtocol>')}} - if (obj_CP == obj_p) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('Class<MyProtocol>' and 'id<MyProtocol>')}} + if (obj_p == obj_CP) foo(); // expected-warning {{comparison of distinct pointer types ('id<MyProtocol>' and 'Class<MyProtocol>')}} + if (obj_CP == obj_p) foo(); // expected-warning {{comparison of distinct pointer types ('Class<MyProtocol>' and 'id<MyProtocol>')}} /* Comparisons between MyOtherClass * and Class types is a warning */ - if (obj_cp == obj_C) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('MyOtherClass *' and 'Class')}} - if (obj_C == obj_cp) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('Class' and 'MyOtherClass *')}} + if (obj_cp == obj_C) foo(); // expected-warning {{comparison of distinct pointer types ('MyOtherClass *' and 'Class')}} + if (obj_C == obj_cp) foo(); // expected-warning {{comparison of distinct pointer types ('Class' and 'MyOtherClass *')}} if (obj_cp == obj_CP) foo(); // expected-warning {{comparison of distinct pointer types ('MyOtherClass *' and 'Class<MyProtocol>')}} if (obj_CP == obj_cp) foo(); // expected-warning {{comparison of distinct pointer types ('Class<MyProtocol>' and 'MyOtherClass *')}} Modified: cfe/trunk/test/SemaObjCXX/class-method-self.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/class-method-self.mm?rev=375125&r1=375124&r2=375125&view=diff ============================================================================== --- cfe/trunk/test/SemaObjCXX/class-method-self.mm (original) +++ cfe/trunk/test/SemaObjCXX/class-method-self.mm Thu Oct 17 08:27:04 2019 @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -verify -Wno-objc-root-class %s -// FIXME: expected-no-diagnostics + @interface XX -- (void)addObserver:(XX*)o; // FIXME -- should note 2{{passing argument to parameter 'o' here}} +- (void)addObserver:(XX*)o; // expected-note 2{{passing argument to parameter 'o' here}} @end @@ -17,9 +17,9 @@ static XX *obj; + (void)classMethod { - [obj addObserver:self]; // FIXME -- should error {{cannot initialize a parameter of type 'XX *' with an lvalue of type 'Class'}} + [obj addObserver:self]; // expected-error {{cannot initialize a parameter of type 'XX *' with an lvalue of type 'Class'}} Class whatever; - [obj addObserver:whatever]; // FIXME -- should error {{cannot initialize a parameter of type 'XX *' with an lvalue of type 'Class'}} + [obj addObserver:whatever]; // expected-error {{cannot initialize a parameter of type 'XX *' with an lvalue of type 'Class'}} } @end Modified: cfe/trunk/test/SemaObjCXX/comptypes-1.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/comptypes-1.mm?rev=375125&r1=375124&r2=375125&view=diff ============================================================================== --- cfe/trunk/test/SemaObjCXX/comptypes-1.mm (original) +++ cfe/trunk/test/SemaObjCXX/comptypes-1.mm Thu Oct 17 08:27:04 2019 @@ -38,7 +38,7 @@ int main() obj_c = obj; /* Ok */ obj_c = obj_p; // expected-error {{assigning to 'MyClass *' from incompatible type 'id<MyProtocol>'}} obj_c = obj_cp; // expected-error {{assigning to 'MyClass *' from incompatible type 'MyOtherClass *'}} - obj_c = obj_C; // FIXME -- should error {{assigning to 'MyClass *' from incompatible type 'Class'}} + obj_c = obj_C; // expected-error {{assigning to 'MyClass *' from incompatible type 'Class'}} obj_c = obj_CP; // expected-error {{assigning to 'MyClass *' from incompatible type 'Class<MyProtocol>'}} /* Assigning to an 'id<MyProtocol>' variable should generate a @@ -48,8 +48,8 @@ int main() obj_p = obj; /* Ok */ obj_p = obj_c; // expected-error {{assigning to 'id<MyProtocol>' from incompatible type 'MyClass *'}} obj_p = obj_cp; /* Ok */ - obj_p = obj_C; // FIXME -- should error {{assigning to 'id<MyProtocol>' from incompatible type 'Class'}} - obj_p = obj_CP; // FIXME -- should error {{assigning to 'id<MyProtocol>' from incompatible type 'Class<MyProtocol>'}} + obj_p = obj_C; // expected-error {{assigning to 'id<MyProtocol>' from incompatible type 'Class'}} + obj_p = obj_CP; // expected-error {{assigning to 'id<MyProtocol>' from incompatible type 'Class<MyProtocol>'}} /* Assigning to a 'MyOtherClass *' variable should always generate a warning, unless done from an 'id' or an 'id<MyProtocol>' (since @@ -57,17 +57,17 @@ int main() obj_cp = obj; /* Ok */ obj_cp = obj_c; // expected-error {{assigning to 'MyOtherClass *' from incompatible type 'MyClass *'}} obj_cp = obj_p; /* Ok */ - obj_cp = obj_C; // FIXME -- should error {{assigning to 'MyOtherClass *' from incompatible type 'Class'}} + obj_cp = obj_C; // expected-error {{assigning to 'MyOtherClass *' from incompatible type 'Class'}} obj_cp = obj_CP; // expected-error {{assigning to 'MyOtherClass *' from incompatible type 'Class<MyProtocol>'}} obj_C = obj; // Ok - obj_C = obj_p; // FIXME -- should error {{assigning to 'Class' from incompatible type 'id<MyProtocol>'}} - obj_C = obj_c; // FIXME -- should error {{assigning to 'Class' from incompatible type 'MyClass *'}} - obj_C = obj_cp; // FIXME -- should error {{assigning to 'Class' from incompatible type 'MyOtherClass *'}} + obj_C = obj_p; // expected-error {{assigning to 'Class' from incompatible type 'id<MyProtocol>'}} + obj_C = obj_c; // expected-error {{assigning to 'Class' from incompatible type 'MyClass *'}} + obj_C = obj_cp; // expected-error {{assigning to 'Class' from incompatible type 'MyOtherClass *'}} obj_C = obj_CP; // Ok obj_CP = obj; // Ok - obj_CP = obj_p; // expected-warning {{incompatible pointer types assigning to 'Class<MyProtocol>' from 'id<MyProtocol>'}} FIXME -- should error {{assigning to 'Class<MyProtocol>' from incompatible type 'id<MyProtocol>'}} + obj_CP = obj_p; // expected-error {{assigning to 'Class<MyProtocol>' from incompatible type 'id<MyProtocol>'}} obj_CP = obj_c; // expected-error {{assigning to 'Class<MyProtocol>' from incompatible type 'MyClass *}} obj_CP = obj_cp; // expected-error {{assigning to 'Class<MyProtocol>' from incompatible type 'MyOtherClass *'}} obj_CP = obj_C; // Ok @@ -92,8 +92,8 @@ int main() if (obj_c == obj_cp) foo(); // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'MyOtherClass *')}} if (obj_cp == obj_c) foo(); // expected-warning {{comparison of distinct pointer types ('MyOtherClass *' and 'MyClass *')}} - if (obj_c == obj_C) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('MyClass *' and 'Class')}} - if (obj_C == obj_c) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('Class' and 'MyClass *')}} + if (obj_c == obj_C) foo(); // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'Class')}} + if (obj_C == obj_c) foo(); // expected-warning {{comparison of distinct pointer types ('Class' and 'MyClass *')}} if (obj_c == obj_CP) foo(); // expected-warning {{comparison of distinct pointer types ('MyClass *' and 'Class<MyProtocol>')}} if (obj_CP == obj_c) foo(); // expected-warning {{comparison of distinct pointer types ('Class<MyProtocol>' and 'MyClass *')}} @@ -103,15 +103,15 @@ int main() if (obj_p == obj_cp) foo(); /* Ok */ if (obj_cp == obj_p) foo(); /* Ok */ - if (obj_p == obj_C) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('id<MyProtocol>' and 'Class')}} - if (obj_C == obj_p) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('Class' and 'id<MyProtocol>')}} + if (obj_p == obj_C) foo(); // expected-warning {{comparison of distinct pointer types ('id<MyProtocol>' and 'Class')}} + if (obj_C == obj_p) foo(); // expected-warning {{comparison of distinct pointer types ('Class' and 'id<MyProtocol>')}} - if (obj_p == obj_CP) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('id<MyProtocol>' and 'Class<MyProtocol>')}} - if (obj_CP == obj_p) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('Class<MyProtocol>' and 'id<MyProtocol>')}} + if (obj_p == obj_CP) foo(); // expected-warning {{comparison of distinct pointer types ('id<MyProtocol>' and 'Class<MyProtocol>')}} + if (obj_CP == obj_p) foo(); // expected-warning {{comparison of distinct pointer types ('Class<MyProtocol>' and 'id<MyProtocol>')}} /* Comparisons between MyOtherClass * and Class types is a warning */ - if (obj_cp == obj_C) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('MyOtherClass *' and 'Class')}} - if (obj_C == obj_cp) foo(); // FIXME -- should warn {{comparison of distinct pointer types ('Class' and 'MyOtherClass *')}} + if (obj_cp == obj_C) foo(); // expected-warning {{comparison of distinct pointer types ('MyOtherClass *' and 'Class')}} + if (obj_C == obj_cp) foo(); // expected-warning {{comparison of distinct pointer types ('Class' and 'MyOtherClass *')}} if (obj_cp == obj_CP) foo(); // expected-warning {{comparison of distinct pointer types ('MyOtherClass *' and 'Class<MyProtocol>')}} if (obj_CP == obj_cp) foo(); // expected-warning {{comparison of distinct pointer types ('Class<MyProtocol>' and 'MyOtherClass *')}} Modified: cfe/trunk/test/SemaObjCXX/comptypes-7.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/comptypes-7.mm?rev=375125&r1=375124&r2=375125&view=diff ============================================================================== --- cfe/trunk/test/SemaObjCXX/comptypes-7.mm (original) +++ cfe/trunk/test/SemaObjCXX/comptypes-7.mm Thu Oct 17 08:27:04 2019 @@ -47,23 +47,23 @@ int main() if (obj == i) foo() ; // expected-error {{comparison between pointer and integer ('id' and 'int')}} if (i == obj) foo() ; // expected-error {{comparison between pointer and integer ('int' and 'id')}} - if (obj == j) foo() ; // expected-error {{invalid operands to binary expression ('id' and 'int *')}} - if (j == obj) foo() ; // expected-error {{invalid operands to binary expression ('int *' and 'id')}} + if (obj == j) foo() ; // expected-error {{comparison of distinct pointer types ('id' and 'int *')}} + if (j == obj) foo() ; // expected-error {{comparison of distinct pointer types ('int *' and 'id')}} if (obj_c == i) foo() ; // expected-error {{comparison between pointer and integer ('MyClass *' and 'int')}} if (i == obj_c) foo() ; // expected-error {{comparison between pointer and integer ('int' and 'MyClass *')}} - if (obj_c == j) foo() ; // expected-error {{invalid operands to binary expression ('MyClass *' and 'int *')}} - if (j == obj_c) foo() ; // expected-error {{invalid operands to binary expression ('int *' and 'MyClass *')}} + if (obj_c == j) foo() ; // expected-error {{comparison of distinct pointer types ('MyClass *' and 'int *')}} + if (j == obj_c) foo() ; // expected-error {{comparison of distinct pointer types ('int *' and 'MyClass *')}} if (obj_p == i) foo() ; // expected-error {{comparison between pointer and integer ('id<MyProtocol>' and 'int')}} if (i == obj_p) foo() ; // expected-error {{comparison between pointer and integer ('int' and 'id<MyProtocol>')}} - if (obj_p == j) foo() ; // expected-error {{invalid operands to binary expression ('id<MyProtocol>' and 'int *')}} - if (j == obj_p) foo() ; // expected-error {{invalid operands to binary expression ('int *' and 'id<MyProtocol>')}} + if (obj_p == j) foo() ; // expected-error {{comparison of distinct pointer types ('id<MyProtocol>' and 'int *')}} + if (j == obj_p) foo() ; // expected-error {{comparison of distinct pointer types ('int *' and 'id<MyProtocol>')}} if (obj_C == i) foo() ; // expected-error {{comparison between pointer and integer ('Class' and 'int')}} if (i == obj_C) foo() ; // expected-error {{comparison between pointer and integer ('int' and 'Class')}} - if (obj_C == j) foo() ; // expected-error {{invalid operands to binary expression ('Class' and 'int *')}} - if (j == obj_C) foo() ; // expected-error {{invalid operands to binary expression ('int *' and 'Class')}} + if (obj_C == j) foo() ; // expected-error {{comparison of distinct pointer types ('Class' and 'int *')}} + if (j == obj_C) foo() ; // expected-error {{comparison of distinct pointer types ('int *' and 'Class')}} Class bar1 = nil; Class <MyProtocol> bar = nil; Modified: cfe/trunk/test/SemaObjCXX/instancetype.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/instancetype.mm?rev=375125&r1=375124&r2=375125&view=diff ============================================================================== --- cfe/trunk/test/SemaObjCXX/instancetype.mm (original) +++ cfe/trunk/test/SemaObjCXX/instancetype.mm Thu Oct 17 08:27:04 2019 @@ -5,7 +5,7 @@ #endif @interface Root -+ (instancetype)alloc; // FIXME -- should note {{explicitly declared 'instancetype'}} ++ (instancetype)alloc; // expected-note {{explicitly declared 'instancetype'}} - (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}} - (instancetype)self; // expected-note {{explicitly declared 'instancetype'}} - (Class)class; @@ -143,7 +143,7 @@ void test_instancetype_narrow_method_sea @implementation Subclass4 + (id)alloc { - return self; // FIXME -- should error{{cannot initialize return object of type 'Subclass4 *' with an lvalue of type 'Class'}} + return self; // expected-error{{cannot initialize return object of type 'Subclass4 *' with an lvalue of type 'Class'}} } - (Subclass3 *)init { return 0; } // don't complain: we lost the related return type _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits