[cfe-commits] r142914 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ include/clang/Serialization/ lib/AST/ lib/CodeGen/ lib/Rewrite/ lib/Sema/ lib/Serialization/ test/SemaObjC/ test/SemaObjCXX/

John McCall rjmccall at apple.com
Tue Oct 25 00:27:56 PDT 2011


Author: rjmccall
Date: Tue Oct 25 02:27:56 2011
New Revision: 142914

URL: http://llvm.org/viewvc/llvm-project?rev=142914&view=rev
Log:
Introduce a placeholder type for "pseudo object"
expressions: expressions which refer to a logical rather
than a physical l-value, where the logical object is
actually accessed via custom getter/setter code.
A subsequent patch will generalize the AST for these
so that arbitrary "implementing" sub-expressions can
be provided.

Right now the only client is ObjC properties, but
this should be generalizable to similar language
features, e.g. Managed C++'s __property methods.



Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/BuiltinTypes.def
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/ExprObjC.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/AST/TypeLoc.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CGExprComplex.cpp
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/lib/Rewrite/RewriteObjC.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprMember.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaObjCProperty.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTCommon.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/test/SemaObjC/property-category-1.m
    cfe/trunk/test/SemaObjC/property-error-readonly-assign.m
    cfe/trunk/test/SemaObjC/property-in-class-extension.m
    cfe/trunk/test/SemaObjC/property-user-setter.m
    cfe/trunk/test/SemaObjCXX/propert-dot-error.mm

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Tue Oct 25 02:27:56 2011
@@ -496,7 +496,7 @@
   CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
   CanQualType VoidPtrTy, NullPtrTy;
   CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
-  CanQualType ARCUnbridgedCastTy;
+  CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
   CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
 
   // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.

Modified: cfe/trunk/include/clang/AST/BuiltinTypes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/BuiltinTypes.def?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/BuiltinTypes.def (original)
+++ cfe/trunk/include/clang/AST/BuiltinTypes.def Tue Oct 25 02:27:56 2011
@@ -179,6 +179,24 @@
 //   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

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Tue Oct 25 02:27:56 2011
@@ -1456,12 +1456,26 @@
 
   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 Opc == UO_PreInc || Opc == UO_PostInc;
+    return isIncrementOp(getOpcode());
+  }
+
+  static bool isDecrementOp(Opcode Op) {
+    return Op == UO_PreDec || Op == UO_PostDec;
   }
+  bool isDecrementOp() const {
+    return isDecrementOp(getOpcode());
+  }
+
+  static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; }
   bool isIncrementDecrementOp() const {
-    return Opc <= UO_PreDec;
+    return isIncrementDecrementOp(getOpcode());
   }
+
   static bool isArithmeticOp(Opcode Op) {
     return Op >= UO_Plus && Op <= UO_LNot;
   }

Modified: cfe/trunk/include/clang/AST/ExprObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprObjC.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprObjC.h (original)
+++ cfe/trunk/include/clang/AST/ExprObjC.h Tue Oct 25 02:27:56 2011
@@ -227,7 +227,6 @@
 
 /// 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
@@ -237,6 +236,11 @@
   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
@@ -255,6 +259,7 @@
            base->containsUnexpandedParameterPack()),
       PropertyOrGetter(PD, false), Setter(0),
       IdLoc(l), ReceiverLoc(), Receiver(base) {
+    assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
   }
   
   ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
@@ -265,6 +270,7 @@
            st->containsUnexpandedParameterPack()),
       PropertyOrGetter(PD, false), Setter(0),
       IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) {
+    assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
   }
 
   ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -275,6 +281,7 @@
            Base->containsUnexpandedParameterPack()),
       PropertyOrGetter(Getter, true), Setter(Setter),
       IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) {
+    assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
   }
 
   ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -284,6 +291,7 @@
     : 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,
@@ -293,6 +301,7 @@
     : 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)
@@ -348,14 +357,15 @@
       if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
         ResultType = Getter->getResultType();
       else
-        ResultType = getType();
+        ResultType = PDecl->getType();
     } else {
       const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
-      ResultType = Getter->getResultType(); // with reference!
+      if (Getter)
+        ResultType = Getter->getResultType(); // with reference!
     }
     return ResultType;
   }
-  
+
   QualType getSetterArgType() const {
     QualType ArgType;
     if (isImplicitProperty()) {

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct 25 02:27:56 2011
@@ -3612,16 +3612,22 @@
   "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 error_nosetter_property_assignment : Error<
-  "setter method is needed to assign to object using property" " assignment syntax">;
+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_no_subobject_property_setting : Error<
   "expression is not assignable">;
 def err_qualified_objc_access : Error<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Oct 25 02:27:56 2011
@@ -5319,6 +5319,8 @@
   ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel,
                                               const ObjCObjectPointerType *OPT,
                                               bool IsInstance);
+  ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty,
+                                           bool IsInstance);
 
   bool inferObjCARCLifetime(ValueDecl *decl);
     
@@ -5777,10 +5779,13 @@
   // 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);
-  
-  void ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS,
-                                QualType& LHSTy);
-  ExprResult ConvertPropertyForRValue(Expr *E);
+
+  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);
                                    
   QualType CheckConditionalOperands( // C99 6.5.15
     ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Tue Oct 25 02:27:56 2011
@@ -556,7 +556,9 @@
       /// \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
+      PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34,
+      /// \brief The pseudo-object placeholder type.
+      PREDEF_TYPE_PSEUDO_OBJECT = 35
     };
 
     /// \brief The number of predefined type IDs that are reserved for

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Tue Oct 25 02:27:56 2011
@@ -461,6 +461,9 @@
   // 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);
 

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Tue Oct 25 02:27:56 2011
@@ -1493,6 +1493,7 @@
   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>";

Modified: cfe/trunk/lib/AST/TypeLoc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeLoc.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypeLoc.cpp (original)
+++ cfe/trunk/lib/AST/TypeLoc.cpp Tue Oct 25 02:27:56 2011
@@ -238,6 +238,7 @@
     case BuiltinType::BoundMember:
     case BuiltinType::UnknownAny:
     case BuiltinType::ARCUnbridgedCast:
+    case BuiltinType::PseudoObject:
     case BuiltinType::ObjCId:
     case BuiltinType::ObjCClass:
     case BuiltinType::ObjCSel:

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Tue Oct 25 02:27:56 2011
@@ -326,7 +326,8 @@
   }
 
   case CK_GetObjCProperty: {
-    LValue LV = CGF.EmitLValue(E->getSubExpr());
+    LValue LV =
+      CGF.EmitObjCPropertyRefLValue(E->getSubExpr()->getObjCProperty());
     assert(LV.isPropertyRef());
     RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot());
     EmitMoveFromReturnSlot(E, RV);

Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Tue Oct 25 02:27:56 2011
@@ -363,7 +363,7 @@
   case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
 
   case CK_GetObjCProperty: {
-    LValue LV = CGF.EmitLValue(Op);
+    LValue LV = CGF.EmitObjCPropertyRefLValue(Op->getObjCProperty());
     assert(LV.isPropertyRef() && "Unknown LValue type!");
     return CGF.EmitLoadOfPropertyRefLValue(LV).getComplexVal();
   }

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Oct 25 02:27:56 2011
@@ -1167,10 +1167,10 @@
     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");
