Index: optimize.c
===================================================================
--- optimize.c	(revision 31)
+++ optimize.c	(working copy)
@@ -444,11 +444,14 @@
 	    }
 	    else if (result & WANTinterpret)
 	    {
-		Expression *eresult = fd->interpret(NULL, arguments);
-		if (eresult && eresult != EXP_VOID_INTERPRET)
+		InterState istate;
+		Expression *eresult = fd->interpret(&istate, arguments);
+		if (!eresult || eresult == EXP_CANT_INTERPRET)
+		    error("cannot evaluate %s at compile time", toChars());
+		else if (eresult == EXP_THROW_INTERPRET)
+		    error("uncaught exception from %s: %s", toChars(), istate.exception->toChars());
+		else if (eresult != EXP_VOID_INTERPRET)
 		    e = eresult;
-		else
-		    error("cannot evaluate %s at compile time", toChars());
 	    }
 	}
     }
Index: statement.h
===================================================================
--- statement.h	(revision 31)
+++ statement.h	(working copy)
@@ -645,6 +645,7 @@
     int hasBreak();
     int usesEH();
     int blockExit();
+    Expression *interpret(InterState *istate);
 
     Statement *inlineScan(InlineScanState *iss);
 
@@ -681,6 +682,7 @@
     int hasContinue();
     int usesEH();
     int blockExit();
+    Expression *interpret(InterState *istate);
 
     Statement *inlineScan(InlineScanState *iss);
 
@@ -712,6 +714,7 @@
     Statement *semantic(Scope *sc);
     void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
     int blockExit();
+    Expression *interpret(InterState *istate);
 
     Statement *inlineScan(InlineScanState *iss);
 
Index: expression.h
===================================================================
--- expression.h	(revision 31)
+++ expression.h	(working copy)
@@ -1519,7 +1519,21 @@
 #define EXP_BREAK_INTERPRET	((Expression *)3)
 #define EXP_GOTO_INTERPRET	((Expression *)4)
 #define EXP_VOID_INTERPRET	((Expression *)5)
+#define EXP_THROW_INTERPRET	((Expression *)6)
 
+struct InterState
+{
+    InterState *caller;		// calling function's InterState
+    FuncDeclaration *fd;	// function being interpreted
+    Dsymbols vars;		// variables used in this function
+    Statement *start;		// if !=NULL, start execution at this statement
+    Statement *gotoTarget;	// target of EXP_GOTO_INTERPRET result
+    Expression *exception;	// if !=NULL, uncaught exception
+
+    InterState();
+};
+
+
 Expression *expType(Type *type, Expression *e);
 
 Expression *Neg(Type *type, Expression *e1);
Index: interpret.c
===================================================================
--- interpret.c	(revision 31)
+++ interpret.c	(working copy)
@@ -27,17 +27,7 @@
 
 #define LOG	0
 
