forked from OSchip/llvm-project
Rewriting of @synchronized. This has one FIXME in it. But this should allow @sychronized to be rewritten.
llvm-svn: 46533
This commit is contained in:
parent
9b4211d25d
commit
284011b462
|
@ -252,10 +252,10 @@ Stmt::child_iterator ObjCAtThrowStmt::child_end() {
|
|||
|
||||
// ObjCAtSynchronizedStmt
|
||||
Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() {
|
||||
return &SynchBody;
|
||||
return &SubStmts[0];
|
||||
}
|
||||
|
||||
Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() {
|
||||
return &SynchBody+1;
|
||||
return &SubStmts[0]+END_EXPR;
|
||||
}
|
||||
|
||||
|
|
|
@ -888,15 +888,13 @@ ObjCAtFinallyStmt* ObjCAtFinallyStmt::CreateImpl(Deserializer& D) {
|
|||
|
||||
void ObjCAtSynchronizedStmt::EmitImpl(Serializer& S) const {
|
||||
S.Emit(AtSynchronizedLoc);
|
||||
S.BatchEmitOwnedPtrs(SynchExpr, SynchBody);
|
||||
}
|
||||
S.BatchEmitOwnedPtrs((unsigned) END_EXPR,&SubStmts[0]);
|
||||
}
|
||||
|
||||
ObjCAtSynchronizedStmt* ObjCAtSynchronizedStmt::CreateImpl(Deserializer& D) {
|
||||
SourceLocation L = SourceLocation::ReadVal(D);
|
||||
Expr *syncExpr;
|
||||
Stmt *synchBody;
|
||||
D.BatchReadOwnedPtrs(syncExpr, synchBody);
|
||||
ObjCAtSynchronizedStmt* stmt = new ObjCAtSynchronizedStmt(L,syncExpr,synchBody);
|
||||
ObjCAtSynchronizedStmt* stmt = new ObjCAtSynchronizedStmt(L,0,0);
|
||||
D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubStmts[0]);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
|
|
|
@ -199,6 +199,7 @@ namespace {
|
|||
Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
|
||||
Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
|
||||
Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S);
|
||||
Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S);
|
||||
Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S);
|
||||
Stmt *RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S);
|
||||
Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S);
|
||||
|
@ -807,6 +808,9 @@ Stmt *RewriteTest::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
|
|||
if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
|
||||
return RewriteObjCTryStmt(StmtTry);
|
||||
|
||||
if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
|
||||
return RewriteObjCSynchronizedStmt(StmtTry);
|
||||
|
||||
if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
|
||||
return RewriteObjCThrowStmt(StmtThrow);
|
||||
|
||||
|
@ -903,7 +907,7 @@ Stmt *RewriteTest::RewriteContinueStmt(ContinueStmt *S) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/// RewriteObjCTryStmt - Rewriter for ObjC2's foreach statement.
|
||||
/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement.
|
||||
/// It rewrites:
|
||||
/// for ( type elem in collection) { stmts; }
|
||||
|
||||
|
@ -1070,6 +1074,54 @@ Stmt *RewriteTest::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/// RewriteObjCSynchronizedStmt -
|
||||
/// This routine rewrites @synchronized(expr) stmt;
|
||||
/// into:
|
||||
/// objc_sync_enter(expr);
|
||||
/// @try stmt @finally { objc_sync_exit(expr); }
|
||||
///
|
||||
Stmt *RewriteTest::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
|
||||
// Get the start location and compute the semi location.
|
||||
SourceLocation startLoc = S->getLocStart();
|
||||
const char *startBuf = SM->getCharacterData(startLoc);
|
||||
|
||||
assert((*startBuf == '@') && "bogus @synchronized location");
|
||||
|
||||
std::string buf;
|
||||
buf = "objc_sync_enter";
|
||||
Rewrite.ReplaceText(startLoc, 13, buf.c_str(), buf.size());
|
||||
SourceLocation endLoc = S->getSynchExpr()->getLocEnd();
|
||||
const char *endBuf = SM->getCharacterData(endLoc);
|
||||
endBuf++;
|
||||
const char *rparenBuf = strchr(endBuf, ')');
|
||||
SourceLocation rparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf);
|
||||
buf = ");\n";
|
||||
// declare a new scope with two variables, _stack and _rethrow.
|
||||
buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n";
|
||||
buf += "int buf[18/*32-bit i386*/];\n";
|
||||
buf += "char *pointers[4];} _stack;\n";
|
||||
buf += "id volatile _rethrow = 0;\n";
|
||||
buf += "objc_exception_try_enter(&_stack);\n";
|
||||
buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n";
|
||||
Rewrite.ReplaceText(rparenLoc, 1, buf.c_str(), buf.size());
|
||||
startLoc = S->getSynchBody()->getLocEnd();
|
||||
startBuf = SM->getCharacterData(startLoc);
|
||||
|
||||
assert((*startBuf == '}') && "bogus @try block");
|
||||
SourceLocation lastCurlyLoc = startLoc;
|
||||
buf = "}\nelse {\n";
|
||||
buf += " _rethrow = objc_exception_extract(&_stack);\n";
|
||||
buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
|
||||
// FIXME: This must be objc_sync_exit(syncExpr);
|
||||
buf += " objc_sync_exit();\n";
|
||||
buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
|
||||
buf += "}\n";
|
||||
buf += "}";
|
||||
|
||||
Rewrite.ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
Stmt *RewriteTest::RewriteObjCTryStmt(ObjCAtTryStmt *S) {
|
||||
// Get the start location and compute the semi location.
|
||||
SourceLocation startLoc = S->getLocStart();
|
||||
|
|
|
@ -813,7 +813,7 @@ Action::StmtResult
|
|||
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprTy *SynchExpr,
|
||||
StmtTy *SynchBody) {
|
||||
ObjCAtSynchronizedStmt *SS = new ObjCAtSynchronizedStmt(AtLoc,
|
||||
static_cast<Expr*>(SynchExpr), static_cast<Stmt*>(SynchBody));
|
||||
static_cast<Stmt*>(SynchExpr), static_cast<Stmt*>(SynchBody));
|
||||
return SS;
|
||||
}
|
||||
|
||||
|
|
|
@ -966,25 +966,31 @@ public:
|
|||
///
|
||||
class ObjCAtSynchronizedStmt : public Stmt {
|
||||
private:
|
||||
Expr* SynchExpr;
|
||||
Stmt* SynchBody;
|
||||
enum { SYNC_EXPR, SYNC_BODY, END_EXPR };
|
||||
Stmt* SubStmts[END_EXPR];
|
||||
SourceLocation AtSynchronizedLoc;
|
||||
|
||||
public:
|
||||
ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Expr *synchExpr,
|
||||
ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr,
|
||||
Stmt *synchBody)
|
||||
: Stmt(ObjCAtSynchronizedStmtClass),
|
||||
SynchExpr(synchExpr), SynchBody(synchBody),
|
||||
AtSynchronizedLoc(atSynchronizedLoc) {}
|
||||
: Stmt(ObjCAtSynchronizedStmtClass) {
|
||||
SubStmts[SYNC_EXPR] = synchExpr;
|
||||
SubStmts[SYNC_BODY] = synchBody;
|
||||
AtSynchronizedLoc = atSynchronizedLoc;
|
||||
}
|
||||
|
||||
const Stmt *getSynchBody() const { return SynchBody; }
|
||||
Stmt *getSynchBody() { return SynchBody; }
|
||||
const Stmt *getSynchBody() const { return SubStmts[SYNC_BODY]; }
|
||||
Stmt *getSynchBody() { return SubStmts[SYNC_BODY]; }
|
||||
|
||||
const Expr *getSynchExpr() const { return SynchExpr; }
|
||||
Expr *getSynchExpr() { return SynchExpr; }
|
||||
const Expr *getSynchExpr() const {
|
||||
return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
|
||||
}
|
||||
Expr *getSynchExpr() {
|
||||
return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AtSynchronizedLoc, SynchBody->getLocEnd());
|
||||
return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd());
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: clang -rewrite-test %s | clang
|
||||
|
||||
id SYNCH_EXPR();
|
||||
void SYNCH_BODY();
|
||||
void SYNCH_BEFORE();
|
||||
void SYNC_AFTER();
|
||||
|
||||
void foo(id sem)
|
||||
{
|
||||
SYNCH_BEFORE();
|
||||
@synchronized (SYNCH_EXPR()) {
|
||||
SYNCH_BODY();
|
||||
return;
|
||||
}
|
||||
SYNC_AFTER();
|
||||
}
|
Loading…
Reference in New Issue