]> granicus.if.org Git - clang/commitdiff
Change the AST representation of operations on Objective-C
authorJohn McCall <rjmccall@apple.com>
Sun, 6 Nov 2011 09:01:30 +0000 (09:01 +0000)
committerJohn McCall <rjmccall@apple.com>
Sun, 6 Nov 2011 09:01:30 +0000 (09:01 +0000)
property references to use a new PseudoObjectExpr
expression which pairs a syntactic form of the expression
with a set of semantic expressions implementing it.
This should significantly reduce the complexity required
elsewhere in the compiler to deal with these kinds of
expressions (e.g. IR generation's special l-value kind,
the static analyzer's Message abstraction), at the lower
cost of specifically dealing with the odd AST structure
of these expressions.  It should also greatly simplify
efforts to implement similar language features in the
future, most notably Managed C++'s properties and indexed
properties.

Most of the effort here is in dealing with the various
clients of the AST.  I've gone ahead and simplified the
ObjC rewriter's use of properties;  other clients, like
IR-gen and the static analyzer, have all the old
complexity *and* all the new complexity, at least
temporarily.  Many thanks to Ted for writing and advising
on the necessary changes to the static analyzer.

I've xfailed a small diagnostics regression in the static
analyzer at Ted's request.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143867 91177308-0d34-0410-b5e6-96231b3b80d8

40 files changed:
include/clang/AST/DeclBase.h
include/clang/AST/Expr.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/Stmt.h
include/clang/Basic/StmtNodes.td
include/clang/Serialization/ASTBitCodes.h
lib/ARCMigrate/TransRetainReleaseDealloc.cpp
lib/ARCMigrate/TransUnbridgedCasts.cpp
lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
lib/AST/DeclBase.cpp
lib/AST/Expr.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtDumper.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/Analysis/CFG.cpp
lib/Analysis/LiveVariables.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CGObjC.cpp
lib/CodeGen/CGValue.h
lib/CodeGen/CodeGenFunction.h
lib/Rewrite/RewriteObjC.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/SemaPseudoObject.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/casts.m
test/Analysis/retain-release-path-notes.m
tools/libclang/CIndex.cpp
tools/libclang/CXCursor.cpp

index 37a9f072af9cfb9541908d91c72e47272e447438..5d95cc81c75800b18b132c793faf8e5572f2fd53 100644 (file)
@@ -974,6 +974,14 @@ public:
   /// declaration context DC.
   bool Encloses(const DeclContext *DC) const;
 
+  /// \brief Find the nearest non-closure ancestor of this context,
+  /// i.e. the innermost semantic parent of this context which is not
+  /// a closure.  A context may be its own non-closure ancestor.
+  DeclContext *getNonClosureAncestor();
+  const DeclContext *getNonClosureAncestor() const {
+    return const_cast<DeclContext*>(this)->getNonClosureAncestor();
+  }
+
   /// getPrimaryContext - There may be many different
   /// declarations of the same entity (including forward declarations
   /// of classes, multiple definitions of namespaces, etc.), each with
index fd88e1e88e0395b7dbb26642b6442460cc578735..3ea590cd84b1df9e1acb5808d10e23607734670b 100644 (file)
@@ -2758,6 +2758,13 @@ public:
   bool isCompoundAssignmentOp() const {
     return isCompoundAssignmentOp(getOpcode());
   }
+  static Opcode getOpForCompoundAssignment(Opcode Opc) {
+    assert(isCompoundAssignmentOp(Opc));
+    if (Opc >= BO_XorAssign)
+      return Opcode(unsigned(Opc) - BO_XorAssign + BO_Xor);
+    else
+      return Opcode(unsigned(Opc) - BO_MulAssign + BO_Mul);
+  }
 
   static bool isShiftAssignOp(Opcode Opc) {
     return Opc == BO_ShlAssign || Opc == BO_ShrAssign;
@@ -4251,6 +4258,140 @@ public:
   child_range children() { return child_range(&SrcExpr, &SrcExpr+1); }
 };
 
+/// PseudoObjectExpr - An expression which accesses a pseudo-object
+/// l-value.  A pseudo-object is an abstract object, accesses to which
+/// are translated to calls.  The pseudo-object expression has a
+/// syntactic form, which shows how the expression was actually
+/// written in the source code, and a semantic form, which is a series
+/// of expressions to be executed in order which detail how the
+/// operation is actually evaluated.  Optionally, one of the semantic
+/// forms may also provide a result value for the expression.
+///
+/// If any of the semantic-form expressions is an OpaqueValueExpr,
+/// that OVE is required to have a source expression, and it is bound
+/// to the result of that source expression.  Such OVEs may appear
+/// only in subsequent semantic-form expressions and as
+/// sub-expressions of the syntactic form.
+///
+/// PseudoObjectExpr should be used only when an operation can be
+/// usefully described in terms of fairly simple rewrite rules on
+/// objects and functions that are meant to be used by end-developers.
+/// For example, under the Itanium ABI, dynamic casts are implemented
+/// as a call to a runtime function called __dynamic_cast; using this
+/// class to describe that would be inappropriate because that call is
+/// not really part of the user-visible semantics, and instead the
+/// cast is properly reflected in the AST and IR-generation has been
+/// taught to generate the call as necessary.  In contrast, an
+/// Objective-C property access is semantically defined to be
+/// equivalent to a particular message send, and this is very much
+/// part of the user model.  The name of this class encourages this
+/// modelling design.
+class PseudoObjectExpr : public Expr {
+  // PseudoObjectExprBits.NumSubExprs - The number of sub-expressions.
+  // Always at least two, because the first sub-expression is the
+  // syntactic form.
+
+  // PseudoObjectExprBits.ResultIndex - The index of the
+  // sub-expression holding the result.  0 means the result is void,
+  // which is unambiguous because it's the index of the syntactic
+  // form.  Note that this is therefore 1 higher than the value passed
+  // in to Create, which is an index within the semantic forms.
+  // Note also that ASTStmtWriter assumes this encoding.
+
+  Expr **getSubExprsBuffer() { return reinterpret_cast<Expr**>(this + 1); }
+  const Expr * const *getSubExprsBuffer() const {
+    return reinterpret_cast<const Expr * const *>(this + 1);
+  }
+
+  friend class ASTStmtReader;
+
+  PseudoObjectExpr(QualType type, ExprValueKind VK,
+                   Expr *syntactic, ArrayRef<Expr*> semantic,
+                   unsigned resultIndex);
+
+  PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs);
+
+  unsigned getNumSubExprs() const {
+    return PseudoObjectExprBits.NumSubExprs;
+  }
+
+public:
+  /// NoResult - A value for the result index indicating that there is
+  /// no semantic result.
+  enum { NoResult = ~0U };
+
+  static PseudoObjectExpr *Create(ASTContext &Context, Expr *syntactic,
+                                  ArrayRef<Expr*> semantic,
+                                  unsigned resultIndex);
+
+  static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell,
+                                  unsigned numSemanticExprs);
+
+  /// Return the syntactic form of this expression, i.e. the
+  /// expression it actually looks like.  Likely to be expressed in
+  /// terms of OpaqueValueExprs bound in the semantic form.
+  Expr *getSyntacticForm() { return getSubExprsBuffer()[0]; }
+  const Expr *getSyntacticForm() const { return getSubExprsBuffer()[0]; }
+
+  /// Return the index of the result-bearing expression into the semantics
+  /// expressions, or PseudoObjectExpr::NoResult if there is none.
+  unsigned getResultExprIndex() const {
+    if (PseudoObjectExprBits.ResultIndex == 0) return NoResult;
+    return PseudoObjectExprBits.ResultIndex - 1;
+  }
+
+  /// Return the result-bearing expression, or null if there is none.
+  Expr *getResultExpr() {
+    if (PseudoObjectExprBits.ResultIndex == 0)
+      return 0;
+    return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex];
+  }
+  const Expr *getResultExpr() const {
+    return const_cast<PseudoObjectExpr*>(this)->getResultExpr();
+  }
+
+  unsigned getNumSemanticExprs() const { return getNumSubExprs() - 1; }
+
+  typedef Expr * const *semantics_iterator;
+  typedef const Expr * const *const_semantics_iterator;
+  semantics_iterator semantics_begin() {
+    return getSubExprsBuffer() + 1;
+  }
+  const_semantics_iterator semantics_begin() const {
+    return getSubExprsBuffer() + 1;
+  }
+  semantics_iterator semantics_end() {
+    return getSubExprsBuffer() + getNumSubExprs();
+  }
+  const_semantics_iterator semantics_end() const {
+    return getSubExprsBuffer() + getNumSubExprs();
+  }
+  Expr *getSemanticExpr(unsigned index) {
+    assert(index + 1 < getNumSubExprs());
+    return getSubExprsBuffer()[index + 1];
+  }
+  const Expr *getSemanticExpr(unsigned index) const {
+    return const_cast<PseudoObjectExpr*>(this)->getSemanticExpr(index);
+  }
+
+  SourceLocation getExprLoc() const {
+    return getSyntacticForm()->getExprLoc();
+  }
+  SourceRange getSourceRange() const {
+    return getSyntacticForm()->getSourceRange();
+  }
+
+  child_range children() {
+    Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer());
+    return child_range(cs, cs + getNumSubExprs());
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == PseudoObjectExprClass;
+  }
+  static bool classof(const PseudoObjectExpr *) { return true; }
+};
+
 /// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*,
 /// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the
 /// similarly-named C++0x instructions.  All of these instructions take one
index 9b65063d35ab431fe9e77bdc31c6517426e8d4ec..409f83019ff347d9653277a8c8c6d63161360c40 100644 (file)
@@ -1874,6 +1874,23 @@ TraverseGenericSelectionExpr(GenericSelectionExpr *S) {
   return true;
 }
 
+// PseudoObjectExpr is a special case because of the wierdness with
+// syntactic expressions and opaque values.
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::
+TraversePseudoObjectExpr(PseudoObjectExpr *S) {
+  TRY_TO(WalkUpFromPseudoObjectExpr(S));
+  TRY_TO(TraverseStmt(S->getSyntacticForm()));
+  for (PseudoObjectExpr::semantics_iterator
+         i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) {
+    Expr *sub = *i;
+    if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub))
+      sub = OVE->getSourceExpr();
+    TRY_TO(TraverseStmt(sub));
+  }
+  return true;
+}
+
 DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
     // This is called for code like 'return T()' where T is a built-in
     // (i.e. non-class) type.
index 8840719413d52a3ea05c93ce620498f30ad9af91..83836b717b259b7fb85f509a51a6759406389842 100644 (file)
@@ -146,6 +146,7 @@ protected:
     friend class CXXUnresolvedConstructExpr; // ctor
     friend class CXXDependentScopeMemberExpr; // ctor
     friend class OverloadExpr; // ctor
+    friend class PseudoObjectExpr; // ctor
     friend class AtomicExpr; // ctor
     unsigned : NumStmtBits;
 
@@ -184,6 +185,18 @@ protected:
     unsigned NumPreArgs : 1;
   };
 
+  class PseudoObjectExprBitfields {
+    friend class PseudoObjectExpr;
+    friend class ASTStmtReader; // deserialization
+
+    unsigned : NumExprBits;
+
+    // These don't need to be particularly wide, because they're
+    // strictly limited by the forms of expressions we permit.
+    unsigned NumSubExprs : 8;
+    unsigned ResultIndex : 32 - 8 - NumExprBits;
+  };
+
   class ObjCIndirectCopyRestoreExprBitfields {
     friend class ObjCIndirectCopyRestoreExpr;
     unsigned : NumExprBits;
@@ -201,6 +214,7 @@ protected:
     DeclRefExprBitfields DeclRefExprBits;
     CastExprBitfields CastExprBits;
     CallExprBitfields CallExprBits;
+    PseudoObjectExprBitfields PseudoObjectExprBits;
     ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits;
   };
 
index 02aec8cfef505ebc40e733776d0657a1fb520fe1..6bb38d0ce7da782c8f8f72692f38c595c35edfac 100644 (file)
@@ -77,6 +77,7 @@ def ImplicitValueInitExpr : DStmt<Expr>;
 def ParenListExpr : DStmt<Expr>;
 def VAArgExpr : DStmt<Expr>;
 def GenericSelectionExpr : DStmt<Expr>;
+def PseudoObjectExpr : DStmt<Expr>;
 
 // Atomic expressions
 def AtomicExpr : DStmt<Expr>;
index 982c31d2932fd50a171b8e9b1cf858f68cf74dce..fc97d2904631e78ca1f7abe261a2df29717281f9 100644 (file)
@@ -1000,6 +1000,8 @@ namespace clang {
       EXPR_BLOCK_DECL_REF,
       /// \brief A GenericSelectionExpr record.
       EXPR_GENERIC_SELECTION,
+      /// \brief A PseudoObjectExpr record.
+      EXPR_PSEUDO_OBJECT,
       /// \brief An AtomicExpr record.
       EXPR_ATOMIC,
 
index bf2517f1198142cab2f72b3113dd8da61aa18cc4..6eb82093cf892e0bf1b4310836d037079ff737a8 100644 (file)
@@ -160,12 +160,14 @@ private:
     if (!E) return false;
 
     E = E->IgnoreParenCasts();
+
+    // Also look through property-getter sugar.
+    if (PseudoObjectExpr *pseudoOp = dyn_cast<PseudoObjectExpr>(E))
+      E = pseudoOp->getResultExpr()->IgnoreImplicit();
+
     if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E))
       return (ME->isInstanceMessage() && ME->getSelector() == DelegateSel);
 
-    if (ObjCPropertyRefExpr *propE = dyn_cast<ObjCPropertyRefExpr>(E))
-      return propE->getGetterSelector() == DelegateSel;
-
     return false;
   }
 
index 69fb2e8949e419376d972009561ea3de15293534..3bfa15c6e0ae1726809304a65e32ef4f72c23b6a 100644 (file)
@@ -236,7 +236,15 @@ private:
       }
     }
 
-    if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getSubExpr())){
+    Expr *subExpr = E->getSubExpr();
+
+    // Look through pseudo-object expressions.
+    if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(subExpr)) {
+      subExpr = pseudo->getResultExpr();
+      assert(subExpr && "no result for pseudo-object of non-void type?");
+    }
+
+    if (ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(subExpr)) {
       if (implCE->getCastKind() == CK_ARCConsumeObject)
         return rewriteToBridgedCast(E, OBC_BridgeRetained);
       if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
index 7c533bcf3a09f91dfa78a70abe97c085fac45f91..d1f08aac28c2162d8e01b53c1570a2892a2519b1 100644 (file)
@@ -78,6 +78,15 @@ public:
     return true;
   }
 
+  bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) {
+    if (isZeroingPropIvar(POE) && isRemovable(POE)) {
+      Transaction Trans(Pass.TA);
+      Pass.TA.removeStmt(POE);
+    }
+
+    return true;
+  }
+
   bool VisitBinaryOperator(BinaryOperator *BOE) {
     if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {
       Transaction Trans(Pass.TA);
@@ -142,17 +151,21 @@ private:
   }
 
   bool isZeroingPropIvar(Expr *E) {
-    BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E);
-    if (!BOE) return false;
+    E = E->IgnoreParens();
+    if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E))
+      return isZeroingPropIvar(BO);
+    if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E))
+      return isZeroingPropIvar(PO);
+    return false;
+  }
 
+  bool isZeroingPropIvar(BinaryOperator *BOE) {
     if (BOE->getOpcode() == BO_Comma)
       return isZeroingPropIvar(BOE->getLHS()) &&
              isZeroingPropIvar(BOE->getRHS());
 
     if (BOE->getOpcode() != BO_Assign)
-        return false;
-
-    ASTContext &Ctx = Pass.Ctx;
+      return false;
 
     Expr *LHS = BOE->getLHS();
     if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {
@@ -172,25 +185,38 @@ private:
       if (!IvarBacksPropertySynthesis)
         return false;
     }
-    else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
-      // TODO: Using implicit property decl.
-      if (PropRefExp->isImplicitProperty())
-        return false;
-      if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
-        if (!SynthesizedProperties.count(PDecl))
-          return false;
-      }
-    }
     else
         return false;
 
-    Expr *RHS = BOE->getRHS();
-    bool RHSIsNull = RHS->isNullPointerConstant(Ctx,
-                                                Expr::NPC_ValueDependentIsNull);
-    if (RHSIsNull)
+    return isZero(BOE->getRHS());
+  }
+
+  bool isZeroingPropIvar(PseudoObjectExpr *PO) {
+    BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm());
+    if (!BO) return false;
+    if (BO->getOpcode() != BO_Assign) return false;
+
+    ObjCPropertyRefExpr *PropRefExp =
+      dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens());
+    if (!PropRefExp) return false;
+
+    // TODO: Using implicit property decl.
+    if (PropRefExp->isImplicitProperty())
+      return false;
+
+    if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
+      if (!SynthesizedProperties.count(PDecl))
+        return false;
+    }
+
+    return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr());
+  }
+
+  bool isZero(Expr *E) {
+    if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull))
       return true;
 
-    return isZeroingPropIvar(RHS);
+    return isZeroingPropIvar(E);
   }
 };
 
index a4daea228725b0aaba6678e57f3350c678c190c5..4c31bbd3d7620b40a2ef5323baf02b4d4fa69455 100644 (file)
@@ -640,7 +640,11 @@ void Decl::CheckAccessDeclContext() const {
 }
 
 DeclContext *Decl::getNonClosureContext() {
-  DeclContext *DC = getDeclContext();
+  return getDeclContext()->getNonClosureAncestor();
+}
+
+DeclContext *DeclContext::getNonClosureAncestor() {
+  DeclContext *DC = this;
 
   // This is basically "while (DC->isClosure()) DC = DC->getParent();"
   // except that it's significantly more efficient to cast to a known
index 323997368879800fc06f6e8edb63ebc7f2f9554a..6eb6116b01b6d75b7c0d37518141f8ab224ead2a 100644 (file)
@@ -1694,6 +1694,19 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
     R1 = getSourceRange();
     return true;
 
+  case PseudoObjectExprClass: {
+    const PseudoObjectExpr *PO = cast<PseudoObjectExpr>(this);
+
+    // Only complain about things that have the form of a getter.
+    if (isa<UnaryOperator>(PO->getSyntacticForm()) ||
+        isa<BinaryOperator>(PO->getSyntacticForm()))
+      return false;
+
+    Loc = getExprLoc();
+    R1 = getSourceRange();
+    return true;
+  }
+
   case StmtExprClass: {
     // Statement exprs don't logically have side effects themselves, but are
     // sometimes used in macros in ways that give them a type that is unused.
@@ -2598,6 +2611,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
   } else if (const MaterializeTemporaryExpr *M 
                                    = dyn_cast<MaterializeTemporaryExpr>(this)) {
     return M->GetTemporaryExpr()->isNullPointerConstant(Ctx, NPC);
+  } else if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(this)) {
+    if (const Expr *Source = OVE->getSourceExpr())
+      return Source->isNullPointerConstant(Ctx, NPC);
   }
 
   // C++0x nullptr_t is always a null pointer constant.
@@ -3306,6 +3322,72 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
   return cast<OpaqueValueExpr>(e);
 }
 
+PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &Context, EmptyShell sh,
+                                           unsigned numSemanticExprs) {
+  void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) +
+                                    (1 + numSemanticExprs) * sizeof(Expr*),
+                                  llvm::alignOf<PseudoObjectExpr>());
+  return new(buffer) PseudoObjectExpr(sh, numSemanticExprs);
+}
+
+PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
+  : Expr(PseudoObjectExprClass, shell) {
+  PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
+}
+
+PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &C, Expr *syntax,
+                                           ArrayRef<Expr*> semantics,
+                                           unsigned resultIndex) {
+  assert(syntax && "no syntactic expression!");
+  assert(semantics.size() && "no semantic expressions!");
+
+  QualType type;
+  ExprValueKind VK;
+  if (resultIndex == NoResult) {
+    type = C.VoidTy;
+    VK = VK_RValue;
+  } else {
+    assert(resultIndex < semantics.size());
+    type = semantics[resultIndex]->getType();
+    VK = semantics[resultIndex]->getValueKind();
+    assert(semantics[resultIndex]->getObjectKind() == OK_Ordinary);
+  }
+
+  void *buffer = C.Allocate(sizeof(PseudoObjectExpr) +
+                              (1 + semantics.size()) * sizeof(Expr*),
+                            llvm::alignOf<PseudoObjectExpr>());
+  return new(buffer) PseudoObjectExpr(type, VK, syntax, semantics,
+                                      resultIndex);
+}
+
+PseudoObjectExpr::PseudoObjectExpr(QualType type, ExprValueKind VK,
+                                   Expr *syntax, ArrayRef<Expr*> semantics,
+                                   unsigned resultIndex)
+  : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary,
+         /*filled in at end of ctor*/ false, false, false, false) {
+  PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;
+  PseudoObjectExprBits.ResultIndex = resultIndex + 1;
+
+  for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {
+    Expr *E = (i == 0 ? syntax : semantics[i-1]);
+    getSubExprsBuffer()[i] = E;
+
+    if (E->isTypeDependent())
+      ExprBits.TypeDependent = true;
+    if (E->isValueDependent())
+      ExprBits.ValueDependent = true;
+    if (E->isInstantiationDependent())
+      ExprBits.InstantiationDependent = true;
+    if (E->containsUnexpandedParameterPack())
+      ExprBits.ContainsUnexpandedParameterPack = true;
+
+    if (isa<OpaqueValueExpr>(E))
+      assert(cast<OpaqueValueExpr>(E)->getSourceExpr() != 0 &&
+             "opaque-value semantic expressions for pseudo-object "
+             "operations must have sources");
+  }
+}
+
 //===----------------------------------------------------------------------===//
 //  ExprIterator.
 //===----------------------------------------------------------------------===//
index 594ae69ec40584d244bfb1eccf6196f0ff1742b5..1251b96fbac3ddb450ec8b0d26d082e0a758ac8d 100644 (file)
@@ -232,6 +232,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
     return ClassifyExprValueKind(Lang, E,
                                  cast<OpaqueValueExpr>(E)->getValueKind());
 
+    // Pseudo-object expressions can produce l-values with reference magic.
+  case Expr::PseudoObjectExprClass:
+    return ClassifyExprValueKind(Lang, E,
+                                 cast<PseudoObjectExpr>(E)->getValueKind());
+
     // Implicit casts are lvalues if they're lvalue casts. Other than that, we
     // only specifically record class temporaries.
   case Expr::ImplicitCastExprClass:
index 3011b7f25fad51bb4ddc48006185968a944271e9..9c9e473f7b5af460bd0a5f3ab72d85f8cc8ed111 100644 (file)
@@ -3450,6 +3450,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
   case Expr::AsTypeExprClass:
   case Expr::ObjCIndirectCopyRestoreExprClass:
   case Expr::MaterializeTemporaryExprClass:
+  case Expr::PseudoObjectExprClass:
   case Expr::AtomicExprClass:
     return ICEDiag(2, E->getLocStart());
 
index 889cf513bba3e1ff1b635002d3667512f65a4b03..b2e1d20ca0122c0f52647485e26413b9a3a28e3b 100644 (file)
@@ -2257,6 +2257,7 @@ recurse:
   case Expr::CXXNoexceptExprClass:
   case Expr::CUDAKernelCallExprClass:
   case Expr::AsTypeExprClass:
+  case Expr::PseudoObjectExprClass:
   case Expr::AtomicExprClass:
   {
     // As bad as this diagnostic is, it's better than crashing.
index 54e62fe35b2ace1641310d937d3467ce059dc027..224834319984b7658de72fb82025f3741bedbd7b 100644 (file)
@@ -148,6 +148,7 @@ namespace  {
     void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
     void VisitAddrLabelExpr(AddrLabelExpr *Node);
     void VisitBlockExpr(BlockExpr *Node);
+    void VisitOpaqueValueExpr(OpaqueValueExpr *Node);
 
     // C++
     void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
@@ -524,6 +525,15 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
   DumpSubTree(block->getBody());
 }
 
+void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
+  DumpExpr(Node);
+
+  if (Expr *Source = Node->getSourceExpr()) {
+    OS << '\n';
+    DumpSubTree(Source);
+  }
+}
+
 // GNU extensions.
 
 void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
index 5b1654c92402167bc62d0c3213cef0c7e66785c8..04617bf9ac8c3d3c2c6d2a14b0c4959451d19809 100644 (file)
@@ -1027,6 +1027,10 @@ void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
   OS << ")";
 }
 
+void StmtPrinter::VisitPseudoObjectExpr(PseudoObjectExpr *Node) {
+  PrintExpr(Node->getSyntacticForm());
+}
+
 void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) {
   const char *Name = 0;
   switch (Node->getOp()) {
index db97e59804e37f3ebb2126e51eb5342d94b2e133..5a6b771b9a8e6462e0a3980afb00c9ff7e94a01b 100644 (file)
@@ -475,6 +475,15 @@ void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
   }
 }
 
+void StmtProfiler::VisitPseudoObjectExpr(const PseudoObjectExpr *S) {
+  VisitExpr(S);
+  for (PseudoObjectExpr::const_semantics_iterator
+         i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i)
+    // Normally, we would not profile the source expressions of OVEs.
+    if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(*i))
+      Visit(OVE->getSourceExpr());
+}
+
 void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {
   VisitExpr(S);
   ID.AddInteger(S->getOp());
index 48888f672ea2b9d9679a15614655586091921e45..73879214f3434a59089ecc518deca5af3fdb916d 100644 (file)
@@ -344,6 +344,7 @@ private:
   CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S);
   CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S);
   CFGBlock *VisitReturnStmt(ReturnStmt *R);
+  CFGBlock *VisitPseudoObjectExpr(PseudoObjectExpr *E);
   CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E,
                                           AddStmtChoice asc);
   CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc);
@@ -981,6 +982,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
     case Stmt::OpaqueValueExprClass:
       return Block;
 
+    case Stmt::PseudoObjectExprClass:
+      return VisitPseudoObjectExpr(cast<PseudoObjectExpr>(S));
+
     case Stmt::ReturnStmtClass:
       return VisitReturnStmt(cast<ReturnStmt>(S));
 
@@ -1907,6 +1911,31 @@ CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *S) {
   return NYS();
 }
 
+CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+  autoCreateBlock();
+
+  // Add the PseudoObject as the last thing.
+  appendStmt(Block, E);
+
+  CFGBlock *lastBlock = Block;  
+
+  // Before that, evaluate all of the semantics in order.  In
+  // CFG-land, that means appending them in reverse order.
+  for (unsigned i = E->getNumSemanticExprs(); i != 0; ) {
+    Expr *Semantic = E->getSemanticExpr(--i);
+
+    // If the semantic is an opaque value, we're being asked to bind
+    // it to its source expression.
+    if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Semantic))
+      Semantic = OVE->getSourceExpr();
+
+    if (CFGBlock *B = Visit(Semantic))
+      lastBlock = B;
+  }
+
+  return lastBlock;
+}
+
 CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
   CFGBlock *LoopSuccessor = NULL;
 
index cd6f09f2a744863cad9bfc935301bd8a5a76ba55..f0dbc532b2e129267c02524fde3d923a693576e0 100644 (file)
@@ -288,6 +288,18 @@ void TransferFunctions::Visit(Stmt *S) {
       }
       break;
     }
