]> granicus.if.org Git - clang/commitdiff
Generate an AST for the conversion from a lambda closure type to a
authorDouglas Gregor <dgregor@apple.com>
Wed, 22 Feb 2012 05:02:47 +0000 (05:02 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 22 Feb 2012 05:02:47 +0000 (05:02 +0000)
block pointer that returns a block literal which captures (by copy)
the lambda closure itself. Some aspects of the block literal are left
unspecified, namely the capture variable (which doesn't actually
exist) and the body (which will be filled in by IRgen because it can't
be written as an AST).

Because we're switching to this model, this patch also eliminates
tracking the copy-initialization expression for the block capture of
the conversion function, since that information is now embedded in the
synthesized block literal. -1 side tables FTW.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151131 91177308-0d34-0410-b5e6-96231b3b80d8

20 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/DeclCXX.h
include/clang/AST/OperationKinds.h
lib/AST/DeclCXX.cpp
lib/AST/Expr.cpp
lib/AST/ExprConstant.cpp
lib/AST/StmtDumper.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGExprConstant.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaLambda.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
lib/StaticAnalyzer/Core/ExprEngineC.cpp
test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm [moved from test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp with 100% similarity]
test/PCH/cxx11-lambdas.mm [moved from test/PCH/cxx11-lambdas.cpp with 100% similarity]

index 10fc81ab22ba8b8122f85d1358de0548d320d147..26e91959624e7315cdb8866af1771080ee7e6e3f 100644 (file)
@@ -323,12 +323,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
   typedef UsuallyTinyPtrVector<const CXXMethodDecl> CXXMethodVector;
   llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
 
-  /// \brief Mapping from lambda-to-block-pointer conversion functions to the
-  /// expression used to copy the lambda object.
-  llvm::DenseMap<const CXXConversionDecl *, Expr *> LambdaBlockPointerInits;
-  
-  friend class CXXConversionDecl;
-  
   /// \brief Mapping from each declaration context to its corresponding lambda 
   /// mangling context.
   llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
index 45bb647a65d888c970987ca65a8927ec198eceee..afb53757459248a5a360fd65e1f91f2ddc5d0618 100644 (file)
@@ -2261,15 +2261,6 @@ public:
   /// a lambda closure type to a block pointer.
   bool isLambdaToBlockPointerConversion() const;
   
-  /// \brief For an implicit conversion function that converts a lambda
-  /// closure type to a block pointer, retrieve the expression used to
-  /// copy the closure object into the block.
-  Expr *getLambdaToBlockPointerCopyInit() const;
-  
-  /// \brief Set the copy-initialization expression to be used when converting
-  /// a lambda object to a block pointer.
-  void setLambdaToBlockPointerCopyInit(Expr *Init);
-  
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classof(const CXXConversionDecl *D) { return true; }
index 8cf79b2bfa8718ad8812153f7d5bbb7b6e20f942..258637d7f9bddd35a9aeeebadd0a6c4ae7ce696d 100644 (file)
@@ -281,7 +281,14 @@ enum CastKind {
   /// \brief Converts from _Atomic(T) to T.
   CK_AtomicToNonAtomic,
   /// \brief Converts from T to _Atomic(T).
-  CK_NonAtomicToAtomic
+  CK_NonAtomicToAtomic,
+  
+  /// \brief Causes a block literal to by copied to the heap and then 
+  /// autoreleased.
+  ///
+  /// This particular cast kind is used for the conversion from a C++11
+  /// lambda expression to a block pointer.
+  CK_CopyAndAutoreleaseBlockObject
 };
 
 #define CK_Invalid ((CastKind) -1)
index 9840cc7820fae5bd29357cd918391a58ac767c02..4dd44cbf179c4fe73ef4a526773454be43813ec5 100644 (file)
@@ -1770,16 +1770,6 @@ bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
          getConversionType()->isBlockPointerType();
 }
 
-Expr *CXXConversionDecl::getLambdaToBlockPointerCopyInit() const {
-  assert(isLambdaToBlockPointerConversion());
-  return getASTContext().LambdaBlockPointerInits[this];
-}
-
-void CXXConversionDecl::setLambdaToBlockPointerCopyInit(Expr *Init) {
-  assert(isLambdaToBlockPointerConversion());
-  getASTContext().LambdaBlockPointerInits[this] = Init;
-}
-
 void LinkageSpecDecl::anchor() { }
 
 LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
