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

Reply via email to