+    case Stmt::PseudoObjectExprClass: {
+      // A pseudo-object operation only directly consumes its result
+      // expression.
+      Expr *child = cast<PseudoObjectExpr>(S)->getResultExpr();
+      if (!child) return;
+      if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(child))
+        child = OV->getSourceExpr();
+      child = child->IgnoreParens();
+      val.liveStmts = LV.SSetFact.add(val.liveStmts, child);
+      return;
+    }
+
     // FIXME: These cases eventually shouldn't be needed.
     case Stmt::ExprWithCleanupsClass: {
       S = cast<ExprWithCleanups>(S)->getSubExpr();
index 9ad3ae8352eaee740c6d070d9296125030391d49..d7371141f328dd855227c7ca42ca8ddafb3554e0 100644 (file)
@@ -672,6 +672,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
     return EmitStringLiteralLValue(cast<StringLiteral>(E));
   case Expr::ObjCEncodeExprClass:
     return EmitObjCEncodeExprLValue(cast<ObjCEncodeExpr>(E));
+  case Expr::PseudoObjectExprClass:
+    return EmitPseudoObjectLValue(cast<PseudoObjectExpr>(E));
 
   case Expr::BlockDeclRefExprClass:
     return EmitBlockDeclRefLValue(cast<BlockDeclRefExpr>(E));
@@ -2768,3 +2770,86 @@ void CodeGenFunction::SetFPAccuracy(llvm::Value *Val, unsigned AccuracyN,
   cast<llvm::Instruction>(Val)->setMetadata(llvm::LLVMContext::MD_fpaccuracy,
                                             Node);
 }
+
+namespace {
+  struct LValueOrRValue {
+    LValue LV;
+    RValue RV;
+  };
+}
+
+static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
+                                           const PseudoObjectExpr *E,
+                                           bool forLValue,
+                                           AggValueSlot slot) {
+  llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
+
+  // Find the result expression, if any.
+  const Expr *resultExpr = E->getResultExpr();
+  LValueOrRValue result;
+
+  for (PseudoObjectExpr::const_semantics_iterator
+         i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
+    const Expr *semantic = *i;
+
+    // If this semantic expression is an opaque value, bind it
+    // to the result of its source expression.
+    if (const OpaqueValueExpr *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
+
+      // If this is the result expression, we may need to evaluate
+      // directly into the slot.
+      typedef CodeGenFunction::OpaqueValueMappingData OVMA;
+      OVMA opaqueData;
+      if (ov == resultExpr && ov->isRValue() && !forLValue &&
+          CodeGenFunction::hasAggregateLLVMType(ov->getType()) &&
+          !ov->getType()->isAnyComplexType()) {
+        CGF.EmitAggExpr(ov->getSourceExpr(), slot);
+
+        LValue LV = CGF.MakeAddrLValue(slot.getAddr(), ov->getType());
+        opaqueData = OVMA::bind(CGF, ov, LV);
+        result.RV = slot.asRValue();
+
+      // Otherwise, emit as normal.
+      } else {
+        opaqueData = OVMA::bind(CGF, ov, ov->getSourceExpr());
+
+        // If this is the result, also evaluate the result now.
+        if (ov == resultExpr) {
+          if (forLValue)
+            result.LV = CGF.EmitLValue(ov);
+          else
+            result.RV = CGF.EmitAnyExpr(ov, slot);
+        }
+      }
+
+      opaques.push_back(opaqueData);
+
+    // Otherwise, if the expression is the result, evaluate it
+    // and remember the result.
+    } else if (semantic == resultExpr) {
+      if (forLValue)
+        result.LV = CGF.EmitLValue(semantic);
+      else
+        result.RV = CGF.EmitAnyExpr(semantic, slot);
+
+    // Otherwise, evaluate the expression in an ignored context.
+    } else {
+      CGF.EmitIgnoredExpr(semantic);
+    }
+  }
+
+  // Unbind all the opaques now.
+  for (unsigned i = 0, e = opaques.size(); i != e; ++i)
+    opaques[i].unbind(CGF);
+
+  return result;
+}
+
+RValue CodeGenFunction::EmitPseudoObjectRValue(const PseudoObjectExpr *E,
+                                               AggValueSlot slot) {
+  return emitPseudoObjectExpr(*this, E, false, slot).RV;
+}
+
+LValue CodeGenFunction::EmitPseudoObjectLValue(const PseudoObjectExpr *E) {
+  return emitPseudoObjectExpr(*this, E, true, AggValueSlot::ignored()).LV;
+}
index 0fa143391d6b37afd3280799d2550a3199b8e584..ffbc2e0732f5efe3f1493843f7e0bc483f3c592a 100644 (file)
@@ -148,6 +148,15 @@ public:
   void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E);
   void VisitOpaqueValueExpr(OpaqueValueExpr *E);
 
+  void VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+    if (E->isGLValue()) {
+      LValue LV = CGF.EmitPseudoObjectLValue(E);
+      return EmitFinalDestCopy(E, LV);
+    }
+
+    CGF.EmitPseudoObjectRValue(E, EnsureSlot(E->getType()));
+  }
+
   void VisitVAArgExpr(VAArgExpr *E);
 
   void EmitInitializationToLValue(Expr *E, LValue Address);
index b6c416bc35546532f5994c08f7771852e673ecbf..c09278c14ed36f4c26b358bd8e1c449cc908a55e 100644 (file)
@@ -137,6 +137,10 @@ public:
     return CGF.getOpaqueRValueMapping(E).getComplexVal();
   }
 
+  ComplexPairTy VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+    return CGF.EmitPseudoObjectRValue(E).getComplexVal();
+  }
+
   // FIXME: CompoundLiteralExpr
 
   ComplexPairTy EmitCast(CastExpr::CastKind CK, Expr *Op, QualType DestTy);
index 50c5057f3ebb16370e6add9f12086e6d6887ec8e..83ca159aa5b0832c6f9148f7702d571a47f70aba 100644 (file)
@@ -197,6 +197,10 @@ public:
     return llvm::ConstantInt::get(ConvertType(E->getType()),E->getPackLength());
   }
 
+  Value *VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+    return CGF.EmitPseudoObjectRValue(E).getScalarVal();
+  }
+
   Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) {
     if (E->isGLValue())
       return EmitLoadOfLValue(CGF.getOpaqueLValueMapping(E));
index 0cd98ee319b32f02d727b1b73afbd5ec2ba4d65f..f164103723dd8291060a6b5eaee0df88a9a660e2 100644 (file)
@@ -2231,6 +2231,59 @@ static bool shouldEmitSeparateBlockRetain(const Expr *e) {
   return true;
 }
 
+/// Try to emit a PseudoObjectExpr at +1.
+///
+/// This massively duplicates emitPseudoObjectRValue.
+static TryEmitResult tryEmitARCRetainPseudoObject(CodeGenFunction &CGF,
+                                                  const PseudoObjectExpr *E) {
+  llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
+
+  // Find the result expression.
+  const Expr *resultExpr = E->getResultExpr();
+  assert(resultExpr);
+  TryEmitResult result;
+
+  for (PseudoObjectExpr::const_semantics_iterator
+         i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
+    const Expr *semantic = *i;
+
+    // If this semantic expression is an opaque value, bind it
+    // to the result of its source expression.
+    if (const OpaqueValueExpr *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
+      typedef CodeGenFunction::OpaqueValueMappingData OVMA;
+      OVMA opaqueData;
+
+      // If this semantic is the result of the pseudo-object
+      // expression, try to evaluate the source as +1.
+      if (ov == resultExpr) {
+        assert(!OVMA::shouldBindAsLValue(ov));
+        result = tryEmitARCRetainScalarExpr(CGF, ov->getSourceExpr());
+        opaqueData = OVMA::bind(CGF, ov, RValue::get(result.getPointer()));
+
+      // Otherwise, just bind it.
+      } else {
+        opaqueData = OVMA::bind(CGF, ov, ov->getSourceExpr());
+      }
+      opaques.push_back(opaqueData);
+
+    // Otherwise, if the expression is the result, evaluate it
+    // and remember the result.
+    } else if (semantic == resultExpr) {
+      result = tryEmitARCRetainScalarExpr(CGF, semantic);
+
+    // Otherwise, evaluate the expression in an ignored context.
+    } else {
+      CGF.EmitIgnoredExpr(semantic);
+    }
+  }
+
+  // Unbind all the opaques now.
+  for (unsigned i = 0, e = opaques.size(); i != e; ++i)
+    opaques[i].unbind(CGF);
+
+  return result;
+}
+
 static TryEmitResult
 tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
   // Look through cleanups.
@@ -2356,6 +2409,17 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
       llvm::Value *result = emitARCRetainCall(CGF, e);
       if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
       return TryEmitResult(result, true);
+
+    // Look through pseudo-object expressions.
+    } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
+      TryEmitResult result
+        = tryEmitARCRetainPseudoObject(CGF, pseudo);
+      if (resultType) {
+        llvm::Value *value = result.getPointer();
+        value = CGF.Builder.CreateBitCast(value, resultType);
+        result.setPointer(value);
+      }
+      return result;
     }
 
     // Conservatively halt the search at any other expression kind.
index 489e600b3ddfc794045ee0a6ea728e26843b122d..bc94e8ebc9b95ef4634798c3aab19dab22333066 100644 (file)
@@ -27,6 +27,7 @@ namespace clang {
   class ObjCPropertyRefExpr;
 
 namespace CodeGen {
+  class AggValueSlot;
   class CGBitFieldInfo;
 
 /// RValue - This trivial value class is used to represent the result of an
@@ -452,7 +453,7 @@ public:
   RValue asRValue() const {
     return RValue::getAggregate(getAddr(), isVolatile());
   }
-  
+
   void setZeroed(bool V = true) { ZeroedFlag = V; }
   IsZeroed_t isZeroed() const {
     return IsZeroed_t(ZeroedFlag);
index 4940e21c8be064f3060bdc00712604c27c79f0c2..0b31ce43a90504fc49365ab2713ab69b31eff7c9 100644 (file)
@@ -950,20 +950,86 @@ public:
 
   public:
     PeepholeProtection() : Inst(0) {}
-  };  
+  };
 
-  /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
-  class OpaqueValueMapping {
-    CodeGenFunction &CGF;
+  /// A non-RAII class containing all the information about a bound
+  /// opaque value.  OpaqueValueMapping, below, is a RAII wrapper for
+  /// this which makes individual mappings very simple; using this
+  /// class directly is useful when you have a variable number of
+  /// opaque values or don't want the RAII functionality for some
+  /// reason.
+  class OpaqueValueMappingData {
     const OpaqueValueExpr *OpaqueValue;
     bool BoundLValue;
     CodeGenFunction::PeepholeProtection Protection;
 
+    OpaqueValueMappingData(const OpaqueValueExpr *ov,
+                           bool boundLValue)
+      : OpaqueValue(ov), BoundLValue(boundLValue) {}
   public:
+    OpaqueValueMappingData() : OpaqueValue(0) {}
+
     static bool shouldBindAsLValue(const Expr *expr) {
       return expr->isGLValue() || expr->getType()->isRecordType();
     }
 
+    static OpaqueValueMappingData bind(CodeGenFunction &CGF,
+                                       const OpaqueValueExpr *ov,
+                                       const Expr *e) {
+      if (shouldBindAsLValue(ov))
+        return bind(CGF, ov, CGF.EmitLValue(e));
+      return bind(CGF, ov, CGF.EmitAnyExpr(e));
+    }
+
+    static OpaqueValueMappingData bind(CodeGenFunction &CGF,
+                                       const OpaqueValueExpr *ov,
+                                       const LValue &lv) {
+      assert(shouldBindAsLValue(ov));
+      CGF.OpaqueLValues.insert(std::make_pair(ov, lv));
+      return OpaqueValueMappingData(ov, true);
+    }
+
+    static OpaqueValueMappingData bind(CodeGenFunction &CGF,
+                                       const OpaqueValueExpr *ov,
+                                       const RValue &rv) {
+      assert(!shouldBindAsLValue(ov));
+      CGF.OpaqueRValues.insert(std::make_pair(ov, rv));
+
+      OpaqueValueMappingData data(ov, false);
+
+      // Work around an extremely aggressive peephole optimization in
+      // EmitScalarConversion which assumes that all other uses of a
+      // value are extant.
+      data.Protection = CGF.protectFromPeepholes(rv);
+
+      return data;
+    }
+
+    bool isValid() const { return OpaqueValue != 0; }
+    void clear() { OpaqueValue = 0; }
+
+    void unbind(CodeGenFunction &CGF) {
+      assert(OpaqueValue && "no data to unbind!");
+
+      if (BoundLValue) {
+        CGF.OpaqueLValues.erase(OpaqueValue);
+      } else {
+        CGF.OpaqueRValues.erase(OpaqueValue);
+        CGF.unprotectFromPeepholes(Protection);
+      }
+    }
+  };
+
+  /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr.
+  class OpaqueValueMapping {
+    CodeGenFunction &CGF;
+    OpaqueValueMappingData Data;
+
+  public:
+    static bool shouldBindAsLValue(const Expr *expr) {
+      return OpaqueValueMappingData::shouldBindAsLValue(expr);
+    }
+
     /// Build the opaque value mapping for the given conditional
     /// operator if it's the GNU ?: extension.  This is a common
     /// enough pattern that the convenience operator is really
@@ -971,75 +1037,34 @@ public:
     ///
     OpaqueValueMapping(CodeGenFunction &CGF,
                        const AbstractConditionalOperator *op) : CGF(CGF) {
-      if (isa<ConditionalOperator>(op)) {
-        OpaqueValue = 0;
-        BoundLValue = false;
+      if (isa<ConditionalOperator>(op))
+        // Leave Data empty.
         return;
-      }
 
       const BinaryConditionalOperator *e = cast<BinaryConditionalOperator>(op);
-      init(e->getOpaqueValue(), e->getCommon());
+      Data = OpaqueValueMappingData::bind(CGF, e->getOpaqueValue(),
+                                          e->getCommon());
     }
 
     OpaqueValueMapping(CodeGenFunction &CGF,
                        const OpaqueValueExpr *opaqueValue,
                        LValue lvalue)
-      : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(true) {
-      assert(opaqueValue && "no opaque value expression!");
-      assert(shouldBindAsLValue(opaqueValue));
-      initLValue(lvalue);
+      : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, lvalue)) {
     }
 
     OpaqueValueMapping(CodeGenFunction &CGF,
                        const OpaqueValueExpr *opaqueValue,
                        RValue rvalue)
-      : CGF(CGF), OpaqueValue(opaqueValue), BoundLValue(false) {
-      assert(opaqueValue && "no opaque value expression!");
-      assert(!shouldBindAsLValue(opaqueValue));
-      initRValue(rvalue);
+      : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, rvalue)) {
     }
 
     void pop() {
-      assert(OpaqueValue && "mapping already popped!");
-      popImpl();
-      OpaqueValue = 0;
+      Data.unbind(CGF);
+      Data.clear();
     }
 
     ~OpaqueValueMapping() {
-      if (OpaqueValue) popImpl();
-    }
-
-  private:
-    void popImpl() {
-      if (BoundLValue)
-        CGF.OpaqueLValues.erase(OpaqueValue);
-      else {
-        CGF.OpaqueRValues.erase(OpaqueValue);
-        CGF.unprotectFromPeepholes(Protection);
-      }
-    }
-
-    void init(const OpaqueValueExpr *ov, const Expr *e) {
-      OpaqueValue = ov;
-      BoundLValue = shouldBindAsLValue(ov);
-      assert(BoundLValue == shouldBindAsLValue(e)
-             && "inconsistent expression value kinds!");
-      if (BoundLValue)
-        initLValue(CGF.EmitLValue(e));
-      else
-        initRValue(CGF.EmitAnyExpr(e));
-    }
-
-    void initLValue(const LValue &lv) {
-      CGF.OpaqueLValues.insert(std::make_pair(OpaqueValue, lv));
-    }
-
-    void initRValue(const RValue &rv) {
-      // Work around an extremely aggressive peephole optimization in
-      // EmitScalarConversion which assumes that all other uses of a
-      // value are extant.
-      Protection = CGF.protectFromPeepholes(rv);
-      CGF.OpaqueRValues.insert(std::make_pair(OpaqueValue, rv));
+      if (Data.isValid()) Data.unbind(CGF);
     }
   };
   
@@ -2015,6 +2040,10 @@ public:
   LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
   LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
 
+  RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e,
+                                AggValueSlot slot = AggValueSlot::ignored());
+  LValue EmitPseudoObjectLValue(const PseudoObjectExpr *e);
+
   llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
                               const ObjCIvarDecl *Ivar);
   LValue EmitLValueForAnonRecordField(llvm::Value* Base,
index 1af9a6ce04109df97e2addc5fc969e731c59c69f..428418a09d95761a9cf44a5e99038d1cfd758cff 100644 (file)
@@ -138,12 +138,6 @@ namespace {
     
     llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
 
-    // This maps a property to it's assignment statement.
-    llvm::DenseMap<Expr *, BinaryOperator *> PropSetters;
-    // This maps a property to it's synthesied message expression.
-    // This allows us to rewrite chained getters (e.g. o.a.b.c).
-    llvm::DenseMap<Expr *, Stmt *> PropGetters;
-
     // This maps an original source AST to it's rewritten form. This allows
     // us to avoid rewriting the same node twice (which is very uncommon).
     // This is needed to support some of the exotic property rewriting.
@@ -154,6 +148,19 @@ namespace {
     VarDecl *GlobalVarDecl;
 
     bool DisableReplaceStmt;
+    class DisableReplaceStmtScope {
+      RewriteObjC &R;
+      bool SavedValue;
+
+    public:
+      DisableReplaceStmtScope(RewriteObjC &R)
+        : R(R), SavedValue(R.DisableReplaceStmt) {
+        R.DisableReplaceStmt = true;
+      }
+      ~DisableReplaceStmtScope() {
+        R.DisableReplaceStmt = SavedValue;
+      }
+    };
 
     static const int OBJC_ABI_VERSION = 7;
   public:
@@ -186,7 +193,7 @@ namespace {
         return; // We can't rewrite the same node twice.
 
       if (DisableReplaceStmt)
-        return; // Used when rewriting the assignment of a property setter.
+        return;
 
       // If replacement succeeded or warning disabled return with no warning.
       if (!Rewrite.ReplaceStmt(Old, New)) {
@@ -200,6 +207,9 @@ namespace {
     }
 
     void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) {
+      if (DisableReplaceStmt)
+        return;
+
       // Measure the old text.
       int Size = Rewrite.getRangeSize(SrcRange);
       if (Size == -1) {
@@ -282,18 +292,14 @@ namespace {
 
     // Expression Rewriting.
     Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S);
-    void CollectPropertySetters(Stmt *S);
 
     Stmt *CurrentBody;
     ParentMap *PropParentMap; // created lazily.
 
     Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp);
-    Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart,
-                                 bool &replaced);
-    Stmt *RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced);
-    Stmt *RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr);
-    Stmt *RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *newStmt,
-                                SourceRange SrcRange);
+    Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV);
+    Stmt *RewritePropertyOrImplicitGetter(PseudoObjectExpr *Pseudo);
+    Stmt *RewritePropertyOrImplicitSetter(PseudoObjectExpr *Pseudo);
     Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp);
     Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
     Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
@@ -1281,184 +1287,173 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
               "/* @end */");
 }
 
-Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *newStmt,
-                                         SourceRange SrcRange) {
-  ObjCMethodDecl *OMD = 0;
-  QualType Ty;
-  Selector Sel;
-  Stmt *Receiver = 0;
-  bool Super = false;
-  QualType SuperTy;
-  SourceLocation SuperLocation;
-  SourceLocation SelectorLoc;
-  // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr or ObjCImplicitSetterGetterRefExpr.
-  // This allows us to reuse all the fun and games in SynthMessageExpr().
-  if (ObjCPropertyRefExpr *PropRefExpr =
-        dyn_cast<ObjCPropertyRefExpr>(BinOp->getLHS())) {
-    SelectorLoc = PropRefExpr->getLocation();
-    if (PropRefExpr->isExplicitProperty()) {
-      ObjCPropertyDecl *PDecl = PropRefExpr->getExplicitProperty();
-      OMD = PDecl->getSetterMethodDecl();
-      Ty = PDecl->getType();
-      Sel = PDecl->getSetterName();
-    } else {
-      OMD = PropRefExpr->getImplicitPropertySetter();
-      Sel = OMD->getSelector();
-      Ty = (*OMD->param_begin())->getType();
-    }
-    Super = PropRefExpr->isSuperReceiver();
-    if (!Super) {
-      Receiver = PropRefExpr->getBase();
-    } else {
-      SuperTy = PropRefExpr->getSuperReceiverType();
-      SuperLocation = PropRefExpr->getReceiverLocation();
+Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(PseudoObjectExpr *PseudoOp) {
+  SourceRange OldRange = PseudoOp->getSourceRange();
+
+  // We just magically know some things about the structure of this
+  // expression.
+  ObjCMessageExpr *OldMsg =
+    cast<ObjCMessageExpr>(PseudoOp->getSemanticExpr(
+                            PseudoOp->getNumSemanticExprs() - 1));
+
+  // Because the rewriter doesn't allow us to rewrite rewritten code,
+  // we need to suppress rewriting the sub-statements.
+  Expr *Base, *RHS;
+  {
+    DisableReplaceStmtScope S(*this);
+
+    // Rebuild the base expression if we have one.
+    Base = 0;
+    if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {
+      Base = OldMsg->getInstanceReceiver();
+      Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();
+      Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));
     }
+
+    // Rebuild the RHS.
+    RHS = cast<BinaryOperator>(PseudoOp->getSyntacticForm())->getRHS();
+    RHS = cast<OpaqueValueExpr>(RHS)->getSourceExpr();
+    RHS = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(RHS));
+  }
+
+  // TODO: avoid this copy.
+  SmallVector<SourceLocation, 1> SelLocs;
+  OldMsg->getSelectorLocs(SelLocs);
+
+  ObjCMessageExpr *NewMsg;
+  switch (OldMsg->getReceiverKind()) {
+  case ObjCMessageExpr::Class:
+    NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+                                     OldMsg->getValueKind(),
+                                     OldMsg->getLeftLoc(),
+                                     OldMsg->getClassReceiverTypeInfo(),
+                                     OldMsg->getSelector(),
+                                     SelLocs,
+                                     OldMsg->getMethodDecl(),
+                                     RHS,
+                                     OldMsg->getRightLoc());
+    break;
+
+  case ObjCMessageExpr::Instance:
+    NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+                                     OldMsg->getValueKind(),
+                                     OldMsg->getLeftLoc(),
+                                     Base,
+                                     OldMsg->getSelector(),
+                                     SelLocs,
+                                     OldMsg->getMethodDecl(),
+                                     RHS,
+                                     OldMsg->getRightLoc());
+    break;
+
+  case ObjCMessageExpr::SuperClass:
+  case ObjCMessageExpr::SuperInstance:
+    NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+                                     OldMsg->getValueKind(),
+                                     OldMsg->getLeftLoc(),
+                                     OldMsg->getSuperLoc(),
+                 OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,
+                                     OldMsg->getSuperType(),
+                                     OldMsg->getSelector(),
+                                     SelLocs,
+                                     OldMsg->getMethodDecl(),
+                                     RHS,
+                                     OldMsg->getRightLoc());
+    break;
   }
-  
-  assert(OMD && "RewritePropertyOrImplicitSetter - null OMD");
-
-  ObjCMessageExpr *MsgExpr;
-  if (Super)
-    MsgExpr = ObjCMessageExpr::Create(*Context, 
-                                      Ty.getNonReferenceType(),
-                                      Expr::getValueKindForType(Ty),
-                                      /*FIXME?*/SourceLocation(),
-                                      SuperLocation,
-                                      /*IsInstanceSuper=*/true,
-                                      SuperTy,
-                                      Sel, SelectorLoc, OMD,
-                                      newStmt,
-                                      /*FIXME:*/SourceLocation());
-  else {
-    // FIXME. Refactor this into common code with that in 
-    // RewritePropertyOrImplicitGetter
-    assert(Receiver && "RewritePropertyOrImplicitSetter - null Receiver");
-    if (Expr *Exp = dyn_cast<Expr>(Receiver))
-      if (PropGetters[Exp])
-        // This allows us to handle chain/nested property/implicit getters.
-        Receiver = PropGetters[Exp];
-  
-    MsgExpr = ObjCMessageExpr::Create(*Context, 
-                                      Ty.getNonReferenceType(),
-                                      Expr::getValueKindForType(Ty),
-                                      /*FIXME: */SourceLocation(),
-                                      cast<Expr>(Receiver),
-                                      Sel, SelectorLoc, OMD,
-                                      newStmt,
-                                      /*FIXME:*/SourceLocation());
-  }
-  Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr);
 
-  // Now do the actual rewrite.
-  ReplaceStmtWithRange(BinOp, ReplacingStmt, SrcRange);
-  //delete BinOp;
-  // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
-  // to things that stay around.
-  Context->Deallocate(MsgExpr);
-  return ReplacingStmt;
+  Stmt *Replacement = SynthMessageExpr(NewMsg);
+  ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);
+  return Replacement;
 }
 
-Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) {
-  // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr or ImplicitGetter.
-  // This allows us to reuse all the fun and games in SynthMessageExpr().
-  Stmt *Receiver = 0;
-  ObjCMethodDecl *OMD = 0;
-  QualType Ty;
-  Selector Sel;
-  bool Super = false;
-  QualType SuperTy;
-  SourceLocation SuperLocation;
-  SourceLocation SelectorLoc;
-  if (ObjCPropertyRefExpr *PropRefExpr = 
-        dyn_cast<ObjCPropertyRefExpr>(PropOrGetterRefExpr)) {
-    SelectorLoc = PropRefExpr->getLocation();
-    if (PropRefExpr->isExplicitProperty()) {
-      ObjCPropertyDecl *PDecl = PropRefExpr->getExplicitProperty();
-      OMD = PDecl->getGetterMethodDecl();
-      Ty = PDecl->getType();
-      Sel = PDecl->getGetterName();
-    } else {
-      OMD = PropRefExpr->getImplicitPropertyGetter();
-      Sel = OMD->getSelector();
-      Ty = OMD->getResultType();
-    }
-    Super = PropRefExpr->isSuperReceiver();
-    if (!Super)
-      Receiver = PropRefExpr->getBase();
-    else {
-      SuperTy = PropRefExpr->getSuperReceiverType();
-      SuperLocation = PropRefExpr->getReceiverLocation();
+Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(PseudoObjectExpr *PseudoOp) {
+  SourceRange OldRange = PseudoOp->getSourceRange();
+
+  // We just magically know some things about the structure of this
+  // expression.
+  ObjCMessageExpr *OldMsg =
+    cast<ObjCMessageExpr>(PseudoOp->getResultExpr()->IgnoreImplicit());
+
+  // Because the rewriter doesn't allow us to rewrite rewritten code,
+  // we need to suppress rewriting the sub-statements.
+  Expr *Base = 0;
+  {
+    DisableReplaceStmtScope S(*this);
+
+    // Rebuild the base expression if we have one.
+    if (OldMsg->getReceiverKind() == ObjCMessageExpr::Instance) {
+      Base = OldMsg->getInstanceReceiver();
+      Base = cast<OpaqueValueExpr>(Base)->getSourceExpr();
+      Base = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(Base));
     }
   }
-  
-  assert (OMD && "RewritePropertyOrImplicitGetter - OMD is null");
-  
-  ObjCMessageExpr *MsgExpr;
-  if (Super)
-    MsgExpr = ObjCMessageExpr::Create(*Context, 
-                                      Ty.getNonReferenceType(),
-                                      Expr::getValueKindForType(Ty),
-                                      PropOrGetterRefExpr->getLocStart(),
-                                      SuperLocation,
-                                      /*IsInstanceSuper=*/true,
-                                      SuperTy,
-                                      Sel, SelectorLoc, OMD,
-                                      ArrayRef<Expr*>(), 
-                                      PropOrGetterRefExpr->getLocEnd());
-  else {
-    assert (Receiver && "RewritePropertyOrImplicitGetter - Receiver is null");
-    if (Expr *Exp = dyn_cast<Expr>(Receiver))
-      if (PropGetters[Exp])
-        // This allows us to handle chain/nested property/implicit getters.
-        Receiver = PropGetters[Exp];
-    MsgExpr = ObjCMessageExpr::Create(*Context, 
-                                      Ty.getNonReferenceType(),
-                                      Expr::getValueKindForType(Ty),
-                                      PropOrGetterRefExpr->getLocStart(),
-                                      cast<Expr>(Receiver),
-                                      Sel, SelectorLoc, OMD,
-                                      ArrayRef<Expr*>(), 
-                                      PropOrGetterRefExpr->getLocEnd());
-  }
-
-  Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr, MsgExpr->getLocStart(),
-                                         MsgExpr->getLocEnd());
-
-  if (!PropParentMap)
-    PropParentMap = new ParentMap(CurrentBody);
-  bool NestedPropertyRef = false;
-  Stmt *Parent = PropParentMap->getParent(PropOrGetterRefExpr);
-  ImplicitCastExpr*ICE=0;
-  if (Parent)
-    if ((ICE = dyn_cast<ImplicitCastExpr>(Parent))) {
-      assert((ICE->getCastKind() == CK_GetObjCProperty)
-             && "RewritePropertyOrImplicitGetter");
-      Parent = PropParentMap->getParent(Parent);
-      NestedPropertyRef = (Parent && isa<ObjCPropertyRefExpr>(Parent));
-    }
-  if (NestedPropertyRef) {
-    // We stash away the ReplacingStmt since actually doing the
-    // replacement/rewrite won't work for nested getters (e.g. obj.p.i)
-    PropGetters[ICE] = ReplacingStmt;
-    // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
-    // to things that stay around.
-    Context->Deallocate(MsgExpr);
-    return PropOrGetterRefExpr; // return the original...
-  } else {
-    ReplaceStmt(PropOrGetterRefExpr, ReplacingStmt);
-    // delete PropRefExpr; elsewhere...
-    // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references
-    // to things that stay around.
-    Context->Deallocate(MsgExpr);
-    return ReplacingStmt;
+
+  // Intentionally empty.
+  SmallVector<SourceLocation, 1> SelLocs;
+  SmallVector<Expr*, 1> Args;
+
+  ObjCMessageExpr *NewMsg;
+  switch (OldMsg->getReceiverKind()) {
+  case ObjCMessageExpr::Class:
+    NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+                                     OldMsg->getValueKind(),
+                                     OldMsg->getLeftLoc(),
+                                     OldMsg->getClassReceiverTypeInfo(),
+                                     OldMsg->getSelector(),
+                                     SelLocs,
+                                     OldMsg->getMethodDecl(),
+                                     Args,
+                                     OldMsg->getRightLoc());
+    break;
+
+  case ObjCMessageExpr::Instance:
+    NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+                                     OldMsg->getValueKind(),
+                                     OldMsg->getLeftLoc(),
+                                     Base,
+                                     OldMsg->getSelector(),
+                                     SelLocs,
+                                     OldMsg->getMethodDecl(),
+                                     Args,
+                                     OldMsg->getRightLoc());
+    break;
+
+  case ObjCMessageExpr::SuperClass:
+  case ObjCMessageExpr::SuperInstance:
+    NewMsg = ObjCMessageExpr::Create(*Context, OldMsg->getType(),
+                                     OldMsg->getValueKind(),
+                                     OldMsg->getLeftLoc(),
+                                     OldMsg->getSuperLoc(),
+                 OldMsg->getReceiverKind() == ObjCMessageExpr::SuperInstance,
+                                     OldMsg->getSuperType(),
+                                     OldMsg->getSelector(),
+                                     SelLocs,
+                                     OldMsg->getMethodDecl(),
+                                     Args,
+                                     OldMsg->getRightLoc());
+    break;
   }
+
+  Stmt *Replacement = SynthMessageExpr(NewMsg);
+  ReplaceStmtWithRange(PseudoOp, Replacement, OldRange);
+  return Replacement;
 }
 
-Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
-                                          SourceLocation OrigStart,
-                                          bool &replaced) {
+Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
+  SourceRange OldRange = IV->getSourceRange();
+  Expr *BaseExpr = IV->getBase();
+
+  // Rewrite the base, but without actually doing replaces.
+  {
+    DisableReplaceStmtScope S(*this);
+    BaseExpr = cast<Expr>(RewriteFunctionBodyOrGlobalInitializer(BaseExpr));
+    IV->setBase(BaseExpr);
+  }
+
   ObjCIvarDecl *D = IV->getDecl();
-  const Expr *BaseExpr = IV->getBase();
+
+  Expr *Replacement = IV;
   if (CurMethodDef) {
     if (BaseExpr->getType()->isObjCObjectPointerType()) {
       const ObjCInterfaceType *iFaceDecl =
@@ -1483,25 +1478,19 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
                                                     CK_BitCast,
                                                     IV->getBase());
       // Don't forget the parens to enforce the proper binding.
-      ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
-                                              IV->getBase()->getLocEnd(),
+      ParenExpr *PE = new (Context) ParenExpr(OldRange.getBegin(),
+                                              OldRange.getEnd(),
                                               castExpr);
-      replaced = true;
       if (IV->isFreeIvar() &&
           CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
         MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
                                                   IV->getLocation(),
                                                   D->getType(),
                                                   VK_LValue, OK_Ordinary);
-        // delete IV; leak for now, see RewritePropertyOrImplicitSetter() usage for more info.
-        return ME;
+        Replacement = ME;
+      } else {
+        IV->setBase(PE);
       }
-      // Get the new text
-      // Cannot delete IV->getBase(), since PE points to it.
-      // Replace the old base with the cast. This is important when doing
-      // embedded rewrites. For example, [newInv->_container addObject:0].
-      IV->setBase(PE);
-      return IV;
     }
   } else { // we are outside a method.
     assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method");
@@ -1532,36 +1521,15 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
       // Don't forget the parens to enforce the proper binding.
       ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
                                     IV->getBase()->getLocEnd(), castExpr);
-      replaced = true;
       // Cannot delete IV->getBase(), since PE points to it.
       // Replace the old base with the cast. This is important when doing
       // embedded rewrites. For example, [newInv->_container addObject:0].
       IV->setBase(PE);
-      return IV;
     }
   }
-  return IV;
-}
 
-Stmt *RewriteObjC::RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced) {
-  for (Stmt::child_range CI = S->children(); CI; ++CI) {
-    if (*CI) {
-      Stmt *newStmt = RewriteObjCNestedIvarRefExpr(*CI, replaced);
-      if (newStmt)
-        *CI = newStmt;
-    }
-  }
-  if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
-    SourceRange OrigStmtRange = S->getSourceRange();
-    Stmt *newStmt = RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin(),
-                                           replaced);
-    return newStmt;
-  } 
-  if (ObjCMessageExpr *MsgRefExpr = dyn_cast<ObjCMessageExpr>(S)) {
-    Stmt *newStmt = SynthMessageExpr(MsgRefExpr);
-    return newStmt;
-  }
-  return S;
+  ReplaceStmtWithRange(IV, Replacement, OldRange);
+  return Replacement;  
 }
 
 /// SynthCountByEnumWithState - To print:
@@ -4753,6 +4721,9 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
     return CondExpr;
   } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) {
     CPT = IRE->getType()->getAs<BlockPointerType>();
+  } else if (const PseudoObjectExpr *POE
+               = dyn_cast<PseudoObjectExpr>(BlockExp)) {
+    CPT = POE->getType()->castAs<BlockPointerType>();
   } else {
     assert(1 && "RewriteBlockClass: Bad type");
   }
@@ -5580,26 +5551,6 @@ bool RewriteObjC::IsDeclStmtInForeachHeader(DeclStmt *DS) {
 // Function Body / Expression rewriting
 //===----------------------------------------------------------------------===//
 
-// This is run as a first "pass" prior to RewriteFunctionBodyOrGlobalInitializer().
-// The allows the main rewrite loop to associate all ObjCPropertyRefExprs with
-// their respective BinaryOperator. Without this knowledge, we'd need to rewrite
-// the ObjCPropertyRefExpr twice (once as a getter, and later as a setter).
-// Since the rewriter isn't capable of rewriting rewritten code, it's important
-// we get this right.
-void RewriteObjC::CollectPropertySetters(Stmt *S) {
-  // Perform a bottom up traversal of all children.
-  for (Stmt::child_range CI = S->children(); CI; ++CI)
-    if (*CI)
-      CollectPropertySetters(*CI);
-
-  if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
-    if (BinOp->isAssignmentOp()) {
-      if (isa<ObjCPropertyRefExpr>(BinOp->getLHS()))
-        PropSetters[BinOp->getLHS()] = BinOp;
-    }
-  }
-}
-
 Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
   if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
       isa<DoStmt>(S) || isa<ForStmt>(S))
@@ -5609,46 +5560,28 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
     ObjCBcLabelNo.push_back(++BcLabelCount);
   }
 
+  // Pseudo-object operations and ivar references need special
+  // treatment because we're going to recursively rewrite them.
+  if (PseudoObjectExpr *PseudoOp = dyn_cast<PseudoObjectExpr>(S)) {
+    if (isa<BinaryOperator>(PseudoOp->getSyntacticForm())) {
+      return RewritePropertyOrImplicitSetter(PseudoOp);
+    } else {
+      return RewritePropertyOrImplicitGetter(PseudoOp);
+    }
+  } else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
+    return RewriteObjCIvarRefExpr(IvarRefExpr);
+  }
+
   SourceRange OrigStmtRange = S->getSourceRange();
 
   // Perform a bottom up rewrite of all children.
   for (Stmt::child_range CI = S->children(); CI; ++CI)
     if (*CI) {
-      Stmt *newStmt;
-      Stmt *ChildStmt = (*CI);
-      if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(ChildStmt)) {
-        Expr *OldBase = IvarRefExpr->getBase();
-        bool replaced = false;
-        newStmt = RewriteObjCNestedIvarRefExpr(ChildStmt, replaced);
-        if (replaced) {
-          if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(newStmt))
-            ReplaceStmt(OldBase, IRE->getBase());
-          else
-            ReplaceStmt(ChildStmt, newStmt);
-        }
-      }
-      else
-        newStmt = RewriteFunctionBodyOrGlobalInitializer(ChildStmt);
+      Stmt *childStmt = (*CI);
+      Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(childStmt);
       if (newStmt) {
-          if (Expr *PropOrImplicitRefExpr = dyn_cast<Expr>(ChildStmt))
-            if (PropSetters[PropOrImplicitRefExpr] == S) {
-              S = newStmt;
-              newStmt = 0;
-            }
-        if (newStmt)
-          *CI = newStmt;
+        *CI = newStmt;
       }
-      // If dealing with an assignment with LHS being a property reference
-      // expression, the entire assignment tree is rewritten into a property
-      // setter messaging. This involvs the RHS too. Do not attempt to rewrite
-      // RHS again.
-      if (Expr *Exp = dyn_cast<Expr>(ChildStmt))
-        if (isa<ObjCPropertyRefExpr>(Exp)) {
-          if (PropSetters[Exp]) {
-            ++CI;
-            continue;
-          }
-        }
     }
 
   if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
@@ -5661,7 +5594,6 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
     // Rewrite the block body in place.
     Stmt *SaveCurrentBody = CurrentBody;
     CurrentBody = BE->getBody();
-    CollectPropertySetters(CurrentBody);
     PropParentMap = 0;
     // block literal on rhs of a property-dot-sytax assignment
     // must be replaced by its synthesize ast so getRewrittenText
@@ -5689,67 +5621,6 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
   if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
     return RewriteAtEncode(AtEncode);
 
-  if (isa<ObjCPropertyRefExpr>(S)) {
-    Expr *PropOrImplicitRefExpr = dyn_cast<Expr>(S);
-    assert(PropOrImplicitRefExpr && "Property or implicit setter/getter is null");
-    
-    BinaryOperator *BinOp = PropSetters[PropOrImplicitRefExpr];
-    if (BinOp) {
-      // Because the rewriter doesn't allow us to rewrite rewritten code,
-      // we need to rewrite the right hand side prior to rewriting the setter.
-      DisableReplaceStmt = true;
-      // Save the source range. Even if we disable the replacement, the
-      // rewritten node will have been inserted into the tree. If the synthesized
-      // node is at the 'end', the rewriter will fail. Consider this:
-      //    self.errorHandler = handler ? handler :
-      //              ^(NSURL *errorURL, NSError *error) { return (BOOL)1; };
-      SourceRange SrcRange = BinOp->getSourceRange();
-      Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(BinOp->getRHS());
-      // Need to rewrite the ivar access expression if need be.
-      if (isa<ObjCIvarRefExpr>(newStmt)) {
-        bool replaced = false;
-        newStmt = RewriteObjCNestedIvarRefExpr(newStmt, replaced);
-      }
-      
-      DisableReplaceStmt = false;
-      //
-      // Unlike the main iterator, we explicily avoid changing 'BinOp'. If
-      // we changed the RHS of BinOp, the rewriter would fail (since it needs
-      // to see the original expression). Consider this example:
-      //
-      // Foo *obj1, *obj2;
-      //
-      // obj1.i = [obj2 rrrr];
-      //
-      // 'BinOp' for the previous expression looks like:
-      //
-      // (BinaryOperator 0x231ccf0 'int' '='
-      //   (ObjCPropertyRefExpr 0x231cc70 'int' Kind=PropertyRef Property="i"
-      //     (DeclRefExpr 0x231cc50 'Foo *' Var='obj1' 0x231cbb0))
-      //   (ObjCMessageExpr 0x231ccb0 'int' selector=rrrr
-      //     (DeclRefExpr 0x231cc90 'Foo *' Var='obj2' 0x231cbe0)))
-      //
-      // 'newStmt' represents the rewritten message expression. For example:
-      //
-      // (CallExpr 0x231d300 'id':'struct objc_object *'
-      //   (ParenExpr 0x231d2e0 'int (*)(id, SEL)'
-      //     (CStyleCastExpr 0x231d2c0 'int (*)(id, SEL)'
-      //       (CStyleCastExpr 0x231d220 'void *'
-      //         (DeclRefExpr 0x231d200 'id (id, SEL, ...)' FunctionDecl='objc_msgSend' 0x231cdc0))))
-      //
-      // Note that 'newStmt' is passed to RewritePropertyOrImplicitSetter so that it
-      // can be used as the setter argument. ReplaceStmt() will still 'see'
-      // the original RHS (since we haven't altered BinOp).
-      //
-      // This implies the Rewrite* routines can no longer delete the original
-      // node. As a result, we now leak the original AST nodes.
-      //
-      return RewritePropertyOrImplicitSetter(BinOp, dyn_cast<Expr>(newStmt), SrcRange);
-    } else {
-      return RewritePropertyOrImplicitGetter(PropOrImplicitRefExpr);
-    }
-  }
-  
   if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
     return RewriteAtSelector(AtSelector);
 
@@ -5930,7 +5801,6 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
     if (CompoundStmt *Body = dyn_cast_or_null<CompoundStmt>(FD->getBody())) {
       CurFunctionDef = FD;
       CurFunctionDeclToDeclareForBlock = FD;
-      CollectPropertySetters(Body);
       CurrentBody = Body;
       Body =
        cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
@@ -5951,7 +5821,6 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
   if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
     if (CompoundStmt *Body = MD->getCompoundBody()) {
       CurMethodDef = MD;
-      CollectPropertySetters(Body);
       CurrentBody = Body;
       Body =
        cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body));