index 75c450867b51b2c2b8a42c7c6191bb83e6e48f5c..f95ca17306729f1c336515f3004a28995444577f 100644 (file)
@@ -1076,6 +1076,11 @@ void CastExpr::CheckCastConsistency() const {
            !getSubExpr()->getType()->isBlockPointerType());
     goto CheckNoBasePath;
 
+  case CK_CopyAndAutoreleaseBlockObject:
+    assert(getType()->isBlockPointerType());
+    assert(getSubExpr()->getType()->isBlockPointerType());
+    goto CheckNoBasePath;
+      
   // These should not have an inheritance path.
   case CK_Dynamic:
   case CK_ToUnion:
@@ -1231,6 +1236,8 @@ const char *CastExpr::getCastKindName() const {
     return "AtomicToNonAtomic";
   case CK_NonAtomicToAtomic:
     return "NonAtomicToAtomic";
+  case CK_CopyAndAutoreleaseBlockObject:
+    return "CopyAndAutoreleaseBlockObject";
   }
 
   llvm_unreachable("Unhandled cast kind!");
index 5420876866d35dda1c0a6d55cde12b9673a6443f..ed64153f853c30d9cd69dc50fe745e1831c4e53a 100644 (file)
@@ -5209,6 +5209,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_ARCConsumeObject:
   case CK_ARCReclaimReturnedObject:
   case CK_ARCExtendBlockObject:
+  case CK_CopyAndAutoreleaseBlockObject:
     return Error(E);
 
   case CK_UserDefinedConversion:
@@ -5684,6 +5685,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
   case CK_ARCConsumeObject:
   case CK_ARCReclaimReturnedObject:
   case CK_ARCExtendBlockObject:
+  case CK_CopyAndAutoreleaseBlockObject:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_LValueToRValue:
index 90a8fb611a7528c9dc607a0a0abe60681a18ead4..608e8ae46e5ffbe99deb29adcca56992e5484638 100644 (file)
@@ -516,7 +516,8 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
     OS << "(capture ";
     if (i->isByRef()) OS << "byref ";
     if (i->isNested()) OS << "nested ";
-    DumpDeclRef(i->getVariable());
+    if (i->getVariable())
+      DumpDeclRef(i->getVariable());
     if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
     OS << ")";
   }
index 060841d50783e26de57ac31ddaeb0b26d8db2e79..18aa0fc4317edc80e502aa47ee1cc1d1facf3966 100644 (file)
@@ -2096,7 +2096,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
   case CK_ARCProduceObject:
   case CK_ARCConsumeObject:
   case CK_ARCReclaimReturnedObject:
-  case CK_ARCExtendBlockObject: {
+  case CK_ARCExtendBlockObject: 
+  case CK_CopyAndAutoreleaseBlockObject: {
     // These casts only produce lvalues when we're binding a reference to a 
     // temporary realized from a (converted) pure rvalue. Emit the expression
     // as a value, copy it into a temporary, and return an lvalue referring to
index afe70a5dda8b353da5e12506be9eb654165d223c..5fb334bd8e86a1534e01efddb86ee98c3ebe8783 100644 (file)
@@ -614,6 +614,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
   case CK_ARCConsumeObject:
   case CK_ARCReclaimReturnedObject:
   case CK_ARCExtendBlockObject:
+  case CK_CopyAndAutoreleaseBlockObject:
     llvm_unreachable("cast kind invalid for aggregate types");
   }
 }
index 15fa225eb85b28117250faed97856fcc7fd58040..ae192cb8365dd82f2660df0f407d8ccec476f697 100644 (file)
@@ -413,6 +413,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
   case CK_ARCConsumeObject:
   case CK_ARCReclaimReturnedObject:
   case CK_ARCExtendBlockObject:
+  case CK_CopyAndAutoreleaseBlockObject:
     llvm_unreachable("invalid cast kind for complex value");
 
   case CK_FloatingRealToComplex:
index a7cd36862ba47cea90adadf9ac94870a1051fef0..4fc21fe708f8633d3f0994eb7cb3ec31751ad103 100644 (file)
@@ -636,6 +636,7 @@ public:
     case CK_ARCConsumeObject:
     case CK_ARCReclaimReturnedObject:
     case CK_ARCExtendBlockObject:
+    case CK_CopyAndAutoreleaseBlockObject:
       return 0;
 
     // These don't need to be handled here because Evaluate knows how to
