diff dmd/expression.c @ 1587:def7a1d494fd

Merge DMD 1.051
author Christian Kamm <kamm incasoftware de>
date Fri, 06 Nov 2009 23:58:01 +0100
parents 05c235309d6f
children 2afcaab30a6a
line wrap: on
line diff
--- a/dmd/expression.c	Fri Nov 06 21:51:41 2009 +0100
+++ b/dmd/expression.c	Fri Nov 06 23:58:01 2009 +0100
@@ -35,8 +35,8 @@
 #endif
 
 #include "rmem.h"
-
-//#include "port.h"
+#include "port.h"
+
 #include "mtype.h"
 #include "init.h"
 #include "expression.h"
@@ -373,6 +373,11 @@
 	}
 
     }
+    else if (e->op == TOKdottd)
+    {
+	e = new CallExp(e->loc, e);
+	e = e->semantic(sc);
+    }
     return e;
 }
 
@@ -543,7 +548,7 @@
     size_t nparams = Argument::dim(tf->parameters);
 
     if (nargs > nparams && tf->varargs == 0)
-	error(loc, "expected %zu arguments, not %zu", nparams, nargs);
+	error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars());
 
     n = (nargs > nparams) ? nargs : nparams;	// n = max(nargs, nparams)
 
@@ -568,7 +573,7 @@
 		{
 		    if (tf->varargs == 2 && i + 1 == nparams)
 			goto L2;
-		    error(loc, "expected %zu arguments, not %zu", nparams, nargs);
+		    error(loc, "expected %zu function arguments, not %zu", nparams, nargs);
 		    break;
 		}
 		arg = p->defaultArg;
@@ -590,7 +595,7 @@
 		if (arg->implicitConvTo(p->type))
 		{
 		    if (nargs != nparams)
-		        error(loc, "expected %zu arguments, not %zu", nparams, nargs);
+		        error(loc, "expected %zu function arguments, not %zu", nparams, nargs);
 		    goto L1;
 		}
 	     L2:
@@ -669,7 +674,16 @@
 
 	L1:
 	    if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
-		arg = arg->implicitCastTo(sc, p->type);
+	    {
+		if (p->type != arg->type)
+		{
+		    //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
+		    if (arg->op == TOKtype)
+			arg->error("cannot pass type %s as function argument", arg->toChars());
+		    arg = arg->implicitCastTo(sc, p->type);
+		    arg = arg->optimize(WANTvalue);
+		}
+	    }
 	    if (p->storageClass & (STCout | STCref))
 	    {
 		// BUG: should check that argument to ref is type 'invariant'
@@ -773,11 +787,15 @@
 	    {
 		arg = callCpCtor(loc, sc, arg);
 	    }
+#endif
 
 	    // Give error for overloaded function addresses
+#if DMDV2
 	    if (arg->op == TOKsymoff)
 	    {	SymOffExp *se = (SymOffExp *)arg;
-		if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique())
+		if (
+		    se->hasOverloads &&
+		    !se->var->isFuncDeclaration()->isUnique())
 		    arg->error("function %s is overloaded", arg->toChars());
 	    }
 #endif