-    RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E));
+    LValue LV = CGF.EmitObjCPropertyRefLValue(E->getObjCProperty());
+    RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV);
     return RV.getScalarVal();
   }
 

Modified: cfe/trunk/lib/Rewrite/RewriteObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/RewriteObjC.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Rewrite/RewriteObjC.cpp (original)
+++ cfe/trunk/lib/Rewrite/RewriteObjC.cpp Tue Oct 25 02:27:56 2011
@@ -1304,7 +1304,7 @@
     } else {
       OMD = PropRefExpr->getImplicitPropertySetter();
       Sel = OMD->getSelector();
-      Ty = PropRefExpr->getType();
+      Ty = (*OMD->param_begin())->getType();
     }
     Super = PropRefExpr->isSuperReceiver();
     if (!Super) {
@@ -1380,7 +1380,7 @@
     } else {
       OMD = PropRefExpr->getImplicitPropertyGetter();
       Sel = OMD->getSelector();
-      Ty = PropRefExpr->getType();
+      Ty = OMD->getResultType();
     }
     Super = PropRefExpr->isSuperReceiver();
     if (!Super)

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Oct 25 02:27:56 2011
@@ -4256,7 +4256,8 @@
   if (LT != Qualifiers::OCL_None)
     return;
   
-  if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
+  if (ObjCPropertyRefExpr *PRE
+        = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens())) {
     if (PRE->isImplicitProperty())
       return;
     const ObjCPropertyDecl *PD = PRE->getExplicitProperty();

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 25 02:27:56 2011
@@ -363,19 +363,9 @@
   assert(!T.isNull() && "r-value conversion on typeless expression?");
 
   // We can't do lvalue-to-rvalue on atomics yet.
-  if (T->getAs<AtomicType>())
+  if (T->isAtomicType())
     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 &&
@@ -3969,6 +3959,23 @@
   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.
 
@@ -7085,10 +7092,8 @@
     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:
-    Diag = diag::error_nosetter_property_assignment;
+    llvm_unreachable("readonly properties should be processed differently");
     break;
   case Expr::MLV_InvalidMessageExpression:
     Diag = diag::error_readonly_message_assignment;
@@ -7114,6 +7119,8 @@
 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();
@@ -7124,14 +7131,6 @@
   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();
@@ -7293,12 +7292,35 @@
   }
 }
 
-ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
+static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
+                                            const ObjCPropertyRefExpr *PRE) {
+  bool instanceProperty;
+  QualType searchType;
+  if (PRE->isObjectReceiver()) {
+    searchType = PRE->getBase()->getType()
+      ->castAs<ObjCObjectPointerType>()->getPointeeType();
+    instanceProperty = true;
+  } else if (PRE->isSuperReceiver()) {
+    searchType = PRE->getSuperReceiverType();
+    instanceProperty = false;
+    if (const ObjCObjectPointerType *PT
+        = searchType->getAs<ObjCObjectPointerType>()) {
+      searchType = PT->getPointeeType();
+      instanceProperty = true;
+    }
+  } else if (PRE->isClassReceiver()) {
+    searchType = S.Context.getObjCInterfaceType(PRE->getClassReceiver());
+    instanceProperty = false;
+  }
+
+  return S.LookupMethodInObjectType(sel, searchType, instanceProperty);
+}
+
+ExprResult Sema::checkPseudoObjectRValue(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();
@@ -7308,28 +7330,50 @@
     ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
     
   ExprValueKind VK = VK_RValue;
+  QualType T;
   if (PRE->isImplicitProperty()) {
     if (ObjCMethodDecl *GetterMethod = 
           PRE->getImplicitPropertyGetter()) {
-      T = getMessageSendResultType(ReceiverType, GetterMethod, 
+      T = getMessageSendResultType(ReceiverType, GetterMethod,
                                    PRE->isClassReceiver(), 
                                    PRE->isSuperReceiver());
       VK = Expr::getValueKindForType(GetterMethod->getResultType());
-    }
-    else {
+    } else {
       Diag(PRE->getLocation(), diag::err_getter_not_found)
             << PRE->getBase()->getType();
+      return ExprError();
+    }
+  } else {
+    ObjCPropertyDecl *prop = PRE->getExplicitProperty();
+
+    ObjCMethodDecl *getter =
+      LookupMethodInReceiverType(*this, prop->getGetterName(), PRE);
+    if (getter && !getter->hasRelatedResultType())
+      DiagnosePropertyAccessorMismatch(prop, getter, PRE->getLocation());
+    if (!getter) getter = prop->getGetterMethodDecl();
+
+    // Figure out the type of the expression.  Mostly this is the
+    // result type of the getter, if possible.
+    if (getter) {
+      T = getMessageSendResultType(ReceiverType, getter, 
+                                   PRE->isClassReceiver(), 
+                                   PRE->isSuperReceiver());
+      VK = Expr::getValueKindForType(getter->getResultType());
+
+      // As a special case, if the method returns 'id', try to get a
+      // better type from the property.
+      if (VK == VK_RValue && T->isObjCIdType() &&
+          prop->getType()->isObjCRetainableType())
+        T = prop->getType();
+    } else {
+      T = prop->getType();
+      VK = Expr::getValueKindForType(T);
+      T = T.getNonLValueExprType(Context);
     }
   }
-  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);
+
+  E->setType(T);
+  E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK);
   
   ExprResult Result = MaybeBindToTemporary(E);
   if (!Result.isInvalid())
@@ -7338,57 +7382,215 @@
   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);
