void RewriteBlockCall(CallExpr *Exp);
void RewriteBlockPointerDecl(NamedDecl *VD);
void RewriteByRefVar(VarDecl *VD);
- Stmt *RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
+ Stmt *RewriteBlockDeclRefExpr(Expr *VD);
void RewriteBlockPointerFunctionArgs(FunctionDecl *FD);
std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i,
// i = 77;
// };
//}
-Stmt *RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
+Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
// Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR
- // for each BDRE where BYREFVAR is name of the variable.
+ // for each DeclRefExp where BYREFVAR is name of the variable.
+ ValueDecl *VD;
+ bool isArrow = true;
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(DeclRefExp))
+ VD = BDRE->getDecl();
+ else {
+ VD = cast<DeclRefExpr>(DeclRefExp)->getDecl();
+ isArrow = false;
+ }
+
FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
&Context->Idents.get("__forwarding"),
Context->VoidPtrTy, 0,
/*BitWidth=*/0, /*Mutable=*/true);
- MemberExpr *ME = new (Context) MemberExpr(BDRE, true, FD, SourceLocation(),
+ MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
+ FD, SourceLocation(),
FD->getType());
- const char *Name = BDRE->getDecl()->getNameAsCString();
+
+ const char *Name = VD->getNameAsCString();
FD = FieldDecl::Create(*Context, 0, SourceLocation(),
&Context->Idents.get(Name),
Context->VoidPtrTy, 0,
/*BitWidth=*/0, /*Mutable=*/true);
ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
- BDRE->getType());
+ DeclRefExp->getType());
// Need parens to enforce precedence.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
ME);
- ReplaceStmt(BDRE, PE);
+ ReplaceStmt(DeclRefExp, PE);
return PE;
}
/// struct __Block_byref_ND *__forwarding;
/// int32_t __flags;
/// int32_t __size;
-/// void *__ByrefKeepFuncPtr; // Only if variable is __block ObjC object
-/// void *__ByrefDestroyFuncPtr; // Only if variable is __block ObjC object
+/// void *__copy_helper; // Only if variable is __block ObjC object
+/// void *__destroy_helper; // Only if variable is __block ObjC object
/// typex ND;
/// };
///
ByrefType += " struct __Block_byref_" + Name + " *__forwarding;\n";
ByrefType += " int __flags;\n";
ByrefType += " int __size;\n";
- // FIXME. Add void *__ByrefKeepFuncPtr; void *__ByrefDestroyFuncPtr;
- // if needed.
- ND->getType().getAsStringInternal(Name, Context->PrintingPolicy);
+ // Add void *__copy_helper; void *__destroy_helper; if needed.
+ QualType Ty = ND->getType();
+ bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
+ if (HasCopyAndDispose) {
+ ByrefType += " void *__copy_helper;\n";
+ ByrefType += " void *__destroy_helper;\n";
+ }
+
+ Ty.getAsStringInternal(Name, Context->PrintingPolicy);
ByrefType += " " + Name + ";\n";
ByrefType += "};\n";
// Insert this type in global scope. It is needed by helper function.
if (!hasInit) {
ByrefType += " " + Name + " = ";
ByrefType += "{0, &" + Name + ", ";
- // FIXME. Compute the flag.
- ByrefType += "0, ";
+ unsigned flag = 0;
+ if (HasCopyAndDispose)
+ flag |= BLOCK_HAS_COPY_DISPOSE;
+ ByrefType += utostr(flag);
+ ByrefType += ", ";
ByrefType += "sizeof(struct __Block_byref_" + Name + ")";
ByrefType += "};\n";
ReplaceText(DeclLoc, endBuf-startBuf+Name.size(),
ReplaceText(DeclLoc, endBuf-startBuf,
ByrefType.c_str(), ByrefType.size());
ByrefType = " = {0, &" + Name + ", ";
- // FIXME. Compute the flag.
- ByrefType += "0, ";
+ unsigned flag = 0;
+ if (HasCopyAndDispose)
+ flag |= BLOCK_HAS_COPY_DISPOSE;
+ ByrefType += utostr(flag);
+ ByrefType += ", ";
ByrefType += "sizeof(struct __Block_byref_" + Name + "), ";
InsertText(startLoc, ByrefType.c_str(), ByrefType.size());
if (BDRE->isByRef())
return RewriteBlockDeclRefExpr(BDRE);
}
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VD->hasAttr<BlocksAttr>())
+ return RewriteBlockDeclRefExpr(DRE);
+ }
+
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
if (CE->getCallee()->getType()->isBlockPointerType()) {
Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee());