Fix the instantiation of pseudo-object expressions.  This is a
really bad way to go about this, but I'm not sure there's a better
choice without substantial changes to TreeTransform --- most
notably, preserving implicit semantic nodes instead of discarding
and rebuilding them.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145480 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index 3bd671d..08b3fc8 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -790,3 +790,54 @@
     llvm_unreachable("unknown pseudo-object kind!");
   }
 }
+
+/// Given a pseudo-object reference, rebuild it without the opaque
+/// values.  Basically, undo the behavior of rebuildAndCaptureObject.
+/// This should never operate in-place.
+static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) {
+  Expr *opaqueRef = E->IgnoreParens();
+  if (ObjCPropertyRefExpr *refExpr
+        = dyn_cast<ObjCPropertyRefExpr>(opaqueRef)) {
+    OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBase());
+    return ObjCPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E);
+  } else {
+    llvm_unreachable("unknown pseudo-object kind!");
+  }
+}
+
+/// Given a pseudo-object expression, recreate what it looks like
+/// syntactically without the attendant OpaqueValueExprs.
+///
+/// This is a hack which should be removed when TreeTransform is
+/// capable of rebuilding a tree without stripping implicit
+/// operations.
+Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
+  Expr *syntax = E->getSyntacticForm();
+  if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
+    Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
+    return new (Context) UnaryOperator(op, uop->getOpcode(), uop->getType(),
+                                       uop->getValueKind(), uop->getObjectKind(),
+                                       uop->getOperatorLoc());
+  } else if (CompoundAssignOperator *cop
+               = dyn_cast<CompoundAssignOperator>(syntax)) {
+    Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());
+    Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr();
+    return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(),
+                                                cop->getType(),
+                                                cop->getValueKind(),
+                                                cop->getObjectKind(),
+                                                cop->getComputationLHSType(),
+                                                cop->getComputationResultType(),
+                                                cop->getOperatorLoc());
+  } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
+    Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
+    Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
+    return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
+                                        bop->getType(), bop->getValueKind(),
+                                        bop->getObjectKind(),
+                                        bop->getOperatorLoc());
+  } else {
+    assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
+    return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
+  }
+}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 7c1dafb..d7bdbaf 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -6104,8 +6104,14 @@
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {
-  // Rebuild the syntactic form.
-  ExprResult result = getDerived().TransformExpr(E->getSyntacticForm());
+  // Rebuild the syntactic form.  The original syntactic form has
+  // opaque-value expressions in it, so strip those away and rebuild
+  // the result.  This is a really awful way of doing this, but the
+  // better solution (rebuilding the semantic expressions and
+  // rebinding OVEs as necessary) doesn't work; we'd need
+  // TreeTransform to not strip away implicit conversions.
+  Expr *newSyntacticForm = SemaRef.recreateSyntacticForm(E);
+  ExprResult result = getDerived().TransformExpr(newSyntacticForm);
   if (result.isInvalid()) return ExprError();
 
   // If that gives us a pseudo-object result back, the pseudo-object