mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
1677 lines
45 KiB
C
1677 lines
45 KiB
C
|
|
// Copyright (c) 1999-2012 by Digital Mars
|
|
// All Rights Reserved
|
|
// written by Walter Bright
|
|
// http://www.digitalmars.com
|
|
// License for redistribution is by either the Artistic License
|
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
|
// See the included readme.txt for details.
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <string.h> // mem{set|cpy}()
|
|
|
|
#include "rmem.h"
|
|
|
|
#include "expression.h"
|
|
#include "mtype.h"
|
|
#include "utf.h"
|
|
#include "declaration.h"
|
|
#include "aggregate.h"
|
|
|
|
/* ==================== implicitCast ====================== */
|
|
|
|
/**************************************
|
|
* Do an implicit cast.
|
|
* Issue error if it can't be done.
|
|
*/
|
|
|
|
Expression *Expression::implicitCastTo(Scope *sc, Type *t)
|
|
{
|
|
//printf("implicitCastTo(%s) => %s\n", type->toChars(), t->toChars());
|
|
if (implicitConvTo(t))
|
|
{ TY tyfrom = type->toBasetype()->ty;
|
|
TY tyto = t->toBasetype()->ty;
|
|
if (global.params.warnings &&
|
|
Type::impcnvWarn[tyfrom][tyto] &&
|
|
op != TOKint64)
|
|
{
|
|
Expression *e = optimize(WANTflags | WANTvalue);
|
|
|
|
if (e->op == TOKint64)
|
|
return e->implicitCastTo(sc, t);
|
|
|
|
if (tyfrom == Tint32 &&
|
|
(op == TOKadd || op == TOKmin ||
|
|
op == TOKand || op == TOKor || op == TOKxor)
|
|
)
|
|
{
|
|
/* This is really only a semi-kludge fix,
|
|
* we really should look at the operands of op
|
|
* and see if they are narrower types.
|
|
* For example, b=b|b and b=b|7 and s=b+b should be allowed,
|
|
* but b=b|i should be an error.
|
|
*/
|
|
;
|
|
}
|
|
else
|
|
{
|
|
warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data",
|
|
toChars(), type->toChars(), t->toChars());
|
|
}
|
|
}
|
|
#if DMDV2
|
|
if (match == MATCHconst && t == type->constOf())
|
|
{
|
|
Expression *e = copy();
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
#endif
|
|
return castTo(sc, t);
|
|
}
|
|
|
|
Expression *e = optimize(WANTflags | WANTvalue);
|
|
if (e != this)
|
|
return e->implicitCastTo(sc, t);
|
|
|
|
#if 0
|
|
printf("ty = %d\n", type->ty);
|
|
print();
|
|
type->print();
|
|
printf("to:\n");
|
|
t->print();
|
|
printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco);
|
|
//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t);
|
|
fflush(stdout);
|
|
#endif
|
|
if (t->ty != Terror && type->ty != Terror)
|
|
{
|
|
if (!t->deco)
|
|
{ /* Can happen with:
|
|
* enum E { One }
|
|
* class A
|
|
* { static void fork(EDG dg) { dg(E.One); }
|
|
* alias void delegate(E) EDG;
|
|
* }
|
|
* Should eventually make it work.
|
|
*/
|
|
error("forward reference to type %s", t->toChars());
|
|
}
|
|
else if (t->reliesOnTident())
|
|
error("forward reference to type %s", t->reliesOnTident()->toChars());
|
|
|
|
error("cannot implicitly convert expression (%s) of type %s to %s",
|
|
toChars(), type->toChars(), t->toChars());
|
|
}
|
|
return new ErrorExp();
|
|
}
|
|
|
|
Expression *ErrorExp::implicitCastTo(Scope *sc, Type *t)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
/*******************************************
|
|
* Return !=0 if we can implicitly convert this to type t.
|
|
* Don't do the actual cast.
|
|
*/
|
|
|
|
MATCH Expression::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
//static int nest; if (++nest == 10) halt();
|
|
if (t == Type::terror)
|
|
return MATCHnomatch;
|
|
if (!type)
|
|
{ error("%s is not an expression", toChars());
|
|
type = Type::terror;
|
|
}
|
|
if (t->ty == Tbit && isBit())
|
|
return MATCHconvert;
|
|
Expression *e = optimize(WANTvalue | WANTflags);
|
|
if (e != this)
|
|
{ //printf("optimzed to %s\n", e->toChars());
|
|
return e->implicitConvTo(t);
|
|
}
|
|
MATCH match = type->implicitConvTo(t);
|
|
if (match)
|
|
return match;
|
|
#if 0
|
|
Type *tb = t->toBasetype();
|
|
if (tb->ty == Tdelegate)
|
|
{ TypeDelegate *td = (TypeDelegate *)tb;
|
|
TypeFunction *tf = (TypeFunction *)td->nextOf();
|
|
|
|
if (!tf->varargs &&
|
|
!(tf->arguments && tf->arguments->dim)
|
|
)
|
|
{
|
|
match = type->implicitConvTo(tf->nextOf());
|
|
if (match)
|
|
return match;
|
|
if (tf->nextOf()->toBasetype()->ty == Tvoid)
|
|
return MATCHconvert;
|
|
}
|
|
}
|
|
#endif
|
|
return MATCHnomatch;
|
|
}
|
|
|
|
|
|
MATCH IntegerExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
if (type->equals(t))
|
|
return MATCHexact;
|
|
|
|
enum TY ty = type->toBasetype()->ty;
|
|
enum TY toty = t->toBasetype()->ty;
|
|
enum TY oldty = ty;
|
|
|
|
if (type->implicitConvTo(t) == MATCHnomatch && t->ty == Tenum)
|
|
{
|
|
return MATCHnomatch;
|
|
}
|
|
|
|
switch (ty)
|
|
{
|
|
case Tbit:
|
|
case Tbool:
|
|
value &= 1;
|
|
ty = Tint32;
|
|
break;
|
|
|
|
case Tint8:
|
|
value = (signed char)value;
|
|
ty = Tint32;
|
|
break;
|
|
|
|
case Tchar:
|
|
case Tuns8:
|
|
value &= 0xFF;
|
|
ty = Tint32;
|
|
break;
|
|
|
|
case Tint16:
|
|
value = (short)value;
|
|
ty = Tint32;
|
|
break;
|
|
|
|
case Tuns16:
|
|
case Twchar:
|
|
value &= 0xFFFF;
|
|
ty = Tint32;
|
|
break;
|
|
|
|
case Tint32:
|
|
value = (int)value;
|
|
break;
|
|
|
|
case Tuns32:
|
|
case Tdchar:
|
|
value &= 0xFFFFFFFF;
|
|
ty = Tuns32;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Only allow conversion if no change in value
|
|
switch (toty)
|
|
{
|
|
case Tbit:
|
|
case Tbool:
|
|
if ((value & 1) != value)
|
|
goto Lno;
|
|
goto Lyes;
|
|
|
|
case Tint8:
|
|
if ((signed char)value != value)
|
|
goto Lno;
|
|
goto Lyes;
|
|
|
|
case Tchar:
|
|
if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F)
|
|
goto Lno;
|
|
case Tuns8:
|
|
//printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
|
|
if ((unsigned char)value != value)
|
|
goto Lno;
|
|
goto Lyes;
|
|
|
|
case Tint16:
|
|
if ((short)value != value)
|
|
goto Lno;
|
|
goto Lyes;
|
|
|
|
case Twchar:
|
|
if (oldty == Tdchar && value > 0xD7FF && value < 0xE000)
|
|
goto Lno;
|
|
case Tuns16:
|
|
if ((unsigned short)value != value)
|
|
goto Lno;
|
|
goto Lyes;
|
|
|
|
case Tint32:
|
|
if (ty == Tuns32)
|
|
{
|
|
}
|
|
else if ((int)value != value)
|
|
goto Lno;
|
|
goto Lyes;
|
|
|
|
case Tuns32:
|
|
if (ty == Tint32)
|
|
{
|
|
}
|
|
else if ((unsigned)value != value)
|
|
goto Lno;
|
|
goto Lyes;
|
|
|
|
case Tdchar:
|
|
if (value > 0x10FFFFUL)
|
|
goto Lno;
|
|
goto Lyes;
|
|
|
|
case Tfloat32:
|
|
{
|
|
volatile float f;
|
|
if (type->isunsigned())
|
|
{
|
|
f = (float)value;
|
|
if (f != value)
|
|
goto Lno;
|
|
}
|
|
else
|
|
{
|
|
f = (float)(long long)value;
|
|
if (f != (long long)value)
|
|
goto Lno;
|
|
}
|
|
goto Lyes;
|
|
}
|
|
|
|
case Tfloat64:
|
|
{
|
|
volatile double f;
|
|
if (type->isunsigned())
|
|
{
|
|
f = (double)value;
|
|
if (f != value)
|
|
goto Lno;
|
|
}
|
|
else
|
|
{
|
|
f = (double)(long long)value;
|
|
if (f != (long long)value)
|
|
goto Lno;
|
|
}
|
|
goto Lyes;
|
|
}
|
|
|
|
case Tfloat80:
|
|
{
|
|
volatile long double f;
|
|
if (type->isunsigned())
|
|
{
|
|
f = (long double)value;
|
|
if (f != value)
|
|
goto Lno;
|
|
}
|
|
else
|
|
{
|
|
f = (long double)(long long)value;
|
|
if (f != (long long)value)
|
|
goto Lno;
|
|
}
|
|
goto Lyes;
|
|
}
|
|
}
|
|
return Expression::implicitConvTo(t);
|
|
|
|
Lyes:
|
|
//printf("MATCHconvert\n");
|
|
return MATCHconvert;
|
|
|
|
Lno:
|
|
//printf("MATCHnomatch\n");
|
|
return MATCHnomatch;
|
|
}
|
|
|
|
MATCH NullExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n",
|
|
toChars(), type->toChars(), t->toChars(), committed);
|
|
#endif
|
|
if (this->type->equals(t))
|
|
return MATCHexact;
|
|
// NULL implicitly converts to any pointer type or dynamic array
|
|
if (type->ty == Tpointer && type->next->ty == Tvoid)
|
|
{
|
|
if (t->ty == Ttypedef)
|
|
t = ((TypeTypedef *)t)->sym->basetype;
|
|
if (t->ty == Tpointer || t->ty == Tarray ||
|
|
t->ty == Taarray || t->ty == Tclass ||
|
|
t->ty == Tdelegate)
|
|
return committed ? MATCHconvert : MATCHexact;
|
|
}
|
|
return Expression::implicitConvTo(t);
|
|
}
|
|
|
|
#if DMDV2
|
|
MATCH StructLiteralExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
MATCH m = Expression::implicitConvTo(t);
|
|
if (m != MATCHnomatch)
|
|
return m;
|
|
if (type->ty == t->ty && type->ty == Tstruct &&
|
|
((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym)
|
|
{
|
|
m = MATCHconst;
|
|
for (size_t i = 0; i < elements->dim; i++)
|
|
{ Expression *e = (*elements)[i];
|
|
Type *te = e->type;
|
|
if (t->mod == 0)
|
|
te = te->mutableOf();
|
|
else
|
|
{ assert(t->mod == MODimmutable);
|
|
te = te->invariantOf();
|
|
}
|
|
MATCH m2 = e->implicitConvTo(te);
|
|
//printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2);
|
|
if (m2 < m)
|
|
m = m2;
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
#endif
|
|
|
|
MATCH StringExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n",
|
|
toChars(), committed, type->toChars(), t->toChars());
|
|
#endif
|
|
if (!committed && t->ty == Tpointer && t->next->ty == Tvoid)
|
|
{
|
|
return MATCHnomatch;
|
|
}
|
|
if (!committed)
|
|
if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer)
|
|
{
|
|
if (type->next->ty == Tchar)
|
|
{
|
|
switch (t->ty)
|
|
{
|
|
case Tsarray:
|
|
if (type->ty == Tsarray &&
|
|
((TypeSArray *)type)->dim->toInteger() !=
|
|
((TypeSArray *)t)->dim->toInteger())
|
|
return MATCHnomatch;
|
|
goto L1;
|
|
case Tarray:
|
|
goto L1;
|
|
case Tpointer:
|
|
L1:
|
|
if (t->next->ty == Tchar)
|
|
return MATCHexact;
|
|
else if (!committed)
|
|
{ if (t->next->ty == Twchar)
|
|
return MATCHexact;
|
|
else if (t->next->ty == Tdchar)
|
|
return MATCHexact;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return Expression::implicitConvTo(t);
|
|
#if 0
|
|
m = (MATCH)type->implicitConvTo(t);
|
|
if (m)
|
|
{
|
|
return m;
|
|
}
|
|
|
|
return MATCHnomatch;
|
|
#endif
|
|
}
|
|
|
|
MATCH ArrayLiteralExp::implicitConvTo(Type *t)
|
|
{ MATCH result = MATCHexact;
|
|
|
|
#if 0
|
|
printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
Type *typeb = type->toBasetype();
|
|
Type *tb = t->toBasetype();
|
|
if ((tb->ty == Tarray || tb->ty == Tsarray) &&
|
|
(typeb->ty == Tarray || typeb->ty == Tsarray))
|
|
{
|
|
if (tb->ty == Tsarray)
|
|
{ TypeSArray *tsa = (TypeSArray *)tb;
|
|
if (elements->dim != tsa->dim->toInteger())
|
|
result = MATCHnomatch;
|
|
}
|
|
|
|
if (!elements->dim && typeb->nextOf()->toBasetype()->ty != Tvoid)
|
|
result = MATCHnomatch;
|
|
|
|
Type *telement = tb->nextOf();
|
|
for (size_t i = 0; i < elements->dim; i++)
|
|
{ Expression *e = (*elements)[i];
|
|
if (result == MATCHnomatch)
|
|
break; // no need to check for worse
|
|
MATCH m = (MATCH)e->implicitConvTo(telement);
|
|
if (m < result)
|
|
result = m; // remember worst match
|
|
}
|
|
|
|
if (!result)
|
|
result = type->implicitConvTo(t);
|
|
|
|
return result;
|
|
}
|
|
#if DMDV2
|
|
else if (tb->ty == Tvector &&
|
|
(typeb->ty == Tarray || typeb->ty == Tsarray))
|
|
{
|
|
// Convert array literal to vector type
|
|
TypeVector *tv = (TypeVector *)tb;
|
|
TypeSArray *tbase = (TypeSArray *)tv->basetype;
|
|
assert(tbase->ty == Tsarray);
|
|
if (elements->dim != tbase->dim->toInteger())
|
|
return MATCHnomatch;
|
|
|
|
Type *telement = tv->elementType();
|
|
for (size_t i = 0; i < elements->dim; i++)
|
|
{ Expression *e = (*elements)[i];
|
|
MATCH m = (MATCH)e->implicitConvTo(telement);
|
|
if (m < result)
|
|
result = m; // remember worst match
|
|
if (result == MATCHnomatch)
|
|
break; // no need to check for worse
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
else
|
|
return Expression::implicitConvTo(t);
|
|
}
|
|
|
|
MATCH AssocArrayLiteralExp::implicitConvTo(Type *t)
|
|
{ MATCH result = MATCHexact;
|
|
|
|
Type *typeb = type->toBasetype();
|
|
Type *tb = t->toBasetype();
|
|
if (tb->ty == Taarray && typeb->ty == Taarray)
|
|
{
|
|
for (size_t i = 0; i < keys->dim; i++)
|
|
{ Expression *e = (Expression *)keys->data[i];
|
|
MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->key);
|
|
if (m < result)
|
|
result = m; // remember worst match
|
|
if (result == MATCHnomatch)
|
|
break; // no need to check for worse
|
|
e = (Expression *)values->data[i];
|
|
m = (MATCH)e->implicitConvTo(tb->nextOf());
|
|
if (m < result)
|
|
result = m; // remember worst match
|
|
if (result == MATCHnomatch)
|
|
break; // no need to check for worse
|
|
}
|
|
return result;
|
|
}
|
|
else
|
|
return Expression::implicitConvTo(t);
|
|
}
|
|
|
|
MATCH AddrExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
MATCH result;
|
|
|
|
result = type->implicitConvTo(t);
|
|
//printf("\tresult = %d\n", result);
|
|
|
|
if (result == MATCHnomatch)
|
|
{
|
|
// Look for pointers to functions where the functions are overloaded.
|
|
VarExp *ve;
|
|
FuncDeclaration *f;
|
|
|
|
t = t->toBasetype();
|
|
if (type->ty == Tpointer && type->next->ty == Tfunction &&
|
|
t->ty == Tpointer && t->next->ty == Tfunction &&
|
|
e1->op == TOKvar)
|
|
{
|
|
ve = (VarExp *)e1;
|
|
f = ve->var->isFuncDeclaration();
|
|
if (f && f->overloadExactMatch(t->next, m))
|
|
result = MATCHexact;
|
|
}
|
|
}
|
|
//printf("\tresult = %d\n", result);
|
|
return result;
|
|
}
|
|
|
|
MATCH SymOffExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
MATCH result;
|
|
|
|
result = type->implicitConvTo(t);
|
|
//printf("\tresult = %d\n", result);
|
|
|
|
if (result == MATCHnomatch)
|
|
{
|
|
// Look for pointers to functions where the functions are overloaded.
|
|
FuncDeclaration *f;
|
|
|
|
t = t->toBasetype();
|
|
if (type->ty == Tpointer && type->next->ty == Tfunction &&
|
|
t->ty == Tpointer && t->next->ty == Tfunction)
|
|
{
|
|
f = var->isFuncDeclaration();
|
|
if (f && f->overloadExactMatch(t->next, m))
|
|
result = MATCHexact;
|
|
}
|
|
}
|
|
//printf("\tresult = %d\n", result);
|
|
return result;
|
|
}
|
|
|
|
MATCH DelegateExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
MATCH result;
|
|
|
|
result = type->implicitConvTo(t);
|
|
|
|
if (result == 0)
|
|
{
|
|
// Look for pointers to functions where the functions are overloaded.
|
|
|
|
t = t->toBasetype();
|
|
if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction &&
|
|
t->ty == Tdelegate && t->nextOf()->ty == Tfunction)
|
|
{
|
|
if (func && func->overloadExactMatch(t->nextOf(), m))
|
|
result = MATCHexact;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
MATCH CondExp::implicitConvTo(Type *t)
|
|
{
|
|
MATCH m1;
|
|
MATCH m2;
|
|
|
|
m1 = e1->implicitConvTo(t);
|
|
m2 = e2->implicitConvTo(t);
|
|
|
|
// Pick the worst match
|
|
return (m1 < m2) ? m1 : m2;
|
|
}
|
|
|
|
|
|
/* ==================== castTo ====================== */
|
|
|
|
/**************************************
|
|
* Do an explicit cast.
|
|
*/
|
|
|
|
Expression *Expression::castTo(Scope *sc, Type *t)
|
|
{
|
|
//printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars());
|
|
#if 0
|
|
printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
if (type == t)
|
|
return this;
|
|
Expression *e = this;
|
|
Type *tb = t->toBasetype();
|
|
Type *typeb = type->toBasetype();
|
|
if (tb != typeb)
|
|
{
|
|
// Do (type *) cast of (type [dim])
|
|
if (tb->ty == Tpointer &&
|
|
typeb->ty == Tsarray
|
|
)
|
|
{
|
|
//printf("Converting [dim] to *\n");
|
|
|
|
if (typeb->size(loc) == 0)
|
|
e = new NullExp(loc);
|
|
else
|
|
e = new AddrExp(loc, e);
|
|
}
|
|
#if 0
|
|
else if (tb->ty == Tdelegate && type->ty != Tdelegate)
|
|
{
|
|
TypeDelegate *td = (TypeDelegate *)tb;
|
|
TypeFunction *tf = (TypeFunction *)td->nextOf();
|
|
return toDelegate(sc, tf->nextOf());
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
e = new CastExp(loc, e, tb);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
e = e->copy(); // because of COW for assignment to e->type
|
|
}
|
|
assert(e != this);
|
|
e->type = t;
|
|
//printf("Returning: %s\n", e->toChars());
|
|
return e;
|
|
}
|
|
|
|
|
|
Expression *ErrorExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
|
|
Expression *RealExp::castTo(Scope *sc, Type *t)
|
|
{ Expression *e = this;
|
|
if (type != t)
|
|
{
|
|
if ((type->isreal() && t->isreal()) ||
|
|
(type->isimaginary() && t->isimaginary())
|
|
)
|
|
{ e = copy();
|
|
e->type = t;
|
|
}
|
|
else
|
|
e = Expression::castTo(sc, t);
|
|
}
|
|
return e;
|
|
}
|
|
|
|
|
|
Expression *ComplexExp::castTo(Scope *sc, Type *t)
|
|
{ Expression *e = this;
|
|
if (type != t)
|
|
{
|
|
if (type->iscomplex() && t->iscomplex())
|
|
{ e = copy();
|
|
e->type = t;
|
|
}
|
|
else
|
|
e = Expression::castTo(sc, t);
|
|
}
|
|
return e;
|
|
}
|
|
|
|
|
|
Expression *NullExp::castTo(Scope *sc, Type *t)
|
|
{ NullExp *e;
|
|
Type *tb;
|
|
|
|
//printf("NullExp::castTo(t = %p)\n", t);
|
|
if (type == t)
|
|
{
|
|
committed = 1;
|
|
return this;
|
|
}
|
|
e = (NullExp *)copy();
|
|
e->committed = 1;
|
|
tb = t->toBasetype();
|
|
e->type = type->toBasetype();
|
|
if (tb != e->type)
|
|
{
|
|
// NULL implicitly converts to any pointer type or dynamic array
|
|
if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid &&
|
|
(tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray ||
|
|
tb->ty == Tdelegate))
|
|
{
|
|
#if 0
|
|
if (tb->ty == Tdelegate)
|
|
{ TypeDelegate *td = (TypeDelegate *)tb;
|
|
TypeFunction *tf = (TypeFunction *)td->nextOf();
|
|
|
|
if (!tf->varargs &&
|
|
!(tf->arguments && tf->arguments->dim)
|
|
)
|
|
{
|
|
return Expression::castTo(sc, t);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
return e->Expression::castTo(sc, t);
|
|
}
|
|
}
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
|
|
Expression *StringExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
/* This follows copy-on-write; any changes to 'this'
|
|
* will result in a copy.
|
|
* The this->string member is considered immutable.
|
|
*/
|
|
int copied = 0;
|
|
|
|
//printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed);
|
|
|
|
if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
|
|
{
|
|
error("cannot convert string literal to void*");
|
|
return new ErrorExp();
|
|
}
|
|
|
|
StringExp *se = this;
|
|
if (!committed)
|
|
{ se = (StringExp *)copy();
|
|
se->committed = 1;
|
|
copied = 1;
|
|
}
|
|
|
|
if (type == t)
|
|
{
|
|
return se;
|
|
}
|
|
|
|
Type *tb = t->toBasetype();
|
|
//printf("\ttype = %s\n", type->toChars());
|
|
if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate)
|
|
return Expression::castTo(sc, t);
|
|
|
|
Type *typeb = type->toBasetype();
|
|
if (typeb == tb)
|
|
{
|
|
if (!copied)
|
|
{ se = (StringExp *)copy();
|
|
copied = 1;
|
|
}
|
|
se->type = t;
|
|
return se;
|
|
}
|
|
|
|
if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
|
|
{ if (!copied)
|
|
{ se = (StringExp *)copy();
|
|
copied = 1;
|
|
}
|
|
goto Lcast;
|
|
}
|
|
if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer)
|
|
{ if (!copied)
|
|
{ se = (StringExp *)copy();
|
|
copied = 1;
|
|
}
|
|
goto Lcast;
|
|
}
|
|
|
|
if (typeb->nextOf()->size() == tb->nextOf()->size())
|
|
{
|
|
if (!copied)
|
|
{ se = (StringExp *)copy();
|
|
copied = 1;
|
|
}
|
|
if (tb->ty == Tsarray)
|
|
goto L2; // handle possible change in static array dimension
|
|
se->type = t;
|
|
return se;
|
|
}
|
|
|
|
if (committed)
|
|
goto Lcast;
|
|
|
|
#define X(tf,tt) ((tf) * 256 + (tt))
|
|
{
|
|
OutBuffer buffer;
|
|
size_t newlen = 0;
|
|
int tfty = typeb->nextOf()->toBasetype()->ty;
|
|
int ttty = tb->nextOf()->toBasetype()->ty;
|
|
switch (X(tfty, ttty))
|
|
{
|
|
case X(Tchar, Tchar):
|
|
case X(Twchar,Twchar):
|
|
case X(Tdchar,Tdchar):
|
|
break;
|
|
|
|
case X(Tchar, Twchar):
|
|
for (size_t u = 0; u < len;)
|
|
{ unsigned c;
|
|
const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
|
|
if (p)
|
|
error("%s", p);
|
|
else
|
|
buffer.writeUTF16(c);
|
|
}
|
|
newlen = buffer.offset / 2;
|
|
buffer.writeUTF16(0);
|
|
goto L1;
|
|
|
|
case X(Tchar, Tdchar):
|
|
for (size_t u = 0; u < len;)
|
|
{ unsigned c;
|
|
const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
|
|
if (p)
|
|
error("%s", p);
|
|
buffer.write4(c);
|
|
newlen++;
|
|
}
|
|
buffer.write4(0);
|
|
goto L1;
|
|
|
|
case X(Twchar,Tchar):
|
|
for (size_t u = 0; u < len;)
|
|
{ unsigned c;
|
|
const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
|
|
if (p)
|
|
error("%s", p);
|
|
else
|
|
buffer.writeUTF8(c);
|
|
}
|
|
newlen = buffer.offset;
|
|
buffer.writeUTF8(0);
|
|
goto L1;
|
|
|
|
case X(Twchar,Tdchar):
|
|
for (size_t u = 0; u < len;)
|
|
{ unsigned c;
|
|
const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
|
|
if (p)
|
|
error("%s", p);
|
|
buffer.write4(c);
|
|
newlen++;
|
|
}
|
|
buffer.write4(0);
|
|
goto L1;
|
|
|
|
case X(Tdchar,Tchar):
|
|
for (size_t u = 0; u < len; u++)
|
|
{
|
|
unsigned c = ((unsigned *)se->string)[u];
|
|
if (!utf_isValidDchar(c))
|
|
error("invalid UCS-32 char \\U%08x", c);
|
|
else
|
|
buffer.writeUTF8(c);
|
|
newlen++;
|
|
}
|
|
newlen = buffer.offset;
|
|
buffer.writeUTF8(0);
|
|
goto L1;
|
|
|
|
case X(Tdchar,Twchar):
|
|
for (size_t u = 0; u < len; u++)
|
|
{
|
|
unsigned c = ((unsigned *)se->string)[u];
|
|
if (!utf_isValidDchar(c))
|
|
error("invalid UCS-32 char \\U%08x", c);
|
|
else
|
|
buffer.writeUTF16(c);
|
|
newlen++;
|
|
}
|
|
newlen = buffer.offset / 2;
|
|
buffer.writeUTF16(0);
|
|
goto L1;
|
|
|
|
L1:
|
|
if (!copied)
|
|
{ se = (StringExp *)copy();
|
|
copied = 1;
|
|
}
|
|
se->string = buffer.extractData();
|
|
se->len = newlen;
|
|
{
|
|
d_uns64 szx = tb->nextOf()->size();
|
|
assert(szx <= 255);
|
|
se->sz = (unsigned char)szx;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(typeb->nextOf()->size() != tb->nextOf()->size());
|
|
goto Lcast;
|
|
}
|
|
}
|
|
#undef X
|
|
L2:
|
|
assert(copied);
|
|
|
|
// See if need to truncate or extend the literal
|
|
if (tb->ty == Tsarray)
|
|
{
|
|
dinteger_t dim2 = ((TypeSArray *)tb)->dim->toInteger();
|
|
|
|
//printf("dim from = %d, to = %d\n", (int)se->len, (int)dim2);
|
|
|
|
// Changing dimensions
|
|
if (dim2 != se->len)
|
|
{
|
|
// Copy when changing the string literal
|
|
unsigned newsz = se->sz;
|
|
void *s;
|
|
int d;
|
|
|
|
d = (dim2 < se->len) ? dim2 : se->len;
|
|
s = (unsigned char *)mem.malloc((dim2 + 1) * newsz);
|
|
memcpy(s, se->string, d * newsz);
|
|
// Extend with 0, add terminating 0
|
|
memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz);
|
|
se->string = s;
|
|
se->len = dim2;
|
|
}
|
|
}
|
|
se->type = t;
|
|
return se;
|
|
|
|
Lcast:
|
|
Expression *e = new CastExp(loc, se, t);
|
|
e->type = t; // so semantic() won't be run on e
|
|
return e;
|
|
}
|
|
|
|
Expression *AddrExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
Type *tb;
|
|
|
|
#if 0
|
|
printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
Expression *e = this;
|
|
|
|
tb = t->toBasetype();
|
|
type = type->toBasetype();
|
|
if (tb != type)
|
|
{
|
|
// Look for pointers to functions where the functions are overloaded.
|
|
VarExp *ve;
|
|
FuncDeclaration *f;
|
|
|
|
if (type->ty == Tpointer && type->next->ty == Tfunction &&
|
|
tb->ty == Tpointer && tb->next->ty == Tfunction &&
|
|
e1->op == TOKvar)
|
|
{
|
|
ve = (VarExp *)e1;
|
|
f = ve->var->isFuncDeclaration();
|
|
if (f)
|
|
{
|
|
f = f->overloadExactMatch(tb->next, m);
|
|
if (f)
|
|
{
|
|
e = new VarExp(loc, f);
|
|
e->type = f->type;
|
|
e = new AddrExp(loc, e);
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
e = Expression::castTo(sc, t);
|
|
}
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
|
|
|
|
Expression *TupleExp::castTo(Scope *sc, Type *t)
|
|
{ TupleExp *e = (TupleExp *)copy();
|
|
e->exps = (Expressions *)exps->copy();
|
|
for (size_t i = 0; i < e->exps->dim; i++)
|
|
{ Expression *ex = (Expression *)e->exps->data[i];
|
|
ex = ex->castTo(sc, t);
|
|
e->exps->data[i] = (void *)ex;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
|
|
Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
#if 0
|
|
printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
if (type == t)
|
|
return this;
|
|
ArrayLiteralExp *e = this;
|
|
Type *typeb = type->toBasetype();
|
|
Type *tb = t->toBasetype();
|
|
if ((tb->ty == Tarray || tb->ty == Tsarray) &&
|
|
(typeb->ty == Tarray || typeb->ty == Tsarray) &&
|
|
// Not trying to convert non-void[] to void[]
|
|
!(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid))
|
|
{
|
|
if (tb->ty == Tsarray)
|
|
{ TypeSArray *tsa = (TypeSArray *)tb;
|
|
if (elements->dim != tsa->dim->toInteger())
|
|
goto L1;
|
|
}
|
|
|
|
e = (ArrayLiteralExp *)copy();
|
|
e->elements = (Expressions *)elements->copy();
|
|
for (size_t i = 0; i < elements->dim; i++)
|
|
{ Expression *ex = (*elements)[i];
|
|
ex = ex->castTo(sc, tb->nextOf());
|
|
(*e->elements)[i] = ex;
|
|
}
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
if (tb->ty == Tpointer && typeb->ty == Tsarray)
|
|
{
|
|
e = (ArrayLiteralExp *)copy();
|
|
e->type = typeb->nextOf()->pointerTo();
|
|
}
|
|
#if DMDV2
|
|
else if (tb->ty == Tvector &&
|
|
(typeb->ty == Tarray || typeb->ty == Tsarray))
|
|
{
|
|
// Convert array literal to vector type
|
|
TypeVector *tv = (TypeVector *)tb;
|
|
TypeSArray *tbase = (TypeSArray *)tv->basetype;
|
|
assert(tbase->ty == Tsarray);
|
|
if (elements->dim != tbase->dim->toInteger())
|
|
goto L1;
|
|
|
|
e = (ArrayLiteralExp *)copy();
|
|
e->elements = (Expressions *)elements->copy();
|
|
Type *telement = tv->elementType();
|
|
for (size_t i = 0; i < elements->dim; i++)
|
|
{ Expression *ex = (*elements)[i];
|
|
ex = ex->castTo(sc, telement);
|
|
(*e->elements)[i] = ex;
|
|
}
|
|
Expression *ev = new VectorExp(loc, e, tb);
|
|
ev = ev->semantic(sc);
|
|
return ev;
|
|
}
|
|
#endif
|
|
L1:
|
|
return e->Expression::castTo(sc, t);
|
|
}
|
|
|
|
Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
if (type == t)
|
|
return this;
|
|
AssocArrayLiteralExp *e = this;
|
|
Type *typeb = type->toBasetype();
|
|
Type *tb = t->toBasetype();
|
|
if (tb->ty == Taarray && typeb->ty == Taarray &&
|
|
tb->nextOf()->toBasetype()->ty != Tvoid)
|
|
{
|
|
e = (AssocArrayLiteralExp *)copy();
|
|
e->keys = (Expressions *)keys->copy();
|
|
e->values = (Expressions *)values->copy();
|
|
assert(keys->dim == values->dim);
|
|
for (size_t i = 0; i < keys->dim; i++)
|
|
{ Expression *ex = (Expression *)values->data[i];
|
|
ex = ex->castTo(sc, tb->nextOf());
|
|
e->values->data[i] = (void *)ex;
|
|
|
|
ex = (Expression *)keys->data[i];
|
|
ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
|
|
e->keys->data[i] = (void *)ex;
|
|
}
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
return e->Expression::castTo(sc, t);
|
|
}
|
|
|
|
Expression *SymOffExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
#if 0
|
|
printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
Expression *e = this;
|
|
|
|
Type *tb = t->toBasetype();
|
|
Type *typeb = type->toBasetype();
|
|
if (tb != typeb)
|
|
{
|
|
// Look for pointers to functions where the functions are overloaded.
|
|
FuncDeclaration *f;
|
|
|
|
if (typeb->ty == Tpointer && typeb->next->ty == Tfunction &&
|
|
tb->ty == Tpointer && tb->next->ty == Tfunction)
|
|
{
|
|
f = var->isFuncDeclaration();
|
|
if (f)
|
|
{
|
|
f = f->overloadExactMatch(tb->next, m);
|
|
if (f)
|
|
{
|
|
#if DMDV2
|
|
if (tb->ty == Tdelegate)
|
|
{
|
|
if (f->needThis() && hasThis(sc))
|
|
{
|
|
e = new DelegateExp(loc, new ThisExp(loc), f);
|
|
e = e->semantic(sc);
|
|
}
|
|
else if (f->isNested())
|
|
{
|
|
e = new DelegateExp(loc, new IntegerExp(0), f);
|
|
e = e->semantic(sc);
|
|
}
|
|
else if (f->needThis())
|
|
{ error("no 'this' to create delegate for %s", f->toChars());
|
|
return new ErrorExp();
|
|
}
|
|
else
|
|
{ error("cannot cast from function pointer to delegate");
|
|
return new ErrorExp();
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
e = new SymOffExp(loc, f, 0);
|
|
e->type = t;
|
|
}
|
|
#if DMDV2
|
|
f->tookAddressOf++;
|
|
#endif
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
e = Expression::castTo(sc, t);
|
|
}
|
|
else
|
|
{
|
|
e->type = t;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
Expression *DelegateExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
#if 0
|
|
printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
static char msg[] = "cannot form delegate due to covariant return type";
|
|
|
|
Expression *e = this;
|
|
Type *tb = t->toBasetype();
|
|
type = type->toBasetype();
|
|
if (tb != type || hasOverloads)
|
|
{
|
|
// Look for delegates to functions where the functions are overloaded.
|
|
FuncDeclaration *f;
|
|
|
|
if (type->ty == Tdelegate && type->next->ty == Tfunction &&
|
|
tb->ty == Tdelegate && tb->next->ty == Tfunction)
|
|
{
|
|
if (func)
|
|
{
|
|
f = func->overloadExactMatch(tb->next, m);
|
|
if (f)
|
|
{ int offset;
|
|
if (f->tintro && f->tintro->next->isBaseOf(f->type->next, &offset) && offset)
|
|
error("%s", msg);
|
|
e = new DelegateExp(loc, e1, f);
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
if (func->tintro)
|
|
error("%s", msg);
|
|
}
|
|
}
|
|
e = Expression::castTo(sc, t);
|
|
}
|
|
else
|
|
{ int offset;
|
|
|
|
if (func->tintro && func->tintro->next->isBaseOf(func->type->next, &offset) && offset)
|
|
error("%s", msg);
|
|
}
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
|
|
Expression *CondExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
Expression *e = this;
|
|
|
|
if (type != t)
|
|
{
|
|
if (1 || e1->op == TOKstring || e2->op == TOKstring)
|
|
{ e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t));
|
|
e->type = t;
|
|
}
|
|
else
|
|
e = Expression::castTo(sc, t);
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/* ==================== ====================== */
|
|
|
|
/****************************************
|
|
* Scale addition/subtraction to/from pointer.
|
|
*/
|
|
|
|
Expression *BinExp::scaleFactor(Scope *sc)
|
|
{ d_uns64 stride;
|
|
Type *t1b = e1->type->toBasetype();
|
|
Type *t2b = e2->type->toBasetype();
|
|
|
|
if (t1b->ty == Tpointer && t2b->isintegral())
|
|
{ // Need to adjust operator by the stride
|
|
// Replace (ptr + int) with (ptr + (int * stride))
|
|
Type *t = Type::tptrdiff_t;
|
|
|
|
stride = t1b->nextOf()->size(loc);
|
|
if (!t->equals(t2b))
|
|
e2 = e2->castTo(sc, t);
|
|
// LDC: llvm uses typesafe pointer arithmetic
|
|
#if !IN_LLVM
|
|
if (t1b->next->isbit())
|
|
// BUG: should add runtime check for misaligned offsets
|
|
// This perhaps should be done by rewriting as &p[i]
|
|
// and letting back end do it.
|
|
e2 = new UshrExp(loc, e2, new IntegerExp(0, 3, t));
|
|
else
|
|
e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t));
|
|
#endif
|
|
e2->type = t;
|
|
type = e1->type;
|
|
}
|
|
else if (t2b->ty == Tpointer && t1b->isintegral())
|
|
{ // Need to adjust operator by the stride
|
|
// Replace (int + ptr) with (ptr + (int * stride))
|
|
Type *t = Type::tptrdiff_t;
|
|
Expression *e;
|
|
|
|
stride = t2b->nextOf()->size(loc);
|
|
if (!t->equals(t1b))
|
|
e = e1->castTo(sc, t);
|
|
else
|
|
e = e1;
|
|
#if !IN_LLVM
|
|
if (t2b->next->isbit())
|
|
// BUG: should add runtime check for misaligned offsets
|
|
e = new UshrExp(loc, e, new IntegerExp(0, 3, t));
|
|
else
|
|
e = new MulExp(loc, e, new IntegerExp(0, stride, t));
|
|
#endif
|
|
e->type = t;
|
|
type = e2->type;
|
|
e1 = e2;
|
|
e2 = e;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/************************************
|
|
* Bring leaves to common type.
|
|
*/
|
|
|
|
Expression *BinExp::typeCombine(Scope *sc)
|
|
{
|
|
Type *t1;
|
|
Type *t2;
|
|
Type *t;
|
|
TY ty;
|
|
|
|
//printf("BinExp::typeCombine()\n");
|
|
//dump(0);
|
|
|
|
e1 = e1->integralPromotions(sc);
|
|
e2 = e2->integralPromotions(sc);
|
|
|
|
// BUG: do toBasetype()
|
|
t1 = e1->type;
|
|
t2 = e2->type;
|
|
assert(t1);
|
|
|
|
//if (t1) printf("\tt1 = %s\n", t1->toChars());
|
|
//if (t2) printf("\tt2 = %s\n", t2->toChars());
|
|
#ifdef DEBUG
|
|
if (!t2) printf("\te2 = '%s'\n", e2->toChars());
|
|
#endif
|
|
assert(t2);
|
|
|
|
Type *t1b = t1->toBasetype();
|
|
Type *t2b = t2->toBasetype();
|
|
|
|
ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty];
|
|
if (ty != Terror)
|
|
{ TY ty1;
|
|
TY ty2;
|
|
|
|
ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty];
|
|
ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty];
|
|
|
|
if (t1b->ty == ty1) // if no promotions
|
|
{
|
|
if (t1 == t2)
|
|
{
|
|
if (!type)
|
|
type = t1;
|
|
return this;
|
|
}
|
|
|
|
if (t1b == t2b)
|
|
{
|
|
if (!type)
|
|
type = t1b;
|
|
return this;
|
|
}
|
|
}
|
|
|
|
if (!type)
|
|
type = Type::basic[ty];
|
|
|
|
t1 = Type::basic[ty1];
|
|
t2 = Type::basic[ty2];
|
|
e1 = e1->castTo(sc, t1);
|
|
e2 = e2->castTo(sc, t2);
|
|
#if 0
|
|
if (type != Type::basic[ty])
|
|
{ t = type;
|
|
type = Type::basic[ty];
|
|
return castTo(sc, t);
|
|
}
|
|
#endif
|
|
//printf("after typeCombine():\n");
|
|
//dump(0);
|
|
//printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
|
|
return this;
|
|
}
|
|
|
|
t = t1;
|
|
if (t1 == t2)
|
|
{
|
|
if ((t1->ty == Tstruct || t1->ty == Tclass) &&
|
|
(op == TOKmin || op == TOKadd))
|
|
goto Lincompatible;
|
|
}
|
|
else if (t1->isintegral() && t2->isintegral())
|
|
{
|
|
printf("t1 = %s, t2 = %s\n", t1->toChars(), t2->toChars());
|
|
int sz1 = t1->size();
|
|
int sz2 = t2->size();
|
|
int sign1 = t1->isunsigned() == 0;
|
|
int sign2 = t2->isunsigned() == 0;
|
|
|
|
if (sign1 == sign2)
|
|
{
|
|
if (sz1 < sz2)
|
|
goto Lt2;
|
|
else
|
|
goto Lt1;
|
|
}
|
|
if (!sign1)
|
|
{
|
|
if (sz1 >= sz2)
|
|
goto Lt1;
|
|
else
|
|
goto Lt2;
|
|
}
|
|
else
|
|
{
|
|
if (sz2 >= sz1)
|
|
goto Lt2;
|
|
else
|
|
goto Lt1;
|
|
}
|
|
}
|
|
else if (t1->ty == Tpointer && t2->ty == Tpointer)
|
|
{
|
|
// Bring pointers to compatible type
|
|
Type *t1n = t1->next;
|
|
Type *t2n = t2->next;
|
|
|
|
//t1->print();
|
|
//t2->print();
|
|
//if (t1n == t2n) *(char *)0 = 0;
|
|
assert(t1n != t2n);
|
|
if (t1n->ty == Tvoid) // pointers to void are always compatible
|
|
t = t2;
|
|
else if (t2n->ty == Tvoid)
|
|
;
|
|
else if (t1n->ty == Tclass && t2n->ty == Tclass)
|
|
{ ClassDeclaration *cd1 = t1n->isClassHandle();
|
|
ClassDeclaration *cd2 = t2n->isClassHandle();
|
|
int offset;
|
|
|
|
if (cd1->isBaseOf(cd2, &offset))
|
|
{
|
|
if (offset)
|
|
e2 = e2->castTo(sc, t);
|
|
}
|
|
else if (cd2->isBaseOf(cd1, &offset))
|
|
{
|
|
t = t2;
|
|
if (offset)
|
|
e1 = e1->castTo(sc, t);
|
|
}
|
|
else
|
|
goto Lincompatible;
|
|
}
|
|
else
|
|
goto Lincompatible;
|
|
}
|
|
else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
|
|
e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid)
|
|
{ /* (T[n] op void*)
|
|
* (T[] op void*)
|
|
*/
|
|
goto Lx1;
|
|
}
|
|
else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
|
|
e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid)
|
|
{ /* (void* op T[n])
|
|
* (void* op T[])
|
|
*/
|
|
goto Lx2;
|
|
}
|
|
else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2))
|
|
{
|
|
if (t1->ty == Tsarray && e2->op == TOKarrayliteral)
|
|
goto Lt1;
|
|
goto Lt2;
|
|
}
|
|
else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
|
|
{
|
|
if (t2->ty == Tsarray && e1->op == TOKarrayliteral)
|
|
goto Lt2;
|
|
goto Lt1;
|
|
}
|
|
else if (t1->ty == Tclass || t2->ty == Tclass)
|
|
{
|
|
while (1)
|
|
{
|
|
int i1 = e2->implicitConvTo(t1);
|
|
int i2 = e1->implicitConvTo(t2);
|
|
|
|
if (i1 && i2)
|
|
{
|
|
// We have the case of class vs. void*, so pick class
|
|
if (t1->ty == Tpointer)
|
|
i1 = 0;
|
|
else if (t2->ty == Tpointer)
|
|
i2 = 0;
|
|
}
|
|
|
|
if (i2)
|
|
{
|
|
goto Lt2;
|
|
}
|
|
else if (i1)
|
|
{
|
|
goto Lt1;
|
|
}
|
|
else if (t1->ty == Tclass && t2->ty == Tclass)
|
|
{ TypeClass *tc1 = (TypeClass *)t1;
|
|
TypeClass *tc2 = (TypeClass *)t2;
|
|
|
|
/* Pick 'tightest' type
|
|
*/
|
|
ClassDeclaration *cd1 = tc1->sym->baseClass;
|
|
ClassDeclaration *cd2 = tc2->sym->baseClass;
|
|
|
|
if (cd1 && cd2)
|
|
{ t1 = cd1->type;
|
|
t2 = cd2->type;
|
|
}
|
|
else if (cd1)
|
|
t1 = cd1->type;
|
|
else if (cd2)
|
|
t2 = cd2->type;
|
|
else
|
|
goto Lincompatible;
|
|
}
|
|
else
|
|
goto Lincompatible;
|
|
}
|
|
}
|
|
else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
|
|
{
|
|
goto Lt2;
|
|
}
|
|
//else if (e2->op == TOKstring) { printf("test2\n"); }
|
|
else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
|
|
{
|
|
goto Lt1;
|
|
}
|
|
else if (t1->ty == Tsarray && t2->ty == Tsarray &&
|
|
e2->implicitConvTo(t1->nextOf()->arrayOf()))
|
|
{
|
|
Lx1:
|
|
t = t1->nextOf()->arrayOf();
|
|
e1 = e1->castTo(sc, t);
|
|
e2 = e2->castTo(sc, t);
|
|
}
|
|
else if (t1->ty == Tsarray && t2->ty == Tsarray &&
|
|
e1->implicitConvTo(t2->nextOf()->arrayOf()))
|
|
{
|
|
Lx2:
|
|
t = t2->nextOf()->arrayOf();
|
|
e1 = e1->castTo(sc, t);
|
|
e2 = e2->castTo(sc, t);
|
|
}
|
|
else if (t1->isintegral() && t2->isintegral())
|
|
{
|
|
assert(0);
|
|
}
|
|
else if (e1->isArrayOperand() && t1->ty == Tarray &&
|
|
e2->implicitConvTo(t1->nextOf()))
|
|
{ // T[] op T
|
|
e2 = e2->castTo(sc, t1->nextOf());
|
|
t = t1->nextOf()->arrayOf();
|
|
}
|
|
else if (e2->isArrayOperand() && t2->ty == Tarray &&
|
|
e1->implicitConvTo(t2->nextOf()))
|
|
{ // T op T[]
|
|
e1 = e1->castTo(sc, t2->nextOf());
|
|
t = t2->nextOf()->arrayOf();
|
|
|
|
//printf("test %s\n", e->toChars());
|
|
e1 = e1->optimize(WANTvalue);
|
|
if (isCommutative() && e1->isConst())
|
|
{ /* Swap operands to minimize number of functions generated
|
|
*/
|
|
//printf("swap %s\n", e->toChars());
|
|
Expression *tmp = e1;
|
|
e1 = e2;
|
|
e2 = tmp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Lincompatible:
|
|
incompatibleTypes();
|
|
type = Type::terror;
|
|
e1 = new ErrorExp();
|
|
e2 = new ErrorExp();
|
|
return new ErrorExp();
|
|
}
|
|
Lret:
|
|
if (!type)
|
|
type = t;
|
|
//dump(0);
|
|
return this;
|
|
|
|
|
|
Lt1:
|
|
e2 = e2->castTo(sc, t1);
|
|
t = t1;
|
|
goto Lret;
|
|
|
|
Lt2:
|
|
e1 = e1->castTo(sc, t2);
|
|
t = t2;
|
|
goto Lret;
|
|
}
|
|
|
|
/***********************************
|
|
* Do integral promotions (convertchk).
|
|
* Don't convert <array of> to <pointer to>
|
|
*/
|
|
|
|
Expression *Expression::integralPromotions(Scope *sc)
|
|
{
|
|
Expression *e = this;
|
|
|
|
//printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars());
|
|
switch (type->toBasetype()->ty)
|
|
{
|
|
case Tvoid:
|
|
error("void has no value");
|
|
return new ErrorExp();
|
|
|
|
case Tint8:
|
|
case Tuns8:
|
|
case Tint16:
|
|
case Tuns16:
|
|
case Tbit:
|
|
case Tbool:
|
|
case Tchar:
|
|
case Twchar:
|
|
e = e->castTo(sc, Type::tint32);
|
|
break;
|
|
|
|
case Tdchar:
|
|
e = e->castTo(sc, Type::tuns32);
|
|
break;
|
|
}
|
|
return e;
|
|
}
|
|
|