changeset 145:8f704cb9969b trunk

[svn r150] fixes #16 and #17, implements GotoCaseStatement
author ChristianK
date Sat, 08 Mar 2008 15:22:07 +0100
parents a27941d00351
children ddfdae91281a
files dmd/scope.c dmd/scope.h dmd/statement.c dmd/statement.h gen/irstate.cpp gen/irstate.h gen/statements.cpp ir/irfunction.cpp ir/irfunction.h
diffstat 9 files changed, 229 insertions(+), 111 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/scope.c	Sat Jan 26 17:13:22 2008 +0100
+++ b/dmd/scope.c	Sat Mar 08 15:22:07 2008 +0100
@@ -53,6 +53,7 @@
     this->parent = NULL;
     this->sw = NULL;
     this->tf = NULL;
+    this->tfOfTry = NULL;
     this->sbreak = NULL;
     this->scontinue = NULL;
     this->fes = NULL;
@@ -89,6 +90,7 @@
     this->sd = NULL;
     this->sw = enclosing->sw;
     this->tf = enclosing->tf;
+    this->tfOfTry = enclosing->tfOfTry;
     this->sbreak = enclosing->sbreak;
     this->scontinue = enclosing->scontinue;
     this->fes = enclosing->fes;
--- a/dmd/scope.h	Sat Jan 26 17:13:22 2008 +0100
+++ b/dmd/scope.h	Sat Mar 08 15:22:07 2008 +0100
@@ -44,7 +44,8 @@
     Dsymbol *parent;		// parent to use
     LabelStatement *slabel;	// enclosing labelled statement
     SwitchStatement *sw;	// enclosing switch statement
-    TryFinallyStatement *tf;	// enclosing try finally statement
+    TryFinallyStatement *tf;	// enclosing try finally statement; set inside its finally block
+    TryFinallyStatement *tfOfTry; // enclosing try finally statement; set inside its try block
     Statement *sbreak;		// enclosing statement that supports "break"
     Statement *scontinue;	// enclosing statement that supports "continue"
     ForeachStatement *fes;	// if nested function for ForeachStatement, this is it
--- a/dmd/statement.c	Sat Jan 26 17:13:22 2008 +0100
+++ b/dmd/statement.c	Sat Mar 08 15:22:07 2008 +0100
@@ -561,6 +561,7 @@
     : Statement(loc)
 {
     statements = s;
+    enclosingtry = NULL;
 }
 
 Statement *UnrolledLoopStatement::syntaxCopy()
@@ -582,6 +583,8 @@
 {
     //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc);
 
+    enclosingtry = sc->tfOfTry;
+
     sc->noctor++;
     Scope *scd = sc->push();
     scd->sbreak = this;
@@ -771,6 +774,7 @@
 {
     condition = c;
     body = b;
+    enclosingtry = NULL;
 }
 
 Statement *WhileStatement::syntaxCopy()
@@ -805,6 +809,8 @@
     }
 #endif
 
+    enclosingtry = sc->tfOfTry;
+
     condition = condition->semantic(sc);
     condition = resolveProperties(sc, condition);
     condition = condition->optimize(WANTvalue);
@@ -870,6 +876,7 @@
 {
     body = b;
     condition = c;
+    enclosingtry = NULL;
 }
 
 Statement *DoStatement::syntaxCopy()
@@ -881,6 +888,8 @@
 
 Statement *DoStatement::semantic(Scope *sc)
 {
+    enclosingtry = sc->tfOfTry;
+
     sc->noctor++;
     if (body)
 	body = body->semanticScope(sc, this, this);
@@ -943,6 +952,7 @@
     this->condition = condition;
     this->increment = increment;
     this->body = body;
+    this->enclosingtry = NULL;
 }
 
 Statement *ForStatement::syntaxCopy()
