aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CGExprAgg.cpp19
-rw-r--r--test/CodeGen/block-byref-aggr.c17
2 files changed, 35 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
diff --git a/test/CodeGen/block-byref-aggr.c b/test/CodeGen/block-byref-aggr.c
new file mode 100644
index 0000000000..3027df0486
--- /dev/null
+++ b/test/CodeGen/block-byref-aggr.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10 | FileCheck %s
+// rdar://9309454
+
+typedef struct { int v; } RetType;
+
+RetType func();
+
+int main () {
+ __attribute__((__blocks__(byref))) RetType a = {100};
+
+ a = func();
+}
+// CHECK: [[C1:%.*]] = call i32 (...)* @func()
+// CHECK-NEXT: [[CO:%.*]] = getelementptr
+// CHECK-NEXT: store i32 [[C1]], i32* [[CO]]
+// CHECK-NEXT: [[FORWARDING:%.*]] = getelementptr inbounds [[BR:%.*]]* [[A:%.*]], i32 0, i32 1
+// CHECK-NEXT: [[O:%.*]] = load [[BR]]** [[FORWARDING]]