diff dmd2/statement.c @ 1577:e4f7b5d9c68a

DMD 2.032 Merge.
author Robert Clipsham <robert@octarineparrot.com>
date Tue, 08 Sep 2009 10:07:56 +0100
parents 54b3c1394d62
children 1dee66f6ec0b
line wrap: on
line diff
--- a/dmd2/statement.c	Tue Aug 25 21:35:43 2009 +0200
+++ b/dmd2/statement.c	Tue Sep 08 10:07:56 2009 +0100
@@ -29,6 +29,12 @@
 #include "template.h"
 #include "attrib.h"
 
+#if IN_LLVM
+#include "gen/tollvm.h"
+#elif IN_DMD
+extern int os_critsecsize();
+#endif
+
 /******************************** Statement ***************************/
 
 Statement::Statement(Loc loc)
@@ -182,6 +188,22 @@
 }
 
 
+/******************************** PeelStatement ***************************/
+
+PeelStatement::PeelStatement(Statement *s)
+    : Statement(s->loc)
+{
+    this->s = s;
+}
+
+Statement *PeelStatement::semantic(Scope *sc)
+{
+    /* "peel" off this wrapper, and don't run semantic()
+     * on the result.
+     */
+    return s;
+}
+
 /******************************** ExpStatement ***************************/
 
 ExpStatement::ExpStatement(Loc loc, Expression *exp)
@@ -344,6 +366,25 @@
 		if (e)
 		{
 		    //printf("dtor is: "); e->print();
+#if 0
+		    if (v->type->toBasetype()->ty == Tstruct)
+		    {	/* Need a 'gate' to turn on/off destruction,
+			 * in case v gets moved elsewhere.
+			 */
+			Identifier *id = Lexer::uniqueId("__runDtor");
+			ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1));
+			VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie);
+			*sentry = new DeclarationStatement(loc, rd);
+			v->rundtor = rd;
+
+			/* Rewrite e as:
+			 *  rundtor && e
+			 */
+			Expression *ve = new VarExp(loc, v->rundtor);
+			e = new AndAndExp(loc, ve, e);
+			e->type = Type::tbool;
+		    }
+#endif
 		    *sfinally = new ExpStatement(loc, e);
 		}
 	    }
@@ -418,7 +459,12 @@
 		if (sentry)
 		{
 		    sentry = sentry->semantic(sc);
-		    statements->data[i] = sentry;
+		    if (s->isDeclarationStatement())
+		    {	statements->insert(i, sentry);
+			i++;
+		    }
+		    else
+			statements->data[i] = sentry;
 		}
 		if (sexception)
 		{
@@ -562,7 +608,8 @@
 //printf("%s\n", s->toChars());
 	    if (!(result & BEfallthru) && !s->comeFrom())
 	    {
-		s->warning("statement is not reachable");
+		if (s->blockExit() != BEhalt)
+		    s->warning("statement is not reachable");
 	    }
 
 	    result &= ~BEfallthru;
@@ -909,46 +956,12 @@
 
 Statement *WhileStatement::semantic(Scope *sc)
 {
-#if 0
-    if (condition->op == TOKmatch)
-    {
-	/* Rewrite while (condition) body as:
-	 *   if (condition)
-	 *     do
-	 *       body
-	 *     while ((_match = _match.opNext), _match);
-	 */
-
-	Expression *ew = new IdentifierExp(0, Id::_match);
-	ew = new DotIdExp(0, ew, Id::next);
-	ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew);
-	////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0));
-	Expression *ev = new IdentifierExp(0, Id::_match);
-	//ev = new CastExp(0, ev, Type::tvoidptr);
-	ew = new CommaExp(0, ew, ev);
-	Statement *sw = new DoStatement(loc, body, ew);
-	Statement *si = new IfStatement(loc, condition, sw, NULL);
-	return si->semantic(sc);
-    }
-#endif
-
-    condition = condition->semantic(sc);
-    condition = resolveProperties(sc, condition);
-    condition = condition->optimize(WANTvalue);
-    condition = condition->checkToBoolean();
-
-    sc->noctor++;
-
-    Scope *scd = sc->push();
-    scd->sbreak = this;
-    scd->scontinue = this;
-    if (body)
-	body = body->semantic(scd);
-    scd->pop();
-
-    sc->noctor--;
-
-    return this;
+    /* Rewrite as a for(;condition;) loop
+     */
+
+    Statement *s = new ForStatement(loc, NULL, condition, NULL, body);
+    s = s->semantic(sc);
+    return s;
 }
 
 int WhileStatement::hasBreak()
@@ -963,11 +976,13 @@
 
 int WhileStatement::usesEH()
 {
+    assert(0);
     return body ? body->usesEH() : 0;
 }
 
 int WhileStatement::blockExit()
 {
+    assert(0);
     //printf("WhileStatement::blockExit(%p)\n", this);
 
     int result = BEnone;
@@ -998,6 +1013,7 @@
 
 int WhileStatement::comeFrom()
 {
+    assert(0);
     if (body)
 	return body->comeFrom();
     return FALSE;
@@ -1193,6 +1209,10 @@
     if (condition)
     {	if (condition->canThrow())
 	    result |= BEthrow;
+	if (condition->isBool(TRUE))
+	    result &= ~BEfallthru;
+	else if (condition->isBool(FALSE))
+	    return result;
     }
     else
 	result &= ~BEfallthru;	// the body must do the exiting
@@ -1452,11 +1472,14 @@
 	    for (size_t i = 0; i < dim; i++)
 	    {	// Declare args
 		Argument *arg = (Argument *)arguments->data[i];
+		Type *argtype = arg->type->semantic(loc, sc);
 		VarDeclaration *var;
 
-		var = new VarDeclaration(loc, arg->type, arg->ident, NULL);
+		var = new VarDeclaration(loc, argtype, arg->ident, NULL);
 		var->storage_class |= STCforeach;
 		var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
+		if (var->storage_class & (STCref | STCout))
+		    var->storage_class |= STCnodtor;
 		if (dim == 2 && i == 0)
 		{   key = var;
 		    //var->storage_class |= STCfinal;
@@ -1471,20 +1494,68 @@
 			var->storage_class |= STCconst;
 		    }
 		}
-#if 1
+#if 0
 		DeclarationExp *de = new DeclarationExp(loc, var);
 		de->semantic(sc);
-#else
-		var->semantic(sc);
-		if (!sc->insert(var))
-		    error("%s already defined", var->ident->toChars());
 #endif
 	    }
 
-	    sc->sbreak = this;
-	    sc->scontinue = this;
-	    body = body->semantic(sc);
-
+#if 1
+	{
+	     /* Convert to a ForStatement
+	      *   foreach (key, value; a) body =>
+	      *   for (T[] tmp = a[], size_t key; key < tmp.length; ++key)
+	      *   { T value = tmp[k]; body }
+	      *
+	      *   foreach_reverse (key, value; a) body =>
+	      *   for (T[] tmp = a[], size_t key = tmp.length; key--; )
+	      *   { T value = tmp[k]; body }
+	      */
+	    Identifier *id = Lexer::uniqueId("__aggr");
+	    ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, aggr, NULL, NULL));
+	    VarDeclaration *tmp = new VarDeclaration(loc, aggr->type->nextOf()->arrayOf(), id, ie);
+
+	    Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length);
+
+	    if (!key)
+	    {
+		Identifier *id = Lexer::uniqueId("__key");
+		key = new VarDeclaration(loc, Type::tsize_t, id, NULL);
+	    }
+	    if (op == TOKforeach_reverse)
+		key->init = new ExpInitializer(loc, tmp_length);
+	    else
+		key->init = new ExpInitializer(loc, new IntegerExp(0));
+
+	    Statements *cs = new Statements();
+	    cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp)));
+	    cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key)));
+	    Statement *forinit = new CompoundDeclarationStatement(loc, cs);
+
+	    Expression *cond;
+	    if (op == TOKforeach_reverse)
+		// key--
+		cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key));
+	    else
+		// key < tmp.length
+		cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), tmp_length);
+
+	    Expression *increment = NULL;
+	    if (op == TOKforeach)
+		// key += 1
+		increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1));
+
+	    // T value = tmp[key];
+	    value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key)));
+	    Statement *ds = new DeclarationStatement(loc, new DeclarationExp(loc, value));
+
+	    body = new CompoundStatement(loc, ds, body);
+
+	    ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body);
+	    s = fs->semantic(sc);
+	    break;
+	}
+#else
 	    if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst)
 	    {
 		if (aggr->op == TOKstring)
@@ -1494,20 +1565,23 @@
 			tab->toChars(), value->type->toChars());
 	    }
 
