changeset 1141:f99a3b393c03

Reorganize EnclosingHandlers to require less changes to the frontend and allow us to implement the synchronized storage class for functions.
author Christian Kamm <kamm incasoftware de>
date Tue, 24 Mar 2009 21:18:18 +0100
parents 45d73f0a9b43
children 49421d3ac5a7
files dmd/func.c dmd/scope.c dmd/scope.h dmd/statement.c dmd/statement.h gen/asmstmt.cpp gen/irstate.cpp gen/irstate.h gen/llvmhelpers.cpp gen/llvmhelpers.h gen/statements.cpp gen/toir.cpp
diffstat 12 files changed, 216 insertions(+), 227 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/func.c	Tue Mar 24 14:34:16 2009 +0100
+++ b/dmd/func.c	Tue Mar 24 21:18:18 2009 +0100
@@ -682,8 +682,8 @@
 	sc2->explicitProtection = 0;
 	sc2->structalign = 8;
 	sc2->incontract = 0;
-	sc2->tf = NULL;
-	sc2->tfOfTry = NULL;
+	sc2->enclosingFinally = NULL;
+	sc2->enclosingScopeExit = NULL;
 	sc2->noctor = 0;
 
 	// Declare 'this'
@@ -1243,6 +1243,38 @@
 	    }
 
 	    fbody = new CompoundStatement(0, a);
+
+	    // wrap body of synchronized functions in a synchronized statement
+	    if (isSynchronized())
+	    {
+		ClassDeclaration *cd = parent->isClassDeclaration();
+		if (!cd)
+		    error("synchronized function %s must be a member of a class", toChars());
+		    
+		Expression *sync;
+		if (isStatic())
+		{
+		    // static member functions synchronize on classinfo 
+		    // (the expression passed doesn't matter)
+		    sync = cd->type->dotExp(sc2, new DollarExp(loc), Id::classinfo);
+		}
+		else
+		{
+		    // non-static member functions synchronize on this
+		    sync = new VarExp(loc, vthis);
+		}
+                
+		// is is ok to not rerun semantic on the whole fbody here; only the enclosingScopeExit
+		// value will differ and as it is impossible to goto out of this synchronized statement,
+		// that should not lead to errors
+		SynchronizedStatement* s = new SynchronizedStatement(loc, sync, NULL);
+		s->semantic(sc2);
+		s->body = fbody;
+		
+		a = new Statements;
+		a->push(s);
+		fbody = new CompoundStatement(0, a);
+	    }
 	}
 
 	sc2->callSuper = 0;
--- a/dmd/scope.c	Tue Mar 24 14:34:16 2009 +0100
+++ b/dmd/scope.c	Tue Mar 24 21:18:18 2009 +0100
@@ -52,8 +52,8 @@
     this->enclosing = NULL;
     this->parent = NULL;
     this->sw = NULL;
-    this->tf = NULL;
-    this->tfOfTry = NULL;
+    this->enclosingFinally = NULL;
+    this->enclosingScopeExit = NULL;
     this->tinst = NULL;
     this->sbreak = NULL;
     this->scontinue = NULL;
@@ -91,8 +91,8 @@
     this->scopesym = NULL;
     this->sd = NULL;
     this->sw = enclosing->sw;
-    this->tf = enclosing->tf;
-    this->tfOfTry = enclosing->tfOfTry;
+    this->enclosingFinally = enclosing->enclosingFinally;
+    this->enclosingScopeExit = enclosing->enclosingScopeExit;
     this->tinst = enclosing->tinst;
     this->sbreak = enclosing->sbreak;
     this->scontinue = enclosing->scontinue;
--- a/dmd/scope.h	Tue Mar 24 14:34:16 2009 +0100
+++ b/dmd/scope.h	Tue Mar 24 21:18:18 2009 +0100
@@ -46,8 +46,8 @@
     Dsymbol *parent;		// parent to use
     LabelStatement *slabel;	// enclosing labelled statement
     SwitchStatement *sw;	// enclosing switch statement
-    TryFinallyStatement *tf;	// enclosing try finally statement; set inside its finally block
-    EnclosingHandler *tfOfTry; // enclosing try-finally, volatile or synchronized statement; set inside its try or body block
+    TryFinallyStatement *enclosingFinally;	// enclosing try finally statement; set inside its finally block
+    Statement *enclosingScopeExit; // enclosing statement that wants to do something on scope exit
     TemplateInstance *tinst;	// enclosing template instance
     Statement *sbreak;		// enclosing statement that supports "break"
     Statement *scontinue;	// enclosing statement that supports "continue"
--- a/dmd/statement.c	Tue Mar 24 14:34:16 2009 +0100
+++ b/dmd/statement.c	Tue Mar 24 21:18:18 2009 +0100
@@ -582,7 +582,6 @@
     : Statement(loc)
 {
     statements = s;
-    enclosinghandler = NULL;
 }
 
 Statement *UnrolledLoopStatement::syntaxCopy()
@@ -604,8 +603,6 @@
 {
     //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
 
-    enclosinghandler = sc->tfOfTry;
-
     sc->noctor++;
     Scope *scd = sc->push();
     scd->sbreak = this;
@@ -795,7 +792,6 @@
 {
     condition = c;
     body = b;
-    enclosinghandler = NULL;
 }
 
 Statement *WhileStatement::syntaxCopy()
@@ -830,8 +826,6 @@
     }
 #endif
 
-    enclosinghandler = sc->tfOfTry;
-
     condition = condition->semantic(sc);
     condition = resolveProperties(sc, condition);
     condition = condition->optimize(WANTvalue);
@@ -919,7 +913,6 @@
 {
     body = b;
     condition = c;
-    enclosinghandler = NULL;
 }
 
 Statement *DoStatement::syntaxCopy()