@@ -962,6 +972,8 @@
 
 Statement *ForStatement::semantic(Scope *sc)
 {
+    enclosingtry = sc->tfOfTry;
+
     ScopeDsymbol *sym = new ScopeDsymbol();
     sym->parent = sc->scopesym;
     sc = sc->push(sym);
@@ -1074,6 +1086,7 @@
     this->arguments = arguments;
     this->aggr = aggr;
     this->body = body;
+    this->enclosingtry = NULL;
 
     this->key = NULL;
     this->value = NULL;
@@ -1102,6 +1115,8 @@
     Type *tn = NULL;
     Type *tnv = NULL;
 
+    enclosingtry = sc->tfOfTry;
+
     func = sc->func;
     if (func->fes)
 	func = func->fes->func;
@@ -1956,7 +1971,7 @@
     cases = NULL;
     hasNoDefault = 0;
     // LLVMDC
-    defaultBB = NULL;
+    enclosingtry = NULL;
 }
 
 Statement *SwitchStatement::syntaxCopy()
@@ -1970,6 +1985,9 @@
 {
     //printf("SwitchStatement::semantic(%p)\n", this);
     assert(!cases);		// ensure semantic() is only run once
+
+    enclosingtry = sc->tfOfTry;
+
     condition = condition->semantic(sc);
     condition = resolveProperties(sc, condition);
     if (condition->type->isString())
@@ -2107,6 +2125,7 @@
     this->exp = exp;
     this->statement = s;
     cblock = NULL;
+    bodyBB = NULL;
 }
 
 Statement *CaseStatement::syntaxCopy()
@@ -2203,6 +2222,7 @@
 #if IN_GCC
 +    cblock = NULL;
 #endif
+    bodyBB = NULL;
 }
 
 Statement *DefaultStatement::syntaxCopy()
@@ -2254,6 +2274,7 @@
     : Statement(loc)
 {
     sw = NULL;
+    enclosingtry = NULL;
 }
 
 Statement *GotoDefaultStatement::syntaxCopy()
