From: Fariborz Jahanian Date: Wed, 24 Feb 2010 22:48:18 +0000 (+0000) Subject: Implement nasty rewriting of nested blocks when inner X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5e49b2f3e0bbc583076fe8af00dff06bcba06daf;p=clang Implement nasty rewriting of nested blocks when inner blocks use variables not used in any of the outer blocks. (Fixes radar 7682149). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97073 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 521abf489b..350d6b2009 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -120,6 +120,9 @@ namespace { // Block expressions. llvm::SmallVector Blocks; + llvm::SmallVector InnerDeclRefsCount; + llvm::SmallVector InnerDeclRefs; + llvm::SmallVector BlockDeclRefs; llvm::DenseMap BlockCallExprs; @@ -385,6 +388,9 @@ namespace { void CollectBlockDeclRefInfo(BlockExpr *Exp); void GetBlockCallExprs(Stmt *S); void GetBlockDeclRefExprs(Stmt *S); + void GetInnerBlockDeclRefExprs(Stmt *S, + llvm::SmallVector &InnerBlockDeclRefs, + llvm::SmallPtrSet &InnerBlockValueDecls); // We avoid calling Type::isBlockPointerType(), since it operates on the // canonical type. We only care if the top-level type is a closure pointer. @@ -416,7 +422,8 @@ namespace { void RewriteCastExpr(CStyleCastExpr *CE); FunctionDecl *SynthBlockInitFunctionDecl(const char *name); - Stmt *SynthBlockInitExpr(BlockExpr *Exp); + Stmt *SynthBlockInitExpr(BlockExpr *Exp, + const llvm::SmallVector &InnerBlockDeclRefs); void QuoteDoublequotes(std::string &From, std::string &To) { for (unsigned i = 0; i < From.length(); i++) { @@ -4187,8 +4194,15 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); // Insert closures that were part of the function. for (unsigned i = 0; i < Blocks.size(); i++) { - + // Need to copy-in the inner copied-in variables not actually used in this + // block. + for (int j = 0; j < InnerDeclRefsCount[i]; j++) + BlockDeclRefs.push_back(InnerDeclRefs[j]); CollectBlockDeclRefInfo(Blocks[i]); + llvm::SmallPtrSet InnerBlockValueDecls; + llvm::SmallVector InnerBlockDeclRefs; + GetInnerBlockDeclRefExprs(Blocks[i]->getBody(), + InnerBlockDeclRefs, InnerBlockValueDecls); std::string ImplTag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); std::string DescTag = "__" + std::string(FunName) + "_block_desc_" + utostr(i); @@ -4218,6 +4232,8 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, ImportedBlockDecls.clear(); } Blocks.clear(); + InnerDeclRefsCount.clear(); + InnerDeclRefs.clear(); RewrittenBlockExprs.clear(); } @@ -4265,6 +4281,33 @@ void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) { return; } +void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, + llvm::SmallVector &InnerBlockDeclRefs, + llvm::SmallPtrSet &InnerBlockValueDecls) { + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + if (BlockExpr *CBE = dyn_cast(*CI)) + GetInnerBlockDeclRefExprs(CBE->getBody(), + InnerBlockDeclRefs, + InnerBlockValueDecls); + else + GetInnerBlockDeclRefExprs(*CI, + InnerBlockDeclRefs, + InnerBlockValueDecls); + + } + // Handle specific things. + if (BlockDeclRefExpr *CDRE = dyn_cast(S)) + if (!isa(CDRE->getDecl()) && + !CDRE->isByRef() && + !InnerBlockValueDecls.count(CDRE->getDecl())) { + InnerBlockValueDecls.insert(CDRE->getDecl()); + InnerBlockDeclRefs.push_back(CDRE); + } + return; +} + void RewriteObjC::GetBlockCallExprs(Stmt *S) { for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; ++CI) @@ -4854,10 +4897,34 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) { false); } -Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { +Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, + const llvm::SmallVector &InnerBlockDeclRefs) { Blocks.push_back(Exp); CollectBlockDeclRefInfo(Exp); + + // Add inner imported variables now used in current block. + int countOfInnerDecls = 0; + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { + BlockDeclRefExpr *Exp = InnerBlockDeclRefs[i]; + ValueDecl *VD = Exp->getDecl(); + if (!BlockByCopyDeclsPtrSet.count(VD)) { + // We need to save the copied-in variables in nested + // blocks because it is needed at the end for some of the API generations. + // See SynthesizeBlockLiterals routine. + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByCopyDeclsPtrSet.insert(VD); + BlockByCopyDecls.push_back(VD); + if (Exp->getType()->isObjCObjectPointerType() || + Exp->getType()->isBlockPointerType()) { + GetBlockCallExprs(Exp); + ImportedBlockDecls.insert(VD); + } + } + } + InnerDeclRefsCount.push_back(countOfInnerDecls); + std::string FuncName; if (CurFunctionDef) @@ -5036,6 +5103,10 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { } if (BlockExpr *BE = dyn_cast(S)) { + llvm::SmallPtrSet InnerBlockValueDecls; + llvm::SmallVector InnerBlockDeclRefs; + GetInnerBlockDeclRefExprs(BE->getBody(), + InnerBlockDeclRefs, InnerBlockValueDecls); // Rewrite the block body in place. RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); @@ -5043,7 +5114,8 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); RewrittenBlockExprs[BE] = Str; - Stmt *blockTranscribed = SynthBlockInitExpr(BE); + Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); + //blockTranscribed->dump(); ReplaceStmt(S, blockTranscribed); return blockTranscribed; diff --git a/test/Rewriter/rewrite-nested-blocks.mm b/test/Rewriter/rewrite-nested-blocks.mm new file mode 100644 index 0000000000..deb0ee5904 --- /dev/null +++ b/test/Rewriter/rewrite-nested-blocks.mm @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// radar 7682149 + + +void f(void (^block)(void)); + +@interface X { + int y; +} +- (void)foo; +@end + +@implementation X +- (void)foo { + f(^{ + f(^{ + f(^{ + y=42; + }); + }); +}); + +} +@end +