@@ -931,8 +924,6 @@
 
 Statement *DoStatement::semantic(Scope *sc)
 {
-    enclosinghandler = sc->tfOfTry;
-
     sc->noctor++;
     if (body)
 	body = body->semanticScope(sc, this, this);
@@ -1010,7 +1001,6 @@
     this->condition = condition;
     this->increment = increment;
     this->body = body;
-    this->enclosinghandler = NULL;
 }
 
 Statement *ForStatement::syntaxCopy()
@@ -1030,8 +1020,6 @@
 
 Statement *ForStatement::semantic(Scope *sc)
 {
-    enclosinghandler = sc->tfOfTry;
-
     ScopeDsymbol *sym = new ScopeDsymbol();
     sym->parent = sc->scopesym;
     sc = sc->push(sym);
@@ -1169,7 +1157,6 @@
     this->arguments = arguments;
     this->aggr = aggr;
     this->body = body;
-    this->enclosinghandler = NULL;
 
     this->key = NULL;
     this->value = NULL;
@@ -1197,8 +1184,6 @@
     Type *tn = NULL;
     Type *tnv = NULL;
 
-    enclosinghandler = sc->tfOfTry;
-
     func = sc->func;
     if (func->fes)
 	func = func->fes->func;
@@ -2253,8 +2238,6 @@
     sdefault = NULL;
     cases = NULL;
     hasNoDefault = 0;
-    // LDC
-    enclosinghandler = NULL;
 }
 
 Statement *SwitchStatement::syntaxCopy()
@@ -2269,8 +2252,6 @@
     //printf("SwitchStatement::semantic(%p)\n", this);
     assert(!cases);		// ensure semantic() is only run once
 
-    enclosinghandler = sc->tfOfTry;
-
     condition = condition->semantic(sc);
     condition = resolveProperties(sc, condition);
     if (condition->type->isString())
@@ -2571,7 +2552,6 @@
     : Statement(loc)
 {
     sw = NULL;
-    enclosinghandler = NULL;
 }
 
 Statement *GotoDefaultStatement::syntaxCopy()
@@ -2582,7 +2562,6 @@
 
 Statement *GotoDefaultStatement::semantic(Scope *sc)
 {
-    enclosinghandler = sc->tfOfTry;
     sw = sc->sw;
     if (!sw)
 	error("goto default not in switch statement");
@@ -2606,7 +2585,6 @@
 {
     cs = NULL;
     this->exp = exp;
-    enclosinghandler = NULL;
     sw = NULL;
 }
 
@@ -2619,7 +2597,6 @@
 
 Statement *GotoCaseStatement::semantic(Scope *sc)
 {
-    enclosinghandler = sc->tfOfTry;
     if (exp)
 	exp = exp->semantic(sc);
 
@@ -2678,7 +2655,6 @@
     : Statement(loc)
 {
     this->exp = exp;
-    this->enclosinghandler = NULL;
 }
 
 Statement *ReturnStatement::syntaxCopy()
@@ -2693,7 +2669,6 @@
 Statement *ReturnStatement::semantic(Scope *sc)
 {
     //printf("ReturnStatement::semantic() %s\n", toChars());
-    this->enclosinghandler = sc->tfOfTry;
 
     FuncDeclaration *fd = sc->parent->isFuncDeclaration();
     Scope *scx = sc;
@@ -2730,7 +2705,7 @@
 
     if (sc->incontract || scx->incontract)
 	error("return statements cannot be in contracts");
-    if (sc->tf || scx->tf)
+    if (sc->enclosingFinally || scx->enclosingFinally)
 	error("return statements cannot be in finally, scope(exit) or scope(success) bodies");
 
     if (fd->isCtorDeclaration())
@@ -2955,7 +2930,6 @@
     : Statement(loc)
 {
     this->ident = ident;
-    this->enclosinghandler = NULL;
 }
 
 Statement *BreakStatement::syntaxCopy()
@@ -2967,7 +2941,6 @@
 Statement *BreakStatement::semantic(Scope *sc)
 {
     //printf("BreakStatement::semantic()\n");
-    enclosinghandler = sc->tfOfTry;
     // If:
     //	break Identifier;
     if (ident)
@@ -3005,7 +2978,7 @@
 
 		if (!s->hasBreak())
 		    error("label '%s' has no break", ident->toChars());
-		if (ls->tf != sc->tf)
+		if (ls->enclosingFinally != sc->enclosingFinally)
 		    error("cannot break out of finally block");
 		
 		this->target = ls;
@@ -3051,7 +3024,6 @@
     : Statement(loc)
 {
     this->ident = ident;
-    this->enclosinghandler = NULL;
 }
 
 Statement *ContinueStatement::syntaxCopy()
@@ -3062,7 +3034,6 @@
 
 Statement *ContinueStatement::semantic(Scope *sc)
 {
-    enclosinghandler = sc->tfOfTry;
     //printf("ContinueStatement::semantic() %p\n", this);
     if (ident)
     {
@@ -3109,7 +3080,7 @@
 
 		if (!s->hasContinue())
 		    error("label '%s' has no continue", ident->toChars());
-		if (ls->tf != sc->tf)
+		if (ls->enclosingFinally != sc->enclosingFinally)
 		    error("cannot continue out of finally block");
 		
 		this->target = ls;
@@ -3156,7 +3127,6 @@
     this->exp = exp;
     this->body = body;
     this->esync = NULL;
-    this->enclosinghandler = NULL;
     // LDC
     this->llsync = NULL;
 }
@@ -3167,7 +3137,6 @@
     this->exp = NULL;
     this->body = body;
     this->esync = esync;
-    this->enclosinghandler = NULL;
     // LDC
     this->llsync = NULL;
 }
@@ -3199,10 +3168,10 @@
     }
     if (body)
     {
-        enclosinghandler = sc->tfOfTry;
-        sc->tfOfTry = new EnclosingSynchro(this);
-        body = body->semantic(sc);
-        sc->tfOfTry = enclosinghandler;
+	Statement* oldScopeExit = sc->enclosingScopeExit;
+	sc->enclosingScopeExit = this;
+	body = body->semantic(sc);
+	sc->enclosingScopeExit = oldScopeExit;
     }
     return this;
 }
@@ -3455,7 +3424,7 @@
     //printf("Catch::semantic(%s)\n", ident->toChars());
 
 #ifndef IN_GCC
-    if (sc->tf)
+    if (sc->enclosingFinally)
     {
 	/* This is because the _d_local_unwind() gets the stack munged
 	 * up on this. The workaround is to place any try-catches into
@@ -3516,7 +3485,6 @@
 {
     this->body = body;
     this->finalbody = finalbody;
-    this->enclosinghandler = NULL;
 }
 
 Statement *TryFinallyStatement::syntaxCopy()
@@ -3530,13 +3498,13 @@
 {
     //printf("TryFinallyStatement::semantic()\n");
 
-    enclosinghandler = sc->tfOfTry;
-    sc->tfOfTry = new EnclosingTryFinally(this);
+    Statement* oldScopeExit = sc->enclosingScopeExit;
+    sc->enclosingScopeExit = this;
     body = body->semantic(sc);
-    sc->tfOfTry = enclosinghandler;
+    sc->enclosingScopeExit = oldScopeExit;
 
     sc = sc->push();
-    sc->tf = this;
+    sc->enclosingFinally = this;
     sc->sbreak = NULL;
     sc->scontinue = NULL;	// no break or continue out of finally block
     finalbody = finalbody->semantic(sc);
@@ -3711,7 +3679,6 @@
     : Statement(loc)
 {
     this->statement = statement;
-    this->enclosinghandler = NULL;
 }
 
 Statement *VolatileStatement::syntaxCopy()
@@ -3725,10 +3692,10 @@
 {
     if (statement)
     {
-    enclosinghandler = sc->tfOfTry;
-    sc->tfOfTry = new EnclosingVolatile(this);
-    statement = statement->semantic(sc);
-    sc->tfOfTry = enclosinghandler;
+	Statement* oldScopeExit = sc->enclosingScopeExit;
+	sc->enclosingScopeExit = this;
+	statement = statement->semantic(sc);
+	sc->enclosingScopeExit = oldScopeExit;
     }
     return this;
 }
@@ -3775,8 +3742,8 @@
 {
     this->ident = ident;
     this->label = NULL;
-    this->tf = NULL;
-    this->enclosinghandler = NULL;
+    this->enclosingFinally = NULL;
+    this->enclosingScopeExit = NULL;
 }
 
 Statement *GotoStatement::syntaxCopy()
@@ -3789,8 +3756,9 @@
 {   FuncDeclaration *fd = sc->parent->isFuncDeclaration();
 
     //printf("GotoStatement::semantic()\n");
-    tf = sc->tf;
-    enclosinghandler = sc->tfOfTry;
+    enclosingFinally = sc->enclosingFinally;
+    enclosingScopeExit = sc->enclosingScopeExit;
+
     label = fd->searchLabel(ident);
     if (!label->statement && sc->fes)
     {
@@ -3808,7 +3776,7 @@
 	sc->fes->gotos.push(s);		// 'look at this later' list
 	return s;
     }
-    if (label->statement && label->statement->tf != sc->tf)
+    if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally)
 	error("cannot goto in or out of finally block");
     return this;
 }
@@ -3834,8 +3802,8 @@
 {
     this->ident = ident;
     this->statement = statement;
-    this->tf = NULL;
-    this->enclosinghandler = NULL;
+    this->enclosingFinally = NULL;
+    this->enclosingScopeExit = NULL;
     this->lblock = NULL;
     this->isReturnLabel = 0;
     this->asmLabel = false;
@@ -3857,8 +3825,10 @@
 	error("Label '%s' already defined", ls->toChars());
     else
 	ls->statement = this;
-    tf = sc->tf;
-    enclosinghandler = sc->tfOfTry;
+
+    enclosingFinally = sc->enclosingFinally;
+    enclosingScopeExit = sc->enclosingScopeExit;
+
     sc = sc->push();
     sc->scopesym = sc->enclosing->scopesym;
     sc->callSuper |= CSXlabel;
--- a/dmd/statement.h	Tue Mar 24 14:34:16 2009 +0100
+++ b/dmd/statement.h	Tue Mar 24 21:18:18 2009 +0100
@@ -94,35 +94,6 @@
     BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt),
 };
 
-// LDC this is used for tracking try-finally, synchronized and volatile scopes
-// definitions in gen/llvmhelpers.cpp
-struct EnclosingHandler : Object
-{
-    virtual void emitCode(IRState* p) = 0;
-    virtual EnclosingHandler* getEnclosing() = 0;
-};
-struct EnclosingTryFinally : EnclosingHandler
-{
-    TryFinallyStatement* tf;
-    void emitCode(IRState* p);
-    EnclosingHandler* getEnclosing();
-    EnclosingTryFinally(TryFinallyStatement* _tf) : tf(_tf) {}
-};
-struct EnclosingVolatile : EnclosingHandler
-{
-    VolatileStatement* v;
-    void emitCode(IRState* p);
-    EnclosingHandler* getEnclosing();
-    EnclosingVolatile(VolatileStatement* _tf) : v(_tf) {}
-};
-struct EnclosingSynchro : EnclosingHandler
-{
-    SynchronizedStatement* s;
-    void emitCode(IRState* p);
-    EnclosingHandler* getEnclosing();
-    EnclosingSynchro(SynchronizedStatement* _tf) : s(_tf) {}
-};
-
 struct Statement : Object
 {
     Loc loc;
@@ -255,7 +226,6 @@
 struct UnrolledLoopStatement : Statement
 {
     Statements *statements;
-    EnclosingHandler* enclosinghandler;
 
     UnrolledLoopStatement(Loc loc, Statements *statements);
     Statement *syntaxCopy();
@@ -300,7 +270,6 @@
 {
     Expression *condition;
     Statement *body;
-    EnclosingHandler* enclosinghandler;
 
     WhileStatement(Loc loc, Expression *c, Statement *b);
     Statement *syntaxCopy();
@@ -322,7 +291,6 @@
 {
     Statement *body;
     Expression *condition;
-    EnclosingHandler* enclosinghandler;
 
     DoStatement(Loc loc, Statement *b, Expression *c);
     Statement *syntaxCopy();
@@ -346,7 +314,6 @@
     Expression *condition;
     Expression *increment;
     Statement *body;
-    EnclosingHandler* enclosinghandler;
 
     ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body);
     Statement *syntaxCopy();
@@ -371,7 +338,6 @@
     Arguments *arguments;	// array of Argument*'s
     Expression *aggr;
     Statement *body;
-    EnclosingHandler* enclosinghandler;
 
     VarDeclaration *key;
     VarDeclaration *value;
@@ -499,7 +465,6 @@
     Statement *body;
 
     DefaultStatement *sdefault;
-    EnclosingHandler* enclosinghandler;
 
     Array gotoCases;		// array of unresolved GotoCaseStatement's
     Array *cases;		// array of CaseStatement's
@@ -574,7 +539,6 @@
 struct GotoDefaultStatement : Statement
 {
     SwitchStatement *sw;
-    EnclosingHandler* enclosinghandler;
 
     GotoDefaultStatement(Loc loc);
     Statement *syntaxCopy();
@@ -590,7 +554,6 @@
 {
     Expression *exp;		// NULL, or which case to goto
     CaseStatement *cs;		// case statement it resolves to
-    EnclosingHandler* enclosinghandler;
     SwitchStatement *sw;
 
     GotoCaseStatement(Loc loc, Expression *exp);
@@ -615,7 +578,6 @@
 struct ReturnStatement : Statement
 {
     Expression *exp;
-    EnclosingHandler* enclosinghandler;
 
     ReturnStatement(Loc loc, Expression *exp);
     Statement *syntaxCopy();
@@ -636,7 +598,6 @@
 struct BreakStatement : Statement
 {
     Identifier *ident;
-    EnclosingHandler* enclosinghandler;
 
     BreakStatement(Loc loc, Identifier *ident);
     Statement *syntaxCopy();
@@ -654,7 +615,6 @@
 struct ContinueStatement : Statement
 {
     Identifier *ident;
-    EnclosingHandler* enclosinghandler;
 
     ContinueStatement(Loc loc, Identifier *ident);
     Statement *syntaxCopy();
@@ -673,7 +633,6 @@
 {
     Expression *exp;
     Statement *body;
-    EnclosingHandler* enclosinghandler;
 
     SynchronizedStatement(Loc loc, Expression *exp, Statement *body);
     Statement *syntaxCopy();
@@ -749,7 +708,6 @@
 {
     Statement *body;
     Statement *finalbody;
-    EnclosingHandler* enclosinghandler;
 
     TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody);
     Statement *syntaxCopy();
@@ -799,7 +757,6 @@
 struct VolatileStatement : Statement
 {
     Statement *statement;
-    EnclosingHandler* enclosinghandler;
 
     VolatileStatement(Loc loc, Statement *statement);
     Statement *syntaxCopy();
@@ -817,8 +774,8 @@
 {
     Identifier *ident;
     LabelDsymbol *label;
-    TryFinallyStatement *tf;
-    EnclosingHandler* enclosinghandler;
+    TryFinallyStatement *enclosingFinally;
+    Statement* enclosingScopeExit;
 
     GotoStatement(Loc loc, Identifier *ident);
     Statement *syntaxCopy();
@@ -835,8 +792,8 @@
 {
     Identifier *ident;
     Statement *statement;
-    TryFinallyStatement *tf;
-    EnclosingHandler* enclosinghandler;
+    TryFinallyStatement *enclosingFinally;
+    Statement* enclosingScopeExit;
     block *lblock;		// back end
     int isReturnLabel;
 
@@ -895,8 +852,8 @@
 
 struct AsmBlockStatement : CompoundStatement
 {
-    EnclosingHandler* enclosinghandler;
-    TryFinallyStatement* tf;
+    TryFinallyStatement* enclosingFinally;
+    Statement* enclosingScopeExit;
 
     AsmBlockStatement(Loc loc, Statements *s);
     Statements *flatten(Scope *sc);
--- a/gen/asmstmt.cpp	Tue Mar 24 14:34:16 2009 +0100
+++ b/gen/asmstmt.cpp	Tue Mar 24 21:18:18 2009 +0100
@@ -444,8 +444,8 @@
 AsmBlockStatement::AsmBlockStatement(Loc loc, Statements* s)
 :   CompoundStatement(loc, s)
 {
-    enclosinghandler = NULL;
-    tf = NULL;
+    enclosingFinally = NULL;
+    enclosingScopeExit = NULL;
 
     abiret = NULL;
 }
@@ -772,7 +772,7 @@
             sw->addCase(llvm::ConstantInt::get(llvm::IntegerType::get(32), it->second), casebb);
 
             p->scope() = IRScope(casebb,bb);
-            DtoGoto(&loc, it->first, enclosinghandler, tf);
+            DtoGoto(loc, it->first);
         }
 
         p->scope() = IRScope(bb,oldend);
@@ -803,8 +803,8 @@
 // necessary for in-asm branches
 Statement *AsmBlockStatement::semantic(Scope *sc)
 {
-    enclosinghandler = sc->tfOfTry;
-    tf = sc->tf;
+    enclosingFinally = sc->enclosingFinally;
+    enclosingScopeExit = sc->enclosingScopeExit;
 
     return CompoundStatement::semantic(sc);
 }
--- a/gen/irstate.cpp	Tue Mar 24 14:34:16 2009 +0100
+++ b/gen/irstate.cpp	Tue Mar 24 21:18:18 2009 +0100
@@ -34,18 +34,16 @@
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-IRLoopScope::IRLoopScope()
+IRTargetScope::IRTargetScope()
 {
 }
 
-IRLoopScope::IRLoopScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* b, llvm::BasicBlock* e, bool isSwitch)
+IRTargetScope::IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget)
 {
-    begin = b;
-    end = e;
-    //builder.SetInsertPoint(b);
     this->s = s;
     this->enclosinghandler = enclosinghandler;
-    this->isSwitch = isSwitch;
+    this->breakTarget = breakTarget;
+    this->continueTarget = continueTarget;
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
--- a/gen/irstate.h	Tue Mar 24 14:34:16 2009 +0100
+++ b/gen/irstate.h	Tue Mar 24 21:18:18 2009 +0100
@@ -51,19 +51,21 @@
     IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e);
 };
 
-// scope for loops
-struct IRLoopScope : IRScope
+// scope statements that can be target of jumps
+// includes loops, switch, case, labels
+struct IRTargetScope
 {
     // generating statement
     Statement* s;
+    
     // the try of a TryFinally that encloses the loop
     EnclosingHandler* enclosinghandler;
-    // if it is a switch, we are a possible target for break
-    // but not for continue
-    bool isSwitch;
+    
+    llvm::BasicBlock* breakTarget;
+    llvm::BasicBlock* continueTarget;
 
-    IRLoopScope();
-    IRLoopScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* b, llvm::BasicBlock* e, bool isSwitch = false);
+    IRTargetScope();
+    IRTargetScope(Statement* s, EnclosingHandler* enclosinghandler, llvm::BasicBlock* continueTarget, llvm::BasicBlock* breakTarget);
 };
 
 struct IRBuilderHelper
@@ -158,8 +160,8 @@
     llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2,  LLValue* Arg3, LLValue* Arg4, const char* Name="");
 
     // loop blocks
-    typedef std::vector<IRLoopScope> LoopScopeVec;
-    LoopScopeVec loopbbs;
+    typedef std::vector<IRTargetScope> TargetScopeVec;
+    TargetScopeVec targetScopes;
 
     // this holds the array being indexed or sliced so $ will work
     // might be a better way but it works. problem is I only get a
--- a/gen/llvmhelpers.cpp	Tue Mar 24 14:34:16 2009 +0100
+++ b/gen/llvmhelpers.cpp	Tue Mar 24 21:18:18 2009 +0100
@@ -110,7 +110,7 @@
 // ASSERT HELPER
 ////////////////////////////////////////////////////////////////////////////////////////*/
 
-void DtoAssert(Module* M, Loc* loc, DValue* msg)
+void DtoAssert(Module* M, Loc loc, DValue* msg)
 {
     std::vector<LLValue*> args;
 
@@ -133,7 +133,7 @@
     args.push_back(DtoLoad(M->ir.irModule->fileName));
 
     // line param
-    LLConstant* c = DtoConstUint(loc->linnum);
+    LLConstant* c = DtoConstUint(loc.linnum);
     args.push_back(c);
 
     // call
@@ -172,19 +172,19 @@
 /*////////////////////////////////////////////////////////////////////////////////////////
 // GOTO HELPER
 ////////////////////////////////////////////////////////////////////////////////////////*/
-void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosinghandler, TryFinallyStatement* sourcetf)
+void DtoGoto(Loc loc, Identifier* target)
 {
     assert(!gIR->scopereturned());
 
     LabelStatement* lblstmt = DtoLabelStatement(target);
     if(!lblstmt) {
-        error(*loc, "the label %s does not exist", target->toChars());
+        error(loc, "the label %s does not exist", target->toChars());
         fatal();
     }
 
     // if the target label is inside inline asm, error
     if(lblstmt->asmLabel) {
-        error(*loc, "cannot goto to label %s inside an inline asm block", target->toChars());
+        error(loc, "cannot goto to label %s inside an inline asm block", target->toChars());
         fatal();
     }
 
@@ -194,25 +194,16 @@
     if (targetBB == NULL)
         targetBB = llvm::BasicBlock::Create("label_" + labelname, gIR->topfunc());
 
-    // find finallys between goto and label
-    EnclosingHandler* endfinally = enclosinghandler;
-    while(endfinally != NULL && endfinally != lblstmt->enclosinghandler) {
-        endfinally = endfinally->getEnclosing();
-    }
-
-    // error if didn't find tf statement of label
-    if(endfinally != lblstmt->enclosinghandler)
-        error(*loc, "cannot goto into try block");
+    // emit code for finallys between goto and label
+    DtoEnclosingHandlers(loc, lblstmt);
 
     // goto into finally blocks is forbidden by the spec
-    // though it should not be problematic to implement
+    // but should work fine
+    /*
     if(lblstmt->tf != sourcetf) {
-        error(*loc, "spec disallows goto into finally block");
+        error(loc, "spec disallows goto into finally block");
         fatal();
-    }
-
-    // emit code for finallys between goto and label
-    DtoEnclosingHandlers(enclosinghandler, endfinally);
+    }*/
 
     llvm::BranchInst::Create(targetBB, gIR->scopebb());
 }
@@ -225,16 +216,11 @@
 void EnclosingSynchro::emitCode(IRState * p)
 {
     if (s->exp)
-        DtoLeaveMonitor(s->llsync);
+        DtoLeaveMonitor(s->exp->toElem(p)->getRVal());
     else
         DtoLeaveCritical(s->llsync);
 }
 
-EnclosingHandler* EnclosingSynchro::getEnclosing()
-{
-    return s->enclosinghandler;
-}
-
 ////////////////////////////////////////////////////////////////////////////////////////
 
 void EnclosingVolatile::emitCode(IRState * p)
@@ -243,11 +229,6 @@
     DtoMemoryBarrier(false, false, true, false);
 }
 
-EnclosingHandler* EnclosingVolatile::getEnclosing()
-{
-    return v->enclosinghandler;
-}
-
 ////////////////////////////////////////////////////////////////////////////////////////
 
 void EnclosingTryFinally::emitCode(IRState * p)
@@ -256,34 +237,43 @@
         tf->finalbody->toIR(p);
 }
 
-EnclosingHandler* EnclosingTryFinally::getEnclosing()
-{
-    return tf->enclosinghandler;
-}
-
 ////////////////////////////////////////////////////////////////////////////////////////
 
-void DtoEnclosingHandlers(EnclosingHandler* start, EnclosingHandler* end)
+void DtoEnclosingHandlers(Loc loc, Statement* target)
 {
-    // verify that end encloses start
-    EnclosingHandler* endfinally = start;
-    while(endfinally != NULL && endfinally != end) {
-        endfinally = endfinally->getEnclosing();
+    // labels are a special case: they are not required to enclose the current scope
+    // for them we use the enclosing scope handler as a reference point
+    LabelStatement* lblstmt = dynamic_cast<LabelStatement*>(target);
+    if (lblstmt)
+        target = lblstmt->enclosingScopeExit;
+
+    // figure out up until what handler we need to emit
+    IRState::TargetScopeVec::reverse_iterator targetit;
+    for (targetit = gIR->targetScopes.rbegin(); targetit != gIR->targetScopes.rend(); ++targetit) {
+        if (targetit->s == target) {
+            break;
+        }
     }
-    assert(endfinally == end);
 
+    if (target && targetit == gIR->targetScopes.rend()) {
+        if (lblstmt)
+            error(loc, "cannot goto into try, volatile or synchronized statement at %s", target->loc.toChars());
+        else
+            error(loc, "internal error, cannot find jump path to statement at %s", target->loc.toChars());
+        return;
+    }
 
     //
-    // emit code for finallys between start and end
+    // emit code for enclosing handlers
     //
 
     // since the labelstatements possibly inside are private
     // and might already exist push a label scope
     gIR->func()->pushUniqueLabelScope("enclosing");
-    EnclosingHandler* tf = start;
-    while(tf != end) {
-        tf->emitCode(gIR);
-        tf = tf->getEnclosing();
+    IRState::TargetScopeVec::reverse_iterator it;
+    for (it = gIR->targetScopes.rbegin(); it != targetit; ++it) {
+        if (it->enclosinghandler)
+            it->enclosinghandler->emitCode(gIR);
     }
     gIR->func()->popLabelScope();
 }
--- a/gen/llvmhelpers.h	Tue Mar 24 14:34:16 2009 +0100
+++ b/gen/llvmhelpers.h	Tue Mar 24 21:18:18 2009 +0100
@@ -4,6 +4,31 @@
 #include "gen/llvm.h"
 #include "statement.h"
 
+// this is used for tracking try-finally, synchronized and volatile scopes
+struct EnclosingHandler
+{
+    virtual void emitCode(IRState* p) = 0;
+};
+struct EnclosingTryFinally : EnclosingHandler
+{
+    TryFinallyStatement* tf;
+    void emitCode(IRState* p);
+    EnclosingTryFinally(TryFinallyStatement* _tf) : tf(_tf) {}
+};
+struct EnclosingVolatile : EnclosingHandler
+{
+    VolatileStatement* v;
+    void emitCode(IRState* p);
+    EnclosingVolatile(VolatileStatement* _tf) : v(_tf) {}
+};
+struct EnclosingSynchro : EnclosingHandler
+{
+    SynchronizedStatement* s;
+    void emitCode(IRState* p);
+    EnclosingSynchro(SynchronizedStatement* _tf) : s(_tf) {}
+};
+
+
 // dynamic memory helpers
 LLValue* DtoNew(Type* newtype);
 void DtoDeleteMemory(LLValue* ptr);
@@ -16,17 +41,16 @@
 llvm::AllocaInst* DtoAlloca(const LLType* lltype, LLValue* arraysize, const std::string& name = "");
 
 // assertion generator
-void DtoAssert(Module* M, Loc* loc, DValue* msg);
+void DtoAssert(Module* M, Loc loc, DValue* msg);
 
 // return the LabelStatement from the current function with the given identifier or NULL if not found
 LabelStatement* DtoLabelStatement(Identifier* ident);
 // emit goto
-void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosingtryfinally, TryFinallyStatement* sourcetf);
+void DtoGoto(Loc loc, Identifier* target);
 
-// generates IR for finally blocks between the 'start' and 'end' statements
-// will begin with the finally block belonging to 'start' and does not include
-// the finally block of 'end'
-void DtoEnclosingHandlers(EnclosingHandler* start, EnclosingHandler* end);
+// Generates IR for enclosing handlers between the current state and
+// the scope created by the 'target' statement.
+void DtoEnclosingHandlers(Loc loc, Statement* target);
 
 // enters a critical section
 void DtoEnterCritical(LLValue* g);
--- a/gen/statements.cpp	Tue Mar 24 14:34:16 2009 +0100
+++ b/gen/statements.cpp	Tue Mar 24 21:18:18 2009 +0100
@@ -76,7 +76,7 @@
             DtoAssign(loc, rvar, e);
 
             // emit scopes
-            DtoEnclosingHandlers(enclosinghandler, NULL);
+            DtoEnclosingHandlers(loc, NULL);
 
             // emit dbg end function
             if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
@@ -122,7 +122,7 @@
                     Logger::cout() << "return value after cast: " << *v << '\n';
             }
 
-            DtoEnclosingHandlers(enclosinghandler, NULL);
+            DtoEnclosingHandlers(loc, NULL);
 
             if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
             llvm::ReturnInst::Create(v, p->scopebb());
@@ -132,7 +132,7 @@
     else
     {
         assert(p->topfunc()->getReturnType() == LLType::VoidTy);
-        DtoEnclosingHandlers(enclosinghandler, NULL);
+        DtoEnclosingHandlers(loc, NULL);
 
         if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
         llvm::ReturnInst::Create(p->scopebb());
@@ -296,9 +296,9 @@
     gIR->scope() = IRScope(whilebodybb,endbb);
 
     // while body code
-    p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,whilebb,endbb));
+    p->targetScopes.push_back(IRTargetScope(this,NULL,whilebb,endbb));
     body->toIR(p);
-    p->loopbbs.pop_back();
+    p->targetScopes.pop_back();
 
     // loop
     if (!gIR->scopereturned())
@@ -332,9 +332,9 @@
     gIR->scope() = IRScope(dowhilebb,condbb);
 
     // do-while body code
-    p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,condbb,endbb));
+    p->targetScopes.push_back(IRTargetScope(this,NULL,condbb,endbb));
     body->toIR(p);
-    p->loopbbs.pop_back();
+    p->targetScopes.pop_back();
 
     // branch to condition block
     llvm::BranchInst::Create(condbb, gIR->scopebb());
@@ -377,7 +377,7 @@
     assert(!gIR->scopereturned());
     llvm::BranchInst::Create(forbb, gIR->scopebb());
 
-    p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,forincbb,endbb));
+    p->targetScopes.push_back(IRTargetScope(this,NULL,forincbb,endbb));
 
     // replace current scope
     gIR->scope() = IRScope(forbb,forbodybb);
@@ -420,7 +420,7 @@
     if (!gIR->scopereturned())
         llvm::BranchInst::Create(forbb, gIR->scopebb());
 
-    p->loopbbs.pop_back();
+    p->targetScopes.pop_back();
 
     // rewrite the scope
     gIR->scope() = IRScope(endbb,oldend);
@@ -444,7 +444,7 @@
     if (ident != 0) {
         Logger::println("ident = %s", ident->toChars());
 
-        DtoEnclosingHandlers(enclosinghandler, target->enclosinghandler);
+        DtoEnclosingHandlers(loc, target);
 
         // get the loop statement the label refers to
         Statement* targetLoopStatement = target->statement;
@@ -454,10 +454,10 @@
 
         // find the right break block and jump there
         bool found = false;
-        IRState::LoopScopeVec::reverse_iterator it;
-        for(it = p->loopbbs.rbegin(); it != p->loopbbs.rend(); ++it) {
+        IRState::TargetScopeVec::reverse_iterator it;
+        for(it = p->targetScopes.rbegin(); it != p->targetScopes.rend(); ++it) {
             if(it->s == targetLoopStatement) {
-                llvm::BranchInst::Create(it->end, p->scopebb());
+                llvm::BranchInst::Create(it->breakTarget, p->scopebb());
                 found = true;
                 break;
             }
@@ -465,8 +465,15 @@
         assert(found);
     }
     else {
-        DtoEnclosingHandlers(enclosinghandler, p->loopbbs.back().enclosinghandler);
-        llvm::BranchInst::Create(p->loopbbs.back().end, p->scopebb());
+        // find closest scope with a break target
+        IRState::TargetScopeVec::reverse_iterator it;
+        for(it = gIR->targetScopes.rbegin(); it != gIR->targetScopes.rend(); ++it) {
+            if(it->breakTarget) {
+                break;
+            }
+        }
+        DtoEnclosingHandlers(loc, it->s);
+        llvm::BranchInst::Create(it->breakTarget, gIR->scopebb());
     }
 
     // the break terminated this basicblock, start a new one
@@ -488,7 +495,7 @@
     if (ident != 0) {
         Logger::println("ident = %s", ident->toChars());
 
-        DtoEnclosingHandlers(enclosinghandler, target->enclosinghandler);
+        DtoEnclosingHandlers(loc, target);
 
         // get the loop statement the label refers to
         Statement* targetLoopStatement = target->statement;
@@ -498,10 +505,10 @@
 
         // find the right continue block and jump there
         bool found = false;
-        IRState::LoopScopeVec::reverse_iterator it;
-        for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) {
+        IRState::TargetScopeVec::reverse_iterator it;
+        for(it = gIR->targetScopes.rbegin(); it != gIR->targetScopes.rend(); ++it) {
             if(it->s == targetLoopStatement) {
-                llvm::BranchInst::Create(it->begin, gIR->scopebb());
+                llvm::BranchInst::Create(it->continueTarget, gIR->scopebb());
                 found = true;
                 break;
             }
@@ -509,15 +516,15 @@
         assert(found);
     }
     else {
-        // can't 'continue' within switch, so omit them
-        IRState::LoopScopeVec::reverse_iterator it;
-        for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) {
-            if(!it->isSwitch) {
+        // find closest scope with a continue target
+        IRState::TargetScopeVec::reverse_iterator it;
+        for(it = gIR->targetScopes.rbegin(); it != gIR->targetScopes.rend(); ++it) {
+            if(it->continueTarget) {
                 break;
             }
         }
-        DtoEnclosingHandlers(enclosinghandler, it->enclosinghandler);
-        llvm::BranchInst::Create(it->begin, gIR->scopebb());
+        DtoEnclosingHandlers(loc, it->s);
+        llvm::BranchInst::Create(it->continueTarget, gIR->scopebb());
     }
 
     // the continue terminated this basicblock, start a new one
@@ -586,7 +593,9 @@
     p->scope() = IRScope(trybb,finallybb);
 
     assert(body);
+    p->targetScopes.push_back(IRTargetScope(this,new EnclosingTryFinally(this),NULL,NULL));
     body->toIR(p);
+    p->targetScopes.pop_back();
 
     // terminate try BB
     if (!p->scopereturned())
@@ -842,9 +851,9 @@
     assert(body);
 
     p->scope() = IRScope(bodybb, endbb);
-    p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,p->scopebb(),endbb,true));
+    p->targetScopes.push_back(IRTargetScope(this,NULL,NULL,endbb));
     body->toIR(p);
-    p->loopbbs.pop_back();
+    p->targetScopes.pop_back();
 
     if (!p->scopereturned())
         llvm::BranchInst::Create(endbb, p->scopebb());
@@ -963,13 +972,13 @@
 
         // push loop scope
         // continue goes to next statement, break goes to end
-        p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb));
+        p->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb));
 
         // do statement
         s->toIR(p);
 
         // pop loop scope
-        p->loopbbs.pop_back();
+        p->targetScopes.pop_back();
 
         // next stmt
         if (!p->scopereturned())
@@ -1086,10 +1095,10 @@
     }
 
     // emit body
-    p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb));
+    p->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb));
     if(body)
         body->toIR(p);
-    p->loopbbs.pop_back();
+    p->targetScopes.pop_back();
 
     if (!p->scopereturned())
         llvm::BranchInst::Create(nextbb, p->scopebb());
@@ -1182,10 +1191,10 @@
     }
 
     // emit body
-    p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb));
+    p->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb));
     if (body)
         body->toIR(p);
-    p->loopbbs.pop_back();
+    p->targetScopes.pop_back();
 
     // jump to next iteration
     if (!p->scopereturned())
@@ -1251,8 +1260,11 @@
         p->scope() = IRScope(labelBB,oldend);
     }
 
-    if (statement)
+    if (statement) {
+        p->targetScopes.push_back(IRTargetScope(this,NULL,NULL,NULL));
         statement->toIR(p);
+        p->targetScopes.pop_back();
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1268,7 +1280,7 @@
     llvm::BasicBlock* oldend = gIR->scopeend();
     llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergoto", p->topfunc(), oldend);
 
-    DtoGoto(&loc, label->ident, enclosinghandler, tf);
+    DtoGoto(loc, label->ident);
 
     p->scope() = IRScope(bb,oldend);
 }
@@ -1289,7 +1301,7 @@
     assert(!p->scopereturned());
     assert(sw->sdefault->bodyBB);
 
-    DtoEnclosingHandlers(enclosinghandler, sw->enclosinghandler);
+    DtoEnclosingHandlers(loc, sw);
 
     llvm::BranchInst::Create(sw->sdefault->bodyBB, p->scopebb());
     p->scope() = IRScope(bb,oldend);
@@ -1314,7 +1326,7 @@
         cs->bodyBB = llvm::BasicBlock::Create("goto_case", p->topfunc(), p->scopeend());
     }
 
-    DtoEnclosingHandlers(enclosinghandler, sw->enclosinghandler);
+    DtoEnclosingHandlers(loc, sw);
 
     llvm::BranchInst::Create(cs->bodyBB, p->scopebb());
     p->scope() = IRScope(bb,oldend);
@@ -1373,7 +1385,9 @@
     }
 
     // emit body
+    p->targetScopes.push_back(IRTargetScope(this,new EnclosingSynchro(this),NULL,NULL));
     body->toIR(p);
+    p->targetScopes.pop_back();
 
     // exit lock
     // no point in a unreachable unlock, terminating statements must insert this themselves.
@@ -1405,7 +1419,9 @@
         DtoMemoryBarrier(false, true, false, false);
 
         // do statement
+	p->targetScopes.push_back(IRTargetScope(this,new EnclosingVolatile(this),NULL,NULL));
         statement->toIR(p);
+	p->targetScopes.pop_back();
 
         // no point in a unreachable barrier, terminating statements must insert this themselves.
         if (statement->blockExit() & BEfallthru)
--- a/gen/toir.cpp	Tue Mar 24 14:34:16 2009 +0100
+++ b/gen/toir.cpp	Tue Mar 24 21:18:18 2009 +0100
@@ -1783,7 +1783,7 @@
 
         // call assert runtime functions
         p->scope() = IRScope(assertbb,endbb);
-        DtoAssert(p->func()->decl->getModule(), &loc, msg ? msg->toElem(p) : NULL);
+        DtoAssert(p->func()->decl->getModule(), loc, msg ? msg->toElem(p) : NULL);
 
         // rewrite the scope
         p->scope() = IRScope(endbb,oldend);
@@ -1958,7 +1958,7 @@
     // FIXME: DMD inserts a trap here... we probably should as well !?!
 
 #if 1
-    DtoAssert(p->func()->decl->getModule(), &loc, NULL);
+    DtoAssert(p->func()->decl->getModule(), loc, NULL);
 #else
     // call the new (?) trap intrinsic
     p->ir->CreateCall(GET_INTRINSIC_DECL(trap),"");