From 3a106e70291140af38dd5107cbbbc86e5835ffa5 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 11 Mar 2010 18:20:03 +0000 Subject: [PATCH] Add tentative support for accessing local variables with external linkage (static, extern, etc.) in blocks in rewriter. wip. llvm-svn: 98265 --- clang/include/clang/AST/Decl.h | 14 +++- clang/lib/Frontend/RewriteObjC.cpp | 70 +++++++++++++++++-- .../rewrite-local-externs-in-block.mm | 23 ++++++ 3 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 clang/test/Rewriter/rewrite-local-externs-in-block.mm diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index bd9f01b0b5ef..7d1d8a5bc934 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -500,7 +500,8 @@ public: bool isExternC() const; /// isBlockVarDecl - Returns true for local variable declarations. Note that - /// this includes static variables inside of functions. + /// this includes static variables inside of functions. It also includes + /// variables inside blocks. /// /// void foo() { int x; static int y; extern int z; } /// @@ -512,6 +513,17 @@ public: return false; } + /// isFunctionOrMethodVarDecl - Similar to isBlockVarDecl, but excludes + /// variables declared in blocks. + bool isFunctionOrMethodVarDecl() const { + if (getKind() != Decl::Var) + return false; + if (const DeclContext *DC = getDeclContext()) + return DC->getLookupContext()->isFunctionOrMethod() && + DC->getLookupContext()->getDeclKind() != Decl::Block; + return false; + } + /// \brief Determines whether this is a static data member. /// /// This will only be true in C++, and applies to, e.g., the diff --git a/clang/lib/Frontend/RewriteObjC.cpp b/clang/lib/Frontend/RewriteObjC.cpp index a3a30e2390f2..3181a55088bb 100644 --- a/clang/lib/Frontend/RewriteObjC.cpp +++ b/clang/lib/Frontend/RewriteObjC.cpp @@ -134,7 +134,8 @@ namespace { llvm::SmallPtrSet BlockByRefDeclsPtrSet; llvm::DenseMap BlockByRefDeclNo; llvm::SmallPtrSet ImportedBlockDecls; - + llvm::SmallPtrSet ImportedLocalExternalDecls; + llvm::DenseMap RewrittenBlockExprs; // This maps a property to it's assignment statement. @@ -372,6 +373,7 @@ namespace { void RewriteByRefVar(VarDecl *VD); std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); Stmt *RewriteBlockDeclRefExpr(Expr *VD); + Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE); void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, @@ -4025,6 +4027,12 @@ void RewriteObjC::RewriteByRefString(std::string &ResultStr, "_" + utostr(BlockByRefDeclNo[VD]) ; } +static bool HasLocalVariableExternalStorage(ValueDecl *VD) { + if (VarDecl *Var = dyn_cast(VD)) + return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage()); + return false; +} + std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, const char *funcName, std::string Tag) { @@ -4099,7 +4107,10 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, } else { std::string Name = (*I)->getNameAsString(); - (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy); + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(Name, Context->PrintingPolicy); S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; } @@ -4188,8 +4199,11 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, S += "struct __block_impl *"; Constructor += ", void *" + ArgName; } else { - (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy); - (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy); + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(FieldName, Context->PrintingPolicy); + QT.getAsStringInternal(ArgName, Context->PrintingPolicy); Constructor += ", " + ArgName; } S += FieldName + ";\n"; @@ -4419,10 +4433,19 @@ void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) { GetBlockDeclRefExprs(*CI); } // Handle specific things. - if (BlockDeclRefExpr *CDRE = dyn_cast(S)) + if (BlockDeclRefExpr *CDRE = dyn_cast(S)) { // FIXME: Handle enums. if (!isa(CDRE->getDecl())) BlockDeclRefs.push_back(CDRE); + } + else if (DeclRefExpr *DRE = dyn_cast(S)) + if (HasLocalVariableExternalStorage(DRE->getDecl())) { + BlockDeclRefExpr *BDRE = + new (Context)BlockDeclRefExpr(DRE->getDecl(), DRE->getType(), + DRE->getLocation(), false); + BlockDeclRefs.push_back(BDRE); + } + return; } @@ -4445,10 +4468,16 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, } // Handle specific things. - if (BlockDeclRefExpr *CDRE = dyn_cast(S)) + if (BlockDeclRefExpr *CDRE = dyn_cast(S)) { if (!isa(CDRE->getDecl()) && !InnerContexts.count(CDRE->getDecl()->getDeclContext())) InnerBlockDeclRefs.push_back(CDRE); + } + else if (DeclRefExpr *DRE = dyn_cast(S)) { + if (VarDecl *Var = dyn_cast(DRE->getDecl())) + if (Var->isFunctionOrMethodVarDecl()) + ImportedLocalExternalDecls.insert(Var); + } return; } @@ -4611,6 +4640,23 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { return PE; } +// Rewrites the imported local variable V with external storage +// (static, extern, etc.) as *V +// +Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { + ValueDecl *VD = DRE->getDecl(); + if (VarDecl *Var = dyn_cast(VD)) + if (!ImportedLocalExternalDecls.count(Var)) + return DRE; + Expr *Exp = new (Context) UnaryOperator(DRE, UnaryOperator::Deref, + DRE->getType(), DRE->getLocation()); + // Need parens to enforce precedence. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + Exp); + ReplaceStmt(DRE, PE); + return PE; +} + void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { SourceLocation LocStart = CE->getLParenLoc(); SourceLocation LocEnd = CE->getRParenLoc(); @@ -5130,6 +5176,13 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, } else { FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); + if (HasLocalVariableExternalStorage(*I)) { + QualType QT = (*I)->getType(); + QT = Context->getPointerType(QT); + Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, QT, + SourceLocation()); + } + } InitExprs.push_back(Exp); } @@ -5244,11 +5297,12 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { llvm::SmallVector InnerBlockDeclRefs; llvm::SmallPtrSet InnerContexts; InnerContexts.insert(BE->getBlockDecl()); + ImportedLocalExternalDecls.clear(); GetInnerBlockDeclRefExprs(BE->getBody(), InnerBlockDeclRefs, InnerContexts); // Rewrite the block body in place. RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); - + ImportedLocalExternalDecls.clear(); // Now we snarf the rewritten text and stash it away for later use. std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); RewrittenBlockExprs[BE] = Str; @@ -5431,6 +5485,8 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { ValueDecl *VD = DRE->getDecl(); if (VD->hasAttr()) return RewriteBlockDeclRefExpr(DRE); + if (HasLocalVariableExternalStorage(VD)) + return RewriteLocalVariableExternalStorage(DRE); } if (CallExpr *CE = dyn_cast(S)) { diff --git a/clang/test/Rewriter/rewrite-local-externs-in-block.mm b/clang/test/Rewriter/rewrite-local-externs-in-block.mm new file mode 100644 index 000000000000..d1a56a89ee58 --- /dev/null +++ b/clang/test/Rewriter/rewrite-local-externs-in-block.mm @@ -0,0 +1,23 @@ +// 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 7735987 + +extern "C" int printf(const char*, ...); + +void bar(void (^block)()) { + block(); +} + +int main() { + static int myArr[3] = {1, 2, 3}; + printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]); + + bar(^{ + printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]); + myArr[0] = 42; + myArr[2] = 100; + printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]); + }); + + printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]); +}