]> granicus.if.org Git - clang/commitdiff
Adds IRGen support for captured rvalue references in blocks.
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 31 Oct 2011 23:44:33 +0000 (23:44 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 31 Oct 2011 23:44:33 +0000 (23:44 +0000)
In this case, temporary value is copied into block descriptor
as their own copy to work on. // rdar://9971124

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

lib/CodeGen/CGBlocks.cpp
lib/CodeGen/CGExpr.cpp
test/CodeGenCXX/block-rvalue-reference-capture.cpp [new file with mode: 0644]

index 969495376642af2bdb20f5d12b6c7ba91dd26f60..19262ec54f6ef69188fcc3873e798fca5fac306a 100644 (file)
@@ -380,13 +380,18 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
       }
     }
 
-    CharUnits size = C.getTypeSizeInChars(variable->getType());
-    CharUnits align = C.getDeclAlign(variable);
+    bool IsRValReference = variable->getType()->isRValueReferenceType();
+    QualType VT = 
+      IsRValReference ? variable->getType()->getPointeeType() 
+                      : variable->getType();
+    CharUnits size = C.getTypeSizeInChars(VT);
+    CharUnits align = C.getDeclAlign(variable, IsRValReference);
+    
     maxFieldAlign = std::max(maxFieldAlign, align);
 
     llvm::Type *llvmType =
-      CGM.getTypes().ConvertTypeForMem(variable->getType());
-
+      CGM.getTypes().ConvertTypeForMem(VT);
+    
     layout.push_back(BlockLayoutChunk(align, size, &*ci, llvmType));
   }
 
@@ -594,30 +599,32 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
       EmitSynthesizedCXXCopyCtor(blockField, src, copyExpr);
 
     // If it's a reference variable, copy the reference into the block field.
-    } else if (type->isReferenceType()) {
+    } else if (type->isReferenceType() && !type->isRValueReferenceType()) {
       Builder.CreateStore(Builder.CreateLoad(src, "ref.val"), blockField);
 
     // Otherwise, fake up a POD copy into the block field.
     } else {
+      QualType VT = 
+        (!type->isRValueReferenceType()) ? type : type->getPointeeType();
       // Fake up a new variable so that EmitScalarInit doesn't think
       // we're referring to the variable in its own initializer.
       ImplicitParamDecl blockFieldPseudoVar(/*DC*/ 0, SourceLocation(),
-                                            /*name*/ 0, type);
+                                            /*name*/ 0, VT);
 
       // We use one of these or the other depending on whether the
       // reference is nested.
-      DeclRefExpr notNested(const_cast<VarDecl*>(variable), type, VK_LValue,
+      DeclRefExpr notNested(const_cast<VarDecl*>(variable), VT, VK_LValue,
                             SourceLocation());
-      BlockDeclRefExpr nested(const_cast<VarDecl*>(variable), type,
+      BlockDeclRefExpr nested(const_cast<VarDecl*>(variable), VT,
                               VK_LValue, SourceLocation(), /*byref*/ false);
 
       Expr *declRef = 
         (ci->isNested() ? static_cast<Expr*>(&nested) : &notNested);
 
-      ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue,
+      ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, VT, CK_LValueToRValue,
                            declRef, VK_RValue);
       EmitExprAsInit(&l2r, &blockFieldPseudoVar,
-                     MakeAddrLValue(blockField, type,
+                     MakeAddrLValue(blockField, VT,
                                     getContext().getDeclAlign(variable)
                                                 .getQuantity()),
                      /*captured by init*/ false);
@@ -789,7 +796,8 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable,
                                    variable->getNameAsString());
   }
 
-  if (variable->getType()->isReferenceType())
+  if (variable->getType()->isReferenceType() &&
+      !variable->getType()->isRValueReferenceType())
     addr = Builder.CreateLoad(addr, "ref.tmp");
 
   return addr;
index 9ad3ae8352eaee740c6d070d9296125030391d49..9680185b7f5a2a00e211e12a1e232695c3eebf2e 100644 (file)
@@ -1409,8 +1409,10 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
 }
 
 LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) {
+  bool RefAsPointee = 
+    E->getDecl()->getType()->isRValueReferenceType() ? true : false;
   unsigned Alignment =
-    getContext().getDeclAlign(E->getDecl()).getQuantity();
+    getContext().getDeclAlign(E->getDecl(), RefAsPointee).getQuantity();
   return MakeAddrLValue(GetAddrOfBlockDecl(E), E->getType(), Alignment);
 }
 
diff --git a/test/CodeGenCXX/block-rvalue-reference-capture.cpp b/test/CodeGenCXX/block-rvalue-reference-capture.cpp
new file mode 100644 (file)
index 0000000..df99e42
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -std=c++11 -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s
+// rdar://9971124
+
+int foo(int && i)
+{ 
+     return ^{ return i; }();
+}
+
+int main() {
+  return foo(100);
+}
+
+// CHECK: [[B:%.*]] = bitcast i8* [[BD:%.*]] to <{ {{.*}} i32 }>*
+// CHECK: [[C:%.*]] = getelementptr inbounds <{ {{.*}} i32 }>* [[B]]
+// CHECK: [[R:%.*]] = load i32* [[C]], align 4
+// CHECK: ret i32 [[R]]