diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index fa1e24574e..9c95d0a3de 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -2039,7 +2039,6 @@ isa = PBXProject; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */; compatibilityVersion = "Xcode 2.4"; - developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 99023eeb7a..107dafe70a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -4404,33 +4404,17 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, if (const ObjCObjectPointerType *lhsOPT = lhs->getAsObjCInterfacePointerType()) { - if (lhsOPT->qual_empty()) { - bool match = false; - if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) { - for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(), - E = rhsQID->qual_end(); I != E; ++I) { - // when comparing an id

on rhs with a static type on lhs, - // static class must implement all of id's protocols directly or - // indirectly through its super class. - if (lhsID->ClassImplementsProtocol(*I, true)) { - match = true; - break; - } - } - if (!match) - return false; - } - return true; - } - // Both the right and left sides have qualifiers. + // If both the right and left sides have qualifiers. for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(), E = lhsOPT->qual_end(); I != E; ++I) { ObjCProtocolDecl *lhsProto = *I; bool match = false; - // when comparing an id

on lhs with a static type on rhs, + // when comparing an id

on rhs with a static type on lhs, // see if static class implements all of id's protocols, directly or // through its super class and categories. + // First, lhs protocols in the qualifier list must be found, direct + // or indirect in rhs's qualifier list or it is a mismatch. for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(), E = rhsQID->qual_end(); J != E; ++J) { ObjCProtocolDecl *rhsProto = *J; @@ -4443,6 +4427,35 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, if (!match) return false; } + + // Static class's protocols, or its super class or category protocols + // must be found, direct or indirect in rhs's qualifier list or it is a mismatch. + if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) { + llvm::SmallPtrSet LHSInheritedProtocols; + CollectInheritedProtocols(lhsID, LHSInheritedProtocols); + // This is rather dubious but matches gcc's behavior. If lhs has + // no type qualifier and its class has no static protocol(s) assume + // assume that it is mismatch. + if (LHSInheritedProtocols.empty() && lhsOPT->qual_empty()) + return false; + for (llvm::SmallPtrSet::iterator I = + LHSInheritedProtocols.begin(), + E = LHSInheritedProtocols.end(); I != E; ++I) { + bool match = false; + ObjCProtocolDecl *lhsProto = (*I); + for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(), + E = rhsQID->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + if (!match) + return false; + } + } return true; } return false; diff --git a/test/SemaObjC/comptypes-10.m b/test/SemaObjC/comptypes-10.m new file mode 100644 index 0000000000..0a2219099f --- /dev/null +++ b/test/SemaObjC/comptypes-10.m @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +//rdar: //8591619 +// pr8453 + +@protocol NSCopying @end +@protocol NSPROTO @end +@protocol NSPROTO1 @end +@protocol NSPROTO2 @end + +@interface NSObject { + Class isa; +} +@end + +void gorf(NSObject *); // expected-note {{passing argument to parameter here}} + +NSObject *foo(id bar, id id_obj) +{ + NSObject *Init = bar; // expected-warning {{initializing 'NSObject *' with an expression of incompatible type 'id'}} + NSObject *Init1 = bar; // expected-warning {{initializing 'NSObject *' with an expression of incompatible type 'id'}} + + NSObject *I = id_obj; + NSObject *I1 = id_obj; + gorf(bar); // expected-warning {{passing 'id' to parameter of incompatible type 'NSObject *'}} + + gorf(id_obj); + + return bar; // expected-warning {{returning 'id' from a function with incompatible result type 'NSObject *'}} +} + +void test(id bar) +{ + NSObject *Init = bar; // expected-warning {{initializing 'NSObject *' with an expression of incompatible type 'id'}} +}