index 6eed2ed346fb87fa34ede9338403b6afaf65e29a..76c91a5ff373d98582af34bde15fdcb553fef624 100644 (file)
@@ -1148,6 +1148,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
   case CK_ARCExtendBlockObject:
     return CGF.EmitARCExtendBlockObject(E);
 
+  case CK_CopyAndAutoreleaseBlockObject:
+    CGF.ErrorUnsupported(E, "copy/autorelease block object");
+    return 0;
+      
   case CK_FloatingRealToComplex:
   case CK_FloatingComplexCast:
   case CK_IntegralRealToComplex:
index 9454a751550d9173e80cafabb0e396581856e79d..7f42b2059d7f96b32f4ad468dff4ca381505ccb7 100644 (file)
@@ -3000,9 +3000,11 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
     Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
     QualType T = SubExpr->getType();
 
-    if (SubExpr->getType()->isPointerType() ||
-        SubExpr->getType()->isBlockPointerType() ||
-        SubExpr->getType()->isObjCQualifiedIdType())
+    if (cast<CastExpr>(E)->getCastKind() == CK_CopyAndAutoreleaseBlockObject)
+      return 0;
+    else if (SubExpr->getType()->isPointerType() ||
+             SubExpr->getType()->isBlockPointerType() ||
+             SubExpr->getType()->isObjCQualifiedIdType())
       return EvalAddr(SubExpr, refVars);
     else if (T->isArrayType())
       return EvalVal(SubExpr, refVars);
index a1a952b833f01b3291bc7e912b572fc60882cef4..22fb8cb7a83b6db0d7edf5c8828a9baf43755d49 100644 (file)
@@ -8755,9 +8755,9 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
 /// \brief Mark the call operator of the given lambda closure type as "used".
 static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
   CXXMethodDecl *CallOperator 