+namespace {
+  struct PseudoObjectInfo {
+    const ObjCPropertyRefExpr *RefExpr;
+    bool HasSetter;
+    Selector SetterSelector;
+    ParmVarDecl *SetterParam;
+    QualType SetterParamType;
+
+    void setSetter(ObjCMethodDecl *setter) {
+      HasSetter = true;
+      SetterParam = *setter->param_begin();
+      SetterParamType = SetterParam->getType().getUnqualifiedType();
+    }
+
+    PseudoObjectInfo(Sema &S, Expr *E)
+      : RefExpr(E->getObjCProperty()), HasSetter(false), SetterParam(0) {
+
+      assert(E->getValueKind() == VK_LValue &&
+             E->getObjectKind() == OK_ObjCProperty);
+
+      // Try to find a setter.
+
+      // For implicit properties, just trust the lookup we already did.
+      if (RefExpr->isImplicitProperty()) {
+        if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) {
+          setSetter(setter);
+          SetterSelector = setter->getSelector();
+        } else {
+          IdentifierInfo *getterName =
+            RefExpr->getImplicitPropertyGetter()->getSelector()
+              .getIdentifierInfoForSlot(0);
+          SetterSelector = 
+            SelectorTable::constructSetterName(S.PP.getIdentifierTable(),
+                                               S.PP.getSelectorTable(),
+                                               getterName);
+        }
         return;
       }
+
+      // For explicit properties, this is more involved.
+      ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();
+      SetterSelector = prop->getSetterName();
+
+      // Do a normal method lookup first.
+      if (ObjCMethodDecl *setter =
+            LookupMethodInReceiverType(S, SetterSelector, RefExpr))
+        return setSetter(setter);
+
+      // If that failed, trust the type on the @property declaration.
+      if (!prop->isReadOnly()) {
+        HasSetter = true;
+        SetterParamType = prop->getType().getUnqualifiedType();
+      }
     }
-  } else {
-    const ObjCMethodDecl *setter
-      = PropRef->getExplicitProperty()->getSetterMethodDecl();
-    if (setter) {
-      ObjCMethodDecl::param_const_iterator P = setter->param_begin();
-      LHSTy = (*P)->getType();
+  };
+}
+
+/// Check an increment or decrement of a pseudo-object expression.
+ExprResult Sema::checkPseudoObjectIncDec(Scope *S, SourceLocation opcLoc,
+                                         UnaryOperatorKind opcode, Expr *op) {
+  assert(UnaryOperator::isIncrementDecrementOp(opcode));
+  PseudoObjectInfo info(*this, op);
+
+  // If there's no setter, we have no choice but to try to assign to
+  // the result of the getter.
+  if (!info.HasSetter) {
+    QualType resultType = info.RefExpr->getGetterResultType();
+    assert(!resultType.isNull() && "property has no setter and no getter!");
+
+    // Only do this if the getter returns an l-value reference type.
+    if (const LValueReferenceType *refType
+          = resultType->getAs<LValueReferenceType>()) {
+      op = ImplicitCastExpr::Create(Context, refType->getPointeeType(),
+                                    CK_GetObjCProperty, op, 0, VK_LValue);
+      return BuildUnaryOp(S, opcLoc, opcode, op);
+    }
+
+    // Otherwise, it's an error.
+    Diag(opcLoc, diag::err_nosetter_property_incdec)
+      << unsigned(info.RefExpr->isImplicitProperty())
+      << unsigned(UnaryOperator::isDecrementOp(opcode))
+      << info.SetterSelector
+      << op->getSourceRange();
+    return ExprError();
+  }
+
+  // ++/-- behave like compound assignments, i.e. they need a getter.
+  QualType getterResultType = info.RefExpr->getGetterResultType();
+  if (getterResultType.isNull()) {
+    assert(info.RefExpr->isImplicitProperty());
+    Diag(opcLoc, diag::err_nogetter_property_incdec)
+      << unsigned(UnaryOperator::isDecrementOp(opcode))
+      << info.RefExpr->getImplicitPropertyGetter()->getSelector()
+      << op->getSourceRange();
+    return ExprError();
+  }
+
+  // HACK: change the type of the operand to prevent further placeholder
+  // transformation.
+  op->setType(getterResultType.getNonLValueExprType(Context));
+  op->setObjectKind(OK_Ordinary);
+  
+  ExprResult result = CreateBuiltinUnaryOp(opcLoc, opcode, op);
+  if (result.isInvalid()) return ExprError();
+
+  // Change the object kind back.
+  op->setObjectKind(OK_ObjCProperty);
+  return result;
+}
+
+ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
+                                             BinaryOperatorKind opcode,
+                                             Expr *LHS, Expr *RHS) {
+  assert(BinaryOperator::isAssignmentOp(opcode));
+  PseudoObjectInfo info(*this, LHS);
+
+  // If there's no setter, we have no choice but to try to assign to
+  // the result of the getter.
+  if (!info.HasSetter) {
+    QualType resultType = info.RefExpr->getGetterResultType();
+    assert(!resultType.isNull() && "property has no setter and no getter!");
+
+    // Only do this if the getter returns an l-value reference type.
+    if (const LValueReferenceType *refType
+          = resultType->getAs<LValueReferenceType>()) {
+      LHS = ImplicitCastExpr::Create(Context, refType->getPointeeType(),
+                                     CK_GetObjCProperty, LHS, 0, VK_LValue);
+      return BuildBinOp(S, opcLoc, opcode, LHS, RHS);
+    }
+
+    // Otherwise, it's an error.
+    Diag(opcLoc, diag::err_nosetter_property_assignment)
+      << unsigned(info.RefExpr->isImplicitProperty())
+      << info.SetterSelector
+      << LHS->getSourceRange() << RHS->getSourceRange();
+    return ExprError();
+  }
+
+  // If there is a setter, we definitely want to use it.
+
+  // If this is a simple assignment, just initialize the parameter
+  // with the RHS.
+  if (opcode == BO_Assign) {
+    LHS->setType(info.SetterParamType.getNonLValueExprType(Context));
+
+    // Under certain circumstances, we need to type-check the RHS as a
+    // straight-up parameter initialization.  This gives somewhat
+    // inferior diagnostics, so we try to avoid it.
+
+    if (RHS->isTypeDependent()) {
+      // Just build the expression.
+
+    } else if ((getLangOptions().CPlusPlus && LHS->getType()->isRecordType()) ||
+               (getLangOptions().ObjCAutoRefCount &&
+                info.SetterParam &&
+                info.SetterParam->hasAttr<NSConsumedAttr>())) {
+      InitializedEntity param = (info.SetterParam
+        ? InitializedEntity::InitializeParameter(Context, info.SetterParam)
+        : InitializedEntity::InitializeParameter(Context, info.SetterParamType,
+                                                 /*consumed*/ false));
+      ExprResult arg = PerformCopyInitialization(param, opcLoc, RHS);
+      if (arg.isInvalid()) return ExprError();
+      RHS = arg.take();
+
+      // Warn about assignments of +1 objects to unsafe pointers in ARC.
+      // CheckAssignmentOperands does this on the other path.
       if (getLangOptions().ObjCAutoRefCount)
-        Consumed = (*P)->hasAttr<NSConsumedAttr>();
+        checkUnsafeExprAssigns(opcLoc, LHS, RHS);
+    } else {
+      ExprResult RHSResult = Owned(RHS);
+
+      LHS->setObjectKind(OK_Ordinary);
+      QualType resultType = CheckAssignmentOperands(LHS, RHSResult, opcLoc,
+                                                    /*compound*/ QualType());
+      LHS->setObjectKind(OK_ObjCProperty);
+
+      if (!RHSResult.isInvalid()) RHS = RHSResult.take();
+      if (resultType.isNull()) return ExprError();
     }
+
+    // Warn about property sets in ARC that might cause retain cycles.
+    if (getLangOptions().ObjCAutoRefCount && !info.RefExpr->isSuperReceiver())
+      checkRetainCycles(const_cast<Expr*>(info.RefExpr->getBase()), RHS);
+
+    return new (Context) BinaryOperator(LHS, RHS, opcode, RHS->getType(),
+                                        RHS->getValueKind(),
+                                        RHS->getObjectKind(),
+                                        opcLoc);
   }
 
-  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());
-    }
+  // If this is a compound assignment, we need to use the getter, too.
+  QualType getterResultType = info.RefExpr->getGetterResultType();
+  if (getterResultType.isNull()) {
+    Diag(opcLoc, diag::err_nogetter_property_compound_assignment)
+      << LHS->getSourceRange() << RHS->getSourceRange();
+    return ExprError();
   }
