From c63de66c4f50973b54e3341194bf847e7bfefe1f Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 2 Feb 2011 13:00:07 +0000 Subject: [PATCH] An insomniac stab at making block declarations list the variables they close on, as well as more reliably limiting invalid references to locals from nested scopes. llvm-svn: 124721 --- clang/include/clang/AST/Decl.h | 33 ++- clang/include/clang/AST/Expr.h | 10 +- clang/include/clang/Sema/ScopeInfo.h | 13 +- clang/lib/AST/Decl.cpp | 17 +- clang/lib/AST/ExprConstant.cpp | 2 +- clang/lib/Sema/SemaChecking.cpp | 2 +- clang/lib/Sema/SemaExpr.cpp | 264 +++++++++++------- clang/lib/Sema/SemaExprCXX.cpp | 24 +- clang/lib/Serialization/ASTReaderDecl.cpp | 9 + clang/lib/Serialization/ASTReaderStmt.cpp | 1 - clang/lib/Serialization/ASTWriterDecl.cpp | 6 + clang/lib/Serialization/ASTWriterStmt.cpp | 1 - clang/lib/StaticAnalyzer/CFRefCount.cpp | 2 +- .../Checkers/UndefCapturedBlockVarChecker.cpp | 2 +- 14 files changed, 249 insertions(+), 137 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index a34a2ef5355c..485883e18b51 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2495,6 +2495,7 @@ public: class BlockDecl : public Decl, public DeclContext { // FIXME: This can be packed into the bitfields in Decl. bool IsVariadic : 1; + bool CapturesCXXThis : 1; /// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal /// parameters of this function. This is null if a prototype or if there are /// no formals. @@ -2504,11 +2505,15 @@ class BlockDecl : public Decl, public DeclContext { Stmt *Body; TypeSourceInfo *SignatureAsWritten; + VarDecl **CapturedDecls; + unsigned NumCapturedDecls; + protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) : Decl(Block, DC, CaretLoc), DeclContext(Block), - IsVariadic(false), ParamInfo(0), NumParams(0), Body(0), - SignatureAsWritten(0) {} + IsVariadic(false), CapturesCXXThis(false), + ParamInfo(0), NumParams(0), Body(0), + SignatureAsWritten(0), CapturedDecls(0), NumCapturedDecls(0) {} public: static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); @@ -2537,7 +2542,7 @@ public: param_const_iterator param_begin() const { return ParamInfo; } param_const_iterator param_end() const { return ParamInfo+param_size(); } - unsigned getNumParams() const; + unsigned getNumParams() const { return NumParams; } const ParmVarDecl *getParamDecl(unsigned i) const { assert(i < getNumParams() && "Illegal param #"); return ParamInfo[i]; @@ -2548,6 +2553,28 @@ public: } void setParams(ParmVarDecl **NewParamInfo, unsigned NumParams); + /// hasCaptures - True if this block (or its nested blocks) captures + /// anything of local storage from its enclosing scopes. + bool hasCaptures() const { return NumCapturedDecls != 0 || CapturesCXXThis; } + + unsigned getNumCapturedDecls() const { return NumCapturedDecls; } + + typedef VarDecl * const *capture_iterator; + typedef VarDecl const * const *capture_const_iterator; + capture_iterator capture_begin() { return CapturedDecls; } + capture_iterator capture_end() { return CapturedDecls + NumCapturedDecls; } + capture_const_iterator capture_begin() const { return CapturedDecls; } + capture_const_iterator capture_end() const { + return CapturedDecls + NumCapturedDecls; + } + + bool capturesCXXThis() const { return CapturesCXXThis; } + + void setCapturedDecls(ASTContext &Context, + VarDecl * const *begin, + VarDecl * const *end, + bool capturesCXXThis); + virtual SourceRange getSourceRange() const; // Implement isa/cast/dyncast/etc. diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 9fb74d541092..e718961866b5 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3528,12 +3528,11 @@ public: class BlockExpr : public Expr { protected: BlockDecl *TheBlock; - bool HasBlockDeclRefExprs; public: - BlockExpr(BlockDecl *BD, QualType ty, bool hasBlockDeclRefExprs) + BlockExpr(BlockDecl *BD, QualType ty) : Expr(BlockExprClass, ty, VK_RValue, OK_Ordinary, ty->isDependentType(), false, false), - TheBlock(BD), HasBlockDeclRefExprs(hasBlockDeclRefExprs) {} + TheBlock(BD) {} /// \brief Build an empty block expression. explicit BlockExpr(EmptyShell Empty) : Expr(BlockExprClass, Empty) { } @@ -3554,11 +3553,6 @@ public: /// getFunctionType - Return the underlying function type for this block. const FunctionType *getFunctionType() const; - /// hasBlockDeclRefExprs - Return true iff the block has BlockDeclRefExpr - /// inside of the block that reference values outside the block. - bool hasBlockDeclRefExprs() const { return HasBlockDeclRefExprs; } - void setHasBlockDeclRefExprs(bool BDRE) { HasBlockDeclRefExprs = BDRE; } - static bool classof(const Stmt *T) { return T->getStmtClass() == BlockExprClass; } diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index 15d17306c9f8..0ba61b34eb05 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -17,6 +17,7 @@ #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SetVector.h" namespace clang { @@ -101,8 +102,6 @@ public: /// \brief Retains information about a block that is currently being parsed. class BlockScopeInfo : public FunctionScopeInfo { public: - bool hasBlockDeclRefExprs; - BlockDecl *TheDecl; /// TheScope - This is the scope for the block itself, which contains @@ -117,9 +116,15 @@ public: /// Its return type may be BuiltinType::Dependent. QualType FunctionType; + /// Captures - The set of variables captured by this block. + llvm::SmallSetVector Captures; + + /// CapturesCXXThis - Whether this block captures 'this'. + bool CapturesCXXThis; + BlockScopeInfo(Diagnostic &Diag, Scope *BlockScope, BlockDecl *Block) - : FunctionScopeInfo(Diag), hasBlockDeclRefExprs(false), - TheDecl(Block), TheScope(BlockScope) + : FunctionScopeInfo(Diag), TheDecl(Block), TheScope(BlockScope), + CapturesCXXThis(false) { IsBlockInfo = true; } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index b1da849ae153..db69e0878afa 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2104,8 +2104,21 @@ void BlockDecl::setParams(ParmVarDecl **NewParamInfo, } } -unsigned BlockDecl::getNumParams() const { - return NumParams; +void BlockDecl::setCapturedDecls(ASTContext &Context, + VarDecl * const *begin, + VarDecl * const *end, + bool capturesCXXThis) { + CapturesCXXThis = capturesCXXThis; + + if (begin == end) { + NumCapturedDecls = 0; + CapturedDecls = 0; + return; + } + + NumCapturedDecls = end - begin; + CapturedDecls = new (Context) VarDecl*[NumCapturedDecls]; + memcpy(CapturedDecls, begin, NumCapturedDecls * sizeof(VarDecl*)); } SourceRange BlockDecl::getSourceRange() const { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 7c3fc63e42ff..0a7a9d22cf0a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -462,7 +462,7 @@ public: { return Success(E); } bool VisitCallExpr(CallExpr *E); bool VisitBlockExpr(BlockExpr *E) { - if (!E->hasBlockDeclRefExprs()) + if (!E->getBlockDecl()->hasCaptures()) return Success(E); return false; } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 0ca1ce52ab17..24ce72032cef 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1935,7 +1935,7 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl &refVars) { } case Stmt::BlockExprClass: - if (cast(E)->hasBlockDeclRefExprs()) + if (cast(E)->getBlockDecl()->hasCaptures()) return E; // local block. return NULL; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ec5e3e0c3c3b..49637f230599 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -733,58 +733,106 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { StringTokLocs.size())); } -/// ShouldSnapshotBlockValueReference - Return true if a reference inside of -/// CurBlock to VD should cause it to be snapshotted (as we do for auto -/// variables defined outside the block) or false if this is not needed (e.g. -/// for values inside the block or for globals). +enum CaptureResult { + /// No capture is required. + CR_NoCapture, + + /// A capture is required. + CR_Capture, + + /// An error occurred when trying to capture the given variable. + CR_Error +}; + +/// Diagnose an uncapturable value reference. /// -/// This also keeps the 'hasBlockDeclRefExprs' in the BlockScopeInfo records -/// up-to-date. -/// -static bool ShouldSnapshotBlockValueReference(Sema &S, BlockScopeInfo *CurBlock, - ValueDecl *VD) { - // If the value is defined inside the block, we couldn't snapshot it even if - // we wanted to. - if (CurBlock->TheDecl == VD->getDeclContext()) - return false; +/// \param var - the variable referenced +/// \param DC - the context which we couldn't capture through +static CaptureResult +DiagnoseUncapturableValueReference(Sema &S, SourceLocation loc, + VarDecl *var, DeclContext *DC) { + switch (S.ExprEvalContexts.back().Context) { + case Sema::Unevaluated: + // The argument will never be evaluated, so don't complain. + return CR_NoCapture; - // If this is an enum constant or function, it is constant, don't snapshot. - if (isa(VD) || isa(VD)) - return false; + case Sema::PotentiallyEvaluated: + case Sema::PotentiallyEvaluatedIfUsed: + break; - // If this is a reference to an extern, static, or global variable, no need to - // snapshot it. - // FIXME: What about 'const' variables in C++? - if (const VarDecl *Var = dyn_cast(VD)) - if (!Var->hasLocalStorage()) - return false; - - // Blocks that have these can't be constant. - CurBlock->hasBlockDeclRefExprs = true; - - // If we have nested blocks, the decl may be declared in an outer block (in - // which case that outer block doesn't get "hasBlockDeclRefExprs") or it may - // be defined outside all of the current blocks (in which case the blocks do - // all get the bit). Walk the nesting chain. - for (unsigned I = S.FunctionScopes.size() - 1; I; --I) { - BlockScopeInfo *NextBlock = dyn_cast(S.FunctionScopes[I]); - - if (!NextBlock) - continue; - - // If we found the defining block for the variable, don't mark the block as - // having a reference outside it. - if (NextBlock->TheDecl == VD->getDeclContext()) - break; - - // Otherwise, the DeclRef from the inner block causes the outer one to need - // a snapshot as well. - NextBlock->hasBlockDeclRefExprs = true; + case Sema::PotentiallyPotentiallyEvaluated: + // FIXME: delay these! + break; } - return true; + // Don't diagnose about capture if we're not actually in code right + // now; in general, there are more appropriate places that will + // diagnose this. + if (!S.CurContext->isFunctionOrMethod()) return CR_NoCapture; + + // This particular madness can happen in ill-formed default + // arguments; claim it's okay and let downstream code handle it. + if (isa(var) && + S.CurContext == var->getDeclContext()->getParent()) + return CR_NoCapture; + + DeclarationName functionName; + if (FunctionDecl *fn = dyn_cast(var->getDeclContext())) + functionName = fn->getDeclName(); + // FIXME: variable from enclosing block that we couldn't capture from! + + S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function) + << var->getIdentifier() << functionName; + S.Diag(var->getLocation(), diag::note_local_variable_declared_here) + << var->getIdentifier(); + + return CR_Error; } +/// ShouldCaptureValueReference - Determine if a reference to the +/// given value in the current context requires a variable capture. +/// +/// This also keeps the captures set in the BlockScopeInfo records +/// up-to-date. +static CaptureResult ShouldCaptureValueReference(Sema &S, SourceLocation loc, + ValueDecl *value) { + // Only variables ever require capture. + VarDecl *var = dyn_cast(value); + if (!var || isa(var)) return CR_NoCapture; + + // Fast path: variables from the current context never require capture. + DeclContext *DC = S.CurContext; + if (var->getDeclContext() == DC) return CR_NoCapture; + + // Only variables with local storage require capture. + // FIXME: What about 'const' variables in C++? + if (!var->hasLocalStorage()) return CR_NoCapture; + + // Otherwise, we need to capture. + + unsigned functionScopesIndex = S.FunctionScopes.size() - 1; + + do { + // Only blocks (and eventually C++0x closures) can capture; other + // scopes don't work. + if (!isa(DC)) + return DiagnoseUncapturableValueReference(S, loc, var, DC); + + BlockScopeInfo *blockScope = + cast(S.FunctionScopes[functionScopesIndex]); + assert(blockScope->TheDecl == static_cast(DC)); + + // Try to capture it in this block. If we've already captured at + // this level, we're done. + if (!blockScope->Captures.insert(var)) + return CR_Capture; + + functionScopesIndex--; + DC = cast(DC)->getDeclContext(); + } while (var->getDeclContext() != DC); + + return CR_Capture; +} ExprResult Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, @@ -811,17 +859,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, // Non-type template parameters can be referenced anywhere they are // visible. Ty = Ty.getNonLValueExprType(Context); - } else if (const CXXMethodDecl *MD = dyn_cast(CurContext)) { - if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) { - if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) { - Diag(NameInfo.getLoc(), - diag::err_reference_to_local_var_in_enclosing_function) - << D->getIdentifier() << FD->getDeclName(); - Diag(D->getLocation(), diag::note_local_variable_declared_here) - << D->getIdentifier(); - return ExprError(); - } - } // This ridiculousness brought to you by 'extern void x;' and the // GNU compiler collection. @@ -2250,66 +2287,74 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // We do not do this for things like enum constants, global variables, etc, // as they do not get snapshotted. // - if (getCurBlock() && - ShouldSnapshotBlockValueReference(*this, getCurBlock(), VD)) { - if (VD->getType().getTypePtr()->isVariablyModifiedType()) { - Diag(Loc, diag::err_ref_vm_type); - Diag(D->getLocation(), diag::note_declared_at); - return ExprError(); - } + switch (ShouldCaptureValueReference(*this, NameInfo.getLoc(), VD)) { + case CR_Error: + return ExprError(); - if (VD->getType()->isArrayType()) { - Diag(Loc, diag::err_ref_array_type); - Diag(D->getLocation(), diag::note_declared_at); - return ExprError(); - } + case CR_NoCapture: + // If this reference is not in a block or if the referenced + // variable is within the block, create a normal DeclRefExpr. + return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), VK, + NameInfo, &SS); - MarkDeclarationReferenced(Loc, VD); - QualType ExprTy = VD->getType().getNonReferenceType(); + case CR_Capture: + break; + } - // The BlocksAttr indicates the variable is bound by-reference. - bool byrefVar = (VD->getAttr() != 0); - QualType T = VD->getType(); - BlockDeclRefExpr *BDRE; + // If we got here, we need to capture. + + if (VD->getType().getTypePtr()->isVariablyModifiedType()) { + Diag(Loc, diag::err_ref_vm_type); + Diag(D->getLocation(), diag::note_declared_at); + return ExprError(); + } + + if (VD->getType()->isArrayType()) { + Diag(Loc, diag::err_ref_array_type); + Diag(D->getLocation(), diag::note_declared_at); + return ExprError(); + } + + MarkDeclarationReferenced(Loc, VD); + QualType ExprTy = VD->getType().getNonReferenceType(); + + // The BlocksAttr indicates the variable is bound by-reference. + bool byrefVar = (VD->getAttr() != 0); + QualType T = VD->getType(); + BlockDeclRefExpr *BDRE; - if (!byrefVar) { - // This is to record that a 'const' was actually synthesize and added. - bool constAdded = !ExprTy.isConstQualified(); - // Variable will be bound by-copy, make it const within the closure. - ExprTy.addConst(); - BDRE = new (Context) BlockDeclRefExpr(VD, ExprTy, VK, - Loc, false, constAdded); - } - else - BDRE = new (Context) BlockDeclRefExpr(VD, ExprTy, VK, Loc, true); + if (!byrefVar) { + // This is to record that a 'const' was actually synthesize and added. + bool constAdded = !ExprTy.isConstQualified(); + // Variable will be bound by-copy, make it const within the closure. + ExprTy.addConst(); + BDRE = new (Context) BlockDeclRefExpr(VD, ExprTy, VK, + Loc, false, constAdded); + } + else + BDRE = new (Context) BlockDeclRefExpr(VD, ExprTy, VK, Loc, true); - if (getLangOptions().CPlusPlus) { - if (!T->isDependentType() && !T->isReferenceType()) { - Expr *E = new (Context) - DeclRefExpr(const_cast(BDRE->getDecl()), T, - VK, SourceLocation()); - if (T->getAs()) - if (!T->isUnionType()) { - ExprResult Res = PerformCopyInitialization( - InitializedEntity::InitializeBlock(VD->getLocation(), + if (getLangOptions().CPlusPlus) { + if (!T->isDependentType() && !T->isReferenceType()) { + Expr *E = new (Context) + DeclRefExpr(const_cast(BDRE->getDecl()), T, + VK, SourceLocation()); + if (T->isStructureOrClassType()) { + ExprResult Res = PerformCopyInitialization( + InitializedEntity::InitializeBlock(VD->getLocation(), T, false), - SourceLocation(), - Owned(E)); - if (!Res.isInvalid()) { - Res = MaybeCreateExprWithCleanups(Res); - Expr *Init = Res.takeAs(); - BDRE->setCopyConstructorExpr(Init); - } + SourceLocation(), + Owned(E)); + if (!Res.isInvalid()) { + Res = MaybeCreateExprWithCleanups(Res); + Expr *Init = Res.takeAs(); + BDRE->setCopyConstructorExpr(Init); } } } - return Owned(BDRE); } - // If this reference is not in a block or if the referenced variable is - // within the block, create a normal DeclRefExpr. - return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), VK, - NameInfo, &SS); + return Owned(BDRE); } ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, @@ -8486,6 +8531,12 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, bool NoReturn = BSI->TheDecl->getAttr(); QualType BlockTy; + // Set the captured variables on the block. + BSI->TheDecl->setCapturedDecls(Context, + BSI->Captures.begin(), + BSI->Captures.end(), + BSI->CapturesCXXThis); + // If the user wrote a function type in some form, try to use that. if (!BSI->FunctionType.isNull()) { const FunctionType *FTy = BSI->FunctionType->getAs(); @@ -8557,8 +8608,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, return ExprError(); } - BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, - BSI->hasBlockDeclRefExprs); + BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); // Issue any analysis-based warnings. const sema::AnalysisBasedWarnings::Policy &WP = diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 7bc9af1191e6..73e9778a7427 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -563,14 +564,23 @@ ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. - DeclContext *DC = getFunctionLevelDeclContext(); - if (CXXMethodDecl *MD = dyn_cast(DC)) - if (MD->isInstance()) - return Owned(new (Context) CXXThisExpr(ThisLoc, - MD->getThisType(Context), - /*isImplicit=*/false)); + // Ignore block scopes (but nothing else). + DeclContext *DC = CurContext; + while (isa(DC)) DC = cast(DC)->getDeclContext(); - return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); + // If we're not an instance method, error out. + CXXMethodDecl *method = dyn_cast(DC); + if (!method || !method->isInstance()) + return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); + + // Mark that we're closing on 'this' in all the block scopes, if applicable. + for (unsigned idx = FunctionScopes.size() - 1; + isa(FunctionScopes[idx]); + --idx) + cast(FunctionScopes[idx])->CapturesCXXThis = true; + + return Owned(new (Context) CXXThisExpr(ThisLoc, method->getThisType(Context), + /*isImplicit=*/false)); } ExprResult diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 26baee47c223..311ce7b5b114 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -696,6 +696,15 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { for (unsigned I = 0; I != NumParams; ++I) Params.push_back(cast(Reader.GetDecl(Record[Idx++]))); BD->setParams(Params.data(), NumParams); + + bool capturesCXXThis = Record[Idx++]; + unsigned numCapturedDecls = Record[Idx++]; + llvm::SmallVector capturedDecls; + capturedDecls.reserve(numCapturedDecls); + for (unsigned i = 0; i != numCapturedDecls; ++i) + capturedDecls.push_back(cast(Reader.GetDecl(Record[Idx++]))); + BD->setCapturedDecls(*Reader.getContext(), capturedDecls.begin(), + capturedDecls.end(), capturesCXXThis); } void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 1a2284bde871..c704eb2ab4ca 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -791,7 +791,6 @@ void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { void ASTStmtReader::VisitBlockExpr(BlockExpr *E) { VisitExpr(E); E->setBlockDecl(cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->setHasBlockDeclRefExprs(Record[Idx++]); } void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 507c66931c55..1fe6398b733d 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -623,6 +623,12 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); + Record.push_back(D->capturesCXXThis()); + Record.push_back(D->getNumCapturedDecls()); + for (BlockDecl::capture_iterator + i = D->capture_begin(), e = D->capture_end(); i != e; ++i) + Writer.AddDeclRef(*i, Record); + Code = serialization::DECL_BLOCK; } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 601de6d8f626..15a36701678c 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -761,7 +761,6 @@ void ASTStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) { VisitExpr(E); Writer.AddDeclRef(E->getBlockDecl(), Record); - Record.push_back(E->hasBlockDeclRefExprs()); Code = serialization::EXPR_BLOCK; } diff --git a/clang/lib/StaticAnalyzer/CFRefCount.cpp b/clang/lib/StaticAnalyzer/CFRefCount.cpp index 3278c4a2bfaf..2790d5452065 100644 --- a/clang/lib/StaticAnalyzer/CFRefCount.cpp +++ b/clang/lib/StaticAnalyzer/CFRefCount.cpp @@ -3417,7 +3417,7 @@ void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C, // Scan the BlockDecRefExprs for any object the retain/release checker // may be tracking. - if (!BE->hasBlockDeclRefExprs()) + if (!BE->getBlockDecl()->hasCaptures()) return; const GRState *state = C.getState(); diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp index 1aaaa68ca610..561777c22820 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -56,7 +56,7 @@ static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S, void UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE) { - if (!BE->hasBlockDeclRefExprs()) + if (!BE->getBlockDecl()->hasCaptures()) return; const GRState *state = C.getState();