@@ -2264,6 +2285,7 @@
 
 Statement *GotoDefaultStatement::semantic(Scope *sc)
 {
+    enclosingtry = sc->tfOfTry;
     sw = sc->sw;
     if (!sw)
 	error("goto default not in switch statement");
@@ -2287,6 +2309,8 @@
 {
     cs = NULL;
     this->exp = exp;
+    enclosingtry = NULL;
+    sw = NULL;
 }
 
 Statement *GotoCaseStatement::syntaxCopy()
@@ -2298,6 +2322,7 @@
 
 Statement *GotoCaseStatement::semantic(Scope *sc)
 {
+    enclosingtry = sc->tfOfTry;
     if (exp)
 	exp = exp->semantic(sc);
 
@@ -2305,6 +2330,7 @@
 	error("goto case not in switch statement");
     else
     {
+	sw = sc->sw;
 	sc->sw->gotoCases.push(this);
 	if (exp)
 	{
@@ -2355,6 +2381,7 @@
     : Statement(loc)
 {
     this->exp = exp;
+    this->enclosingtry = NULL;
 }
 
 Statement *ReturnStatement::syntaxCopy()
@@ -2369,6 +2396,7 @@
 Statement *ReturnStatement::semantic(Scope *sc)
 {
     //printf("ReturnStatement::semantic() %s\n", toChars());
+    this->enclosingtry = sc->tfOfTry;
 
     FuncDeclaration *fd = sc->parent->isFuncDeclaration();
     Scope *scx = sc;
@@ -2629,6 +2657,7 @@
     : Statement(loc)
 {
     this->ident = ident;
+    this->enclosingtry = NULL;
 }
 
 Statement *BreakStatement::syntaxCopy()
@@ -2639,6 +2668,7 @@
 
 Statement *BreakStatement::semantic(Scope *sc)
 {
+    enclosingtry = sc->tfOfTry;
     // If:
     //	break Identifier;
     if (ident)
@@ -2678,6 +2708,8 @@
 		    error("label '%s' has no break", ident->toChars());
 		if (ls->tf != sc->tf)
 		    error("cannot break out of finally block");
+		
+		this->target = ls;
 		return this;
 	    }
 	}
@@ -2719,6 +2751,7 @@
     : Statement(loc)
 {
     this->ident = ident;
+    this->enclosingtry = NULL;
 }
 
 Statement *ContinueStatement::syntaxCopy()
@@ -2729,6 +2762,7 @@
 
 Statement *ContinueStatement::semantic(Scope *sc)
 {
+    enclosingtry = sc->tfOfTry;
     //printf("ContinueStatement::semantic() %p\n", this);
     if (ident)
     {
@@ -2777,6 +2811,8 @@
 		    error("label '%s' has no continue", ident->toChars());
 		if (ls->tf != sc->tf)
 		    error("cannot continue out of finally block");
+		
+		this->target = ls;
 		return this;
 	    }
 	}
@@ -3159,6 +3195,7 @@
 {
     this->body = body;
     this->finalbody = finalbody;
+    this->enclosingtry = NULL;
 }
 
 Statement *TryFinallyStatement::syntaxCopy()
@@ -3171,7 +3208,12 @@
 Statement *TryFinallyStatement::semantic(Scope *sc)
 {
     //printf("TryFinallyStatement::semantic()\n");
+
+    enclosingtry = sc->tfOfTry;
+    sc->tfOfTry = this;
     body = body->semantic(sc);
+    sc->tfOfTry = enclosingtry;
+
     sc = sc->push();
     sc->tf = this;
     sc->sbreak = NULL;
@@ -3405,6 +3447,7 @@
     this->ident = ident;
     this->label = NULL;
     this->tf = NULL;
+    this->enclosingtry = NULL;
 }
 
 Statement *GotoStatement::syntaxCopy()
@@ -3418,6 +3461,7 @@
 
     //printf("GotoStatement::semantic()\n");
     tf = sc->tf;
+    enclosingtry = sc->tfOfTry;
     label = fd->searchLabel(ident);
     if (!label->statement && sc->fes)
     {
@@ -3461,6 +3505,7 @@
     this->ident = ident;
     this->statement = statement;
     this->tf = NULL;
+    this->enclosingtry = NULL;
     this->lblock = NULL;
     this->isReturnLabel = 0;
     this->llvmBB = NULL;
@@ -3483,6 +3528,7 @@
     else
 	ls->statement = this;
     tf = sc->tf;
+    enclosingtry = sc->tfOfTry;
     sc = sc->push();
     sc->scopesym = sc->enclosing->scopesym;
     sc->callSuper |= CSXlabel;
--- a/dmd/statement.h	Sat Jan 26 17:13:22 2008 +0100
+++ b/dmd/statement.h	Sat Mar 08 15:22:07 2008 +0100
@@ -44,9 +44,11 @@
 struct GotoStatement;
 struct ScopeStatement;
 struct TryCatchStatement;
+struct TryFinallyStatement;
 struct HdrGenState;
 struct InterState;
 struct CaseStatement;
+struct LabelStatement;
 
 enum TOK;
 
@@ -191,6 +193,7 @@
 struct UnrolledLoopStatement : Statement
 {
     Statements *statements;
+    TryFinallyStatement *enclosingtry;
 
     UnrolledLoopStatement(Loc loc, Statements *statements);
     Statement *syntaxCopy();
@@ -235,6 +238,7 @@
 {
     Expression *condition;
     Statement *body;
+    TryFinallyStatement *enclosingtry;
 
     WhileStatement(Loc loc, Expression *c, Statement *b);
     Statement *syntaxCopy();
@@ -256,6 +260,7 @@
 {
     Statement *body;
     Expression *condition;
+    TryFinallyStatement *enclosingtry;
 
     DoStatement(Loc loc, Statement *b, Expression *c);
     Statement *syntaxCopy();
@@ -279,6 +284,7 @@
     Expression *condition;
     Expression *increment;
     Statement *body;
+    TryFinallyStatement *enclosingtry;
 
     ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body);
     Statement *syntaxCopy();
@@ -303,6 +309,7 @@
     Arguments *arguments;	// array of Argument*'s
     Expression *aggr;
     Statement *body;
+    TryFinallyStatement *enclosingtry;
 
     VarDeclaration *key;
     VarDeclaration *value;
@@ -399,6 +406,7 @@
     Expression *condition;
     Statement *body;
     DefaultStatement *sdefault;
+    TryFinallyStatement *enclosingtry;
 
     Array gotoCases;		// array of unresolved GotoCaseStatement's
     Array *cases;		// array of CaseStatement's
@@ -416,9 +424,6 @@
     Statement *inlineScan(InlineScanState *iss);
 
     void toIR(IRState *irs);
-
-    // LLVMDC
-    llvm::BasicBlock* defaultBB;
 };
 
 struct CaseStatement : Statement
@@ -443,6 +448,9 @@
     void toIR(IRState *irs);
 
     CaseStatement* isCaseStatement() { return this; }
+
+    // LLVMDC
+    llvm::BasicBlock* bodyBB;
 };
 
 struct DefaultStatement : Statement
@@ -464,11 +472,15 @@
     Statement *inlineScan(InlineScanState *iss);
 
     void toIR(IRState *irs);
+
+    // LLVMDC
+    llvm::BasicBlock* bodyBB;
 };
 
 struct GotoDefaultStatement : Statement
 {
     SwitchStatement *sw;
+    TryFinallyStatement *enclosingtry;
 
     GotoDefaultStatement(Loc loc);
     Statement *syntaxCopy();
@@ -484,6 +496,8 @@
 {
     Expression *exp;		// NULL, or which case to goto
     CaseStatement *cs;		// case statement it resolves to
+    TryFinallyStatement *enclosingtry;
+    SwitchStatement *sw;
 
     GotoCaseStatement(Loc loc, Expression *exp);
     Statement *syntaxCopy();
@@ -507,6 +521,7 @@
 struct ReturnStatement : Statement
 {
     Expression *exp;
+    TryFinallyStatement *enclosingtry;
 
     ReturnStatement(Loc loc, Expression *exp);
     Statement *syntaxCopy();
@@ -527,6 +542,7 @@
 struct BreakStatement : Statement
 {
     Identifier *ident;
+    TryFinallyStatement *enclosingtry;
 
     BreakStatement(Loc loc, Identifier *ident);
     Statement *syntaxCopy();
@@ -536,11 +552,15 @@
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
     void toIR(IRState *irs);
+
+    // LLVMDC: only set if ident is set: label statement to jump to
+    LabelStatement *target;
 };
 
 struct ContinueStatement : Statement
 {
     Identifier *ident;
+    TryFinallyStatement *enclosingtry;
 
     ContinueStatement(Loc loc, Identifier *ident);
     Statement *syntaxCopy();
@@ -550,6 +570,9 @@
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
 
     void toIR(IRState *irs);
+
+    // LLVMDC: only set if ident is set: label statement to jump to
+    LabelStatement *target;
 };
 
 struct SynchronizedStatement : Statement
@@ -629,6 +652,7 @@
 {
     Statement *body;
     Statement *finalbody;
+    TryFinallyStatement *enclosingtry;
 
     TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody);
     Statement *syntaxCopy();
@@ -695,6 +719,7 @@
     Identifier *ident;
     LabelDsymbol *label;
     TryFinallyStatement *tf;
+    TryFinallyStatement *enclosingtry;
 
     GotoStatement(Loc loc, Identifier *ident);
     Statement *syntaxCopy();
@@ -712,6 +737,7 @@
     Identifier *ident;
     Statement *statement;
     TryFinallyStatement *tf;
+    TryFinallyStatement *enclosingtry;
     block *lblock;		// back end
     int isReturnLabel;
 
--- a/gen/irstate.cpp	Sat Jan 26 17:13:22 2008 +0100
+++ b/gen/irstate.cpp	Sat Mar 08 15:22:07 2008 +0100
@@ -31,6 +31,20 @@
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
+IRLoopScope::IRLoopScope()
+{
+}
+
+IRLoopScope::IRLoopScope(Statement* s, TryFinallyStatement* enclosingtry, llvm::BasicBlock* b, llvm::BasicBlock* e)
+{
+    begin = b;
+    end = e;
+    builder.SetInsertPoint(b);
+    this->s = s;
+    this->enclosingtry = enclosingtry;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
 IRState::IRState()
 {
     dmodule = 0;
--- a/gen/irstate.h	Sat Jan 26 17:13:22 2008 +0100
+++ b/gen/irstate.h	Sat Mar 08 15:22:07 2008 +0100
@@ -23,6 +23,7 @@
 struct Module;
 struct TypeStruct;
 struct BaseClass;
+struct TryFinallyStatement;
 
 // represents a scope
 struct IRScope
@@ -35,6 +36,18 @@
     IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e);
 };
 
+// scope for loops
+struct IRLoopScope : IRScope
+{
+    // generating statement
+    Statement* s;
+    // the try of a TryFinally that encloses the loop
+    TryFinallyStatement* enclosingtry;
+
+    IRLoopScope();
+    IRLoopScope(Statement* s, TryFinallyStatement* enclosingtry, llvm::BasicBlock* b, llvm::BasicBlock* e);
+};
+
 struct IRBuilderHelper
 {
     IRState* state;
@@ -95,7 +108,8 @@
 
     // loop blocks
     typedef std::vector<IRScope> BBVec;
-    BBVec loopbbs;
+    typedef std::vector<IRLoopScope> LoopScopeVec;
+    LoopScopeVec loopbbs;
 
     // 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/statements.cpp	Sat Jan 26 17:13:22 2008 +0100
+++ b/gen/statements.cpp	Sat Mar 08 15:22:07 2008 +0100
@@ -45,6 +45,28 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
+// 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 emit_finallyblocks(IRState* p, TryFinallyStatement* start, TryFinallyStatement* end)
+{
+    // verify that end encloses start
+    TryFinallyStatement* endfinally = start;
+    while(endfinally != NULL && endfinally != end) {
+        endfinally = endfinally->enclosingtry;
+    }
+    assert(endfinally == end);
+
+    // emit code for finallys between start and end
+    TryFinallyStatement* tf = start;
+    while(tf != end) {
+        tf->finalbody->toIR(p);
+        tf = tf->enclosingtry;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
 void ReturnStatement::toIR(IRState* p)
 {
     Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
@@ -68,14 +90,11 @@
             if (!e->inPlace())
                 DtoAssign(rvar, e);
 
-            IrFunction::FinallyVec& fin = f->finallys;
-            if (fin.empty()) {
-                if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
-                new llvm::ReturnInst(p->scopebb());
-            }
-            else {
-                new llvm::BranchInst(fin.back().retbb, p->scopebb());
-            }
+            emit_finallyblocks(p, enclosingtry, NULL);
+
+            if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
+            new llvm::ReturnInst(p->scopebb());
+
         }
         else {
             if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
@@ -84,31 +103,19 @@
             delete e;
             Logger::cout() << "return value is '" <<*v << "'\n";
 
-            IrFunction::FinallyVec& fin = p->func()->finallys;
-            if (fin.empty()) {
-                if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
-                new llvm::ReturnInst(v, p->scopebb());
-            }
-            else {
-                if (!p->func()->finallyretval)
-                    p->func()->finallyretval = new llvm::AllocaInst(v->getType(),"tmpreturn",p->topallocapoint());
-                llvm::Value* rettmp = p->func()->finallyretval;
-                new llvm::StoreInst(v,rettmp,p->scopebb());
-                new llvm::BranchInst(fin.back().retbb, p->scopebb());
-            }
+            emit_finallyblocks(p, enclosingtry, NULL);
+
+            if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
+            new llvm::ReturnInst(v, p->scopebb());
         }
     }
     else
     {
         if (p->topfunc()->getReturnType() == llvm::Type::VoidTy) {
-            IrFunction::FinallyVec& fin = p->func()->finallys;
-            if (fin.empty()) {
-                if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
-                new llvm::ReturnInst(p->scopebb());
-            }
-            else {
-                new llvm::BranchInst(fin.back().retbb, p->scopebb());
-            }
+            emit_finallyblocks(p, enclosingtry, NULL);
+
+            if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
+            new llvm::ReturnInst(p->scopebb());
         }
         else {
             assert(0); // why should this ever happen?
@@ -247,7 +254,7 @@
     gIR->scope() = IRScope(whilebodybb,endbb);
 
     // while body code
-    p->loopbbs.push_back(IRScope(whilebb,endbb));
+    p->loopbbs.push_back(IRLoopScope(this,enclosingtry,whilebb,endbb));
     body->toIR(p);
     p->loopbbs.pop_back();
 
@@ -279,7 +286,7 @@
     gIR->scope() = IRScope(dowhilebb,endbb);
 
     // do-while body code
-    p->loopbbs.push_back(IRScope(dowhilebb,endbb));
+    p->loopbbs.push_back(IRLoopScope(this,enclosingtry,dowhilebb,endbb));
     body->toIR(p);
     p->loopbbs.pop_back();
 
@@ -317,7 +324,7 @@
     assert(!gIR->scopereturned());
     new llvm::BranchInst(forbb, gIR->scopebb());
 
-    p->loopbbs.push_back(IRScope(forincbb,endbb));
+    p->loopbbs.push_back(IRLoopScope(this,enclosingtry,forincbb,endbb));
 
     // replace current scope
     gIR->scope() = IRScope(forbb,forbodybb);
@@ -367,9 +374,27 @@
 
     if (ident != 0) {
         Logger::println("ident = %s", ident->toChars());
+
+        emit_finallyblocks(p, enclosingtry, target->enclosingtry);
+
+        // get the loop statement the label refers to
+        Statement* targetLoopStatement = target->statement;
+        ScopeStatement* tmp;
+        while(tmp = targetLoopStatement->isScopeStatement())
+            targetLoopStatement = tmp->statement;
+
+        // find the right break block and jump there
+        IRState::LoopScopeVec::reverse_iterator it;
+        for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) {
+            if(it->s == targetLoopStatement) {
+                new llvm::BranchInst(it->end, gIR->scopebb());
+                return;
+            }
+        }
         assert(0);
     }
     else {
+        emit_finallyblocks(p, enclosingtry, gIR->loopbbs.back().enclosingtry);
         new llvm::BranchInst(gIR->loopbbs.back().end, gIR->scopebb());
     }
 }
@@ -383,9 +408,27 @@
 
     if (ident != 0) {
         Logger::println("ident = %s", ident->toChars());
+
+        emit_finallyblocks(p, enclosingtry, target->enclosingtry);
+
+        // get the loop statement the label refers to
+        Statement* targetLoopStatement = target->statement;
+        ScopeStatement* tmp;
+        while(tmp = targetLoopStatement->isScopeStatement())
+            targetLoopStatement = tmp->statement;
+
+        // find the right continue block and jump there
+        IRState::LoopScopeVec::reverse_iterator it;
+        for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) {
+            if(it->s == targetLoopStatement) {
+                new llvm::BranchInst(it->begin, gIR->scopebb());
+                return;
+            }
+        }
         assert(0);
     }
     else {
+        emit_finallyblocks(p, enclosingtry, gIR->loopbbs.back().enclosingtry);
         new llvm::BranchInst(gIR->loopbbs.back().begin, gIR->scopebb());
     }
 }
@@ -413,7 +456,6 @@
 
     llvm::BasicBlock* trybb = new llvm::BasicBlock("try", p->topfunc(), oldend);
     llvm::BasicBlock* finallybb = new llvm::BasicBlock("finally", p->topfunc(), oldend);
-    llvm::BasicBlock* finallyretbb = new llvm::BasicBlock("finallyreturn", p->topfunc(), oldend);
     llvm::BasicBlock* endbb = new llvm::BasicBlock("endtryfinally", p->topfunc(), oldend);
 
     // pass the previous BB into this
@@ -422,8 +464,6 @@
 
     // do the try block
     p->scope() = IRScope(trybb,finallybb);
-    gIR->func()->finallys.push_back(IrFinally(finallybb,finallyretbb));
-    IrFinally& fin = p->func()->finallys.back();
 
     assert(body);
     body->toIR(p);
@@ -433,7 +473,7 @@
         new llvm::BranchInst(finallybb, p->scopebb());
 
     // do finally block
-    p->scope() = IRScope(finallybb,finallyretbb);
+    p->scope() = IRScope(finallybb,endbb);
     assert(finalbody);
     finalbody->toIR(p);
 
@@ -442,40 +482,7 @@
         new llvm::BranchInst(endbb, p->scopebb());
     }
 
-    // do finally block (return path)
-    p->scope() = IRScope(finallyretbb,endbb);
-    assert(finalbody);
-    finalbody->toIR(p); // hope this will work, otherwise it's time it gets fixed
-
-    // terminate finally (return path)
-    size_t nfin = p->func()->finallys.size();
-    if (nfin > 1) {
-        IrFinally& ofin = p->func()->finallys[nfin-2];
-        p->ir->CreateBr(ofin.retbb);
-    }
-    // no outer
-    else
-    {
-        if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
-        llvm::Value* retval = p->func()->finallyretval;
-        if (retval) {
-            retval = p->ir->CreateLoad(retval,"tmp");
-            p->ir->CreateRet(retval);
-        }
-        else {
-            FuncDeclaration* fd = p->func()->decl;
-            if (fd->isMain()) {
-                assert(fd->type->next->ty == Tvoid);
-                p->ir->CreateRet(DtoConstInt(0));
-            }
-            else {
-                p->ir->CreateRetVoid();
-            }
-        }
-    }
-
     // rewrite the scope
-    p->func()->finallys.pop_back();
     p->scope() = IRScope(endbb,oldend);
 }
 
@@ -603,6 +610,7 @@
 
         std::string lblname("case");
         llvm::BasicBlock* bb = new llvm::BasicBlock(lblname, p->topfunc(), oldend);
+        cs->bodyBB = bb;
 
         std::vector<llvm::ConstantInt*> tmp;
         CaseStatement* last;
@@ -670,7 +678,7 @@
     llvm::BasicBlock* defbb = 0;
     if (!hasNoDefault) {
         defbb = new llvm::BasicBlock("default", p->topfunc(), oldend);
-        defaultBB = defbb;
+        sdefault->bodyBB = defbb;
     }
 
     // end (break point)
@@ -705,8 +713,7 @@
     {
         llvm::BasicBlock* nextbb = (i == n-1) ? (defbb ? defbb : endbb) : vcases[i+1].first;
         p->scope() = IRScope(vcases[i].first,nextbb);
-
-        p->loopbbs.push_back(IRScope(p->scopebb(),endbb));
+        p->loopbbs.push_back(IRLoopScope(this,enclosingtry,p->scopebb(),endbb));
         vbodies[i]->toIR(p);
         p->loopbbs.pop_back();
 
@@ -721,7 +728,7 @@
     if (defbb)
     {
         p->scope() = IRScope(defbb,endbb);
-        p->loopbbs.push_back(IRScope(defbb,endbb));
+        p->loopbbs.push_back(IRLoopScope(this,enclosingtry,p->scopebb(),endbb));
         Logger::println("doing default statement");
         sdefault->statement->toIR(p);
         p->loopbbs.pop_back();
@@ -756,7 +763,7 @@
     llvm::BasicBlock* endbb = new llvm::BasicBlock("unrolledend", p->topfunc(), oldend);
 
     p->scope() = IRScope(p->scopebb(),endbb);
-    p->loopbbs.push_back(IRScope(p->scopebb(),endbb));
+    p->loopbbs.push_back(IRLoopScope(this,enclosingtry,p->scopebb(),endbb));
 
     for (int i=0; i<statements->dim; ++i)
     {
@@ -914,7 +921,7 @@
     }
 
     // emit body
-    p->loopbbs.push_back(IRScope(nextbb,endbb));
+    p->loopbbs.push_back(IRLoopScope(this,enclosingtry,nextbb,endbb));
     body->toIR(p);
     p->loopbbs.pop_back();
 
@@ -973,6 +980,20 @@
     if (label->statement->llvmBB == NULL)
         label->statement->llvmBB = new llvm::BasicBlock("label", p->topfunc());
     assert(!p->scopereturned());
+
+    // find finallys between goto and label
+    TryFinallyStatement* endfinally = enclosingtry;
+    while(endfinally != NULL && endfinally != label->statement->enclosingtry) {
+        endfinally = endfinally->enclosingtry;
+    }
+
+    // error if didn't find tf statement of label
+    if(endfinally != label->statement->enclosingtry)
+        error("cannot goto into try block", loc.toChars());
+
+    // emit code for finallys between goto and label
+    emit_finallyblocks(p, enclosingtry, endfinally);
+
     new llvm::BranchInst(label->statement->llvmBB, p->scopebb());
     p->scope() = IRScope(bb,oldend);
 }
@@ -988,8 +1009,30 @@
     llvm::BasicBlock* bb = new llvm::BasicBlock("aftergotodefault", p->topfunc(), oldend);
 
     assert(!p->scopereturned());
-    assert(sw->defaultBB);
-    new llvm::BranchInst(sw->defaultBB, p->scopebb());
+    assert(sw->sdefault->bodyBB);
+
+    emit_finallyblocks(p, enclosingtry, sw->enclosingtry);
+
+    new llvm::BranchInst(sw->sdefault->bodyBB, p->scopebb());
+    p->scope() = IRScope(bb,oldend);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void GotoCaseStatement::toIR(IRState* p)
+{
+    Logger::println("GotoCaseStatement::toIR(): %s", loc.toChars());
+    LOG_SCOPE;
+
+    llvm::BasicBlock* oldend = gIR->scopeend();
+    llvm::BasicBlock* bb = new llvm::BasicBlock("aftergotocase", p->topfunc(), oldend);
+
+    assert(!p->scopereturned());
+    assert(cs->bodyBB);
+
+    emit_finallyblocks(p, enclosingtry, sw->enclosingtry);
+
+    new llvm::BranchInst(cs->bodyBB, p->scopebb());
     p->scope() = IRScope(bb,oldend);
 }
 
@@ -1097,7 +1140,7 @@
 //STUBST(VolatileStatement);
 //STUBST(LabelStatement);
 //STUBST(ThrowStatement);
-STUBST(GotoCaseStatement);
+//STUBST(GotoCaseStatement);
 //STUBST(GotoDefaultStatement);
 //STUBST(GotoStatement);
 //STUBST(UnrolledLoopStatement);
--- a/ir/irfunction.cpp	Sat Jan 26 17:13:22 2008 +0100
+++ b/ir/irfunction.cpp	Sat Mar 08 15:22:07 2008 +0100
@@ -1,18 +1,6 @@
 #include "gen/tollvm.h"
 #include "ir/irfunction.h"
 
-IrFinally::IrFinally()
-{
-    bb = 0;
-    retbb = 0;
-}
-
-IrFinally::IrFinally(llvm::BasicBlock* b, llvm::BasicBlock* rb)
-{
-    bb = b;
-    retbb = rb;
-}
-
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
@@ -26,7 +14,6 @@
     type = (TypeFunction*)t;
     func = NULL;
     allocapoint = NULL;
-    finallyretval = NULL;
 
     queued = false;
     defined = false;
--- a/ir/irfunction.h	Sat Jan 26 17:13:22 2008 +0100
+++ b/ir/irfunction.h	Sat Mar 08 15:22:07 2008 +0100
@@ -5,16 +5,6 @@
 
 #include <vector>
 
-// represents a finally block
-struct IrFinally
-{
-    llvm::BasicBlock* bb;
-    llvm::BasicBlock* retbb;
-
-    IrFinally();
-    IrFinally(llvm::BasicBlock* b, llvm::BasicBlock* rb);
-};
-
 // represents a function
 struct IrFunction : IrBase
 {
@@ -23,11 +13,6 @@
     FuncDeclaration* decl;
     TypeFunction* type;
 
-    // finally blocks
-    typedef std::vector<IrFinally> FinallyVec;
-    FinallyVec finallys;
-    llvm::Value* finallyretval;
-
     bool queued;
     bool defined;
     llvm::Value* retArg;