-  LHSTy = LHSTy.getNonReferenceType();
+
+  // HACK: change the type of the LHS to prevent further placeholder
+  // transformation.
+  LHS->setType(getterResultType.getNonLValueExprType(Context));
+  LHS->setObjectKind(OK_Ordinary);
+  
+  ExprResult result = CreateBuiltinBinOp(opcLoc, opcode, LHS, RHS);
+  if (result.isInvalid()) return ExprError();
+
+  // Change the object kind back.
+  LHS->setObjectKind(OK_ObjCProperty);
+  return result;
 }
   
 
@@ -7473,31 +7675,39 @@
 /// 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, Expr *OrigOp,
+static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
                                       SourceLocation OpLoc) {
-  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();
+  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();
       return QualType();
     }
-                  
-    return S.Context.OverloadTy;
-  }
-  if (OrigOp->getType() == S.Context.UnknownAnyTy)
-    return S.Context.UnknownAnyTy;
-  if (OrigOp->getType() == S.Context.BoundMemberTy) {
-    S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
-      << OrigOp->getSourceRange();
-    return QualType();
+
+    OrigOp = S.CheckPlaceholderExpr(OrigOp.take());
+    if (OrigOp.isInvalid()) return QualType();
   }
 
-  assert(!OrigOp->getType()->isPlaceholderType());
+  if (OrigOp.get()->isTypeDependent())
+    return S.Context.DependentTy;
+
+  assert(!OrigOp.get()->getType()->isPlaceholderType());
 
   // Make sure to ignore parentheses in subsequent checks
-  Expr *op = OrigOp->IgnoreParens();
+  Expr *op = OrigOp.get()->IgnoreParens();
 
   if (S.getLangOptions().C99) {
     // Implement C99-only parts of addressof rules.
@@ -7530,16 +7740,16 @@
     // If the underlying expression isn't a decl ref, give up.
     if (!isa<DeclRefExpr>(op)) {
       S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
-        << OrigOp->getSourceRange();
+        << OrigOp.get()->getSourceRange();
       return QualType();
     }
     DeclRefExpr *DRE = cast<DeclRefExpr>(op);
     CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
 
     // The id-expression was parenthesized.
-    if (OrigOp != DRE) {
+    if (OrigOp.get() != DRE) {
       S.Diag(OpLoc, diag::err_parens_pointer_member_function)
-        << OrigOp->getSourceRange();
+        << OrigOp.get()->getSourceRange();
 
     // The method was named without a qualifier.
     } else if (!DRE->getQualifier()) {
@@ -7553,10 +7763,15 @@
     // C99 6.5.3.2p1
     // The operand must be either an l-value or a function designator
     if (!op->getType()->isFunctionType()) {
-      // FIXME: emit more specific diag...
-      S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
-        << op->getSourceRange();
-      return QualType();
+      // Use a special diagnostic for loads from property references.
+      if (isa<ObjCPropertyRefExpr>(op->IgnoreImplicit()->IgnoreParens())) {
+        AddressOfError = AO_Property_Expansion;
+      } else {
+        // FIXME: emit more specific diag...
+        S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+          << op->getSourceRange();
+        return QualType();
+      }
     }
   } else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1
     // The operand cannot be a bit-field
@@ -7781,23 +7996,6 @@
   ExprValueKind VK = VK_RValue;
   ExprObjectKind OK = OK_Ordinary;
 
-  // Check if a 'foo<int>' involved in a binary op, identifies a single 
-  // function unambiguously (i.e. an lvalue ala 13.4)
-  // But since an assignment can trigger target based overload, exclude it in 
-  // our blind search. i.e:
-  // template<class T> void f(); template<class T, class U> void f(U);
-  // f<int> == 0;  // resolve f<int> blindly
-  // void (*p)(int); p = f<int>;  // resolve f<int> using target
-  if (Opc != BO_Assign) { 
-    ExprResult resolvedLHS = CheckPlaceholderExpr(LHS.get());
-    if (!resolvedLHS.isUsable()) return ExprError();
-    LHS = move(resolvedLHS);
-
-    ExprResult resolvedRHS = CheckPlaceholderExpr(RHS.get());
-    if (!resolvedRHS.isUsable()) return ExprError();
-    RHS = move(resolvedRHS);
-  }
-
   switch (Opc) {
   case BO_Assign:
     ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
@@ -8093,38 +8291,83 @@
   return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr);
 }
 
+/// Build an overloaded binary operator expression in the given scope.
+static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
+                                       BinaryOperatorKind Opc,
+                                       Expr *LHS, Expr *RHS) {
+  // Find all of the overloaded operators visible from this
+  // point. We perform both an operator-name lookup from the local
+  // scope and an argument-dependent lookup based on the types of
+  // the arguments.
+  UnresolvedSet<16> Functions;
+  OverloadedOperatorKind OverOp
+    = BinaryOperator::getOverloadedOperator(Opc);
+  if (Sc && OverOp != OO_None)
+    S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),
+                                   RHS->getType(), Functions);
+
+  // Build the (potentially-overloaded, potentially-dependent)
+  // binary operation.
+  return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS);
+}
+
 ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
                             BinaryOperatorKind Opc,
                             Expr *LHSExpr, Expr *RHSExpr) {
+  // Handle pseudo-objects in the LHS.
+  if (const BuiltinType *pty = LHSExpr->getType()->getAsPlaceholderType()) {
+    // Assignments with a pseudo-object l-value need special analysis.
+    if (pty->getKind() == BuiltinType::PseudoObject &&
+        BinaryOperator::isAssignmentOp(Opc))
+      return checkPseudoObjectAssignment(S, OpLoc, Opc, LHSExpr, RHSExpr);
+
+    // Don't resolve overloads if the other type is overloadable.
+    if (pty->getKind() == BuiltinType::Overload) {
+      // We can't actually test that if we still have a placeholder,
+      // though.  Fortunately, none of the exceptions we see in that
+      // code below are valid when the LHS is an overload set.
+      ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr);
+      if (resolvedRHS.isInvalid()) return ExprError();
+      RHSExpr = resolvedRHS.take();
+
+      if (RHSExpr->getType()->isOverloadableType())
+        return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
+    }
+        
+    ExprResult LHS = CheckPlaceholderExpr(LHSExpr);
+    if (LHS.isInvalid()) return ExprError();
+    LHSExpr = LHS.take();
+  }
+
+  // Handle pseudo-objects in the RHS.
+  if (const BuiltinType *pty = RHSExpr->getType()->getAsPlaceholderType()) {
+    // An overload in the RHS can potentially be resolved by the type
+    // being assigned to.
+    if (Opc == BO_Assign && pty->getKind() == BuiltinType::Overload)
+      return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
+
+    // Don't resolve overloads if the other type is overloadable.
+    if (pty->getKind() == BuiltinType::Overload &&
+        LHSExpr->getType()->isOverloadableType())
+      return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
+
+    ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr);
+    if (!resolvedRHS.isUsable()) return ExprError();
+    RHSExpr = resolvedRHS.take();
+  }
+
   if (getLangOptions().CPlusPlus) {
     bool UseBuiltinOperator;
 
     if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) {
       UseBuiltinOperator = false;
-    } else if (Opc == BO_Assign &&
-               LHSExpr->getObjectKind() == OK_ObjCProperty) {
-      UseBuiltinOperator = true;
     } else {
       UseBuiltinOperator = !LHSExpr->getType()->isOverloadableType() &&
                            !RHSExpr->getType()->isOverloadableType();
     }
 
