diff options
32 files changed, 441 insertions, 360 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index a8590b2983..1a8dbe551b 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -496,7 +496,7 @@ public: CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; CanQualType VoidPtrTy, NullPtrTy; CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; - CanQualType PseudoObjectTy, ARCUnbridgedCastTy; + CanQualType ARCUnbridgedCastTy; CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand. diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def index bfcd55bedb..067862c1c1 100644 --- a/include/clang/AST/BuiltinTypes.def +++ b/include/clang/AST/BuiltinTypes.def @@ -179,24 +179,6 @@ PLACEHOLDER_TYPE(Overload, OverloadTy) // x->foo # if only contains non-static members PLACEHOLDER_TYPE(BoundMember, BoundMemberTy) -// The type of an expression which refers to a pseudo-object, -// such as those introduced by Objective C's @property or -// VS.NET's __property declarations. A placeholder type. The -// pseudo-object is actually accessed by emitting a call to -// some sort of function or method; typically there is a pair -// of a setter and a getter, with the setter used if the -// pseudo-object reference is used syntactically as the -// left-hand-side of an assignment operator. -// -// A pseudo-object reference naming an Objective-C @property is -// always a dot access with a base of object-pointer type, -// e.g. 'x.foo'. -// -// In VS.NET, a __property declaration creates an implicit -// member with an associated name, which can then be named -// in any of the normal ways an ordinary member could be. -PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy) - // __builtin_any_type. A placeholder type. Useful for clients // like debuggers that don't know what type to give something. // Only a small number of operations are valid on expressions of diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index e0f5e60157..e7b1a0593f 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -1456,26 +1456,12 @@ public: bool isPrefix() const { return isPrefix(getOpcode()); } bool isPostfix() const { return isPostfix(getOpcode()); } - - static bool isIncrementOp(Opcode Op) { - return Op == UO_PreInc || Op == UO_PostInc; - } bool isIncrementOp() const { - return isIncrementOp(getOpcode()); - } - - static bool isDecrementOp(Opcode Op) { - return Op == UO_PreDec || Op == UO_PostDec; + return Opc == UO_PreInc || Opc == UO_PostInc; } - bool isDecrementOp() const { - return isDecrementOp(getOpcode()); - } - - static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; } bool isIncrementDecrementOp() const { - return isIncrementDecrementOp(getOpcode()); + return Opc <= UO_PreDec; } - static bool isArithmeticOp(Opcode Op) { return Op >= UO_Plus && Op <= UO_LNot; } diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 5e4b5b2310..55726eb4ae 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -227,6 +227,7 @@ public: /// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC /// property. +/// class ObjCPropertyRefExpr : public Expr { private: /// If the bool is true, this is an implicit property reference; the @@ -236,11 +237,6 @@ private: llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter; ObjCMethodDecl *Setter; - // FIXME: Maybe we should store the property identifier here, - // because it's not rederivable from the other data when there's an - // implicit property with no getter (because the 'foo' -> 'setFoo:' - // transformation is lossy on the first character). - SourceLocation IdLoc; /// \brief When the receiver in property access is 'super', this is @@ -259,7 +255,6 @@ public: base->containsUnexpandedParameterPack()), PropertyOrGetter(PD, false), Setter(0), IdLoc(l), ReceiverLoc(), Receiver(base) { - assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, @@ -270,7 +265,6 @@ public: st->containsUnexpandedParameterPack()), PropertyOrGetter(PD, false), Setter(0), IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) { - assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, @@ -281,7 +275,6 @@ public: Base->containsUnexpandedParameterPack()), PropertyOrGetter(Getter, true), Setter(Setter), IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) { - assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, @@ -291,7 +284,6 @@ public: : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), PropertyOrGetter(Getter, true), Setter(Setter), IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { - assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, @@ -301,7 +293,6 @@ public: : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), PropertyOrGetter(Getter, true), Setter(Setter), IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { - assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); } explicit ObjCPropertyRefExpr(EmptyShell Empty) @@ -357,15 +348,14 @@ public: if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl()) ResultType = Getter->getResultType(); else - ResultType = PDecl->getType(); + ResultType = getType(); } else { const ObjCMethodDecl *Getter = getImplicitPropertyGetter(); - if (Getter) - ResultType = Getter->getResultType(); // with reference! + ResultType = Getter->getResultType(); // with reference! } return ResultType; } - + QualType getSetterArgType() const { QualType ArgType; if (isImplicitProperty()) { diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 74272ba523..61a182e81b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3612,22 +3612,16 @@ def ext_gnu_ptr_func_arith : Extension< "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function " "type%select{|s}2 %1%select{| and %3}2 is a GNU extension">, InGroup<PointerArith>; +def error_readonly_property_assignment : Error< + "assigning to property with 'readonly' attribute not allowed">; def error_readonly_message_assignment : Error< "assigning to 'readonly' return result of an objective-c message not allowed">; def ext_integer_increment_complex : Extension< "ISO C does not support '++'/'--' on complex integer type %0">; def ext_integer_complement_complex : Extension< "ISO C does not support '~' for complex conjugation of %0">; -def err_nosetter_property_assignment : Error< - "%select{assignment to readonly property|" - "no setter method %1 for assignment to property}0">; -def err_nosetter_property_incdec : Error< - "%select{%select{increment|decrement}1 of readonly property|" - "no setter method %2 for %select{increment|decrement}1 of property}0">; -def err_nogetter_property_compound_assignment : Error< - "a getter method is needed to perform a compound assignment on a property">; -def err_nogetter_property_incdec : Error< - "no getter method %1 for %select{increment|decrement} of property">; +def error_nosetter_property_assignment : Error< + "setter method is needed to assign to object using property" " assignment syntax">; def error_no_subobject_property_setting : Error< "expression is not assignable">; def err_qualified_objc_access : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 2b33392e6b..b55fdea6b9 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -5319,8 +5319,6 @@ public: ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, const ObjCObjectPointerType *OPT, bool IsInstance); - ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, - bool IsInstance); bool inferObjCARCLifetime(ValueDecl *decl); @@ -5779,13 +5777,10 @@ public: // For compound assignment, pass both expressions and the converted type. QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType); - - ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc, - UnaryOperatorKind Opcode, Expr *Op); - ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc, - BinaryOperatorKind Opcode, - Expr *LHS, Expr *RHS); - ExprResult checkPseudoObjectRValue(Expr *E); + + void ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, + QualType& LHSTy); + ExprResult ConvertPropertyForRValue(Expr *E); QualType CheckConditionalOperands( // C99 6.5.15 ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 485b8fe3bb..d237f1b634 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -556,9 +556,7 @@ namespace clang { /// \brief The OpenCL 'half' / ARM NEON __fp16 type. PREDEF_TYPE_HALF_ID = 33, /// \brief ARC's unbridged-cast placeholder type. - PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34, - /// \brief The pseudo-object placeholder type. - PREDEF_TYPE_PSEUDO_OBJECT = 35 + PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34 }; /// \brief The number of predefined type IDs that are reserved for diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ae28149407..4fbb5408dc 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -461,9 +461,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { // Placeholder type for bound members. InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember); - // Placeholder type for pseudo-objects. - InitBuiltinType(PseudoObjectTy, BuiltinType::PseudoObject); - // "any" type; useful for debugger-like clients. InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0bac5f4f61..5b7daadd98 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1493,7 +1493,6 @@ const char *BuiltinType::getName(const PrintingPolicy &Policy) const { case NullPtr: return "nullptr_t"; case Overload: return "<overloaded function type>"; case BoundMember: return "<bound member function type>"; - case PseudoObject: return "<pseudo-object type>"; case Dependent: return "<dependent type>"; case UnknownAny: return "<unknown type>"; case ARCUnbridgedCast: return "<ARC unbridged cast type>"; diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 9bdea433a9..2724e8c46a 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -238,7 +238,6 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::BoundMember: case BuiltinType::UnknownAny: case BuiltinType::ARCUnbridgedCast: - case BuiltinType::PseudoObject: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 0fa143391d..97754d5c0b 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -326,8 +326,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { } case CK_GetObjCProperty: { - LValue LV = - CGF.EmitObjCPropertyRefLValue(E->getSubExpr()->getObjCProperty()); + LValue LV = CGF.EmitLValue(E->getSubExpr()); assert(LV.isPropertyRef()); RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot()); EmitMoveFromReturnSlot(E, RV); diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index b6c416bc35..4a31bcfbe9 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -363,7 +363,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!"); case CK_GetObjCProperty: { - LValue LV = CGF.EmitObjCPropertyRefLValue(Op->getObjCProperty()); + LValue LV = CGF.EmitLValue(Op); assert(LV.isPropertyRef() && "Unknown LValue type!"); return CGF.EmitLoadOfPropertyRefLValue(LV).getComplexVal(); } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 582d1c4572..b088103aa3 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1167,10 +1167,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { break; case CK_GetObjCProperty: { + assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy)); assert(E->isGLValue() && E->getObjectKind() == OK_ObjCProperty && "CK_GetObjCProperty for non-lvalue or non-ObjCProperty"); - LValue LV = CGF.EmitObjCPropertyRefLValue(E->getObjCProperty()); - RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV); + RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E)); return RV.getScalarVal(); } diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp index 1af9a6ce04..6a392ea357 100644 --- a/lib/Rewrite/RewriteObjC.cpp +++ b/lib/Rewrite/RewriteObjC.cpp @@ -1304,7 +1304,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr * } else { OMD = PropRefExpr->getImplicitPropertySetter(); Sel = OMD->getSelector(); - Ty = (*OMD->param_begin())->getType(); + Ty = PropRefExpr->getType(); } Super = PropRefExpr->isSuperReceiver(); if (!Super) { @@ -1380,7 +1380,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) { } else { OMD = PropRefExpr->getImplicitPropertyGetter(); Sel = OMD->getSelector(); - Ty = OMD->getResultType(); + Ty = PropRefExpr->getType(); } Super = PropRefExpr->isSuperReceiver(); if (!Super) diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 06d02252d6..dbbb980de8 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -31,7 +31,6 @@ add_clang_library(clangSema SemaLookup.cpp SemaObjCProperty.cpp SemaOverload.cpp - SemaPseudoObject.cpp SemaStmt.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 6e81c3c966..daab1cd487 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -4256,8 +4256,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, if (LT != Qualifiers::OCL_None) return; - if (ObjCPropertyRefExpr *PRE - = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens())) { + if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) { if (PRE->isImplicitProperty()) return; const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 885b9664d6..3b4a40b51a 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -363,9 +363,19 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { assert(!T.isNull() && "r-value conversion on typeless expression?"); // We can't do lvalue-to-rvalue on atomics yet. - if (T->isAtomicType()) + if (T->getAs<AtomicType>()) return Owned(E); + // Create a load out of an ObjCProperty l-value, if necessary. + if (E->getObjectKind() == OK_ObjCProperty) { + ExprResult Res = ConvertPropertyForRValue(E); + if (Res.isInvalid()) + return Owned(E); + E = Res.take(); + if (!E->isGLValue()) + return Owned(E); + } + // We don't want to throw lvalue-to-rvalue casts on top of // expressions of certain types in C++. if (getLangOptions().CPlusPlus && @@ -3959,23 +3969,6 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, unsigned NumInit = InitArgList.size(); Expr **InitList = InitArgList.release(); - // Immediately handle non-overload placeholders. Overloads can be - // resolved contextually, but everything else here can't. - for (unsigned I = 0; I != NumInit; ++I) { - if (const BuiltinType *pty - = InitList[I]->getType()->getAsPlaceholderType()) { - if (pty->getKind() == BuiltinType::Overload) continue; - - ExprResult result = CheckPlaceholderExpr(InitList[I]); - - // Ignore failures; dropping the entire initializer list because - // of one failure would be terrible for indexing/etc. - if (result.isInvalid()) continue; - - InitList[I] = result.take(); - } - } - // Semantic analysis for initializers is done by ActOnDeclarator() and // CheckInitializer() - it requires knowledge of the object being intialized. @@ -6960,41 +6953,51 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] /// depends on various declarations and thus must be treated specially. /// static bool IsReadonlyProperty(Expr *E, Sema &S) { - const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E); - if (!PropExpr) return false; - if (PropExpr->isImplicitProperty()) return false; + if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) { + const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E); + if (PropExpr->isImplicitProperty()) return false; - ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty(); - QualType BaseType = PropExpr->isSuperReceiver() ? + ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty(); + QualType BaseType = PropExpr->isSuperReceiver() ? PropExpr->getSuperReceiverType() : PropExpr->getBase()->getType(); - if (const ObjCObjectPointerType *OPT = - BaseType->getAsObjCInterfacePointerType()) - if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl()) - 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; } static bool IsConstProperty(Expr *E, Sema &S) { - const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E); - if (!PropExpr) return false; - if (PropExpr->isImplicitProperty()) return false; + if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) { + const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E); + if (PropExpr->isImplicitProperty()) return false; - ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty(); - QualType T = PDecl->getType().getNonReferenceType(); - return T.isConstQualified(); + ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty(); + QualType T = PDecl->getType(); + if (T->isReferenceType()) + T = T->getAs<ReferenceType>()->getPointeeType(); + CanQualType CT = S.Context.getCanonicalType(T); + return CT.isConstQualified(); + } + return false; } static bool IsReadonlyMessage(Expr *E, Sema &S) { - const MemberExpr *ME = dyn_cast<MemberExpr>(E); - if (!ME) return false; - if (!isa<FieldDecl>(ME->getMemberDecl())) return false; - ObjCMessageExpr *Base = - dyn_cast<ObjCMessageExpr>(ME->getBase()->IgnoreParenImpCasts()); - if (!Base) return false; - return Base->getMethodDecl() != 0; + if (E->getStmtClass() != Expr::MemberExprClass) + return false; + const MemberExpr *ME = cast<MemberExpr>(E); + NamedDecl *Member = ME->getMemberDecl(); + if (isa<FieldDecl>(Member)) { + Expr *Base = ME->getBase()->IgnoreParenImpCasts(); + if (Base->getStmtClass() != Expr::ObjCMessageExprClass) + return false; + return cast<ObjCMessageExpr>(Base)->getMethodDecl() != 0; + } + return false; } /// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not, @@ -7082,8 +7085,10 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { Diag = diag::err_block_decl_ref_not_modifiable_lvalue; break; case Expr::MLV_ReadonlyProperty: + Diag = diag::error_readonly_property_assignment; + break; case Expr::MLV_NoSetterProperty: - llvm_unreachable("readonly properties should be processed differently"); + Diag = diag::error_nosetter_property_assignment; break; case Expr::MLV_InvalidMessageExpression: Diag = diag::error_readonly_message_assignment; @@ -7109,8 +7114,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType) { - assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject)); - // Verify that LHS is a modifiable lvalue, and emit error if not. if (CheckForModifiableLvalue(LHSExpr, Loc, *this)) return QualType(); @@ -7121,6 +7124,14 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, AssignConvertType ConvTy; if (CompoundType.isNull()) { QualType LHSTy(LHSType); + // Simple assignment "x = y". + if (LHSExpr->getObjectKind() == OK_ObjCProperty) { + ExprResult LHSResult = Owned(LHSExpr); + ConvertPropertyForLValue(LHSResult, RHS, LHSTy); + if (LHSResult.isInvalid()) + return QualType(); + LHSExpr = LHSResult.take(); + } ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); if (RHS.isInvalid()) return QualType(); @@ -7281,6 +7292,104 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, return ResType.getUnqualifiedType(); } } + +ExprResult Sema::ConvertPropertyForRValue(Expr *E) { + assert(E->getValueKind() == VK_LValue && + E->getObjectKind() == OK_ObjCProperty); + const ObjCPropertyRefExpr *PRE = E->getObjCProperty(); + + QualType T = E->getType(); + QualType ReceiverType; + if (PRE->isObjectReceiver()) + ReceiverType = PRE->getBase()->getType(); + else if (PRE->isSuperReceiver()) + ReceiverType = PRE->getSuperReceiverType(); + else + ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver()); + + ExprValueKind VK = VK_RValue; + if (PRE->isImplicitProperty()) { + if (ObjCMethodDecl *GetterMethod = + PRE->getImplicitPropertyGetter()) { + T = getMessageSendResultType(ReceiverType, GetterMethod, + PRE->isClassReceiver(), + PRE->isSuperReceiver()); + VK = Expr::getValueKindForType(GetterMethod->getResultType()); + } + else { + Diag(PRE->getLocation(), diag::err_getter_not_found) + << PRE->getBase()->getType(); + } + } + else { + // lvalue-ness of an explicit property is determined by + // getter type. + QualType ResT = PRE->getGetterResultType(); + VK = Expr::getValueKindForType(ResT); + } + + E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, + E, 0, VK); + + ExprResult Result = MaybeBindToTemporary(E); + if (!Result.isInvalid()) + E = Result.take(); + + return Owned(E); +} + +void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, + QualType &LHSTy) { + assert(LHS.get()->getValueKind() == VK_LValue && + LHS.get()->getObjectKind() == OK_ObjCProperty); + const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty(); + + bool Consumed = false; + + if (PropRef->isImplicitProperty()) { + // If using property-dot syntax notation for assignment, and there is a + // setter, RHS expression is being passed to the setter argument. So, + // type conversion (and comparison) is RHS to setter's argument type. + if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) { + ObjCMethodDecl::param_const_iterator P = SetterMD->param_begin(); + LHSTy = (*P)->getType(); + Consumed = (getLangOptions().ObjCAutoRefCount && + (*P)->hasAttr<NSConsumedAttr>()); + + // Otherwise, if the getter returns an l-value, just call that. + } else { + QualType Result = PropRef->getImplicitPropertyGetter()->getResultType(); + ExprValueKind VK = Expr::getValueKindForType(Result); + if (VK == VK_LValue) { + LHS = ImplicitCastExpr::Create(Context, LHS.get()->getType(), + CK_GetObjCProperty, LHS.take(), 0, VK); + return; + } + } + } else { + const ObjCMethodDecl *setter + = PropRef->getExplicitProperty()->getSetterMethodDecl(); + if (setter) { + ObjCMethodDecl::param_const_iterator P = setter->param_begin(); + LHSTy = (*P)->getType(); + if (getLangOptions().ObjCAutoRefCount) + Consumed = (*P)->hasAttr<NSConsumedAttr>(); + } + } + + if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) || + getLangOptions().ObjCAutoRefCount) { + InitializedEntity Entity = + InitializedEntity::InitializeParameter(Context, LHSTy, Consumed); + ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS); + if (!ArgE.isInvalid()) { + RHS = ArgE; + if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver()) + checkRetainCycles(const_cast<Expr*>(PropRef->getBase()), RHS.get()); + } + } + LHSTy = LHSTy.getNonReferenceType(); +} /// getPrimaryDecl - Helper function for CheckAddressOfOperand(). @@ -7364,39 +7473,31 @@ static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc, /// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. /// In C++, the operand might be an overloaded function name, in which case /// we allow the '&' but retain the overloaded-function type. -static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp, +static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, SourceLocation OpLoc) { - if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){ - if (PTy->getKind() == BuiltinType::Overload) { - if (!isa<OverloadExpr>(OrigOp.get()->IgnoreParens())) { - S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) - << OrigOp.get()->getSourceRange(); - return QualType(); - } - - return S.Context.OverloadTy; - } - - if (PTy->getKind() == BuiltinType::UnknownAny) - return S.Context.UnknownAnyTy; - - if (PTy->getKind() == BuiltinType::BoundMember) { - S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function) - << OrigOp.get()->getSourceRange(); + if (OrigOp->isTypeDependent()) + return S.Context.DependentTy; + if (OrigOp->getType() == S.Context.OverloadTy) { + if (!isa<OverloadExpr>(OrigOp->IgnoreParens())) { + S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) + << OrigOp->getSourceRange(); return QualType(); } - - OrigOp = S.CheckPlaceholderExpr(OrigOp.take()); - if |