diff options
20 files changed, 114 insertions, 46 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 10fc81ab22b..26e91959624 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -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; diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 45bb647a65d..afb53757459 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -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; } diff --git a/clang/include/clang/AST/OperationKinds.h b/clang/include/clang/AST/OperationKinds.h index 8cf79b2bfa8..258637d7f9b 100644 --- a/clang/include/clang/AST/OperationKinds.h +++ b/clang/include/clang/AST/OperationKinds.h @@ -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) diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 9840cc7820f..4dd44cbf179 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -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, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 75c450867b5..f95ca173067 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -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!"); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 5420876866d..ed64153f853 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -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: diff --git a/clang/lib/AST/StmtDumper.cpp b/clang/lib/AST/StmtDumper.cpp index 90a8fb611a7..608e8ae46e5 100644 --- a/clang/lib/AST/StmtDumper.cpp +++ b/clang/lib/AST/StmtDumper.cpp @@ -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 << ")"; } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 060841d5078..18aa0fc4317 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -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 diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index afe70a5dda8..5fb334bd8e8 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -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"); } } diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 15fa225eb85..ae192cb8365 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -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: diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index a7cd36862ba..4fc21fe708f 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -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 diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 6eed2ed346f..76c91a5ff37 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -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: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 9454a751550..7f42b2059d7 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -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); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a1a952b833f..22fb8cb7a83 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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); } diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 016322fe523..b0c6a61bce9 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -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. diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index fe09cdafa7c..ce92e9cab49 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -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) { diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index f57a166d7ca..26ee8b5f2af 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -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; } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 3e1b6b0aec6..e06e71699f2 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -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. diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm index f6a8db23e9b..f6a8db23e9b 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm diff --git a/clang/test/PCH/cxx11-lambdas.cpp b/clang/test/PCH/cxx11-lambdas.mm index c00ec638075..c00ec638075 100644 --- a/clang/test/PCH/cxx11-lambdas.cpp +++ b/clang/test/PCH/cxx11-lambdas.mm |