mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-09 04:15:58 +03:00
1705 lines
38 KiB
C
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;
|
|
}
|
|
|