@@ -1214,10 +1232,10 @@
 Expression *Expression::deref()
 {
     //printf("Expression::deref()\n");
-    if (type->ty == Treference)
-    {	Expression *e;
-
-	e = new PtrExp(loc, this);
+    // type could be null if forward referencing an 'auto' variable
+    if (type && type->ty == Treference)
+    {
+	Expression *e = new PtrExp(loc, this);
 	e->type = ((TypeReference *)type)->next;
 	return e;
     }
@@ -2155,6 +2173,10 @@
     f = s->isFuncDeclaration();
     if (f)
     {	//printf("'%s' is a function\n", f->toChars());
+	if (!f->type->deco)
+	{
+	    error("forward reference to %s", toChars());
+	}
 	return new VarExp(loc, f);
     }
     cd = s->isClassDeclaration();
@@ -2209,7 +2231,7 @@
 
     TemplateInstance *ti = s->isTemplateInstance();
     if (ti && !global.errors)
-    {   if (!ti->semanticdone)
+    {   if (!ti->semanticRun)
 	    ti->semantic(sc);
 	s = ti->inst->toAlias();
 	if (!s->isTemplateInstance())
@@ -3166,7 +3188,16 @@
 	    if (v->init)
 	    {   e = v->init->toExpression();
 		if (!e)
-		    error("cannot make expression out of initializer for %s", v->toChars());
+		{   error("cannot make expression out of initializer for %s", v->toChars());
+		    e = new ErrorExp();
+		}
+		else if (v->scope)
+		{   // Do deferred semantic anaylsis
+		    Initializer *i2 = v->init->syntaxCopy();
+		    i2 = i2->semantic(v->scope, v->type);
+		    e = i2->toExpression();
+		    v->scope = NULL;
+		}
 	    }
 	    else
 	    {	e = v->type->defaultInit();
@@ -3200,8 +3231,26 @@
 	e = (Expression *)elements->data[i];
 	if (e)
 	{
-	    e = e->copy();
-	    e->type = type;
+	    //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars());
+
+	    /* If type is a static array, and e is an initializer for that array,
+	     * then the field initializer should be an array literal of e.
+	     */
+	    if (e->type != type && type->ty == Tsarray)
+	    {   TypeSArray *tsa = (TypeSArray *)type;
+		uinteger_t length = tsa->dim->toInteger();
+		Expressions *z = new Expressions;
+		z->setDim(length);
+		for (int q = 0; q < length; ++q)
+		    z->data[q] = e->copy();
+		e = new ArrayLiteralExp(loc, z);
+		e->type = type;
+	    }
+	    else
+	    {
+		e = e->copy();
+		e->type = type;
+	    }
 	}
     }
     return e;
@@ -3216,20 +3265,23 @@
 {
     /* Find which field offset is by looking at the field offsets
      */
-    for (size_t i = 0; i < sd->fields.dim; i++)
-    {
-	Dsymbol *s = (Dsymbol *)sd->fields.data[i];
-	VarDeclaration *v = s->isVarDeclaration();
-	assert(v);
-
-	if (offset == v->offset &&
-	    type->size() == v->type->size())
-	{   Expression *e = (Expression *)elements->data[i];
-	    if (e)
-	    {
-		return i;
-	    }
-	    break;
+    if (elements->dim)
+    {
+	for (size_t i = 0; i < sd->fields.dim; i++)
+	{
+	    Dsymbol *s = (Dsymbol *)sd->fields.data[i];
+	    VarDeclaration *v = s->isVarDeclaration();
+	    assert(v);
+
+	    if (offset == v->offset &&
+		type->size() == v->type->size())
+	    {   Expression *e = (Expression *)elements->data[i];
+		if (e)
+		{
+		    return i;
+		}
+		break;
+	    }
 	}
     }
     return -1;
@@ -3365,7 +3417,7 @@
     ti = sds->isTemplateInstance();
     if (ti && !global.errors)
     {	Dsymbol *s;
-	if (!ti->semanticdone)
+	if (!ti->semanticRun)
 	    ti->semantic(sc);
 	s = ti->inst->toAlias();
 	sds2 = s->isScopeDsymbol();
@@ -3583,7 +3635,7 @@
 	    else if (thisexp)
 		error("e.new is only for allocating nested classes");
 	    else if (fdn)
-	    {
+ 	    {
 		// make sure the parent context fdn of cd is reachable from sc
 		for (Dsymbol *sp = sc->parent; 1; sp = sp->parent)
 		{
@@ -3606,7 +3658,7 @@
 	if (f)
 	{
 	    assert(f);
-	    f = f->overloadResolve(loc, arguments, sc->module);
+	    f = f->overloadResolve(loc, NULL, arguments, sc->module);
 	    checkDeprecated(sc, f);
 	    member = f->isCtorDeclaration();
 	    assert(member);
@@ -3634,7 +3686,7 @@
 		newargs = new Expressions();
 	    newargs->shift(e);
 
-	    f = cd->aggNew->overloadResolve(loc, newargs, sc->module);
+	    f = cd->aggNew->overloadResolve(loc, NULL, newargs, sc->module);
 	    allocator = f->isNewDeclaration();
 	    assert(allocator);
 
@@ -3667,7 +3719,7 @@
 		newargs = new Expressions();
 	    newargs->shift(e);
 
-	    f = f->overloadResolve(loc, newargs, sc->module);
+	    f = f->overloadResolve(loc, NULL, newargs, sc->module);
 	    allocator = f->isNewDeclaration();
 	    assert(allocator);
 
@@ -4200,6 +4252,7 @@
 	return (Expression *)exps->data[0];
     }
     type = new TypeTuple(exps);
+    type = type->semantic(loc, sc);
     //printf("-TupleExp::semantic(%s)\n", toChars());
     return this;
 }
@@ -4263,13 +4316,13 @@
 	fd->parent = sc->parent;
 	if (global.errors)
 	{
-	    if (!fd->type->next)
-		fd->type->next = Type::terror;
 	}
 	else
 	{
 	    fd->semantic2(sc);
-	    if (!global.errors)
+	    if (!global.errors ||
+		// need to infer return type
+		(fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()))
 	    {
 		fd->semantic3(sc);
 
@@ -4278,6 +4331,10 @@
 	    }
 	}
 
+	// need to infer return type
+	if (global.errors && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf())
+	    ((TypeFunction *)fd->type)->next = Type::terror;
+
 	// Type is a "delegate to" or "pointer to" the function literal
 	if (fd->isNested())
 	{
@@ -4377,7 +4434,13 @@
     }
     if (!s->isVarDeclaration())
     {
-	declaration->semantic(sc);
+	Scope *sc2 = sc;
+	if (sc2->stc & (STCpure | STCnothrow))
+	    sc2 = sc->push();
+	sc2->stc &= ~(STCpure | STCnothrow);
+	declaration->semantic(sc2);
+	if (sc2 != sc)
+	    sc2->pop();
 	s->parent = sc->parent;
     }
     if (!global.errors)
@@ -4920,7 +4983,7 @@
 
 	if (op == TOKmodass && e2->type->iscomplex())
 	{   error("cannot perform modulo complex arithmetic");
-	    return new IntegerExp(0);
+	    return new ErrorExp();
 	}
     }
     return this;
@@ -4985,6 +5048,46 @@
     return Expression::checkSideEffect(flag);
 }
 
+// generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
+void BinExp::checkComplexMulAssign()
+{
+    // Any multiplication by an imaginary or complex number yields a complex result.
+    // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
+    const char *opstr = Token::toChars(op);
+    if ( e1->type->isreal() && e2->type->iscomplex())
+    {
+        error("%s %s %s is undefined. Did you mean %s %s %s.re ?",
+            e1->type->toChars(), opstr, e2->type->toChars(), 
+            e1->type->toChars(), opstr, e2->type->toChars());
+    }
+    else if (e1->type->isimaginary() && e2->type->iscomplex())
+    {
+        error("%s %s %s is undefined. Did you mean %s %s %s.im ?",
+            e1->type->toChars(), opstr, e2->type->toChars(),
+            e1->type->toChars(), opstr, e2->type->toChars());
+    }
+    else if ((e1->type->isreal() || e1->type->isimaginary()) &&
+	e2->type->isimaginary())
+    {
+        error("%s %s %s is an undefined operation", e1->type->toChars(),
+		opstr, e2->type->toChars());
+    }
+}
+
+// generate an error if this is a nonsensical += or -=, eg real += imaginary
+void BinExp::checkComplexAddAssign()
+{
+    // Addition or subtraction of a real and an imaginary is a complex result.
+    // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
+    if ( (e1->type->isreal() && (e2->type->isimaginary() || e2->type->iscomplex())) ||
+         (e1->type->isimaginary() && (e2->type->isreal() || e2->type->iscomplex()))        
+        )
+    {
+        error("%s %s %s is undefined (result is complex)",
+	    e1->type->toChars(), Token::toChars(op), e2->type->toChars());
+    }
+}
+
 void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {
     expToCBuffer(buf, hgs, e1, precedence[op]);
@@ -5094,7 +5197,7 @@
     }
 
     if (global.params.verbose)
-	printf("file      %s\t(%s)\n", (char*)se->string, name);
+	printf("file      %s\t(%s)\n", (char *)se->string, name);
 
     {	File f(name);
 	if (f.read())
@@ -5177,7 +5280,10 @@
 #if DMDV2
 int AssertExp::canThrow()
 {
-    return (global.params.useAssert != 0);
+    /* assert()s are non-recoverable errors, so functions that
+     * use them can be considered "nothrow"
+     */
+    return 0; //(global.params.useAssert != 0);
 }
 #endif
 
@@ -5479,7 +5585,11 @@
 	     ident != Id::init && ident != Id::__sizeof &&
 	     ident != Id::alignof && ident != Id::offsetof &&
 	     ident != Id::mangleof && ident != Id::stringof)
-    {
+    {	/* Rewrite:
+         *   p.ident
+         * as:
+         *   (*p).ident
+         */
 	e = new PtrExp(loc, e1);
 	e->type = ((TypePointer *)e1->type)->next;
 	return e->type->dotExp(sc, e, ident);
@@ -5598,7 +5708,7 @@
 	type = var->type;
 	if (!type && global.errors)
 	{   // var is goofed up, just return 0
-	    return new IntegerExp(0);
+	    return new ErrorExp();
 	}
 	assert(type);
 
@@ -5935,9 +6045,10 @@
 	: UnaExp(loc, TOKcall, sizeof(CallExp), e)
 {
     Expressions *arguments = new Expressions();
-    arguments->setDim(1);
-    arguments->data[0] = (void *)earg1;
-
+    if (earg1)
+    {	arguments->setDim(1);
+	arguments->data[0] = (void *)earg1;
+    }
     this->arguments = arguments;
 }
 
@@ -6040,7 +6151,7 @@
     if (e1->op == TOKimport && !e1->type)
     {	ScopeExp *se = (ScopeExp *)e1;
 	TemplateInstance *ti = se->sds->isTemplateInstance();
-	if (ti && !ti->semanticdone)
+	if (ti && !ti->semanticRun)
 	{
 	    /* Attempt to instantiate ti. If that works, go with it.
 	     * If not, go with partial explicit specialization.
@@ -6067,7 +6178,7 @@
     if (e1->op == TOKdotti && !e1->type)
     {	DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)e1;
 	TemplateInstance *ti = se->ti;
-	if (!ti->semanticdone)
+	if (!ti->semanticRun)
 	{
 	    /* Attempt to instantiate ti. If that works, go with it.
 	     * If not, go with partial explicit specialization.
@@ -6163,6 +6274,36 @@
 	if (t1->ty == Tstruct)
 	{
 	    ad = ((TypeStruct *)t1)->sym;
+#if DMDV2
+	    // First look for constructor
+	    if (ad->ctor && arguments && arguments->dim)
+	    {
+		// Create variable that will get constructed
+		Identifier *idtmp = Lexer::uniqueId("__ctmp");
+		VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL);
+		Expression *av = new DeclarationExp(loc, tmp);
+		av = new CommaExp(loc, av, new VarExp(loc, tmp));
+
+		Expression *e;
+		CtorDeclaration *cf = ad->ctor->isCtorDeclaration();
+		if (cf)
+		    e = new DotVarExp(loc, av, cf, 1);
+		else
+		{   TemplateDeclaration *td = ad->ctor->isTemplateDeclaration();
+		    assert(td);
+		    e = new DotTemplateExp(loc, av, td);
+		}
+		e = new CallExp(loc, e, arguments);
+#if !STRUCTTHISREF
+		/* Constructors return a pointer to the instance
+		 */
+		e = new PtrExp(loc, e);
+#endif
+		e = e->semantic(sc);
+		return e;
+	    }
+#endif
+	    // No constructor, look for overload of opCall
 	    if (search_function(ad, Id::call))
 		goto L1;	// overload of opCall, therefore it's a call
 
@@ -6205,7 +6346,7 @@
 
 	    f = dve->var->isFuncDeclaration();
 	    assert(f);
-	    f = f->overloadResolve(loc, arguments, sc->module);
+	    f = f->overloadResolve(loc, NULL, arguments, sc->module);
 
 	    ad = f->toParent()->isAggregateDeclaration();
 	}
@@ -6306,7 +6447,7 @@
 		    sc->callSuper |= CSXany_ctor | CSXsuper_ctor;
 		}
 
-		f = f->overloadResolve(loc, arguments, sc->module);
+		f = f->overloadResolve(loc, NULL, arguments, sc->module);
 		checkDeprecated(sc, f);
 #if DMDV2
 		checkPurity(sc, f);
@@ -6346,7 +6487,7 @@
 	    }
 
 	    f = cd->ctor;
-	    f = f->overloadResolve(loc, arguments, sc->module);
+	    f = f->overloadResolve(loc, NULL, arguments, sc->module);
 	    checkDeprecated(sc, f);
 #if DMDV2
 	    checkPurity(sc, f);
@@ -6440,7 +6581,7 @@
 	    }
 	}
 
-	f = f->overloadResolve(loc, arguments, sc->module);
+	f = f->overloadResolve(loc, NULL, arguments, sc->module);
 	checkDeprecated(sc, f);
 #if DMDV2
 	checkPurity(sc, f);
@@ -6523,6 +6664,7 @@
 #if DMDV2
 int CallExp::canThrow()
 {
+    //printf("CallExp::canThrow() %s\n", toChars());
     if (e1->canThrow())
 	return 1;
 
@@ -6531,10 +6673,13 @@
     for (size_t i = 0; i < arguments->dim; i++)
     {   Expression *e = (Expression *)arguments->data[i];
 
-	if (e->canThrow())
+	if (e && e->canThrow())
 	    return 1;
     }
 
+    if (global.errors && !e1->type)
+	return 0;			// error recovery
+
     /* If calling a function or delegate that is typed as nothrow,
      * then this expression cannot throw.
      * Note that pure functions can throw.
@@ -6552,8 +6697,8 @@
 #if DMDV2
 int CallExp::isLvalue()
 {
-    if (type->toBasetype()->ty == Tstruct)
-	return 1;
+//    if (type->toBasetype()->ty == Tstruct)
+//	return 1;
     Type *tb = e1->type->toBasetype();
     if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref)
 	return 1;		// function returns a reference
@@ -6563,12 +6708,28 @@
 
 Expression *CallExp::toLvalue(Scope *sc, Expression *e)
 {
+#if 1
     if (type->toBasetype()->ty == Tstruct)
 	return this;
     else
+#endif
 	return Expression::toLvalue(sc, e);
 }
 
+Expression *CallExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+#if 1
+    return Expression::modifiableLvalue(sc, e);
+#else
+    /* Although function return values being usable as "ref" parameters is
+     * unsound, disabling it breaks existing code.
+     * Bugzilla 3167
+     */
+    error("cannot assign to function call");
+    return toLvalue(sc, e);
+#endif
+}
+
 void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
 {   int i;
 
@@ -6600,8 +6761,19 @@
 	if (!e1->type)
 	{
 	    error("cannot take address of %s", e1->toChars());
-	    type = Type::tint32;
-	    return this;
+	    return new ErrorExp();
+	}
+	if (!e1->type->deco)
+	{
+	    /* No deco means semantic() was not run on the type.
+	     * We have to run semantic() on the symbol to get the right type:
+	     *	auto x = &bar;
+	     *	pure: int bar() { return 1;}
+	     * otherwise the 'pure' is missing from the type assigned to x.
+	     */
+
+	    error("forward reference to %s", e1->toChars());
+	    return new ErrorExp();
 	}
 	type = e1->type->pointerTo();
 
@@ -6653,8 +6825,8 @@
 PtrExp::PtrExp(Loc loc, Expression *e)
 	: UnaExp(loc, TOKstar, sizeof(PtrExp), e)
 {
-    if (e->type)
-	type = ((TypePointer *)e->type)->next;
+//    if (e->type)
+//	type = ((TypePointer *)e->type)->next;
 }
 
 PtrExp::PtrExp(Loc loc, Expression *e, Type *t)
@@ -6664,43 +6836,35 @@
 }
 
 Expression *PtrExp::semantic(Scope *sc)
-{   Type *tb;
-
+{
 #if LOGSEMANTIC
     printf("PtrExp::semantic('%s')\n", toChars());
 #endif
-    UnaExp::semantic(sc);
-    e1 = resolveProperties(sc, e1);
-    if (type)
-	return this;
-    if (!e1->type)
-	printf("PtrExp::semantic('%s')\n", toChars());
-    tb = e1->type->toBasetype();
-    switch (tb->ty)
-    {
-	case Tpointer:
-	    type = tb->next;
-	    if (type->isbit())
-	    {	Expression *e;
-
-		// Rewrite *p as p[0]
-		e = new IndexExp(loc, e1, new IntegerExp(0));
-		return e->semantic(sc);
-	    }
-	    break;
-
-	case Tsarray:
-	case Tarray:
-	    type = tb->next;
-	    e1 = e1->castTo(sc, type->pointerTo());
-	    break;
-
-	default:
-	    error("can only * a pointer, not a '%s'", e1->type->toChars());
-	    type = Type::tint32;
-	    break;
-    }
-    rvalue();
+    if (!type)
+    {
+	UnaExp::semantic(sc);
+	e1 = resolveProperties(sc, e1);
+	if (!e1->type)
+	    printf("PtrExp::semantic('%s')\n", toChars());
+	Type *tb = e1->type->toBasetype();
+	switch (tb->ty)
+	{
+	    case Tpointer:
+		type = tb->next;
+		break;
+
+	    case Tsarray:
+	    case Tarray:
+		type = tb->next;
+		e1 = e1->castTo(sc, type->pointerTo());
+		break;
+
+	    default:
+		error("can only * a pointer, not a '%s'", e1->type->toChars());
+		return new ErrorExp();
+	}
+	rvalue();
+    }
     return this;
 }
 
@@ -6766,7 +6930,7 @@
 	    return e;
 
 	e1->checkNoBool();
-	if (e1->op != TOKslice)
+	if (!e1->isArrayOperand())
 	    e1->checkArithmetic();
 	type = e1->type;
     }
@@ -6816,7 +6980,7 @@
 	    return e;
 
 	e1->checkNoBool();
-	if (e1->op != TOKslice)
+	if (!e1->isArrayOperand())
 	    e1 = e1->checkIntegral();
 	type = e1->type;
     }
@@ -7012,9 +7176,16 @@
 	    return e->implicitCastTo(sc, to);
 	}
 
+	if (e1->op == TOKtemplate)
+	{
+	    error("cannot cast template %s to type %s", e1->toChars(), to->toChars());
+	    return new ErrorExp();
+	}
+
+	Type *t1b = e1->type->toBasetype();
 	Type *tob = to->toBasetype();
 	if (tob->ty == Tstruct &&
-	    !tob->equals(e1->type->toBasetype()) &&
+	    !tob->equals(t1b) &&
 	    ((TypeStruct *)to)->sym->search(0, Id::call, 0)
 	   )
 	{
@@ -7031,6 +7202,18 @@
 	    e = e->semantic(sc);
 	    return e;
 	}
+
+	// Struct casts are possible only when the sizes match
+	if (tob->ty == Tstruct || t1b->ty == Tstruct)
+	{
+	    size_t fromsize = t1b->size(loc);
+	    size_t tosize = tob->size(loc);
+	    if (fromsize != tosize)
+	    {
+		error("cannot cast from %s to %s", e1->type->toChars(), to->toChars());
+		return new ErrorExp();
+	    }
+	}
     }
     e = e1->castTo(sc, to);
     return e;
@@ -7737,7 +7920,7 @@
 
 /************************************************************/
 
-/* Can be TOKconstruct too */
+/* op can be TOKassign, TOKconstruct, or TOKblit */
 
 AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2)
 	: BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2)
@@ -7746,26 +7929,39 @@
 }
 
 Expression *AssignExp::semantic(Scope *sc)
