[cfe-commits] r124721 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/Expr.h include/clang/Sema/ScopeInfo.h lib/AST/Decl.cpp lib/AST/ExprConstant.cpp lib/Sema/SemaChecking.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterDecl.cpp lib/Serialization/ASTWriterStmt.cpp lib/StaticAnalyzer/CFRefCount.cpp lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
John McCall
rjmccall at apple.com
Wed Feb 2 05:00:07 PST 2011
Author: rjmccall
Date: Wed Feb 2 07:00:07 2011
New Revision: 124721
URL: http://llvm.org/viewvc/llvm-project?rev=124721&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/Sema/ScopeInfo.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp
cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Feb 2 07:00:07 2011
@@ -2495,6 +2495,7 @@
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 @@
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 @@
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 @@
}
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.
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Wed Feb 2 07:00:07 2011
@@ -3528,12 +3528,11 @@
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 @@
/// 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;
}
Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Wed Feb 2 07:00:07 2011
@@ -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 @@
/// \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 @@
/// Its return type may be BuiltinType::Dependent.
QualType FunctionType;
+ /// Captures - The set of variables captured by this block.
+ llvm::SmallSetVector<VarDecl*, 4> 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;
}
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Feb 2 07:00:07 2011
@@ -2104,8 +2104,21 @@
}
}
-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 {
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Feb 2 07:00:07 2011
@@ -462,7 +462,7 @@
{ return Success(E); }
bool VisitCallExpr(CallExpr *E);
bool VisitBlockExpr(BlockExpr *E) {
- if (!E->hasBlockDeclRefExprs())
+ if (!E->getBlockDecl()->hasCaptures())
return Success(E);
return false;
}
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Feb 2 07:00:07 2011
@@ -1935,7 +1935,7 @@
}
case Stmt::BlockExprClass:
- if (cast<BlockExpr>(E)->hasBlockDeclRefExprs())
+ if (cast<BlockExpr>(E)->getBlockDecl()->hasCaptures())
return E; // local block.
return NULL;
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb 2 07:00:07 2011
@@ -733,58 +733,106 @@
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).
-///
-/// This also keeps the 'hasBlockDeclRefExprs' in the BlockScopeInfo records
-/// up-to-date.
+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.
///
-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<EnumConstantDecl>(VD) || isa<FunctionDecl>(VD))
- return false;
+ case Sema::PotentiallyEvaluated:
+ case Sema::PotentiallyEvaluatedIfUsed:
+ break;
+
+ case Sema::PotentiallyPotentiallyEvaluated:
+ // FIXME: delay these!
+ break;
+ }
+
+ // 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<ParmVarDecl>(var) &&
+ S.CurContext == var->getDeclContext()->getParent())
+ return CR_NoCapture;
- // If this is a reference to an extern, static, or global variable, no need to
- // snapshot it.
+ DeclarationName functionName;
+ if (FunctionDecl *fn = dyn_cast<FunctionDecl>(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<VarDecl>(value);
+ if (!var || isa<NonTypeTemplateParmDecl>(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 (const VarDecl *Var = dyn_cast<VarDecl>(VD))
- if (!Var->hasLocalStorage())
- return false;
+ if (!var->hasLocalStorage()) return CR_NoCapture;
- // Blocks that have these can't be constant.
- CurBlock->hasBlockDeclRefExprs = true;
+ // Otherwise, we need to capture.
- // 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<BlockScopeInfo>(S.FunctionScopes[I]);
+ unsigned functionScopesIndex = S.FunctionScopes.size() - 1;
- if (!NextBlock)
- continue;
+ do {
+ // Only blocks (and eventually C++0x closures) can capture; other
+ // scopes don't work.
+ if (!isa<BlockDecl>(DC))
+ return DiagnoseUncapturableValueReference(S, loc, var, DC);
- // 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;
+ BlockScopeInfo *blockScope =
+ cast<BlockScopeInfo>(S.FunctionScopes[functionScopesIndex]);
+ assert(blockScope->TheDecl == static_cast<BlockDecl*>(DC));
- // Otherwise, the DeclRef from the inner block causes the outer one to need
- // a snapshot as well.
- NextBlock->hasBlockDeclRefExprs = true;
- }
+ // 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;
- return true;
-}
+ functionScopesIndex--;
+ DC = cast<BlockDecl>(DC)->getDeclContext();
+ } while (var->getDeclContext() != DC);
+ return CR_Capture;
+}
ExprResult
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
@@ -811,17 +859,6 @@
// Non-type template parameters can be referenced anywhere they are
// visible.
Ty = Ty.getNonLValueExprType(Context);
- } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(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 @@
// 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;
+ }
+
+ // If we got here, we need to capture.
- // The BlocksAttr indicates the variable is bound by-reference.
- bool byrefVar = (VD->getAttr<BlocksAttr>() != 0);
- QualType T = VD->getType();
- BlockDeclRefExpr *BDRE;
+ 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<BlocksAttr>() != 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<ValueDecl*>(BDRE->getDecl()), T,
- VK, SourceLocation());
- if (T->getAs<RecordType>())
- 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<ValueDecl*>(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<Expr>();
- BDRE->setCopyConstructorExpr(Init);
- }
+ SourceLocation(),
+ Owned(E));
+ if (!Res.isInvalid()) {
+ Res = MaybeCreateExprWithCleanups(Res);
+ Expr *Init = Res.takeAs<Expr>();
+ 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 @@
bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>();
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<FunctionType>();
@@ -8557,8 +8608,7 @@
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 =
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 2 07:00:07 2011
@@ -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 @@
/// 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<CXXMethodDecl>(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<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
+
+ // If we're not an instance method, error out.
+ CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(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<BlockScopeInfo>(FunctionScopes[idx]);
+ --idx)
+ cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
- return ExprError(Diag(ThisLoc, diag::err_invalid_this_use));
+ return Owned(new (Context) CXXThisExpr(ThisLoc, method->getThisType(Context),
+ /*isImplicit=*/false));
}
ExprResult
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Feb 2 07:00:07 2011
@@ -696,6 +696,15 @@
for (unsigned I = 0; I != NumParams; ++I)
Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
BD->setParams(Params.data(), NumParams);
+
+ bool capturesCXXThis = Record[Idx++];
+ unsigned numCapturedDecls = Record[Idx++];
+ llvm::SmallVector<VarDecl*, 16> capturedDecls;
+ capturedDecls.reserve(numCapturedDecls);
+ for (unsigned i = 0; i != numCapturedDecls; ++i)
+ capturedDecls.push_back(cast<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ BD->setCapturedDecls(*Reader.getContext(), capturedDecls.begin(),
+ capturedDecls.end(), capturesCXXThis);
}
void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Wed Feb 2 07:00:07 2011
@@ -791,7 +791,6 @@
void ASTStmtReader::VisitBlockExpr(BlockExpr *E) {
VisitExpr(E);
E->setBlockDecl(cast_or_null<BlockDecl>(Reader.GetDecl(Record[Idx++])));
- E->setHasBlockDeclRefExprs(Record[Idx++]);
}
void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Feb 2 07:00:07 2011
@@ -623,6 +623,12 @@
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;
}
Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Wed Feb 2 07:00:07 2011
@@ -761,7 +761,6 @@
void ASTStmtWriter::VisitBlockExpr(BlockExpr *E) {
VisitExpr(E);
Writer.AddDeclRef(E->getBlockDecl(), Record);
- Record.push_back(E->hasBlockDeclRefExprs());
Code = serialization::EXPR_BLOCK;
}
Modified: cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/CFRefCount.cpp Wed Feb 2 07:00:07 2011
@@ -3417,7 +3417,7 @@
// 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();
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp?rev=124721&r1=124720&r2=124721&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp Wed Feb 2 07:00:07 2011
@@ -56,7 +56,7 @@
void
UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C,
const BlockExpr *BE) {
- if (!BE->hasBlockDeclRefExprs())
+ if (!BE->getBlockDecl()->hasCaptures())
return;
const GRState *state = C.getState();
More information about the cfe-commits
mailing list