Index: cfe/trunk/lib/CodeGen/CGBlocks.h =================================================================== --- cfe/trunk/lib/CodeGen/CGBlocks.h +++ cfe/trunk/lib/CodeGen/CGBlocks.h @@ -159,6 +159,11 @@ EHScopeStack::stable_iterator Cleanup; CharUnits::QuantityType Offset; + /// Type of the capture field. Normally, this is identical to the type of + /// the capture's VarDecl, but can be different if there is an enclosing + /// lambda. + QualType FieldType; + public: bool isIndex() const { return (Data & 1) != 0; } bool isConstant() const { return !isIndex(); } @@ -185,10 +190,16 @@ return reinterpret_cast(Data); } - static Capture makeIndex(unsigned index, CharUnits offset) { + QualType fieldType() const { + return FieldType; + } + + static Capture makeIndex(unsigned index, CharUnits offset, + QualType FieldType) { Capture v; v.Data = (index << 1) | 1; v.Offset = offset.getQuantity(); + v.FieldType = FieldType; return v; } Index: cfe/trunk/lib/CodeGen/CGBlocks.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGBlocks.cpp +++ cfe/trunk/lib/CodeGen/CGBlocks.cpp @@ -199,13 +199,14 @@ Qualifiers::ObjCLifetime Lifetime; const BlockDecl::Capture *Capture; // null for 'this' llvm::Type *Type; + QualType FieldType; BlockLayoutChunk(CharUnits align, CharUnits size, Qualifiers::ObjCLifetime lifetime, const BlockDecl::Capture *capture, - llvm::Type *type) + llvm::Type *type, QualType fieldType) : Alignment(align), Size(size), Lifetime(lifetime), - Capture(capture), Type(type) {} + Capture(capture), Type(type), FieldType(fieldType) {} /// Tell the block info that this chunk has the given field index. void setIndex(CGBlockInfo &info, unsigned index, CharUnits offset) { @@ -213,8 +214,8 @@ info.CXXThisIndex = index; info.CXXThisOffset = offset; } else { - info.Captures.insert({Capture->getVariable(), - CGBlockInfo::Capture::makeIndex(index, offset)}); + auto C = CGBlockInfo::Capture::makeIndex(index, offset, FieldType); + info.Captures.insert({Capture->getVariable(), C}); } } }; @@ -363,7 +364,7 @@ layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first, Qualifiers::OCL_None, - nullptr, llvmType)); + nullptr, llvmType, thisType)); } // Next, all the block captures. @@ -380,7 +381,7 @@ layout.push_back(BlockLayoutChunk(align, CGM.getPointerSize(), Qualifiers::OCL_None, &CI, - CGM.VoidPtrTy)); + CGM.VoidPtrTy, variable->getType())); continue; } @@ -436,6 +437,14 @@ } QualType VT = variable->getType(); + + // If the variable is captured by an enclosing block or lambda expression, + // use the type of the capture field. + if (CGF->BlockInfo && CI.isNested()) + VT = CGF->BlockInfo->getCapture(variable).fieldType(); + else if (auto *FD = CGF->LambdaCaptureFields.lookup(variable)) + VT = FD->getType(); + CharUnits size = C.getTypeSizeInChars(VT); CharUnits align = C.getDeclAlign(variable); @@ -444,7 +453,8 @@ llvm::Type *llvmType = CGM.getTypes().ConvertTypeForMem(VT); - layout.push_back(BlockLayoutChunk(align, size, lifetime, &CI, llvmType)); + layout.push_back( + BlockLayoutChunk(align, size, lifetime, &CI, llvmType, VT)); } // If that was everything, we're done here. @@ -775,7 +785,7 @@ // Ignore constant captures. if (capture.isConstant()) continue; - QualType type = variable->getType(); + QualType type = capture.fieldType(); // This will be a [[type]]*, except that a byref entry will just be // an i8**. @@ -1033,9 +1043,8 @@ variable->getName()); } - if (auto refType = variable->getType()->getAs()) { + if (auto refType = capture.fieldType()->getAs()) addr = EmitLoadOfReference(addr, refType); - } return addr; } Index: cfe/trunk/test/CodeGenObjCXX/lambda-expressions.mm =================================================================== --- cfe/trunk/test/CodeGenObjCXX/lambda-expressions.mm +++ cfe/trunk/test/CodeGenObjCXX/lambda-expressions.mm @@ -4,6 +4,8 @@ typedef int (^fp)(); fp f() { auto x = []{ return 3; }; return x; } +// ARC: %[[LAMBDACLASS:.*]] = type { i32 } + // MRC: @OBJC_METH_VAR_NAME{{.*}} = private global [5 x i8] c"copy\00" // MRC: @OBJC_METH_VAR_NAME{{.*}} = private global [12 x i8] c"autorelease\00" // MRC-LABEL: define i32 ()* @_Z1fv( @@ -60,6 +62,40 @@ } @end +// ARC: define void @_ZN13LambdaCapture4foo1ERi(i32* dereferenceable(4) %{{.*}}) +// ARC: %[[CAPTURE0:.*]] = getelementptr inbounds %[[LAMBDACLASS]], %[[LAMBDACLASS]]* %{{.*}}, i32 0, i32 0 +// ARC: store i32 %{{.*}}, i32* %[[CAPTURE0]] + +// ARC: define internal void @"_ZZN13LambdaCapture4foo1ERiENK3$_3clEv"(%[[LAMBDACLASS]]* %{{.*}}) +// ARC: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }> +// ARC: %[[CAPTURE1:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %[[BLOCK]], i32 0, i32 5 +// ARC: store i32 %{{.*}}, i32* %[[CAPTURE1]] + +// ARC: define internal void @"___ZZN13LambdaCapture4foo1ERiENK3$_3clEv_block_invoke" +// ARC: %[[CAPTURE2:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %{{.*}}, i32 0, i32 5 +// ARC: store i32 %{{.*}}, i32* %[[CAPTURE2]] + +// ARC: define internal void @"___ZZN13LambdaCapture4foo1ERiENK3$_3clEv_block_invoke_2"(i8* %{{.*}}) +// ARC: %[[CAPTURE3:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32 }>* %{{.*}}, i32 0, i32 5 +// ARC: %[[V1:.*]] = load i32, i32* %[[CAPTURE3]] +// ARC: store i32 %[[V1]], i32* @_ZN13LambdaCapture1iE + +namespace LambdaCapture { + int i; + void foo1(int &a) { + auto lambda = [a]{ + auto block1 = ^{ + auto block2 = ^{ + i = a; + }; + block2(); + }; + block1(); + }; + lambda(); + } +} + // ARC-LABEL: define linkonce_odr i32 ()* @_ZZNK13StaticMembersIfE1fMUlvE_clEvENKUlvE_cvU13block_pointerFivEEv // Check lines for BlockInLambda test below