-    if (!UseBuiltinOperator) {
-      // Find all of the overloaded operators visible from this
-      // point. We perform both an operator-name lookup from the local
-      // scope and an argument-dependent lookup based on the types of
-      // the arguments.
-      UnresolvedSet<16> Functions;
-      OverloadedOperatorKind OverOp
-        = BinaryOperator::getOverloadedOperator(Opc);
-      if (S && OverOp != OO_None)
-        LookupOverloadedOperatorName(OverOp, S, LHSExpr->getType(),
-                                     RHSExpr->getType(), Functions);
-
-      // Build the (potentially-overloaded, potentially-dependent)
-      // binary operation.
-      return CreateOverloadedBinOp(OpLoc, Opc, Functions, LHSExpr, RHSExpr);
-    }
+    if (!UseBuiltinOperator)
+      return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
   }
 
   // Build a built-in binary operation.
@@ -8150,12 +8393,9 @@
                                                 Opc == UO_PreDec);
     break;
   case UO_AddrOf:
-    resultType = CheckAddressOfOperand(*this, Input.get(), OpLoc);
+    resultType = CheckAddressOfOperand(*this, Input, OpLoc);
     break;
   case UO_Deref: {
-    ExprResult resolved = CheckPlaceholderExpr(Input.get());
-    if (!resolved.isUsable()) return ExprError();
-    Input = move(resolved);
     Input = DefaultFunctionArrayLvalueConversion(Input.take());
     resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
     break;
@@ -8177,11 +8417,6 @@
              Opc == UO_Plus &&
              resultType->isPointerType())
       break;
-    else if (resultType->isPlaceholderType()) {
-      Input = CheckPlaceholderExpr(Input.take());
-      if (Input.isInvalid()) return ExprError();
-      return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
-    }
 
     return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
       << resultType << Input.get()->getSourceRange());
@@ -8199,11 +8434,7 @@
         << resultType << Input.get()->getSourceRange();
     else if (resultType->hasIntegerRepresentation())
       break;
-    else if (resultType->isPlaceholderType()) {
-      Input = CheckPlaceholderExpr(Input.take());
-      if (Input.isInvalid()) return ExprError();
-      return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
-    } else {
+    else {
       return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
         << resultType << Input.get()->getSourceRange());
     }
@@ -8231,10 +8462,6 @@
         Input = ImpCastExprToType(Input.take(), Context.BoolTy,
                                   ScalarTypeToBooleanCastKind(resultType));
       }
-    } else if (resultType->isPlaceholderType()) {
-      Input = CheckPlaceholderExpr(Input.take());
-      if (Input.isInvalid()) return ExprError();
-      return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
     } else {
       return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
         << resultType << Input.get()->getSourceRange());
@@ -8275,6 +8502,32 @@
 
 ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
                               UnaryOperatorKind Opc, Expr *Input) {
+  // First things first: handle placeholders so that the
+  // overloaded-operator check considers the right type.
+  if (const BuiltinType *pty = Input->getType()->getAsPlaceholderType()) {
+    // Increment and decrement of pseudo-object references.
+    if (pty->getKind() == BuiltinType::PseudoObject &&
+        UnaryOperator::isIncrementDecrementOp(Opc))
+      return checkPseudoObjectIncDec(S, OpLoc, Opc, Input);
+
+    // extension is always a builtin operator.
+    if (Opc == UO_Extension)
+      return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
+
+    // & gets special logic for several kinds of placeholder.
+    // The builtin code knows what to do.
+    if (Opc == UO_AddrOf &&
+        (pty->getKind() == BuiltinType::Overload ||
+         pty->getKind() == BuiltinType::UnknownAny ||
+         pty->getKind() == BuiltinType::BoundMember))
+      return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
+
+    // Anything else needs to be handled now.
+    ExprResult Result = CheckPlaceholderExpr(Input);
+    if (Result.isInvalid()) return ExprError();
+    Input = Result.take();
+  }
+
   if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() &&
       UnaryOperator::getOverloadedOperator(Opc) != OO_None) {
     // Find all of the overloaded operators visible from this
@@ -10151,6 +10404,10 @@
   case BuiltinType::UnknownAny:
     return diagnoseUnknownAnyExpr(*this, E);
 
+  // Pseudo-objects.
+  case BuiltinType::PseudoObject:
+    return checkPseudoObjectRValue(E);
+
   // Everything else should be impossible.
 #define BUILTIN_TYPE(Id, SingletonId) \
   case BuiltinType::Id:

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Oct 25 02:27:56 2011
@@ -2260,15 +2260,7 @@
     break;
 
   case ICK_Lvalue_To_Rvalue:
-    // Should this get its own ICK?
-    if (From->getObjectKind() == OK_ObjCProperty) {
-      ExprResult FromRes = ConvertPropertyForRValue(From);
-      if (FromRes.isInvalid())
-        return ExprError();
-      From = FromRes.take();
-      if (!From->isGLValue()) break;
-    }
-
+    assert(From->getObjectKind() != OK_ObjCProperty);
     FromType = FromType.getUnqualifiedType();
     From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue,
                                     From, 0, VK_RValue);
@@ -4194,6 +4186,10 @@
   if (Result.isInvalid()) return ExprError();
   Base = Result.get();
 
