Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

2844 lines (2552 sloc) 82.597 kb
// Copyright (c) 1999-2011 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 "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)
{ TY tyfrom = type->toBasetype()->ty;
TY tyto = t->toBasetype()->ty;
#if DMDV1
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 && 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());
//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);
}
/*******************************************
* 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;
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:
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 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 Twchar:
if ((unsigned short)value != value)
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))
{
if (tb->ty == Tsarray)
{ TypeSArray *tsa = (TypeSArray *)tb;
if (elements->dim != tsa->dim->toInteger())
result = MATCHnomatch;
}
for (size_t i = 0; i < elements->dim; i++)
{ Expression *e = (*elements)[i];
MATCH m = (MATCH)e->implicitConvTo(tb->nextOf());
if (m < result)
result = m; // remember worst match
if (result == MATCHnomatch)
break; // no need to check for worse
}
if (!result)
result = type->implicitConvTo(t);
return result;
}
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 = keys->tdata()[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->tdata()[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)
{
if (e != this)
return e->implicitConvTo(t);
/* MATCHconst: Conversion from implicit to explicit function pointer
* MATCHconvert: Conversion from impliict funciton pointer to delegate
*/
if (tok == TOKreserved && type->ty == Tpointer &&
(t->ty == Tpointer || t->ty == Tdelegate))
{
if (type == t)
return MATCHexact;
if (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;
}
/* ==================== 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)
{
e = new VectorExp(loc, e, tb);
e = e->semantic(sc);
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) ((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.
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->tdata()[i];
ex = ex->castTo(sc, t);
e->exps->tdata()[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;
}
}
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->tdata()[i];
ex = ex->castTo(sc, tb->nextOf());
e->values->tdata()[i] = ex;
ex = keys->tdata()[i];
ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
e->keys->tdata()[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);
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
* 2: ldc specific: allow to infer function literal kind (TOKdelegate or TOKfunction)
*/
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)
{ 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;
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
}
}
}
TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
e = (new ScopeExp(loc, ti))->semantic(td->scope);
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();
assert(typen->deco);
//if (typen->covariant(to->nextOf()) == 1)
{
FuncExp *fe = (FuncExp *)copy();
fe->tok = TOKdelegate;
fe->type = (new TypeDelegate(typen))->merge();
e = fe;
//e = fe->Expression::implicitCastTo(sc, to);
}
}
else
e = this;
#if IN_LLVM
if (flag == 2 && e)
{ FuncExp *fe = (FuncExp *)e;
if (fe->fd && fe->fd->tok == TOKreserved)
{
if (fe->type->ty == Tpointer)
{
fe->fd->vthis = NULL;
fe->fd->tok = TOKfunction;
}
else
{
fe->fd->tok = TOKdelegate;
}
}
}
#endif
}
L1:
if (flag != 1 && !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->tdata()[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);
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) && 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;
}
/* 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)
{
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 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;
int i1 = 0;
int i2 = 0;
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;
}
Jump to Line
Something went wrong with that request. Please try again.