Index: include/clang/Sema/Initialization.h =================================================================== --- include/clang/Sema/Initialization.h +++ include/clang/Sema/Initialization.h @@ -118,6 +118,10 @@ /// \brief Whether the entity being initialized may end up using the /// named return value optimization (NRVO). bool NRVO; + + /// \brief When Kind == EK_BlockElement, this flag determines if the entity + /// is a lambda that's captured by a block it's converted to. + bool IsLambdaToBlockConversionEntity; }; struct VD { @@ -180,11 +184,11 @@ /// function, throwing an object, performing an explicit cast, or /// initializing a parameter for which there is no declaration. InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, - bool NRVO = false) - : Kind(Kind), Parent(nullptr), Type(Type), ManglingNumber(0) - { + bool NRVO = false, bool IsLambdaToBlockConversion = false) + : Kind(Kind), Parent(nullptr), Type(Type), ManglingNumber(0) { LocAndNRVO.Location = Loc.getRawEncoding(); LocAndNRVO.NRVO = NRVO; + LocAndNRVO.IsLambdaToBlockConversionEntity = IsLambdaToBlockConversion; } /// \brief Create the initialization entity for a member subobject. @@ -256,9 +260,11 @@ return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); } - static InitializedEntity InitializeBlock(SourceLocation BlockVarLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO); + static InitializedEntity + InitializeBlock(SourceLocation BlockVarLoc, QualType Type, bool NRVO, + bool IsLambdaToBlockConversion = false) { + return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO, + IsLambdaToBlockConversion); } /// \brief Create the initialization entity for an exception object. @@ -388,6 +394,10 @@ /// value optimization, which also applies to thrown objects. bool allowsNRVO() const; + /// \brief Determines whether this initialization is the lambda to block + /// entity conversion. + bool isLambdaToBlockEntity() const; + bool isParameterKind() const { return (getKind() == EK_Parameter || getKind() == EK_Parameter_CF_Audited); Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -3000,6 +3000,10 @@ return false; } +bool InitializedEntity::isLambdaToBlockEntity() const { + return Kind == EK_BlockElement && LocAndNRVO.IsLambdaToBlockConversionEntity; +} + unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { assert(getParent() != this); unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0; @@ -3625,7 +3629,8 @@ if (S.getLangOpts().CPlusPlus1z && Entity.getKind() != InitializedEntity::EK_Base && Entity.getKind() != InitializedEntity::EK_Delegating && - UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isRValue() && + !Entity.isLambdaToBlockEntity() && UnwrappedArgs.size() == 1 && + UnwrappedArgs[0]->isRValue() && S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(), DestType)) { // Convert qualifications if necessary. Sequence.AddQualificationConversionStep(DestType, VK_RValue); Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -1649,10 +1649,10 @@ CallOperator->markUsed(Context); ExprResult Init = PerformCopyInitialization( - InitializedEntity::InitializeBlock(ConvLocation, - Src->getType(), - /*NRVO=*/false), - CurrentLocation, Src); + InitializedEntity::InitializeBlock(ConvLocation, Src->getType(), + /*NRVO=*/false, + /*IsLambdaToBlockConversion=*/true), + CurrentLocation, Src); if (!Init.isInvalid()) Init = ActOnFinishFullExpr(Init.get()); Index: test/CodeGenObjCXX/lambda-to-block.mm =================================================================== --- /dev/null +++ test/CodeGenObjCXX/lambda-to-block.mm @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -std=c++1z -emit-llvm -o - %s | FileCheck %s + +// rdar://31385153 +// Shouldn't crash! + +void takesBlock(void (^)(void)); + +struct Copyable { + Copyable(const Copyable &x); +}; + +void hasLambda(Copyable x) { + takesBlock([x] () { }); +} +// CHECK-LABEL: __copy_helper_block_ +// CHECK: call void @_ZN8CopyableC1ERKS_ +// CHECK-LABE: __destroy_helper_block_