+  Result = CheckPlaceholderExpr(Base);
+  if (Result.isInvalid()) return ExprError();
+  Base = Result.take();
+
   QualType BaseType = Base->getType();
   MayBePseudoDestructor = false;
   if (BaseType->isDependentType()) {
@@ -4592,6 +4588,12 @@
 /// Perform the conversions required for an expression used in a
 /// context that ignores the result.
 ExprResult Sema::IgnoredValueConversions(Expr *E) {
+  if (E->hasPlaceholderType()) {
+    ExprResult result = CheckPlaceholderExpr(E);
+    if (result.isInvalid()) return Owned(E);
+    E = result.take();
+  }
+
   // C99 6.3.2.1:
   //   [Except in specific positions,] an lvalue that does not have
   //   array type is converted to the value stored in the
@@ -4607,14 +4609,6 @@
     return Owned(E);
   }
 
-  // We always want to do this on ObjC property references.
-  if (E->getObjectKind() == OK_ObjCProperty) {
-    ExprResult Res = ConvertPropertyForRValue(E);
-    if (Res.isInvalid()) return Owned(E);
-    E = Res.take();
-    if (E->isRValue()) return Owned(E);
-  }
-
   // Otherwise, this rule does not apply in C++, at least not for the moment.
   if (getLangOptions().CPlusPlus) return Owned(E);
 

Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprMember.cpp Tue Oct 25 02:27:56 2011
@@ -777,7 +777,7 @@
   QualType BaseType = BaseExprType;
   if (IsArrow) {
     assert(BaseType->isPointerType());
-    BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+    BaseType = BaseType->castAs<PointerType>()->getPointeeType();
   }
   R.setBaseObjectType(BaseType);
 
@@ -814,15 +814,6 @@
       CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
     return ExprError();
   
-  // Perform a property load on the base regardless of whether we
-  // actually need it for the declaration.
-  if (BaseExpr && BaseExpr->getObjectKind() == OK_ObjCProperty) {
-    ExprResult Result = ConvertPropertyForRValue(BaseExpr);
-    if (Result.isInvalid())
-      return ExprError();
-    BaseExpr = Result.take();
-  }
-
   // Construct an unresolved result if we in fact got an unresolved
   // result.
   if (R.isOverloadedResult() || R.isUnresolvableResult()) {
@@ -1209,11 +1200,8 @@
           if (DiagnoseUseOfDecl(PD, MemberLoc))
             return ExprError();
 
-          QualType T = PD->getType();
-          if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
-            T = getMessageSendResultType(BaseType, Getter, false, false);
-         
-          return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+          return Owned(new (Context) ObjCPropertyRefExpr(PD,
+                                                         Context.PseudoObjectTy,
                                                          VK_LValue,
                                                          OK_ObjCProperty,
                                                          MemberLoc, 
@@ -1231,16 +1219,10 @@
           if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, 
                                                      SetterSel, Context))
             SMD = dyn_cast<ObjCMethodDecl>(SDecl);
-          QualType PType = getMessageSendResultType(BaseType, OMD, false, 
-                                                    false);
           
-          ExprValueKind VK = VK_LValue;
-          if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
-            VK = VK_RValue;
-          ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
-          return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
-                                                         VK, OK,
+          return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD,
+                                                         Context.PseudoObjectTy,
+                                                         VK_LValue, OK_ObjCProperty,
                                                          MemberLoc, BaseExpr.take()));
         }
       }
@@ -1295,23 +1277,9 @@
         return ExprError();
 
       if (Getter || Setter) {
-        QualType PType;
-
-        ExprValueKind VK = VK_LValue;
-        if (Getter) {
-          PType = getMessageSendResultType(QualType(OT, 0), Getter, true, 
-                                           false);
-          if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
-            VK = VK_RValue;
-        } else {
-          // Get the expression type from Setter's incoming parameter.
-          PType = (*(Setter->param_end() -1))->getType();
-        }
-        ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
-        // FIXME: we must check that the setter has property type.
         return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
-                                                       PType, VK, OK,
+                                                       Context.PseudoObjectTy,
+                                                       VK_LValue, OK_ObjCProperty,
                                                        MemberLoc, BaseExpr.take()));
       }
 

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Tue Oct 25 02:27:56 2011
@@ -527,6 +527,35 @@
   return Method;
 }
 
+/// LookupMethodInType - Look up a method in an ObjCObjectType.
+ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type,
+                                               bool isInstance) {
+  const ObjCObjectType *objType = type->castAs<ObjCObjectType>();
+  if (ObjCInterfaceDecl *iface = objType->getInterface()) {
+    // Look it up in the main interface (and categories, etc.)
+    if (ObjCMethodDecl *method = iface->lookupMethod(sel, isInstance))
+      return method;
+
+    // Okay, look for "private" methods declared in any
+    // @implementations we've seen.
+    if (isInstance) {
+      if (ObjCMethodDecl *method = LookupPrivateInstanceMethod(sel, iface))
+        return method;
+    } else {
+      if (ObjCMethodDecl *method = LookupPrivateClassMethod(sel, iface))
+        return method;
+    }
+  }
+
+  // Check qualifiers.
+  for (ObjCObjectType::qual_iterator
+         i = objType->qual_begin(), e = objType->qual_end(); i != e; ++i)
+    if (ObjCMethodDecl *method = (*i)->lookupMethod(sel, isInstance))
+      return method;
+
+  return 0;
+}
+
 /// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier 
 /// list of a qualified objective pointer type.
 ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
@@ -575,23 +604,14 @@
     // Check whether we can reference this property.
     if (DiagnoseUseOfDecl(PD, MemberLoc))
       return ExprError();
-    QualType ResTy = PD->getType();
-    ResTy = ResTy.getNonLValueExprType(Context);
-    Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
-    ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
-    if (Getter &&
-        (Getter->hasRelatedResultType()
-         || DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)))
-        ResTy = getMessageSendResultType(QualType(OPT, 0), Getter, false, 
-                                         Super);
              
     if (Super)
-      return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
+      return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
                                                      VK_LValue, OK_ObjCProperty,
                                                      MemberLoc, 
                                                      SuperLoc, SuperType));
     else
-      return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
+      return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
                                                      VK_LValue, OK_ObjCProperty,
                                                      MemberLoc, BaseExpr));
   }
@@ -603,17 +623,16 @@
       if (DiagnoseUseOfDecl(PD, MemberLoc))
         return ExprError();
       
-      QualType T = PD->getType();
-      if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
-        T = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
       if (Super)
-        return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+        return Owned(new (Context) ObjCPropertyRefExpr(PD,
+                                                       Context.PseudoObjectTy,
                                                        VK_LValue,
                                                        OK_ObjCProperty,
                                                        MemberLoc, 
                                                        SuperLoc, SuperType));
       else
-        return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+        return Owned(new (Context) ObjCPropertyRefExpr(PD,
+                                                       Context.PseudoObjectTy,
                                                        VK_LValue,
                                                        OK_ObjCProperty,
                                                        MemberLoc,
@@ -668,28 +687,16 @@
     return ExprError();
 
   if (Getter || Setter) {
-    QualType PType;
-    if (Getter)
-      PType = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
-    else {
-      ParmVarDecl *ArgDecl = *Setter->param_begin();
-      PType = ArgDecl->getType().getUnqualifiedType(); // can't be an array
-    }
-    
-    ExprValueKind VK = VK_LValue;
-    ExprObjectKind OK = OK_ObjCProperty;
-    if (!getLangOptions().CPlusPlus && !PType.hasQualifiers() &&
-        PType->isVoidType())
-      VK = VK_RValue, OK = OK_Ordinary;
-
     if (Super)
       return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
-                                                     PType, VK, OK,
+                                                     Context.PseudoObjectTy,
+                                                     VK_LValue, OK_ObjCProperty,
                                                      MemberLoc,
                                                      SuperLoc, SuperType));
     else
       return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
-                                                     PType, VK, OK,
+                                                     Context.PseudoObjectTy,
+                                                     VK_LValue, OK_ObjCProperty,
                                                      MemberLoc, BaseExpr));
 
   }
