diff options
author | Chris Lattner <sabre@nondot.org> | 2009-04-21 22:26:47 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2009-04-21 22:26:47 +0000 |
commit | 497d7b0c8acd6d55555b11e3d49121da71a5cf1d (patch) | |
tree | b263c9c9ca29afa8c027160842cd235957a089f4 /clang | |
parent | a868bbd392594290cff15a3d25e8a69fe43a3857 (diff) | |
download | bcm5719-llvm-497d7b0c8acd6d55555b11e3d49121da71a5cf1d.tar.gz bcm5719-llvm-497d7b0c8acd6d55555b11e3d49121da71a5cf1d.zip |
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
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 36 | ||||
-rw-r--r-- | clang/test/Sema/block-misc.c | 19 |
2 files changed, 43 insertions, 12 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 33fefe53bc0..57902cc02b5 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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()); diff --git a/clang/test/Sema/block-misc.c b/clang/test/Sema/block-misc.c index efe021efb85..8775aa752ac 100644 --- a/clang/test/Sema/block-misc.c +++ b/clang/test/Sema/block-misc.c @@ -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() { |