diff options
author | Akira Hatanaka <ahatanaka@apple.com> | 2018-10-01 18:50:14 +0000 |
---|---|---|
committer | Akira Hatanaka <ahatanaka@apple.com> | 2018-10-01 18:50:14 +0000 |
commit | 2bf09ccfd57e9526dfa4cd0d56a68c5cf1dedee9 (patch) | |
tree | 3043aaea1fe0074f6733aa98bbab38421811ee6c /clang/lib/Sema | |
parent | be5cda81d5f09add18cb1b215500f6165a1ef481 (diff) | |
download | bcm5719-llvm-2bf09ccfd57e9526dfa4cd0d56a68c5cf1dedee9.tar.gz bcm5719-llvm-2bf09ccfd57e9526dfa4cd0d56a68c5cf1dedee9.zip |
Distinguish `__block` variables that are captured by escaping blocks
from those that aren't.
This patch changes the way __block variables that aren't captured by
escaping blocks are handled:
- Since non-escaping blocks on the stack never get copied to the heap
(see https://reviews.llvm.org/D49303), Sema shouldn't error out when
the type of a non-escaping __block variable doesn't have an accessible
copy constructor.
- IRGen doesn't have to use the specialized byref structure (see
https://clang.llvm.org/docs/Block-ABI-Apple.html#id8) for a
non-escaping __block variable anymore. Instead IRGen can emit the
variable as a normal variable and copy the reference to the block
literal. Byref copy/dispose helpers aren't needed either.
This reapplies r341754, which was reverted in r341757 because it broke a
couple of bots. r341754 was calling markEscapingByrefs after the call to
PopFunctionScopeInfo, which caused the popped function scope to be
cleared out when the following code was compiled, for example:
$ cat test.m
struct A {
id data[10];
};
void foo() {
__block A v;
^{ (void)v; };
}
This commit calls markEscapingByrefs before calling PopFunctionScopeInfo
to prevent that from happening.
rdar://problem/39352313
Differential Revision: https://reviews.llvm.org/D51564
llvm-svn: 343518
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/ScopeInfo.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 59 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 33 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 3 |
4 files changed, 66 insertions, 31 deletions
diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp index 62a83ccb70a..bd8db6f4ed9 100644 --- a/clang/lib/Sema/ScopeInfo.cpp +++ b/clang/lib/Sema/ScopeInfo.cpp @@ -54,6 +54,8 @@ void FunctionScopeInfo::Clear() { PossiblyUnreachableDiags.clear(); WeakObjectUses.clear(); ModifiedNonNullParams.clear(); + Blocks.clear(); + ByrefBlockVars.clear(); } static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) { diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index d777afe9811..ccbbe50093b 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1401,9 +1401,68 @@ void Sema::RecordParsingTemplateParameterDepth(unsigned Depth) { "Remove assertion if intentionally called in a non-lambda context."); } +// Check that the type of the VarDecl has an accessible copy constructor and +// resolve its destructor's exception spefication. +static void checkEscapingByref(VarDecl *VD, Sema &S) { + QualType T = VD->getType(); + EnterExpressionEvaluationContext scope( + S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); + SourceLocation Loc = VD->getLocation(); + Expr *VarRef = new (S.Context) DeclRefExpr(VD, false, T, VK_LValue, Loc); + ExprResult Result = S.PerformMoveOrCopyInitialization( + InitializedEntity::InitializeBlock(Loc, T, false), VD, VD->getType(), + VarRef, /*AllowNRVO=*/true); + if (!Result.isInvalid()) { + Result = S.MaybeCreateExprWithCleanups(Result); + Expr *Init = Result.getAs<Expr>(); + S.Context.setBlockVarCopyInit(VD, Init, S.canThrow(Init)); + } + + // The destructor's exception spefication is needed when IRGen generates + // block copy/destroy functions. Resolve it here. + if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + if (CXXDestructorDecl *DD = RD->getDestructor()) { + auto *FPT = DD->getType()->getAs<FunctionProtoType>(); + S.ResolveExceptionSpec(Loc, FPT); + } +} + +static void markEscapingByrefs(const FunctionScopeInfo &FSI, Sema &S) { + // Set the EscapingByref flag of __block variables captured by + // escaping blocks. + for (const BlockDecl *BD : FSI.Blocks) { + if (BD->doesNotEscape()) + continue; + for (const BlockDecl::Capture &BC : BD->captures()) { + VarDecl *VD = BC.getVariable(); + if (VD->hasAttr<BlocksAttr>()) + VD->setEscapingByref(); + } + } + + for (VarDecl *VD : FSI.ByrefBlockVars) { + // __block variables might require us to capture a copy-initializer. + if (!VD->isEscapingByref()) + continue; + // It's currently invalid to ever have a __block variable with an + // array type; should we diagnose that here? + // Regardless, we don't want to ignore array nesting when + // constructing this copy. + if (VD->getType()->isStructureOrClassType()) + checkEscapingByref(VD, S); + } +} + void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, const Decl *D, const BlockExpr *blkExpr) { assert(!FunctionScopes.empty() && "mismatched push/pop!"); + + // This function shouldn't be called after popping the current function scope. + // markEscapingByrefs calls PerformMoveOrCopyInitialization, which can call + // PushFunctionScope, which can cause clearing out PreallocatedFunctionScope + // when FunctionScopes is empty. + markEscapingByrefs(*FunctionScopes.back(), *this); + FunctionScopeInfo *Scope = FunctionScopes.pop_back_val(); if (LangOpts.OpenMP) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f5ba87f635d..441c54dc358 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11826,37 +11826,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { QualType type = var->getType(); if (type->isDependentType()) return; - // __block variables might require us to capture a copy-initializer. - if (var->hasAttr<BlocksAttr>()) { - // It's currently invalid to ever have a __block variable with an - // array type; should we diagnose that here? - - // Regardless, we don't want to ignore array nesting when - // constructing this copy. - if (type->isStructureOrClassType()) { - EnterExpressionEvaluationContext scope( - *this, ExpressionEvaluationContext::PotentiallyEvaluated); - SourceLocation poi = var->getLocation(); - Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi); - ExprResult result - = PerformMoveOrCopyInitialization( - InitializedEntity::InitializeBlock(poi, type, false), - var, var->getType(), varRef, /*AllowNRVO=*/true); - if (!result.isInvalid()) { - result = MaybeCreateExprWithCleanups(result); - Expr *init = result.getAs<Expr>(); - Context.setBlockVarCopyInit(var, init, canThrow(init)); - } - - // The destructor's exception spefication is needed when IRGen generates - // block copy/destroy functions. Resolve it here. - if (const CXXRecordDecl *RD = type->getAsCXXRecordDecl()) - if (CXXDestructorDecl *DD = RD->getDestructor()) { - auto *FPT = DD->getType()->getAs<FunctionProtoType>(); - FPT = ResolveExceptionSpec(poi, FPT); - } - } - } + if (var->hasAttr<BlocksAttr>()) + getCurFunction()->addByrefBlockVar(var); Expr *Init = var->getInit(); bool IsGlobal = GlobalStorage && !var->isStaticLocal(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 26fb107688f..5b5b8220bfc 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13530,6 +13530,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } } + if (getCurFunction()) + getCurFunction()->addBlock(BSI->TheDecl); + return Result; } |