mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
3030 lines
88 KiB
C
3030 lines
88 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"
|
|
#include "template.h"
|
|
#include "scope.h"
|
|
|
|
//#define DUMP .dump(__PRETTY_FUNCTION__, this)
|
|
#define DUMP
|
|
|
|
/* ==================== implicitCast ====================== */
|
|
|
|
/**************************************
|
|
* Do an implicit cast.
|
|
* Issue error if it can't be done.
|
|
*/
|
|
|
|
Expression *Expression::implicitCastTo(Scope *sc, Type *t)
|
|
{
|
|
//printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars());
|
|
|
|
MATCH match = implicitConvTo(t);
|
|
if (match)
|
|
{
|
|
#if DMDV1
|
|
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());
|
|
}
|
|
}
|
|
#endif
|
|
#if DMDV2
|
|
if (match == MATCHconst && type->constConv(t))
|
|
{
|
|
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());
|
|
|
|
//printf("type %p ty %d deco %p\n", type, type->ty, type->deco);
|
|
//type = type->semantic(loc, sc);
|
|
//printf("type %s t %s\n", type->deco, t->deco);
|
|
error("cannot implicitly convert expression (%s) of type %s to %s",
|
|
toChars(), type->toChars(), t->toChars());
|
|
}
|
|
return new ErrorExp();
|
|
}
|
|
|
|
Expression *StringExp::implicitCastTo(Scope *sc, Type *t)
|
|
{
|
|
//printf("StringExp::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars());
|
|
unsigned char committed = this->committed;
|
|
Expression *e = Expression::implicitCastTo(sc, t);
|
|
if (e->op == TOKstring)
|
|
{
|
|
// Retain polysemous nature if it started out that way
|
|
((StringExp *)e)->committed = committed;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
Expression *ErrorExp::implicitCastTo(Scope *sc, Type *t)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
Expression *FuncExp::implicitCastTo(Scope *sc, Type *t)
|
|
{
|
|
//printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars());
|
|
return inferType(t)->Expression::implicitCastTo(sc, t);
|
|
}
|
|
|
|
/*******************************************
|
|
* 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;
|
|
}
|
|
Expression *e = optimize(WANTvalue | WANTflags);
|
|
if (e->type == t)
|
|
return MATCHexact;
|
|
if (e != this)
|
|
{ //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars());
|
|
return e->implicitConvTo(t);
|
|
}
|
|
MATCH match = type->implicitConvTo(t);
|
|
if (match != MATCHnomatch)
|
|
return match;
|
|
|
|
/* See if we can do integral narrowing conversions
|
|
*/
|
|
if (type->isintegral() && t->isintegral() &&
|
|
type->isTypeBasic() && t->isTypeBasic())
|
|
{ IntRange src = this->getIntRange() DUMP;
|
|
IntRange targetUnsigned = IntRange::fromType(t, /*isUnsigned*/true) DUMP;
|
|
IntRange targetSigned = IntRange::fromType(t, /*isUnsigned*/false) DUMP;
|
|
if (targetUnsigned.contains(src) || targetSigned.contains(src))
|
|
return MATCHconvert;
|
|
}
|
|
|
|
#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
|
|
MATCH m = type->implicitConvTo(t);
|
|
if (m >= MATCHconst)
|
|
return m;
|
|
|
|
TY ty = type->toBasetype()->ty;
|
|
TY toty = t->toBasetype()->ty;
|
|
TY oldty = ty;
|
|
|
|
if (m == MATCHnomatch && t->ty == Tenum)
|
|
goto Lno;
|
|
|
|
if (t->ty == Tvector)
|
|
{ TypeVector *tv = (TypeVector *)t;
|
|
TypeBasic *tb = tv->elementType();
|
|
toty = tb->ty;
|
|
}
|
|
|
|
switch (ty)
|
|
{
|
|
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 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_longdouble f;
|
|
if (type->isunsigned())
|
|
{
|
|
f = ldouble(value);
|
|
if (f != value) // isn't this a noop, because the compiler prefers ld
|
|
goto Lno;
|
|
}
|
|
else
|
|
{
|
|
f = ldouble((long long)value);
|
|
if (f != (long long)value)
|
|
goto Lno;
|
|
}
|
|
goto Lyes;
|
|
}
|
|
|
|
case Tpointer:
|
|
//printf("type = %s\n", type->toBasetype()->toChars());
|
|
//printf("t = %s\n", t->toBasetype()->toChars());
|
|
if (ty == Tpointer &&
|
|
type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty)
|
|
{ /* Allow things like:
|
|
* const char* P = cast(char *)3;
|
|
* char* q = P;
|
|
*/
|
|
goto Lyes;
|
|
}
|
|
break;
|
|
}
|
|
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;
|
|
|
|
/* Allow implicit conversions from immutable to mutable|const,
|
|
* and mutable to immutable. It works because, after all, a null
|
|
* doesn't actually point to anything.
|
|
*/
|
|
if (t->invariantOf()->equals(type->invariantOf()))
|
|
return MATCHconst;
|
|
|
|
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;
|
|
te = te->castMod(t->mod);
|
|
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->nextOf()->ty == Tvoid)
|
|
{
|
|
return MATCHnomatch;
|
|
}
|
|
if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer)
|
|
{
|
|
TY tyn = type->nextOf()->ty;
|
|
if (tyn == Tchar || tyn == Twchar || tyn == Tdchar)
|
|
{ Type *tn;
|
|
MATCH m;
|
|
|
|
switch (t->ty)
|
|
{
|
|
case Tsarray:
|
|
if (type->ty == Tsarray)
|
|
{
|
|
if (((TypeSArray *)type)->dim->toInteger() !=
|
|
((TypeSArray *)t)->dim->toInteger())
|
|
return MATCHnomatch;
|
|
TY tynto = t->nextOf()->ty;
|
|
if (tynto == tyn)
|
|
return MATCHexact;
|
|
if (!committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
|
|
return MATCHexact;
|
|
}
|
|
else if (type->ty == Tarray)
|
|
{
|
|
if (length() >
|
|
((TypeSArray *)t)->dim->toInteger())
|
|
return MATCHnomatch;
|
|
TY tynto = t->nextOf()->ty;
|
|
if (tynto == tyn)
|
|
return MATCHexact;
|
|
if (!committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
|
|
return MATCHexact;
|
|
}
|
|
case Tarray:
|
|
case Tpointer:
|
|
tn = t->nextOf();
|
|
m = MATCHexact;
|
|
if (type->nextOf()->mod != tn->mod)
|
|
{ if (!tn->isConst())
|
|
return MATCHnomatch;
|
|
m = MATCHconst;
|
|
}
|
|
if (!committed)
|
|
{
|
|
switch (tn->ty)
|
|
{
|
|
case Tchar:
|
|
return (postfix != 'w' && postfix != 'd' ? m : MATCHconvert);
|
|
case Twchar:
|
|
return (postfix == 'w' ? m : MATCHconvert);
|
|
case Tdchar:
|
|
return (postfix == 'd' ? m : MATCHconvert);
|
|
}
|
|
}
|
|
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))
|
|
{
|
|
Type *typen = typeb->nextOf()->toBasetype();
|
|
|
|
if (tb->ty == Tsarray)
|
|
{ TypeSArray *tsa = (TypeSArray *)tb;
|
|
if (elements->dim != tsa->dim->toInteger())
|
|
result = MATCHnomatch;
|
|
}
|
|
|
|
Type *telement = tb->nextOf();
|
|
if (!elements->dim)
|
|
{ if (typen->ty != Tvoid)
|
|
result = typen->implicitConvTo(telement);
|
|
}
|
|
else
|
|
{ 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;
|
|
}
|
|
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;
|
|
}
|
|
else
|
|
return Expression::implicitConvTo(t);
|
|
}
|
|
|
|
MATCH AssocArrayLiteralExp::implicitConvTo(Type *t)
|
|
{
|
|
Type *typeb = type->toBasetype();
|
|
Type *tb = t->toBasetype();
|
|
if (tb->ty == Taarray && typeb->ty == Taarray)
|
|
{
|
|
MATCH result = MATCHexact;
|
|
for (size_t i = 0; i < keys->dim; i++)
|
|
{ Expression *e = (*keys)[i];
|
|
MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index);
|
|
if (m < result)
|
|
result = m; // remember worst match
|
|
if (result == MATCHnomatch)
|
|
break; // no need to check for worse
|
|
e = (*values)[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 CallExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("CalLExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
|
|
MATCH m = Expression::implicitConvTo(t);
|
|
if (m)
|
|
return m;
|
|
|
|
/* Allow the result of strongly pure functions to
|
|
* convert to immutable
|
|
*/
|
|
if (f && f->isPure() == PUREstrong && !f->type->hasWild())
|
|
return type->invariantOf()->implicitConvTo(t);
|
|
|
|
return MATCHnomatch;
|
|
}
|
|
|
|
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.
|
|
|
|
t = t->toBasetype();
|
|
|
|
if (e1->op == TOKoverloadset &&
|
|
(t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
|
|
{ OverExp *eo = (OverExp *)e1;
|
|
FuncDeclaration *f = NULL;
|
|
for (size_t i = 0; i < eo->vars->a.dim; i++)
|
|
{ Dsymbol *s = eo->vars->a[i];
|
|
FuncDeclaration *f2 = s->isFuncDeclaration();
|
|
assert(f2);
|
|
if (f2->overloadExactMatch(t->nextOf(), m))
|
|
{ if (f)
|
|
/* Error if match in more than one overload set,
|
|
* even if one is a 'better' match than the other.
|
|
*/
|
|
ScopeDsymbol::multiplyDefined(loc, f, f2);
|
|
else
|
|
f = f2;
|
|
result = MATCHexact;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
|
|
t->ty == Tpointer && t->nextOf()->ty == Tfunction &&
|
|
e1->op == TOKvar)
|
|
{
|
|
#if !IN_LLVM
|
|
/* I don't think this can ever happen -
|
|
* it should have been
|
|
* converted to a SymOffExp.
|
|
*/
|
|
assert(0);
|
|
#endif
|
|
VarExp *ve = (VarExp *)e1;
|
|
FuncDeclaration *f = ve->var->isFuncDeclaration();
|
|
if (f && f->overloadExactMatch(t->nextOf(), 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->nextOf()->ty == Tfunction &&
|
|
(t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
|
|
{
|
|
f = var->isFuncDeclaration();
|
|
if (f)
|
|
{ f = f->overloadExactMatch(t->nextOf(), m);
|
|
if (f)
|
|
{ if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) ||
|
|
(t->ty == Tpointer && !(f->needThis() || f->isNested())))
|
|
{
|
|
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 == MATCHnomatch)
|
|
{
|
|
// Look for pointers to functions where the functions are overloaded.
|
|
|
|
t = t->toBasetype();
|
|
if (type->ty == Tdelegate &&
|
|
t->ty == Tdelegate)
|
|
{
|
|
if (func && func->overloadExactMatch(t->nextOf(), m))
|
|
result = MATCHexact;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
MATCH FuncExp::implicitConvTo(Type *t)
|
|
{
|
|
//printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars());
|
|
Expression *e = inferType(t, 1);
|
|
if (e &&
|
|
(t->ty == Tdelegate ||
|
|
t->ty == Tpointer && t->nextOf()->ty == Tfunction))
|
|
{
|
|
if (e != this)
|
|
return e->implicitConvTo(t);
|
|
|
|
/* MATCHconst: Conversion from implicit to explicit function pointer
|
|
* MATCHconvert: Conversion from impliict funciton pointer to delegate
|
|
*/
|
|
if (fd->tok == TOKreserved && // fbody doesn't have a frame pointer
|
|
(type->equals(t) || type->nextOf()->covariant(t->nextOf()) == 1))
|
|
{
|
|
return t->ty == Tpointer ? MATCHconst : MATCHconvert;
|
|
}
|
|
}
|
|
return Expression::implicitConvTo(t);
|
|
}
|
|
|
|
MATCH OrExp::implicitConvTo(Type *t)
|
|
{
|
|
MATCH result = Expression::implicitConvTo(t);
|
|
|
|
if (result == MATCHnomatch)
|
|
{
|
|
MATCH m1 = e1->implicitConvTo(t);
|
|
MATCH m2 = e2->implicitConvTo(t);
|
|
|
|
// Pick the worst match
|
|
result = (m1 < m2) ? m1 : m2;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
MATCH XorExp::implicitConvTo(Type *t)
|
|
{
|
|
MATCH result = Expression::implicitConvTo(t);
|
|
|
|
if (result == MATCHnomatch)
|
|
{
|
|
MATCH m1 = e1->implicitConvTo(t);
|
|
MATCH m2 = e2->implicitConvTo(t);
|
|
|
|
// Pick the worst match
|
|
result = (m1 < m2) ? m1 : m2;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
MATCH CondExp::implicitConvTo(Type *t)
|
|
{
|
|
MATCH m1 = e1->implicitConvTo(t);
|
|
MATCH m2 = e2->implicitConvTo(t);
|
|
//printf("CondExp: m1 %d m2 %d\n", m1, m2);
|
|
|
|
// Pick the worst match
|
|
return (m1 < m2) ? m1 : m2;
|
|
}
|
|
|
|
MATCH CommaExp::implicitConvTo(Type *t)
|
|
{
|
|
return e2->implicitConvTo(t);
|
|
}
|
|
|
|
MATCH CastExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
MATCH result;
|
|
|
|
result = type->implicitConvTo(t);
|
|
|
|
if (result == MATCHnomatch)
|
|
{
|
|
if (t->isintegral() &&
|
|
e1->type->isintegral() &&
|
|
e1->implicitConvTo(t) != MATCHnomatch)
|
|
result = MATCHconvert;
|
|
else
|
|
result = Expression::implicitConvTo(t);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
MATCH NewExp::implicitConvTo(Type *t)
|
|
{
|
|
#if 0
|
|
printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
|
|
toChars(), type->toChars(), t->toChars());
|
|
#endif
|
|
MATCH match = Expression::implicitConvTo(t);
|
|
if (match != MATCHnomatch)
|
|
return match;
|
|
|
|
/* The return from new() is special in that it might be a unique pointer.
|
|
* If we can prove it is, allow the following implicit conversions:
|
|
* mutable => immutable
|
|
* non-shared => shared
|
|
* shared => non-shared
|
|
*/
|
|
|
|
Type *typeb = type->toBasetype();
|
|
Type *tb = t->toBasetype();
|
|
|
|
if (tb->ty == Tclass)
|
|
{
|
|
//printf("%s => %s\n", type->castMod(0)->toChars(), t->castMod(0)->toChars());
|
|
match = type->castMod(0)->implicitConvTo(t->castMod(0));
|
|
if (!match)
|
|
goto Lnomatch;
|
|
|
|
// Regardless, don't allow immutable to be implicitly converted to mutable
|
|
if (tb->isMutable() && !typeb->isMutable())
|
|
goto Lnomatch;
|
|
|
|
// All the fields must be convertible as well
|
|
ClassDeclaration *cd = ((TypeClass *)tb)->sym;
|
|
|
|
cd->size(loc); // resolve any forward references
|
|
|
|
/* The following is excessively conservative, but be very
|
|
* careful in loosening them up.
|
|
*/
|
|
if (cd->isNested() ||
|
|
cd->isInterfaceDeclaration() ||
|
|
cd->ctor ||
|
|
cd->baseClass != ClassDeclaration::object)
|
|
goto Lnomatch;
|
|
|
|
for (size_t i = 0; i < cd->fields.dim; i++)
|
|
{ Dsymbol *sm = cd->fields[i];
|
|
Declaration *d = sm->isDeclaration();
|
|
if (d->storage_class & STCref || d->hasPointers())
|
|
goto Lnomatch;
|
|
}
|
|
return (match == MATCHexact) ? MATCHconst : match;
|
|
}
|
|
else if ((tb->ty == Tpointer || tb->ty == Tarray) &&
|
|
(typeb->ty == Tpointer || typeb->ty == Tarray))
|
|
{
|
|
Type *typen = type->nextOf()->toBasetype();
|
|
Type *tn = tb->nextOf()->toBasetype();
|
|
|
|
//printf("%s => %s\n", typen->castMod(0)->toChars(), tn->castMod(0)->toChars());
|
|
{
|
|
/* Determine if the match failure was solely due to a difference
|
|
* in the mod bits, by rebuilding type and t without mod bits and
|
|
* retrying the implicit conversion.
|
|
*/
|
|
Type *tn2 = tn->castMod(0); // cast off mod bits
|
|
Type *typen2 = typen->castMod(0);
|
|
Type *t2 = (tb->ty == Tpointer) ? tn2->pointerTo() : tn2->arrayOf();
|
|
Type *type2 = (typeb->ty == Tpointer) ? typen2->pointerTo() : typen2->arrayOf();
|
|
match = type2->implicitConvTo(t2);
|
|
if (!match)
|
|
goto Lnomatch;
|
|
}
|
|
|
|
// Regardless, don't allow immutable to be implicitly converted to mutable
|
|
if (tn->isMutable() && !typen->isMutable())
|
|
goto Lnomatch;
|
|
|
|
if (tn->isTypeBasic())
|
|
;
|
|
else if (tn->ty == Tstruct)
|
|
{
|
|
// All the fields must be convertible as well
|
|
StructDeclaration *sd = ((TypeStruct *)tn)->sym;
|
|
|
|
sd->size(loc); // resolve any forward references
|
|
|
|
/* The following is excessively conservative, but be very
|
|
* careful in loosening them up.
|
|
*/
|
|
|
|
if (sd->isNested() ||
|
|
sd->ctor)
|
|
goto Lnomatch;
|
|
|
|
for (size_t i = 0; i < sd->fields.dim; i++)
|
|
{ Dsymbol *sm = sd->fields[i];
|
|
Declaration *d = sm->isDeclaration();
|
|
if (d->storage_class & STCref || d->hasPointers())
|
|
goto Lnomatch;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* More fruit left on the table, such as pointers to immutable.
|
|
*/
|
|
goto Lnomatch;
|
|
}
|
|
|
|
return (match == MATCHexact) ? MATCHconst : match;
|
|
}
|
|
|
|
Lnomatch:
|
|
return MATCHnomatch;
|
|
}
|
|
|
|
/* ==================== 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)
|
|
{
|
|
#if !IN_LLVM
|
|
// 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);
|
|
}
|
|
else
|
|
#endif
|
|
#if 0
|
|
if (tb->ty == Tdelegate && type->ty != Tdelegate)
|
|
{
|
|
TypeDelegate *td = (TypeDelegate *)tb;
|
|
TypeFunction *tf = (TypeFunction *)td->nextOf();
|
|
return toDelegate(sc, tf->nextOf());
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (typeb->ty == Tstruct)
|
|
{ TypeStruct *ts = (TypeStruct *)typeb;
|
|
if (!(tb->ty == Tstruct && ts->sym == ((TypeStruct *)tb)->sym) &&
|
|
ts->sym->aliasthis)
|
|
{ /* Forward the cast to our alias this member, rewrite to:
|
|
* cast(to)e1.aliasthis
|
|
*/
|
|
Expression *e1 = resolveAliasThis(sc, this);
|
|
Expression *e2 = new CastExp(loc, e1, tb);
|
|
e2 = e2->semantic(sc);
|
|
return e2;
|
|
}
|
|
}
|
|
else if (typeb->ty == Tclass)
|
|
{ TypeClass *ts = (TypeClass *)typeb;
|
|
if (ts->sym->aliasthis)
|
|
{
|
|
if (tb->ty == Tclass)
|
|
{
|
|
ClassDeclaration *cdfrom = typeb->isClassHandle();
|
|
ClassDeclaration *cdto = tb->isClassHandle();
|
|
int offset;
|
|
if (cdto->isBaseOf(cdfrom, &offset))
|
|
goto L1;
|
|
}
|
|
/* Forward the cast to our alias this member, rewrite to:
|
|
* cast(to)e1.aliasthis
|
|
*/
|
|
Expression *e1 = resolveAliasThis(sc, this);
|
|
Expression *e2 = new CastExp(loc, e1, tb);
|
|
e2 = e2->semantic(sc);
|
|
return e2;
|
|
}
|
|
L1: ;
|
|
}
|
|
else if (tb->ty == Tvector && typeb->ty != Tvector)
|
|
{
|
|
//printf("test1 e = %s, e->type = %s, tb = %s\n", e->toChars(), e->type->toChars(), tb->toChars());
|
|
TypeVector *tv = (TypeVector *)tb;
|
|
e = new CastExp(loc, e, tv->elementType());
|
|
e = new VectorExp(loc, e, tb);
|
|
e = e->semantic(sc);
|
|
return e;
|
|
}
|
|
else if (typeb->implicitConvTo(tb) == MATCHconst && t == type->constOf())
|
|
{
|
|
Expression *e = copy();
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
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)
|
|
{
|
|
//printf("NullExp::castTo(t = %p)\n", t);
|
|
if (type == t)
|
|
{
|
|
committed = 1;
|
|
return this;
|
|
}
|
|
|
|
NullExp *e = (NullExp *)copy();
|
|
e->committed = 1;
|
|
Type *tb = t->toBasetype();
|
|
#if 0
|
|
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 (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);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//return e->Expression::castTo(sc, t);
|
|
}
|
|
}
|
|
#else
|
|
if (tb->ty == Tvoid)
|
|
{
|
|
e->type = type->toBasetype();
|
|
return e->Expression::castTo(sc, t);
|
|
}
|
|
#endif
|
|
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 (committed && tb->ty == Tsarray && typeb->ty == Tarray)
|
|
{
|
|
se = (StringExp *)copy();
|
|
d_uns64 szx = tb->nextOf()->size();
|
|
assert(szx <= 255);
|
|
se->sz = (unsigned char)szx;
|
|
se->len = (len * sz) / se->sz;
|
|
se->committed = 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) ((int)(tf) * 256 + (int)(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
|
|
size_t newsz = se->sz;
|
|
size_t d = (dim2 < se->len) ? dim2 : se->len;
|
|
void *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.
|
|
|
|
if (e1->op == TOKoverloadset &&
|
|
(t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
|
|
{ OverExp *eo = (OverExp *)e1;
|
|
FuncDeclaration *f = NULL;
|
|
for (size_t i = 0; i < eo->vars->a.dim; i++)
|
|
{ Dsymbol *s = eo->vars->a[i];
|
|
FuncDeclaration *f2 = s->isFuncDeclaration();
|
|
assert(f2);
|
|
if (f2->overloadExactMatch(t->nextOf(), m))
|
|
{ if (f)
|
|
/* Error if match in more than one overload set,
|
|
* even if one is a 'better' match than the other.
|
|
*/
|
|
ScopeDsymbol::multiplyDefined(loc, f, f2);
|
|
else
|
|
f = f2;
|
|
}
|
|
}
|
|
#if IN_LLVM
|
|
if (f)
|
|
{
|
|
f = f->overloadExactMatch(tb->nextOf(), m);
|
|
if (f)
|
|
{
|
|
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
|
|
{
|
|
e = new VarExp(loc, f);
|
|
e->type = f->type;
|
|
e = new AddrExp(loc, e);
|
|
e->type = t;
|
|
return e;
|
|
}
|
|
#if DMDV2
|
|
f->tookAddressOf++;
|
|
#endif
|
|
return e;
|
|
}
|
|
}
|
|
#else
|
|
if (f)
|
|
{ f->tookAddressOf++;
|
|
SymOffExp *se = new SymOffExp(loc, f, 0, 0);
|
|
se->semantic(sc);
|
|
// Let SymOffExp::castTo() do the heavy lifting
|
|
return se->castTo(sc, t);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (type->ty == Tpointer && type->nextOf()->ty == Tfunction &&
|
|
tb->ty == Tpointer && tb->nextOf()->ty == Tfunction &&
|
|
e1->op == TOKvar)
|
|
{
|
|
VarExp *ve = (VarExp *)e1;
|
|
FuncDeclaration *f = ve->var->isFuncDeclaration();
|
|
if (f)
|
|
{
|
|
#if !IN_LLVM
|
|
assert(0); // should be SymOffExp instead
|
|
#endif
|
|
f = f->overloadExactMatch(tb->nextOf(), 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);
|
|
}
|
|
#if IN_LLVM
|
|
else if (e1->op == TOKvar)
|
|
{
|
|
VarExp *ve = (VarExp*)e1->copy();
|
|
ve->hasOverloads = 0;
|
|
e1 = ve;
|
|
}
|
|
#endif
|
|
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 = (*e->exps)[i];
|
|
ex = ex->castTo(sc, t);
|
|
(*e->exps)[i] = 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)
|
|
{
|
|
Type *tp = typeb->nextOf()->pointerTo();
|
|
if (!tp->equals(e->type))
|
|
{ e = (ArrayLiteralExp *)copy();
|
|
e->type = tp;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
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 = (*values)[i];
|
|
ex = ex->castTo(sc, tb->nextOf());
|
|
(*e->values)[i] = ex;
|
|
|
|
ex = (*keys)[i];
|
|
ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
|
|
(*e->keys)[i] = 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
|
|
if (type == t && hasOverloads == 0)
|
|
return this;
|
|
Expression *e;
|
|
Type *tb = t->toBasetype();
|
|
Type *typeb = type->toBasetype();
|
|
if (tb != typeb)
|
|
{
|
|
// Look for pointers to functions where the functions are overloaded.
|
|
FuncDeclaration *f;
|
|
|
|
if (hasOverloads &&
|
|
typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction &&
|
|
(tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction)
|
|
{
|
|
f = var->isFuncDeclaration();
|
|
if (f)
|
|
{
|
|
f = f->overloadExactMatch(tb->nextOf(), m);
|
|
if (f)
|
|
{
|
|
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
|
|
{
|
|
e = new SymOffExp(loc, f, 0);
|
|
e->type = t;
|
|
}
|
|
#if DMDV2
|
|
f->tookAddressOf++;
|
|
#endif
|
|
return e;
|
|
}
|
|
}
|
|
}
|
|
e = Expression::castTo(sc, t);
|
|
}
|
|
else
|
|
{ e = copy();
|
|
e->type = t;
|
|
((SymOffExp *)e)->hasOverloads = 0;
|
|
}
|
|
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 *typeb = type->toBasetype();
|
|
if (tb != typeb || hasOverloads)
|
|
{
|
|
// Look for delegates to functions where the functions are overloaded.
|
|
FuncDeclaration *f;
|
|
|
|
if (typeb->ty == Tdelegate &&
|
|
tb->ty == Tdelegate)
|
|
{
|
|
if (func)
|
|
{
|
|
f = func->overloadExactMatch(tb->nextOf(), m);
|
|
if (f)
|
|
{ int offset;
|
|
if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset)
|
|
error("%s", msg);
|
|
f->tookAddressOf++;
|
|
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;
|
|
|
|
func->tookAddressOf++;
|
|
if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset)
|
|
error("%s", msg);
|
|
e = copy();
|
|
e->type = t;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
Expression *FuncExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
//printf("FuncExp::castTo type = %s, t = %s\n", type->toChars(), t->toChars());
|
|
Expression *e = inferType(t, 1);
|
|
if (e)
|
|
{
|
|
if (e != this)
|
|
e = e->castTo(sc, t);
|
|
else if (!e->type->equals(t))
|
|
{
|
|
assert(e->type->nextOf()->covariant(t->nextOf()) == 1);
|
|
e = e->copy();
|
|
e->type = t;
|
|
}
|
|
return e;
|
|
}
|
|
return Expression::castTo(sc, t);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
Expression *CommaExp::castTo(Scope *sc, Type *t)
|
|
{
|
|
Expression *e2c = e2->castTo(sc, t);
|
|
Expression *e;
|
|
|
|
if (e2c != e2)
|
|
{
|
|
e = new CommaExp(loc, e1, e2c);
|
|
e->type = e2c->type;
|
|
}
|
|
else
|
|
{ e = this;
|
|
e->type = e2->type;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/* ==================== inferType ====================== */
|
|
|
|
/****************************************
|
|
* Set type inference target
|
|
* flag 1: don't put an error when inference fails
|
|
*/
|
|
|
|
Expression *Expression::inferType(Type *t, int flag, TemplateParameters *tparams)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
Expression *ArrayLiteralExp::inferType(Type *t, int flag, TemplateParameters *tparams)
|
|
{
|
|
if (t)
|
|
{
|
|
t = t->toBasetype();
|
|
if (t->ty == Tarray || t->ty == Tsarray)
|
|
{
|
|
Type *tn = t->nextOf();
|
|
for (size_t i = 0; i < elements->dim; i++)
|
|
{ Expression *e = (*elements)[i];
|
|
if (e)
|
|
{ e = e->inferType(tn, flag, tparams);
|
|
(*elements)[i] = e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Expression *AssocArrayLiteralExp::inferType(Type *t, int flag, TemplateParameters *tparams)
|
|
{
|
|
if (t)
|
|
{
|
|
t = t->toBasetype();
|
|
if (t->ty == Taarray)
|
|
{ TypeAArray *taa = (TypeAArray *)t;
|
|
Type *ti = taa->index;
|
|
Type *tv = taa->nextOf();
|
|
for (size_t i = 0; i < keys->dim; i++)
|
|
{ Expression *e = (*keys)[i];
|
|
if (e)
|
|
{ e = e->inferType(ti, flag, tparams);
|
|
(*keys)[i] = e;
|
|
}
|
|
}
|
|
for (size_t i = 0; i < values->dim; i++)
|
|
{ Expression *e = (*values)[i];
|
|
if (e)
|
|
{ e = e->inferType(tv, flag, tparams);
|
|
(*values)[i] = e;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams)
|
|
{
|
|
if (!to)
|
|
return this;
|
|
|
|
//printf("FuncExp::interType('%s'), to=%s\n", type?type->toChars():"null", to->toChars());
|
|
|
|
if (!type) // semantic is not yet done
|
|
{
|
|
if (to->ty == Tdelegate ||
|
|
to->ty == Tpointer && to->nextOf()->ty == Tfunction)
|
|
{ fd->treq = to;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Expression *e = NULL;
|
|
|
|
Type *t = to;
|
|
if (t->ty == Tdelegate)
|
|
{ if (tok == TOKfunction)
|
|
goto L1;
|
|
t = t->nextOf();
|
|
}
|
|
else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
|
|
{ if (tok == TOKdelegate)
|
|
goto L1;
|
|
t = t->nextOf();
|
|
}
|
|
|
|
if (td)
|
|
{ /// Parameter types inference from
|
|
assert(td->scope);
|
|
if (t->ty == Tfunction)
|
|
{
|
|
TypeFunction *tfv = (TypeFunction *)t;
|
|
TypeFunction *tfl = (TypeFunction *)fd->type;
|
|
//printf("\ttfv = %s\n", tfv->toChars());
|
|
//printf("\ttfl = %s\n", tfl->toChars());
|
|
size_t dim = Parameter::dim(tfl->parameters);
|
|
|
|
if (Parameter::dim(tfv->parameters) == dim &&
|
|
tfv->varargs == tfl->varargs)
|
|
{
|
|
Objects *tiargs = new Objects();
|
|
tiargs->reserve(td->parameters->dim);
|
|
|
|
for (size_t i = 0; i < td->parameters->dim; i++)
|
|
{
|
|
TemplateParameter *tp = (*td->parameters)[i];
|
|
for (size_t u = 0; u < dim; u++)
|
|
{ Parameter *p = Parameter::getNth(tfl->parameters, u);
|
|
if (p->type->ty == Tident &&
|
|
((TypeIdentifier *)p->type)->ident == tp->ident)
|
|
{ p = Parameter::getNth(tfv->parameters, u);
|
|
Type *tprm = p->type;
|
|
if (tprm->reliesOnTident(tparams))
|
|
goto L1;
|
|
tprm = tprm->semantic(loc, td->scope);
|
|
tiargs->push(tprm);
|
|
u = dim; // break inner loop
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set target of return type inference
|
|
assert(td->onemember);
|
|
FuncLiteralDeclaration *fld = td->onemember->isFuncLiteralDeclaration();
|
|
assert(fld);
|
|
if (!fld->type->nextOf() && tfv->next)
|
|
fld->treq = to;
|
|
|
|
TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
|
|
e = (new ScopeExp(loc, ti))->semantic(td->scope);
|
|
|
|
// Reset inference target for the later re-semantic
|
|
fld->treq = NULL;
|
|
|
|
if (e->op == TOKfunction)
|
|
{ FuncExp *fe = (FuncExp *)e;
|
|
assert(fe->td == NULL);
|
|
e = fe->inferType(to, flag);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (type)
|
|
{
|
|
assert(type != Type::tvoid); // semantic is already done
|
|
|
|
// Allow conversion from implicit function pointer to delegate
|
|
if (tok == TOKreserved && type->ty == Tpointer &&
|
|
to->ty == Tdelegate)
|
|
{
|
|
Type *typen = type->nextOf();
|
|
if (typen->deco)
|
|
{
|
|
FuncExp *fe = (FuncExp *)copy();
|
|
fe->tok = TOKdelegate;
|
|
fe->type = (new TypeDelegate(typen))->merge();
|
|
e = fe;
|
|
}
|
|
}
|
|
else
|
|
e = this;
|
|
}
|
|
L1:
|
|
if (!flag && !e)
|
|
{ error("cannot infer function literal type from %s", to->toChars());
|
|
e = new ErrorExp();
|
|
}
|
|
return e;
|
|
}
|
|
|
|
Expression *CondExp::inferType(Type *t, int flag, TemplateParameters *tparams)
|
|
{
|
|
if (t)
|
|
{
|
|
t = t->toBasetype();
|
|
e1 = e1->inferType(t, flag, tparams);
|
|
e2 = e2->inferType(t, flag, tparams);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/* ==================== ====================== */
|
|
|
|
/****************************************
|
|
* Scale addition/subtraction to/from pointer.
|
|
*/
|
|
|
|
Expression *BinExp::scaleFactor(Scope *sc)
|
|
{
|
|
if (sc->func && !sc->intypeof)
|
|
{
|
|
if (sc->func->setUnsafe())
|
|
{
|
|
error("pointer arithmetic not allowed in @safe functions");
|
|
return new ErrorExp();
|
|
}
|
|
}
|
|
|
|
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
|
|
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
|
|
e = new MulExp(loc, e, new IntegerExp(0, stride, t));
|
|
#endif
|
|
e->type = t;
|
|
type = e2->type;
|
|
e1 = e2;
|
|
e2 = e;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**************************************
|
|
* Return true if e is an empty array literal with dimensionality
|
|
* equal to or less than type of other array.
|
|
* [], [[]], [[[]]], etc.
|
|
* I.e., make sure that [1,2] is compatible with [],
|
|
* [[1,2]] is compatible with [[]], etc.
|
|
*/
|
|
bool isVoidArrayLiteral(Expression *e, Type *other)
|
|
{
|
|
while (e->op == TOKarrayliteral && e->type->ty == Tarray
|
|
&& (((ArrayLiteralExp *)e)->elements->dim == 1))
|
|
{
|
|
e = (*((ArrayLiteralExp *)e)->elements)[0];
|
|
if (other->ty == Tsarray || other->ty == Tarray)
|
|
other = other->nextOf();
|
|
else
|
|
return false;
|
|
}
|
|
if (other->ty != Tsarray && other->ty != Tarray)
|
|
return false;
|
|
Type *t = e->type;
|
|
return (e->op == TOKarrayliteral && t->ty == Tarray &&
|
|
t->nextOf()->ty == Tvoid &&
|
|
((ArrayLiteralExp *)e)->elements->dim == 0);
|
|
}
|
|
|
|
|
|
/**************************************
|
|
* Combine types.
|
|
* Output:
|
|
* *pt merged type, if *pt is not NULL
|
|
* *pe1 rewritten e1
|
|
* *pe2 rewritten e2
|
|
* Returns:
|
|
* !=0 success
|
|
* 0 failed
|
|
*/
|
|
|
|
int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2)
|
|
{
|
|
//printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars());
|
|
//e->dump(0);
|
|
|
|
MATCH m;
|
|
Expression *e1 = *pe1;
|
|
Expression *e2 = *pe2;
|
|
|
|
if (e->op != TOKquestion ||
|
|
e1->type->toBasetype()->ty != e2->type->toBasetype()->ty)
|
|
{
|
|
e1 = e1->integralPromotions(sc);
|
|
e2 = e2->integralPromotions(sc);
|
|
}
|
|
|
|
Type *t1 = e1->type;
|
|
Type *t2 = e2->type;
|
|
assert(t1);
|
|
Type *t = 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);
|
|
|
|
Lagain:
|
|
Type *t1b = t1->toBasetype();
|
|
Type *t2b = t2->toBasetype();
|
|
|
|
TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty];
|
|
if (ty != Terror)
|
|
{
|
|
TY ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty];
|
|
TY ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty];
|
|
|
|
if (t1b->ty == ty1) // if no promotions
|
|
{
|
|
if (t1 == t2)
|
|
{
|
|
t = t1;
|
|
goto Lret;
|
|
}
|
|
|
|
if (t1b == t2b)
|
|
{
|
|
t = t1b;
|
|
goto Lret;
|
|
}
|
|
}
|
|
|
|
t = Type::basic[ty];
|
|
|
|
t1 = Type::basic[ty1];
|
|
t2 = Type::basic[ty2];
|
|
e1 = e1->castTo(sc, t1);
|
|
e2 = e2->castTo(sc, t2);
|
|
//printf("after typeCombine():\n");
|
|
//dump(0);
|
|
//printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
|
|
goto Lret;
|
|
}
|
|
|
|
t1 = t1b;
|
|
t2 = t2b;
|
|
|
|
if (t1 == t2)
|
|
{
|
|
}
|
|
else if ((t1->ty == Tpointer && t2->ty == Tpointer) ||
|
|
(t1->ty == Tdelegate && t2->ty == Tdelegate))
|
|
{
|
|
// Bring pointers to compatible type
|
|
Type *t1n = t1->nextOf();
|
|
Type *t2n = t2->nextOf();
|
|
|
|
if (t1n == t2n)
|
|
;
|
|
#if IN_LLVM
|
|
else if (t1n->equals(t2n))
|
|
;
|
|
#endif
|
|
else if (t1n->ty == Tvoid) // pointers to void are always compatible
|
|
t = t2;
|
|
else if (t2n->ty == Tvoid)
|
|
;
|
|
else if (t1->implicitConvTo(t2))
|
|
{
|
|
goto Lt2;
|
|
}
|
|
else if (t2->implicitConvTo(t1))
|
|
{
|
|
goto Lt1;
|
|
}
|
|
else if (t1n->ty == Tfunction && t2n->ty == Tfunction)
|
|
{
|
|
TypeFunction *tf1 = (TypeFunction *)t1n;
|
|
TypeFunction *tf2 = (TypeFunction *)t2n;
|
|
TypeFunction *d = (TypeFunction *)tf1->syntaxCopy();
|
|
|
|
if (tf1->purity != tf2->purity)
|
|
d->purity = PUREimpure;
|
|
assert(d->purity != PUREfwdref);
|
|
|
|
d->isnothrow = (tf1->isnothrow && tf2->isnothrow);
|
|
|
|
if (tf1->trust == tf2->trust)
|
|
d->trust = tf1->trust;
|
|
else if (tf1->trust <= TRUSTsystem || tf2->trust <= TRUSTsystem)
|
|
d->trust = TRUSTsystem;
|
|
else
|
|
d->trust = TRUSTtrusted;
|
|
|
|
Type *tx = NULL;
|
|
if (t1->ty == Tdelegate)
|
|
{
|
|
tx = new TypeDelegate(d);
|
|
tx = tx->merge();
|
|
}
|
|
else
|
|
tx = d->pointerTo();
|
|
|
|
if (t1->implicitConvTo(tx) && t2->implicitConvTo(tx))
|
|
{
|
|
t = tx;
|
|
e1 = e1->castTo(sc, t);
|
|
e2 = e2->castTo(sc, t);
|
|
goto Lret;
|
|
}
|
|
goto Lincompatible;
|
|
}
|
|
else if (t1n->mod != t2n->mod)
|
|
{
|
|
if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared())
|
|
goto Lincompatible;
|
|
unsigned char mod = MODmerge(t1n->mod, t2n->mod);
|
|
t1 = t1n->castMod(mod)->pointerTo();
|
|
t2 = t2n->castMod(mod)->pointerTo();
|
|
t = t1;
|
|
goto Lagain;
|
|
}
|
|
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
|
|
{
|
|
t1 = t1n->constOf()->pointerTo();
|
|
t2 = t2n->constOf()->pointerTo();
|
|
if (t1->implicitConvTo(t2))
|
|
{
|
|
goto Lt2;
|
|
}
|
|
else if (t2->implicitConvTo(t1))
|
|
{
|
|
goto Lt1;
|
|
}
|
|
goto Lincompatible;
|
|
}
|
|
}
|
|
else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
|
|
(e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid ||
|
|
// if e2 is void[]
|
|
e2->op == TOKarrayliteral && t2->ty == Tsarray && t2->nextOf()->ty == Tvoid && ((TypeSArray *)t2)->dim->toInteger() == 0 ||
|
|
isVoidArrayLiteral(e2, t1))
|
|
)
|
|
{ /* (T[n] op void*) => T[]
|
|
* (T[] op void*) => T[]
|
|
* (T[n] op void[0]) => T[]
|
|
* (T[] op void[0]) => T[]
|
|
* (T[n] op void[]) => T[]
|
|
* (T[] op void[]) => T[]
|
|
*/
|
|
goto Lx1;
|
|
}
|
|
else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
|
|
(e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid ||
|
|
e1->op == TOKarrayliteral && t1->ty == Tsarray && t1->nextOf()->ty == Tvoid && ((TypeSArray *)t1)->dim->toInteger() == 0 ||
|
|
isVoidArrayLiteral(e1, t2))
|
|
)
|
|
{ /* (void* op T[n]) => T[]
|
|
* (void* op T[]) => T[]
|
|
* (void[0] op T[n]) => T[]
|
|
* (void[0] op T[]) => T[]
|
|
* (void[] op T[n]) => T[]
|
|
* (void[] op T[]) => T[]
|
|
*/
|
|
goto Lx2;
|
|
}
|
|
else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
|
|
(m = t1->implicitConvTo(t2)) != MATCHnomatch)
|
|
{
|
|
if (t1->ty == Tsarray && e2->op == TOKarrayliteral)
|
|
goto Lt1;
|
|
if (m == MATCHconst &&
|
|
(e->op == TOKaddass || e->op == TOKminass || e->op == TOKmulass ||
|
|
e->op == TOKdivass || e->op == TOKmodass || e->op == TOKpowass ||
|
|
e->op == TOKandass || e->op == TOKorass || e->op == TOKxorass)
|
|
)
|
|
{ // Don't make the lvalue const
|
|
t = t2;
|
|
goto Lret;
|
|
}
|
|
goto Lt2;
|
|
}
|
|
else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
|
|
{
|
|
if (t2->ty == Tsarray && e1->op == TOKarrayliteral)
|
|
goto Lt2;
|
|
goto Lt1;
|
|
}
|
|
/* If one is mutable and the other invariant, then retry
|
|
* with both of them as const
|
|
*/
|
|
else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) &&
|
|
(t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) &&
|
|
t1->nextOf()->mod != t2->nextOf()->mod
|
|
)
|
|
{
|
|
Type *t1n = t1->nextOf();
|
|
Type *t2n = t2->nextOf();
|
|
unsigned char mod;
|
|
if (e1->op == TOKnull && e2->op != TOKnull)
|
|
mod = t2n->mod;
|
|
else if (e1->op != TOKnull && e2->op == TOKnull)
|
|
mod = t1n->mod;
|
|
else if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared())
|
|
goto Lincompatible;
|
|
else
|
|
mod = MODmerge(t1n->mod, t2n->mod);
|
|
|
|
if (t1->ty == Tpointer)
|
|
t1 = t1n->castMod(mod)->pointerTo();
|
|
else
|
|
t1 = t1n->castMod(mod)->arrayOf();
|
|
|
|
if (t2->ty == Tpointer)
|
|
t2 = t2n->castMod(mod)->pointerTo();
|
|
else
|
|
t2 = t2n->castMod(mod)->arrayOf();
|
|
t = t1;
|
|
goto Lagain;
|
|
}
|
|
else if (t1->ty == Tclass && t2->ty == Tclass)
|
|
{
|
|
if (t1->mod != t2->mod)
|
|
{
|
|
unsigned char mod;
|
|
if (e1->op == TOKnull && e2->op != TOKnull)
|
|
mod = t2->mod;
|
|
else if (e1->op != TOKnull && e2->op == TOKnull)
|
|
mod = t1->mod;
|
|
else if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
|
|
goto Lincompatible;
|
|
else
|
|
mod = MODmerge(t1->mod, t2->mod);
|
|
t1 = t1->castMod(mod);
|
|
t2 = t2->castMod(mod);
|
|
t = t1;
|
|
goto Lagain;
|
|
}
|
|
goto Lcc;
|
|
}
|
|
else if (t1->ty == Tclass || t2->ty == Tclass)
|
|
{
|
|
Lcc:
|
|
while (1)
|
|
{
|
|
MATCH i1 = e2->implicitConvTo(t1);
|
|
MATCH i2 = e1->implicitConvTo(t2);
|
|
|
|
if (i1 && i2)
|
|
{
|
|
// We have the case of class vs. void*, so pick class
|
|
if (t1->ty == Tpointer)
|
|
i1 = MATCHnomatch;
|
|
else if (t2->ty == Tpointer)
|
|
i2 = MATCHnomatch;
|
|
}
|
|
|
|
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 if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
|
|
{
|
|
e1 = resolveAliasThis(sc, e1);
|
|
t1 = e1->type;
|
|
continue;
|
|
}
|
|
else if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
|
|
{
|
|
e2 = resolveAliasThis(sc, e2);
|
|
t2 = e2->type;
|
|
continue;
|
|
}
|
|
else
|
|
goto Lincompatible;
|
|
}
|
|
}
|
|
else if (t1->ty == Tstruct && t2->ty == Tstruct)
|
|
{
|
|
if (t1->mod != t2->mod)
|
|
{
|
|
if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
|
|
goto Lincompatible;
|
|
unsigned char mod = MODmerge(t1->mod, t2->mod);
|
|
t1 = t1->castMod(mod);
|
|
t2 = t2->castMod(mod);
|
|
t = t1;
|
|
goto Lagain;
|
|
}
|
|
|
|
TypeStruct *ts1 = (TypeStruct *)t1;
|
|
TypeStruct *ts2 = (TypeStruct *)t2;
|
|
if (ts1->sym != ts2->sym)
|
|
{
|
|
if (!ts1->sym->aliasthis && !ts2->sym->aliasthis)
|
|
goto Lincompatible;
|
|
|
|
MATCH i1 = MATCHnomatch;
|
|
MATCH i2 = MATCHnomatch;
|
|
|
|
Expression *e1b = NULL;
|
|
Expression *e2b = NULL;
|
|
if (ts2->sym->aliasthis)
|
|
{
|
|
e2b = resolveAliasThis(sc, e2);
|
|
i1 = e2b->implicitConvTo(t1);
|
|
}
|
|
if (ts1->sym->aliasthis)
|
|
{
|
|
e1b = resolveAliasThis(sc, e1);
|
|
i2 = e1b->implicitConvTo(t2);
|
|
}
|
|
if (i1 && i2)
|
|
goto Lincompatible;
|
|
|
|
if (i1)
|
|
goto Lt1;
|
|
else if (i2)
|
|
goto Lt2;
|
|
|
|
if (e1b)
|
|
{ e1 = e1b;
|
|
t1 = e1b->type->toBasetype();
|
|
}
|
|
if (e2b)
|
|
{ e2 = e2b;
|
|
t2 = e2b->type->toBasetype();
|
|
}
|
|
t = t1;
|
|
goto Lagain;
|
|
}
|
|
}
|
|
else if (t1->ty == Tstruct || t2->ty == Tstruct)
|
|
{
|
|
if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
|
|
{
|
|
e1 = resolveAliasThis(sc, e1);
|
|
t1 = e1->type;
|
|
t = t1;
|
|
goto Lagain;
|
|
}
|
|
if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
|
|
{
|
|
e2 = resolveAliasThis(sc, e2);
|
|
t2 = e2->type;
|
|
t = t2;
|
|
goto Lagain;
|
|
}
|
|
goto Lincompatible;
|
|
}
|
|
else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
|
|
{
|
|
goto Lt2;
|
|
}
|
|
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(); // T[]
|
|
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->ty == Tvector && t2->ty != Tvector &&
|
|
e2->implicitConvTo(t1))
|
|
{
|
|
e2 = e2->castTo(sc, t1);
|
|
t2 = t1;
|
|
goto Lagain;
|
|
}
|
|
else if (t2->ty == Tvector && t1->ty != Tvector &&
|
|
e1->implicitConvTo(t2))
|
|
{
|
|
e1 = e1->castTo(sc, t2);
|
|
t1 = t2;
|
|
goto Lagain;
|
|
}
|
|
else if (t1->isintegral() && t2->isintegral())
|
|
{
|
|
assert(t1->ty == t2->ty);
|
|
if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
|
|
goto Lincompatible;
|
|
unsigned char mod = MODmerge(t1->mod, t2->mod);
|
|
|
|
t1 = t1->castMod(mod);
|
|
t2 = t2->castMod(mod);
|
|
t = t1;
|
|
e1 = e1->castTo(sc, t);
|
|
e2 = e2->castTo(sc, t);
|
|
goto Lagain;
|
|
}
|
|
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 (e && e->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:
|
|
return 0;
|
|
}
|
|
Lret:
|
|
if (!*pt)
|
|
*pt = t;
|
|
*pe1 = e1;
|
|
*pe2 = e2;
|
|
#if 0
|
|
printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars());
|
|
if (e1->type) printf("\tt1 = %s\n", e1->type->toChars());
|
|
if (e2->type) printf("\tt2 = %s\n", e2->type->toChars());
|
|
printf("\ttype = %s\n", t->toChars());
|
|
#endif
|
|
//dump(0);
|
|
return 1;
|
|
|
|
|
|
Lt1:
|
|
e2 = e2->castTo(sc, t1);
|
|
t = t1;
|
|
goto Lret;
|
|
|
|
Lt2:
|
|
e1 = e1->castTo(sc, t2);
|
|
t = t2;
|
|
goto Lret;
|
|
}
|
|
|
|
/************************************
|
|
* Bring leaves to common type.
|
|
*/
|
|
|
|
Expression *BinExp::typeCombine(Scope *sc)
|
|
{
|
|
Type *t1 = e1->type->toBasetype();
|
|
Type *t2 = e2->type->toBasetype();
|
|
|
|
if (op == TOKmin || op == TOKadd)
|
|
{
|
|
// struct+struct, and class+class are errors
|
|
if (t1->ty == Tstruct && t2->ty == Tstruct)
|
|
goto Lerror;
|
|
else if (t1->ty == Tclass && t2->ty == Tclass)
|
|
goto Lerror;
|
|
}
|
|
|
|
if (!typeMerge(sc, this, &type, &e1, &e2))
|
|
goto Lerror;
|
|
return this;
|
|
|
|
Lerror:
|
|
incompatibleTypes();
|
|
type = Type::terror;
|
|
e1 = new ErrorExp();
|
|
e2 = new ErrorExp();
|
|
return new ErrorExp();
|
|
}
|
|
|
|
/***********************************
|
|
* 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 Tbool:
|
|
case Tchar:
|
|
case Twchar:
|
|
e = e->castTo(sc, Type::tint32);
|
|
break;
|
|
|
|
case Tdchar:
|
|
e = e->castTo(sc, Type::tuns32);
|
|
break;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/***********************************
|
|
* See if both types are arrays that can be compared
|
|
* for equality. Return !=0 if so.
|
|
* If they are arrays, but incompatible, issue error.
|
|
* This is to enable comparing things like an immutable
|
|
* array with a mutable one.
|
|
*/
|
|
|
|
int arrayTypeCompatible(Loc loc, Type *t1, Type *t2)
|
|
{
|
|
t1 = t1->toBasetype();
|
|
t2 = t2->toBasetype();
|
|
|
|
if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
|
|
(t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
|
|
{
|
|
if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst &&
|
|
t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst &&
|
|
(t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid))
|
|
{
|
|
error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars());
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***********************************
|
|
* See if both types are arrays that can be compared
|
|
* for equality without any casting. Return !=0 if so.
|
|
* This is to enable comparing things like an immutable
|
|
* array with a mutable one.
|
|
*/
|
|
int arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2)
|
|
{
|
|
t1 = t1->toBasetype();
|
|
t2 = t2->toBasetype();
|
|
|
|
if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
|
|
t2->ty == t1->ty)
|
|
{
|
|
if (t1->nextOf()->implicitConvTo(t2->nextOf()) >= MATCHconst ||
|
|
t2->nextOf()->implicitConvTo(t1->nextOf()) >= MATCHconst)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
|
|
/* Determine the integral ranges of an expression.
|
|
* This is used to determine if implicit narrowing conversions will
|
|
* be allowed.
|
|
*/
|
|
|
|
uinteger_t getMask(uinteger_t v)
|
|
{
|
|
// Ref: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
|
v |= v >> 1;
|
|
v |= v >> 2;
|
|
v |= v >> 4;
|
|
v |= v >> 8;
|
|
v |= v >> 16;
|
|
v |= v >> 32;
|
|
return v /* | 0xff*/;
|
|
}
|
|
IntRange Expression::getIntRange()
|
|
{
|
|
return IntRange::fromType(type) DUMP;
|
|
}
|
|
|
|
IntRange IntegerExp::getIntRange()
|
|
{
|
|
return IntRange(value).cast(type) DUMP;
|
|
}
|
|
|
|
IntRange CastExp::getIntRange()
|
|
{
|
|
return e1->getIntRange().cast(type) DUMP;
|
|
}
|
|
|
|
IntRange AddExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange();
|
|
IntRange ir2 = e2->getIntRange();
|
|
return IntRange(ir1.imin + ir2.imin, ir1.imax + ir2.imax).cast(type) DUMP;
|
|
}
|
|
|
|
IntRange MinExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange();
|
|
IntRange ir2 = e2->getIntRange();
|
|
return IntRange(ir1.imin - ir2.imax, ir1.imax - ir2.imin).cast(type) DUMP;
|
|
}
|
|
|
|
IntRange DivExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange();
|
|
IntRange ir2 = e2->getIntRange();
|
|
|
|
// Should we ignore the possibility of div-by-0???
|
|
if (ir2.containsZero())
|
|
return Expression::getIntRange() DUMP;
|
|
|
|
// [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
|
|
SignExtendedNumber bdy[4] = {
|
|
ir1.imin / ir2.imin,
|
|
ir1.imin / ir2.imax,
|
|
ir1.imax / ir2.imin,
|
|
ir1.imax / ir2.imax
|
|
};
|
|
return IntRange::fromNumbers4(bdy).cast(type) DUMP;
|
|
}
|
|
|
|
IntRange MulExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange();
|
|
IntRange ir2 = e2->getIntRange();
|
|
|
|
// [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
|
|
SignExtendedNumber bdy[4] = {
|
|
ir1.imin * ir2.imin,
|
|
ir1.imin * ir2.imax,
|
|
ir1.imax * ir2.imin,
|
|
ir1.imax * ir2.imax
|
|
};
|
|
return IntRange::fromNumbers4(bdy).cast(type) DUMP;
|
|
}
|
|
|
|
IntRange ModExp::getIntRange()
|
|
{
|
|
IntRange irNum = e1->getIntRange();
|
|
IntRange irDen = e2->getIntRange().absNeg();
|
|
|
|
/*
|
|
due to the rules of D (C)'s % operator, we need to consider the cases
|
|
separately in different range of signs.
|
|
|
|
case 1. [500, 1700] % [7, 23] (numerator is always positive)
|
|
= [0, 22]
|
|
case 2. [-500, 1700] % [7, 23] (numerator can be negative)
|
|
= [-22, 22]
|
|
case 3. [-1700, -500] % [7, 23] (numerator is always negative)
|
|
= [-22, 0]
|
|
|
|
the number 22 is the maximum absolute value in the denomator's range. We
|
|
don't care about divide by zero.
|
|
*/
|
|
|
|
// Modding on 0 is invalid anyway.
|
|
if (!irDen.imin.negative)
|
|
return Expression::getIntRange() DUMP;
|
|
|
|
++ irDen.imin;
|
|
irDen.imax = -irDen.imin;
|
|
|
|
if (!irNum.imin.negative)
|
|
irNum.imin.value = 0;
|
|
else if (irNum.imin < irDen.imin)
|
|
irNum.imin = irDen.imin;
|
|
|
|
if (irNum.imax.negative)
|
|
{
|
|
irNum.imax.negative = false;
|
|
irNum.imax.value = 0;
|
|
}
|
|
else if (irNum.imax > irDen.imax)
|
|
irNum.imax = irDen.imax;
|
|
|
|
return irNum.cast(type) DUMP;
|
|
}
|
|
|
|
// The algorithms for &, |, ^ are not yet the best! Sometimes they will produce
|
|
// not the tightest bound. See
|
|
// https://github.com/D-Programming-Language/dmd/pull/116
|
|
// for detail.
|
|
static IntRange unsignedBitwiseAnd(const IntRange& a, const IntRange& b)
|
|
{
|
|
// the DiffMasks stores the mask of bits which are variable in the range.
|
|
uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
|
|
uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
|
|
// Since '&' computes the digitwise-minimum, the we could set all varying
|
|
// digits to 0 to get a lower bound, and set all varying digits to 1 to get
|
|
// an upper bound.
|
|
IntRange result;
|
|
result.imin.value = (a.imin.value & ~aDiffMask) & (b.imin.value & ~bDiffMask);
|
|
result.imax.value = (a.imax.value | aDiffMask) & (b.imax.value | bDiffMask);
|
|
// Sometimes the upper bound is overestimated. The upper bound will never
|
|
// exceed the input.
|
|
if (result.imax.value > a.imax.value)
|
|
result.imax.value = a.imax.value;
|
|
if (result.imax.value > b.imax.value)
|
|
result.imax.value = b.imax.value;
|
|
result.imin.negative = result.imax.negative = a.imin.negative && b.imin.negative;
|
|
return result;
|
|
}
|
|
static IntRange unsignedBitwiseOr(const IntRange& a, const IntRange& b)
|
|
{
|
|
// the DiffMasks stores the mask of bits which are variable in the range.
|
|
uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
|
|
uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
|
|
// The imax algorithm by Adam D. Ruppe.
|
|
// http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=108796
|
|
IntRange result;
|
|
result.imin.value = (a.imin.value & ~aDiffMask) | (b.imin.value & ~bDiffMask);
|
|
result.imax.value = a.imax.value | b.imax.value | getMask(a.imax.value & b.imax.value);
|
|
// Sometimes the lower bound is underestimated. The lower bound will never
|
|
// less than the input.
|
|
if (result.imin.value < a.imin.value)
|
|
result.imin.value = a.imin.value;
|
|
if (result.imin.value < b.imin.value)
|
|
result.imin.value = b.imin.value;
|
|
result.imin.negative = result.imax.negative = a.imin.negative || b.imin.negative;
|
|
return result;
|
|
}
|
|
static IntRange unsignedBitwiseXor(const IntRange& a, const IntRange& b)
|
|
{
|
|
// the DiffMasks stores the mask of bits which are variable in the range.
|
|
uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
|
|
uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
|
|
IntRange result;
|
|
result.imin.value = (a.imin.value ^ b.imin.value) & ~(aDiffMask | bDiffMask);
|
|
result.imax.value = (a.imax.value ^ b.imax.value) | (aDiffMask | bDiffMask);
|
|
result.imin.negative = result.imax.negative = a.imin.negative != b.imin.negative;
|
|
return result;
|
|
}
|
|
|
|
|
|
IntRange AndExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange();
|
|
IntRange ir2 = e2->getIntRange();
|
|
|
|
IntRange ir1neg, ir1pos, ir2neg, ir2pos;
|
|
bool has1neg, has1pos, has2neg, has2pos;
|
|
|
|
ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
|
|
ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
|
|
|
|
IntRange result;
|
|
bool hasResult = false;
|
|
if (has1pos && has2pos)
|
|
result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2pos), /*ref*/hasResult);
|
|
if (has1pos && has2neg)
|
|
result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2neg), /*ref*/hasResult);
|
|
if (has1neg && has2pos)
|
|
result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2pos), /*ref*/hasResult);
|
|
if (has1neg && has2neg)
|
|
result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2neg), /*ref*/hasResult);
|
|
assert(hasResult);
|
|
return result.cast(type) DUMP;
|
|
}
|
|
|
|
IntRange OrExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange();
|
|
IntRange ir2 = e2->getIntRange();
|
|
|
|
IntRange ir1neg, ir1pos, ir2neg, ir2pos;
|
|
bool has1neg, has1pos, has2neg, has2pos;
|
|
|
|
ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
|
|
ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
|
|
|
|
IntRange result;
|
|
bool hasResult = false;
|
|
if (has1pos && has2pos)
|
|
result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2pos), /*ref*/hasResult);
|
|
if (has1pos && has2neg)
|
|
result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2neg), /*ref*/hasResult);
|
|
if (has1neg && has2pos)
|
|
result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2pos), /*ref*/hasResult);
|
|
if (has1neg && has2neg)
|
|
result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2neg), /*ref*/hasResult);
|
|
|
|
assert(hasResult);
|
|
return result.cast(type) DUMP;
|
|
}
|
|
|
|
IntRange XorExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange();
|
|
IntRange ir2 = e2->getIntRange();
|
|
|
|
IntRange ir1neg, ir1pos, ir2neg, ir2pos;
|
|
bool has1neg, has1pos, has2neg, has2pos;
|
|
|
|
ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
|
|
ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
|
|
|
|
IntRange result;
|
|
bool hasResult = false;
|
|
if (has1pos && has2pos)
|
|
result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2pos), /*ref*/hasResult);
|
|
if (has1pos && has2neg)
|
|
result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2neg), /*ref*/hasResult);
|
|
if (has1neg && has2pos)
|
|
result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2pos), /*ref*/hasResult);
|
|
if (has1neg && has2neg)
|
|
result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2neg), /*ref*/hasResult);
|
|
|
|
assert(hasResult);
|
|
return result.cast(type) DUMP;
|
|
}
|
|
|
|
IntRange ShlExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange();
|
|
IntRange ir2 = e2->getIntRange();
|
|
|
|
if (ir2.imin.negative)
|
|
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
|
|
|
|
SignExtendedNumber lower = ir1.imin << (ir1.imin.negative ? ir2.imax : ir2.imin);
|
|
SignExtendedNumber upper = ir1.imax << (ir1.imax.negative ? ir2.imin : ir2.imax);
|
|
|
|
return IntRange(lower, upper).cast(type) DUMP;
|
|
}
|
|
|
|
IntRange ShrExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange();
|
|
IntRange ir2 = e2->getIntRange();
|
|
|
|
if (ir2.imin.negative)
|
|
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
|
|
|
|
SignExtendedNumber lower = ir1.imin >> (ir1.imin.negative ? ir2.imin : ir2.imax);
|
|
SignExtendedNumber upper = ir1.imax >> (ir1.imax.negative ? ir2.imax : ir2.imin);
|
|
|
|
return IntRange(lower, upper).cast(type) DUMP;
|
|
}
|
|
|
|
IntRange UshrExp::getIntRange()
|
|
{
|
|
IntRange ir1 = e1->getIntRange().castUnsigned(e1->type);
|
|
IntRange ir2 = e2->getIntRange();
|
|
|
|
if (ir2.imin.negative)
|
|
ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
|
|
|
|
return IntRange(ir1.imin >> ir2.imax, ir1.imax >> ir2.imin).cast(type) DUMP;
|
|
|
|
}
|
|
|
|
IntRange CommaExp::getIntRange()
|
|
{
|
|
return e2->getIntRange() DUMP;
|
|
}
|
|
|
|
IntRange ComExp::getIntRange()
|
|
{
|
|
IntRange ir = e1->getIntRange();
|
|
return IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative),
|
|
SignExtendedNumber(~ir.imin.value, !ir.imin.negative)).cast(type) DUMP;
|
|
}
|
|
|
|
IntRange NegExp::getIntRange()
|
|
{
|
|
IntRange ir = e1->getIntRange();
|
|
return IntRange(-ir.imax, -ir.imin).cast(type) DUMP;
|
|
}
|
|
|