-	    if (key && key->type->ty != Tint32 && key->type->ty != Tuns32)
+	    if (key)
 	    {
 		if (global.params.is64bit)
 		{
 		    if (key->type->ty != Tint64 && key->type->ty != Tuns64)
 			error("foreach: key type must be int or uint, long or ulong, not %s", key->type->toChars());
 		}
-		else
-		    error("foreach: key type must be int or uint, not %s", key->type->toChars());
+
+		if (key->storage_class & (STCout | STCref))
+		    error("foreach: key cannot be out or ref");
 	    }
 
-	    if (key && key->storage_class & (STCout | STCref))
-		error("foreach: key cannot be out or ref");
+	    sc->sbreak = this;
+	    sc->scontinue = this;
+	    body = body->semantic(sc);
 	    break;
+#endif
 
 	case Taarray:
 	    if (!checkForArgTypes())
@@ -1745,12 +1819,14 @@
 		keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1);
 		exps->push(new IntegerExp(0, keysize, Type::tsize_t));
 
+#if IN_LLVM
         // LDC paint delegate argument to the type runtime expects
         if (!fldeTy->equals(flde->type))
         {
             flde = new CastExp(loc, flde, flde->type);
             flde->type = fldeTy;
         }
+#endif
 		exps->push(flde);
 		e = new CallExp(loc, ec, exps);
 		e->type = Type::tindex;	// don't run semantic() on e
@@ -2055,6 +2131,55 @@
 	lwr = ea.e1;
 	upr = ea.e2;
     }
+#if 1
+    /* Convert to a for loop:
+     *	foreach (key; lwr .. upr) =>
+     *	for (auto key = lwr, auto tmp = upr; key < tmp; ++key)
+     *
+     *	foreach_reverse (key; lwr .. upr) =>
+     *	for (auto tmp = lwr, auto key = upr; key-- > tmp;)
+     */
+
+    ExpInitializer *ie = new ExpInitializer(loc, (op == TOKforeach) ? lwr : upr);
+    key = new VarDeclaration(loc, arg->type, arg->ident, ie);
+
+    Identifier *id = Lexer::uniqueId("__limit");
+    ie = new ExpInitializer(loc, (op == TOKforeach) ? upr : lwr);
+    VarDeclaration *tmp = new VarDeclaration(loc, arg->type, id, ie);
+
+    Statements *cs = new Statements();
+    // Keep order of evaluation as lwr, then upr
+    if (op == TOKforeach)
+    {
+	cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key)));
+	cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp)));
+    }
+    else
+    {
+	cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp)));
+	cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key)));
+    }
+    Statement *forinit = new CompoundDeclarationStatement(loc, cs);
+
+    Expression *cond;
+    if (op == TOKforeach_reverse)
+    {	// key-- > tmp
+	cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key));
+	cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp));
+    }
+    else
+	// key < tmp
+	cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), new VarExp(loc, tmp));
+
+    Expression *increment = NULL;
+    if (op == TOKforeach)
+	// key += 1
+	increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1));
+
+    ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body);
+    s = fs->semantic(sc);
+    return s;
+#else
     if (!arg->type->isscalar())
 	error("%s is not a scalar type", arg->type->toChars());
 
