diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Decl.cpp | 1 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterDecl.cpp | 1 |
6 files changed, 45 insertions, 1 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 4f49bd79878..78501f5e3a9 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -4265,6 +4265,7 @@ BlockDecl::BlockDecl(DeclContext *DC, SourceLocation CaretLoc) setBlockMissingReturnType(true); setIsConversionFromLambda(false); setDoesNotEscape(false); + setCanAvoidCopyToHeap(false); } void BlockDecl::setParams(ArrayRef<ParmVarDecl *> NewParamInfo) { diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index fba1a531a2a..7063517efc3 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -2871,6 +2871,7 @@ public: Result visit(const Expr *e); Result visitCastExpr(const CastExpr *e); Result visitPseudoObjectExpr(const PseudoObjectExpr *e); + Result visitBlockExpr(const BlockExpr *e); Result visitBinaryOperator(const BinaryOperator *e); Result visitBinAssign(const BinaryOperator *e); Result visitBinAssignUnsafeUnretained(const BinaryOperator *e); @@ -2947,6 +2948,12 @@ ARCExprEmitter<Impl,Result>::visitPseudoObjectExpr(const PseudoObjectExpr *E) { } template <typename Impl, typename Result> +Result ARCExprEmitter<Impl, Result>::visitBlockExpr(const BlockExpr *e) { + // The default implementation just forwards the expression to visitExpr. + return asImpl().visitExpr(e); +} + +template <typename Impl, typename Result> Result ARCExprEmitter<Impl,Result>::visitCastExpr(const CastExpr *e) { switch (e->getCastKind()) { @@ -3089,7 +3096,8 @@ Result ARCExprEmitter<Impl,Result>::visit(const Expr *e) { // Look through pseudo-object expressions. } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) { return asImpl().visitPseudoObjectExpr(pseudo); - } + } else if (auto *be = dyn_cast<BlockExpr>(e)) + return asImpl().visitBlockExpr(be); return asImpl().visitExpr(e); } @@ -3124,6 +3132,15 @@ struct ARCRetainExprEmitter : return TryEmitResult(result, true); } + TryEmitResult visitBlockExpr(const BlockExpr *e) { + TryEmitResult result = visitExpr(e); + // Avoid the block-retain if this is a block literal that doesn't need to be + // copied to the heap. + if (e->getBlockDecl()->canAvoidCopyToHeap()) + result.setInt(true); + return result; + } + /// Block extends are net +0. Naively, we could just recurse on /// the subexpression, but actually we need to ensure that the /// value is copied as a block, so there's a little filter here. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index cbef0e2bb46..2078caa0bb9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11257,6 +11257,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { << Culprit->getSourceRange(); } } + + if (auto *E = dyn_cast<ExprWithCleanups>(Init)) + if (auto *BE = dyn_cast<BlockExpr>(E->getSubExpr()->IgnoreParens())) + if (VDecl->hasLocalStorage()) + BE->getBlockDecl()->setCanAvoidCopyToHeap(); } else if (VDecl->isStaticDataMember() && !VDecl->isInline() && VDecl->getLexicalDeclContext()->isRecord()) { // This is an in-class initialization for a static data member, e.g., diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e91115aec5b..266120dfdc7 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12443,6 +12443,25 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (!ResultTy.isNull()) { DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true); DiagnoseSelfMove(LHS.get(), RHS.get(), OpLoc); + + // Avoid copying a block to the heap if the block is assigned to a local + // auto variable that is declared in the same scope as the block. This + // optimization is unsafe if the local variable is declared in an outer + // scope. For example: + // + // BlockTy b; + // { + // b = ^{...}; + // } + // // It is unsafe to invoke the block here if it wasn't copied to the + // // heap. + // b(); + + if (auto *BE = dyn_cast<BlockExpr>(RHS.get()->IgnoreParens())) + if (auto *DRE = dyn_cast<DeclRefExpr>(LHS.get()->IgnoreParens())) + if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) + if (VD->hasLocalStorage() && getCurScope()->isDeclScope(VD)) + BE->getBlockDecl()->setCanAvoidCopyToHeap(); } RecordModifiableNonNullParam(*this, LHS.get()); break; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 6d02f4d1121..fb56170d8ab 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1479,6 +1479,7 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { BD->setBlockMissingReturnType(Record.readInt()); BD->setIsConversionFromLambda(Record.readInt()); BD->setDoesNotEscape(Record.readInt()); + BD->setCanAvoidCopyToHeap(Record.readInt()); bool capturesCXXThis = Record.readInt(); unsigned numCaptures = Record.readInt(); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index ff0c56b9ed4..6de1320be42 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1110,6 +1110,7 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { Record.push_back(D->blockMissingReturnType()); Record.push_back(D->isConversionFromLambda()); Record.push_back(D->doesNotEscape()); + Record.push_back(D->canAvoidCopyToHeap()); Record.push_back(D->capturesCXXThis()); Record.push_back(D->getNumCaptures()); for (const auto &capture : D->captures()) { |