arphaman created this revision. The commit r288866 introduced guaranteed copy elision to C++ 17. This unfortunately broke the lambda to block conversion in C++17 (the compiler crashes when performing IRGen). This patch fixes the conversion by avoiding copy elision for the capture that captures the lambda that's used in the block created by lambda to block conversion process.
Repository: rL LLVM https://reviews.llvm.org/D31669 Files: include/clang/Sema/Initialization.h lib/Sema/SemaInit.cpp lib/Sema/SemaLambda.cpp test/CodeGenObjCXX/lambda-to-block.mm
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_ 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: 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: 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);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits