diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index de58597e298d..850c77c4b7d3 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -296,8 +296,11 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { const BlockDeclRefExpr *BDRE = dyn_cast(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(VD), - VD->getType(), - SourceLocation()); + VD->getType().getNonReferenceType(), + SourceLocation()); + if (VD->getType()->isReferenceType()) + E = new (getContext()) + UnaryOperator(const_cast(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/clang/test/CodeGenCXX/reference-in-block-args.cpp b/clang/test/CodeGenCXX/reference-in-block-args.cpp new file mode 100644 index 000000000000..1ff1ae2dc856 --- /dev/null +++ b/clang/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(); +}