diff options
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 130 |
1 files changed, 74 insertions, 56 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 762ab673fa8..7a86e885bd7 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13823,8 +13823,6 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (BSI->HasImplicitReturnType) deduceClosureReturnType(*BSI); - PopDeclContext(); - QualType RetTy = Context.VoidTy; if (!BSI->ReturnType.isNull()) RetTy = BSI->ReturnType; @@ -13832,17 +13830,6 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, bool NoReturn = BD->hasAttr<NoReturnAttr>(); QualType BlockTy; - // Set the captured variables on the block. - SmallVector<BlockDecl::Capture, 4> Captures; - for (Capture &Cap : BSI->Captures) { - if (Cap.isInvalid() || Cap.isThisCapture()) - continue; - BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(), - Cap.isNested(), Cap.getInitExpr()); - Captures.push_back(NewCap); - } - BD->setCaptures(Context, Captures, BSI->CXXThisCaptureIndex != 0); - // If the user wrote a function type in some form, try to use that. if (!BSI->FunctionType.isNull()) { const FunctionType *FTy = BSI->FunctionType->getAs<FunctionType>(); @@ -13898,9 +13885,80 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, !BD->isDependentContext()) computeNRVO(Body, BSI); - BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy); + PopDeclContext(); + + // Pop the block scope now but keep it alive to the end of this function. AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); - PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result); + PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo(&WP, BD, BlockTy); + + // Set the captured variables on the block. + SmallVector<BlockDecl::Capture, 4> Captures; + for (Capture &Cap : BSI->Captures) { + if (Cap.isInvalid() || Cap.isThisCapture()) + continue; + + VarDecl *Var = Cap.getVariable(); + Expr *CopyExpr = nullptr; + if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { + if (const RecordType *Record = + Cap.getCaptureType()->getAs<RecordType>()) { + // The capture logic needs the destructor, so make sure we mark it. + // Usually this is unnecessary because most local variables have + // their destructors marked at declaration time, but parameters are + // an exception because it's technically only the call site that + // actually requires the destructor. + if (isa<ParmVarDecl>(Var)) + FinalizeVarWithDestructor(Var, Record); + + // Enter a separate potentially-evaluated context while building block + // initializers to isolate their cleanups from those of the block + // itself. + // FIXME: Is this appropriate even when the block itself occurs in an + // unevaluated operand? + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated); + + SourceLocation Loc = Cap.getLocation(); + + ExprResult Result = BuildDeclarationNameExpr( + CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var); + + // According to the blocks spec, the capture of a variable from + // the stack requires a const copy constructor. This is not true + // of the copy/move done to move a __block variable to the heap. + if (!Result.isInvalid() && + !Result.get()->getType().isConstQualified()) { + Result = ImpCastExprToType(Result.get(), + Result.get()->getType().withConst(), + CK_NoOp, VK_LValue); + } + + if (!Result.isInvalid()) { + Result = PerformCopyInitialization( + InitializedEntity::InitializeBlock(Var->getLocation(), + Cap.getCaptureType(), false), + Loc, Result.get()); + } + + // Build a full-expression copy expression if initialization + // succeeded and used a non-trivial constructor. Recover from + // errors by pretending that the copy isn't necessary. + if (!Result.isInvalid() && + !cast<CXXConstructExpr>(Result.get())->getConstructor() + ->isTrivial()) { + Result = MaybeCreateExprWithCleanups(Result); + CopyExpr = Result.get(); + } + } + } + + BlockDecl::Capture NewCap(Var, Cap.isBlockCapture(), Cap.isNested(), + CopyExpr); + Captures.push_back(NewCap); + } + BD->setCaptures(Context, Captures, BSI->CXXThisCaptureIndex != 0); + + BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy); // If the block isn't obviously global, i.e. it captures anything at // all, then we need to do a few things in the surrounding context: @@ -15192,7 +15250,6 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, QualType &DeclRefType, const bool Nested, Sema &S, bool Invalid) { - Expr *CopyExpr = nullptr; bool ByRef = false; // Blocks are not allowed to capture arrays, excepting OpenCL. @@ -15264,51 +15321,12 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, // Block capture by copy introduces 'const'. CaptureType = CaptureType.getNonReferenceType().withConst(); DeclRefType = CaptureType; - - if (S.getLangOpts().CPlusPlus && BuildAndDiagnose) { - if (const RecordType *Record = DeclRefType->getAs<RecordType>()) { - // The capture logic needs the destructor, so make sure we mark it. - // Usually this is unnecessary because most local variables have - // their destructors marked at declaration time, but parameters are - // an exception because it's technically only the call site that - // actually requires the destructor. - if (isa<ParmVarDecl>(Var)) - S.FinalizeVarWithDestructor(Var, Record); - - // Enter a new evaluation context to insulate the copy - // full-expression. - EnterExpressionEvaluationContext scope( - S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); - - // According to the blocks spec, the capture of a variable from - // the stack requires a const copy constructor. This is not true - // of the copy/move done to move a __block variable to the heap. - Expr *DeclRef = new (S.Context) DeclRefExpr( - S.Context, Var, Nested, DeclRefType.withConst(), VK_LValue, Loc); - - ExprResult Result - = S.PerformCopyInitialization( - InitializedEntity::InitializeBlock(Var->getLocation(), - CaptureType, false), - Loc, DeclRef); - - // Build a full-expression copy expression if initialization - // succeeded and used a non-trivial constructor. Recover from - // errors by pretending that the copy isn't necessary. - if (!Result.isInvalid() && - !cast<CXXConstructExpr>(Result.get())->getConstructor() - ->isTrivial()) { - Result = S.MaybeCreateExprWithCleanups(Result); - CopyExpr = Result.get(); - } - } - } } // Actually capture the variable. if (BuildAndDiagnose) BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc, SourceLocation(), - CaptureType, CopyExpr, Invalid); + CaptureType, nullptr, Invalid); return !Invalid; } |