@@ -5989,7 +5858,6 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
     }
     if (VD->getInit()) {
       GlobalVarDecl = VD;
-      CollectPropertySetters(VD->getInit());
       CurrentBody = VD->getInit();
       RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
       CurrentBody = 0;
index 8cae0408f065e50788867c1952307a22c2622564..8a3324230d08ec3534a635921bccd04ea43cf177 100644 (file)
@@ -4213,6 +4213,26 @@ static bool findRetainCycleOwner(Expr *e, RetainCycleOwner &owner) {
       continue;
     }
 
+    if (PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
+      // Only pay attention to pseudo-objects on property references.
+      ObjCPropertyRefExpr *pre
+        = dyn_cast<ObjCPropertyRefExpr>(pseudo->getSyntacticForm()
+                                              ->IgnoreParens());
+      if (!pre) return false;
+      if (pre->isImplicitProperty()) return false;
+      ObjCPropertyDecl *property = pre->getExplicitProperty();
+      if (!property->isRetaining() &&
+          !(property->getPropertyIvarDecl() &&
+            property->getPropertyIvarDecl()->getType()
+              .getObjCLifetime() == Qualifiers::OCL_Strong))
+          return false;
+
+      owner.Indirect = true;
+      e = const_cast<Expr*>(cast<OpaqueValueExpr>(pre->getBase())
+                              ->getSourceExpr());
+      continue;
+    }
+
     // Array ivars?
 
     return false;
index febd394eb330ad6fa17ee97097b4b2163ec42e7c..c6a5f1ec6f54cab301881651daa637d3feca418e 100644 (file)
@@ -7468,7 +7468,7 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
     // The operand must be either an l-value or a function designator
     if (!op->getType()->isFunctionType()) {
       // Use a special diagnostic for loads from property references.
-      if (isa<ObjCPropertyRefExpr>(op->IgnoreImplicit()->IgnoreParens())) {
+      if (isa<PseudoObjectExpr>(op)) {
         AddressOfError = AO_Property_Expansion;
       } else {
         // FIXME: emit more specific diag...
@@ -7483,9 +7483,6 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
   } else if (op->getObjectKind() == OK_VectorComponent) {
     // The operand cannot be an element of a vector
     AddressOfError = AO_Vector_Element;
-  } else if (op->getObjectKind() == OK_ObjCProperty) {
-    // cannot take address of a property expression.
-    AddressOfError = AO_Property_Expansion;
   } else if (dcl) { // C99 6.5.3.2p1
     // We have an lvalue with a decl. Make sure the decl is not declared
     // with the register storage-class specifier.
@@ -8951,8 +8948,15 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType,
       return;
   }
 
-  // Strip off any parens and casts.
-  StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts());
+  // Ignore any parens, implicit casts (should only be
+  // array-to-pointer decays), and not-so-opaque values.  The last is
+  // important for making this trigger for property assignments.
+  SrcExpr = SrcExpr->IgnoreParenImpCasts();
+  if (OpaqueValueExpr *OV = dyn_cast<OpaqueValueExpr>(SrcExpr))
+    if (OV->getSourceExpr())
+      SrcExpr = OV->getSourceExpr()->IgnoreParenImpCasts();
+
+  StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr);
   if (!SL || !SL->isAscii())
     return;
 
index 019dc817643d8f5f10ced8bc22d54447d120ac16..a9179dcf7fdbe31e2dae1b3ba65d0943d4ffae73 100644 (file)
@@ -467,14 +467,13 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
 
 bool Sema::isSelfExpr(Expr *receiver) {
   // 'self' is objc 'self' in an objc method only.
-  DeclContext *DC = CurContext;
-  while (isa<BlockDecl>(DC))
-    DC = DC->getParent();
-  if (DC && !isa<ObjCMethodDecl>(DC))
-    return false;
+  ObjCMethodDecl *method =
+    dyn_cast<ObjCMethodDecl>(CurContext->getNonClosureAncestor());
+  if (!method) return false;
+
   receiver = receiver->IgnoreParenLValueCasts();
   if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(receiver))
-    if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self"))
+    if (DRE->getDecl() == method->getSelfDecl())
       return true;
   return false;
 }
@@ -1725,6 +1724,12 @@ namespace {
       return merge(left, Visit(e->getFalseExpr()));
     }
 
+    /// Look through pseudo-objects.
+    ACCResult VisitPseudoObjectExpr(PseudoObjectExpr *e) {
+      // If we're getting here, we should always have a result.
+      return Visit(e->getResultExpr());
+    }
+
     /// Statement expressions are okay if their result expression is okay.
     ACCResult VisitStmtExpr(StmtExpr *e) {
       return Visit(e->getSubStmt()->body_back());
index 97fbe48aa23b4221708bf7130df5f6e608fa12b9..e0a62712159aa89410cd096e01bd07e035efac5a 100644 (file)
 using namespace clang;
 using namespace sema;
 
+namespace {
+  // Basically just a very focused copy of TreeTransform.
+  template <class T> struct Rebuilder {
+    Sema &S;
+    Rebuilder(Sema &S) : S(S) {}
+
+    T &getDerived() { return static_cast<T&>(*this); }
+
+    Expr *rebuild(Expr *e) {
+      // Fast path: nothing to look through.
+      if (typename T::specific_type *specific
+            = dyn_cast<typename T::specific_type>(e))
+        return getDerived().rebuildSpecific(specific);
+
+      // Otherwise, we should look through and rebuild anything that
+      // IgnoreParens would.
+
+      if (ParenExpr *parens = dyn_cast<ParenExpr>(e)) {
+        e = rebuild(parens->getSubExpr());
+        return new (S.Context) ParenExpr(parens->getLParen(),
+                                         parens->getRParen(),
+                                         e);
+      }
+
+      if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) {
+        assert(uop->getOpcode() == UO_Extension);
+        e = rebuild(uop->getSubExpr());
+        return new (S.Context) UnaryOperator(e, uop->getOpcode(),
+                                             uop->getType(),
+                                             uop->getValueKind(),
+                                             uop->getObjectKind(),
+                                             uop->getOperatorLoc());
+      }
+
+      if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) {
+        assert(!gse->isResultDependent());
+        unsigned resultIndex = gse->getResultIndex();
+        unsigned numAssocs = gse->getNumAssocs();
+
+        SmallVector<Expr*, 8> assocs(numAssocs);
+        SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs);
+
+        for (unsigned i = 0; i != numAssocs; ++i) {
+          Expr *assoc = gse->getAssocExpr(i);
+          if (i == resultIndex) assoc = rebuild(assoc);
+          assocs[i] = assoc;
+          assocTypes[i] = gse->getAssocTypeSourceInfo(i);
+        }
+
+        return new (S.Context) GenericSelectionExpr(S.Context,
+                                                    gse->getGenericLoc(),
+                                                    gse->getControllingExpr(),
+                                                    assocTypes.data(),
+                                                    assocs.data(),
+                                                    numAssocs,
+                                                    gse->getDefaultLoc(),
+                                                    gse->getRParenLoc(),
+                                      gse->containsUnexpandedParameterPack(),
+                                                    resultIndex);
+      }
+
+      llvm_unreachable("bad expression to rebuild!");
+    }
+  };
+
+  struct ObjCPropertyRefRebuilder : Rebuilder<ObjCPropertyRefRebuilder> {
+    Expr *NewBase;
+    ObjCPropertyRefRebuilder(Sema &S, Expr *newBase)
+      : Rebuilder(S), NewBase(newBase) {}
+
+    typedef ObjCPropertyRefExpr specific_type;
+    Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) {
+      // Fortunately, the constraint that we're rebuilding something
+      // with a base limits the number of cases here.
+      assert(refExpr->getBase());
+
+      if (refExpr->isExplicitProperty()) {
+        return new (S.Context)
+          ObjCPropertyRefExpr(refExpr->getExplicitProperty(),
+                              refExpr->getType(), refExpr->getValueKind(),
+                              refExpr->getObjectKind(), refExpr->getLocation(),
+                              NewBase);
+      }
+      return new (S.Context)
+        ObjCPropertyRefExpr(refExpr->getImplicitPropertyGetter(),
+                            refExpr->getImplicitPropertySetter(),
+                            refExpr->getType(), refExpr->getValueKind(),
+                            refExpr->getObjectKind(),refExpr->getLocation(),
+                            NewBase);
+    }
+  };
+
+  class PseudoOpBuilder {
+  public:
+    Sema &S;
+    unsigned ResultIndex;
+    SourceLocation GenericLoc;
+    SmallVector<Expr *, 4> Semantics;
+
+    PseudoOpBuilder(Sema &S, SourceLocation genericLoc)
+      : S(S), ResultIndex(PseudoObjectExpr::NoResult),
+        GenericLoc(genericLoc) {}
+
+    /// Add a normal semantic expression.
+    void addSemanticExpr(Expr *semantic) {
+      Semantics.push_back(semantic);
+    }
+
+    /// Add the 'result' semantic expression.
+    void addResultSemanticExpr(Expr *resultExpr) {
+      assert(ResultIndex == PseudoObjectExpr::NoResult);
+      ResultIndex = Semantics.size();
+      Semantics.push_back(resultExpr);
+    }
+
+    ExprResult buildRValueOperation(Expr *op);
+    ExprResult buildAssignmentOperation(Scope *Sc,
+                                        SourceLocation opLoc,
+                                        BinaryOperatorKind opcode,
+                                        Expr *LHS, Expr *RHS);
+    ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc,
+                                    UnaryOperatorKind opcode,
+                                    Expr *op);
+
+    ExprResult complete(Expr *syntacticForm);
+
+    OpaqueValueExpr *capture(Expr *op);
+    OpaqueValueExpr *captureValueAsResult(Expr *op);
+
+    void setResultToLastSemantic() {
+      assert(ResultIndex == PseudoObjectExpr::NoResult);
+      ResultIndex = Semantics.size() - 1;
+    }
+
+    /// Return true if assignments have a non-void result.
+    virtual bool assignmentsHaveResult() { return true; }
+
+    virtual Expr *rebuildAndCaptureObject(Expr *) = 0;
+    virtual ExprResult buildGet() = 0;
+    virtual ExprResult buildSet(Expr *, SourceLocation,
+                                bool captureSetValueAsResult) = 0;
+  };
+
+  /// A PseudoOpBuilder for Objective-C @properties.
+  class ObjCPropertyOpBuilder : public PseudoOpBuilder {
+    ObjCPropertyRefExpr *RefExpr;
+    OpaqueValueExpr *InstanceReceiver;
+    ObjCMethodDecl *Getter;
+
+    ObjCMethodDecl *Setter;
+    Selector SetterSelector;
+
+  public:
+    ObjCPropertyOpBuilder(Sema &S, ObjCPropertyRefExpr *refExpr) :
+      PseudoOpBuilder(S, refExpr->getLocation()), RefExpr(refExpr),
+      InstanceReceiver(0), Getter(0), Setter(0) {
+    }
+
+    ExprResult buildRValueOperation(Expr *op);
+    ExprResult buildAssignmentOperation(Scope *Sc,
+                                        SourceLocation opLoc,
+                                        BinaryOperatorKind opcode,
+                                        Expr *LHS, Expr *RHS);
+    ExprResult buildIncDecOperation(Scope *Sc, SourceLocation opLoc,
+                                    UnaryOperatorKind opcode,
+                                    Expr *op);
+
+    bool tryBuildGetOfReference(Expr *op, ExprResult &result);
+    bool findSetter();
+    bool findGetter();
+
+    Expr *rebuildAndCaptureObject(Expr *syntacticBase);
+    ExprResult buildGet();
+    ExprResult buildSet(Expr *op, SourceLocation, bool);
+  };
+}
+
+/// Capture the given expression in an OpaqueValueExpr.
+OpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) {
+  // Make a new OVE whose source is the given expression.
+  OpaqueValueExpr *captured = 
+    new (S.Context) OpaqueValueExpr(GenericLoc, e->getType(),
+                                    e->getValueKind());
+  captured->setSourceExpr(e);
+  
+  // Make sure we bind that in the semantics.
+  addSemanticExpr(captured);
+  return captured;
+}
+
+/// Capture the given expression as the result of this pseudo-object
+/// operation.  This routine is safe against expressions which may
+/// already be captured.
+///
+/// \param Returns the captured expression, which will be the
+///   same as the input if the input was already captured
+OpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) {
+  assert(ResultIndex == PseudoObjectExpr::NoResult);
+
+  // If the expression hasn't already been captured, just capture it
+  // and set the new semantic 
+  if (!isa<OpaqueValueExpr>(e)) {
+    OpaqueValueExpr *cap = capture(e);
+    setResultToLastSemantic();
+    return cap;
+  }
+
+  // Otherwise, it must already be one of our semantic expressions;
+  // set ResultIndex to its index.
+  unsigned index = 0;
+  for (;; ++index) {
+    assert(index < Semantics.size() &&
+           "captured expression not found in semantics!");
+    if (e == Semantics[index]) break;
+  }
+  ResultIndex = index;
+  return cast<OpaqueValueExpr>(e);
+}
+
+/// The routine which creates the final PseudoObjectExpr.
+ExprResult PseudoOpBuilder::complete(Expr *syntactic) {
+  return PseudoObjectExpr::Create(S.Context, syntactic,
+                                  Semantics, ResultIndex);
+}
+
+/// The main skeleton for building an r-value operation.
+ExprResult PseudoOpBuilder::buildRValueOperation(Expr *op) {
+  Expr *syntacticBase = rebuildAndCaptureObject(op);
+
+  ExprResult getExpr = buildGet();
+  if (getExpr.isInvalid()) return ExprError();
+  addResultSemanticExpr(getExpr.take());
+
+  return complete(syntacticBase);
+}
+
+/// The basic skeleton for building a simple or compound
+/// assignment operation.
+ExprResult
+PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc,
+                                          BinaryOperatorKind opcode,
+                                          Expr *LHS, Expr *RHS) {
+  assert(BinaryOperator::isAssignmentOp(opcode));
+
+  Expr *syntacticLHS = rebuildAndCaptureObject(LHS);
+  OpaqueValueExpr *capturedRHS = capture(RHS);
+
+  Expr *syntactic;
+
+  ExprResult result;
+  if (opcode == BO_Assign) {
+    result = capturedRHS;
+    syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS,
+                                               opcode, capturedRHS->getType(),
+                                               capturedRHS->getValueKind(),
+                                               OK_Ordinary, opcLoc);
+  } else {
+    ExprResult opLHS = buildGet();
+    if (opLHS.isInvalid()) return ExprError();
+
+    // Build an ordinary, non-compound operation.
+    BinaryOperatorKind nonCompound =
+      BinaryOperator::getOpForCompoundAssignment(opcode);
+    result = S.BuildBinOp(Sc, opcLoc, nonCompound,
+                          opLHS.take(), capturedRHS);
+    if (result.isInvalid()) return ExprError();
+
+    syntactic =
+      new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode,
+                                             result.get()->getType(),
+                                             result.get()->getValueKind(),
+                                             OK_Ordinary,
+                                             opLHS.get()->getType(),
+                                             result.get()->getType(),
+                                             opcLoc);
+  }
+
+  // The result of the assignment, if not void, is the value set into
+  // the l-value.
+  result = buildSet(result.take(), opcLoc, assignmentsHaveResult());
+  if (result.isInvalid()) return ExprError();
+  addSemanticExpr(result.take());
+
+  return complete(syntactic);
+}
+
+/// The basic skeleton for building an increment or decrement
+/// operation.
+ExprResult
+PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
+                                      UnaryOperatorKind opcode,
+                                      Expr *op) {
+  assert(UnaryOperator::isIncrementDecrementOp(opcode));
+
+  Expr *syntacticOp = rebuildAndCaptureObject(op);
+
+  // Load the value.
+  ExprResult result = buildGet();
+  if (result.isInvalid()) return ExprError();
+
+  QualType resultType = result.get()->getType();
+
+  // That's the postfix result.
+  if (UnaryOperator::isPostfix(opcode) && assignmentsHaveResult()) {
+    result = capture(result.take());
+    setResultToLastSemantic();
+  }
+
+  // Add or subtract a literal 1.
+  llvm::APInt oneV(S.Context.getTypeSize(S.Context.IntTy), 1);
+  Expr *one = IntegerLiteral::Create(S.Context, oneV, S.Context.IntTy,
+                                     GenericLoc);
+
+  if (UnaryOperator::isIncrementOp(opcode)) {
+    result = S.BuildBinOp(Sc, opcLoc, BO_Add, result.take(), one);
+  } else {
+    result = S.BuildBinOp(Sc, opcLoc, BO_Sub, result.take(), one);
+  }
+  if (result.isInvalid()) return ExprError();
+
+  // Store that back into the result.  The value stored is the result
+  // of a prefix operation.
+  result = buildSet(result.take(), opcLoc,
+             UnaryOperator::isPrefix(opcode) && assignmentsHaveResult());
+  if (result.isInvalid()) return ExprError();
+  addSemanticExpr(result.take());
+
+  UnaryOperator *syntactic =
+    new (S.Context) UnaryOperator(syntacticOp, opcode, resultType,
+                                  VK_LValue, OK_Ordinary, opcLoc);
+  return complete(syntactic);
+}
+
+
+//===----------------------------------------------------------------------===//
+//  Objective-C @property and implicit property references
+//===----------------------------------------------------------------------===//
+
+/// Look up a method in the receiver type of an Objective-C property
+/// reference.
 static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
                                             const ObjCPropertyRefExpr *PRE) {
   if (PRE->isObjectReceiver()) {
     const ObjCObjectPointerType *PT =
       PRE->getBase()->getType()->castAs<ObjCObjectPointerType>();
+
+    // Special case for 'self' in class method implementations.
+    if (PT->isObjCClassType() &&
+        S.isSelfExpr(const_cast<Expr*>(PRE->getBase()))) {
+      // This cast is safe because isSelfExpr is only true within
+      // methods.
+      ObjCMethodDecl *method =
+        cast<ObjCMethodDecl>(S.CurContext->getNonClosureAncestor());
+      return S.LookupMethodInObjectType(sel,
+                 S.Context.getObjCInterfaceType(method->getClassInterface()),
+                                        /*instance*/ false);
+    }
+
     return S.LookupMethodInObjectType(sel, PT->getPointeeType(), true);
   }
 
@@ -59,281 +412,374 @@ static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
   return S.LookupMethodInObjectType(sel, IT, false);
 }
 
