forked from OSchip/llvm-project
Add tentative support for accessing local variables with
external linkage (static, extern, etc.) in blocks in rewriter. wip. llvm-svn: 98265
This commit is contained in:
parent
9723d6c699
commit
3a106e7029
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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]);
|
||||
}
|
Loading…
Reference in New Issue