diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e593ab9419ad..79a8fd57ee33 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1689,8 +1689,8 @@ def err_init_conversion_failed : Error< "cannot initialize %select{a variable|a parameter|return object|an " "exception object|a member subobject|an array element|a new value|a value|a " "base class|a constructor delegation|a vector element|a block element|a " - "complex element|a lambda capture|a compound literal initializer|a " - "related result|a parameter of CF audited function}0 " + "block element|a complex element|a lambda capture|a compound literal " + "initializer|a related result|a parameter of CF audited function}0 " "%diff{of type $ with an %select{rvalue|lvalue}2 of type $|" "with an %select{rvalue|lvalue}2 of incompatible type}1,3" "%select{|: different classes%diff{ ($ vs $)|}5,6" diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h index c16b3d34eab4..bd07b9ea9aee 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -70,6 +70,9 @@ public: /// \brief The entity being initialized is a field of block descriptor for /// the copied-in c++ object. EK_BlockElement, + /// The entity being initialized is a field of block descriptor for the + /// copied-in lambda object that's used in the lambda to block conversion. + EK_LambdaToBlockConversionBlockElement, /// \brief The entity being initialized is the real or imaginary part of a /// complex number. EK_ComplexElement, @@ -260,7 +263,13 @@ public: QualType Type, bool NRVO) { return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO); } - + + static InitializedEntity InitializeLambdaToBlock(SourceLocation BlockVarLoc, + QualType Type, bool NRVO) { + return InitializedEntity(EK_LambdaToBlockConversionBlockElement, + BlockVarLoc, Type, NRVO); + } + /// \brief Create the initialization entity for an exception object. static InitializedEntity InitializeException(SourceLocation ThrowLoc, QualType Type, bool NRVO) { diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index b11769bf4289..b6f799b62119 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -950,6 +950,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaToBlockConversionBlockElement: case InitializedEntity::EK_Binding: llvm_unreachable("unexpected braced scalar init"); } @@ -2934,6 +2935,7 @@ DeclarationName InitializedEntity::getName() const { case EK_VectorElement: case EK_ComplexElement: case EK_BlockElement: + case EK_LambdaToBlockConversionBlockElement: case EK_CompoundLiteralInit: case EK_RelatedResult: return DeclarationName(); @@ -2963,6 +2965,7 @@ ValueDecl *InitializedEntity::getDecl() const { case EK_VectorElement: case EK_ComplexElement: case EK_BlockElement: + case EK_LambdaToBlockConversionBlockElement: case EK_LambdaCapture: case EK_CompoundLiteralInit: case EK_RelatedResult: @@ -2992,6 +2995,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_VectorElement: case EK_ComplexElement: case EK_BlockElement: + case EK_LambdaToBlockConversionBlockElement: case EK_LambdaCapture: case EK_RelatedResult: break; @@ -3025,6 +3029,9 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { case EK_VectorElement: OS << "VectorElement " << Index; break; case EK_ComplexElement: OS << "ComplexElement " << Index; break; case EK_BlockElement: OS << "Block"; break; + case EK_LambdaToBlockConversionBlockElement: + OS << "Block (lambda)"; + break; case EK_LambdaCapture: OS << "LambdaCapture "; OS << DeclarationName(Capture.VarID); @@ -3622,9 +3629,13 @@ static void TryConstructorInitialization(Sema &S, // destination object. // Per DR (no number yet), this does not apply when initializing a base // class or delegating to another constructor from a mem-initializer. + // ObjC++: Lambda captured by the block in the lambda to block conversion + // should avoid copy elision. if (S.getLangOpts().CPlusPlus1z && Entity.getKind() != InitializedEntity::EK_Base && Entity.getKind() != InitializedEntity::EK_Delegating && + Entity.getKind() != + InitializedEntity::EK_LambdaToBlockConversionBlockElement && UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isRValue() && S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(), DestType)) { // Convert qualifications if necessary. @@ -5488,6 +5499,7 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) { case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaToBlockConversionBlockElement: case InitializedEntity::EK_LambdaCapture: case InitializedEntity::EK_CompoundLiteralInit: return Sema::AA_Initializing; @@ -5511,6 +5523,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaToBlockConversionBlockElement: case InitializedEntity::EK_LambdaCapture: case InitializedEntity::EK_CompoundLiteralInit: return false; @@ -5537,6 +5550,7 @@ static bool shouldDestroyEntity(const InitializedEntity &Entity) { case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaToBlockConversionBlockElement: case InitializedEntity::EK_LambdaCapture: return false; @@ -5584,6 +5598,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaToBlockConversionBlockElement: case InitializedEntity::EK_CompoundLiteralInit: case InitializedEntity::EK_RelatedResult: return Initializer->getLocStart(); @@ -6021,6 +6036,7 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) { case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaToBlockConversionBlockElement: case InitializedEntity::EK_ComplexElement: // Could not determine what the full initialization is. Assume it might not // outlive the full-expression. @@ -6109,6 +6125,7 @@ static const InitializedEntity *getEntityForTemporaryLifetimeExtension( return FallbackDecl; case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_LambdaToBlockConversionBlockElement: case InitializedEntity::EK_LambdaCapture: case InitializedEntity::EK_Exception: case InitializedEntity::EK_VectorElement: diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 2b13f2af6856..7a9a8ff911aa 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1649,10 +1649,9 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation, CallOperator->markUsed(Context); ExprResult Init = PerformCopyInitialization( - InitializedEntity::InitializeBlock(ConvLocation, - Src->getType(), - /*NRVO=*/false), - CurrentLocation, Src); + InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType(), + /*NRVO=*/false), + CurrentLocation, Src); if (!Init.isInvalid()) Init = ActOnFinishFullExpr(Init.get()); diff --git a/clang/test/CodeGenObjCXX/lambda-to-block.mm b/clang/test/CodeGenObjCXX/lambda-to-block.mm new file mode 100644 index 000000000000..a8d0718b1244 --- /dev/null +++ b/clang/test/CodeGenObjCXX/lambda-to-block.mm @@ -0,0 +1,18 @@ +// 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: define internal void @__copy_helper_block_ +// CHECK: call void @"_ZZ9hasLambda8CopyableEN3$_0C1ERKS0_" +// CHECK-LABEL: define internal void @"_ZZ9hasLambda8CopyableEN3$_0C2ERKS0_" +// CHECK: call void @_ZN8CopyableC1ERKS_