-  = cast<CXXMethodDecl>(
-      *Lambda->lookup(
-        S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+    = cast<CXXMethodDecl>(
+        *Lambda->lookup(
+          S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
   CallOperator->setReferenced();
   CallOperator->setUsed();
 }
@@ -8805,14 +8805,21 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
        SourceLocation CurrentLocation,
        CXXConversionDecl *Conv) 
 {
+  CXXRecordDecl *Lambda = Conv->getParent();
+  
   // Make sure that the lambda call operator is marked used.
-  markLambdaCallOperatorUsed(*this, Conv->getParent());
+  CXXMethodDecl *CallOperator 
+    = cast<CXXMethodDecl>(
+        *Lambda->lookup(
+          Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+  CallOperator->setReferenced();
+  CallOperator->setUsed();
   Conv->setUsed();
   
   ImplicitlyDefinedFunctionScope Scope(*this, Conv);
   DiagnosticErrorTrap Trap(Diags);
   
-  // Copy-initialize the lambda object as needed to capture
+  // Copy-initialize the lambda object as needed to capture it.
   Expr *This = ActOnCXXThis(CurrentLocation).take();
   Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).take();
   ExprResult Init = PerformCopyInitialization(
@@ -8823,16 +8830,78 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
   if (!Init.isInvalid())
     Init = ActOnFinishFullExpr(Init.take());
   
-  if (!Init.isInvalid())
-    Conv->setLambdaToBlockPointerCopyInit(Init.take());
-  else {
+  if (Init.isInvalid()) {
     Diag(CurrentLocation, diag::note_lambda_to_block_conv);
+    Conv->setInvalidDecl();
+    return;
   }
   
-  // Introduce a bogus body, which IR generation will override anyway.
-  Conv->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(),
+  // Create the new block to be returned.
+  BlockDecl *Block = BlockDecl::Create(Context, Conv, Conv->getLocation());
+  
+  // Set the type information.
+  Block->setSignatureAsWritten(CallOperator->getTypeSourceInfo());
+  Block->setIsVariadic(CallOperator->isVariadic());
+  Block->setBlockMissingReturnType(false);
+  
+  // Add parameters.
+  SmallVector<ParmVarDecl *, 4> BlockParams;
+  for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
+    ParmVarDecl *From = CallOperator->getParamDecl(I);
+    BlockParams.push_back(ParmVarDecl::Create(Context, Block,
+                                              From->getLocStart(),
+                                              From->getLocation(),
+                                              From->getIdentifier(),
+                                              From->getType(),
+                                              From->getTypeSourceInfo(),
+                                              From->getStorageClass(),
+                                            From->getStorageClassAsWritten(),
+                                              /*DefaultArg=*/0));
+  }
+  Block->setParams(BlockParams);
+  
+  // Add capture. The capture is uses a fake (NULL) variable, since we don't
+  // actually want to have to name a capture variable. However, the 
+  // initializer copy-initializes the lambda object.
+  BlockDecl::Capture Capture(/*Variable=*/0, /*ByRef=*/false, /*Nested=*/false,
+                             /*Copy=*/Init.take());
+  Block->setCaptures(Context, &Capture, &Capture + 1, 
+                     /*CapturesCXXThis=*/false);
+  
+  // Add a fake function body to the block. IR generation is responsible
+  // for filling in the actual body, which cannot be expressed as an AST.
+  Block->setBody(new (Context) CompoundStmt(Context, 0, 0, 
+                                            Conv->getLocation(),
+                                            Conv->getLocation()));
+
+  // Create the block literal expression.
+  Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
+  ExprCleanupObjects.push_back(Block);
+  ExprNeedsCleanups = true;
+
+  // If we're not under ARC, make sure we still get the _Block_copy/autorelease
+  // behavior.
+  if (!getLangOptions().ObjCAutoRefCount)
+    BuildBlock = ImplicitCastExpr::Create(Context, BuildBlock->getType(),
+                                          CK_CopyAndAutoreleaseBlockObject,
+                                          BuildBlock, 0, VK_RValue);
+  
+  // Create the return statement that returns the block from the conversion
+  // function.
+  StmtResult Return = ActOnReturnStmt(Conv->getLocation(), BuildBlock);
+  if (Return.isInvalid()) {
+    Diag(CurrentLocation, diag::note_lambda_to_block_conv);
+    Conv->setInvalidDecl();
+    return;
+  }
+
+  // Set the body of the conversion function.
+  Stmt *ReturnS = Return.take();
+  Conv->setBody(new (Context) CompoundStmt(Context, &ReturnS, 1, 
+                                           Conv->getLocation(), 
                                            Conv->getLocation()));
   
+  // We're done; notify the mutation listener, if any.
   if (ASTMutationListener *L = getASTMutationListener()) {
     L->CompletedImplicitDefinition(Conv);
   }
index 016322fe5237c749fca54ded047d1635042df6c1..b0c6a61bce9f07f250acf642317c8c5d2f7c0f0f 100644 (file)
@@ -643,7 +643,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
     //   non-explicit const conversion function to a block pointer having the
     //   same parameter and return types as the closure type's function call
     //   operator.
-    if (getLangOptions().Blocks)
+    if (getLangOptions().Blocks && getLangOptions().ObjC1)
       addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
     
     // Finalize the lambda class.
index fe09cdafa7c0092a3846774749f23b55bc24e40f..ce92e9cab49050178f50ce4544b5198b30e3f3bd 100644 (file)
@@ -1213,8 +1213,6 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
 void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
   VisitCXXMethodDecl(D);
   D->IsExplicitSpecified = Record[Idx++];
-  if (D->isLambdaToBlockPointerConversion())
-    D->setLambdaToBlockPointerCopyInit(Reader.ReadExpr(F));
 }
 
 void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
index f57a166d7ca88a3e74ee95a584d673f8e5c6fb8f..26ee8b5f2af12eeebdb7b07e60f5fd9a56da543a 100644 (file)
@@ -965,8 +965,6 @@ void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
 void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
   VisitCXXMethodDecl(D);
   Record.push_back(D->IsExplicitSpecified);
-  if (D->isLambdaToBlockPointerConversion())
-    Writer.AddStmt(D->getLambdaToBlockPointerCopyInit());
   Code = serialization::DECL_CXX_CONVERSION;
 }
 
index 3e1b6b0aec674e6fb3345d23c2baeb65f8fadcfe..e06e71699f2a7864baf61be14ba1710c114a08e1 100644 (file)
@@ -218,6 +218,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
       case CK_ARCConsumeObject:
       case CK_ARCReclaimReturnedObject:
       case CK_ARCExtendBlockObject: // Fall-through.
+      case CK_CopyAndAutoreleaseBlockObject:
         // The analyser can ignore atomic casts for now, although some future
         // checkers may want to make certain that you're not modifying the same
         // value through atomic and nonatomic pointers.