diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2010-03-11 18:20:03 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2010-03-11 18:20:03 +0000 |
commit | 6cb6eb4c792b504ad652d9230640656852e18ee9 (patch) | |
tree | 4692fd63d8c9e9d300f27045af8b8c16f2f3f9a1 | |
parent | a14db75641f377ef8b033c67653cd95ac4c36fe3 (diff) |
Add tentative support for accessing local variables with
external linkage (static, extern, etc.) in blocks in
rewriter. wip.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98265 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Decl.h | 14 | ||||
-rw-r--r-- | lib/Frontend/RewriteObjC.cpp | 70 | ||||
-rw-r--r-- | test/Rewriter/rewrite-local-externs-in-block.mm | 23 |
3 files changed, 99 insertions, 8 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index bd9f01b0b5..7d1d8a5bc9 100644 --- a/include/clang/AST/Decl.h +++ b/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/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index a3a30e2390..3181a55088 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -134,7 +134,8 @@ namespace { llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet; llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo; llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; - + llvm::SmallPtrSet<VarDecl *, 8> ImportedLocalExternalDecls; + llvm::DenseMap<BlockExpr *, std::string> 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<VarDecl>(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<BlockDeclRefExpr>(S)) + if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) { // FIXME: Handle enums. if (!isa<FunctionDecl>(CDRE->getDecl())) BlockDeclRefs.push_back(CDRE); + } + else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(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<BlockDeclRefExpr>(S)) + if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) { if (!isa<FunctionDecl>(CDRE->getDecl()) && !InnerContexts.count(CDRE->getDecl()->getDeclContext())) InnerBlockDeclRefs.push_back(CDRE); + } + else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { + if (VarDecl *Var = dyn_cast<VarDecl>(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<VarDecl>(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<BlockDeclRefExpr *, 8> InnerBlockDeclRefs; llvm::SmallPtrSet<const DeclContext *, 8> 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<BlocksAttr>()) return RewriteBlockDeclRefExpr(DRE); + if (HasLocalVariableExternalStorage(VD)) + return RewriteLocalVariableExternalStorage(DRE); } if (CallExpr *CE = dyn_cast<CallExpr>(S)) { diff --git a/test/Rewriter/rewrite-local-externs-in-block.mm b/test/Rewriter/rewrite-local-externs-in-block.mm new file mode 100644 index 0000000000..d1a56a89ee --- /dev/null +++ b/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]); +} |