diff options
43 files changed, 892 insertions, 755 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index fbd56023d6..b13028d8f7 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -107,7 +107,6 @@ class ASTContext { /// ObjCIdType - a pseudo built-in typedef type (set by Sema). QualType ObjCIdType; - const RecordType *IdStructType; /// ObjCSelType - another pseudo built-in typedef type (set by Sema). QualType ObjCSelType; @@ -119,7 +118,6 @@ class ASTContext { /// ObjCClassType - another pseudo built-in typedef type (set by Sema). QualType ObjCClassType; - const RecordType *ClassStructType; QualType ObjCConstantStringType; RecordDecl *CFConstantStringTypeDecl; @@ -375,7 +373,7 @@ public: /// getObjCObjectPointerType - Return a ObjCObjectPointerType type for the /// given interface decl and the conforming protocol list. - QualType getObjCObjectPointerType(ObjCInterfaceDecl *Decl, + QualType getObjCObjectPointerType(QualType OIT = QualType(), ObjCProtocolDecl **ProtocolList = 0, unsigned NumProtocols = 0); @@ -770,26 +768,18 @@ public: bool isObjCIdType(QualType T) const { return T == ObjCIdType; } - bool isObjCIdStructType(QualType T) const { - if (!IdStructType) // ObjC isn't enabled - return false; - return T->getAsStructureType() == IdStructType; - } bool isObjCClassType(QualType T) const { return T == ObjCClassType; } - bool isObjCClassStructType(QualType T) const { - if (!ClassStructType) // ObjC isn't enabled - return false; - return T->getAsStructureType() == ClassStructType; - } bool isObjCSelType(QualType T) const { assert(SelStructType && "isObjCSelType used before 'SEL' type is built"); return T->getAsStructureType() == SelStructType; } // Check the safety of assignment from LHS to RHS - bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS, + bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT); + bool canAssignObjCInterfaces(const ObjCInterfaceType *LHS, const ObjCInterfaceType *RHS); bool areComparableObjCPointerTypes(QualType LHS, QualType RHS); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 39eb1842b3..8de6a03c8f 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -396,9 +396,13 @@ public: bool isVectorType() const; // GCC vector type. bool isExtVectorType() const; // Extended vector type. bool isObjCObjectPointerType() const; // Pointer to *any* ObjC object. + // FIXME: change this to 'raw' interface type, so we can used 'interface' type + // for the common case. bool isObjCInterfaceType() const; // NSString or NSString<foo> bool isObjCQualifiedInterfaceType() const; // NSString<foo> bool isObjCQualifiedIdType() const; // id<foo> + bool isObjCIdType() const; // id + bool isObjCClassType() const; // Class bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++0x nullptr_t @@ -443,9 +447,12 @@ public: const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. const ExtVectorType *getAsExtVectorType() const; // Extended vector type. const ObjCObjectPointerType *getAsObjCObjectPointerType() const; + // The following is a convenience method that returns an ObjCObjectPointerType + // for object declared using an interface. + const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; + const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; const ObjCInterfaceType *getAsObjCInterfaceType() const; const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const; - const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; const TemplateTypeParmType *getAsTemplateTypeParmType() const; const TemplateSpecializationType * @@ -460,6 +467,10 @@ public: /// This method should never be used when type qualifiers are meaningful. const Type *getArrayElementTypeNoTypeQual() const; + /// getPointeeType - If this is a pointer or ObjC object pointer, this + /// returns the respective pointee. + QualType getPointeeType() const; + /// getDesugaredType - Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of /// the type is already concrete, it returns it unmodified. This is similar @@ -1809,53 +1820,6 @@ public: static bool classof(const TypenameType *T) { return true; } }; -/// ObjCObjectPointerType - Used to represent 'id', 'Interface *', 'id <p>', -/// and 'Interface <p> *'. -/// -/// Duplicate protocols are removed and protocol list is canonicalized to be in -/// alphabetical order. -class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { - ObjCInterfaceDecl *Decl; - // List of protocols for this protocol conforming object type - // List is sorted on protocol name. No protocol is entered more than once. - llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols; - - ObjCObjectPointerType(ObjCInterfaceDecl *D, - ObjCProtocolDecl **Protos, unsigned NumP) : - Type(ObjCObjectPointer, QualType(), /*Dependent=*/false), - Decl(D), Protocols(Protos, Protos+NumP) { } - friend class ASTContext; // ASTContext creates these. - -public: - ObjCInterfaceDecl *getDecl() const { return Decl; } - - /// isObjCQualifiedIdType - true for "id <p>". - bool isObjCQualifiedIdType() const { return Decl == 0 && Protocols.size(); } - - /// qual_iterator and friends: this provides access to the (potentially empty) - /// list of protocols qualifying this interface. - typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator; - - qual_iterator qual_begin() const { return Protocols.begin(); } - qual_iterator qual_end() const { return Protocols.end(); } - bool qual_empty() const { return Protocols.size() == 0; } - - /// getNumProtocols - Return the number of qualifying protocols in this - /// interface type, or 0 if there are none. - unsigned getNumProtocols() const { return Protocols.size(); } - - void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **protocols, unsigned NumProtocols); - virtual void getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const; - static bool classof(const Type *T) { - return T->getTypeClass() == ObjCObjectPointer; - } - static bool classof(const ObjCObjectPointerType *) { return true; } -}; - /// ObjCInterfaceType - Interfaces are the core concept in Objective-C for /// object oriented design. They basically correspond to C++ classes. There /// are two kinds of interface types, normal interfaces like "NSString" and @@ -1868,10 +1832,15 @@ protected: ObjCInterfaceType(TypeClass tc, ObjCInterfaceDecl *D) : Type(tc, QualType(), /*Dependent=*/false), Decl(D) { } friend class ASTContext; // ASTContext creates these. + + // FIXME: These can go away when we move ASTContext::canAssignObjCInterfaces + // to this class (as a static helper). + bool isObjCIdInterface() const; + bool isObjCClassInterface() const; public: ObjCInterfaceDecl *getDecl() const { return Decl; } - + /// qual_iterator and friends: this provides access to the (potentially empty) /// list of protocols qualifying this interface. If this is an instance of /// ObjCQualifiedInterfaceType it returns the list, otherwise it returns an @@ -1893,11 +1862,85 @@ public: static bool classof(const ObjCInterfaceType *) { return true; } }; +/// ObjCObjectPointerType - Used to represent 'id', 'Interface *', 'id <p>', +/// and 'Interface <p> *'. +/// +/// Duplicate protocols are removed and protocol list is canonicalized to be in +/// alphabetical order. +class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; // will always point to an interface type. + + // List of protocols for this protocol conforming object type + // List is sorted on protocol name. No protocol is entered more than once. + llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols; + + ObjCObjectPointerType(QualType T, ObjCProtocolDecl **Protos, unsigned NumP) : + Type(ObjCObjectPointer, QualType(), /*Dependent=*/false), + PointeeType(T), Protocols(Protos, Protos+NumP) { } + friend class ASTContext; // ASTContext creates these. + friend class ObjCInterfaceType; // To enable 'id' and 'Class' predicates. + + static ObjCInterfaceType *IdInterfaceT; + static ObjCInterfaceType *ClassInterfaceT; + static void setIdInterface(QualType T) { + IdInterfaceT = dyn_cast<ObjCInterfaceType>(T.getTypePtr()); + } + static void setClassInterface(QualType T) { + ClassInterfaceT = dyn_cast<ObjCInterfaceType>(T.getTypePtr()); + } + static ObjCInterfaceType *getIdInterface() { return IdInterfaceT; } + static ObjCInterfaceType *getClassInterface() { return ClassInterfaceT; } +public: + // Get the pointee type. Pointee is required to always be an interface type. + // Note: Pointee can be a TypedefType whose canonical type is an interface. + // Example: typedef NSObject T; T *var; + QualType getPointeeType() const { return PointeeType; } + + const ObjCInterfaceType *getInterfaceType() const { + return PointeeType->getAsObjCInterfaceType(); + } + ObjCInterfaceDecl *getInterfaceDecl() const { + return getInterfaceType()->getDecl(); + } + /// isObjCQualifiedIdType - true for "id <p>". + bool isObjCQualifiedIdType() const { + return getInterfaceType() == IdInterfaceT && Protocols.size(); + } + bool isObjCIdType() const { + return getInterfaceType() == IdInterfaceT && !Protocols.size(); + } + bool isObjCClassType() const { + return getInterfaceType() == ClassInterfaceT && !Protocols.size(); + } + /// qual_iterator and friends: this provides access to the (potentially empty) + /// list of protocols qualifying this interface. + typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator; + + qual_iterator qual_begin() const { return Protocols.begin(); } + qual_iterator qual_end() const { return Protocols.end(); } + bool qual_empty() const { return Protocols.size() == 0; } + + /// getNumProtocols - Return the number of qualifying protocols in this + /// interface type, or 0 if there are none. + unsigned getNumProtocols() const { return Protocols.size(); } + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, QualType T, + ObjCProtocolDecl **protocols, unsigned NumProtocols); + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCObjectPointer; + } + static bool classof(const ObjCObjectPointerType *) { return true; } +}; + /// ObjCQualifiedInterfaceType - This class represents interface types /// conforming to a list of protocols, such as INTF<Proto1, Proto2, Proto1>. /// /// Duplicate protocols are removed and protocol list is canonicalized to be in /// alphabetical order. +/// FIXME: Remove this class (converting uses to ObjCObjectPointerType). class ObjCQualifiedInterfaceType : public ObjCInterfaceType, public llvm::FoldingSetNode { @@ -1983,7 +2026,7 @@ inline QualType::GCAttrTypes QualType::getObjCGCAttr() const { return AT->getElementType().getObjCGCAttr(); if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CT)) return EXTQT->getObjCGCAttr(); - if (const PointerType *PT = CT->getAsPointerType()) + if (const ObjCObjectPointerType *PT = CT->getAsObjCObjectPointerType()) return PT->getPointeeType().getObjCGCAttr(); return GCNone; } @@ -2115,6 +2158,18 @@ inline bool Type::isObjCQualifiedIdType() const { } return false; } +inline bool Type::isObjCIdType() const { + if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) { + return OPT->isObjCIdType(); + } + return false; +} +inline bool Type::isObjCClassType() const { + if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) { + return OPT->isObjCClassType(); + } + return false; +} inline bool Type::isTemplateTypeParmType() const { return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType()); } @@ -2134,12 +2189,12 @@ inline bool Type::isOverloadableType() const { inline bool Type::hasPointerRepresentation() const { return (isPointerType() || isReferenceType() || isBlockPointerType() || - isObjCInterfaceType() || isObjCQualifiedIdType() || + isObjCInterfaceType() || isObjCObjectPointerType() || isObjCQualifiedInterfaceType() || isNullPtrType()); } inline bool Type::hasObjCPointerRepresentation() const { - return (isObjCInterfaceType() || isObjCQualifiedIdType() || + return (isObjCInterfaceType() || isObjCObjectPointerType() || isObjCQualifiedInterfaceType()); } diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h index 4bc5e27aac..dd7c93639f 100644 --- a/include/clang/Analysis/PathSensitive/SVals.h +++ b/include/clang/Analysis/PathSensitive/SVals.h @@ -196,7 +196,7 @@ public: } static inline bool IsLocType(QualType T) { - return T->isPointerType() || T->isObjCQualifiedIdType() + return T->isPointerType() || T->isObjCObjectPointerType() || T->isBlockPointerType(); } }; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 2bd1482adc..dbac120d26 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -42,8 +42,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, Idents(idents), Selectors(sels), BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { if (size_reserve > 0) Types.reserve(size_reserve); - InitBuiltinTypes(); TUDecl = TranslationUnitDecl::Create(*this); + InitBuiltinTypes(); } ASTContext::~ASTContext() { @@ -190,11 +190,10 @@ void ASTContext::InitBuiltinTypes() { LongDoubleComplexTy = getComplexType(LongDoubleTy); BuiltinVaListType = QualType(); + ObjCIdType = QualType(); - IdStructType = 0; ObjCClassType = QualType(); - ClassStructType = 0; - + ObjCConstantStringType = QualType(); // void * type @@ -1071,7 +1070,7 @@ QualType ASTContext::getObjCGCQualType(QualType T, if (T->isPointerType()) { QualType Pointee = T->getAsPointerType()->getPointeeType(); - if (Pointee->isPointerType()) { + if (Pointee->isPointerType() || Pointee->isObjCObjectPointerType()) { QualType ResultType = getObjCGCQualType(Pointee, GCAttr); return getPointerType(ResultType); } @@ -1847,15 +1846,18 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, /// getObjCObjectPointerType - Return a ObjCObjectPointerType type for /// the given interface decl and the conforming protocol list. -QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl, +QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, ObjCProtocolDecl **Protocols, unsigned NumProtocols) { + if (InterfaceT.isNull()) + InterfaceT = QualType(ObjCObjectPointerType::getIdInterface(), 0); + // Sort the protocol list alphabetically to canonicalize it. if (NumProtocols) SortAndUniqueProtocols(Protocols, NumProtocols); llvm::FoldingSetNodeID ID; - ObjCObjectPointerType::Profile(ID, Decl, Protocols, NumProtocols); + ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols); void *InsertPos = 0; if (ObjCObjectPointerType *QT = @@ -1864,7 +1866,7 @@ QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl, // No Match; ObjCObjectPointerType *QType = - new (*this,8) ObjCObjectPointerType(Decl, Protocols, NumProtocols); + new (*this,8) ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols); Types.push_back(QType); ObjCObjectPointerTypes.InsertNode(QType, InsertPos); @@ -2745,25 +2747,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += 'j'; getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false, false); - } else if (T->isObjCQualifiedIdType()) { - getObjCEncodingForTypeImpl(getObjCIdType(), S, - ExpandPointedToStructures, - ExpandStructures, FD); - if (FD || EncodingProperty) { - // Note that we do extended encoding of protocol qualifer list - // Only when doing ivar or property encoding. - const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType(); - S += '"'; - for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(), - E = QIDT->qual_end(); I != E; ++I) { - S += '<'; - S += (*I)->getNameAsString(); - S += '>'; - } - S += '"'; - } - return; - } + } else if (const PointerType *PT = T->getAsPointerType()) { QualType PointeeTy = PT->getPointeeType(); bool isReadOnly = false; @@ -2797,42 +2781,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S.replace(S.end()-2, S.end(), replace); } } - if (isObjCIdStructType(PointeeTy)) { - S += '@'; - return; - } - else if (PointeeTy->isObjCInterfaceType()) { - if (!EncodingProperty && - isa<TypedefType>(PointeeTy.getTypePtr())) { - // Another historical/compatibility reason. - // We encode the underlying type which comes out as - // {...}; - S += '^'; - getObjCEncodingForTypeImpl(PointeeTy, S, - false, ExpandPointedToStructures, - NULL); - return; - } - S += '@'; - if (FD || EncodingProperty) { - const ObjCInterfaceType *OIT = - PointeeTy.getUnqualifiedType()->getAsObjCInterfaceType(); - ObjCInterfaceDecl *OI = OIT->getDecl(); - S += '"'; - S += OI->getNameAsCString(); - for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(), - E = OIT->qual_end(); I != E; ++I) { - S += '<'; - S += (*I)->getNameAsString(); - S += '>'; - } - S += '"'; - } - return; - } else if (isObjCClassStructType(PointeeTy)) { - S += '#'; - return; - } else if (isObjCSelType(PointeeTy)) { + if (isObjCSelType(PointeeTy)) { S += ':'; return; } @@ -2937,7 +2886,61 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } S += '}'; } - else + else if (const ObjCObjectPointerType *OPT = T->getAsObjCObjectPointerType()) { + if (OPT->isObjCIdType()) { + S += '@'; + return; + } else if (OPT->isObjCClassType()) { + S += '#'; + return; + } else if (OPT->isObjCQualifiedIdType()) { + getObjCEncodingForTypeImpl(getObjCIdType(), S, + ExpandPointedToStructures, + ExpandStructures, FD); + if (FD || EncodingProperty) { + // Note that we do extended encoding of protocol qualifer list + // Only when doing ivar or property encoding. + const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType(); + S += '"'; + for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(), + E = QIDT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } else { + QualType PointeeTy = OPT->getPointeeType(); + if (!EncodingProperty && + isa<TypedefType>(PointeeTy.getTypePtr())) { + // Another historical/compatibility reason. + // We encode the underlying type which comes out as + // {...}; + S += '^'; + getObjCEncodingForTypeImpl(PointeeTy, S, + false, ExpandPointedToStructures, + NULL); + return; + } + S += '@'; + if (FD || EncodingProperty) { + const ObjCInterfaceType *OIT = OPT->getInterfaceType(); + ObjCInterfaceDecl *OI = OIT->getDecl(); + S += '"'; + S += OI->getNameAsCString(); + for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(), + E = OIT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } + } else assert(0 && "@encode for type not implemented!"); } @@ -2967,23 +2970,12 @@ void ASTContext::setBuiltinVaListType(QualType T) void ASTContext::setObjCIdType(QualType T) { ObjCIdType = T; - const TypedefType *TT = T->getAsTypedefType(); - if (!TT) - return; - - TypedefDecl *TD = TT->getDecl(); - - // typedef struct objc_object *id; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); - // User error - caller will issue diagnostics. - if (!ptr) - return; - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - // User error - caller will issue diagnostics. - if (!rec) - return; - IdStructType = rec; + assert(TT && "missing 'id' typedef"); + const ObjCObjectPointerType *OPT = + TT->getDecl()->getUnderlyingType()->getAsObjCObjectPointerType(); + assert(OPT && "missing 'id' type"); + ObjCObjectPointerType::setIdInterface(OPT->getPointeeType()); } void ASTContext::setObjCSelType(QualType T) @@ -3013,18 +3005,12 @@ void ASTContext::setObjCProtoType(QualType QT) void ASTContext::setObjCClassType(QualType T) { ObjCClassType = T; - const TypedefType *TT = T->getAsTypedefType(); - if (!TT) - return; - TypedefDecl *TD = TT->getDecl(); - - // typedef struct objc_class *Class; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); - assert(ptr && "'Class' incorrectly typed"); - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - assert(rec && "'Class' incorrectly typed"); - ClassStructType = rec; + assert(TT && "missing 'Class' typedef"); + const ObjCObjectPointerType *OPT = + TT->getDecl()->getUnderlyingType()->getAsObjCObjectPointerType(); + assert(OPT && "missing 'Class' type"); + ObjCObjectPointerType::setClassInterface(OPT->getPointeeType()); } void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { @@ -3123,6 +3109,8 @@ bool ASTContext::isObjCNSObjectType(QualType Ty) const { /// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified /// ID type). bool ASTContext::isObjCObjectPointerType(QualType Ty) const { + if (Ty->isObjCObjectPointerType()) + return true; if (Ty->isObjCQualifiedIdType()) return true; @@ -3198,8 +3186,30 @@ static bool areCompatVectorTypes(const VectorType *LHS, /// compatible for assignment from RHS to LHS. This handles validation of any /// protocol qualifiers on the LHS or RHS. /// +/// FIXME: Move the following to ObjCObjectPointerType/ObjCInterfaceType. +bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT) { + // If either interface represents the built-in 'id' or 'Class' types, + // then return true (no need to call canAssignObjCInterfaces()). + if (LHSOPT->isObjCIdType() || RHSOPT->isObjCIdType() || + LHSOPT->isObjCClassType() || RHSOPT->isObjCClassType()) + return true; + + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + if (!LHS || !RHS) + return false; + return canAssignObjCInterfaces(LHS, RHS); +} + bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, const ObjCInterfaceType *RHS) { + // If either interface represents the built-in 'id' or 'Class' types, + // then return true. + if (LHS->isObjCIdInterface() || RHS->isObjCIdInterface() || + LHS->isObjCClassInterface() || RHS->isObjCClassInterface()) + return true; + // Verify that the base decls are compatible: the RHS must be a subclass of // the LHS. if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl())) @@ -3245,25 +3255,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { // get the "pointed to" types - const PointerType *LHSPT = LHS->getAsPointerType(); - const PointerType *RHSPT = RHS->getAsPointerType(); + const ObjCObjectPointerType *LHSOPT = LHS->getAsObjCObjectPointerType(); + const ObjCObjectPointerType *RHSOPT = RHS->getAsObjCObjectPointerType(); - if (!LHSPT || !RHSPT) - return false; - - QualType lhptee = LHSPT->getPointeeType(); - QualType rhptee = RHSPT->getPointeeType(); - const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType(); - // ID acts sort of like void* for ObjC interfaces - if (LHSIface && isObjCIdStructType(rhptee)) - return true; - if (RHSIface && isObjCIdStructType(lhptee)) - return true; - if (!LHSIface || !RHSIface) + if (!LHSOPT || !RHSOPT) return false; - return canAssignObjCInterfaces(LHSIface, RHSIface) || - canAssignObjCInterfaces(RHSIface, LHSIface); + + return canAssignObjCInterfaces(LHSOPT, RHSOPT) || + canAssignObjCInterfaces(RHSOPT, LHSOPT); } /// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, @@ -3406,8 +3405,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { // issue error. if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) || (GCAttr == QualType::Strong && GCLHSAttr != GCAttr && - LHSCan->isPointerType() && !isObjCObjectPointerType(LHSCan) && - !isObjCIdStructType(LHSCan->getAsPointerType()->getPointeeType()))) + !LHSCan->isObjCObjectPointerType())) return QualType(); RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(), @@ -3432,8 +3430,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { // issue error. if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) || (GCAttr == QualType::Strong && GCRHSAttr != GCAttr && - RHSCan->isPointerType() && !isObjCObjectPointerType(RHSCan) && - !isObjCIdStructType(RHSCan->getAsPointerType()->getPointeeType()))) + !RHSCan->isObjCObjectPointerType())) return QualType(); LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(), @@ -3460,47 +3457,12 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { if (RHSClass == Type::ExtVector) RHSClass = Type::Vector; // Consider qualified interfaces and interfaces the same. + // FIXME: Remove (ObjCObjectPointerType should obsolete this funny business). 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) { - const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType(); - - // 'id' and 'Class' act sort of like void* for ObjC interfaces - if (LHSIface && (isObjCIdStructType(RHS) || isObjCClassStructType(RHS))) - return LHS; - if (RHSIface && (isObjCIdStructType(LHS) || isObjCClassStructType(LHS))) - return RHS; - - // ID is compatible with all qualified id types. - if (LHS->isObjCQualifiedIdType()) { - if (const PointerType *PT = RHS->getAsPointerType()) { - QualType pType = PT->getPointeeType(); - if (isObjCIdStructType(pType) || isObjCClassStructType(pType)) - return LHS; - // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true). - // Unfortunately, this API is part of Sema (which we don't have access - // to. Need to refactor. The following check is insufficient, since we - // need to make sure the class implements the protocol. - if (pType->isObjCInterfaceType()) - return LHS; - } - } - if (RHS->isObjCQualifiedIdType()) { - if (const PointerType *PT = LHS->getAsPointerType()) { - QualType pType = PT->getPointeeType(); - if (isObjCIdStructType(pType) || isObjCClassStructType(pType)) - return RHS; - // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true). - // Unfortunately, this API is part of Sema (which we don't have access - // to. Need to refactor. The following check is insufficient, since we - // need to make sure the class implements the protocol. - if (pType->isObjCInterfaceType()) - return RHS; - } - } // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, // a signed integer type, or an unsigned integer type. if (const EnumType* ETy = LHS->getAsEnumType()) { @@ -3611,9 +3573,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { return mergeFunctionTypes(LHS, RHS); case Type::Record: case Type::Enum: - // FIXME: Why are these compatible? - if (isObjCIdStructType(LHS) && isObjCClassStructType(RHS)) return LHS; - if (isObjCClassStructType(LHS) && isObjCIdStructType(RHS)) return LHS; return QualType(); case Type::Builtin: // Only exactly equal builtin types are compatible, which is tested above. @@ -3638,10 +3597,17 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { return QualType(); } - case Type::ObjCObjectPointer: - // FIXME: finish - // Distinct qualified id's are not compatible. + case Type::ObjCObjectPointer: { + // FIXME: Incorporate tests from Sema::ObjCQualifiedIdTypesAreCompatible(). + if (LHS->isObjCQualifiedIdType() && RHS->isObjCQualifiedIdType()) + return QualType(); + + if (canAssignObjCInterfaces(LHS->getAsObjCObjectPointerType(), + RHS->getAsObjCObjectPointerType())) + return LHS; + return QualType(); + } case Type::FixedWidthInt: // Distinct fixed-width integers are not compatible. return QualType(); diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 54f13e14ba..613dc58a57 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -280,7 +280,7 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, // of the interface (which has been reported). Recover gracefully. if (OID) { selfTy = Context.getObjCInterfaceType(OID); - selfTy = Context.getPointerType(selfTy); + selfTy = Context.getObjCObjectPointerType(selfTy); } else { selfTy = Context.getObjCIdType(); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 970e8bc6c7..2c65179f95 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1095,6 +1095,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { switch (getStmtClass()) { default: break; case StringLiteralClass: + case ObjCStringLiteralClass: case ObjCEncodeExprClass: return true; case CompoundLiteralExprClass: { @@ -1136,7 +1137,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx); break; } - return isEvaluatable(Ctx); } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index eb6b5b725f..c3d0402152 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -382,7 +382,8 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { const Expr* SubExpr = E->getSubExpr(); // Check for pointer->pointer cast - if (SubExpr->getType()->isPointerType()) { + if (SubExpr->getType()->isPointerType() || + SubExpr->getType()->isObjCObjectPointerType()) { APValue Result; if (EvaluatePointer(SubExpr, Result, Info)) return Result; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 78c3b78977..fd368c4815 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -22,6 +22,9 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +ObjCInterfaceType *ObjCObjectPointerType::IdInterfaceT; +ObjCInterfaceType *ObjCObjectPointerType::ClassInterfaceT; + bool QualType::isConstant(ASTContext &Ctx) const { if (isConstQualified()) return true; @@ -295,6 +298,15 @@ const FunctionProtoType *Type::getAsFunctionProtoType() const { return dyn_cast_or_null<FunctionProtoType>(getAsFunctionType()); } +QualType Type::getPointeeType() const { + if (const PointerType *PT = getAsPointerType()) + return PT->getPointeeType(); + if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) + return OPT->getPointeeType(); + if (const BlockPointerType *BPT = getAsBlockPointerType()) + return BPT->getPointeeType(); + return QualType(); +} const PointerType *Type::getAsPointerType() const { // If this is directly a pointer type, return it. @@ -609,6 +621,14 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { return 0; } +const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { + if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) { + if (OPT->getInterfaceType()) + return OPT; + } + return 0; +} + const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const { // There is no sugar for template type parameters, so just return // the canonical type pointer if it is the right class. @@ -1016,16 +1036,18 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **protocols, + QualType OIT, ObjCProtocolDecl **protocols, unsigned NumProtocols) { - ID.AddPointer(Decl); + ID.AddPointer(OIT.getAsOpaquePtr()); for (unsigned i = 0; i != NumProtocols; i++) ID.AddPointer(protocols[i]); } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDecl(), &Protocols[0], getNumProtocols()); + if (getNumProtocols()) + Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols()); + else + Profile(ID, getPointeeType(), 0, 0); } void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, @@ -1663,6 +1685,14 @@ void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingP InnerString = MyString + ' ' + InnerString; } +bool ObjCInterfaceType::isObjCIdInterface() const { + return this == ObjCObjectPointerType::getIdInterface(); +} + +bool ObjCInterfaceType::isObjCClassInterface() const { + return this == ObjCObjectPointerType::getClassInterface(); +} + void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; @@ -1671,15 +1701,7 @@ void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const Prin void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - - std::string ObjCQIString; - - if (getDecl()) - ObjCQIString = getDecl()->getNameAsString(); - else - ObjCQIString = "id"; + std::string ObjCQIString = getInterfaceType()->getDecl()->getNameAsString(); if (!qual_empty()) { ObjCQIString += '<'; @@ -1690,6 +1712,11 @@ void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, } ObjCQIString += '>'; } + if (!isObjCIdType() && !isObjCQualifiedIdType()) + ObjCQIString += " *"; // Don't forget the implicit pointer. + else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + InnerString = ObjCQIString + InnerString; } diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index aa85769157..b454a3605c 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -31,26 +31,21 @@ using namespace clang; -static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) { - Expr* Receiver = ME->getReceiver(); +static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { + const Expr* Receiver = ME->getReceiver(); if (!Receiver) return NULL; - QualType X = Receiver->getType(); - - if (X->isPointerType()) { - Type* TP = X.getTypePtr(); - const PointerType* T = TP->getAsPointerType(); - return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr()); - } + if (const ObjCObjectPointerType *PT = + Receiver->getType()->getAsObjCObjectPointerType()) + return PT->getInterfaceType(); - // FIXME: Support ObjCQualifiedIdType? return NULL; } -static const char* GetReceiverNameType(ObjCMessageExpr* ME) { - ObjCInterfaceType* ReceiverType = GetReceiverType(ME); +static const char* GetReceiverNameType(const ObjCMessageExpr* ME) { + const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName() : NULL; } @@ -67,7 +62,7 @@ class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck { BugReporter& BR; ASTContext &Ctx; - bool isNSString(ObjCInterfaceType* T, const char* suffix); + bool isNSString(const ObjCInterfaceType *T, const char* suffix); bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME); void Warn(NodeTy* N, Expr* E, const std::string& s); @@ -114,7 +109,7 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N, ObjCMessageExpr* ME = cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt()); - ObjCInterfaceType* ReceiverType = GetReceiverType(ME); + const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); if (!ReceiverType) return false; @@ -129,8 +124,7 @@ bool BasicObjCFoundationChecks::Audit(ExplodedNode<GRState>* N, name += 2; - // FIXME: Make all of this faster. - + // FIXME: Make all of this faster. if (isNSString(ReceiverType, name)) return AuditNSString(N, ME); @@ -163,9 +157,8 @@ bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) { // NSString checking. //===----------------------------------------------------------------------===// -bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T, - const char* suffix) { - +bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T, + const char* suffix) { return !strcmp("String", suffix) || !strcmp("MutableString", suffix); } diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index c74668cf0f..1cfd783492 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -547,14 +547,12 @@ public: return I == M.end() ? M.find(ObjCSummaryKey(S)) : I; } - ObjCInterfaceDecl* getReceiverDecl(Expr* E) { - - const PointerType* PT = E->getType()->getAsPointerType(); - if (!PT) return 0; - - ObjCInterfaceType* OI = dyn_cast<ObjCInterfaceType>(PT->getPointeeType()); - - return OI ? OI->getDecl() : 0; + const ObjCInterfaceDecl* getReceiverDecl(Expr* E) { + if (const ObjCObjectPointerType* PT = + E->getType()->getAsObjCObjectPointerType()) + return PT->getInterfaceDecl(); + + return NULL; } iterator end() { return M.end(); } @@ -564,7 +562,7 @@ public: Selector S = ME->getSelector(); if (Expr* Receiver = ME->getReceiver()) { - ObjCInterfaceDecl* OD = getReceiverDecl(Receiver); + const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver); return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; } @@ -886,20 +884,20 @@ bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) { if (!Ctx.isObjCObjectPointerType(Ty)) return false; - // We assume that id<..>, id, and "Class" all represent tracked objects. - const PointerType *PT = Ty->getAsPointerType(); - if (PT == 0) + const ObjCObjectPointerType *PT = Ty->getAsObjCObjectPointerType(); + + // Can be true for objects with the 'NSObject' attribute. + if (!PT) return true; - - const ObjCInterfaceType *OT = PT->getPointeeType()->getAsObjCInterfaceType(); - + // We assume that id<..>, id, and "Class" all represent tracked objects. - if (!OT) + if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || + PT->isObjCClassType()) return true; - + // Does the interface subclass NSObject? // FIXME: We can memoize here if this gets too expensive. - ObjCInterfaceDecl* ID = OT->getDecl(); + const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); // Assume that anything declared with a forward declaration and no // @interface subclasses NSObject. @@ -908,7 +906,6 @@ bool RetainSummaryManager::isTrackedObjCObjectType(QualType Ty) { IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject"); - for ( ; ID ; ID = ID->getSuperClass()) if (ID->getIdentifier() == NSObjectII) return true; @@ -977,7 +974,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { case 17: // Handle: id NSMakeCollectable(CFTypeRef) if (!memcmp(FName, "NSMakeCollectable", 17)) { - S = (RetTy == Ctx.getObjCIdType()) + S = (RetTy->isObjCIdType()) ? getUnarySummary(FT, cfmakecollectable) : getPersistentStopSummary(); } @@ -2726,34 +2723,26 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, /// While the the return type can be queried directly from RetEx, when /// invoking class methods we augment to the return type to be that of /// a pointer to the class (as opposed it just being id). -static QualType GetReturnType(Expr* RetE, ASTContext& Ctx) { - +static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { QualType RetTy = RetE->getType(); - - // FIXME: We aren't handling id<...>. - const PointerType* PT = RetTy->getAsPointerType(); - if (!PT) - return RetTy; - - // If RetEx is not a message expression just return its type. - // If RetEx is a message expression, return its types if it is something + // If RetE is not a message expression just return its type. + // If RetE is a message expression, return its types if it is something /// more specific than id. + if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE)) + if (const ObjCObjectPointerType *PT = RetTy->getAsObjCObjectPointerType()) + if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || + PT->isObjCClassType()) { + // At this point we know the return type of the message expression is + // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this + // is a call to a class method whose type we can resolve. In such + // cases, promote the return type to XXX* (where XXX is the class). + const ObjCInterfaceDecl *D = ME->getClassInfo().first; + return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); + } - ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(RetE); - - if (!ME || !Ctx.isObjCIdStructType(PT->getPointeeType())) - return RetTy; - - ObjCInterfaceDecl* D = ME->getClassInfo().first; - - // At this point we know the return type of the message expression is id. - // If we have an ObjCInterceDecl, we know this is a call to a class method - // whose type we can resolve. In such cases, promote the return type to - // Class*. - return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); + return RetTy; } - void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst, GRExprEngine& Eng, GRStmtNodeBuilder<GRState>& Builder, @@ -3009,26 +2998,21 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet<GRState>& Dst, SVal V = St->getSValAsScalarOrLoc(Receiver); SymbolRef Sym = V.getAsLocSymbol(); + if (Sym) { if (const RefVal* T = St->get<RefBindings>(Sym)) { - QualType Ty = T->getType(); - - if (const PointerType* PT = Ty->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - - if (ObjCInterfaceType* IT = dyn_cast<ObjCInterfaceType>(PointeeTy)) - ID = IT->getDecl(); - } + if (const ObjCObjectPointerType* PT = + T->getType()->getAsObjCObjectPointerType()) + ID = PT->getInterfaceDecl(); } } // FIXME: this is a hack. This may or may not be the actual method // that is called. if (!ID) { - if (const PointerType *PT = Receiver->getType()->getAsPointerType()) - if (const ObjCInterfaceType *p = - PT->getPointeeType()->getAsObjCInterfaceType()) - ID = p->getDecl(); + if (const ObjCObjectPointerType *PT = + Receiver->getType()->getAsObjCObjectPointerType()) + ID = PT->getInterfaceDecl(); } // FIXME: The receiver could be a reference to a class, meaning that diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp index c91442b5e8..c1382d0377 100644 --- a/lib/Analysis/CheckNSError.cpp +++ b/lib/Analysis/CheckNSError.cpp @@ -162,16 +162,22 @@ NSErrorCheck::CheckSignature(FunctionDecl& F, QualType& ResultTy, bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) { const PointerType* PPT = ArgTy->getAsPointerType(); - if (!PPT) return false; + if (!PPT) + return false; + + const ObjCObjectPointerType* PT = + PPT->getPointeeType()->getAsObjCObjectPointerType(); + + if (!PT) + return false; - const PointerType* PT = PPT->getPointeeType()->getAsPointerType(); - if (!PT) return false; + const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); - const ObjCInterfaceType *IT = - PT->getPointeeType()->getAsObjCInterfaceType(); + // FIXME: Can ID ever be NULL? + if (ID) + return II == ID->getIdentifier(); - if (!IT) return false; - return IT->getDecl()->getIdentifier() == II; + return false; } bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) { diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp index 28814867bd..c4e586d2e4 100644 --- a/lib/Analysis/CheckObjCInstMethSignature.cpp +++ b/lib/Analysis/CheckObjCInstMethSignature.cpp @@ -30,8 +30,8 @@ static bool AreTypesCompatible(QualType Derived, QualType Ancestor, // Right now don't compare the compatibility of pointers. That involves // looking at subtyping relationships. FIXME: Future patch. - if ((Derived->isPointerType() || Derived->isObjCQualifiedIdType()) && - (Ancestor->isPointerType() || Ancestor->isObjCQualifiedIdType())) + if ((Derived->isPointerType() || Derived->isObjCObjectPointerType()) && + (Ancestor->isPointerType() || Ancestor->isObjCObjectPointerType())) return true; return C.typesAreCompatible(Derived, Ancestor); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 8fa1e9c920..e45fa55cd4 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -761,8 +761,10 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, // Unsupported types return llvm::DIType(); case Type::ObjCObjectPointer: // Encode id<p> in debug info just like id. - return Slot = getOrCreateType(M->getContext().getObjCIdType(), Unit); - + { + ObjCObjectPointerType *OPT = cast<ObjCObjectPointerType>(Ty); + return Slot = CreateType(OPT->getInterfaceType(), Unit); + } case Type::ObjCQualifiedInterface: // Drop protocols from interface. case Type::ObjCInterface: return Slot = CreateType(cast<ObjCInterfaceType>(Ty), Unit); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 0951019f01..d42ca17e48 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -257,7 +257,6 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp"); } } - Builder.CreateStore(Value, Addr, Volatile); } @@ -758,11 +757,11 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { default: assert(0 && "Unknown unary operator lvalue!"); case UnaryOperator::Deref: { - QualType T = - E->getSubExpr()->getType()->getAsPointerType()->getPointeeType(); + QualType T = E->getSubExpr()->getType()->getPointeeType(); + assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); + LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), - ExprTy->getAsPointerType()->getPointeeType() - .getCVRQualifiers(), + T.getCVRQualifiers(), getContext().getObjCGCAttrKind(T)); // We should not generate __weak write barrier on indirect reference // of a pointer to object; as in void foo (__weak id *param); *param = 0; @@ -900,7 +899,10 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { Address = Builder.CreateGEP(Base, Idx, "arrayidx"); } - QualType T = E->getBase()->getType()->getAsPointerType()->getPointeeType(); + QualType T = E->getBase()->getType()->getPointeeType(); + assert(!T.isNull() && + "CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type"); + LValue LV = LValue::MakeAddr(Address, T.getCVRQualifiers(), getContext().getObjCGCAttrKind(T)); @@ -1261,8 +1263,7 @@ LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) { QualType ObjectTy; if (E->isArrow()) { BaseValue = EmitScalarExpr(BaseExpr); - const PointerType *PTy = BaseExpr->getType()->getAsPointerType(); - ObjectTy = PTy->getPointeeType(); + ObjectTy = BaseExpr->getType()->getPointeeType(); CVRQualifiers = ObjectTy.getCVRQualifiers(); } else { LValue BaseLV = EmitLValue(BaseExpr); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 161cd57418..94d0789a6f 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -987,7 +987,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { } Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { - if (!Ops.Ty->isPointerType()) { + if (!Ops.Ty->isPointerType() && !Ops.Ty->isObjCObjectPointerType()) { if (CGF.getContext().getLangOptions().OverflowChecking && Ops.Ty->isSignedIntegerType()) return EmitOverflowCheckedBinOp(Ops); @@ -998,20 +998,24 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { return Builder.CreateAdd(Ops.LHS, Ops.RHS, "add"); } - if (Ops.Ty->getAsPointerType()->isVariableArrayType()) { + if (Ops.Ty->isPointerType() && + Ops.Ty->getAsPointerType()->isVariableArrayType()) { // The amount of the addition needs to account for the VLA size CGF.ErrorUnsupported(Ops.E, "VLA pointer addition"); } Value *Ptr, *Idx; Expr *IdxExp; - const PointerType *PT; - if ((PT = Ops.E->getLHS()->getType()->getAsPointerType())) { + const PointerType *PT = Ops.E->getLHS()->getType()->getAsPointerType(); + const ObjCObjectPointerType *OPT = + Ops.E->getLHS()->getType()->getAsObjCObjectPointerType(); + if (PT || OPT) { Ptr = Ops.LHS; Idx = Ops.RHS; IdxExp = Ops.E->getRHS(); - } else { // int + pointer + } else { // int + pointer PT = Ops.E->getRHS()->getType()->getAsPointerType(); - assert(PT && "Invalid add expr"); + OPT = Ops.E->getRHS()->getType()->getAsObjCObjectPointerType(); + assert((PT || OPT) && "Invalid add expr"); Ptr = Ops.RHS; Idx = Ops.LHS; IdxExp = Ops.E->getLHS(); @@ -1027,8 +1031,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { else Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext"); } - - const QualType ElementType = PT->getPointeeType(); + const QualType ElementType = PT ? PT->getPointeeType() : OPT->getPointeeType(); // Handle interface types, which are not represented with a concrete // type. if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) { @@ -1066,7 +1069,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub"); } - if (Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) { + if (Ops.E->getLHS()->getType()->isPointerType() && + Ops.E->getLHS()->getType()->getAsPointerType()->isVariableArrayType()) { // The amount of the addition needs to account for the VLA size for // ptr-int // The amount of the division needs to account for the VLA size for @@ -1075,7 +1079,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { } const QualType LHSType = Ops.E->getLHS()->getType(); - const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType(); + const QualType LHSElementType = LHSType->getPointeeType(); if (!isa<llvm::PointerType>(Ops.RHS->getType())) { // pointer - int Value *Idx = Ops.RHS; diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 33cb5bca38..5d378410f8 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -305,8 +305,8 @@ llvm::Value *CodeGenFunction::LoadObjCSelf() { QualType CodeGenFunction::TypeOfSelfObject() { const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); ImplicitParamDecl *selfDecl = OMD->getSelfDecl(); - const PointerType *PTy = - cast<PointerType>(getContext().getCanonicalType(selfDecl->getType())); + const ObjCObjectPointerType *PTy = cast<ObjCObjectPointerType>( + getContext().getCanonicalType(selfDecl->getType())); return PTy->getPointeeType(); } diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 46e948e4d5..a75b39af20 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -1338,7 +1338,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); // @catch() and @catch(id) both catch any ObjC exception - if (!CatchDecl || CGF.getContext().isObjCIdType(CatchDecl->getType()) + if (!CatchDecl || CatchDecl->getType()->isObjCIdType() || CatchDecl->getType()->isObjCQualifiedIdType()) { // Use i8* null here to signal this is a catch all, not a cleanup. ESelArgs.push_back(NULLPtr); @@ -1348,10 +1348,11 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, } // All other types should be Objective-C interface pointer types. - const PointerType *PT = CatchDecl->getType()->getAsPointerType(); - assert(PT && "Invalid @catch type."); + const ObjCObjectPointerType *OPT = + CatchDecl->getType()->getAsObjCObjectPointerType(); + assert(OPT && "Invalid @catch type."); const ObjCInterfaceType *IT = - PT->getPointeeType()->getAsObjCInterfaceType(); + OPT->getPointeeType()->getAsObjCInterfaceType(); assert(IT && "Invalid @catch type."); llvm::Value *EHType = MakeConstantString(IT->getDecl()->getNameAsString()); diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index fadbdd76d4..82ab88fa82 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -2523,19 +2523,18 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch"); const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl(); - const PointerType *PT = 0; + const ObjCObjectPointerType *OPT = 0; // catch(...) always matches. if (!CatchParam) { AllMatched = true; } else { - PT = CatchParam->getType()->getAsPointerType(); + OPT = CatchParam->getType()->getAsObjCObjectPointerType(); // catch(id e) always matches. // FIXME: For the time being we also match id<X>; this should // be rejected by Sema instead. - if ((PT && CGF.getContext().isObjCIdStructType(PT->getPointeeType())) || - CatchParam->getType()->isObjCQualifiedIdType()) + if (OPT && (OPT->isObjCIdType()) || OPT->isObjCQualifiedIdType()) AllMatched = true; } @@ -2551,8 +2550,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, break; } - assert(PT && "Unexpected non-pointer type in @catch"); - QualType T = PT->getPointeeType(); + assert(OPT && "Unexpected non-object pointer type in @catch"); + QualType T = OPT->getPointeeType(); const ObjCInterfaceType *ObjCType = T->getAsObjCInterfaceType(); assert(ObjCType && "Catch parameter must have Objective-C type!"); @@ -5443,7 +5442,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, break; } - if (CGF.getContext().isObjCIdType(CatchDecl->getType()) || + if (CatchDecl->getType()->isObjCIdType() || CatchDecl->getType()->isObjCQualifiedIdType()) { llvm::Value *IDEHType = CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); @@ -5459,10 +5458,10 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, } // All other types should be Objective-C interface pointer types. - const PointerType *PT = CatchDecl->getType()->getAsPointerType(); + const ObjCObjectPointerType *PT = + CatchDecl->getType()->getAsObjCObjectPointerType(); assert(PT && "Invalid @catch type."); - const ObjCInterfaceType *IT = - PT->getPointeeType()->getAsObjCInterfaceType(); + const ObjCInterfaceType *IT = PT->getInterfaceType(); assert(IT && "Invalid @catch type."); llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false); SelectorArgs.push_back(EHType); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 1a30ea37fb..30a69f1dc2 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -215,6 +215,7 @@ static const llvm::Type* getTypeForFormat(const llvm::fltSemantics &format) { const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { const clang::Type &Ty = *Context.getCanonicalType(T); + //T->dump(); switch (Ty.getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -353,10 +354,14 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { return T; } - case Type::ObjCObjectPointer: - // Protocols don't influence the LLVM type. - return ConvertTypeRecursive(Context.getObjCIdType()); - + case Type::ObjCObjectPointer: { + // Qualified id types don't influence the LLVM type, here we always return + // an opaque type for 'id'. + const llvm::Type *&T = InterfaceTypes[0]; + if (!T) + T = llvm::OpaqueType::get(); + return llvm::PointerType::getUnqual(T); + } case Type::Record: case Type::Enum: { const TagDecl *TD = cast<TagType>(Ty).getDecl(); diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 8018b4f45a..97c26f87b1 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -480,6 +480,11 @@ void CXXNameMangler::mangleType(QualType T) { Out << 'P'; mangleType(PT->getPointeeType()); } + else if (const ObjCObjectPointerType *PT = + dyn_cast<ObjCObjectPointerType>(T.getTypePtr())) { + Out << 'P'; + mangleType(PT->getPointeeType()); + } // ::= R <type> # reference-to else if (const LValueReferenceType *RT = dyn_cast<LValueReferenceType>(T.getTypePtr())) { diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 47a7e6264a..c922b0d6db 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1531,6 +1531,7 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { Context->setObjCProtoType(GetType(Proto)); if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS]) Context->setObjCClassType(GetType(Class)); + if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING]) Context->setCFConstantStringType(GetType(String)); if (unsigned FastEnum @@ -1934,13 +1935,12 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { case pch::TYPE_OBJC_OBJECT_POINTER: { unsigned Idx = 0; - ObjCInterfaceDecl *ItfD = - cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++])); + QualType OIT = GetType(Record[Idx++]); unsigned NumProtos = Record[Idx++]; llvm::SmallVector<ObjCProtocolDecl*, 4> Protos; for (unsigned I = 0; I != NumProtos; ++I) Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++]))); - return Context->getObjCObjectPointerType(ItfD, Protos.data(), NumProtos); + return Context->getObjCObjectPointerType(OIT, Protos.data(), NumProtos); } } // Suppress a GCC warning diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 0362e8a490..57577b7dfa 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -255,7 +255,7 @@ PCHTypeWriter::VisitObjCQualifiedInterfaceType( void PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { - Writer.AddDeclRef(T->getDecl(), Record); + Writer.AddTypeRef(T->getPointeeType(), Record); Record.push_back(T->getNumProtocols()); for (ObjCInterfaceType::qual_iterator I = T->qual_begin(), E = T->qual_end(); I != E; ++I) diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index cf31f2b2de..1bc7451a17 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -2163,9 +2163,10 @@ ObjCInterfaceDecl *RewriteObjC::isSuperReceiver(Expr *recExpr) { if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return 0; if (ObjCSuperExpr *Super = dyn_cast<ObjCSuperExpr>(recExpr)) { - const PointerType *PT = Super->getType()->getAsPointerType(); - assert(PT); - ObjCInterfaceType *IT = cast<ObjCInterfaceType>(PT->getPointeeType()); + const ObjCObjectPointerType *OPT = + Super->getType()->getAsObjCObjectPointerType(); + assert(OPT); + const ObjCInterfaceType *IT = OPT->getInterfaceType(); return IT->getDecl(); } return 0; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 6cbb1c3712..9b58e47746 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -53,9 +53,9 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, // Don't desugar magic Objective-C types. Ty.getUnqualifiedType() != Context.getObjCIdType() && + Ty.getUnqualifiedType() != Context.getObjCClassType() && Ty.getUnqualifiedType() != Context.getObjCSelType() && Ty.getUnqualifiedType() != Context.getObjCProtoType() && - Ty.getUnqualifiedType() != Context.getObjCClassType() && // Not va_list. Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { @@ -140,17 +140,6 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); } - if (Context.getObjCClassType().isNull()) { - RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class"); - QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag)); - TypedefDecl *ClassTypedef = - TypedefDecl::Create(Context, CurContext, SourceLocation(), - &Context.Idents.get("Class"), ClassT); - PushOnScopeChains(ClassTag, TUScope); - PushOnScopeChains(ClassTypedef, TUScope); - Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); - } - // Synthesize "@class Protocol; if (Context.getObjCProtoType().isNull()) { ObjCInterfaceDecl *ProtocolDecl = @@ -160,20 +149,38 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); PushOnScopeChains(ProtocolDecl, TUScope); } - - // Synthesize "typedef struct objc_object { Class isa; } *id;" + // Create the built-in decls/typedefs for 'id' and 'Class'. if (Context.getObjCIdType().isNull()) { - RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object"); + ObjCInterfaceDecl *IdIDecl = + ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("id"), + SourceLocation(), true); + QualType IdIType = Context.getObjCInterfaceType(IdIDecl); + QualType ObjCIdType = Context.getObjCObjectPointerType(IdIType); - QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag)); - PushOnScopeChains(ObjectTag, TUScope); TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("id"), - ObjT); + ObjCIdType); PushOnScopeChains(IdTypedef, TUScope); Context.setObjCIdType(Context.getTypeDeclType(IdTypedef)); } + // Create the built-in decls/typedefs and type for "Class". + if (Context.getObjCClassType().isNull()) { + ObjCInterfaceDecl *ClassIDecl = + ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("Class"), + SourceLocation(), true); + QualType ClassIType = Context.getObjCInterfaceType(ClassIDecl); + QualType ObjCClassType = Context.getObjCObjectPointerType(ClassIType); + + TypedefDecl *ClassTypedef = TypedefDecl::Create(Context, CurContext, + SourceLocation(), + &Context.Idents.get("Class"), + ObjCClassType); + PushOnScopeChains(ClassTypedef, TUScope); + Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); + } } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 58fccc3e01..10ea5146a0 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3037,6 +3037,8 @@ public: // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1) AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType); + AssignConvertType CheckPointeeTypesForAssignment(QualType lhsType, + QualType rhsType); // Helper function for CheckAssignmentConstraints involving two // block pointer types. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 1a8cec11b7..2c24dc976e 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -516,8 +516,6 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { if (New->isInvalidDecl() || OldD->isInvalidDecl()) return New->setInvalidDecl(); - bool objc_types = false; - // Allow multiple definitions for ObjC built-in typedefs. // FIXME: Verify the underlying types are equivalent! if (getLangOptions().ObjC1) { @@ -527,13 +525,15 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { case 2: if (!TypeID->isStr("id")) break; - Context.setObjCIdType(Context.getTypeDeclType(New)); - objc_types = true; + // Install the built-in type for 'id', ignoring the current definition. + New->setTypeForDecl(Context.getObjCIdType().getTypePtr()); + return; break; case 5: if (!TypeID->isStr("Class")) break; - Context.setObjCClassType(Context.getTypeDeclType(New)); + // Install the built-in type for 'Class', ignoring the current definition. + New->setTypeForDecl(Context.getObjCClassType().getTypePtr()); return; case 3: if (!TypeID->isStr("SEL")) @@ -578,7 +578,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { return New->setInvalidDecl(); } - if (objc_types || getLangOptions().Microsoft) + if (getLangOptions().Microsoft) return; // C++ [dcl.typedef]p2: diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 2b71df7224..bdf6ca13a3 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -117,7 +117,7 @@ static bool isFunctionOrMethodVariadic(Decl *d) { } static inline bool isNSStringType(QualType T, ASTContext &Ctx) { - const PointerType *PT = T->getAsPointerType(); + const ObjCObjectPointerType *PT = T->getAsObjCObjectPointerType(); if (!PT) return false; @@ -1690,7 +1690,8 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, return; } - if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType())) { + if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType() + || RetTy->getAsObjCObjectPointerType())) { S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type) << Attr.getName(); return; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 62d28f326f..b8a9834b50 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -2048,7 +2048,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, << property->getDeclName() << Ivar->getDeclName(); // Fall thru - see previous comment } - if ((Context.isObjCObjectPointerType(property->getType()) || + if ((property->getType()->isObjCObjectPointerType() || PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && getLangOptions().getGCMode() != LangOptions::NonGC) { Diag(PropertyLoc, diag::error_strong_property) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 820c1775ae..8611fd5461 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -925,8 +925,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, QualType T; if (getCurMethodDecl()->isInstanceMethod()) - T = Context.getPointerType(Context.getObjCInterfaceType( - getCurMethodDecl()->getClassInterface())); + T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType( + getCurMethodDecl()->getClassInterface())); else T = Context.getObjCClassType(); return Owned(new (Context) ObjCSuperExpr(Loc, T)); @@ -1844,6 +1844,17 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, BaseExpr = RHSExp; IndexExpr = LHSExp; ResultType = PTy->getPointeeType(); + } else if (const ObjCObjectPointerType *PTy = + LHSTy->getAsObjCObjectPointerType()) { + BaseExpr = LHSExp; + IndexExpr = RHSExp; + ResultType = PTy->getPointeeType(); + } else if (const ObjCObjectPointerType *PTy = + RHSTy->getAsObjCObjectPointerType()) { + // Handle the uncommon case of "123[Ptr]". + BaseExpr = RHSExp; + IndexExpr = LHSExp; + ResultType = PTy->getPointeeType(); } else if (const VectorType *VTy = LHSTy->getAsVectorType()) { BaseExpr = LHSExp; // vectors: V[123] IndexExpr = RHSExp; @@ -2089,6 +2100,8 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, MemberLoc)); else if (const PointerType *PT = BaseType->getAsPointerType()) BaseType = PT->getPointeeType(); + else if (BaseType->isObjCObjectPointerType()) + ; else if (getLangOptions().CPlusPlus && BaseType->isRecordType()) return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc, MemberLoc, Member)); @@ -2212,12 +2225,71 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, << DeclarationName(&Member) << int(OpKind == tok::arrow)); } + // Handle properties on ObjC 'Class' types. + if (OpKind == tok::period && (BaseType->isObjCClassType())) { + // Also must look for a getter name which uses property syntax. + Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); + if (ObjCMethodDecl *MD = getCurMethodDecl()) { + ObjCInterfaceDecl *IFace = MD->getClassInterface(); + ObjCMethodDecl *Getter; + // FIXME: need to also look locally in the implementation. + if ((Getter = IFace->lookupClassMethod(Sel))) { + // Check the use of this method. + if (DiagnoseUseOfDecl(Getter, MemberLoc)) + return ExprError(); + } + // If we found a getter then this may be a valid dot-reference, we + // will look for the matching setter, in case it is needed. + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), &Member); + ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); + if (!Setter) { + // If this reference is in an @implementation, also check for 'private' + // methods. + Setter = FindMethodInNestedImplementations(IFace, SetterSel); + } + // Look through local category implementations associated with the class. + if (!Setter) { + for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) { + if (ObjCCategoryImpls[i]->getClassInterface() == IFace) + Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel); + } + } + + if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) + return ExprError(); + + if (Getter || Setter) { + QualType PType; + + if (Getter) + PType = Getter->getResultType(); + else { + for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), + E = Setter->param_end(); PI != E; ++PI) + PType = (*PI)->getType(); + } + // FIXME: we must check that the setter has property type. + return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, + Setter, MemberLoc, BaseExpr)); + } + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << &Member << BaseType); + } + } // Handle access to Objective-C instance variables, such as "Obj->ivar" and // (*Obj).ivar. - if (const ObjCInterfaceType *IFTy = BaseType->getAsObjCInterfaceType()) { + if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) || + (OpKind == tok::period && BaseType->isObjCInterfaceType())) { + const ObjCObjectPointerType *OPT = BaseType->getAsObjCObjectPointerType(); + const ObjCInterfaceType *IFaceT = + OPT ? OPT->getInterfaceType() : BaseType->getAsObjCInterfaceType(); + ObjCInterfaceDecl *IDecl = IFaceT->getDecl(); ObjCInterfaceDecl *ClassDeclared; - if (ObjCIvarDecl *IV = IFTy->getDecl()->lookupInstanceVariable(&Member, - ClassDeclared)) { + + if (ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(&Member, + ClassDeclared)) { // If the decl being referenced had an error, return an error for this // sub-expr without emitting another error, in order to avoid cascading // error cases. @@ -2249,12 +2321,12 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, } if (IV->getAccessControl() == ObjCIvarDecl::Private) { - if (ClassDeclared != IFTy->getDecl() || + if (ClassDeclared != IDecl || ClassOfMethodDecl != ClassDeclared) Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName(); } // @protected - else if (!IFTy->getDecl()->isSuperClassOf(ClassOfMethodDecl)) + else if (!IDecl->isSuperClassOf(ClassOfMethodDecl)) Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName(); } @@ -2263,18 +2335,46 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, OpKind == tok::arrow)); } return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) - << IFTy->getDecl()->getDeclName() << &Member + << IDecl->getDeclName() << &Member << BaseExpr->getSourceRange()); } + // Handle properties on qualified "id" protocols. + const ObjCObjectPointerType *QIdTy; + if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) { + // Check protocols on qualified interfaces. + Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); + if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) { + if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) { + // Check the use of this declaration + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + MemberLoc, BaseExpr)); + } + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { + // Check the use of this method. + if (DiagnoseUseOfDecl(OMD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel, + OMD->getResultType(), + OMD, OpLoc, MemberLoc, + NULL, 0)); + } + } + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << &Member << BaseType); + } // Handle Objective-C property access, which is "Obj.property" where Obj is a // pointer to a (potentially qualified) interface type. - const PointerType *PTy; - const ObjCInterfaceType *IFTy; - if (OpKind == tok::period && (PTy = BaseType->getAsPointerType()) && - (IFTy = PTy->getPointeeType()->getAsObjCInterfaceType())) { - ObjCInterfaceDecl *IFace = IFTy->getDecl(); - + const ObjCObjectPointerType *OPT; + if (OpKind == tok::period && + (OPT = BaseType->getAsObjCInterfacePointerType())) { + const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); + ObjCInterfaceDecl *IFace = IFaceT->getDecl(); + // Search for a declared property first. if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) { // Check whether we can reference this property. @@ -2288,10 +2388,9 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, MemberLoc, BaseExpr)); } - // Check protocols on qualified interfaces. - for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(), - E = IFTy->qual_end(); I != E; ++I) + for (ObjCObjectPointerType::qual_iterator I = IFaceT->qual_begin(), + E = IFaceT->qual_end(); I != E; ++I) if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) @@ -2300,7 +2399,16 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), MemberLoc, BaseExpr)); } + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) { + // Check whether we can reference this property. + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + MemberLoc, BaseExpr)); + } // If that failed, look for an "implicit" property by seeing if the nullary // selector is implemented. @@ -2365,88 +2473,6 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return ExprError(Diag(MemberLoc, diag::err_property_not_found) << &Member << BaseType); } - // Handle properties on qualified "id" protocols. - const ObjCObjectPointerType *QIdTy; - if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) { - // Check protocols on qualified interfaces. - Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); - if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) { - if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) { - // Check the use of this declaration - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), - MemberLoc, BaseExpr)); - } - if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { - // Check the use of this method. - if (DiagnoseUseOfDecl(OMD, MemberLoc)) - return ExprError(); - - return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel, - OMD->getResultType(), - OMD, OpLoc, MemberLoc, - NULL, 0)); - } - } - - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << &Member << BaseType); - } - // Handle properties on ObjC 'Class' types. - if (OpKind == tok::period && (BaseType == Context.getObjCClassType())) { - // Also must look for a getter name which uses property syntax. - Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); - if (ObjCMethodDecl *MD = getCurMethodDecl()) { - ObjCInterfaceDecl *IFace = MD->getClassInterface(); - ObjCMethodDecl *Getter; - // FIXME: need to also look locally in the implementation. - if ((Getter = IFace->lookupClassMethod(Sel))) { - // Check the use of this method. - if (DiagnoseUseOfDecl(Getter, MemberLoc)) - return ExprError(); - } - // If we found a getter then this may be a valid dot-reference, we - // will look for the matching setter, in case it is needed. - Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), &Member); - ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); - if (!Setter) { - // If this reference is in an @implementation, also check for 'private' - // methods. - Setter = FindMethodInNestedImplementations(IFace, SetterSel); - } - // Look through local category implementations associated with the class. - if (!Setter) { - for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) { - if (ObjCCategoryImpls[i]->getClassInterface() == IFace) - Setter = ObjCCategoryImpls[i]->getClassMethod(SetterSel); - } - } - - if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) - return ExprError(); - - if (Getter || Setter) { - QualType PType; - - if (Getter) - PType = Getter->getResultType(); - else { - for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), - E = Setter->param_end(); PI != E; ++PI) - PType = (*PI)->getType(); - } - // FIXME: we must check that the setter has property type. - return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, - Setter, MemberLoc, BaseExpr)); - } - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << &Member << BaseType); - } - } // Handle 'field access' to vectors, such as 'V.xx'. if (BaseType->isExtVectorType()) { @@ -3069,13 +3095,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() || - Context.isObjCObjectPointerType(LHSTy)) && + LHSTy->isObjCObjectPointerType()) && RHS->isNullPointerConstant(Context)) { ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer. return LHSTy; } if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() || - Context.isObjCObjectPointerType(RHSTy)) && + RHSTy->isObjCObjectPointerType()) && LHS->isNullPointerConstant(Context)) { ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer. return RHSTy; @@ -3119,46 +3145,15 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(RHS, LHSTy); return LHSTy; } - // Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type - // evaluates to "struct objc_object *" (and is handled above when comparing - // id with statically typed objects). - if (LHSTy->isObjCQualifiedIdType() || RHSTy->isObjCQualifiedIdType()) { - // GCC allows qualified id and any Objective-C type to devolve to - // id. Currently localizing to here until clear this should be - // part of ObjCQualifiedIdTypesAreCompatible. - if (ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true) || - (LHSTy->isObjCQualifiedIdType() && - Context.isObjCObjectPointerType(RHSTy)) || - (RHSTy->isObjCQualifiedIdType() && - Context.isObjCObjectPointerType(LHSTy))) { - // FIXME: This is not the correct composite type. This only happens to - // work because id can more or less be used anywhere, however this may - // change the type of method sends. - - // FIXME: gcc adds some type-checking of the arguments and emits - // (confusing) incompatible comparison warnings in some - // cases. Investigate. - QualType compositeType = Context.getObjCIdType(); - ImpCastExprToType(LHS, compositeType); - ImpCastExprToType(RHS, compositeType); - return compositeType; - } - } // Check constraints for Objective-C object pointers types. - if (Context.isObjCObjectPointerType(LHSTy) && - Context.isObjCObjectPointerType(RHSTy)) { + if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) { if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { // Two identical object pointer types are always compatible. return LHSTy; } - // No need to check for block pointer types or qualified id types (they - // were handled above). - assert((LHSTy->isPointerType() && RHSTy->isPointerType()) && - "Sema::CheckConditionalOperands(): Unexpected type"); - QualType lhptee = LHSTy->getAsPointerType()->getPointeeType(); - QualType rhptee = RHSTy->getAsPointerType()->getPointeeType(); - + const ObjCObjectPointerType *LHSOPT = LHSTy->getAsObjCObjectPointerType(); + const ObjCObjectPointerType *RHSOPT = RHSTy->getAsObjCObjectPointerType(); QualType compositeType = LHSTy; // If both operands are interfaces and either operand can be @@ -3174,16 +3169,19 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. // It could return the composite type. - const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType(); - if (LHSIface && RHSIface && - Context.canAssignObjCInterfaces(LHSIface, RHSIface)) { + if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { compositeType = LHSTy; - } else if (LHSIface && RHSIface && - Context.canAssignObjCInterfaces(RHSIface, LHSIface)) { + } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { compositeType = RHSTy; - } else if (Context.isObjCIdStructType(lhptee) || - Context.isObjCIdStructType(rhptee)) { + } else if ((LHSTy->isObjCQualifiedIdType() || + RHSTy->isObjCQualifiedIdType()) && + ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) { + // Need to handle "id<xx>" explicitly. + // GCC allows qualified id and any Objective-C type to devolve to + // id. Currently localizing to here until clear this should be + // part of ObjCQualifiedIdTypesAreCompatible. + compositeType = Context.getObjCIdType(); + } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { compositeType = Context.getObjCIdType(); } else { Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) @@ -3312,6 +3310,11 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { lhptee = lhsType->getAsPointerType()->getPointeeType(); rhptee = rhsType->getAsPointerType()->getPointeeType(); + return CheckPointeeTypesForAssignment(lhptee, rhptee); +} + +Sema::AssignConvertType +Sema::CheckPointeeTypesForAssignment(QualType lhptee, QualType rhptee) { // make sure we operate on the canonical type lhptee = Context.getCanonicalType(lhptee); rhptee = Context.getCanonicalType(rhptee); @@ -3443,7 +3446,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return Compatible; return Incompatible; } - + // FIXME: Look into removing. With ObjCObjectPointerType, I don't see a need. if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) { if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false)) return Compatible; @@ -3454,7 +3457,6 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return PointerToInt; return IncompatibleObjCQualifiedId; } - // Allow scalar to ExtVector assignments, and assignments of an ExtVector type // to the same ExtVector type. if (lhsType->isExtVectorType()) { @@ -3486,13 +3488,18 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { if (isa<PointerType>(rhsType)) return CheckPointerTypesForAssignment(lhsType, rhsType); + if (isa<ObjCObjectPointerType>(rhsType)) { + QualType rhptee = rhsType->getAsObjCObjectPointerType()->getPointeeType(); + QualType lhptee = lhsType->getAsPointerType()->getPointeeType(); + return CheckPointeeTypesForAssignment(lhptee, rhptee); + } + if (rhsType->getAsBlockPointerType()) { if (lhsType->getAsPointerType()->getPointeeType()->isVoidType()) return Compatible; // Treat block pointers as objects. - if (getLangOptions().ObjC1 && - lhsType == Context.getCanonicalType(Context.getObjCIdType())) + if (getLangOptions().ObjC1 && lhsType->isObjCIdType()) return Compatible; } return Incompatible; @@ -3503,8 +3510,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return IntToBlockPointer; // Treat block pointers as objects. - if (getLangOptions().ObjC1 && - rhsType == Context.getCanonicalType(Context.getObjCIdType())) + if (getLangOptions().ObjC1 && rhsType->isObjCIdType()) return Compatible; if (rhsType->isBlockPointerType()) @@ -3517,6 +3523,29 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return Incompatible; } + if (isa<ObjCObjectPointerType>(lhsType)) { + if (rhsType->isIntegerType()) + return IntToPointer; + + if (isa<PointerType>(rhsType)) { + QualType lhptee = lhsType->getAsObjCObjectPointerType()->getPointeeType(); + QualType rhptee = rhsType->getAsPointerType()->getPointeeType(); + return CheckPointeeTypesForAssignment(lhptee, rhptee); + } + if (rhsType->isObjCObjectPointerType()) { + QualType lhptee = lhsType->getAsObjCObjectPointerType()->getPointeeType(); + QualType rhptee = rhsType->getAsObjCObjectPointerType()->getPointeeType(); + return CheckPointeeTypesForAssignment(lhptee, rhptee); + } + if (const PointerType *RHSPT = rhsType->getAsPointerType()) { + if (RHSPT->getPointeeType()->isVoidType()) + return Compatible; + } + // Treat block pointers as objects. + if (rhsType->isBlockPointerType()) + return Compatible; + return Incompatible; + } if (isa<PointerType>(rhsType)) { // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. if (lhsType == Context.BoolTy) @@ -3533,6 +3562,24 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return Compatible; return Incompatible; } + if (isa<ObjCObjectPointerType>(rhsType)) { + // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. + if (lhsType == Context.BoolTy) + return Compatible; + + if (lhsType->isIntegerType()) + return PointerToInt; + + if (isa<PointerType>(lhsType)) { + QualType rhptee = lhsType->getAsObjCObjectPointerType()->getPointeeType(); + QualType lhptee = rhsType->getAsPointerType()->getPointeeType(); + return CheckPointeeTypesForAssignment(lhptee, rhptee); + } + if (isa<BlockPointerType>(lhsType) && + rhsType->getAsPointerType()->getPointeeType()->isVoidType()) + return Compatible; + return Incompatible; + } if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) { if (Context.typesAreCompatible(lhsType, rhsType)) @@ -3628,7 +3675,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // C99 6.5.16.1p1: the left operand is a pointer and the right is // a null pointer constant. if ((lhsType->isPointerType() || - lhsType->isObjCQualifiedIdType() || + lhsType->isObjCObjectPointerType() || lhsType->isBlockPointerType()) && rExpr->isNullPointerConstant(Context)) { ImpCastExprToType(rExpr, lhsType); @@ -3776,12 +3823,23 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 // Put any potential pointer into PExp Expr* PExp = lex, *IExp = rex; - if (IExp->getType()->isPointerType()) + if (IExp->getType()->isPointerType() || + IExp->getType()->isObjCObjectPointerType()) std::swap(PExp, IExp); - if (const PointerType *PTy = PExp->getType()->getAsPointerType()) { + if (PExp->getType()->isPointerType() || + PExp->getType()->isObjCObjectPointerType()) { + if (IExp->getType()->isIntegerType()) { - QualType PointeeTy = PTy->getPointeeType(); + QualType PointeeTy; + const PointerType *PTy; + const ObjCObjectPointerType *OPT; + + if ((PTy = PExp->getType()->getAsPointerType())) + PointeeTy = PTy->getPointeeType(); + else if ((OPT = PExp->getType()->getAsObjCObjectPointerType())) + PointeeTy = OPT->getPointeeType(); + // Check for arithmetic on pointers to incomplete types. if (PointeeTy->isVoidType()) { if (getLangOptions().CPlusPlus) { @@ -3803,7 +3861,7 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 // GNU extension: arithmetic on pointer to function Diag(Loc, diag::ext_gnu_ptr_func_arith) << lex->getType() << lex->getSourceRange(); - } else if (!PTy->isDependentType() && + } else if (((PTy && !PTy->isDependentType()) || OPT) && RequireCompleteType(Loc, PointeeTy, diag::err_typecheck_arithmetic_incomplete_type, PExp->getSourceRange(), SourceRange(), @@ -3855,10 +3913,16 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, if (CompLHSTy) *CompLHSTy = compType; return compType; } - + // Either ptr - int or ptr - ptr. - if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) { - QualType lpointee = LHSPTy->getPointeeType(); + if (lex->getType()->isPointerType() || + lex->getType()->isObjCObjectPointerType()) { + QualType lpointee; + if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) + lpointee = LHSPTy->getPointeeType(); + else if (const ObjCObjectPointerType *OPT = + lex->getType()->getAsObjCObjectPointerType()) + lpointee = OPT->getPointeeType(); // The LHS must be an completely-defined object type. @@ -4156,8 +4220,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2 !LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() && !Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(), - RCanPointeeTy.getUnqualifiedType()) && - !Context.areComparableObjCPointerTypes(lType, rType)) { + RCanPointeeTy.getUnqualifiedType())) { Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } @@ -4207,7 +4270,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return ResultTy; } - if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) { + if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) { if (lType->isPointerType() || rType->isPointerType()) { const PointerType *LPT = lType->getAsPointerType(); const PointerType *RPT = rType->getAsPointerType(); @@ -4226,19 +4289,27 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, ImpCastExprToType(rex, lType); return ResultTy; } - if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) { - ImpCastExprToType(rex, lType); - return ResultTy; - } else { - if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) { - Diag(Loc, diag::warn_incompatible_qualified_id_operands) + if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) { + if (!Context.areComparableObjCPointerTypes(lType, rType)) { + Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - ImpCastExprToType(rex, lType); - return ResultTy; } + if (lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType()) { + if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) { + ImpCastExprToType(rex, lType); + return ResultTy; + } else { + Diag(Loc, diag::warn_incompatible_qualified_id_operands) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + ImpCastExprToType(rex, lType); + return ResultTy; + } + } + ImpCastExprToType(rex, lType); + return ResultTy; } } - if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) && + if ((lType->isPointerType() || lType->isObjCObjectPointerType()) && rType->isIntegerType()) { if (isRelational) Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer) @@ -4250,7 +4321,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return ResultTy; } if (lType->isIntegerType() && - (rType->isPointerType() || rType->isObjCQualifiedIdType())) { + (rType->isPointerType() || rType->isObjCObjectPointerType())) { if (isRelational) Diag(Loc, diag::ext_typecheck_ordered_comparison_of_pointer_integer) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); @@ -4358,12 +4429,11 @@ static bool IsReadonlyProperty(Expr *E, Sema &S) const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E); if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) { QualType BaseType = PropExpr->getBase()->getType(); - if (const PointerType *PTy = BaseType->getAsPointerType()) - if (const ObjCInterfaceType *IFTy = - PTy->getPointeeType()->getAsObjCInterfaceType()) - if (ObjCInterfaceDecl *IFace = IFTy->getDecl()) - if (S.isPropertyReadonly(PDecl, IFace)) - return true; + if (const ObjCObjectPointerType *OPT = + BaseType->getAsObjCInterfacePointerType()) + if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl()) + if (S.isPropertyReadonly(PDecl, IFace)) + return true; } } return false; @@ -4524,9 +4594,17 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange(); } else if (ResType->isRealType()) { // OK! - } else if (const PointerType *PT = ResType->getAsPointerType()) { + } else if (ResType->getAsPointerType() ||ResType->isObjCObjectPointerType()) { + QualType PointeeTy; + + if (const PointerType *PTy = ResType->getAsPointerType()) + PointeeTy = PTy->getPointeeType(); + else if (const ObjCObjectPointerType *OPT = + ResType->getAsObjCObjectPointerType()) + PointeeTy = OPT->getPointeeType(); + // C99 6.5.2.4p2, 6.5.6p2 - if (PT->getPointeeType()->isVoidType()) { + if (PointeeTy->isVoidType()) { if (getLangOptions().CPlusPlus) { Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) << Op->getSourceRange(); @@ -4535,7 +4613,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, // Pointer to void is a GNU extension in C. Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); - } else if (PT->getPointeeType()->isFunctionType()) { + } else if (PointeeTy->isFunctionType()) { if (getLangOptions().CPlusPlus) { Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) << Op->getType() << Op->getSourceRange(); @@ -4544,7 +4622,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, Diag(OpLoc, diag::ext_gnu_ptr_func_arith) << ResType << Op->getSourceRange(); - } else if (RequireCompleteType(OpLoc, PT->getPointeeType(), + } else if (RequireCompleteType(OpLoc, PointeeTy, diag::err_typecheck_arithmetic_incomplete_type, Op->getSourceRange(), SourceRange(), ResType)) @@ -4741,6 +4819,9 @@ QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) { if (const PointerType *PT = Ty->getAsPointerType()) return PT->getPointeeType(); + if (const ObjCObjectPointerType *OPT = Ty->getAsObjCObjectPointerType()) + return OPT->getPointeeType(); + Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer) << Ty << Op->getSourceRange(); return QualType(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index b6c2d0521f..d522bf29dc 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1482,7 +1482,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); - if(!T1->isPointerType() && !T2->isPointerType()) + if(!T1->isPointerType() && !T2->isPointerType() && + !T1->isObjCObjectPointerType() && !T2->isObjCObjectPointerType()) return QualType(); // C++0x 5.9p2 diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 7bb6b44c39..cca4ce3551 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -74,14 +74,14 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, // interface private (even though it appears in the header files). QualType Ty = Context.getObjCConstantStringInterface(); if (!Ty.isNull()) { - Ty = Context.getPointerType(Ty); + Ty = Context.getObjCObjectPointerType(Ty); } else { IdentifierInfo *NSIdent = &Context.Idents.get("NSString"); NamedDecl *IF = LookupName(TUScope, NSIdent, LookupOrdinaryName); if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { Context.setObjCConstantStringInterface(StrIF); Ty = Context.getObjCConstantStringInterface(); - Ty = Context.getPointerType(Ty); + Ty = Context.getObjCObjectPointerType(Ty); } else { // If there is no NSString interface defined then treat constant // strings as untyped objects and let the runtime figure it out later. @@ -156,7 +156,7 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, QualType Ty = Context.getObjCProtoType(); if (Ty.isNull()) return true; - Ty = Context.getPointerType(Ty); + Ty = Context.getObjCObjectPointerType(Ty); return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc); } @@ -390,7 +390,7 @@ Sema::ExprResult Sema::ActOnClassMessage( return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName(); if (getCurMethodDecl()->isInstanceMethod()) { QualType superTy = Context.getObjCInterfaceType(ClassDecl); - superTy = Context.getPointerType(superTy); + superTy = Context.getObjCObjectPointerType(superTy); ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(), superTy); // We are really in an instance method, redirect. @@ -527,7 +527,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, rbrac, ArgExprs, NumArgs); } - // Handle messages to id. + // Handle messages to id. if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) || ReceiverCType->isBlockPointerType() || Context.isObjCNSObjectType(RExpr->getType())) { @@ -602,11 +602,11 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) break; } - } else if (const ObjCInterfaceType *OCIType = - ReceiverCType->getAsPointerToObjCInterfaceType()) { + } else if (const ObjCObjectPointerType *OCIType = + ReceiverCType->getAsObjCInterfacePointerType()) { // We allow sending a message to a pointer to an interface (an object). - ClassDecl = OCIType->getDecl(); + ClassDecl = OCIType->getInterfaceDecl(); // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be // faster than the following method (which can do *many* linear searches). // The idea is to add class info to InstanceMethodPool. @@ -614,7 +614,7 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (!Method) { // Search protocol qualifiers. - for (ObjCQualifiedInterfaceType::qual_iterator QI = OCIType->qual_begin(), + for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(), E = OCIType->qual_end(); QI != E; ++QI) { if ((Method = (*QI)->lookupInstanceMethod(Sel))) break; @@ -631,9 +631,9 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool( Sel, SourceRange(lbrac,rbrac)); - if (Method && !OCIType->getDecl()->isForwardDecl()) + if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) Diag(lbrac, diag::warn_maynot_respond) - << OCIType->getDecl()->getIdentifier()->getName() << Sel; + << OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel; } } } @@ -741,60 +741,36 @@ bool Sema::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, bool compare) { // Allow id<P..> and an 'id' or void* type in all cases. - if (const PointerType *PT = lhs->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - if (PointeeTy->isVoidType() || - Context.isObjCIdStructType(PointeeTy) || - Context.isObjCClassStructType(PointeeTy)) - return true; - } else if (const PointerType *PT = rhs->getAsPointerType()) { - QualType PointeeTy = PT->getPointeeType(); - if (PointeeTy->isVoidType() || - Context.isObjCIdStructType(PointeeTy) || - Context.isObjCClassStructType(PointeeTy)) - return true; - } - + if (lhs->isVoidPointerType() || + lhs->isObjCIdType() || lhs->isObjCClassType()) + return true; + else if (rhs->isVoidPointerType() || + rhs->isObjCIdType() || rhs->isObjCClassType()) + return true; + if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) { - const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType(); - const ObjCQualifiedInterfaceType *rhsQI = 0; - QualType rtype; + const ObjCObjectPointerType *rhsOPT = rhs->getAsObjCObjectPointerType(); - if (!rhsQID) { - // Not comparing two ObjCQualifiedIdType's? - if (!rhs->isPointerType()) return false; - - rtype = rhs->getAsPointerType()->getPointeeType(); - rhsQI = rtype->getAsObjCQualifiedInterfaceType(); - if (rhsQI == 0) { - // If the RHS is a unqualified interface pointer "NSString*", - // make sure we check the class hierarchy. - if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { - ObjCInterfaceDecl *rhsID = IT->getDecl(); - for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), - E = lhsQID->qual_end(); I != E; ++I) { - // when comparing an id<P> on lhs with a static type on rhs, - // see if static class implements all of id's protocols, directly or - // through its super class and categories. - if (!ClassImplementsProtocol(*I, rhsID, true)) - return false; - } - return true; - } - } - } + if (!rhsOPT) return false; - ObjCObjectPointerType::qual_iterator RHSProtoI, RHSProtoE; - if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *"). - RHSProtoI = rhsQI->qual_begin(); - RHSProtoE = rhsQI->qual_end(); - } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *"). - RHSProtoI = rhsQID->qual_begin(); - RHSProtoE = rhsQID->qual_end(); - } else { - return false; + if (rhsOPT->qual_empty()) { + // If the RHS is a unqualified interface pointer "NSString*", + // make sure we check the class hierarchy. + if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) { + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + // when comparing an id<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (!ClassImplementsProtocol(*I, rhsID, true)) + return false; + } + return true; + } + // If there are no qualifiers and no interface, we have an 'id'. + return true; } - + // Both the right and left sides have qualifiers. for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), E = lhsQID->qual_end(); I != E; ++I) { ObjCProtocolDecl *lhsProto = *I; @@ -803,28 +779,26 @@ bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, // when comparing an id<P> on lhs with a static type on rhs, // see if static class implements all of id's protocols, directly or // through its super class and categories. - for (; RHSProtoI != RHSProtoE; ++RHSProtoI) { - ObjCProtocolDecl *rhsProto = *RHSProtoI; + for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(), + E = rhsOPT->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { match = true; break; } } - if (rhsQI) { - // If the RHS is a qualified interface pointer "NSString<P>*", - // make sure we check the class hierarchy. - if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { - ObjCInterfaceDecl *rhsID = IT->getDecl(); - for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), - E = lhsQID->qual_end(); I != E; ++I) { - // when comparing an id<P> on lhs with a static type on rhs, - // see if static class implements all of id's protocols, directly or - // through its super class and categories. - if (ClassImplementsProtocol(*I, rhsID, true)) { - match = true; - break; - } + // If the RHS is a qualified interface pointer "NSString<P>*", + // make sure we check the class hierarchy. + if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) { + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + // when comparing an id<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (ClassImplementsProtocol(*I, rhsID, true)) { + match = true; + break; } } } @@ -837,7 +811,52 @@ bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType(); assert(rhsQID && "One of the LHS/RHS should be id<x>"); - + + 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<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (ClassImplementsProtocol(*I, lhsID, true)) { + match = true; + break; + } + } + if (!match) + return false; + } + return true; + } + // 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<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + 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; + } + // FIXME: The code below will be removed when ObjCQualifiedInterfaceType is + // removed. if (!lhs->isPointerType()) return false; @@ -864,17 +883,6 @@ bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, return true; } - if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) { - // for static type vs. qualified 'id' type, check that class implements - // all of 'id's protocols. - ObjCInterfaceDecl *lhsID = IT->getDecl(); - for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(), - E = rhsQID->qual_end(); I != E; ++I) { - if (!ClassImplementsProtocol(*I, lhsID, compare, true)) - return false; - } - return true; - } return false; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index d10d32c62a..4021e547e1 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1005,77 +1005,64 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, if (!getLangOptions().ObjC1) return false; - // Conversions with Objective-C's id<...>. - if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) && - ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) { - ConvertedType = ToType; - return true; - } + // First, we handle all conversions on ObjC object pointer types. + const ObjCObjectPointerType* ToObjCPtr = ToType->getAsObjCObjectPointerType(); + const ObjCObjectPointerType *FromObjCPtr = + FromType->getAsObjCObjectPointerType(); + + if (ToObjCPtr && FromObjCPtr) { + // Objective C++: We're able to convert between "id" and a pointer + // to any interface (in both directions). + if (ToObjCPtr->isObjCIdType() && FromObjCPtr->isObjCIdType()) { + ConvertedType = ToType; + return true; + } + // Objective C++: Allow conversions between the Objective-C "Class" and a + // pointer to any interface (in both directions). + if (ToObjCPtr->isObjCClassType() || FromObjCPtr->isObjCClassType()) { + ConvertedType = ToType; + return true; + } + // Conversions with Objective-C's id<...>. + if ((FromObjCPtr->isObjCQualifiedIdType() || + ToObjCPtr->isObjCQualifiedIdType()) && + ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) { + ConvertedType = ToType; + return true; + } + // Objective C++: We're able to convert from a pointer to an + // interface to a pointer to a different interface. + if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) { + ConvertedType = ToType; + return true; + } - // Beyond this point, both types need to be pointers or block pointers. + if (Context.canAssignObjCInterfaces(FromObjCPtr, ToObjCPtr)) { + // Okay: this is some kind of implicit downcast of Objective-C + // interfaces, which is permitted. However, we're going to + // complain about it. + IncompatibleObjC = true; + ConvertedType = FromType; + return true; + } + } + // Beyond this point, both types need to be C pointers or block pointers. QualType ToPointeeType; - const PointerType* ToTypePtr = ToType->getAsPointerType(); - if (ToTypePtr) - ToPointeeType = ToTypePtr->getPointeeType(); + if (const PointerType *ToCPtr = ToType->getAsPointerType()) + ToPointeeType = ToCPtr->getPointeeType(); else if (const BlockPointerType *ToBlockPtr = ToType->getAsBlockPointerType()) ToPointeeType = ToBlockPtr->getPointeeType(); else return false; QualType FromPointeeType; - const PointerType *FromTypePtr = FromType->getAsPointerType(); - if (FromTypePtr) - FromPointeeType = FromTypePtr->getPointeeType(); - else if (const BlockPointerType *FromBlockPtr - = FromType->getAsBlockPointerType()) + if (const PointerType *FromCPtr = FromType->getAsPointerType()) + FromPointeeType = FromCPtr->getPointeeType(); + else if (const BlockPointerType *FromBlockPtr = FromType->getAsBlockPointerType()) FromPointeeType = FromBlockPtr->getPointeeType(); else return false; - // Objective C++: We're able to convert from a pointer to an - // interface to a pointer to a different interface. - const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType(); - const ObjCInterfaceType* ToIface = ToPointeeType->getAsObjCInterfaceType(); - if (FromIface && ToIface && - Context.canAssignObjCInterfaces(ToIface, FromIface)) { - ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, - ToPointeeType, - ToType, Context); - return true; - } - - if (FromIface && ToIface && - Context.canAssignObjCInterfaces(FromIface, ToIface)) { - // Okay: this is some kind of implicit downcast of Objective-C - // interfaces, which is permitted. However, we're going to - // complain about it. - IncompatibleObjC = true; - ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, - ToPointeeType, - ToType, Context); - return true; - } - - // Objective C++: We're able to convert between "id" and a pointer - // to any interface (in both directions). - if ((FromIface && Context.isObjCIdStructType(ToPointeeType)) - || (ToIface && Context.isObjCIdStructType(FromPointeeType))) { - ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, - ToPointeeType, - ToType, Context); - return true; - } - - // Objective C++: Allow conversions between the Objective-C "id" and - // "Class", in either direction. - if ((Context.isObjCIdStructType(FromPointeeType) && - Context.isObjCClassStructType(ToPointeeType)) || - (Context.isObjCClassStructType(FromPointeeType) && - Context.isObjCIdStructType(ToPointeeType))) { - ConvertedType = ToType; - return true; - } - // If we have pointers to pointers, recursively check whether this // is an Objective-C conversion. if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() && @@ -1086,7 +1073,6 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ConvertedType = ToType; return true; } - // If we have pointers to functions or blocks, check whether the only // differences in the argument and result types are in Objective-C // pointer conversions. If so, we permit the conversion (but @@ -1167,15 +1153,6 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType) { QualType FromPointeeType = FromPtrType->getPointeeType(), ToPointeeType = ToPtrType->getPointeeType(); - // Objective-C++ conversions are always okay. - // FIXME: We should have a different class of conversions for the - // Objective-C++ implicit conversions. - if (Context.isObjCIdStructType(FromPointeeType) || - Context.isObjCIdStructType(ToPointeeType) || - Context.isObjCClassStructType(FromPointeeType) || - Context.isObjCClassStructType(ToPointeeType)) - return false; - if (FromPointeeType->isRecordType() && ToPointeeType->isRecordType()) { // We must have a derived-to-base conversion. Check an @@ -1185,7 +1162,18 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType) { From->getSourceRange()); } } + if (const ObjCObjectPointerType *FromPtrType = + FromType->getAsObjCObjectPointerType()) + if (const ObjCObjectPointerType *ToPtrType = + ToType->getAsObjCObjectPointerType()) { + // Objective-C++ conversions are always okay. + // FIXME: We should have a different class of conversions for the + // Objective-C++ implicit conversions. + if (FromPtrType->isObjCIdType() || ToPtrType->isObjCIdType() || + FromPtrType->isObjCClassType() || ToPtrType->isObjCClassType()) + return false; + } return false; } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 8dcf4e48f5..7551d93c66 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -91,7 +91,8 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ, + Result = Context.getObjCObjectPointerType(QualType(), + (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); break; } @@ -197,14 +198,16 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so we have // this "hack" for now... if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType()) + // FIXME: Remove ObjCQualifiedInterfaceType (by moving the list of + // protocols 'up' to ObjCInterfaceType). Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(), (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); - else if (Result == Context.getObjCIdType()) + else if (Result->isObjCIdType()) // id<protocol-list> - Result = Context.getObjCObjectPointerType(0, (ObjCProtocolDecl**)PQ, - DS.getNumProtocolQualifiers()); - else if (Result == Context.getObjCClassType()) { + Result = Context.getObjCObjectPointerType(QualType(), + (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); + else if (Result->isObjCClassType()) { if (DeclLoc.isInvalid()) DeclLoc = DS.getSourceRange().getBegin(); // Class<protocol-list> @@ -886,6 +889,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, D.setInvalidType(true); // Build the type anyway. } + if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) { + const ObjCInterfaceType *OIT = T->getAsObjCInterfaceType(); + T = Context.getObjCObjectPointerType(T, + (ObjCProtocolDecl **)OIT->qual_begin(), + OIT->getNumProtocols()); + break; + } T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name); break; case DeclaratorChunk::Reference: diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m index ca54a51c3b..8d78639e96 100644 --- a/test/CodeGenObjC/encode-test.m +++ b/test/CodeGenObjC/encode-test.m @@ -1,7 +1,7 @@ // RUN: clang-cc -triple=i686-apple-darwin9 -fnext-runtime -emit-llvm -o %t %s && // RUN: grep -e "\^{Innermost=CC}" %t | count 1 && -// RUN: grep -e "{Derived=#ib32b8b3b8sb16b8b8b2b8ccb6}" %t | count 1 && -// RUN: grep -e "{B1=#@c}" %t | count 1 && +// RUN: grep -e "{Derived=^{objc_class}ib32b8b3b8sb16b8b8b2b8ccb6}" %t | count 1 && +// RUN: grep -e "{B1=^{objc_class}@c}" %t | count 1 && // RUN: grep -e "v12@0:4\[3\[4@]]8" %t | count 1 && // RUN: grep -e "r\^{S=i}" %t | count 1 && // RUN: grep -e "\^{Object=#}" %t | count 1 diff --git a/test/CodeGenObjC/overloadable.m b/test/CodeGenObjC/overloadable.m index 972dc4ed58..fc5c2e4085 100644 --- a/test/CodeGenObjC/overloadable.m +++ b/test/CodeGenObjC/overloadable.m @@ -3,8 +3,8 @@ @class C; -// RUN: grep _Z1fP11objc_object %t | count 1 && -void __attribute__((overloadable)) f(C *c) { } +// RUN: grep _Z1fP2id %t | count 1 && +void __attribute__((overloadable)) f(id c) { } // RUN: grep _Z1fP1C %t | count 1 -void __attribute__((overloadable)) f(id c) { } +void __attribute__((overloadable)) f(C *c) { } diff --git a/test/PCH/objc_exprs.m b/test/PCH/objc_exprs.m index eb1ae434a7..48966f36f3 100644 --- a/test/PCH/objc_exprs.m +++ b/test/PCH/objc_exprs.m @@ -6,7 +6,7 @@ // RUN: clang-cc -fblocks -include-pch %t -fsyntax-only -verify %s // Expressions -int *A1 = (objc_string)0; // expected-warning {{'struct objc_object *'}} +int *A1 = (objc_string)0; // expected-warning {{aka 'id'}} char A2 = (objc_encode){}; // expected-error {{not a compile-time constant}} \ expected-warning {{char [2]}} @@ -15,8 +15,7 @@ int *A3 = (objc_protocol)0; // expected-warning {{aka 'Protocol *'}} // Types. -int *T0 = (objc_id_protocol_ty)0; // expected-error {{not a compile-time constant}} \ - expected-warning {{aka 'id<foo>'}} +int *T0 = (objc_id_protocol_ty)0; // expected-warning {{aka 'id<foo>'}} int *T1 = (objc_interface_ty)0; // expected-warning {{aka 'itf *'}} int *T2 = (objc_qual_interface_ty)0; // expected-warning {{aka 'itf<foo> *'}} diff --git a/test/SemaObjC/comptypes-5.m b/test/SemaObjC/comptypes-5.m index afd8a4949e..478e8c8114 100644 --- a/test/SemaObjC/comptypes-5.m +++ b/test/SemaObjC/comptypes-5.m @@ -26,8 +26,8 @@ int main() MyOtherClass<MyProtocol> *obj_c_super_p_q = nil; MyClass<MyProtocol> *obj_c_cat_p_q = nil; - obj_c_cat_p = obj_id_p; // expected-warning {{incompatible type assigning 'id<MyProtocol>', expected 'MyClass *'}} - obj_c_super_p = obj_id_p; // expected-warning {{incompatible type assigning 'id<MyProtocol>', expected 'MyOtherClass *'}} + obj_c_cat_p = obj_id_p; + obj_c_super_p = obj_id_p; obj_id_p = obj_c_cat_p; /* Ok */ obj_id_p = obj_c_super_p; /* Ok */ diff --git a/test/SemaObjC/conditional-expr-3.m b/test/SemaObjC/conditional-expr-3.m index 31d4834ff0..0b392d4882 100644 --- a/test/SemaObjC/conditional-expr-3.m +++ b/test/SemaObjC/conditional-expr-3.m @@ -59,7 +59,7 @@ void f9(int cond, id<P0,P1> x0, id<P0,P2> x1) { } void f10(int cond, id<P0,P1> x0, id<P0,P2> x1) { - barP2(cond ? x0 : x1); + barP2(cond ? x0 : x1); // expected-warning {{incompatible type passing 'id<P0,P1>', expected 'id<P2>'}} } int f11(int cond, A* a, B* b) { diff --git a/test/SemaObjC/id.m b/test/SemaObjC/id.m index 1781ce71d9..70d981c42b 100644 --- a/test/SemaObjC/id.m +++ b/test/SemaObjC/id.m @@ -15,6 +15,6 @@ void foo() { } // Test attempt to redefine 'id' in an incompatible fashion. -typedef int id; // expected-error {{typedef redefinition with different types}} +typedef int id; // FIXME: Decide how we want to deal with this (now that 'id' is more of a built-in type). id b; diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m index 7b6a4ee3f7..f4a85dab6b 100644 --- a/test/SemaObjC/message.m +++ b/test/SemaObjC/message.m @@ -95,6 +95,6 @@ int test5(int X) { void foo4() { struct objc_object X[10]; - [X rect]; + [(id)X rect]; } diff --git a/test/SemaObjC/objc2-merge-gc-attribue-decl.m b/test/SemaObjC/objc2-merge-gc-attribue-decl.m index 9dae1efdcd..0da0ce876d 100644 --- a/test/SemaObjC/objc2-merge-gc-attribue-decl.m +++ b/test/SemaObjC/objc2-merge-gc-attribue-decl.m @@ -25,6 +25,5 @@ extern __strong id p5; extern char* __strong p6; // expected-note {{previous definition is here}} extern char* p6; // expected-error {{redefinition of 'p6' with a different type}} -// FIXME. We do not issue error here because we don't put the attribute on the pointer type. -extern __strong char* p7; -extern char* p7; +extern __strong char* p7; // expected-note {{previous definition is here}} +extern char* p7; // expected-error {{redefinition of 'p7' with a different type}} diff --git a/test/SemaObjC/property-missing.m b/test/SemaObjC/property-missing.m index 1aa94ce71b..301907ad1c 100644 --- a/test/SemaObjC/property-missing.m +++ b/test/SemaObjC/property-missing.m @@ -17,6 +17,6 @@ void f2(id<NSCopying> o) void f3(id o) { - o.foo; // expected-error{{member reference base type 'id' is not a structure or union}} + o.foo; // expected-error{{property 'foo' not found on object of type 'id'}} } diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm index 8ab22e1ca7..4714100286 100644 --- a/test/SemaObjCXX/overload.mm +++ b/test/SemaObjCXX/overload.mm @@ -1,4 +1,5 @@ // RUN: clang-cc -fsyntax-only -verify %s +// XFAIL @interface Foo @end |