-ExprResult Sema::checkPseudoObjectRValue(Expr *E) {
-  assert(E->getValueKind() == VK_LValue &&
-         E->getObjectKind() == OK_ObjCProperty);
-  const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
-
-  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;
-  QualType T;
-  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();
-      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();
+bool ObjCPropertyOpBuilder::findGetter() {
+  if (Getter) return true;
+
+  Getter = LookupMethodInReceiverType(S, RefExpr->getGetterSelector(), RefExpr);
+  return (Getter != 0);
+}
+
+/// Try to find the most accurate setter declaration for the property
+/// reference.
+///
+/// \return true if a setter was found, in which case Setter 
+bool ObjCPropertyOpBuilder::findSetter() {
+  // For implicit properties, just trust the lookup we already did.
+  if (RefExpr->isImplicitProperty()) {
+    if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) {
+      Setter = setter;
+      SetterSelector = setter->getSelector();
+      return true;
     } else {
-      T = prop->getType();
-      VK = Expr::getValueKindForType(T);
-      T = T.getNonLValueExprType(Context);
+      IdentifierInfo *getterName =
+        RefExpr->getImplicitPropertyGetter()->getSelector()
+          .getIdentifierInfoForSlot(0);
+      SetterSelector =
+        SelectorTable::constructSetterName(S.PP.getIdentifierTable(),
+                                           S.PP.getSelectorTable(),
+                                           getterName);
+      return false;
     }
   }
 
-  E->setType(T);
-  E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK);
+  // 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)) {
+    Setter = setter;
+    return true;
+  }
+
+  // That can fail in the somewhat crazy situation that we're
+  // type-checking a message send within the @interface declaration
+  // that declared the @property.  But it's not clear that that's
+  // valuable to support.
+
+  return false;
+}
+
+/// Capture the base object of an Objective-C property expression.
+Expr *ObjCPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) {
+  assert(InstanceReceiver == 0);
+
+  // If we have a base, capture it in an OVE and rebuild the syntactic
+  // form to use the OVE as its base.
+  if (RefExpr->isObjectReceiver()) {
+    InstanceReceiver = capture(RefExpr->getBase());
+
+    syntacticBase =
+      ObjCPropertyRefRebuilder(S, InstanceReceiver).rebuild(syntacticBase);
+  }
+
+  return syntacticBase;
+}
+
+/// Load from an Objective-C property reference.
+ExprResult ObjCPropertyOpBuilder::buildGet() {
+  findGetter();
+  assert(Getter);
   
-  ExprResult Result = MaybeBindToTemporary(E);
-  if (!Result.isInvalid())
-    E = Result.take();
+  QualType receiverType;
+  SourceLocation superLoc;
+  if (RefExpr->isClassReceiver()) {
+    receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());
+  } else if (RefExpr->isSuperReceiver()) {
+    superLoc = RefExpr->getReceiverLocation();
+    receiverType = RefExpr->getSuperReceiverType();
+  } else {
+    assert(InstanceReceiver);
+    receiverType = InstanceReceiver->getType();
+  }
 
-  return Owned(E);
+  // Build a message-send.
+  ExprResult msg;
+  if (Getter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
+    assert(InstanceReceiver || RefExpr->isSuperReceiver());
+    msg = S.BuildInstanceMessage(InstanceReceiver, receiverType, superLoc,
+                                 Getter->getSelector(), Getter,
+                                 GenericLoc, GenericLoc, GenericLoc,
+                                 MultiExprArg());
+  } else {
+    TypeSourceInfo *receiverTypeInfo = 0;
+    if (!RefExpr->isSuperReceiver())
+      receiverTypeInfo = S.Context.getTrivialTypeSourceInfo(receiverType);
+
+    msg = S.BuildClassMessage(receiverTypeInfo, receiverType, superLoc,
+                              Getter->getSelector(), Getter,
+                              GenericLoc, GenericLoc, GenericLoc,
+                              MultiExprArg());
+  }
+  return msg;
 }
 
-namespace {
-  struct PseudoObjectInfo {
-    const ObjCPropertyRefExpr *RefExpr;
-    bool HasSetter;
-    Selector SetterSelector;
-    ParmVarDecl *SetterParam;
-    QualType SetterParamType;
+/// Store to an Objective-C property reference.
+///
+/// \param bindSetValueAsResult - If true, capture the actual
+///   value being set as the value of the property operation.
+ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
+                                           bool captureSetValueAsResult) {
+  bool hasSetter = findSetter();
+  assert(hasSetter); (void) hasSetter;
+
+  QualType receiverType;
+  SourceLocation superLoc;
+  if (RefExpr->isClassReceiver()) {
+    receiverType = S.Context.getObjCInterfaceType(RefExpr->getClassReceiver());
+  } else if (RefExpr->isSuperReceiver()) {
+    superLoc = RefExpr->getReceiverLocation();
+    receiverType = RefExpr->getSuperReceiverType();
+  } else {
+    assert(InstanceReceiver);
+    receiverType = InstanceReceiver->getType();
+  }
 
-    void setSetter(ObjCMethodDecl *setter) {
-      HasSetter = true;
-      SetterParam = *setter->param_begin();
-      SetterParamType = SetterParam->getType().getUnqualifiedType();
+  // Use assignment constraints when possible; they give us better
+  // diagnostics.  "When possible" basically means anything except a
+  // C++ class type.
+  if (!S.getLangOptions().CPlusPlus || !op->getType()->isRecordType()) {
+    QualType paramType = (*Setter->param_begin())->getType();
+    if (!S.getLangOptions().CPlusPlus || !paramType->isRecordType()) {
+      ExprResult opResult = op;
+      Sema::AssignConvertType assignResult
+        = S.CheckSingleAssignmentConstraints(paramType, opResult);
+      if (S.DiagnoseAssignmentResult(assignResult, opcLoc, paramType,
+                                     op->getType(), opResult.get(),
+                                     Sema::AA_Assigning))
+        return ExprError();
+
+      op = opResult.take();
+      assert(op && "successful assignment left argument invalid?");
     }
+  }
 
-    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;
-      }
+  // Arguments.
+  Expr *args[] = { op };
 
-      // For explicit properties, this is more involved.
-      ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();
-      SetterSelector = prop->getSetterName();
+  // Build a message-send.
+  ExprResult msg;
+  if (Setter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
+    msg = S.BuildInstanceMessage(InstanceReceiver, receiverType, superLoc,
+                                 SetterSelector, Setter,
+                                 GenericLoc, GenericLoc, GenericLoc,
+                                 MultiExprArg(args, 1));
+  } else {
+    TypeSourceInfo *receiverTypeInfo = 0;
+    if (!RefExpr->isSuperReceiver())
+      receiverTypeInfo = S.Context.getTrivialTypeSourceInfo(receiverType);
+
+    msg = S.BuildClassMessage(receiverTypeInfo, receiverType, superLoc,
+                              SetterSelector, Setter,
+                              GenericLoc, GenericLoc, GenericLoc,
+                              MultiExprArg(args, 1));
+  }
 
-      // Do a normal method lookup first.
-      if (ObjCMethodDecl *setter =
-            LookupMethodInReceiverType(S, SetterSelector, RefExpr)) {
-        setSetter(setter);
-        return;
-      }
+  if (!msg.isInvalid() && captureSetValueAsResult) {
+    ObjCMessageExpr *msgExpr =
+      cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit());
+    Expr *arg = msgExpr->getArg(0);
+    msgExpr->setArg(0, captureValueAsResult(arg));
+  }
 
-      // If that failed, trust the type on the @property declaration.
-      if (!prop->isReadOnly()) {
-        HasSetter = true;
-        SetterParamType = prop->getType().getUnqualifiedType();
-      }
+  return msg;
+}
+
+/// @property-specific behavior for doing lvalue-to-rvalue conversion.
+ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) {
+  // Explicit properties always have getters, but implicit ones don't.
+  // Check that before proceeding.
+  if (RefExpr->isImplicitProperty() &&
+      !RefExpr->getImplicitPropertyGetter()) {
+    S.Diag(RefExpr->getLocation(), diag::err_getter_not_found)
+      << RefExpr->getBase()->getType();
+    return ExprError();
+  }
+
+  ExprResult result = PseudoOpBuilder::buildRValueOperation(op);
+  if (result.isInvalid()) return ExprError();
+
+  if (RefExpr->isExplicitProperty() && !Getter->hasRelatedResultType())
+    S.DiagnosePropertyAccessorMismatch(RefExpr->getExplicitProperty(),
+                                       Getter, RefExpr->getLocation());
+
+  // As a special case, if the method returns 'id', try to get
+  // a better type from the property.
+  if (RefExpr->isExplicitProperty() && result.get()->isRValue() &&
+      result.get()->getType()->isObjCIdType()) {
+    QualType propType = RefExpr->getExplicitProperty()->getType();
+    if (const ObjCObjectPointerType *ptr
+          = propType->getAs<ObjCObjectPointerType>()) {
+      if (!ptr->isObjCIdType())
+        result = S.ImpCastExprToType(result.get(), propType, CK_BitCast);
     }
-  };
+  }
+
+  return result;
 }
 