-{   Type *t1;
+{
     Expression *e1old = e1;
 
 #if LOGSEMANTIC
     printf("AssignExp::semantic('%s')\n", toChars());
 #endif
     //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op));
+    //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op));
+
+    if (type)
+	return this;
+
+    if (e2->op == TOKcomma)
+    {	/* Rewrite to get rid of the comma from rvalue
+	 */
+	AssignExp *ea = new AssignExp(loc, e1, ((CommaExp *)e2)->e2);
+	ea->op = op;
+	Expression *e = new CommaExp(loc, ((CommaExp *)e2)->e1, ea);
+	return e->semantic(sc);
+    }
 
     /* Look for operator overloading of a[i]=value.
      * Do it before semantic() otherwise the a[i] will have been
      * converted to a.opIndex() already.
      */
     if (e1->op == TOKarray)
-    {	Type *t1;
+    {
 	ArrayExp *ae = (ArrayExp *)e1;
 	AggregateDeclaration *ad;
 	Identifier *id = Id::index;
 
 	ae->e1 = ae->e1->semantic(sc);
-	t1 = ae->e1->type->toBasetype();
+	Type *t1 = ae->e1->type->toBasetype();
 	if (t1->ty == Tstruct)
 	{
 	    ad = ((TypeStruct *)t1)->sym;
@@ -7880,13 +8076,20 @@
 	}
     }
 
-    t1 = e1->type->toBasetype();
+    // Determine if this is an initialization of a reference
+    int refinit = 0;
+    if (op == TOKconstruct && e1->op == TOKvar)
+    {	VarExp *ve = (VarExp *)e1;
+	VarDeclaration *v = ve->var->isVarDeclaration();
+	if (v->storage_class & (STCout | STCref))
+	    refinit = 1;
+    }
+
+    Type *t1 = e1->type->toBasetype();
 
     if (t1->ty == Tfunction)
     {	// Rewrite f=value to f(value)
-	Expression *e;
-
-	e = new CallExp(loc, e1, e2);
+	Expression *e = new CallExp(loc, e1, e2);
 	e = e->semantic(sc);
 	return e;
     }
@@ -7918,7 +8121,8 @@
     else
     {	// Try to do a decent error message with the expression
 	// before it got constant folded
-	e1 = e1->modifiableLvalue(sc, e1old);
+	if (op != TOKconstruct)
+	    e1 = e1->modifiableLvalue(sc, e1old);
     }
 
     if (e1->op == TOKslice &&
@@ -7930,7 +8134,7 @@
 	ismemset = 1;	// make it easy for back end to tell what this is
 	e2 = e2->implicitCastTo(sc, t1->next);
     }
-    else if (t1->ty == Tsarray)
+    else if (t1->ty == Tsarray && !refinit)
     {
 	error("cannot assign to static array %s", e1->toChars());
     }
@@ -8061,6 +8265,7 @@
 	    typeCombine(sc);
 	    e1->checkArithmetic();
 	    e2->checkArithmetic();
+	    checkComplexAddAssign();
 	    if (type->isreal() || type->isimaginary())
 	    {
 		assert(global.errors || e2->type->isfloating());
@@ -8111,6 +8316,7 @@
     {
 	e1 = e1->checkArithmetic();
 	e2 = e2->checkArithmetic();
+	checkComplexAddAssign();
 	type = e1->type;
 	typeCombine(sc);
 	if (type->isreal() || type->isimaginary())
@@ -8215,6 +8421,7 @@
     typeCombine(sc);
     e1->checkArithmetic();
     e2->checkArithmetic();
+    checkComplexMulAssign();
     if (e2->type->isfloating())
     {	Type *t1;
 	Type *t2;
@@ -8281,6 +8488,7 @@
     typeCombine(sc);
     e1->checkArithmetic();
     e2->checkArithmetic();
+    checkComplexMulAssign();
     if (e2->type->isimaginary())
     {	Type *t1;
 	Type *t2;
@@ -8328,6 +8536,8 @@
 
 Expression *ModAssignExp::semantic(Scope *sc)
 {
+    BinExp::semantic(sc);
+    checkComplexMulAssign();
     return commonSemanticAssign(sc);
 }
 
@@ -8736,10 +8946,10 @@
 	return e;
 
     typeCombine(sc);
-    if (e1->op != TOKslice && e2->op != TOKslice)
-    {	e1->checkArithmetic();
+    if (!e1->isArrayOperand())
+	e1->checkArithmetic();
+    if (!e2->isArrayOperand())
 	e2->checkArithmetic();
-    }
     if (type->isfloating())
     {	Type *t1 = e1->type;
 	Type *t2 = e2->type;
@@ -8802,10 +9012,10 @@
 	return e;
 
     typeCombine(sc);
-    if (e1->op != TOKslice && e2->op != TOKslice)
-    {	e1->checkArithmetic();
+    if (!e1->isArrayOperand())
+	e1->checkArithmetic();
+    if (!e2->isArrayOperand())
 	e2->checkArithmetic();
-    }
     if (type->isfloating())
     {	Type *t1 = e1->type;
 	Type *t2 = e2->type;
@@ -8869,10 +9079,10 @@
 	return e;
 
     typeCombine(sc);
-    if (e1->op != TOKslice && e2->op != TOKslice)
-    {	e1->checkArithmetic();
+    if (!e1->isArrayOperand())
+	e1->checkArithmetic();
+    if (!e2->isArrayOperand())
 	e2->checkArithmetic();
-    }
     if (type->isfloating())
     {	type = e1->type;
 	if (e2->type->iscomplex())
@@ -8983,10 +9193,10 @@
 	else
 	{
 	    typeCombine(sc);
-	    if (e1->op != TOKslice && e2->op != TOKslice)
-	    {   e1->checkIntegral();
+	    if (!e1->isArrayOperand())
+		e1->checkIntegral();
+	    if (!e2->isArrayOperand())
 		e2->checkIntegral();
-	    }
 	}
     }
     return this;
@@ -9016,10 +9226,10 @@
 	else
 	{
 	    typeCombine(sc);
-	    if (e1->op != TOKslice && e2->op != TOKslice)
-	    {   e1->checkIntegral();
+	    if (!e1->isArrayOperand())
+		e1->checkIntegral();
+	    if (!e2->isArrayOperand())
 		e2->checkIntegral();
-	    }
 	}
     }
     return this;
@@ -9049,10 +9259,10 @@
 	else
 	{
 	    typeCombine(sc);
-	    if (e1->op != TOKslice && e2->op != TOKslice)
-	    {   e1->checkIntegral();
+	    if (!e1->isArrayOperand())
+		e1->checkIntegral();
+	    if (!e2->isArrayOperand())
 		e2->checkIntegral();
-	    }
 	}
     }
     return this;
@@ -9254,8 +9464,6 @@
 
 Expression *CmpExp::semantic(Scope *sc)
 {   Expression *e;
-    Type *t1;
-    Type *t2;
 
 #if LOGSEMANTIC
     printf("CmpExp::semantic('%s')\n", toChars());
@@ -9265,8 +9473,10 @@
 
     BinExp::semanticp(sc);
 
-    if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull ||
-	e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull)
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+    if (t1->ty == Tclass && e2->op == TOKnull ||
+	t2->ty == Tclass && e1->op == TOKnull)
     {
 	error("do not use null when comparing class types");
     }
@@ -9286,6 +9496,15 @@
 	return e;
     }
 
+    /* Disallow comparing T[]==T and T==T[]
+     */
+    if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) ||
+	e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf()))
+    {
+	incompatibleTypes();
+	return new ErrorExp();
+    }
+
     typeCombine(sc);
     type = Type::tboolean;
 
@@ -9337,8 +9556,6 @@
 
 Expression *EqualExp::semantic(Scope *sc)
 {   Expression *e;
-    Type *t1;
-    Type *t2;
 
     //printf("EqualExp::semantic('%s')\n", toChars());
     if (type)
@@ -9367,8 +9584,10 @@
 	}
     }
 
-    if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull ||
-	e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull)
+    Type *t1 = e1->type->toBasetype();
+    Type *t2 = e2->type->toBasetype();
+    if (t1->ty == Tclass && e2->op == TOKnull ||
+	t2->ty == Tclass && e1->op == TOKnull)
     {
 	error("use '%s' instead of '%s' when comparing with null",
 		Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity),
@@ -9389,6 +9608,15 @@
 	}
     }
 
+    /* Disallow comparing T[]==T and T==T[]
+     */
+    if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) ||
+	e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf()))
+    {
+	incompatibleTypes();
+	return new ErrorExp();
+    }
+
     e = typeCombine(sc);
     type = Type::tboolean;