fix marking of nested blocks with the "hasBlockDeclRefExprs" to

mark exactly the blocks which have references that are "live through".
This fixes a rejects valid: 
rdar://6808730 - [sema] [blocks] block rejected at global scope

llvm-svn: 69738
This commit is contained in:
Chris Lattner 2009-04-21 22:26:47 +00:00
parent a868bbd392
commit 497d7b0c8a
2 changed files with 43 additions and 12 deletions

View File

@ -402,9 +402,9 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
/// variables defined outside the block) or false if this is not needed (e.g.
/// for values inside the block or for globals).
///
/// FIXME: This will create BlockDeclRefExprs for global variables,
/// function references, etc which is suboptimal :) and breaks
/// things like "integer constant expression" tests.
/// This also keeps the 'hasBlockDeclRefExprs' in the BlockSemaInfo records
/// up-to-date.
///
static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
ValueDecl *VD) {
// If the value is defined inside the block, we couldn't snapshot it even if
@ -420,7 +420,27 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
// snapshot it.
// FIXME: What about 'const' variables in C++?
if (const VarDecl *Var = dyn_cast<VarDecl>(VD))
return Var->hasLocalStorage();
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 (BlockSemaInfo *NextBlock = CurBlock->PrevBlockInfo; NextBlock;
NextBlock = NextBlock->PrevBlockInfo) {
// 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;
}
return true;
}
@ -948,9 +968,6 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// as they do not get snapshotted.
//
if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) {
// Blocks that have these can't be constant.
CurBlock->hasBlockDeclRefExprs = true;
QualType ExprTy = VD->getType().getNonReferenceType();
// The BlocksAttr indicates the variable is bound by-reference.
if (VD->getAttr<BlocksAttr>())
@ -4763,11 +4780,6 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (BSI->ReturnType)
RetTy = QualType(BSI->ReturnType, 0);
// A reference in a nested block, winds up being a reference in the outer
// block.
if (CurBlock)
CurBlock->hasBlockDeclRefExprs |= BSI->hasBlockDeclRefExprs;
llvm::SmallVector<QualType, 8> ArgTypes;
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
ArgTypes.push_back(BSI->Params[i]->getType());

View File

@ -112,6 +112,25 @@ void test11(int i) {
^{ break; }(); // expected-error {{'break' statement not in loop or switch statement}}
}
// rdar://6808730
void *test13 = ^{
int X = 32;
void *P = ^{
return X+4; // References outer block's "X", so outer block is constant.
};
};
void test14() {
int X = 32;
static void *P = ^{ // expected-error {{initializer element is not a compile-time constant}}
void *Q = ^{
// References test14's "X": outer block is non constant.
return X+4;
};
};
}
void (^test12f)(void);
void test12() {