@@ -2078,6 +2203,7 @@
     sc->noctor--;
     sc->pop();
     return s;
+#endif
 }
 
 int ForeachRangeStatement::hasBreak()
@@ -2092,11 +2218,14 @@
 
 int ForeachRangeStatement::usesEH()
 {
+    assert(0);
     return body->usesEH();
 }
 
 int ForeachRangeStatement::blockExit()
-{   int result = BEfallthru;
+{
+    assert(0);
+    int result = BEfallthru;
 
     if (lwr && lwr->canThrow())
 	result |= BEthrow;
@@ -2113,6 +2242,7 @@
 
 int ForeachRangeStatement::comeFrom()
 {
+    assert(0);
     if (body)
 	return body->comeFrom();
     return FALSE;
@@ -2462,7 +2592,7 @@
     {
         sc->func->allowInlining = true;
     }
-
+#if DMDV2
     else if (ident == Id::startaddress)
     {
 	if (!args || args->dim != 1)
@@ -2483,6 +2613,7 @@
 	    return this;
 	}
     }
+#endif
     else
         error("unrecognized pragma(%s)", ident->toChars());
 
@@ -2657,7 +2788,7 @@
 	;
     }
 
-    if (!sc->sw->sdefault)
+    if (!sc->sw->sdefault && !isFinal)
     {	hasNoDefault = 1;
 
 	warning("switch statement has no default");
@@ -3693,21 +3824,145 @@
 Statement *SynchronizedStatement::semantic(Scope *sc)
 {
     if (exp)
-    {	ClassDeclaration *cd;
-
+    {
 	exp = exp->semantic(sc);
 	exp = resolveProperties(sc, exp);
-	cd = exp->type->isClassHandle();
+	ClassDeclaration *cd = exp->type->isClassHandle();
 	if (!cd)
 	    error("can only synchronize on class objects, not '%s'", exp->type->toChars());
 	else if (cd->isInterfaceDeclaration())
-	{   Type *t = new TypeIdentifier(0, Id::Object);
+	{   /* Cast the interface to an object, as the object has the monitor,
+	     * not the interface.
+	     */
+	    Type *t = new TypeIdentifier(0, Id::Object);
 
 	    t = t->semantic(0, sc);
 	    exp = new CastExp(loc, exp, t);
 	    exp = exp->semantic(sc);
 	}
+
+#if 1
+	/* Rewrite as:
+	 *  auto tmp = exp;
+	 *  _d_monitorenter(tmp);
+	 *  try { body } finally { _d_monitorexit(tmp); }
+	 */
+	Identifier *id = Lexer::uniqueId("__sync");
+	ExpInitializer *ie = new ExpInitializer(loc, exp);
+	VarDeclaration *tmp = new VarDeclaration(loc, exp->type, id, ie);
+
+	Statements *cs = new Statements();
+	cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp)));
+
+#if IN_LLVM
+	// LDC: Build args
+	Arguments* args = new Arguments;
+	args->push(new Argument(STCin, ClassDeclaration::object->type, NULL, NULL));
+	FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter);
+#else
+	FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorenter);
+#endif
+	Expression *e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp));
+	e->type = Type::tvoid;			// do not run semantic on e
+	cs->push(new ExpStatement(loc, e));
+
+#if IN_LLVM
+	FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit);
+#else
+	FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit);
+#endif
+	e = new CallExp(loc, new VarExp(loc, fdexit), new VarExp(loc, tmp));
+	e->type = Type::tvoid;			// do not run semantic on e
+	Statement *s = new ExpStatement(loc, e);
+	s = new TryFinallyStatement(loc, body, s);
+	cs->push(s);
+
+	s = new CompoundStatement(loc, cs);
+	return s->semantic(sc);
+#endif
     }
