aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGExprAgg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/CGExprAgg.cpp')
-rw-r--r--lib/CodeGen/CGExprAgg.cpp19
1 files changed, 18 insertions, 1 deletions
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 87d3819e48..2f2f7c1fe5 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -393,7 +393,24 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
E->getRHS()->getType())
&& "Invalid assignment");
- // FIXME: __block variables need the RHS evaluated first!
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getLHS()))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (VD->hasAttr<BlocksAttr>() &&
+ E->getRHS()->HasSideEffects(CGF.getContext())) {
+ // When __block variable on LHS, the RHS must be evaluated first
+ // as it may change the 'forwarding' field via call to Block_copy.
+ LValue RHS = CGF.EmitLValue(E->getRHS());
+ LValue LHS = CGF.EmitLValue(E->getLHS());
+ bool GCollection = false;
+ if (CGF.getContext().getLangOptions().getGCMode())
+ GCollection = TypeRequiresGCollection(E->getLHS()->getType());
+ // Codegen the RHS so that it stores directly into the LHS.
+ Dest = AggValueSlot::forLValue(LHS, true, GCollection);
+ EmitFinalDestCopy(E, RHS, true);
+ return;
+ }
+ }
+
LValue LHS = CGF.EmitLValue(E->getLHS());
// We have to special case property setters, otherwise we must have