-struct InterState
-{
-    InterState *caller;		// calling function's InterState
-    FuncDeclaration *fd;	// function being interpreted
-    Dsymbols vars;		// variables used in this function
-    Statement *start;		// if !=NULL, start execution at this statement
-    Statement *gotoTarget;	// target of EXP_GOTO_INTERPRET result
 
-    InterState();
-};
-
 InterState::InterState()
 {
     memset(this, 0, sizeof(InterState));
@@ -47,6 +37,36 @@
 Expression *interpret_aaKeys(InterState *istate, Expressions *arguments);
 Expression *interpret_aaValues(InterState *istate, Expressions *arguments);
 
+
+// Used for emulating an Exception object
+struct InterpretorExceptionExp : Expression
+{
+    Expression *msg;
+
+    InterpretorExceptionExp(Loc loc, Type *type, Expression *msg);
+    Expression *interpret(InterState *istate);
+    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
+};
+
+InterpretorExceptionExp::InterpretorExceptionExp(Loc loc, Type *type, Expression *msg)
+    : Expression(loc, TOKreserved, sizeof(InterpretorExceptionExp))
+{
+    this->type = type;
+    this->msg = msg;
+    assert(msg->op == TOKstring);
+}
+
+Expression *InterpretorExceptionExp::interpret(InterState *istate)
+{
+    return this;
+}
+
+void InterpretorExceptionExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    msg->toCBuffer(buf, hgs);
+}
+
+
 /*************************************
  * Attempt to interpret a function given the arguments.
  * Input:
@@ -145,6 +165,8 @@
 		earg = earg->interpret(istate ? istate : &istatex);
 		if (earg == EXP_CANT_INTERPRET)
 		    return NULL;
+		if (earg == EXP_THROW_INTERPRET)
+		    return earg;
 	    }
 	    eargs.data[i] = earg;
 	}
@@ -231,6 +253,8 @@
 #endif
 	    e = NULL;
 	}
+	if (e == EXP_THROW_INTERPRET)
+	    break;
 
 	/* This is how we deal with a recursive statement AST
 	 * that has arbitrary goto statements in it.
@@ -267,6 +291,9 @@
 		//printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : "");
 	    }
 	}
+
+	// throw
+	istate->exception = istatex.exception;
     }
 
     return e;
@@ -307,10 +334,10 @@
     if (exp)
     {
 	Expression *e = exp->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	{
 	    //printf("-ExpStatement::interpret(): %p\n", e);
-	    return EXP_CANT_INTERPRET;
+	    return e;
 	}
     }
     return NULL;
@@ -357,7 +384,7 @@
 	{   Statement *s = (Statement *)statements->data[i];
 
 	    e = s->interpret(istate);
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    if (e == EXP_CONTINUE_INTERPRET)
 	    {	e = NULL;
@@ -395,7 +422,7 @@
     Expression *e = condition->interpret(istate);
     assert(e);
     //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n");
-    if (e != EXP_CANT_INTERPRET)
+    if (e != EXP_CANT_INTERPRET && e != EXP_THROW_INTERPRET)
     {
 	if (e->isBool(TRUE))
 	    e = ifbody ? ifbody->interpret(istate) : NULL;
@@ -474,7 +501,7 @@
 	e = body ? body->interpret(istate) : NULL;
 	if (istate->start)
 	    return NULL;
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	    return e;
 	if (e == EXP_BREAK_INTERPRET)
 	    return NULL;
@@ -485,7 +512,7 @@
     while (1)
     {
 	e = condition->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	    break;
 	if (!e->isConst())
 	{   e = EXP_CANT_INTERPRET;
@@ -493,7 +520,7 @@
 	}
 	if (e->isBool(TRUE))
 	{   e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    if (e == EXP_CONTINUE_INTERPRET)
 		continue;
@@ -528,7 +555,7 @@
 	e = body ? body->interpret(istate) : NULL;
 	if (istate->start)
 	    return NULL;
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	    return e;
 	if (e == EXP_BREAK_INTERPRET)
 	    return NULL;
@@ -541,7 +568,7 @@
     while (1)
     {
 	e = body ? body->interpret(istate) : NULL;
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	    break;
 	if (e == EXP_BREAK_INTERPRET)
 	{   e = NULL;
@@ -552,7 +579,7 @@
 
     Lcontinue:
 	e = condition->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	    break;
 	if (!e->isConst())
 	{   e = EXP_CANT_INTERPRET;
@@ -583,7 +610,7 @@
     if (init)
     {
 	e = init->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	    return e;
 	assert(!e);
     }
@@ -593,7 +620,7 @@
 	e = body ? body->interpret(istate) : NULL;
 	if (istate->start)
 	    return NULL;
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	    return e;
 	if (e == EXP_BREAK_INTERPRET)
 	    return NULL;
@@ -608,7 +635,7 @@
 	if (!condition)
 	    goto Lhead;
 	e = condition->interpret(istate);
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	    break;
 	if (!e->isConst())
 	{   e = EXP_CANT_INTERPRET;
@@ -618,7 +645,7 @@
 	{
 	Lhead:
 	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    if (e == EXP_BREAK_INTERPRET)
 	    {   e = NULL;
@@ -630,7 +657,7 @@
 	    if (increment)
 	    {
 		e = increment->interpret(istate);
-		if (e == EXP_CANT_INTERPRET)
+		if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		    break;
 	    }
 	}
@@ -661,12 +688,12 @@
 	return EXP_CANT_INTERPRET;
 
     eaggr = aggr->interpret(istate);
-    if (eaggr == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
+    if (eaggr == EXP_CANT_INTERPRET || eaggr == EXP_THROW_INTERPRET)
+	return eaggr;
 
     Expression *dim = ArrayLength(Type::tsize_t, eaggr);
-    if (dim == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
+    if (dim == EXP_CANT_INTERPRET || dim == EXP_THROW_INTERPRET)
+	return dim;
 
     Expression *keysave = key ? key->value : NULL;
     Expression *valuesave = value->value;
@@ -682,12 +709,12 @@
 	    if (key)
 		key->value = ekey;
 	    e = Index(value->type, eaggr, ekey);
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    value->value = e;
 
 	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    if (e == EXP_BREAK_INTERPRET)
 	    {   e = NULL;
@@ -707,12 +734,12 @@
 	    if (key)
 		key->value = ekey;
 	    e = Index(value->type, eaggr, ekey);
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    value->value = e;
 
 	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    if (e == EXP_BREAK_INTERPRET)
 	    {   e = NULL;
@@ -743,12 +770,12 @@
 
     Expression *e = NULL;
     Expression *elwr = lwr->interpret(istate);
-    if (elwr == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
+    if (elwr == EXP_CANT_INTERPRET || elwr == EXP_THROW_INTERPRET)
+	return elwr;
 
     Expression *eupr = upr->interpret(istate);
-    if (eupr == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
+    if (eupr == EXP_CANT_INTERPRET || eupr == EXP_THROW_INTERPRET)
+	return eupr;
 
     Expression *keysave = key->value;
 
@@ -759,7 +786,7 @@
 	while (1)
 	{
 	    e = Cmp(TOKlt, key->value->type, key->value, upr);
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    if (e->isBool(TRUE) == FALSE)
 	    {	e = NULL;
@@ -767,14 +794,14 @@
 	    }
 
 	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    if (e == EXP_BREAK_INTERPRET)
 	    {   e = NULL;
 		break;
 	    }
 	    e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    key->value = e;
 	}
@@ -786,7 +813,7 @@
 	while (1)
 	{
 	    e = Cmp(TOKgt, key->value->type, key->value, lwr);
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    if (e->isBool(TRUE) == FALSE)
 	    {	e = NULL;
@@ -794,12 +821,12 @@
 	    }
 
 	    e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type));
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    key->value = e;
 
 	    e = body ? body->interpret(istate) : NULL;
-	    if (e == EXP_CANT_INTERPRET)
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 		break;
 	    if (e == EXP_BREAK_INTERPRET)
 	    {   e = NULL;
@@ -826,7 +853,7 @@
 	e = body ? body->interpret(istate) : NULL;
 	if (istate->start)
 	    return NULL;
-	if (e == EXP_CANT_INTERPRET)
+	if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
 	    return e;
 	if (e == EXP_BREAK_INTERPRET)
 	    return NULL;
@@ -835,8 +862,8 @@
 
 
     Expression *econdition = condition->interpret(istate);
-    if (econdition == EXP_CANT_INTERPRET)
-	return EXP_CANT_INTERPRET;
+    if (econdition == EXP_CANT_INTERPRET || econdition == EXP_THROW_INTERPRET)
+	return econdition;
 
     Statement *s = NULL;
     if (cases)
@@ -845,8 +872,8 @@
 	{
 	    CaseStatement *cs = (CaseStatement *)cases->data[i];
 	    e = Equal(TOKequal, Type::tint32, econdition, cs->exp);
-	    if (e == EXP_CANT_INTERPRET)
-		return EXP_CANT_INTERPRET;
+	    if (e == EXP_CANT_INTERPRET || e == EXP_THROW_INTERPRET)
+		return e;
 	    if (e->isBool(TRUE))
 	    {	s = cs;
 		break;
@@ -937,6 +964,142 @@
     return statement ? statement->interpret(istate) : NULL;
 }
 
+
+static Expression *emulateNewException(Loc loc, InterState *istate, NewExp *enew)
+{
+    Type *tnew = enew->newtype;
+    ClassDeclaration *newcd = tnew->toBasetype()->isClassHandle();
+    assert(newcd);
+
+    /* emulate: new Exception("msg", null)
+     */
+    if (newcd->ident->equals(Id::Exception))
+    {
+	if (enew->thisexp || enew->newargs)
+	    goto Lcant;
+
+	// args must be (StringExp, NullExp)
+	Expressions *args = enew->arguments;
+	if (args->dim != 2)
+	    goto Lcant;
+
+	Expression *msg = (Expression *)args->data[0];
+	msg = msg->interpret(istate);
+	if (msg == EXP_THROW_INTERPRET)
+	    return msg;
+	if (msg == EXP_CANT_INTERPRET || msg == EXP_VOID_INTERPRET || msg->op != TOKstring)
+	    goto Lcant;
+
+	Expression *next = (Expression *)args->data[1];
+	next = next->interpret(istate);
+	if (next == EXP_THROW_INTERPRET)
+	    return next;
+	if (next == EXP_CANT_INTERPRET || next == EXP_VOID_INTERPRET || next->op != TOKnull)
+	    goto Lcant;
+
+	return new InterpretorExceptionExp(loc, tnew, msg);
+    }
+
+Lcant:
+    return NULL;
+}
+
+Expression *ThrowStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("ThrowStatement::interpret()\n");
+#endif
+    START()
+
+    Expression *e = NULL;
+    if (exp->op == TOKnew)
+	e = emulateNewException(loc, istate, (NewExp *)exp);
+    if (!e)
+	e = exp->interpret(istate);
+
+    if (e == EXP_CANT_INTERPRET)
+    {
+	error("cannot throw %s at compile time", exp->toChars());
+	return e;
+    }
+    if (e == EXP_THROW_INTERPRET)
+	return e;
+
+    assert(e);
+    if (istate)
+	istate->exception = e;
+    return EXP_THROW_INTERPRET;
+}
+
+Expression *TryCatchStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("TryCatchStatement::interpret()\n");
+#endif
+    START()
+
+    InterState istatex;
+    if (!istate)
+	istate = &istatex;
+
+    // try
+    Expression *e = body->interpret(istate);
+
+    // catch
+    if (istate->exception && catches->dim)
+    {
+	Expression *except = istate->exception;
+	Type *extype = except->type;
+	assert(extype);
+
+	/* Search an appropriate catch clause.
+	 */
+	Catch *catchhit = NULL;
+
+	for (size_t i = 0; i < catches->dim; i++)
+	{
+	    Catch *ca = (Catch *)catches->data[i];
+	    Type *catype = ca->type;
+
+	    if (catype->equals(extype) || catype->isBaseOf(extype, NULL))
+	    {
+		catchhit = ca;
+		break;
+	    }
+	}
+
+	/* Clear the exception and execute the catch clause.
+	 */
+	if (catchhit)
+	{
+	    istate->exception = NULL;
+	    if (catchhit->var)
+		catchhit->var->value = except;
+	    e = catchhit->handler->interpret(istate);
+	}
+    }
+    return e;
+}
+
+Expression *TryFinallyStatement::interpret(InterState *istate)
+{
+#if LOG
+    printf("TryFinallyStatement::interpret()\n");
+#endif
+    START()
+
+    Expression *e = body->interpret(istate);
+    if (e == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    Expression *efin = finalbody->interpret(istate);
+    if (efin == EXP_CANT_INTERPRET)
+	return EXP_CANT_INTERPRET;
+
+    return e;
+}
+
+
 /******************************** Expression ***************************/
 
 Expression *Expression::interpret(InterState *istate)
@@ -1003,7 +1166,7 @@
 	{   e = v->value;
 	    if (!e)
 		error(loc, "variable %s is used before initialization", v->toChars());
-	    else if (e != EXP_CANT_INTERPRET)
+	    else if (e != EXP_CANT_INTERPRET && e != EXP_THROW_INTERPRET)
 		e = e->interpret(istate);
 	}
 	if (!e)
@@ -1086,7 +1249,7 @@
 	Expression *ex;
 
 	ex = e->interpret(istate);
-	if (ex == EXP_CANT_INTERPRET)
+	if (ex == EXP_CANT_INTERPRET || ex == EXP_THROW_INTERPRET)
 	{   delete expsx;
 	    return ex;
 	}
@@ -1128,9 +1291,9 @@
 	    Expression *ex;
 
 	    ex = e->interpret(istate);
-	    if (ex == EXP_CANT_INTERPRET)
+	    if (ex == EXP_CANT_INTERPRET || ex == EXP_THROW_INTERPRET)
 	    {   delete expsx;
-		return EXP_CANT_INTERPRET;
+		return ex;
 	    }
 
 	    /* If any changes, do Copy On Write
@@ -1166,6 +1329,7 @@
 Expression *AssocArrayLiteralExp::interpret(InterState *istate)
 {   Expressions *keysx = keys;
     Expressions *valuesx = values;
+    Expression *ex;
 
 #if LOG
     printf("AssocArrayLiteralExp::interpret() %s\n", toChars());
@@ -1173,10 +1337,9 @@
     for (size_t i = 0; i < keys->dim; i++)
     {   Expression *ekey = (Expression *)keys->data[i];
 	Expression *evalue = (Expression *)values->data[i];
-	Expression *ex;
 
 	ex = ekey->interpret(istate);
-	if (ex == EXP_CANT_INTERPRET)
+	if (ex == EXP_CANT_INTERPRET || ex == EXP_THROW_INTERPRET)
 	    goto Lerr;
 
 	/* If any changes, do Copy On Write
@@ -1189,7 +1352,7 @@
 	}
 
 	ex = evalue->interpret(istate);
-	if (ex == EXP_CANT_INTERPRET)
+	if (ex == EXP_CANT_INTERPRET || ex == EXP_THROW_INTERPRET)
 	    goto Lerr;
 
 	/* If any changes, do Copy On Write
@@ -1215,8 +1378,8 @@
 
 	for (size_t j = i; j < keysx->dim; j++)
 	{   Expression *ekey2 = (Expression *)keysx->data[j];
-	    Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2);
-	    if (ex == EXP_CANT_INTERPRET)
+	    ex = Equal(TOKequal, Type::tbool, ekey, ekey2);
+	    if (ex == EXP_CANT_INTERPRET || ex == EXP_THROW_INTERPRET)
 		goto Lerr;
 	    if (ex->isBool(TRUE))	// if a match
 	    {
@@ -1247,7 +1410,7 @@
 	delete keysx;
     if (valuesx != values)
 	delete values;
-    return EXP_CANT_INTERPRET;
+    return ex;
 }
 
 Expression *StructLiteralExp::interpret(InterState *istate)
@@ -1269,9 +1432,9 @@
 		continue;
 
 	    Expression *ex = e->interpret(istate);
-	    if (ex == EXP_CANT_INTERPRET)
+	    if (ex == EXP_CANT_INTERPRET || ex == EXP_THROW_INTERPRET)
 	    {   delete expsx;
-		return EXP_CANT_INTERPRET;
+		return ex;
 	    }
 
 	    /* If any changes, do Copy On Write
@@ -1314,6 +1477,8 @@
     e1 = this->e1->interpret(istate);
     if (e1 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e1 == EXP_THROW_INTERPRET)
+	return e1;
     if (e1->isConst() != 1)
 	goto Lcant;
 
@@ -1349,12 +1514,16 @@
     e1 = this->e1->interpret(istate);
     if (e1 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e1 == EXP_THROW_INTERPRET)
+	return e1;
     if (e1->isConst() != 1)
 	goto Lcant;
 
     e2 = this->e2->interpret(istate);
     if (e2 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e2 == EXP_THROW_INTERPRET)
+	return e2;
     if (e2->isConst() != 1)
 	goto Lcant;
 
@@ -1397,6 +1566,8 @@
     e1 = this->e1->interpret(istate);
     if (e1 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e1 == EXP_THROW_INTERPRET)
+	return e1;
     if (e1->isConst() != 1 &&
 	e1->op != TOKnull &&
 	e1->op != TOKstring &&
@@ -1407,6 +1578,8 @@
     e2 = this->e2->interpret(istate);
     if (e2 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e2 == EXP_THROW_INTERPRET)
+	return e2;
     if (e2->isConst() != 1 &&
 	e2->op != TOKnull &&
 	e2->op != TOKstring &&
@@ -1446,10 +1619,10 @@
 	    e1 = ce->e1;
 	}
     }
-    if (e1 == EXP_CANT_INTERPRET)
+    if (e1 == EXP_CANT_INTERPRET || e1 == EXP_THROW_INTERPRET)
 	return e1;
     Expression *e2 = this->e2->interpret(istate);
-    if (e2 == EXP_CANT_INTERPRET)
+    if (e2 == EXP_CANT_INTERPRET || e2 == EXP_THROW_INTERPRET)
 	return e2;
 
     /* Assignment to variable of the form:
@@ -1494,7 +1667,7 @@
 		}
 		e2 = Cast(v->type, v->type, e2);
 	    }
-	    if (e2 != EXP_CANT_INTERPRET)
+	    if (e2 != EXP_CANT_INTERPRET && e2 != EXP_THROW_INTERPRET)
 	    {
 		if (!v->isParameter())
 		{
@@ -1556,7 +1729,7 @@
 	    e2 = (*fp)(type, ev, e2);
 	else
 	    e2 = Cast(type, type, e2);
-	if (e2 == EXP_CANT_INTERPRET)
+	if (e2 == EXP_CANT_INTERPRET || e2 == EXP_THROW_INTERPRET)
 	    return e2;
 
 	if (!v->isParameter())
@@ -1704,21 +1877,21 @@
 	    return EXP_CANT_INTERPRET;
 
 	Expression *index = ie->e2->interpret(istate);
-	if (index == EXP_CANT_INTERPRET)
-	    return EXP_CANT_INTERPRET;
+	if (index == EXP_CANT_INTERPRET || index == EXP_THROW_INTERPRET)
+	    return index;
 	Expression *ev;
 	if (fp || ae || se)	// not for aae, because key might not be there
 	{
 	    ev = Index(type, v->value, index);
-	    if (ev == EXP_CANT_INTERPRET)
-		return EXP_CANT_INTERPRET;
+	    if (ev == EXP_CANT_INTERPRET || ev == EXP_THROW_INTERPRET)
+		return ev;
 	}
 
 	if (fp)
 	    e2 = (*fp)(type, ev, e2);
 	else
 	    e2 = Cast(type, type, e2);
-	if (e2 == EXP_CANT_INTERPRET)
+	if (e2 == EXP_CANT_INTERPRET || e2 == EXP_THROW_INTERPRET)
 	    return e2;
 
 	if (!v->isParameter())
@@ -1763,8 +1936,8 @@
 	    {	j--;
 		Expression *ekey = (Expression *)aae->keys->data[j];
 		Expression *ex = Equal(TOKequal, Type::tbool, ekey, index);
-		if (ex == EXP_CANT_INTERPRET)
-		    return EXP_CANT_INTERPRET;
+		if (ex == EXP_CANT_INTERPRET || ex == EXP_THROW_INTERPRET)
+		    return ex;
 		if (ex->isBool(TRUE))
 		{   valuesx->data[j] = (void *)e2;
 		    updated = 1;
@@ -1866,14 +2039,14 @@
     printf("AndAndExp::interpret() %s\n", toChars());
 #endif
     Expression *e = e1->interpret(istate);
-    if (e != EXP_CANT_INTERPRET)
+    if (e != EXP_CANT_INTERPRET && e != EXP_THROW_INTERPRET)
     {
 	if (e->isBool(FALSE))
 	    e = new IntegerExp(e1->loc, 0, type);
 	else if (e->isBool(TRUE))
 	{
 	    e = e2->interpret(istate);
-	    if (e != EXP_CANT_INTERPRET)
+	    if (e != EXP_CANT_INTERPRET && e != EXP_THROW_INTERPRET)
 	    {
 		if (e->isBool(FALSE))
 		    e = new IntegerExp(e1->loc, 0, type);
@@ -1895,14 +2068,14 @@
     printf("OrOrExp::interpret() %s\n", toChars());
 #endif
     Expression *e = e1->interpret(istate);
-    if (e != EXP_CANT_INTERPRET)
+    if (e != EXP_CANT_INTERPRET && e != EXP_THROW_INTERPRET)
     {
 	if (e->isBool(TRUE))
 	    e = new IntegerExp(e1->loc, 1, type);
 	else if (e->isBool(FALSE))
 	{
 	    e = e2->interpret(istate);
-	    if (e != EXP_CANT_INTERPRET)
+	    if (e != EXP_CANT_INTERPRET && e != EXP_THROW_INTERPRET)
 	    {
 		if (e->isBool(FALSE))
 		    e = new IntegerExp(e1->loc, 0, type);
@@ -1939,7 +2112,7 @@
 		{
 		    Expression *earg = (Expression *)arguments->data[i];
 		    earg = earg->interpret(istate);
-		    if (earg == EXP_CANT_INTERPRET)
+		    if (earg == EXP_CANT_INTERPRET || earg == EXP_THROW_INTERPRET)
 			return earg;
 		    args.data[i] = (void *)earg;
 		}
@@ -1954,7 +2127,7 @@
 	    {
 		e = (Expression *)arguments->data[1];
 		e = e->interpret(istate);
-		if (e != EXP_CANT_INTERPRET)
+		if (e != EXP_CANT_INTERPRET && e != EXP_THROW_INTERPRET)
 		{
 		    e = expType(type, e);
 		}
@@ -1962,12 +2135,12 @@
 	    else
 	    {
 		Expression *eresult = fd->interpret(istate, arguments);
-		if (eresult)
+		if (!eresult || eresult == EXP_CANT_INTERPRET)
+		    error("cannot evaluate %s at compile time", toChars());
+		else if (eresult)
 		    e = eresult;
 		else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors)
 		    e = EXP_VOID_INTERPRET;
-		else
-		    error("cannot evaluate %s at compile time", toChars());
 	    }
 	}
     }
@@ -1980,7 +2153,7 @@
     printf("CommaExp::interpret() %s\n", toChars());
 #endif
     Expression *e = e1->interpret(istate);
-    if (e != EXP_CANT_INTERPRET)
+    if (e != EXP_CANT_INTERPRET && e != EXP_THROW_INTERPRET)
 	e = e2->interpret(istate);
     return e;
 }
@@ -1991,7 +2164,7 @@
     printf("CondExp::interpret() %s\n", toChars());
 #endif
     Expression *e = econd->interpret(istate);
-    if (e != EXP_CANT_INTERPRET)
+    if (e != EXP_CANT_INTERPRET && e != EXP_THROW_INTERPRET)
     {
 	if (e->isBool(TRUE))
 	    e = e1->interpret(istate);
@@ -2013,6 +2186,8 @@
     e1 = this->e1->interpret(istate);
     if (e1 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e1 == EXP_THROW_INTERPRET)
+	return e1;
     if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
     {
 	e = ArrayLength(type, e1);
@@ -2040,6 +2215,8 @@
     e1 = this->e1->interpret(istate);
     if (e1 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e1 == EXP_THROW_INTERPRET)
+	return e1;
 
     if (e1->op == TOKstring || e1->op == TOKarrayliteral)
     {
@@ -2048,6 +2225,8 @@
 	e = ArrayLength(Type::tsize_t, e1);
 	if (e == EXP_CANT_INTERPRET)
 	    goto Lcant;
+	if (e == EXP_THROW_INTERPRET)
+	    return e;
 	if (lengthVar)
 	    lengthVar->value = e;
     }
@@ -2055,6 +2234,8 @@
     e2 = this->e2->interpret(istate);
     if (e2 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e2 == EXP_THROW_INTERPRET)
+	return e2;
     return Index(type, e1, e2);
 
 Lcant:
@@ -2074,6 +2255,8 @@
     e1 = this->e1->interpret(istate);
     if (e1 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e1 == EXP_THROW_INTERPRET)
+	return e1;
     if (!this->lwr)
     {
 	e = e1->castTo(NULL, type);
@@ -2085,6 +2268,8 @@
     e = ArrayLength(Type::tsize_t, e1);
     if (e == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e == EXP_THROW_INTERPRET)
+	return e;
     if (lengthVar)
 	lengthVar->value = e;
 
@@ -2093,9 +2278,13 @@
     lwr = this->lwr->interpret(istate);
     if (lwr == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (lwr == EXP_THROW_INTERPRET)
+	return lwr;
     upr = this->upr->interpret(istate);
     if (upr == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (upr == EXP_THROW_INTERPRET)
+	return upr;
 
     return Slice(type, e1, lwr, upr);
 
@@ -2117,9 +2306,13 @@
     {
 	goto Lcant;
     }
+    if (e1 == EXP_THROW_INTERPRET)
+	return e1;
     e2 = this->e2->interpret(istate);
     if (e2 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e2 == EXP_THROW_INTERPRET)
+	return e2;
     return Cat(type, e1, e2);
 
 Lcant:
@@ -2140,6 +2333,8 @@
     e1 = this->e1->interpret(istate);
     if (e1 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e1 == EXP_THROW_INTERPRET)
+	return e1;
     return Cast(type, to, e1);
 
 Lcant:
@@ -2160,6 +2355,8 @@
     e1 = this->e1->interpret(istate);
     if (e1 == EXP_CANT_INTERPRET)
 	goto Lcant;
+    if (e1 == EXP_THROW_INTERPRET)
+	return e1;
     if (e1->isBool(TRUE))
     {
     }
@@ -2170,6 +2367,8 @@
 	    e = msg->interpret(istate);
 	    if (e == EXP_CANT_INTERPRET)
 		goto Lcant;
+	    if (e == EXP_THROW_INTERPRET)
+		return e;
 	    error("%s", e->toChars());
 	}
 	else
@@ -2198,7 +2397,7 @@
 	{   AddrExp *ade = (AddrExp *)ae->e1;
 	    Expression *ex = ade->e1;
 	    ex = ex->interpret(istate);
-	    if (ex != EXP_CANT_INTERPRET)
+	    if (ex != EXP_CANT_INTERPRET && ex != EXP_THROW_INTERPRET)
 	    {
 		if (ex->op == TOKstructliteral)
 		{   StructLiteralExp *se = (StructLiteralExp *)ex;
@@ -2217,7 +2416,7 @@
 	VarDeclaration *v = soe->var->isVarDeclaration();
 	if (v)
 	{   Expression *ev = getVarExp(loc, istate, v);
-	    if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral)
+	    if (ev != EXP_CANT_INTERPRET && ev != EXP_THROW_INTERPRET && ev->op == TOKstructliteral)
 	    {	StructLiteralExp *se = (StructLiteralExp *)ev;
 		e = se->getField(type, soe->offset);
 		if (!e)
@@ -2240,7 +2439,7 @@
 #endif
 
     Expression *ex = e1->interpret(istate);
-    if (ex != EXP_CANT_INTERPRET)
+    if (ex != EXP_CANT_INTERPRET && ex != EXP_THROW_INTERPRET)
     {
 	if (ex->op == TOKstructliteral)
 	{   StructLiteralExp *se = (StructLiteralExp *)ex;
@@ -2271,6 +2470,8 @@
     earg = earg->interpret(istate);
     if (earg == EXP_CANT_INTERPRET)
 	return NULL;
+    if (earg == EXP_THROW_INTERPRET)
+	return earg;
     if (earg->op != TOKassocarrayliteral)
 	return NULL;
     AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
@@ -2287,6 +2488,8 @@
     earg = earg->interpret(istate);
     if (earg == EXP_CANT_INTERPRET)
 	return NULL;
+    if (earg == EXP_THROW_INTERPRET)
+	return earg;
     if (earg->op != TOKassocarrayliteral)
 	return NULL;
     AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
@@ -2303,6 +2506,8 @@
     earg = earg->interpret(istate);
     if (earg == EXP_CANT_INTERPRET)
 	return NULL;
+    if (earg == EXP_THROW_INTERPRET)
+	return earg;
     if (earg->op != TOKassocarrayliteral)
 	return NULL;
     AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