+#if 1
+    else
+    {	/* Generate our own critical section, then rewrite as:
+	 *  __gshared byte[CriticalSection.sizeof] critsec;
+	 *  _d_criticalenter(critsec.ptr);
+	 *  try { body } finally { _d_criticalexit(critsec.ptr); }
+	 */
+	Identifier *id = Lexer::uniqueId("__critsec");
+#if IN_LLVM	
+	Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + getTypePaddedSize(DtoMutexType())));
+#elif IN_DMD
+	Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + os_critsecsize()));
+#endif
+	VarDeclaration *tmp = new VarDeclaration(loc, t, id, NULL);
+	tmp->storage_class |= STCgshared | STCstatic;
+
+	Statements *cs = new Statements();
+	cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp)));
+
+#if IN_LLVM
+	// LDC: Build args (based on the code from gen/tollvm.cpp:DtoMutexType()
+	Arguments* args = new Arguments;
+	StructDeclaration* dcs = new StructDeclaration(loc, id);
+	if (global.params.os == OSWindows)
+	{
+		dcs->addField(dcs->scope, new VarDeclaration(loc, Type::tint32, id, NULL));
+	}
+	else if (global.params.os == OSFreeBSD)
+	{
+		dcs->addField(dcs->scope, new VarDeclaration(loc, Type::tsize_t, id, NULL));
+	}
+	else
+	{
+		// pthread_fastlock
+		StructDeclaration* pfl = new StructDeclaration(loc, id);
+		pfl->scope->linkage = LINKc;
+		pfl->addField(pfl->scope, new VarDeclaration(loc, Type::tsize_t, id, NULL));
+		pfl->addField(pfl->scope, new VarDeclaration(loc, Type::tint32, id, NULL));
+
+		// pthread_mutex
+		StructDeclaration* pm = new StructDeclaration(loc, id);
+		pm->scope->linkage = LINKc;
+		pm->addField(pm->scope, new VarDeclaration(loc, Type::tint32, id, NULL));
+		pm->addField(pm->scope, new VarDeclaration(loc, Type::tint32, id, NULL));
+		pm->addField(pm->scope, new VarDeclaration(loc, Type::tvoidptr, id, NULL));
+		pm->addField(pm->scope, new VarDeclaration(loc, Type::tint32, id, NULL));
+		pm->addField(pm->scope, new VarDeclaration(loc, pfl->type, id, NULL));
+
+		// D_CRITICAL_SECTION
+		dcs->scope->linkage = LINKc;
+		dcs->addField(dcs->scope, new VarDeclaration(loc, dcs->type->pointerTo(), id, NULL));
+		dcs->addField(dcs->scope, new VarDeclaration(loc, pm->type, id, NULL));
+	}
+	args->push(new Argument(STCin, dcs->type->pointerTo(), NULL, NULL));
+
+	FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter);
+#else
+	FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalenter);
+#endif
+	Expression *e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr);
+	e = e->semantic(sc);
+	e = new CallExp(loc, new VarExp(loc, fdenter), e);
+	e->type = Type::tvoid;			// do not run semantic on e
+	cs->push(new ExpStatement(loc, e));
+
+#if IN_LLVM
+	FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit);
+#else
+	FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalexit);
+#endif
+	e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr);
+	e = e->semantic(sc);
+	e = new CallExp(loc, new VarExp(loc, fdexit), e);
+	e->type = Type::tvoid;			// do not run semantic on e
+	Statement *s = new ExpStatement(loc, e);
+	s = new TryFinallyStatement(loc, body, s);
+	cs->push(s);
+
+	s = new CompoundStatement(loc, cs);
+	return s->semantic(sc);
+    }
+#endif
     if (body)
     {
 	Statement* oldScopeExit = sc->enclosingScopeExit;