From b0489814dcb3cb801eeb0784cc6b6fcf575ff71d Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 7 Apr 2008 06:38:24 +0000 Subject: [PATCH] merge compatibility testing of qualified/unqualified interfaces together and fix a bug. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49322 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ASTContext.cpp | 77 +++++++++++++++++------------------- test/Sema/objc-comptypes-5.m | 4 +- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c071e5ebd6..f6330f67ab 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -839,7 +839,7 @@ QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl, SortAndUniqueProtocols(Protocols, NumProtocols); llvm::FoldingSetNodeID ID; - ObjCQualifiedInterfaceType::Profile(ID, Protocols, NumProtocols); + ObjCQualifiedInterfaceType::Profile(ID, Decl, Protocols, NumProtocols); void *InsertPos = 0; if (ObjCQualifiedInterfaceType *QT = @@ -1435,40 +1435,40 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { ObjCConstantStringType = getObjCInterfaceType(Decl); } -/// areCompatObjCInterfaces - This routine is called when we are testing -/// compatibility of two different [potentially qualified] ObjCInterfaceType's. -static bool areCompatObjCInterfaces(const ObjCInterfaceType *LHS, - const ObjCInterfaceType *RHS) { - // II is compatible with II

if the base is the same. Otherwise, no two - // qualified interface types are the same. - if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl())) - return false; - - // If the base decls match and one is a qualified interface and one isn't, - // then they are compatible. - return isa(LHS) != - isa(RHS); -} -/// areCompatObjCQualInterfaces - Return true if the two qualified interface -/// types are compatible for assignment from RHS to LHS. +/// areCompatObjCInterfaces - Return true if the two interface types are +/// compatible for assignment from RHS to LHS. This handles validation of any +/// protocol qualifiers on the LHS or RHS. /// static bool -areCompatObjCQualInterfaces(const ObjCQualifiedInterfaceType *LHS, - const ObjCQualifiedInterfaceType *RHS) { +areCompatObjCInterfaces(const ObjCInterfaceType *LHS, + const ObjCInterfaceType *RHS) { // Verify that the base decls are compatible: the RHS must be a subclass of // the LHS. if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl())) return false; + + // RHS must have a superset of the protocols in the LHS. If the LHS is not + // protocol qualified at all, then we are good. + if (!isa(LHS)) + return true; + + // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it + // isn't a superset. + if (!isa(RHS)) + return true; // FIXME: should return false! + + // Finally, we must have two protocol-qualified interfaces. + const ObjCQualifiedInterfaceType *LHSP =cast(LHS); + const ObjCQualifiedInterfaceType *RHSP =cast(RHS); + ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHSP->qual_begin(); + ObjCQualifiedInterfaceType::qual_iterator LHSPE = LHSP->qual_end(); + ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHSP->qual_begin(); + ObjCQualifiedInterfaceType::qual_iterator RHSPE = RHSP->qual_end(); // All protocols in LHS must have a presence in RHS. Since the protocol lists // are both sorted alphabetically and have no duplicates, we can scan RHS and // LHS in a single parallel scan until we run out of elements in LHS. - ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHS->qual_begin(); - ObjCQualifiedInterfaceType::qual_iterator LHSPE = LHS->qual_end(); - ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHS->qual_begin(); - ObjCQualifiedInterfaceType::qual_iterator RHSPE = RHS->qual_end(); - assert(LHSPI != LHSPE && "Empty LHS protocol list?"); ObjCProtocolDecl *LHSProto = *LHSPI; @@ -1653,19 +1653,17 @@ bool ASTContext::typesAreCompatible(QualType LHS_NC, QualType RHS_NC) { if (LHSClass == Type::OCUVector) LHSClass = Type::Vector; if (RHSClass == Type::OCUVector) RHSClass = Type::Vector; + // Consider qualified interfaces and interfaces the same. + if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface; + if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface; + // If the canonical type classes don't match. if (LHSClass != RHSClass) { - // For Objective-C, it is possible for two types to be compatible - // when their classes don't match (when dealing with "id"). If either type - // is an interface, we defer to areCompatObjCIDType(). - if (const ObjCInterfaceType *LHSIT = LHS->getAsObjCInterfaceType()) { - if (const ObjCInterfaceType *RHSIT = RHS->getAsObjCInterfaceType()) - return areCompatObjCInterfaces(LHSIT, RHSIT); - return isObjCIdType(RHS); // ID is compatible with all interface types. - } - - if (RHS->isObjCInterfaceType()) - return isObjCIdType(LHS); // ID is compatible with all interface types. + // ID is compatible with all interface types. + if (isa(LHS)) + return isObjCIdType(RHS); + if (isa(RHS)) + return isObjCIdType(LHS); // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, // a signed integer type, or an unsigned integer type. @@ -1688,6 +1686,7 @@ bool ASTContext::typesAreCompatible(QualType LHS_NC, QualType RHS_NC) { case Type::VariableArray: case Type::IncompleteArray: case Type::Reference: + case Type::ObjCQualifiedInterface: assert(0 && "Canonicalized away above"); case Type::Pointer: return pointerTypesAreCompatible(LHS, RHS); @@ -1703,12 +1702,8 @@ bool ASTContext::typesAreCompatible(QualType LHS_NC, QualType RHS_NC) { case Type::Vector: return areCompatVectorTypes(cast(LHS), cast(RHS)); case Type::ObjCInterface: - // The LHS must be a superclass of the RHS. - return cast(LHS)->getDecl()->isSuperClassOf( - cast(RHS)->getDecl()); - case Type::ObjCQualifiedInterface: - return areCompatObjCQualInterfaces(cast(LHS), - cast(RHS)); + return areCompatObjCInterfaces(cast(LHS), + cast(RHS)); default: assert(0 && "unexpected type"); } diff --git a/test/Sema/objc-comptypes-5.m b/test/Sema/objc-comptypes-5.m index 7101e96043..f12fa9ab5d 100644 --- a/test/Sema/objc-comptypes-5.m +++ b/test/Sema/objc-comptypes-5.m @@ -24,6 +24,7 @@ int main() MyClass *obj_c_cat_p = nil; MyOtherClass *obj_c_super_p = nil; MyOtherClass *obj_c_super_p_q = nil; + MyClass *obj_c_cat_p_q = nil; obj_c_cat_p = obj_id_p; // expected-error {{incompatible type assigning 'id', expected 'MyClass *'}} obj_c_super_p = obj_id_p; // expected-error {{incompatible type assigning 'id', expected 'MyOtherClass *'}} @@ -37,6 +38,7 @@ int main() obj_c_cat_p = obj_c_super_p; // ok. obj_c_cat_p = obj_c_super_p_q; // ok. - + obj_c_super_p = obj_c_cat_p_q; // expected-warning {{incompatible pointer types}} + obj_c_cat_p_q = obj_c_super_p; return 0; }