From 17f3a6d0d8026238830eacd0d765267a6ced4edc Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 21 Apr 2009 22:26:47 +0000 Subject: [PATCH] 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69738 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaExpr.cpp | 36 ++++++++++++++++++++++++------------ test/Sema/block-misc.c | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 33fefe53bc..57902cc02b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/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(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()) @@ -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 ArgTypes; for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i) ArgTypes.push_back(BSI->Params[i]->getType()); diff --git a/test/Sema/block-misc.c b/test/Sema/block-misc.c index efe021efb8..8775aa752a 100644 --- a/test/Sema/block-misc.c +++ b/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() { -- 2.40.0