@@ -825,34 +832,17 @@
     return ExprError();
 
   if (Getter || Setter) {
-    QualType PType;
-
-    ExprValueKind VK = VK_LValue;
-    if (Getter) {
-      PType = getMessageSendResultType(Context.getObjCInterfaceType(IFace),
-                                       Getter, true, 
-                                       receiverNamePtr->isStr("super"));
-      if (!getLangOptions().CPlusPlus &&
-          !PType.hasQualifiers() && PType->isVoidType())
-        VK = VK_RValue;
-    } else {
-      for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
-           E = Setter->param_end(); PI != E; ++PI)
-        PType = (*PI)->getType();
-      VK = VK_LValue;
-    }
-
-    ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
     if (IsSuper)
     return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
-                                                   PType, VK, OK,
+                                                   Context.PseudoObjectTy,
+                                                   VK_LValue, OK_ObjCProperty,
                                                    propertyNameLoc,
                                                    receiverNameLoc, 
                                           Context.getObjCInterfaceType(IFace)));
 
     return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
-                                                   PType, VK, OK,
+                                                   Context.PseudoObjectTy,
+                                                   VK_LValue, OK_ObjCProperty,
                                                    propertyNameLoc,
                                                    receiverNameLoc, IFace));
   }

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Oct 25 02:27:56 2011
@@ -3795,15 +3795,8 @@
   setSequenceKind(NormalSequence);
 
   for (unsigned I = 0; I != NumArgs; ++I)
