diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.cpp | 43 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 441 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 186 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 126 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 20 |
10 files changed, 469 insertions, 371 deletions
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: |