-/// 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);
+/// Try to build this as a call to a getter that returns a reference.
+///
+/// \return true if it was possible, whether or not it actually
+///   succeeded
+bool ObjCPropertyOpBuilder::tryBuildGetOfReference(Expr *op,
+                                                   ExprResult &result) {
+  if (!S.getLangOptions().CPlusPlus) return false;
+
+  findGetter();
+  assert(Getter && "property has no setter and no getter!");
+
+  // Only do this if the getter returns an l-value reference type.
+  QualType resultType = Getter->getResultType();
+  if (!resultType->isLValueReferenceType()) return false;
+
+  result = buildRValueOperation(op);
+  return true;
+}
+
+/// @property-specific behavior for doing assignments.
+ExprResult
+ObjCPropertyOpBuilder::buildAssignmentOperation(Scope *Sc,
+                                                SourceLocation opcLoc,
+                                                BinaryOperatorKind opcode,
+                                                Expr *LHS, Expr *RHS) {
+  assert(BinaryOperator::isAssignmentOp(opcode));
 
   // 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);
+  if (!findSetter()) {
+    ExprResult result;
+    if (tryBuildGetOfReference(LHS, result)) {
+      if (result.isInvalid()) return ExprError();
+      return S.BuildBinOp(Sc, opcLoc, opcode, result.take(), RHS);
     }
 
     // Otherwise, it's an error.
-    Diag(opcLoc, diag::err_nosetter_property_incdec)
-      << unsigned(info.RefExpr->isImplicitProperty())
-      << unsigned(UnaryOperator::isDecrementOp(opcode))
-      << info.SetterSelector
-      << op->getSourceRange();
+    S.Diag(opcLoc, diag::err_nosetter_property_assignment)
+      << unsigned(RefExpr->isImplicitProperty())
+      << SetterSelector
+      << LHS->getSourceRange() << RHS->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();
+  // If there is a setter, we definitely want to use it.
+
+  // Verify that we can do a compound assignment.
+  if (opcode != BO_Assign && !findGetter()) {
+    S.Diag(opcLoc, diag::err_nogetter_property_compound_assignment)
+      << LHS->getSourceRange() << RHS->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);
+  ExprResult result =
+    PseudoOpBuilder::buildAssignmentOperation(Sc, opcLoc, opcode, LHS, RHS);
   if (result.isInvalid()) return ExprError();
 
-  // Change the object kind back.
-  op->setObjectKind(OK_ObjCProperty);
+  // Various warnings about property assignments in ARC.
+  if (S.getLangOptions().ObjCAutoRefCount && InstanceReceiver) {
+    S.checkRetainCycles(InstanceReceiver->getSourceExpr(), RHS);
+    S.checkUnsafeExprAssigns(opcLoc, LHS, RHS);
+  }
+
   return result;
 }
 
-ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
-                                             BinaryOperatorKind opcode,
-                                             Expr *LHS, Expr *RHS) {
-  assert(BinaryOperator::isAssignmentOp(opcode));
-  PseudoObjectInfo info(*this, LHS);
-
+/// @property-specific behavior for doing increments and decrements.
+ExprResult
+ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc,
+                                            UnaryOperatorKind opcode,
+                                            Expr *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>()) {
-      LHS = ImplicitCastExpr::Create(Context, refType->getPointeeType(),
-                                     CK_GetObjCProperty, LHS, 0, VK_LValue);
-      return BuildBinOp(S, opcLoc, opcode, LHS, RHS);
+  if (!findSetter()) {
+    ExprResult result;
+    if (tryBuildGetOfReference(op, result)) {
+      if (result.isInvalid()) return ExprError();
+      return S.BuildUnaryOp(Sc, opcLoc, opcode, result.take());
     }
 
     // Otherwise, it's an error.
-    Diag(opcLoc, diag::err_nosetter_property_assignment)
-      << unsigned(info.RefExpr->isImplicitProperty())
-      << info.SetterSelector
-      << LHS->getSourceRange() << RHS->getSourceRange();
+    S.Diag(opcLoc, diag::err_nosetter_property_incdec)
+      << unsigned(RefExpr->isImplicitProperty())
+      << unsigned(UnaryOperator::isDecrementOp(opcode))
+      << SetterSelector
+      << op->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)
-        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);
+  // We also need a getter.
+  if (!findGetter()) {
+    assert(RefExpr->isImplicitProperty());
+    S.Diag(opcLoc, diag::err_nogetter_property_incdec)
+      << unsigned(UnaryOperator::isDecrementOp(opcode))
+      << RefExpr->getImplicitPropertyGetter()->getSelector() // FIXME!
+      << op->getSourceRange();
+    return ExprError();
+  }
 
-      if (!RHSResult.isInvalid()) RHS = RHSResult.take();
-      if (resultType.isNull()) return ExprError();
-    }
+  return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op);
+}
 
-    // 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);
+//===----------------------------------------------------------------------===//
+//  General Sema routines.
+//===----------------------------------------------------------------------===//
 
-    return new (Context) BinaryOperator(LHS, RHS, opcode, RHS->getType(),
-                                        RHS->getValueKind(),
-                                        RHS->getObjectKind(),
-                                        opcLoc);
+ExprResult Sema::checkPseudoObjectRValue(Expr *E) {
+  Expr *opaqueRef = E->IgnoreParens();
+  if (ObjCPropertyRefExpr *refExpr
+        = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
+    ObjCPropertyOpBuilder builder(*this, refExpr);
+    return builder.buildRValueOperation(E);
+  } else {
+    llvm_unreachable("unknown pseudo-object kind!");
   }
+}
 
-  // 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();
+/// Check an increment or decrement of a pseudo-object expression.
+ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc,
+                                         UnaryOperatorKind opcode, Expr *op) {
+  // Do nothing if the operand is dependent.
+  if (op->isTypeDependent())
+    return new (Context) UnaryOperator(op, opcode, Context.DependentTy,
+                                       VK_RValue, OK_Ordinary, opcLoc);
+
+  assert(UnaryOperator::isIncrementDecrementOp(opcode));
+  Expr *opaqueRef = op->IgnoreParens();
+  if (ObjCPropertyRefExpr *refExpr
+        = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
+    ObjCPropertyOpBuilder builder(*this, refExpr);
+    return builder.buildIncDecOperation(Sc, opcLoc, opcode, op);
+  } else {
+    llvm_unreachable("unknown pseudo-object kind!");
   }
+}
 
-  // 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();
+ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
+                                             BinaryOperatorKind opcode,
+                                             Expr *LHS, Expr *RHS) {
+  // Do nothing if either argument is dependent.
+  if (LHS->isTypeDependent() || RHS->isTypeDependent())
+    return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,
+                                        VK_RValue, OK_Ordinary, opcLoc);
+
+  // Filter out non-overload placeholder types in the RHS.
+  if (const BuiltinType *PTy = RHS->getType()->getAsPlaceholderType()) {
+    if (PTy->getKind() != BuiltinType::Overload) {
+      ExprResult result = CheckPlaceholderExpr(RHS);
+      if (result.isInvalid()) return ExprError();
+      RHS = result.take();
+    }
+  }
 
-  // Change the object kind back.
-  LHS->setObjectKind(OK_ObjCProperty);
-  return result;
+  Expr *opaqueRef = LHS->IgnoreParens();
+  if (ObjCPropertyRefExpr *refExpr
+        = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
+    ObjCPropertyOpBuilder builder(*this, refExpr);
+    return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS);
+  } else {
+    llvm_unreachable("unknown pseudo-object kind!");
+  }
 }
index 8c99e8a4de42dcb4b9506a212c3f7aaeac6be1b4..a34d83812f61972c94fd36d2d87f9cddec98cc19 100644 (file)
@@ -198,7 +198,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
       Diag(Loc, diag::warn_unused_result) << R1 << R2;
       return;
     }
-  } else if (isa<ObjCPropertyRefExpr>(E)) {
+  } else if (isa<PseudoObjectExpr>(E)) {
     DiagID = diag::warn_unused_property_expr;
   } else if (const CXXFunctionalCastExpr *FC
                                        = dyn_cast<CXXFunctionalCastExpr>(E)) {
index 5596a9a6caaef5578211b22cf2a27bb0f1f0a9bd..f55e2a706bbd0967b4d93586734542c87dd35eda 100644 (file)
@@ -6101,6 +6101,22 @@ TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) {
   return SemaRef.Owned(E);
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {
+  // Rebuild the syntactic form.
+  ExprResult result = getDerived().TransformExpr(E->getSyntacticForm());
+  if (result.isInvalid()) return ExprError();
+
+  // If that gives us a pseudo-object result back, the pseudo-object
+  // expression must have been an lvalue-to-rvalue conversion which we
+  // should reapply.
+  if (result.get()->hasPlaceholderType(BuiltinType::PseudoObject))
+    result = SemaRef.checkPseudoObjectRValue(result.take());
+
+  return result;
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr(
index e57ab1937c5b92e2b6c4774048c8dc4cb752b47f..ff306b06c9ea49d456d269ced10572711dfe3ecf 100644 (file)
@@ -775,6 +775,24 @@ void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
   E->RParenLoc = ReadSourceLocation(Record, Idx);
 }
 
+void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+  VisitExpr(E);
+  unsigned numSemanticExprs = Record[Idx++];
+  assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);
+  E->PseudoObjectExprBits.ResultIndex = Record[Idx++];
+
+  // Read the syntactic expression.
+  E->getSubExprsBuffer()[0] = Reader.ReadSubExpr();
+
+  // Read all the semantic expressions.
+  for (unsigned i = 0; i != numSemanticExprs; ++i) {
+    Expr *subExpr = Reader.ReadSubExpr();
+    if (isa<OpaqueValueExpr>(subExpr))
+      cast<OpaqueValueExpr>(subExpr)->setSourceExpr(Reader.ReadSubExpr());
+    E->getSubExprsBuffer()[i+1] = subExpr;
+  }
+}
+
 void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) {
   VisitExpr(E);
   E->setOp(AtomicExpr::AtomicOp(Record[Idx++]));
@@ -2059,6 +2077,12 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
       S = new (Context) AsTypeExpr(Empty);
       break;
 
+    case EXPR_PSEUDO_OBJECT: {
+      unsigned numSemanticExprs = Record[ASTStmtReader::NumExprFields];
+      S = PseudoObjectExpr::Create(Context, Empty, numSemanticExprs);
+      break;
+    }
+
     case EXPR_ATOMIC:
       S = new (Context) AtomicExpr(Empty);
       break;
index 61570a880a0d63de4d645ff8f5e98cfdb304a30c..a8c76b51143f91fc04c1254494903f7e2c910bdc 100644 (file)
@@ -736,6 +736,25 @@ void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
   Code = serialization::EXPR_GENERIC_SELECTION;
 }
 
+void ASTStmtWriter::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+  VisitExpr(E);
+  Record.push_back(E->getNumSemanticExprs());
+
+  // Push the result index.  Currently, this needs to exactly match
+  // the encoding used internally for ResultIndex.
+  unsigned result = E->getResultExprIndex();
+  result = (result == PseudoObjectExpr::NoResult ? 0 : result + 1);
+  Record.push_back(result);
+
+  Writer.AddStmt(E->getSyntacticForm());
+  for (PseudoObjectExpr::semantics_iterator
+         i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
+    Writer.AddStmt(*i);
+    if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(*i))
+      Writer.AddStmt(OVE->getSourceExpr());
+  }
+}
+
 void ASTStmtWriter::VisitAtomicExpr(AtomicExpr *E) {
   VisitExpr(E);
   Record.push_back(E->getOp());
index 471936c84ad2f8d08b8966733af3266f321cd62b..32cfa847e9ed30d9c44f7c5c5c494cb10e166359 100644 (file)
@@ -857,6 +857,21 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       Bldr.addNodes(Dst);
       break;
     }
+
+    case Stmt::PseudoObjectExprClass: {
+      Bldr.takeNodes(Pred);
+      const ProgramState *state = Pred->getState();
+      const PseudoObjectExpr *PE = cast<PseudoObjectExpr>(S);
+      if (const Expr *Result = PE->getResultExpr()) { 
+        SVal V = state->getSVal(Result);
+        Bldr.generateNode(S, Pred, state->BindExpr(S, V));
+      }
+      else
+        Bldr.generateNode(S, Pred, state->BindExpr(S, UnknownVal()));
+
+      Bldr.addNodes(Dst);
+      break;
+    }
   }
 }
 
index d9700fe5c75406a0400a22df8c809b8e08760df7..6f19211976b792e7e0b4f7a2757c451ba22b6547 100644 (file)
@@ -33,9 +33,10 @@ typedef enum {
   RDR10087620Enum   elem;
 }
 @property (readwrite, nonatomic) RDR10087620Enum elem;
+@end
+
 static void
 adium_media_ready_cb(RDR10087620 *InObj)
 {
   InObj.elem |= EEOne;
 }
-@end
\ No newline at end of file
index e34942a8968c8a4adaa9a804f742317305b94a5a..dfe44748e65faa03f65d8a0220d0791998be8bd4 100644 (file)
@@ -1,5 +1,10 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
 
+// This actually still works after the pseudo-object refactor, it just
+// uses messages that say 'method' instead of 'property'.  Ted wanted
+// this xfailed and filed as a bug.  rdar://problem/10402993
+// XFAIL: *
+
 /***
 This file is for testing the path-sensitive notes for retain/release errors.
 Its goal is to have simple branch coverage of any path-based diagnostics,
index bf5607b5300a96f4bae2c6fa7265fd53c9bb19b7..0f93931034d67317e3f2871a0ff863bb40a174bf 100644 (file)
@@ -1714,6 +1714,8 @@ public:
   void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U);
   void VisitVAArgExpr(VAArgExpr *E);
   void VisitSizeOfPackExpr(SizeOfPackExpr *E);
+  void VisitPseudoObjectExpr(PseudoObjectExpr *E);
+  void VisitOpaqueValueExpr(OpaqueValueExpr *E);
   
 private:
   void AddDeclarationNameInfo(Stmt *S);
@@ -2022,6 +2024,17 @@ void EnqueueVisitor::VisitVAArgExpr(VAArgExpr *E) {
 void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
   WL.push_back(SizeOfPackExprParts(E, Parent));
 }
+void EnqueueVisitor::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+  // If the opaque value has a source expression, just transparently
+  // visit that.  This is useful for (e.g.) pseudo-object expressions.
+  if (Expr *SourceExpr = E->getSourceExpr())
+    return Visit(SourceExpr);
+  AddStmt(E);
+}
+void EnqueueVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+  // Treat the expression like its syntactic form.
+  Visit(E->getSyntacticForm());
+}
 
 void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) {
   EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
@@ -2702,6 +2715,11 @@ static Decl *getDeclFromExpr(Stmt *E) {
     return RE->getDecl();
   if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E))
     return PRE->isExplicitProperty() ? PRE->getExplicitProperty() : 0;
+  if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+    return getDeclFromExpr(POE->getSyntacticForm());
+  if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+    if (Expr *Src = OVE->getSourceExpr())
+      return getDeclFromExpr(Src);
       
   if (CallExpr *CE = dyn_cast<CallExpr>(E))
     return getDeclFromExpr(CE->getCallee());
index ae3aeea06c744de249b00c354e9115fc1192af49..202a19254e9dff0deaaeaeb7a93a78b074adfabb 100644 (file)
@@ -219,7 +219,6 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
   case Stmt::MaterializeTemporaryExprClass:
   case Stmt::ObjCIndirectCopyRestoreExprClass:
   case Stmt::OffsetOfExprClass:
-  case Stmt::OpaqueValueExprClass:
   case Stmt::ParenListExprClass:
   case Stmt::PredefinedExprClass:
   case Stmt::ShuffleVectorExprClass:
@@ -229,6 +228,16 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
     K = CXCursor_UnexposedExpr;
     break;
 
+  case Stmt::OpaqueValueExprClass:
+    if (Expr *Src = cast<OpaqueValueExpr>(S)->getSourceExpr())
+      return MakeCXCursor(Src, Parent, TU, RegionOfInterest);
+    K = CXCursor_UnexposedExpr;
+    break;
+
+  case Stmt::PseudoObjectExprClass:
+    return MakeCXCursor(cast<PseudoObjectExpr>(S)->getSyntacticForm(),
+                        Parent, TU, RegionOfInterest);
+
   case Stmt::CompoundStmtClass:
     K = CXCursor_CompoundStmt;
     break;