-    if (Args[I]->getObjectKind() == OK_ObjCProperty) {
-      ExprResult Result = S.ConvertPropertyForRValue(Args[I]);
-      if (Result.isInvalid()) {
-        SetFailed(FK_ConversionFromPropertyFailed);
-        return;
-      }
-      Args[I] = Result.take();
-    } else if (const BuiltinType *PlaceholderTy
-                 = Args[I]->getType()->getAsPlaceholderType()) {
+    if (const BuiltinType *PlaceholderTy
+          = Args[I]->getType()->getAsPlaceholderType()) {
       // FIXME: should we be doing this here?
       if (PlaceholderTy->getKind() != BuiltinType::Overload) {
         ExprResult result = S.CheckPlaceholderExpr(Args[I]);
@@ -4493,13 +4486,6 @@
     assert(Args.size() == 1);
     CurInit = Args.get()[0];
     if (!CurInit.get()) return ExprError();
-
-    // Read from a property when initializing something with it.
-    if (CurInit.get()->getObjectKind() == OK_ObjCProperty) {
-      CurInit = S.ConvertPropertyForRValue(CurInit.take());
-      if (CurInit.isInvalid())
-        return ExprError();
-    }
     break;
   }
 

Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Tue Oct 25 02:27:56 2011
@@ -800,9 +800,7 @@
                                       SelfExpr, true, true);
       ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
       ParmVarDecl *Param = (*P);
-      QualType T = Param->getType();
-      if (T->isReferenceType())
-        T = T->getAs<ReferenceType>()->getPointeeType();
+      QualType T = Param->getType().getNonReferenceType();
       Expr *rhs = new (Context) DeclRefExpr(Param, T,
                                             VK_LValue, SourceLocation());
       ExprResult Res = BuildBinOp(S, lhs->getLocEnd(), 
@@ -954,8 +952,8 @@
                                             ObjCMethodDecl *GetterMethod,
                                             SourceLocation Loc) {
   if (GetterMethod &&
-      GetterMethod->getResultType().getNonReferenceType() 
-      != property->getType().getNonReferenceType()) {
+      !Context.hasSameType(GetterMethod->getResultType().getNonReferenceType(),
+                           property->getType().getNonReferenceType())) {
     AssignConvertType result = Incompatible;
     if (property->getType()->isObjCObjectPointerType())
       result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(),

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Oct 25 02:27:56 2011
@@ -575,17 +575,6 @@
 /// Return true on unrecoverable error.
 static bool checkPlaceholderForOverload(Sema &S, Expr *&E,
                                         UnbridgedCastsSet *unbridgedCasts = 0) {
-  // ObjCProperty l-values are placeholder-like.
-  if (E->getObjectKind() == OK_ObjCProperty) {
-    ExprResult result = S.ConvertPropertyForRValue(E);
-    if (result.isInvalid())
-      return true;
-
-    E = result.take();
-    return false;
-  }
-
-  // Handle true placeholders.
   if (const BuiltinType *placeholder =  E->getType()->getAsPlaceholderType()) {
     // We can't handle overloaded expressions here because overload
     // resolution might reasonably tweak them.
@@ -1003,6 +992,9 @@
 Sema::PerformImplicitConversion(Expr *From, QualType ToType,
                                 AssignmentAction Action, bool AllowExplicit,
                                 ImplicitConversionSequence& ICS) {
+  if (checkPlaceholderForOverload(*this, From))
+    return ExprError();
+
   // Objective-C ARC: Determine whether we will allow the writeback conversion.
   bool AllowObjCWritebackConversion
     = getLangOptions().ObjCAutoRefCount && 
@@ -4086,6 +4078,9 @@
 /// PerformContextuallyConvertToBool - Perform a contextual conversion
 /// of the expression From to bool (C++0x [conv]p3).
 ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) {
+  if (checkPlaceholderForOverload(*this, From))
+    return ExprError();
+
   ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From);
   if (!ICS.isBad())
     return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
@@ -4145,6 +4140,9 @@
 /// PerformContextuallyConvertToObjCPointer - Perform a contextual
 /// conversion of the expression From to an Objective-C pointer type.
 ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
+  if (checkPlaceholderForOverload(*this, From))
+    return ExprError();
+
   QualType Ty = Context.getObjCIdType();
   ImplicitConversionSequence ICS =
     TryContextuallyConvertToObjCPointer(*this, From);
@@ -9009,39 +9007,9 @@
   if (checkPlaceholderForOverload(*this, Args[1]))
     return ExprError();
 
-  // The LHS is more complicated.
-  if (Args[0]->getObjectKind() == OK_ObjCProperty) {
-
-    // There's a tension for assignment operators between primitive
-    // property assignment and the overloaded operators.
-    if (BinaryOperator::isAssignmentOp(Opc)) {
-      const ObjCPropertyRefExpr *PRE = LHS->getObjCProperty();
-
-      // Is the property "logically" settable?
-      bool Settable = (PRE->isExplicitProperty() ||
-                       PRE->getImplicitPropertySetter());
-
-      // To avoid gratuitously inventing semantics, use the primitive
-      // unless it isn't.  Thoughts in case we ever really care:
-      // - If the property isn't logically settable, we have to
-      //   load and hope.
-      // - If the property is settable and this is simple assignment,
-      //   we really should use the primitive.
-      // - If the property is settable, then we could try overloading
-      //   on a generic lvalue of the appropriate type;  if it works
-      //   out to a builtin candidate, we would do that same operation
-      //   on the property, and otherwise just error.
-      if (Settable)
-        return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
-    }
-
-    ExprResult Result = ConvertPropertyForRValue(Args[0]);
-    if (Result.isInvalid())
-      return ExprError();
-    Args[0] = Result.take();
-  }
-
-  // Handle all the other placeholders.
+  // Do placeholder-like conversion on the LHS; note that we should
+  // not get here with a PseudoObject LHS.
+  assert(Args[0]->getObjectKind() != OK_ObjCProperty);
   if (checkPlaceholderForOverload(*this, Args[0]))
     return ExprError();
 

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Oct 25 02:27:56 2011
@@ -492,6 +492,10 @@
   if (!Cond)
     return StmtError();
 
+  CondResult = CheckPlaceholderExpr(Cond);
+  if (CondResult.isInvalid())
+    return StmtError();
+
   CondResult
     = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond,
                           PDiag(diag::err_typecheck_statement_requires_integer),

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Oct 25 02:27:56 2011
@@ -2249,8 +2249,8 @@
   /// By default, performs semantic analysis to build the new expression.
   /// Subclasses may override this routine to provide different behavior.
   ExprResult RebuildObjCPropertyRefExpr(Expr *BaseArg, 
-                                              ObjCPropertyDecl *Property,
-                                              SourceLocation PropertyLoc) {
+                                        ObjCPropertyDecl *Property,
+                                        SourceLocation PropertyLoc) {
     CXXScopeSpec SS;
     ExprResult Base = getSema().Owned(BaseArg);
     LookupResult R(getSema(), Property->getDeclName(), PropertyLoc,
@@ -8049,7 +8049,7 @@
                                                    E->getLocation());
 
   return getDerived().RebuildObjCPropertyRefExpr(Base.get(),
-                                                 E->getType(),
+                                                 SemaRef.Context.PseudoObjectTy,
                                                  E->getImplicitPropertyGetter(),
                                                  E->getImplicitPropertySetter(),
                                                  E->getLocation());

Modified: cfe/trunk/lib/Serialization/ASTCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTCommon.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTCommon.cpp Tue Oct 25 02:27:56 2011
@@ -52,6 +52,7 @@
   case BuiltinType::Char32:     ID = PREDEF_TYPE_CHAR32_ID;     break;
   case BuiltinType::Overload:   ID = PREDEF_TYPE_OVERLOAD_ID;   break;
   case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER;  break;
+  case BuiltinType::PseudoObject:ID = PREDEF_TYPE_PSEUDO_OBJECT;break;
   case BuiltinType::Dependent:  ID = PREDEF_TYPE_DEPENDENT_ID;  break;
   case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY;   break;
   case BuiltinType::ARCUnbridgedCast:

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue Oct 25 02:27:56 2011
@@ -3857,6 +3857,7 @@
     case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy;       break;
     case PREDEF_TYPE_OVERLOAD_ID:   T = Context.OverloadTy;         break;
     case PREDEF_TYPE_BOUND_MEMBER:  T = Context.BoundMemberTy;      break;
+    case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy;     break;
     case PREDEF_TYPE_DEPENDENT_ID:  T = Context.DependentTy;        break;
     case PREDEF_TYPE_UNKNOWN_ANY:   T = Context.UnknownAnyTy;       break;
     case PREDEF_TYPE_NULLPTR_ID:    T = Context.NullPtrTy;          break;

Modified: cfe/trunk/test/SemaObjC/property-category-1.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-category-1.m?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-category-1.m (original)
+++ cfe/trunk/test/SemaObjC/property-category-1.m Tue Oct 25 02:27:56 2011
@@ -48,6 +48,6 @@
   
 @implementation I0	// expected-warning {{property 'p0' requires method 'p0' to be define}}
 - (void) foo {
-  self.p0 = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+  self.p0 = 0; // expected-error {{assignment to readonly property}}
 }
 @end

Modified: cfe/trunk/test/SemaObjC/property-error-readonly-assign.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-error-readonly-assign.m?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-error-readonly-assign.m (original)
+++ cfe/trunk/test/SemaObjC/property-error-readonly-assign.m Tue Oct 25 02:27:56 2011
@@ -13,9 +13,9 @@
 @end
 
 void f0(A *a, B* b) {
-  a.x = 10;  // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+  a.x = 10;  // expected-error {{assignment to readonly property}}
   a.ok = 20;
-  b.x = 10;  // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+  b.x = 10;  // expected-error {{no setter method 'setX:' for assignment to property}}
   b.ok = 20;
 }
 
@@ -39,6 +39,6 @@
 @implementation NSWindow (Category)
 -(void)methodToMakeClangCrash
 {
- self.frame =  NSMakeRect(); // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+ self.frame =  NSMakeRect(); // expected-error {{no setter method 'setFrame:' for assignment to property}}
 }
 @end

Modified: cfe/trunk/test/SemaObjC/property-in-class-extension.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-in-class-extension.m?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-in-class-extension.m (original)
+++ cfe/trunk/test/SemaObjC/property-in-class-extension.m Tue Oct 25 02:27:56 2011
@@ -9,7 +9,7 @@
 
 void FUNC () {
     Foo *foo;
-    foo.bar = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+    foo.bar = 0; // expected-error {{assignment to readonly property}}
 }
 
 // rdar://8747333

Modified: cfe/trunk/test/SemaObjC/property-user-setter.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-user-setter.m?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-user-setter.m (original)
+++ cfe/trunk/test/SemaObjC/property-user-setter.m Tue Oct 25 02:27:56 2011
@@ -20,7 +20,7 @@
 -(void) im0 {
   self.x = 0;
   self.y = 2;
-  self.z = 2; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+  self.z = 2; // expected-error {{assignment to readonly property}}
 }
 @end
 
@@ -85,7 +85,7 @@
 - (void)setFoo:(int)value;
 @end
 
-void g(int);
+void g(int); // expected-note {{passing argument to parameter here}}
 
 void f(C *c) {
     c.Foo = 17; // OK 

Modified: cfe/trunk/test/SemaObjCXX/propert-dot-error.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/propert-dot-error.mm?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/propert-dot-error.mm (original)
+++ cfe/trunk/test/SemaObjCXX/propert-dot-error.mm Tue Oct 25 02:27:56 2011
@@ -20,7 +20,7 @@
 @end
 
 void f(A* a) {
-  a.x = X(); // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+  a.x = X(); // expected-error {{no setter method 'setX:' for assignment to property}}
 }
 
 struct Y : X { };





More information about the cfe-commits mailing list