diff options
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 18 | ||||
-rw-r--r-- | test/CodeGenCXX/reference-in-block-args.cpp | 29 |
2 files changed, 43 insertions, 4 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index de58597e29..850c77c4b7 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -296,8 +296,11 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); QualType Ty = E->getType(); if (BDRE && BDRE->isByRef()) { - Types[i+BlockFields] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0); - } else + Types[i+BlockFields] = + llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0); + } else if (BDRE && BDRE->getDecl()->getType()->isReferenceType()) { + Types[i+BlockFields] = llvm::PointerType::get(ConvertType(Ty), 0); + } else Types[i+BlockFields] = ConvertType(Ty); } @@ -359,8 +362,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { continue; } else { E = new (getContext()) DeclRefExpr(const_cast<ValueDecl*>(VD), - VD->getType(), - SourceLocation()); + VD->getType().getNonReferenceType(), + SourceLocation()); + if (VD->getType()->isReferenceType()) + E = new (getContext()) + UnaryOperator(const_cast<Expr*>(E), UnaryOperator::AddrOf, + getContext().getPointerType(E->getType()), + SourceLocation()); } } @@ -629,6 +637,8 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const ValueDecl *VD, Ty = llvm::PointerType::get(Ty, 0); V = Builder.CreateBitCast(V, Ty); + if (VD->getType()->isReferenceType()) + V = Builder.CreateLoad(V, "tmp"); } return V; } diff --git a/test/CodeGenCXX/reference-in-block-args.cpp b/test/CodeGenCXX/reference-in-block-args.cpp new file mode 100644 index 0000000000..1ff1ae2dc8 --- /dev/null +++ b/test/CodeGenCXX/reference-in-block-args.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fblocks %s -emit-llvm -o %t +// rdar: // 8041962 + +extern "C" int printf(const char*, ...); + +struct ST { + int filler; + int referrer; +}; + +void OUTER_BLOCK(void (^fixer)(ST& ref)) { + ST ref = {2, 100}; + fixer(ref); +} + +void INNER_BLOCK(int (^largeDo) ()) { + printf("%d\n", largeDo()); +} + +void scan() { + OUTER_BLOCK(^(ST &ref) { + INNER_BLOCK(^() { return ref.referrer + ref.filler; }); + }); + +} + +int main() { + scan(); +} |