ldc/dmd2/cast.c
Tomas Lindquist Olsen b7bea99dbb Merged DMD 2.021 frontend.
Removed generated files from dmd/dmd2 dirs.
2008-12-13 16:14:37 +01:00

1705 lines
38 KiB
C

// Copyright (c) 1999-2008 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>
#if _WIN32 || IN_GCC || IN_LLVM
#include "mem.h"
#else
#include "../root/mem.h"
#endif
#include "expression.h"
#include "mtype.h"
#include "utf.h"
#include "declaration.h"
#include "aggregate.h"
/* ==================== implicitCast ====================== */
/**************************************
* Do an implicit cast.
* Issue error if it can't be done.
*/
Expression *Expression::implicitCastTo(Scope *sc, Type *t)
{
//printf("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 (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("%s: implicit conversion of expression (%s) of type %s to %s can cause loss of data",
loc.toChars(), toChars(), type->toChars(), t->toChars());
}
}
#if DMDV2
if (match == MATCHconst && t == type->constOf())
{
Expression *e = copy();
e->type = t;
return e;
}
#endif
return castTo(sc, t);
}
Expression *e = optimize(WANTflags | WANTvalue);
if (e != this)
return e->implicitCastTo(sc, t);
#if 0
printf("ty = %d\n", type->ty);
print();
type->print();
printf("to:\n");
t->print();
printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco);
//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t);
fflush(stdout);
#endif
if (!t->deco)
{ /* Can happen with:
* enum E { One }
* class A
* { static void fork(EDG dg) { dg(E.One); }
* alias void delegate(E) EDG;
* }
* Should eventually make it work.
*/
error("forward reference to type %s", t->toChars());
}
else if (t->reliesOnTident())
error("forward reference to type %s", t->reliesOnTident()->toChars());
error("cannot implicitly convert expression (%s) of type %s to %s",
toChars(), type->toChars(), t->toChars());
return castTo(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 (!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;
#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;
switch (ty)
{
case Tbit:
case Tbool:
value &= 1;
ty = Tint32;
break;
case Tint8:
value = (signed char)value;
ty = Tint32;
break;
case Tchar:
case Tuns8:
value &= 0xFF;
ty = Tint32;
break;
case Tint16:
value = (short)value;
ty = Tint32;
break;
case Tuns16:
case Twchar:
value &= 0xFFFF;
ty = Tint32;
break;
case Tint32:
value = (int)value;
break;
case Tuns32:
case Tdchar:
value &= 0xFFFFFFFF;
ty = Tuns32;
break;
default:
break;
}
// Only allow conversion if no change in value
switch (toty)
{
case Tbit:
case Tbool:
if ((value & 1) != value)
goto Lno;
goto Lyes;
case Tint8:
if ((signed char)value != value)
goto Lno;
goto Lyes;
case Tchar:
case Tuns8:
//printf("value = %llu %llu\n", (integer_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 long double f;
if (type->isunsigned())
{
f = (long double)value;
if (f != value)
goto Lno;
}
else
{
f = (long double)(long long)value;
if (f != (long long)value)
goto Lno;
}
goto Lyes;
}
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 invariant to mutable|const,
* and mutable to invariant. It works because, after all, a null
* doesn't actually point to anything.
*/
if (t->invariantOf()->equals(type->invariantOf()))
return MATCHconst;
// NULL implicitly converts to any pointer type or dynamic array
if (type->ty == Tpointer && type->nextOf()->ty == Tvoid)
{
if (t->ty == Ttypedef)
t = ((TypeTypedef *)t)->sym->basetype;
if (t->ty == Tpointer || t->ty == Tarray ||
t->ty == Taarray || t->ty == Tclass ||
t->ty == Tdelegate)
return committed ? MATCHconvert : MATCHexact;
}
return Expression::implicitConvTo(t);
}
#if DMDV2
MATCH StructLiteralExp::implicitConvTo(Type *t)
{
#if 0
printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH m = Expression::implicitConvTo(t);
if (m != MATCHnomatch)
return m;
if (type->ty == t->ty && type->ty == Tstruct &&
((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym)
{
m = MATCHconst;
for (int i = 0; i < elements->dim; i++)
{ Expression *e = (Expression *)elements->data[i];
Type *te = e->type;
if (t->mod == 0)
te = te->mutableOf();
else
{ assert(t->mod == MODinvariant);
te = te->invariantOf();
}
MATCH m2 = e->implicitConvTo(te);
//printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2);
if (m2 < m)
m = m2;
}
}
return m;
}
#endif
MATCH StringExp::implicitConvTo(Type *t)
{ MATCH m;
#if 0
printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n",
toChars(), committed, type->toChars(), t->toChars());
#endif
if (!committed)
{
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 == 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;
}
switch (tn->ty)
{
case Tchar:
case Twchar:
case Tdchar:
return m;
}
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 (int i = 0; i < elements->dim; i++)
{ Expression *e = (Expression *)elements->data[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
}
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 = (Expression *)keys->data[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 = (Expression *)values->data[i];
m = (MATCH)e->implicitConvTo(tb->nextOf());
if (m < result)
result = m; // remember worst match
if (result == MATCHnomatch)
break; // no need to check for worse
}
return result;
}
else
return Expression::implicitConvTo(t);
}
MATCH AddrExp::implicitConvTo(Type *t)
{
#if 0
printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
MATCH result;
result = type->implicitConvTo(t);
//printf("\tresult = %d\n", result);
if (result == MATCHnomatch)
{
// Look for pointers to functions where the functions are overloaded.
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 (int i = 0; i < eo->vars->a.dim; i++)
{ Dsymbol *s = (Dsymbol *)eo->vars->a.data[i];
FuncDeclaration *f2 = s->isFuncDeclaration();
assert(f2);
if (f2->overloadExactMatch(t->nextOf()))
{ 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)
{
// LDC: it happens for us
#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()))
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());
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.
FuncDeclaration *f;
t = t->toBasetype();
if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction &&
t->ty == Tdelegate && t->nextOf()->ty == Tfunction)
{
if (func && func->overloadExactMatch(t->nextOf()))
result = MATCHexact;
}
}
return result;
}
MATCH CondExp::implicitConvTo(Type *t)
{
MATCH m1;
MATCH m2;
m1 = e1->implicitConvTo(t);
m2 = e2->implicitConvTo(t);
// Pick the worst match
return (m1 < m2) ? m1 : m2;
}
/* ==================== castTo ====================== */
/**************************************
* Do an explicit cast.
*/
Expression *Expression::castTo(Scope *sc, Type *t)
{
//printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars());
#if 0
printf("Expression::castTo(this=%s, type=%s, t=%s)\n",
toChars(), type->toChars(), t->toChars());
#endif
if (type == t)
return this;
Expression *e = this;
Type *tb = t->toBasetype();
Type *typeb = type->toBasetype();
if (tb != typeb)
{
// Do (type *) cast of (type [dim])
if (tb->ty == Tpointer &&
typeb->ty == Tsarray
)
{
//printf("Converting [dim] to *\n");
if (typeb->size(loc) == 0)
e = new NullExp(loc);
else
e = new AddrExp(loc, e);
}
#if 0
else if (tb->ty == Tdelegate && type->ty != Tdelegate)
{
TypeDelegate *td = (TypeDelegate *)tb;
TypeFunction *tf = (TypeFunction *)td->nextOf();
return toDelegate(sc, tf->nextOf());
}
#endif
else
{
e = new CastExp(loc, e, tb);
}
}
else
{
e = e->copy(); // because of COW for assignment to e->type
}
assert(e != this);
e->type = t;
//printf("Returning: %s\n", e->toChars());
return e;
}
Expression *RealExp::castTo(Scope *sc, Type *t)
{ Expression *e = this;
if (type != t)
{
if ((type->isreal() && t->isreal()) ||
(type->isimaginary() && t->isimaginary())
)
{ e = copy();
e->type = t;
}
else
e = Expression::castTo(sc, t);
}
return e;
}
Expression *ComplexExp::castTo(Scope *sc, Type *t)
{ Expression *e = this;
if (type != t)
{
if (type->iscomplex() && t->iscomplex())
{ e = copy();
e->type = t;
}
else
e = Expression::castTo(sc, t);
}
return e;
}
Expression *NullExp::castTo(Scope *sc, Type *t)
{ NullExp *e;
Type *tb;
//printf("NullExp::castTo(t = %p)\n", t);
if (type == t)
{
committed = 1;
return this;
}
e = (NullExp *)copy();
e->committed = 1;
tb = t->toBasetype();
e->type = type->toBasetype();
if (tb != e->type)
{
// NULL implicitly converts to any pointer type or dynamic array
if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid &&
(tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray ||
tb->ty == Tdelegate))
{
#if 0
if (tb->ty == Tdelegate)
{ TypeDelegate *td = (TypeDelegate *)tb;
TypeFunction *tf = (TypeFunction *)td->nextOf();
if (!tf->varargs &&
!(tf->arguments && tf->arguments->dim)
)
{
return Expression::castTo(sc, t);
}
}
#endif
}
else
{
return e->Expression::castTo(sc, t);
}
}
e->type = t;
return e;
}
Expression *StringExp::castTo(Scope *sc, Type *t)
{
/* This follows copy-on-write; any changes to 'this'
* will result in a copy.
* The this->string member is considered immutable.
*/
StringExp *se;
Type *tb;
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*");
}
se = this;
if (!committed)
{ se = (StringExp *)copy();
se->committed = 1;
copied = 1;
}
if (type == t)
{
return se;
}
tb = t->toBasetype();
//printf("\ttype = %s\n", type->toChars());
if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate)
return Expression::castTo(sc, t);
Type *typeb = type->toBasetype();
if (typeb == tb)
{
if (!copied)
{ se = (StringExp *)copy();
copied = 1;
}
se->type = t;
return se;
}
if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
{ if (!copied)
{ se = (StringExp *)copy();
copied = 1;
}
goto Lcast;
}
if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer)
{ if (!copied)
{ se = (StringExp *)copy();
copied = 1;
}
goto Lcast;
}
if (typeb->nextOf()->size() == tb->nextOf()->size())
{
if (!copied)
{ se = (StringExp *)copy();
copied = 1;
}
if (tb->ty == Tsarray)
goto L2; // handle possible change in static array dimension
se->type = t;
return se;
}
if (committed)
goto Lcast;
#define X(tf,tt) ((tf) * 256 + (tt))
{
OutBuffer buffer;
size_t newlen = 0;
int tfty = typeb->nextOf()->toBasetype()->ty;
int ttty = tb->nextOf()->toBasetype()->ty;
switch (X(tfty, ttty))
{
case X(Tchar, Tchar):
case X(Twchar,Twchar):
case X(Tdchar,Tdchar):
break;
case X(Tchar, Twchar):
for (size_t u = 0; u < len;)
{ unsigned c;
const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
if (p)
error("%s", p);
else
buffer.writeUTF16(c);
}
newlen = buffer.offset / 2;
buffer.writeUTF16(0);
goto L1;
case X(Tchar, Tdchar):
for (size_t u = 0; u < len;)
{ unsigned c;
const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c);
if (p)
error("%s", p);
buffer.write4(c);
newlen++;
}
buffer.write4(0);
goto L1;
case X(Twchar,Tchar):
for (size_t u = 0; u < len;)
{ unsigned c;
const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
if (p)
error("%s", p);
else
buffer.writeUTF8(c);
}
newlen = buffer.offset;
buffer.writeUTF8(0);
goto L1;
case X(Twchar,Tdchar):
for (size_t u = 0; u < len;)
{ unsigned c;
const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c);
if (p)
error("%s", p);
buffer.write4(c);
newlen++;
}
buffer.write4(0);
goto L1;
case X(Tdchar,Tchar):
for (size_t u = 0; u < len; u++)
{
unsigned c = ((unsigned *)se->string)[u];
if (!utf_isValidDchar(c))
error("invalid UCS-32 char \\U%08x", c);
else
buffer.writeUTF8(c);
newlen++;
}
newlen = buffer.offset;
buffer.writeUTF8(0);
goto L1;
case X(Tdchar,Twchar):
for (size_t u = 0; u < len; u++)
{
unsigned c = ((unsigned *)se->string)[u];
if (!utf_isValidDchar(c))
error("invalid UCS-32 char \\U%08x", c);
else
buffer.writeUTF16(c);
newlen++;
}
newlen = buffer.offset / 2;
buffer.writeUTF16(0);
goto L1;
L1:
if (!copied)
{ se = (StringExp *)copy();
copied = 1;
}
se->string = buffer.extractData();
se->len = newlen;
se->sz = tb->nextOf()->size();
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)
{
int dim2 = ((TypeSArray *)tb)->dim->toInteger();
//printf("dim from = %d, to = %d\n", se->len, 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 (int i = 0; i < eo->vars->a.dim; i++)
{ Dsymbol *s = (Dsymbol *)eo->vars->a.data[i];
FuncDeclaration *f2 = s->isFuncDeclaration();
assert(f2);
if (f2->overloadExactMatch(t->nextOf()))
{ 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 (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);
}
}
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)
{
// LDC: not in ldc
#if !IN_LLVM
assert(0); // should be SymOffExp instead
#endif
f = f->overloadExactMatch(tb->nextOf());
if (f)
{
e = new VarExp(loc, f);
e->type = f->type;
e = new AddrExp(loc, e);
e->type = t;
return e;
}
}
}
e = Expression::castTo(sc, t);
}
e->type = t;
return e;
}
Expression *TupleExp::castTo(Scope *sc, Type *t)
{ TupleExp *e = (TupleExp *)copy();
e->exps = (Expressions *)exps->copy();
for (size_t i = 0; i < e->exps->dim; i++)
{ Expression *ex = (Expression *)e->exps->data[i];
ex = ex->castTo(sc, t);
e->exps->data[i] = (void *)ex;
}
return e;
}
Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t)
{
#if 0
printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n",
toChars(), type->toChars(), t->toChars());
#endif
if (type == t)
return this;
ArrayLiteralExp *e = this;
Type *typeb = type->toBasetype();
Type *tb = t->toBasetype();
if ((tb->ty == Tarray || tb->ty == Tsarray) &&
(typeb->ty == Tarray || typeb->ty == Tsarray) &&
// Not trying to convert non-void[] to void[]
!(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid))
{
if (tb->ty == Tsarray)
{ TypeSArray *tsa = (TypeSArray *)tb;
if (elements->dim != tsa->dim->toInteger())
goto L1;
}
e = (ArrayLiteralExp *)copy();
e->elements = (Expressions *)elements->copy();
for (int i = 0; i < elements->dim; i++)
{ Expression *ex = (Expression *)elements->data[i];
ex = ex->castTo(sc, tb->nextOf());
e->elements->data[i] = (void *)ex;
}
e->type = t;
return e;
}
if (tb->ty == Tpointer && typeb->ty == Tsarray)
{
e = (ArrayLiteralExp *)copy();
e->type = typeb->nextOf()->pointerTo();
}
L1:
return e->Expression::castTo(sc, t);
}
Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t)
{
if (type == t)
return this;
AssocArrayLiteralExp *e = this;
Type *typeb = type->toBasetype();
Type *tb = t->toBasetype();
if (tb->ty == Taarray && typeb->ty == Taarray &&
tb->nextOf()->toBasetype()->ty != Tvoid)
{
e = (AssocArrayLiteralExp *)copy();
e->keys = (Expressions *)keys->copy();
e->values = (Expressions *)values->copy();
assert(keys->dim == values->dim);
for (size_t i = 0; i < keys->dim; i++)
{ Expression *ex = (Expression *)values->data[i];
ex = ex->castTo(sc, tb->nextOf());
e->values->data[i] = (void *)ex;
ex = (Expression *)keys->data[i];
ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
e->keys->data[i] = (void *)ex;
}
e->type = t;
return e;
}
L1:
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());
if (f)
{
if (tb->ty == Tdelegate && f->needThis() && hasThis(sc))
{
e = new DelegateExp(loc, new ThisExp(loc), f);
e = e->semantic(sc);
}
else if (tb->ty == Tdelegate && f->isNested())
{
e = new DelegateExp(loc, new IntegerExp(0), f);
e = e->semantic(sc);
}
else
{
e = new SymOffExp(loc, f, 0);
e->type = t;
}
f->tookAddressOf++;
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)
{
// Look for delegates to functions where the functions are overloaded.
FuncDeclaration *f;
if (typeb->ty == Tdelegate && typeb->nextOf()->ty == Tfunction &&
tb->ty == Tdelegate && tb->nextOf()->ty == Tfunction)
{
if (func)
{
f = func->overloadExactMatch(tb->nextOf());
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 *CondExp::castTo(Scope *sc, Type *t)
{
Expression *e = this;
if (type != t)
{
if (1 || e1->op == TOKstring || e2->op == TOKstring)
{ e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t));
e->type = t;
}
else
e = Expression::castTo(sc, t);
}
return e;
}
/* ==================== ====================== */
/****************************************
* Scale addition/subtraction to/from pointer.
*/
Expression *BinExp::scaleFactor(Scope *sc)
{ d_uns64 stride;
Type *t1b = e1->type->toBasetype();
Type *t2b = e2->type->toBasetype();
if (t1b->ty == Tpointer && t2b->isintegral())
{ // Need to adjust operator by the stride
// Replace (ptr + int) with (ptr + (int * stride))
Type *t = Type::tptrdiff_t;
stride = t1b->nextOf()->size(loc);
if (!t->equals(t2b))
e2 = e2->castTo(sc, t);
// LDC: llvm uses typesafe pointer arithmetic
#if !IN_LLVM
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;
}
/**************************************
* 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());
//dump(0);
Expression *e1 = (*pe1)->integralPromotions(sc);
Expression *e2 = (*pe2)->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);
Type *t1b = t1->toBasetype();
Type *t2b = t2->toBasetype();
TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty];
if (ty != Terror)
{ TY ty1;
TY ty2;
ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty];
ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty];
if (t1b->ty == ty1) // if no promotions
{
if (t1 == t2)
{
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;
Lagain:
if (t1 == t2)
{
}
else if (t1->ty == Tpointer && t2->ty == Tpointer)
{
// Bring pointers to compatible type
Type *t1n = t1->nextOf();
Type *t2n = t2->nextOf();
if (t1n == t2n)
;
else if (t1n->ty == Tvoid) // pointers to void are always compatible
t = t2;
else if (t2n->ty == Tvoid)
;
else if (t1n->mod != t2n->mod)
{
t1 = t1n->mutableOf()->constOf()->pointerTo();
t2 = t2n->mutableOf()->constOf()->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
goto Lincompatible;
}
else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid)
{ /* (T[n] op void*)
* (T[] op void*)
*/
goto Lx1;
}
else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid)
{ /* (void* op T[n])
* (void* op T[])
*/
goto Lx2;
}
else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2))
{
goto Lt2;
}
else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
{
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
)
{
if (t1->ty == Tpointer)
t1 = t1->nextOf()->mutableOf()->constOf()->pointerTo();
else
t1 = t1->nextOf()->mutableOf()->constOf()->arrayOf();
if (t2->ty == Tpointer)
t2 = t2->nextOf()->mutableOf()->constOf()->pointerTo();
else
t2 = t2->nextOf()->mutableOf()->constOf()->arrayOf();
t = t1;
goto Lagain;
}
else if (t1->ty == Tclass || t2->ty == Tclass)
{
while (1)
{
int i1 = e2->implicitConvTo(t1);
int i2 = e1->implicitConvTo(t2);
if (i1 && i2)
{
// We have the case of class vs. void*, so pick class
if (t1->ty == Tpointer)
i1 = 0;
else if (t2->ty == Tpointer)
i2 = 0;
}
if (i2)
{
goto Lt2;
}
else if (i1)
{
goto Lt1;
}
else if (t1->ty == Tclass && t2->ty == Tclass)
{ TypeClass *tc1 = (TypeClass *)t1;
TypeClass *tc2 = (TypeClass *)t2;
/* Pick 'tightest' type
*/
ClassDeclaration *cd1 = tc1->sym->baseClass;
ClassDeclaration *cd2 = tc2->sym->baseClass;
if (cd1 && cd2)
{ t1 = cd1->type;
t2 = cd2->type;
}
else if (cd1)
t1 = cd1->type;
else if (cd2)
t2 = cd2->type;
else
goto Lincompatible;
}
else
goto Lincompatible;
}
}
else if (t1->ty == Tstruct && t2->ty == Tstruct)
{
if (((TypeStruct *)t1)->sym != ((TypeStruct *)t2)->sym)
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();
e1 = e1->castTo(sc, t);
e2 = e2->castTo(sc, t);
}
else if (t1->ty == Tsarray && t2->ty == Tsarray &&
e1->implicitConvTo(t2->nextOf()->arrayOf()))
{
Lx2:
t = t2->nextOf()->arrayOf();
e1 = e1->castTo(sc, t);
e2 = e2->castTo(sc, t);
}
else if (t1->isintegral() && t2->isintegral())
{
assert(0);
}
else if (e1->op == TOKslice && t1->ty == Tarray &&
e2->implicitConvTo(t1->nextOf()))
{ // T[] op T
e2 = e2->castTo(sc, t1->nextOf());
t = t1->nextOf()->arrayOf();
}
else if (e2->op == TOKslice && 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)
{
if (t1 == t2 && (t1->ty == Tstruct || t1->ty == Tclass))
goto Lerror;
}
if (!typeMerge(sc, this, &type, &e1, &e2))
goto Lerror;
return this;
Lerror:
incompatibleTypes();
type = Type::terror;
return this;
}
/***********************************
* 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");
break;
case Tint8:
case Tuns8:
case Tint16:
case Tuns16:
case Tbit:
case Tbool:
case Tchar:
case Twchar:
e = e->castTo(sc, Type::tint32);
break;
case Tdchar:
e = e->castTo(sc, Type::tuns32);
break;
}
return e;
}