ldc/dmd2/mtype.c

6395 lines
138 KiB
C

// Compiler implementation of the D programming language
// 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.
#define __USE_ISOC99 1 // so signbit() gets defined
#include <cmath>
#include <stdio.h>
#include <assert.h>
#include <float.h>
#ifdef __DMC__
#include <fp.h>
#endif
#if _MSC_VER
#include <malloc.h>
#include <complex>
#include <limits>
#elif __DMC__
#include <complex.h>
#elif __MINGW32__
#include <malloc.h>
#else
//#define signbit 56
#endif
#if __APPLE__
#include <cmath>
static double zero = 0;
#elif __MINGW32__
#include <cmath>
static double zero = 0;
#elif __GNUC__
#include <cmath>
#include <bits/nan.h>
#include <bits/mathdef.h>
static double zero = 0;
#endif
#include "mem.h"
#include "dsymbol.h"
#include "mtype.h"
#include "scope.h"
#include "init.h"
#include "expression.h"
#include "attrib.h"
#include "declaration.h"
#include "template.h"
#include "id.h"
#include "enum.h"
#include "import.h"
#include "aggregate.h"
#include "hdrgen.h"
#include "gen/tollvm.h"
FuncDeclaration *hasThis(Scope *sc);
#define LOGDOTEXP 0 // log ::dotExp()
#define LOGDEFAULTINIT 0 // log ::defaultInit()
// Allow implicit conversion of T[] to T*
#define IMPLICIT_ARRAY_TO_PTR global.params.useDeprecated
/* These have default values for 32 bit code, they get
* adjusted for 64 bit code.
*/
int PTRSIZE = 4;
#if IN_LLVM
int REALSIZE = 8;
int REALPAD = 0;
#elif TARGET_LINUX
int REALSIZE = 12;
int REALPAD = 2;
#else
int REALSIZE = 10;
int REALPAD = 0;
#endif
int Tsize_t = Tuns32;
int Tptrdiff_t = Tint32;
/***************************** Type *****************************/
ClassDeclaration *Type::typeinfo;
ClassDeclaration *Type::typeinfoclass;
ClassDeclaration *Type::typeinfointerface;
ClassDeclaration *Type::typeinfostruct;
ClassDeclaration *Type::typeinfotypedef;
ClassDeclaration *Type::typeinfopointer;
ClassDeclaration *Type::typeinfoarray;
ClassDeclaration *Type::typeinfostaticarray;
ClassDeclaration *Type::typeinfoassociativearray;
ClassDeclaration *Type::typeinfoenum;
ClassDeclaration *Type::typeinfofunction;
ClassDeclaration *Type::typeinfodelegate;
ClassDeclaration *Type::typeinfotypelist;
ClassDeclaration *Type::typeinfoconst;
ClassDeclaration *Type::typeinfoinvariant;
Type *Type::tvoidptr;
Type *Type::basic[TMAX];
unsigned char Type::mangleChar[TMAX];
unsigned char Type::sizeTy[TMAX];
StringTable Type::stringtable;
Type::Type(TY ty)
{
this->ty = ty;
this->mod = 0;
this->deco = NULL;
#if DMDV2
this->cto = NULL;
this->ito = NULL;
#endif
this->pto = NULL;
this->rto = NULL;
this->arrayof = NULL;
this->vtinfo = NULL;
this->ctype = NULL;
}
Type *Type::syntaxCopy()
{
print();
fprintf(stdmsg, "ty = %d\n", ty);
assert(0);
return this;
}
int Type::equals(Object *o)
{ Type *t;
t = (Type *)o;
//printf("Type::equals(%s, %s)\n", toChars(), t->toChars());
if (this == o ||
(t && deco == t->deco) && // deco strings are unique
deco != NULL) // and semantic() has been run
{
//printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
return 1;
}
//if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
return 0;
}
char Type::needThisPrefix()
{
return 'M'; // name mangling prefix for functions needing 'this'
}
void Type::init()
{ int i;
int j;
Lexer::initKeywords();
for (i = 0; i < TMAX; i++)
sizeTy[i] = sizeof(TypeBasic);
sizeTy[Tsarray] = sizeof(TypeSArray);
sizeTy[Tarray] = sizeof(TypeDArray);
sizeTy[Taarray] = sizeof(TypeAArray);
sizeTy[Tpointer] = sizeof(TypePointer);
sizeTy[Treference] = sizeof(TypeReference);
sizeTy[Tfunction] = sizeof(TypeFunction);
sizeTy[Tdelegate] = sizeof(TypeDelegate);
sizeTy[Tident] = sizeof(TypeIdentifier);
sizeTy[Tinstance] = sizeof(TypeInstance);
sizeTy[Ttypeof] = sizeof(TypeTypeof);
sizeTy[Tenum] = sizeof(TypeEnum);
sizeTy[Ttypedef] = sizeof(TypeTypedef);
sizeTy[Tstruct] = sizeof(TypeStruct);
sizeTy[Tclass] = sizeof(TypeClass);
sizeTy[Ttuple] = sizeof(TypeTuple);
sizeTy[Tslice] = sizeof(TypeSlice);
sizeTy[Treturn] = sizeof(TypeReturn);
mangleChar[Tarray] = 'A';
mangleChar[Tsarray] = 'G';
mangleChar[Taarray] = 'H';
mangleChar[Tpointer] = 'P';
mangleChar[Treference] = 'R';
mangleChar[Tfunction] = 'F';
mangleChar[Tident] = 'I';
mangleChar[Tclass] = 'C';
mangleChar[Tstruct] = 'S';
mangleChar[Tenum] = 'E';
mangleChar[Ttypedef] = 'T';
mangleChar[Tdelegate] = 'D';
mangleChar[Tnone] = 'n';
mangleChar[Tvoid] = 'v';
mangleChar[Tint8] = 'g';
mangleChar[Tuns8] = 'h';
mangleChar[Tint16] = 's';
mangleChar[Tuns16] = 't';
mangleChar[Tint32] = 'i';
mangleChar[Tuns32] = 'k';
mangleChar[Tint64] = 'l';
mangleChar[Tuns64] = 'm';
mangleChar[Tfloat32] = 'f';
mangleChar[Tfloat64] = 'd';
mangleChar[Tfloat80] = 'e';
mangleChar[Timaginary32] = 'o';
mangleChar[Timaginary64] = 'p';
mangleChar[Timaginary80] = 'j';
mangleChar[Tcomplex32] = 'q';
mangleChar[Tcomplex64] = 'r';
mangleChar[Tcomplex80] = 'c';
mangleChar[Tbool] = 'b';
mangleChar[Tascii] = 'a';
mangleChar[Twchar] = 'u';
mangleChar[Tdchar] = 'w';
mangleChar[Tbit] = '@';
mangleChar[Tinstance] = '@';
mangleChar[Terror] = '@';
mangleChar[Ttypeof] = '@';
mangleChar[Ttuple] = 'B';
mangleChar[Tslice] = '@';
mangleChar[Treturn] = '@';
for (i = 0; i < TMAX; i++)
{ if (!mangleChar[i])
fprintf(stdmsg, "ty = %d\n", i);
assert(mangleChar[i]);
}
// Set basic types
static TY basetab[] =
{ Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64,
Tfloat32, Tfloat64, Tfloat80,
Timaginary32, Timaginary64, Timaginary80,
Tcomplex32, Tcomplex64, Tcomplex80,
Tbool,
Tascii, Twchar, Tdchar };
for (i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++)
{ Type *t = new TypeBasic(basetab[i]);
t = t->merge();
basic[basetab[i]] = t;
}
basic[Terror] = basic[Tint32];
tvoidptr = tvoid->pointerTo();
// set size_t / ptrdiff_t types and pointer size
if (global.params.is64bit)
{
Tsize_t = Tuns64;
Tptrdiff_t = Tint64;
PTRSIZE = 8;
}
else
{
Tsize_t = Tuns32;
Tptrdiff_t = Tint32;
PTRSIZE = 4;
}
// set real size and padding
if (global.params.cpu == ARCHx86)
{
REALSIZE = 12;
REALPAD = 2;
}
else if (global.params.cpu == ARCHx86_64)
{
REALSIZE = 16;
REALPAD = 6;
}
else
{
REALSIZE = 8;
REALPAD = 0;
}
}
d_uns64 Type::size()
{
return size(0);
}
d_uns64 Type::size(Loc loc)
{
error(loc, "no size for type %s", toChars());
return 1;
}
unsigned Type::alignsize()
{
return size(0);
}
Type *Type::semantic(Loc loc, Scope *sc)
{
return merge();
}
/*******************************
* Determine if converting 'this' to 'to' is an identity operation,
* a conversion to const operation, or the types aren't the same.
* Returns:
* MATCHequal 'this' == 'to'
* MATCHconst 'to' is const
* MATCHnomatch conversion to mutable or invariant
*/
MATCH Type::constConv(Type *to)
{
if (equals(to))
return MATCHexact;
if (ty == to->ty && to->mod == MODconst)
return MATCHconst;
return MATCHnomatch;
}
Type *Type::constOf()
{
//printf("Type::constOf() %p %s\n", this, toChars());
if (isConst())
return this;
if (cto)
return cto;
Type *t = makeConst();
t = t->merge();
cto = t;
if (ito)
ito->cto = t;
//if (t->nextOf()) assert(t->nextOf()->isConst());
//printf("-Type::constOf() %p %s\n", t, toChars());
return t;
}
Type *Type::invariantOf()
{
//printf("Type::invariantOf() %p %s\n", this, toChars());
if (isInvariant())
{
return this;
}
if (ito)
{
//if (!ito->isInvariant()) printf("\tito is %p %s\n", ito, ito->toChars());
assert(ito->isInvariant());
return ito;
}
Type *t = makeInvariant();
t = t->merge();
ito = t;
if (cto)
cto->ito = t;
#if 0 // fails for function types
if (t->nextOf() && !t->nextOf()->isInvariant())
{
assert(0);
}
#endif
//printf("\t%p\n", t);
return t;
}
Type *Type::mutableOf()
{
//printf("Type::mutableOf() %p, %s\n", this, toChars());
Type *t = this;
if (isConst())
{ t = cto;
assert(!t || t->isMutable());
}
else if (isInvariant())
{ t = ito;
assert(!t || t->isMutable());
}
if (!t)
{
unsigned sz = sizeTy[ty];
t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = 0;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->vtinfo = NULL;
if (ty == Tsarray)
{ TypeSArray *ta = (TypeSArray *)t;
//ta->next = ta->next->mutableOf();
}
t = t->merge();
if (isConst())
{ cto = t;
t->cto = this;
if (ito)
ito->cto = this;
}
else if (isInvariant())
{ ito = t;
t->ito = this;
if (cto)
cto->ito = this;
}
}
return t;
}
Type *Type::makeConst()
{
//printf("Type::makeConst() %p, %s\n", this, toChars());
if (cto)
return cto;
unsigned sz = sizeTy[ty];
Type *t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = MODconst;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->vtinfo = NULL;
//printf("-Type::makeConst() %p, %s\n", t, toChars());
return t;
}
Type *Type::makeInvariant()
{
if (ito)
return ito;
unsigned sz = sizeTy[ty];
Type *t = (Type *)mem.malloc(sz);
memcpy(t, this, sz);
t->mod = MODinvariant;
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->vtinfo = NULL;
return t;
}
/**************************
* Return type with the top level of it being mutable.
*/
Type *Type::toHeadMutable()
{
if (!mod)
return this;
return mutableOf();
}
Type *Type::pointerTo()
{
if (!pto)
{ Type *t;
t = new TypePointer(this);
pto = t->merge();
}
return pto;
}
Type *Type::referenceTo()
{
if (!rto)
{ Type *t;
t = new TypeReference(this);
rto = t->merge();
}
return rto;
}
Type *Type::arrayOf()
{
if (!arrayof)
{ Type *t;
t = new TypeDArray(this);
arrayof = t->merge();
}
return arrayof;
}
Dsymbol *Type::toDsymbol(Scope *sc)
{
return NULL;
}
/*******************************
* If this is a shell around another type,
* get that other type.
*/
Type *Type::toBasetype()
{
return this;
}
/********************************
* Name mangling.
* Input:
* flag 0x100 do not do const/invariant
*/
void Type::toDecoBuffer(OutBuffer *buf, int flag)
{
if (flag != mod && flag != 0x100)
{
if (mod & MODshared)
buf->writeByte('O');
if (mod & MODconst)
buf->writeByte('x');
else if (mod & MODinvariant)
buf->writeByte('y');
// Cannot be both const and invariant
assert((mod & (MODconst | MODinvariant)) != (MODconst | MODinvariant));
}
buf->writeByte(mangleChar[ty]);
}
/********************************
* For pretty-printing a type.
*/
char *Type::toChars()
{ OutBuffer *buf;
HdrGenState hgs;
buf = new OutBuffer();
toCBuffer(buf, NULL, &hgs);
return buf->toChars();
}
void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
{
toCBuffer2(buf, hgs, 0);
if (ident)
{ buf->writeByte(' ');
buf->writestring(ident->toChars());
}
}
void Type::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(toChars());
}
void Type::toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ const char *p;
if (mod & MODshared)
buf->writestring("shared(");
switch (this->mod & (MODconst | MODinvariant))
{
case 0:
toCBuffer2(buf, hgs, this->mod);
break;
case MODconst:
p = "const(";
goto L1;
case MODinvariant:
p = "invariant(";
L1: buf->writestring(p);
toCBuffer2(buf, hgs, this->mod);
buf->writeByte(')');
break;
default:
assert(0);
}
if (mod & MODshared)
buf->writeByte(')');
}
}
/************************************
*/
Type *Type::merge()
{ Type *t;
//printf("merge(%s)\n", toChars());
t = this;
assert(t);
if (!deco)
{
OutBuffer buf;
StringValue *sv;
//if (next)
//next = next->merge();
toDecoBuffer(&buf);
sv = stringtable.update((char *)buf.data, buf.offset);
if (sv->ptrvalue)
{ t = (Type *) sv->ptrvalue;
assert(t->deco);
//printf("old value, deco = '%s' %p\n", t->deco, t->deco);
}
else
{
sv->ptrvalue = this;
deco = sv->lstring.string;
//printf("new value, deco = '%s' %p\n", t->deco, t->deco);
}
}
return t;
}
int Type::isintegral()
{
return FALSE;
}
int Type::isfloating()
{
return FALSE;
}
int Type::isreal()
{
return FALSE;
}
int Type::isimaginary()
{
return FALSE;
}
int Type::iscomplex()
{
return FALSE;
}
int Type::isscalar()
{
return FALSE;
}
int Type::isunsigned()
{
return FALSE;
}
ClassDeclaration *Type::isClassHandle()
{
return NULL;
}
int Type::isauto()
{
return FALSE;
}
int Type::isString()
{
return FALSE;
}
/**************************
* Given:
* T a, b;
* Can we assign:
* a = b;
* ?
*/
int Type::isAssignable()
{
return TRUE;
}
int Type::checkBoolean()
{
return isscalar();
}
/*********************************
* Check type to see if it is based on a deprecated symbol.
*/
void Type::checkDeprecated(Loc loc, Scope *sc)
{
Dsymbol *s = toDsymbol(sc);
if (s)
s->checkDeprecated(loc, sc);
}
Expression *Type::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("Type::defaultInit() '%s'\n", toChars());
#endif
return NULL;
}
int Type::isZeroInit()
{
return 0; // assume not
}
int Type::isBaseOf(Type *t, int *poffset)
{
return 0; // assume not
}
/********************************
* Determine if 'this' can be implicitly converted
* to type 'to'.
* Returns:
* 0 can't convert
* 1 can convert using implicit conversions
* 2 this and to are the same type
*/
MATCH Type::implicitConvTo(Type *to)
{
//printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
if (this == to)
return MATCHexact;
return MATCHnomatch;
}
Expression *Type::getProperty(Loc loc, Identifier *ident)
{ Expression *e;
#if LOGDOTEXP
printf("Type::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
#endif
if (ident == Id::__sizeof)
{
e = new IntegerExp(loc, size(loc), Type::tsize_t);
}
else if (ident == Id::size)
{
error(loc, ".size property should be replaced with .sizeof");
e = new IntegerExp(loc, size(loc), Type::tsize_t);
}
else if (ident == Id::alignof)
{
e = new IntegerExp(loc, alignsize(), Type::tsize_t);
}
else if (ident == Id::typeinfo)
{
if (!global.params.useDeprecated)
error(loc, ".typeinfo deprecated, use typeid(type)");
e = getTypeInfo(NULL);
}
else if (ident == Id::init)
{
if (ty == Tvoid)
error(loc, "void does not have an initializer");
e = defaultInit(loc);
}
else if (ident == Id::mangleof)
{
assert(deco);
e = new StringExp(loc, deco, strlen(deco), 'c');
Scope sc;
e = e->semantic(&sc);
}
else if (ident == Id::stringof)
{ char *s = toChars();
e = new StringExp(loc, s, strlen(s), 'c');
Scope sc;
e = e->semantic(&sc);
}
else
{
error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
e = new IntegerExp(loc, 1, Type::tint32);
}
return e;
}
Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident)
{ VarDeclaration *v = NULL;
#if LOGDOTEXP
printf("Type::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (e->op == TOKdotvar)
{
DotVarExp *dv = (DotVarExp *)e;
v = dv->var->isVarDeclaration();
}
else if (e->op == TOKvar)
{
VarExp *ve = (VarExp *)e;
v = ve->var->isVarDeclaration();
}
if (v)
{
if (ident == Id::offset)
{
if (!global.params.useDeprecated)
error(e->loc, ".offset deprecated, use .offsetof");
goto Loffset;
}
else if (ident == Id::offsetof)
{
Loffset:
if (v->storage_class & STCfield)
{
e = new IntegerExp(e->loc, v->offset, Type::tsize_t);
return e;
}
}
else if (ident == Id::init)
{
#if 0
if (v->init)
{
if (v->init->isVoidInitializer())
error(e->loc, "%s.init is void", v->toChars());
else
{ Loc loc = e->loc;
e = v->init->toExpression();
if (e->op == TOKassign || e->op == TOKconstruct || e->op == TOKblit)
{
e = ((AssignExp *)e)->e2;
/* Take care of case where we used a 0
* to initialize the struct.
*/
if (e->type == Type::tint32 &&
e->isBool(0) &&
v->type->toBasetype()->ty == Tstruct)
{
e = v->type->defaultInit(e->loc);
}
}
e = e->optimize(WANTvalue | WANTinterpret);
// if (!e->isConst())
// error(loc, ".init cannot be evaluated at compile time");
}
return e;
}
#endif
Expression *ex = defaultInit(e->loc);
return ex;
}
}
if (ident == Id::typeinfo)
{
if (!global.params.useDeprecated)
error(e->loc, ".typeinfo deprecated, use typeid(type)");
e = getTypeInfo(sc);
return e;
}
if (ident == Id::stringof)
{ char *s = e->toChars();
e = new StringExp(e->loc, s, strlen(s), 'c');
Scope sc;
e = e->semantic(&sc);
return e;
}
return getProperty(e->loc, ident);
}
unsigned Type::memalign(unsigned salign)
{
return salign;
}
void Type::error(Loc loc, const char *format, ...)
{
va_list ap;
va_start(ap, format);
::verror(loc, format, ap);
va_end( ap );
}
Identifier *Type::getTypeInfoIdent(int internal)
{
// _init_10TypeInfo_%s
OutBuffer buf;
Identifier *id;
char *name;
int len;
if (internal)
{ buf.writeByte(mangleChar[ty]);
if (ty == Tarray)
buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]);
}
else
toDecoBuffer(&buf);
len = buf.offset;
name = (char *)alloca(19 + sizeof(len) * 3 + len + 1);
buf.writeByte(0);
sprintf(name, "_D%dTypeInfo_%s6__initZ", 9 + len, buf.data);
// LDC
// it is not clear where the underscore that's stripped here is added back in
// if (global.params.isWindows)
// name++; // C mangling will add it back in
//printf("name = %s\n", name);
id = Lexer::idPool(name);
return id;
}
TypeBasic *Type::isTypeBasic()
{
return NULL;
}
void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
//printf("Type::resolve() %s, %d\n", toChars(), ty);
Type *t = semantic(loc, sc);
*pt = t;
*pe = NULL;
*ps = NULL;
}
/*******************************
* If one of the subtypes of this type is a TypeIdentifier,
* i.e. it's an unresolved type, return that type.
*/
Type *Type::reliesOnTident()
{
return NULL;
}
/********************************
* We've mistakenly parsed this as a type.
* Redo it as an Expression.
* NULL if cannot.
*/
Expression *Type::toExpression()
{
return NULL;
}
/***************************************
* Return !=0 if type has pointers that need to
* be scanned by the GC during a collection cycle.
*/
int Type::hasPointers()
{
return FALSE;
}
/*************************************
* If this is a type of something, return that something.
*/
Type *Type::nextOf()
{
return NULL;
}
/* ============================= TypeNext =========================== */
TypeNext::TypeNext(TY ty, Type *next)
: Type(ty)
{
this->next = next;
}
void TypeNext::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
assert(next != this);
//printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty);
next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
}
void TypeNext::checkDeprecated(Loc loc, Scope *sc)
{
Type::checkDeprecated(loc, sc);
next->checkDeprecated(loc, sc);
}
Type *TypeNext::reliesOnTident()
{
return next->reliesOnTident();
}
Type *TypeNext::nextOf()
{
return next;
}
Type *TypeNext::makeConst()
{
//printf("TypeNext::makeConst() %p, %s\n", this, toChars());
if (cto)
return cto;
TypeNext *t = (TypeNext *)Type::makeConst();
if (ty != Tfunction && ty != Tdelegate && next->deco &&
!next->isInvariant())
t->next = next->constOf();
//printf("TypeNext::makeConst() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeInvariant()
{
//printf("TypeNext::makeInvariant() %s\n", toChars());
if (ito)
{ assert(ito->isInvariant());
return ito;
}
TypeNext *t = (TypeNext *)Type::makeInvariant();
if (ty != Tfunction && ty != Tdelegate && next->deco)
{ t->next = next->invariantOf();
}
return t;
}
MATCH TypeNext::constConv(Type *to)
{ MATCH m = Type::constConv(to);
if (m == MATCHconst &&
next->constConv(((TypeNext *)to)->next) == MATCHnomatch)
m = MATCHnomatch;
return m;
}
/* ============================= TypeBasic =========================== */
TypeBasic::TypeBasic(TY ty)
: Type(ty)
{ const char *d;
unsigned flags;
#define TFLAGSintegral 1
#define TFLAGSfloating 2
#define TFLAGSunsigned 4
#define TFLAGSreal 8
#define TFLAGSimaginary 0x10
#define TFLAGScomplex 0x20
flags = 0;
switch (ty)
{
case Tvoid: d = Token::toChars(TOKvoid);
break;
case Tint8: d = Token::toChars(TOKint8);
flags |= TFLAGSintegral;
break;
case Tuns8: d = Token::toChars(TOKuns8);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tint16: d = Token::toChars(TOKint16);
flags |= TFLAGSintegral;
break;
case Tuns16: d = Token::toChars(TOKuns16);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tint32: d = Token::toChars(TOKint32);
flags |= TFLAGSintegral;
break;
case Tuns32: d = Token::toChars(TOKuns32);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tfloat32: d = Token::toChars(TOKfloat32);
flags |= TFLAGSfloating | TFLAGSreal;
break;
case Tint64: d = Token::toChars(TOKint64);
flags |= TFLAGSintegral;
break;
case Tuns64: d = Token::toChars(TOKuns64);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tfloat64: d = Token::toChars(TOKfloat64);
flags |= TFLAGSfloating | TFLAGSreal;
break;
case Tfloat80: d = Token::toChars(TOKfloat80);
flags |= TFLAGSfloating | TFLAGSreal;
break;
case Timaginary32: d = Token::toChars(TOKimaginary32);
flags |= TFLAGSfloating | TFLAGSimaginary;
break;
case Timaginary64: d = Token::toChars(TOKimaginary64);
flags |= TFLAGSfloating | TFLAGSimaginary;
break;
case Timaginary80: d = Token::toChars(TOKimaginary80);
flags |= TFLAGSfloating | TFLAGSimaginary;
break;
case Tcomplex32: d = Token::toChars(TOKcomplex32);
flags |= TFLAGSfloating | TFLAGScomplex;
break;
case Tcomplex64: d = Token::toChars(TOKcomplex64);
flags |= TFLAGSfloating | TFLAGScomplex;
break;
case Tcomplex80: d = Token::toChars(TOKcomplex80);
flags |= TFLAGSfloating | TFLAGScomplex;
break;
case Tbool: d = "bool";
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tascii: d = Token::toChars(TOKchar);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Twchar: d = Token::toChars(TOKwchar);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tdchar: d = Token::toChars(TOKdchar);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
default: assert(0);
}
this->dstring = d;
this->flags = flags;
merge();
}
Type *TypeBasic::syntaxCopy()
{
// No semantic analysis done on basic types, no need to copy
return this;
}
char *TypeBasic::toChars()
{
return Type::toChars();
}
void TypeBasic::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
//printf("TypeBasic::toCBuffer2(mod = %d, this->mod = %d)\n", mod, this->mod);
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(dstring);
}
d_uns64 TypeBasic::size(Loc loc)
{ unsigned size;
//printf("TypeBasic::size()\n");
switch (ty)
{
case Tint8:
case Tuns8: size = 1; break;
case Tint16:
case Tuns16: size = 2; break;
case Tint32:
case Tuns32:
case Tfloat32:
case Timaginary32:
size = 4; break;
case Tint64:
case Tuns64:
case Tfloat64:
case Timaginary64:
size = 8; break;
case Tfloat80:
case Timaginary80:
size = REALSIZE; break;
case Tcomplex32:
size = 8; break;
case Tcomplex64:
size = 16; break;
case Tcomplex80:
size = REALSIZE * 2; break;
case Tvoid:
//size = Type::size(); // error message
size = 1;
break;
case Tbool: size = 1; break;
case Tascii: size = 1; break;
case Twchar: size = 2; break;
case Tdchar: size = 4; break;
default:
assert(0);
break;
}
//printf("TypeBasic::size() = %d\n", size);
return size;
}
unsigned TypeBasic::alignsize()
{
if (ty == Tvoid)
return 1;
return getABITypeAlign(DtoType(this));
}
Expression *TypeBasic::getProperty(Loc loc, Identifier *ident)
{
Expression *e;
d_int64 ivalue;
#ifdef IN_GCC
real_t fvalue;
#else
d_float80 fvalue;
#endif
//printf("TypeBasic::getProperty('%s')\n", ident->toChars());
if (ident == Id::max)
{
switch (ty)
{
case Tint8: ivalue = 0x7F; goto Livalue;
case Tuns8: ivalue = 0xFF; goto Livalue;
case Tint16: ivalue = 0x7FFFUL; goto Livalue;
case Tuns16: ivalue = 0xFFFFUL; goto Livalue;
case Tint32: ivalue = 0x7FFFFFFFUL; goto Livalue;
case Tuns32: ivalue = 0xFFFFFFFFUL; goto Livalue;
case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFLL; goto Livalue;
case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFULL; goto Livalue;
case Tbool: ivalue = 1; goto Livalue;
case Tchar: ivalue = 0xFF; goto Livalue;
case Twchar: ivalue = 0xFFFFUL; goto Livalue;
case Tdchar: ivalue = 0x10FFFFUL; goto Livalue;
case Tcomplex32:
case Timaginary32:
case Tfloat32: fvalue = FLT_MAX; goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64: fvalue = DBL_MAX; goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80: fvalue = LDBL_MAX; goto Lfvalue;
}
}
else if (ident == Id::min)
{
switch (ty)
{
case Tint8: ivalue = -128; goto Livalue;
case Tuns8: ivalue = 0; goto Livalue;
case Tint16: ivalue = -32768; goto Livalue;
case Tuns16: ivalue = 0; goto Livalue;
case Tint32: ivalue = -2147483647L - 1; goto Livalue;
case Tuns32: ivalue = 0; goto Livalue;
case Tint64: ivalue = (-9223372036854775807LL-1LL); goto Livalue;
case Tuns64: ivalue = 0; goto Livalue;
case Tbool: ivalue = 0; goto Livalue;
case Tchar: ivalue = 0; goto Livalue;
case Twchar: ivalue = 0; goto Livalue;
case Tdchar: ivalue = 0; goto Livalue;
case Tcomplex32:
case Timaginary32:
case Tfloat32: fvalue = FLT_MIN; goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64: fvalue = DBL_MIN; goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80: fvalue = LDBL_MIN; goto Lfvalue;
}
}
else if (ident == Id::nan)
{
switch (ty)
{
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
{
#if IN_GCC
// mode doesn't matter, will be converted in RealExp anyway
fvalue = real_t::getnan(real_t::LongDouble);
#elif __GNUC__
// gcc nan's have the sign bit set by default, so turn it off
// Need the volatile to prevent gcc from doing incorrect
// constant folding.
volatile d_float80 foo;
foo = NAN;
if (std::signbit(foo)) // signbit sometimes, not always, set
foo = -foo; // turn off sign bit
fvalue = foo;
#elif _MSC_VER
unsigned long nan[2]= { 0xFFFFFFFF, 0x7FFFFFFF };
fvalue = *(double*)nan;
#else
fvalue = NAN;
#endif
goto Lfvalue;
}
}
}
else if (ident == Id::infinity)
{
switch (ty)
{
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
#if IN_GCC
fvalue = real_t::getinfinity();
#elif __GNUC__
fvalue = 1 / zero;
#elif _MSC_VER
fvalue = std::numeric_limits<long double>::infinity();
#else
fvalue = INFINITY;
#endif
goto Lfvalue;
}
}
else if (ident == Id::dig)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_DIG; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_DIG; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_DIG; goto Lint;
}
}
else if (ident == Id::epsilon)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: fvalue = FLT_EPSILON; goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64: fvalue = DBL_EPSILON; goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80: fvalue = LDBL_EPSILON; goto Lfvalue;
}
}
else if (ident == Id::mant_dig)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MANT_DIG; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MANT_DIG; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MANT_DIG; goto Lint;
}
}
else if (ident == Id::max_10_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MAX_10_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MAX_10_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MAX_10_EXP; goto Lint;
}
}
else if (ident == Id::max_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MAX_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MAX_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MAX_EXP; goto Lint;
}
}
else if (ident == Id::min_10_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MIN_10_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MIN_10_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MIN_10_EXP; goto Lint;
}
}
else if (ident == Id::min_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MIN_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MIN_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MIN_EXP; goto Lint;
}
}
Ldefault:
return Type::getProperty(loc, ident);
Livalue:
e = new IntegerExp(loc, ivalue, this);
return e;
Lfvalue:
if (isreal() || isimaginary())
e = new RealExp(loc, fvalue, this);
else
{
complex_t cvalue;
#if __DMC__
//((real_t *)&cvalue)[0] = fvalue;
//((real_t *)&cvalue)[1] = fvalue;
cvalue = fvalue + fvalue * I;
#else
cvalue.re = fvalue;
cvalue.im = fvalue;
#endif
//for (int i = 0; i < 20; i++)
// printf("%02x ", ((unsigned char *)&cvalue)[i]);
//printf("\n");
e = new ComplexExp(loc, cvalue, this);
}
return e;
Lint:
e = new IntegerExp(loc, ivalue, Type::tint32);
return e;
}
Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
Type *t;
if (ident == Id::re)
{
switch (ty)
{
case Tcomplex32: t = tfloat32; goto L1;
case Tcomplex64: t = tfloat64; goto L1;
case Tcomplex80: t = tfloat80; goto L1;
L1:
e = e->castTo(sc, t);
break;
case Tfloat32:
case Tfloat64:
case Tfloat80:
break;
case Timaginary32: t = tfloat32; goto L2;
case Timaginary64: t = tfloat64; goto L2;
case Timaginary80: t = tfloat80; goto L2;
L2:
e = new RealExp(0, 0.0, t);
break;
default:
return Type::getProperty(e->loc, ident);
}
}
else if (ident == Id::im)
{ Type *t2;
switch (ty)
{
case Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3;
case Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3;
case Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3;
L3:
e = e->castTo(sc, t);
e->type = t2;
break;
case Timaginary32: t = tfloat32; goto L4;
case Timaginary64: t = tfloat64; goto L4;
case Timaginary80: t = tfloat80; goto L4;
L4:
e = e->copy();
e->type = t;
break;
case Tfloat32:
case Tfloat64:
case Tfloat80:
e = new RealExp(0, 0.0, this);
break;
default:
return Type::getProperty(e->loc, ident);
}
}
else
{
return Type::dotExp(sc, e, ident);
}
return e;
}
Expression *TypeBasic::defaultInit(Loc loc)
{ integer_t value = 0;
#if LOGDEFAULTINIT
printf("TypeBasic::defaultInit() '%s'\n", toChars());
#endif
switch (ty)
{
case Tvoid:
return new IntegerExp(loc, value, Type::tbool);
case Tchar:
value = 0xFF;
break;
case Twchar:
case Tdchar:
value = 0xFFFF;
break;
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
return getProperty(loc, Id::nan);
}
return new IntegerExp(loc, value, this);
}
int TypeBasic::isZeroInit()
{
switch (ty)
{
case Tchar:
case Twchar:
case Tdchar:
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
return 0; // no
}
return 1; // yes
}
int TypeBasic::isintegral()
{
//printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
return flags & TFLAGSintegral;
}
int TypeBasic::isfloating()
{
return flags & TFLAGSfloating;
}
int TypeBasic::isreal()
{
return flags & TFLAGSreal;
}
int TypeBasic::isimaginary()
{
return flags & TFLAGSimaginary;
}
int TypeBasic::iscomplex()
{
return flags & TFLAGScomplex;
}
int TypeBasic::isunsigned()
{
return flags & TFLAGSunsigned;
}
int TypeBasic::isscalar()
{
return flags & (TFLAGSintegral | TFLAGSfloating);
}
MATCH TypeBasic::implicitConvTo(Type *to)
{
//printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
if (this == to)
return MATCHexact;
if (ty == to->ty)
{
return (mod == to->mod) ? MATCHexact : MATCHconst;
}
if (ty == Tvoid || to->ty == Tvoid)
return MATCHnomatch;
if (1 || global.params.Dversion == 1)
{
if (to->ty == Tbool)
return MATCHnomatch;
}
else
{
if (ty == Tbool || to->ty == Tbool)
return MATCHnomatch;
}
if (!to->isTypeBasic())
return MATCHnomatch;
TypeBasic *tob = (TypeBasic *)to;
if (flags & TFLAGSintegral)
{
// Disallow implicit conversion of integers to imaginary or complex
if (tob->flags & (TFLAGSimaginary | TFLAGScomplex))
return MATCHnomatch;
// If converting to integral
if (0 && global.params.Dversion > 1 && tob->flags & TFLAGSintegral)
{ d_uns64 sz = size(0);
d_uns64 tosz = tob->size(0);
/* Can't convert to smaller size or, if same size, change sign
*/
if (sz > tosz)
return MATCHnomatch;
/*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned)
return MATCHnomatch;*/
}
}
else if (flags & TFLAGSfloating)
{
// Disallow implicit conversion of floating point to integer
if (tob->flags & TFLAGSintegral)
return MATCHnomatch;
assert(tob->flags & TFLAGSfloating);
// Disallow implicit conversion from complex to non-complex
if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex))
return MATCHnomatch;
// Disallow implicit conversion of real or imaginary to complex
if (flags & (TFLAGSreal | TFLAGSimaginary) &&
tob->flags & TFLAGScomplex)
return MATCHnomatch;
// Disallow implicit conversion to-from real and imaginary
if ((flags & (TFLAGSreal | TFLAGSimaginary)) !=
(tob->flags & (TFLAGSreal | TFLAGSimaginary)))
return MATCHnomatch;
}
return MATCHconvert;
}
TypeBasic *TypeBasic::isTypeBasic()
{
return (TypeBasic *)this;
}
/***************************** TypeArray *****************************/
TypeArray::TypeArray(TY ty, Type *next)
: TypeNext(ty, next)
{
}
Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
Type *n = this->next->toBasetype(); // uncover any typedef's
#if LOGDOTEXP
printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar))
{
Expression *ec;
Expressions *arguments;
//LDC: Build arguments.
static FuncDeclaration *adReverseChar_fd = NULL;
if(!adReverseChar_fd) {
Arguments* args = new Arguments;
Type* arrty = Type::tchar->arrayOf();
args->push(new Argument(STCin, arrty, NULL, NULL));
adReverseChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseChar");
}
static FuncDeclaration *adReverseWchar_fd = NULL;
if(!adReverseWchar_fd) {
Arguments* args = new Arguments;
Type* arrty = Type::twchar->arrayOf();
args->push(new Argument(STCin, arrty, NULL, NULL));
adReverseWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseWchar");
}
if(n->ty == Twchar)
ec = new VarExp(0, adReverseWchar_fd);
else
ec = new VarExp(0, adReverseChar_fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
arguments->push(e);
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else if (ident == Id::sort && (n->ty == Tchar || n->ty == Twchar))
{
Expression *ec;
Expressions *arguments;
//LDC: Build arguments.
static FuncDeclaration *adSortChar_fd = NULL;
if(!adSortChar_fd) {
Arguments* args = new Arguments;
Type* arrty = Type::tchar->arrayOf();
args->push(new Argument(STCin, arrty, NULL, NULL));
adSortChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortChar");
}
static FuncDeclaration *adSortWchar_fd = NULL;
if(!adSortWchar_fd) {
Arguments* args = new Arguments;
Type* arrty = Type::twchar->arrayOf();
args->push(new Argument(STCin, arrty, NULL, NULL));
adSortWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortWchar");
}
if(n->ty == Twchar)
ec = new VarExp(0, adSortWchar_fd);
else
ec = new VarExp(0, adSortChar_fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
arguments->push(e);
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else if (ident == Id::reverse || ident == Id::dup || ident == Id::idup)
{
Expression *ec;
Expressions *arguments;
int size = next->size(e->loc);
int dup;
assert(size);
dup = (ident == Id::dup || ident == Id::idup);
//LDC: Build arguments.
static FuncDeclaration *adDup_fd = NULL;
if(!adDup_fd) {
Arguments* args = new Arguments;
args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL));
args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL));
adDup_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adDup);
}
static FuncDeclaration *adReverse_fd = NULL;
if(!adReverse_fd) {
Arguments* args = new Arguments;
args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL));
args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
adReverse_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adReverse);
}
if(dup)
ec = new VarExp(0, adDup_fd);
else
ec = new VarExp(0, adReverse_fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
if (dup)
arguments->push(getTypeInfo(sc));
// LDC repaint array type to void[]
if (n->ty != Tvoid) {
e = new CastExp(e->loc, e, e->type);
e->type = Type::tvoid->arrayOf();
}
arguments->push(e);
if (!dup)
arguments->push(new IntegerExp(0, size, Type::tsize_t));
e = new CallExp(e->loc, ec, arguments);
if (ident == Id::idup)
{ Type *einv = next->invariantOf();
if (next->implicitConvTo(einv) < MATCHconst)
error(e->loc, "cannot implicitly convert element type %s to invariant", next->toChars());
e->type = einv->arrayOf();
}
else
e->type = next->mutableOf()->arrayOf();
}
else if (ident == Id::sort)
{
Expression *ec;
Expressions *arguments;
bool isBit = (n->ty == Tbit);
//LDC: Build arguments.
static FuncDeclaration *adSort_fd = NULL;
if(!adSort_fd) {
Arguments* args = new Arguments;
args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL));
args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL));
adSort_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSort");
}
static FuncDeclaration *adSortBit_fd = NULL;
if(!adSortBit_fd) {
Arguments* args = new Arguments;
args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL));
args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL));
adSortBit_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSortBit");
}
if(isBit)
ec = new VarExp(0, adSortBit_fd);
else
ec = new VarExp(0, adSort_fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
// LDC repaint array type to void[]
if (n->ty != Tvoid) {
e = new CastExp(e->loc, e, e->type);
e->type = Type::tvoid->arrayOf();
}
arguments->push(e);
arguments->push(n->getTypeInfo(sc)); // LDC, we don't support the getInternalTypeInfo
// optimization arbitrarily, not yet at least...
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else
{
e = Type::dotExp(sc, e, ident);
}
return e;
}
/***************************** TypeSArray *****************************/
TypeSArray::TypeSArray(Type *t, Expression *dim)
: TypeArray(Tsarray, t)
{
//printf("TypeSArray(%s)\n", dim->toChars());
this->dim = dim;
}
Type *TypeSArray::syntaxCopy()
{
Type *t = next->syntaxCopy();
Expression *e = dim->syntaxCopy();
t = new TypeSArray(t, e);
t->mod = mod;
return t;
}
d_uns64 TypeSArray::size(Loc loc)
{ integer_t sz;
if (!dim)
return Type::size(loc);
sz = dim->toInteger();
{ integer_t n, n2;
n = next->size();
n2 = n * sz;
if (n && (n2 / n) != sz)
goto Loverflow;
sz = n2;
}
return sz;
Loverflow:
error(loc, "index %lld overflow for static array", sz);
return 1;
}
unsigned TypeSArray::alignsize()
{
return next->alignsize();
}
/**************************
* This evaluates exp while setting length to be the number
* of elements in the tuple t.
*/
Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
{
if (t->ty == Ttuple)
{ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t);
sym->parent = sc->scopesym;
sc = sc->push(sym);
exp = exp->semantic(sc);
sc->pop();
}
else
exp = exp->semantic(sc);
return exp;
}
Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
{
ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s);
sym->parent = sc->scopesym;
sc = sc->push(sym);
exp = exp->semantic(sc);
sc->pop();
return exp;
}
void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
//printf("TypeSArray::resolve() %s\n", toChars());
next->resolve(loc, sc, pe, pt, ps);
//printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
if (*pe)
{ // It's really an index expression
Expression *e = new IndexExp(loc, *pe, dim);
*pe = e;
}
else if (*ps)
{ Dsymbol *s = *ps;
TupleDeclaration *td = s->isTupleDeclaration();
if (td)
{
ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
sym->parent = sc->scopesym;
sc = sc->push(sym);
dim = dim->semantic(sc);
dim = dim->optimize(WANTvalue | WANTinterpret);
uinteger_t d = dim->toUInteger();
sc = sc->pop();
if (d >= td->objects->dim)
{ error(loc, "tuple index %llu exceeds %u", d, td->objects->dim);
goto Ldefault;
}
Object *o = (Object *)td->objects->data[(size_t)d];
if (o->dyncast() == DYNCAST_DSYMBOL)
{
*ps = (Dsymbol *)o;
return;
}
if (o->dyncast() == DYNCAST_EXPRESSION)
{
*ps = NULL;
*pe = (Expression *)o;
return;
}
/* Create a new TupleDeclaration which
* is a slice [d..d+1] out of the old one.
* Do it this way because TemplateInstance::semanticTiargs()
* can handle unresolved Objects this way.
*/
Objects *objects = new Objects;
objects->setDim(1);
objects->data[0] = o;
TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
*ps = tds;
}
else
goto Ldefault;
}
else
{
Ldefault:
Type::resolve(loc, sc, pe, pt, ps);
}
}
Type *TypeSArray::semantic(Loc loc, Scope *sc)
{
//printf("TypeSArray::semantic() %s\n", toChars());
Type *t;
Expression *e;
Dsymbol *s;
next->resolve(loc, sc, &e, &t, &s);
if (dim && s && s->isTupleDeclaration())
{ TupleDeclaration *sd = s->isTupleDeclaration();
dim = semanticLength(sc, sd, dim);
dim = dim->optimize(WANTvalue | WANTinterpret);
uinteger_t d = dim->toUInteger();
if (d >= sd->objects->dim)
{ error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim);
return Type::terror;
}
Object *o = (Object *)sd->objects->data[(size_t)d];
if (o->dyncast() != DYNCAST_TYPE)
{ error(loc, "%s is not a type", toChars());
return Type::terror;
}
t = (Type *)o;
return t;
}
next = next->semantic(loc,sc);
if (mod == MODconst && !next->isInvariant())
next = next->constOf();
else if (mod == MODinvariant)
next = next->invariantOf();
Type *tbn = next->toBasetype();
if (dim)
{ integer_t n, n2;
dim = semanticLength(sc, tbn, dim);
dim = dim->optimize(WANTvalue | WANTinterpret);
if (sc && sc->parameterSpecialization && dim->op == TOKvar &&
((VarExp *)dim)->var->storage_class & STCtemplateparameter)
{
/* It could be a template parameter N which has no value yet:
* template Foo(T : T[N], size_t N);
*/
return this;
}
integer_t d1 = dim->toInteger();
dim = dim->castTo(sc, tsize_t);
dim = dim->optimize(WANTvalue);
integer_t d2 = dim->toInteger();
if (d1 != d2)
goto Loverflow;
if (tbn->isintegral() ||
tbn->isfloating() ||
tbn->ty == Tpointer ||
tbn->ty == Tarray ||
tbn->ty == Tsarray ||
tbn->ty == Taarray ||
tbn->ty == Tclass)
{
/* Only do this for types that don't need to have semantic()
* run on them for the size, since they may be forward referenced.
*/
n = tbn->size(loc);
n2 = n * d2;
if ((int)n2 < 0)
goto Loverflow;
if (n2 >= 0x1000000) // put a 'reasonable' limit on it
goto Loverflow;
if (n && n2 / n != d2)
{
Loverflow:
error(loc, "index %lld overflow for static array", d1);
dim = new IntegerExp(0, 1, tsize_t);
}
}
}
switch (tbn->ty)
{
case Ttuple:
{ // Index the tuple to get the type
assert(dim);
TypeTuple *tt = (TypeTuple *)tbn;
uinteger_t d = dim->toUInteger();
if (d >= tt->arguments->dim)
{ error(loc, "tuple index %llu exceeds %u", d, tt->arguments->dim);
return Type::terror;
}
Argument *arg = (Argument *)tt->arguments->data[(size_t)d];
return arg->type;
}
case Tfunction:
case Tnone:
error(loc, "can't have array of %s", tbn->toChars());
tbn = next = tint32;
break;
}
if (tbn->isauto())
error(loc, "cannot have array of auto %s", tbn->toChars());
return merge();
}
void TypeSArray::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
if (dim)
buf->printf("%llu", dim->toInteger());
if (next)
/* Note that static arrays are value types, so
* for a parameter, propagate the 0x100 to the next
* level, since for T[4][3], any const should apply to the T,
* not the [4].
*/
next->toDecoBuffer(buf, (flag & 0x100) ? flag : mod);
}
void TypeSArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
buf->printf("[%s]", dim->toChars());
}
Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::length)
{
e = dim;
}
else if (ident == Id::ptr)
{
e = e->castTo(sc, next->pointerTo());
}
else
{
e = TypeArray::dotExp(sc, e, ident);
}
return e;
}
int TypeSArray::isString()
{
TY nty = next->toBasetype()->ty;
return nty == Tchar || nty == Twchar || nty == Tdchar;
}
unsigned TypeSArray::memalign(unsigned salign)
{
return next->memalign(salign);
}
MATCH TypeSArray::constConv(Type *to)
{
if (to->ty == Tsarray)
{
TypeSArray *tsa = (TypeSArray *)to;
if (!dim->equals(tsa->dim))
return MATCHnomatch;
}
return TypeNext::constConv(to);
}
MATCH TypeSArray::implicitConvTo(Type *to)
{
//printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
// Allow implicit conversion of static array to pointer or dynamic array
if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer)
{
TypePointer *tp = (TypePointer *)to;
if (next->mod != tp->next->mod && tp->next->mod != MODconst)
return MATCHnomatch;
if (tp->next->ty == Tvoid || next->constConv(tp->next) != MATCHnomatch)
{
return MATCHconvert;
}
return MATCHnomatch;
}
if (to->ty == Tarray)
{ int offset = 0;
TypeDArray *ta = (TypeDArray *)to;
if (next->mod != ta->next->mod && ta->next->mod != MODconst)
return MATCHnomatch;
if (next->equals(ta->next) ||
next->implicitConvTo(ta->next) >= MATCHconst ||
(ta->next->isBaseOf(next, &offset) && offset == 0) ||
ta->next->ty == Tvoid)
return MATCHconvert;
return MATCHnomatch;
}
if (to->ty == Tsarray)
{
if (this == to)
return MATCHexact;
TypeSArray *tsa = (TypeSArray *)to;
if (dim->equals(tsa->dim))
{
/* Since static arrays are value types, allow
* conversions from const elements to non-const
* ones, just like we allow conversion from const int
* to int.
*/
MATCH m = next->implicitConvTo(tsa->next);
if (m >= MATCHconst)
{
if (mod != to->mod)
m = MATCHconst;
return m;
}
}
}
return MATCHnomatch;
}
Expression *TypeSArray::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeSArray::defaultInit() '%s'\n", toChars());
#endif
return next->defaultInit(loc);
}
int TypeSArray::isZeroInit()
{
return next->isZeroInit();
}
Expression *TypeSArray::toExpression()
{
Expression *e = next->toExpression();
if (e)
{ Expressions *arguments = new Expressions();
arguments->push(dim);
e = new ArrayExp(dim->loc, e, arguments);
}
return e;
}
int TypeSArray::hasPointers()
{
return next->hasPointers();
}
/***************************** TypeDArray *****************************/
TypeDArray::TypeDArray(Type *t)
: TypeArray(Tarray, t)
{
//printf("TypeDArray(t = %p)\n", t);
}
Type *TypeDArray::syntaxCopy()
{
Type *t = next->syntaxCopy();
if (t == next)
t = this;
else
{ t = new TypeDArray(t);
t->mod = mod;
}
return t;
}
d_uns64 TypeDArray::size(Loc loc)
{
//printf("TypeDArray::size()\n");
return PTRSIZE * 2;
}
unsigned TypeDArray::alignsize()
{
// A DArray consists of two ptr-sized values, so align it on pointer size
// boundary
return PTRSIZE;
}
Type *TypeDArray::semantic(Loc loc, Scope *sc)
{ Type *tn = next;
tn = next->semantic(loc,sc);
Type *tbn = tn->toBasetype();
switch (tbn->ty)
{
case Tfunction:
case Tnone:
case Ttuple:
error(loc, "can't have array of %s", tbn->toChars());
tn = next = tint32;
break;
}
if (tn->isauto())
error(loc, "cannot have array of auto %s", tn->toChars());
if (mod == MODconst && !tn->isInvariant())
tn = tn->constOf();
else if (mod == MODinvariant)
tn = tn->invariantOf();
next = tn;
return merge();
}
void TypeDArray::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
if (next)
next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
}
void TypeDArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
buf->writestring("[]");
}
Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::length)
{
if (e->op == TOKstring)
{ StringExp *se = (StringExp *)e;
return new IntegerExp(se->loc, se->len, Type::tindex);
}
e = new ArrayLengthExp(e->loc, e);
e->type = Type::tsize_t;
return e;
}
else if (ident == Id::ptr)
{
e = e->castTo(sc, next->pointerTo());
return e;
}
else
{
e = TypeArray::dotExp(sc, e, ident);
}
return e;
}
int TypeDArray::isString()
{
TY nty = next->toBasetype()->ty;
return nty == Tchar || nty == Twchar || nty == Tdchar;
}
MATCH TypeDArray::implicitConvTo(Type *to)
{
//printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
if (equals(to))
return MATCHexact;
// Allow implicit conversion of array to pointer
if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer)
{
TypePointer *tp = (TypePointer *)to;
/* Allow conversion to void*
*/
if (tp->next->ty == Tvoid &&
(next->mod == tp->next->mod || tp->next->mod == MODconst))
{
return MATCHconvert;
}
return next->constConv(to);
}
if (to->ty == Tarray)
{ int offset = 0;
TypeDArray *ta = (TypeDArray *)to;
if (!(next->mod == ta->next->mod || ta->next->mod == MODconst))
return MATCHnomatch; // not const-compatible
/* Allow conversion to void[]
*/
if (next->ty != Tvoid && ta->next->ty == Tvoid)
{
return MATCHconvert;
}
MATCH m = next->constConv(ta->next);
if (m != MATCHnomatch)
{
if (m == MATCHexact && mod != to->mod)
m = MATCHconst;
return m;
}
/* Allow conversions of T[][] to const(T)[][]
*/
if (mod == ta->mod && next->ty == Tarray && ta->next->ty == Tarray)
{
m = next->implicitConvTo(ta->next);
if (m == MATCHconst)
return m;
}
/* Conversion of array of derived to array of base
*/
if (ta->next->isBaseOf(next, &offset) && offset == 0)
return MATCHconvert;
}
return Type::implicitConvTo(to);
}
Expression *TypeDArray::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeDArray::defaultInit() '%s'\n", toChars());
#endif
Expression *e;
e = new NullExp(loc);
e->type = this;
return e;
}
int TypeDArray::isZeroInit()
{
return 1;
}
int TypeDArray::checkBoolean()
{
return TRUE;
}
int TypeDArray::hasPointers()
{
return TRUE;
}
/***************************** TypeAArray *****************************/
TypeAArray::TypeAArray(Type *t, Type *index)
: TypeArray(Taarray, t)
{
this->index = index;
}
Type *TypeAArray::syntaxCopy()
{
Type *t = next->syntaxCopy();
Type *ti = index->syntaxCopy();
if (t == next && ti == index)
t = this;
else
{ t = new TypeAArray(t, ti);
t->mod = mod;
}
return t;
}
d_uns64 TypeAArray::size(Loc loc)
{
return PTRSIZE /* * 2*/;
}
Type *TypeAArray::semantic(Loc loc, Scope *sc)
{
//printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty);
// Deal with the case where we thought the index was a type, but
// in reality it was an expression.
if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
{
Expression *e;
Type *t;
Dsymbol *s;
index->resolve(loc, sc, &e, &t, &s);
if (e)
{ // It was an expression -
// Rewrite as a static array
TypeSArray *tsa;
tsa = new TypeSArray(next, e);
return tsa->semantic(loc,sc);
}
else if (t)
index = t;
else
index->error(loc, "index is not a type or an expression");
}
else
index = index->semantic(loc,sc);
if (index->nextOf() && !index->nextOf()->isInvariant())
{
index = index->constOf()->mutableOf();
}
switch (index->toBasetype()->ty)
{
case Tbool:
case Tfunction:
case Tvoid:
case Tnone:
error(loc, "can't have associative array key of %s", index->toBasetype()->toChars());
break;
}
next = next->semantic(loc,sc);
if (mod == MODconst && !next->isInvariant())
next = next->constOf();
else if (mod == MODinvariant)
next = next->invariantOf();
switch (next->toBasetype()->ty)
{
case Tfunction:
case Tnone:
error(loc, "can't have associative array of %s", next->toChars());
break;
}
if (next->isauto())
error(loc, "cannot have array of auto %s", next->toChars());
return merge();
}
void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
//printf("TypeAArray::resolve() %s\n", toChars());
// Deal with the case where we thought the index was a type, but
// in reality it was an expression.
if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
{
Expression *e;
Type *t;
Dsymbol *s;
index->resolve(loc, sc, &e, &t, &s);
if (e)
{ // It was an expression -
// Rewrite as a static array
TypeSArray *tsa = new TypeSArray(next, e);
return tsa->resolve(loc, sc, pe, pt, ps);
}
else if (t)
index = t;
else
index->error(loc, "index is not a type or an expression");
}
Type::resolve(loc, sc, pe, pt, ps);
}
Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::length)
{
Expression *ec;
Expressions *arguments;
//LDC: Build arguments.
static FuncDeclaration *aaLen_fd = NULL;
if(!aaLen_fd) {
Arguments* args = new Arguments;
args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
aaLen_fd = FuncDeclaration::genCfunc(args, Type::tsize_t, Id::aaLen);
}
ec = new VarExp(0, aaLen_fd);
arguments = new Expressions();
arguments->push(e);
e = new CallExp(e->loc, ec, arguments);
e->type = ((TypeFunction *)aaLen_fd->type)->next;
}
else if (ident == Id::keys)
{
Expression *ec;
Expressions *arguments;
int size = index->size(e->loc);
assert(size);
//LDC: Build arguments.
static FuncDeclaration *aaKeys_fd = NULL;
if(!aaKeys_fd) {
Arguments* args = new Arguments;
args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
aaKeys_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::aaKeys);
}
ec = new VarExp(0, aaKeys_fd);
arguments = new Expressions();
arguments->push(e);
arguments->push(new IntegerExp(0, size, Type::tsize_t));
e = new CallExp(e->loc, ec, arguments);
e->type = index->arrayOf();
}
else if (ident == Id::values)
{
Expression *ec;
Expressions *arguments;
//LDC: Build arguments.
static FuncDeclaration *aaValues_fd = NULL;
if(!aaValues_fd) {
Arguments* args = new Arguments;
args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
aaValues_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::aaValues);
}
ec = new VarExp(0, aaValues_fd);
arguments = new Expressions();
arguments->push(e);
size_t keysize = index->size(e->loc);
keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1);
arguments->push(new IntegerExp(0, keysize, Type::tsize_t));
arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t));
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else if (ident == Id::rehash)
{
Expression *ec;
Expressions *arguments;
//LDC: Build arguments.
static FuncDeclaration *aaRehash_fd = NULL;
if(!aaRehash_fd) {
Arguments* args = new Arguments;
args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL));
aaRehash_fd = FuncDeclaration::genCfunc(args, Type::tvoidptr, Id::aaRehash);
}
ec = new VarExp(0, aaRehash_fd);
arguments = new Expressions();
arguments->push(e->addressOf(sc));
arguments->push(index->getInternalTypeInfo(sc));
e = new CallExp(e->loc, ec, arguments);
e->type = this;
}
else
{
e = Type::dotExp(sc, e, ident);
}
return e;
}
void TypeAArray::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
index->toDecoBuffer(buf);
next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod);
}
void TypeAArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
buf->writeByte('[');
index->toCBuffer2(buf, hgs, 0);
buf->writeByte(']');
}
Expression *TypeAArray::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeAArray::defaultInit() '%s'\n", toChars());
#endif
Expression *e;
e = new NullExp(loc);
e->type = this;
return e;
}
int TypeAArray::isZeroInit()
{
return TRUE;
}
int TypeAArray::checkBoolean()
{
return TRUE;
}
int TypeAArray::hasPointers()
{
return TRUE;
}
MATCH TypeAArray::implicitConvTo(Type *to)
{
//printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
if (equals(to))
return MATCHexact;
if (to->ty == Taarray)
{ TypeAArray *ta = (TypeAArray *)to;
if (!(next->mod == ta->next->mod || ta->next->mod == MODconst))
return MATCHnomatch; // not const-compatible
if (!(index->mod == ta->index->mod || ta->index->mod == MODconst))
return MATCHnomatch; // not const-compatible
MATCH m = next->constConv(ta->next);
MATCH mi = index->constConv(ta->index);
if (m != MATCHnomatch && mi != MATCHnomatch)
{
if (m == MATCHexact && mod != to->mod)
m = MATCHconst;
if (mi < m)
m = mi;
return m;
}
}
return Type::implicitConvTo(to);
}
MATCH TypeAArray::constConv(Type *to)
{
if (to->ty == Taarray)
{
TypeAArray *taa = (TypeAArray *)to;
MATCH mindex = index->constConv(taa->index);
MATCH mkey = next->constConv(taa->next);
// Pick the worst match
return mkey < mindex ? mkey : mindex;
}
else
return Type::constConv(to);
}
/***************************** TypePointer *****************************/
TypePointer::TypePointer(Type *t)
: TypeNext(Tpointer, t)
{
}
Type *TypePointer::syntaxCopy()
{
Type *t = next->syntaxCopy();
if (t == next)
t = this;
else
{ t = new TypePointer(t);
t->mod = mod;
}
return t;
}
Type *TypePointer::semantic(Loc loc, Scope *sc)
{
//printf("TypePointer::semantic()\n");
Type *n = next->semantic(loc, sc);
switch (n->toBasetype()->ty)
{
case Ttuple:
error(loc, "can't have pointer to %s", n->toChars());
n = tint32;
break;
}
if (n != next)
deco = NULL;
next = n;
if (mod == MODconst && !next->isInvariant())
next = next->constOf();
else if (mod == MODinvariant)
next = next->invariantOf();
return merge();
}
d_uns64 TypePointer::size(Loc loc)
{
return PTRSIZE;
}
void TypePointer::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
//printf("TypePointer::toCBuffer2() next = %d\n", next->ty);
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
if (next->ty != Tfunction)
buf->writeByte('*');
}
MATCH TypePointer::implicitConvTo(Type *to)
{
//printf("TypePointer::implicitConvTo(to = %s) %s\n", to->toChars(), toChars());
if (equals(to))
return MATCHexact;
if (to->ty == Tpointer)
{ TypePointer *tp = (TypePointer *)to;
assert(tp->next);
if (!(next->mod == tp->next->mod || tp->next->mod == MODconst))
return MATCHnomatch; // not const-compatible
/* Alloc conversion to void[]
*/
if (next->ty != Tvoid && tp->next->ty == Tvoid)
{
return MATCHconvert;
}
MATCH m = next->constConv(tp->next);
if (m != MATCHnomatch)
{
if (m == MATCHexact && mod != to->mod)
m = MATCHconst;
return m;
}
/* Conversion of ptr to derived to ptr to base
*/
int offset = 0;
if (tp->next->isBaseOf(next, &offset) && offset == 0)
return MATCHconvert;
}
return MATCHnomatch;
}
int TypePointer::isscalar()
{
return TRUE;
}
Expression *TypePointer::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypePointer::defaultInit() '%s'\n", toChars());
#endif
Expression *e;
e = new NullExp(loc);
e->type = this;
return e;
}
int TypePointer::isZeroInit()
{
return 1;
}
int TypePointer::hasPointers()
{
return TRUE;
}
/***************************** TypeReference *****************************/
TypeReference::TypeReference(Type *t)
: TypeNext(Treference, t)
{
// BUG: what about references to static arrays?
}
Type *TypeReference::syntaxCopy()
{
Type *t = next->syntaxCopy();
if (t == next)
t = this;
else
{ t = new TypeReference(t);
t->mod = mod;
}
return t;
}
Type *TypeReference::semantic(Loc loc, Scope *sc)
{
//printf("TypeReference::semantic()\n");
Type *n = next->semantic(loc, sc);
if (n != next)
deco = NULL;
next = n;
if (mod == MODconst && !next->isInvariant())
next = next->constOf();
else if (mod == MODinvariant)
next = next->invariantOf();
return merge();
}
d_uns64 TypeReference::size(Loc loc)
{
return PTRSIZE;
}
void TypeReference::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
buf->writeByte('&');
}
Expression *TypeReference::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
// References just forward things along
return next->dotExp(sc, e, ident);
}
Expression *TypeReference::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeReference::defaultInit() '%s'\n", toChars());
#endif
Expression *e = new NullExp(loc);
e->type = this;
return e;
}
int TypeReference::isZeroInit()
{
return 1;
}
/***************************** TypeFunction *****************************/
TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage)
: TypeNext(Tfunction, treturn)
{
//if (!treturn) *(char*)0=0;
// assert(treturn);
assert(0 <= varargs && varargs <= 2);
this->parameters = parameters;
this->varargs = varargs;
this->linkage = linkage;
this->inuse = 0;
this->isnothrow = false;
this->ispure = false;
this->isref = false;
// LDC
this->fty = NULL;
}
Type *TypeFunction::syntaxCopy()
{
Type *treturn = next ? next->syntaxCopy() : NULL;
Arguments *params = Argument::arraySyntaxCopy(parameters);
TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage);
t->mod = mod;
t->isnothrow = isnothrow;
t->ispure = ispure;
t->isref = isref;
return t;
}
/*******************************
* Returns:
* 0 types are distinct
* 1 this is covariant with t
* 2 arguments match as far as overloading goes,
* but types are not covariant
* 3 cannot determine covariance because of forward references
*/
int Type::covariant(Type *t)
{
#if 0
printf("Type::covariant(t = %s) %s\n", t->toChars(), toChars());
printf("deco = %p, %p\n", deco, t->deco);
// printf("ty = %d\n", next->ty);
#endif
int inoutmismatch = 0;
TypeFunction *t1;
TypeFunction *t2;
if (equals(t))
return 1; // covariant
if (ty != Tfunction || t->ty != Tfunction)
goto Ldistinct;
t1 = (TypeFunction *)this;
t2 = (TypeFunction *)t;
if (t1->varargs != t2->varargs)
goto Ldistinct;
if (t1->parameters && t2->parameters)
{
size_t dim = Argument::dim(t1->parameters);
if (dim != Argument::dim(t2->parameters))
goto Ldistinct;
for (size_t i = 0; i < dim; i++)
{ Argument *arg1 = Argument::getNth(t1->parameters, i);
Argument *arg2 = Argument::getNth(t2->parameters, i);
if (!arg1->type->equals(arg2->type))
goto Ldistinct;
if ((arg1->storageClass & ~STCscope) != (arg2->storageClass & ~STCscope))
inoutmismatch = 1;
// We can add scope, but not subtract it
if (!(arg1->storageClass & STCscope) && (arg2->storageClass & STCscope))
inoutmismatch = 1;
}
}
else if (t1->parameters != t2->parameters)
goto Ldistinct;
// The argument lists match
if (inoutmismatch)
goto Lnotcovariant;
if (t1->linkage != t2->linkage)
goto Lnotcovariant;
{
// Return types
Type *t1n = t1->next;
Type *t2n = t2->next;
if (t1n->equals(t2n))
goto Lcovariant;
if (t1n->ty == Tclass && t2n->ty == Tclass)
{
/* If same class type, but t2n is const, then it's
* covariant. Do this test first because it can work on
* forward references.
*/
if (((TypeClass *)t1n)->sym == ((TypeClass *)t2n)->sym &&
t2n->mod == MODconst)
goto Lcovariant;
// If t1n is forward referenced:
ClassDeclaration *cd = ((TypeClass *)t1n)->sym;
if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration())
{
return 3;
}
}
if (t1n->implicitConvTo(t2n))
goto Lcovariant;
}
goto Lnotcovariant;
Lcovariant:
/* Can convert pure to impure, and nothrow to throw
*/
if (!t1->ispure && t2->ispure)
goto Lnotcovariant;
if (!t1->isnothrow && t2->isnothrow)
goto Lnotcovariant;
if (t1->isref != t2->isref)
goto Lnotcovariant;
//printf("\tcovaraint: 1\n");
return 1;
Ldistinct:
//printf("\tcovaraint: 0\n");
return 0;
Lnotcovariant:
//printf("\tcovaraint: 2\n");
return 2;
}
void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag)
{ unsigned char mc;
//printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars());
//static int nest; if (++nest == 50) *(char*)0=0;
if (inuse)
{ inuse = 2; // flag error to caller
return;
}
inuse++;
#if 1
if (mod & MODshared)
buf->writeByte('O');
if (mod & MODconst)
buf->writeByte('x');
else if (mod & MODinvariant)
buf->writeByte('y');
#endif
switch (linkage)
{
case LINKd: mc = 'F'; break;
case LINKc: mc = 'U'; break;
case LINKwindows: mc = 'W'; break;
case LINKpascal: mc = 'V'; break;
case LINKcpp: mc = 'R'; break;
// LDC
case LINKintrinsic: mc = 'Q'; break;
default:
assert(0);
}
buf->writeByte(mc);
if (ispure || isnothrow || isref)
{
if (ispure)
buf->writestring("Na");
if (isnothrow)
buf->writestring("Nb");
if (isref)
buf->writestring("Nc");
}
// Write argument types
Argument::argsToDecoBuffer(buf, parameters);
//if (buf->data[buf->offset - 1] == '@') halt();
buf->writeByte('Z' - varargs); // mark end of arg list
next->toDecoBuffer(buf);
inuse--;
}
void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
{
//printf("TypeFunction::toCBuffer() this = %p %s\n", this, toChars());
const char *p = NULL;
if (inuse)
{ inuse = 2; // flag error to caller
return;
}
inuse++;
/* Use 'storage class' style for attributes
*/
if (mod & MODconst)
buf->writestring("const ");
if (mod & MODinvariant)
buf->writestring("invariant ");
if (mod & MODshared)
buf->writestring("shared ");
if (ispure)
buf->writestring("pure ");
if (isnothrow)
buf->writestring("nothrow ");
if (isref)
buf->writestring("ref ");
if (next && (!ident || ident->toHChars2() == ident->toChars()))
next->toCBuffer2(buf, hgs, 0);
if (hgs->ddoc != 1)
{
switch (linkage)
{
case LINKd: p = NULL; break;
case LINKc: p = "C "; break;
case LINKwindows: p = "Windows "; break;
case LINKpascal: p = "Pascal "; break;
case LINKcpp: p = "C++ "; break;
// LDC
case LINKintrinsic: p = "Intrinsic"; break;
default:
assert(0);
}
}
if (!hgs->hdrgen && p)
buf->writestring(p);
if (ident)
{ buf->writeByte(' ');
buf->writestring(ident->toHChars2());
}
Argument::argsToCBuffer(buf, hgs, parameters, varargs);
inuse--;
}
void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
//printf("TypeFunction::toCBuffer2() this = %p %s\n", this, toChars());
const char *p = NULL;
if (inuse)
{ inuse = 2; // flag error to caller
return;
}
inuse++;
if (next)
next->toCBuffer2(buf, hgs, 0);
if (hgs->ddoc != 1)
{
switch (linkage)
{
case LINKd: p = NULL; break;
case LINKc: p = "C "; break;
case LINKwindows: p = "Windows "; break;
case LINKpascal: p = "Pascal "; break;
case LINKcpp: p = "C++ "; break;
// LDC
case LINKintrinsic: p = "Intrinsic"; break;
default:
assert(0);
}
}
if (!hgs->hdrgen && p)
buf->writestring(p);
buf->writestring(" function");
Argument::argsToCBuffer(buf, hgs, parameters, varargs);
/* Use postfix style for attributes
*/
if (mod != this->mod)
{
if (mod & MODconst)
buf->writestring(" const");
if (mod & MODinvariant)
buf->writestring(" invariant");
if (mod & MODshared)
buf->writestring(" shared");
}
if (ispure)
buf->writestring(" pure");
if (isnothrow)
buf->writestring(" nothrow");
if (isref)
buf->writestring(" ref");
inuse--;
}
Type *TypeFunction::semantic(Loc loc, Scope *sc)
{
if (deco) // if semantic() already run
{
//printf("already done\n");
return this;
}
//printf("TypeFunction::semantic() this = %p\n", this);
TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction));
memcpy(tf, this, sizeof(TypeFunction));
if (parameters)
{ tf->parameters = (Arguments *)parameters->copy();
for (size_t i = 0; i < parameters->dim; i++)
{ Argument *arg = (Argument *)parameters->data[i];
Argument *cpy = (Argument *)mem.malloc(sizeof(Argument));
memcpy(cpy, arg, sizeof(Argument));
tf->parameters->data[i] = (void *)cpy;
}
}
if (sc->stc & STCpure)
tf->ispure = TRUE;
if (sc->stc & STCnothrow)
tf->isnothrow = TRUE;
if (sc->stc & STCref)
tf->isref = TRUE;
tf->linkage = sc->linkage;
if (!tf->next)
{
assert(global.errors);
tf->next = tvoid;
}
tf->next = tf->next->semantic(loc,sc);
if (tf->next->toBasetype()->ty == Tsarray)
{ error(loc, "functions cannot return static array %s", tf->next->toChars());
tf->next = Type::terror;
}
if (tf->next->toBasetype()->ty == Tfunction)
{ error(loc, "functions cannot return a function");
tf->next = Type::terror;
}
if (tf->next->toBasetype()->ty == Ttuple)
{ error(loc, "functions cannot return a tuple");
tf->next = Type::terror;
}
if (tf->next->isauto() && !(sc->flags & SCOPEctor))
error(loc, "functions cannot return auto %s", tf->next->toChars());
if (tf->parameters)
{ size_t dim = Argument::dim(tf->parameters);
for (size_t i = 0; i < dim; i++)
{ Argument *arg = Argument::getNth(tf->parameters, i);
tf->inuse++;
arg->type = arg->type->semantic(loc,sc);
if (tf->inuse == 1) tf->inuse--;
if (arg->storageClass & (STCconst | STCin))
{
if (!arg->type->isInvariant())
arg->type = arg->type->constOf();
}
else if (arg->storageClass & STCinvariant)
arg->type = arg->type->invariantOf();
if (arg->storageClass & (STCauto | STCalias | STCstatic))
{
if (!arg->type)
continue;
}
Type *t = arg->type->toBasetype();
if (arg->storageClass & (STCout | STCref | STClazy))
{
if (t->ty == Tsarray)
error(loc, "cannot have out or ref parameter of type %s", t->toChars());
if (arg->storageClass & STCout && arg->type->mod)
error(loc, "cannot have const/invariant out parameter of type %s", t->toChars());
}
if (!(arg->storageClass & STClazy) && t->ty == Tvoid)
error(loc, "cannot have parameter of type %s", arg->type->toChars());
if (arg->defaultArg)
{
arg->defaultArg = arg->defaultArg->semantic(sc);
arg->defaultArg = resolveProperties(sc, arg->defaultArg);
arg->defaultArg = arg->defaultArg->implicitCastTo(sc, arg->type);
}
/* If arg turns out to be a tuple, the number of parameters may
* change.
*/
if (t->ty == Ttuple)
{ dim = Argument::dim(tf->parameters);
i--;
}
}
}
tf->deco = tf->merge()->deco;
if (tf->inuse)
{ error(loc, "recursive type");
tf->inuse = 0;
return terror;
}
if (tf->varargs == 1 && tf->linkage != LINKd && Argument::dim(tf->parameters) == 0)
error(loc, "variadic functions with non-D linkage must have at least one parameter");
/* Don't return merge(), because arg identifiers and default args
* can be different
* even though the types match
*/
return tf;
}
/********************************
* 'args' are being matched to function 'this'
* Determine match level.
* Returns:
* MATCHxxxx
*/
int TypeFunction::callMatch(Expression *ethis, Expressions *args)
{
//printf("TypeFunction::callMatch() %s\n", toChars());
MATCH match = MATCHexact; // assume exact match
if (ethis)
{ Type *t = ethis->type;
if (t->toBasetype()->ty == Tpointer)
t = t->toBasetype()->nextOf(); // change struct* to struct
if (t->mod != mod)
{
if (mod == MODconst)
match = MATCHconst;
else
return MATCHnomatch;
}
}
size_t nparams = Argument::dim(parameters);
size_t nargs = args ? args->dim : 0;
if (nparams == nargs)
;
else if (nargs > nparams)
{
if (varargs == 0)
goto Nomatch; // too many args; no match
match = MATCHconvert; // match ... with a "conversion" match level
}
for (size_t u = 0; u < nparams; u++)
{ MATCH m;
Expression *arg;
// BUG: what about out and ref?
Argument *p = Argument::getNth(parameters, u);
assert(p);
if (u >= nargs)
{
if (p->defaultArg)
continue;
if (varargs == 2 && u + 1 == nparams)
goto L1;
goto Nomatch; // not enough arguments
}
arg = (Expression *)args->data[u];
assert(arg);
// Non-lvalues do not match ref or out parameters
if (p->storageClass & (STCref | STCout) && !arg->isLvalue())
goto Nomatch;
if (p->storageClass & STClazy && p->type->ty == Tvoid &&
arg->type->ty != Tvoid)
m = MATCHconvert;
else
m = arg->implicitConvTo(p->type);
//printf("\tm = %d\n", m);
if (m == MATCHnomatch) // if no match
{
L1:
if (varargs == 2 && u + 1 == nparams) // if last varargs param
{ Type *tb = p->type->toBasetype();
TypeSArray *tsa;
integer_t sz;
switch (tb->ty)
{
case Tsarray:
tsa = (TypeSArray *)tb;
sz = tsa->dim->toInteger();
if (sz != nargs - u)
goto Nomatch;
case Tarray:
{ TypeArray *ta = (TypeArray *)tb;
for (; u < nargs; u++)
{
arg = (Expression *)args->data[u];
assert(arg);
#if 1
/* If lazy array of delegates,
* convert arg(s) to delegate(s)
*/
Type *tret = p->isLazyArray();
if (tret)
{
if (ta->next->equals(arg->type))
{ m = MATCHexact;
}
else
{
m = arg->implicitConvTo(tret);
if (m == MATCHnomatch)
{
if (tret->toBasetype()->ty == Tvoid)
m = MATCHconvert;
}
}
}
else
m = arg->implicitConvTo(ta->next);
#else
m = arg->implicitConvTo(ta->next);
#endif
if (m == MATCHnomatch)
goto Nomatch;
if (m < match)
match = m;
}
goto Ldone;
}
case Tclass:
// Should see if there's a constructor match?
// Or just leave it ambiguous?
goto Ldone;
default:
goto Nomatch;
}
}
goto Nomatch;
}
if (m < match)
match = m; // pick worst match
}
Ldone:
//printf("match = %d\n", match);
return match;
Nomatch:
//printf("no match\n");
return MATCHnomatch;
}
Type *TypeFunction::reliesOnTident()
{
if (parameters)
{
for (size_t i = 0; i < parameters->dim; i++)
{ Argument *arg = (Argument *)parameters->data[i];
Type *t = arg->type->reliesOnTident();
if (t)
return t;
}
}
return next->reliesOnTident();
}
/***************************
* Examine function signature for parameter p and see if
* p can 'escape' the scope of the function.
*/
bool TypeFunction::parameterEscapes(Argument *p)
{
/* Scope parameters do not escape.
* Allow 'lazy' to imply 'scope' -
* lazy parameters can be passed along
* as lazy parameters to the next function, but that isn't
* escaping.
*/
if (p->storageClass & (STCscope | STClazy))
return FALSE;
if (ispure)
{ /* With pure functions, we need only be concerned if p escapes
* via any return statement.
*/
Type* tret = nextOf()->toBasetype();
if (!isref && !tret->hasPointers())
{ /* The result has no references, so p could not be escaping
* that way.
*/
return FALSE;
}
}
/* Assume it escapes in the absence of better information.
*/
return TRUE;
}
/***************************** TypeDelegate *****************************/
TypeDelegate::TypeDelegate(Type *t)
: TypeNext(Tfunction, t)
{
ty = Tdelegate;
}
Type *TypeDelegate::syntaxCopy()
{
Type *t = next->syntaxCopy();
if (t == next)
t = this;
else
{ t = new TypeDelegate(t);
t->mod = mod;
}
return t;
}
Type *TypeDelegate::semantic(Loc loc, Scope *sc)
{
if (deco) // if semantic() already run
{
//printf("already done\n");
return this;
}
next = next->semantic(loc,sc);
return merge();
}
d_uns64 TypeDelegate::size(Loc loc)
{
return PTRSIZE * 2;
}
// LDC added, no reason to align to 2*PTRSIZE
unsigned TypeDelegate::alignsize()
{
// A Delegate consists of two ptr values, so align it on pointer size
// boundary
return PTRSIZE;
}
void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
TypeFunction *tf = (TypeFunction *)next;
tf->next->toCBuffer2(buf, hgs, 0);
buf->writestring(" delegate");
Argument::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs);
}
Expression *TypeDelegate::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeDelegate::defaultInit() '%s'\n", toChars());
#endif
Expression *e;
e = new NullExp(loc);
e->type = this;
return e;
}
int TypeDelegate::isZeroInit()
{
return 1;
}
int TypeDelegate::checkBoolean()
{
return TRUE;
}
Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::ptr)
{
e = new GEPExp(e->loc, e, ident, 0);
e->type = tvoidptr;
return e;
}
else if (ident == Id::funcptr)
{
e = new GEPExp(e->loc, e, ident, 1);
e->type = tvoidptr;
return e;
}
else
{
e = Type::dotExp(sc, e, ident);
}
return e;
}
int TypeDelegate::hasPointers()
{
return TRUE;
}
/***************************** TypeQualified *****************************/
TypeQualified::TypeQualified(TY ty, Loc loc)
: Type(ty)
{
this->loc = loc;
}
void TypeQualified::syntaxCopyHelper(TypeQualified *t)
{
//printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars());
idents.setDim(t->idents.dim);
for (int i = 0; i < idents.dim; i++)
{
Identifier *id = (Identifier *)t->idents.data[i];
if (id->dyncast() == DYNCAST_DSYMBOL)
{
TemplateInstance *ti = (TemplateInstance *)id;
ti = (TemplateInstance *)ti->syntaxCopy(NULL);
id = (Identifier *)ti;
}
idents.data[i] = id;
}
}
void TypeQualified::addIdent(Identifier *ident)
{
idents.push(ident);
}
void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs)
{
int i;
for (i = 0; i < idents.dim; i++)
{ Identifier *id = (Identifier *)idents.data[i];
buf->writeByte('.');
if (id->dyncast() == DYNCAST_DSYMBOL)
{
TemplateInstance *ti = (TemplateInstance *)id;
ti->toCBuffer(buf, hgs);
}
else
buf->writestring(id->toChars());
}
}
d_uns64 TypeQualified::size(Loc loc)
{
error(this->loc, "size of type %s is not known", toChars());
return 1;
}
/*************************************
* Takes an array of Identifiers and figures out if
* it represents a Type or an Expression.
* Output:
* if expression, *pe is set
* if type, *pt is set
*/
void TypeQualified::resolveHelper(Loc loc, Scope *sc,
Dsymbol *s, Dsymbol *scopesym,
Expression **pe, Type **pt, Dsymbol **ps)
{
VarDeclaration *v;
EnumMember *em;
TupleDeclaration *td;
Expression *e;
#if 0
printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars());
if (scopesym)
printf("\tscopesym = '%s'\n", scopesym->toChars());
#endif
*pe = NULL;
*pt = NULL;
*ps = NULL;
if (s)
{
//printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
s->checkDeprecated(loc, sc); // check for deprecated aliases
s = s->toAlias();
//printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
for (int i = 0; i < idents.dim; i++)
{
Identifier *id = (Identifier *)idents.data[i];
Dsymbol *sm = s->searchX(loc, sc, id);
//printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
//printf("\tgetType = '%s'\n", s->getType()->toChars());
if (!sm)
{ Type *t;
v = s->isVarDeclaration();
if (v && id == Id::length)
{
e = v->getConstInitializer();
if (!e)
e = new VarExp(loc, v);
t = e->type;
if (!t)
goto Lerror;
goto L3;
}
t = s->getType();
if (!t && s->isDeclaration())
t = s->isDeclaration()->type;
if (t)
{
sm = t->toDsymbol(sc);
if (sm)
{ sm = sm->search(loc, id, 0);
if (sm)
goto L2;
}
//e = t->getProperty(loc, id);
e = new TypeExp(loc, t);
e = t->dotExp(sc, e, id);
i++;
L3:
for (; i < idents.dim; i++)
{
id = (Identifier *)idents.data[i];
//printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type);
if (id == Id::offsetof)
{ e = new DotIdExp(e->loc, e, id);
e = e->semantic(sc);
}
else
e = e->type->dotExp(sc, e, id);
}
*pe = e;
}
else
Lerror:
error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars());
return;
}
L2:
s = sm->toAlias();
}
v = s->isVarDeclaration();
if (v)
{
#if 0
// It's not a type, it's an expression
Expression *e = v->getConstInitializer();
if (e)
{
*pe = e->copy(); // make copy so we can change loc
(*pe)->loc = loc;
}
else
#endif
{
#if 0
WithScopeSymbol *withsym;
if (scopesym && (withsym = scopesym->isWithScopeSymbol()) != NULL)
{
// Same as wthis.ident
e = new VarExp(loc, withsym->withstate->wthis);
e = new DotIdExp(loc, e, ident);
//assert(0); // BUG: should handle this
}
else
#endif
*pe = new VarExp(loc, v);
}
return;
}
em = s->isEnumMember();
if (em)
{
// It's not a type, it's an expression
*pe = em->value->copy();
return;
}
L1:
Type *t = s->getType();
if (!t)
{
// If the symbol is an import, try looking inside the import
Import *si;
si = s->isImport();
if (si)
{
s = si->search(loc, s->ident, 0);
if (s && s != si)
goto L1;
s = si;
}
*ps = s;
return;
}
if (t->ty == Tinstance && t != this && !t->deco)
{ error(loc, "forward reference to '%s'", t->toChars());
return;
}
if (t != this)
{
if (t->reliesOnTident())
{
Scope *scx;
for (scx = sc; 1; scx = scx->enclosing)
{
if (!scx)
{ error(loc, "forward reference to '%s'", t->toChars());
return;
}
if (scx->scopesym == scopesym)
break;
}
t = t->semantic(loc, scx);
//((TypeIdentifier *)t)->resolve(loc, scx, pe, &t, ps);
}
}
if (t->ty == Ttuple)
*pt = t->syntaxCopy();
else
*pt = t->merge();
}
if (!s)
{
error(loc, "identifier '%s' is not defined", toChars());
}
}
/***************************** TypeIdentifier *****************************/
TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident)
: TypeQualified(Tident, loc)
{
this->ident = ident;
}
Type *TypeIdentifier::syntaxCopy()
{
TypeIdentifier *t;
t = new TypeIdentifier(loc, ident);
t->syntaxCopyHelper(this);
t->mod = mod;
return t;
}
void TypeIdentifier::toDecoBuffer(OutBuffer *buf, int flag)
{ unsigned len;
char *name;
Type::toDecoBuffer(buf, flag);
name = ident->toChars();
len = strlen(name);
buf->printf("%d%s", len, name);
}
void TypeIdentifier::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(this->ident->toChars());
toCBuffer2Helper(buf, hgs);
}
/*************************************
* Takes an array of Identifiers and figures out if
* it represents a Type or an Expression.
* Output:
* if expression, *pe is set
* if type, *pt is set
*/
void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{ Dsymbol *s;
Dsymbol *scopesym;
//printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars());
s = sc->search(loc, ident, &scopesym);
resolveHelper(loc, sc, s, scopesym, pe, pt, ps);
if (*pt && mod)
{
if (mod & MODconst)
*pt = (*pt)->constOf();
else if (mod & MODinvariant)
*pt = (*pt)->invariantOf();
}
}
/*****************************************
* See if type resolves to a symbol, if so,
* return that symbol.
*/
Dsymbol *TypeIdentifier::toDsymbol(Scope *sc)
{
//printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
if (!sc)
return NULL;
//printf("ident = '%s'\n", ident->toChars());
Dsymbol *scopesym;
Dsymbol *s = sc->search(loc, ident, &scopesym);
if (s)
{
for (int i = 0; i < idents.dim; i++)
{
Identifier *id = (Identifier *)idents.data[i];
s = s->searchX(loc, sc, id);
if (!s) // failed to find a symbol
{ //printf("\tdidn't find a symbol\n");
break;
}
}
}
return s;
}
Type *TypeIdentifier::semantic(Loc loc, Scope *sc)
{
Type *t;
Expression *e;
Dsymbol *s;
//printf("TypeIdentifier::semantic(%s)\n", toChars());
resolve(loc, sc, &e, &t, &s);
if (t)
{
//printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
if (t->ty == Ttypedef)
{ TypeTypedef *tt = (TypeTypedef *)t;
if (tt->sym->sem == 1)
error(loc, "circular reference of typedef %s", tt->toChars());
}
if (isConst())
t = t->constOf();
else if (isInvariant())
t = t->invariantOf();
}
else
{
#ifdef DEBUG
if (!global.gag)
printf("1: ");
#endif
if (s)
{
s->error(loc, "is used as a type");
//halt();
}
else
error(loc, "%s is used as a type", toChars());
t = tvoid;
}
//t->print();
return t;
}
Type *TypeIdentifier::reliesOnTident()
{
return this;
}
Expression *TypeIdentifier::toExpression()
{
Expression *e = new IdentifierExp(loc, ident);
for (int i = 0; i < idents.dim; i++)
{
Identifier *id = (Identifier *)idents.data[i];
e = new DotIdExp(loc, e, id);
}
return e;
}
/***************************** TypeInstance *****************************/
TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst)
: TypeQualified(Tinstance, loc)
{
this->tempinst = tempinst;
}
Type *TypeInstance::syntaxCopy()
{
//printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim);
TypeInstance *t;
t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL));
t->syntaxCopyHelper(this);
t->mod = mod;
return t;
}
void TypeInstance::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
tempinst->toCBuffer(buf, hgs);
toCBuffer2Helper(buf, hgs);
}
void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
// Note close similarity to TypeIdentifier::resolve()
Dsymbol *s;
*pe = NULL;
*pt = NULL;
*ps = NULL;
#if 0
if (!idents.dim)
{
error(loc, "template instance '%s' has no identifier", toChars());
return;
}
#endif
//id = (Identifier *)idents.data[0];
//printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars());
s = tempinst;
if (s)
s->semantic(sc);
resolveHelper(loc, sc, s, NULL, pe, pt, ps);
if (*pt && mod)
{
if (mod & MODconst)
*pt = (*pt)->constOf();
else if (mod & MODinvariant)
*pt = (*pt)->invariantOf();
}
//printf("pt = '%s'\n", (*pt)->toChars());
}
Type *TypeInstance::semantic(Loc loc, Scope *sc)
{
Type *t;
Expression *e;
Dsymbol *s;
//printf("TypeInstance::semantic(%s)\n", toChars());
if (sc->parameterSpecialization)
{
unsigned errors = global.errors;
global.gag++;
resolve(loc, sc, &e, &t, &s);
global.gag--;
if (errors != global.errors)
{ if (global.gag == 0)
global.errors = errors;
return this;
}
}
else
resolve(loc, sc, &e, &t, &s);
if (!t)
{
#ifdef DEBUG
printf("2: ");
#endif
error(loc, "%s is used as a type", toChars());
t = tvoid;
}
return t;
}
/***************************** TypeTypeof *****************************/
TypeTypeof::TypeTypeof(Loc loc, Expression *exp)
: TypeQualified(Ttypeof, loc)
{
this->exp = exp;
}
Type *TypeTypeof::syntaxCopy()
{
TypeTypeof *t;
t = new TypeTypeof(loc, exp->syntaxCopy());
t->syntaxCopyHelper(this);
t->mod = mod;
return t;
}
Dsymbol *TypeTypeof::toDsymbol(Scope *sc)
{
Type *t;
t = semantic(loc, sc);
if (t == this)
return NULL;
return t->toDsymbol(sc);
}
void TypeTypeof::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring("typeof(");
exp->toCBuffer(buf, hgs);
buf->writeByte(')');
toCBuffer2Helper(buf, hgs);
}
Type *TypeTypeof::semantic(Loc loc, Scope *sc)
{ Expression *e;
Type *t;
//printf("TypeTypeof::semantic() %p\n", this);
//static int nest; if (++nest == 50) *(char*)0=0;
#if 0
/* Special case for typeof(this) and typeof(super) since both
* should work even if they are not inside a non-static member function
*/
if (exp->op == TOKthis || exp->op == TOKsuper)
{
// Find enclosing struct or class
for (Dsymbol *s = sc->parent; 1; s = s->parent)
{
ClassDeclaration *cd;
StructDeclaration *sd;
if (!s)
{
error(loc, "%s is not in a struct or class scope", exp->toChars());
goto Lerr;
}
cd = s->isClassDeclaration();
if (cd)
{
if (exp->op == TOKsuper)
{
cd = cd->baseClass;
if (!cd)
{ error(loc, "class %s has no 'super'", s->toChars());
goto Lerr;
}
}
t = cd->type;
break;
}
sd = s->isStructDeclaration();
if (sd)
{
if (exp->op == TOKsuper)
{
error(loc, "struct %s has no 'super'", sd->toChars());
goto Lerr;
}
t = sd->type->pointerTo();
break;
}
}
}
else
#endif
{
sc->intypeof++;
exp = exp->semantic(sc);
sc->intypeof--;
if (exp->op == TOKtype)
{
error(loc, "argument %s to typeof is not an expression", exp->toChars());
}
t = exp->type;
if (!t)
{
error(loc, "expression (%s) has no type", exp->toChars());
goto Lerr;
}
if (t->ty == Ttypeof)
error(loc, "forward reference to %s", toChars());
/* typeof should reflect the true type,
* not what 'auto' would have gotten us.
*/
//t = t->toHeadMutable();
}
if (idents.dim)
{
Dsymbol *s = t->toDsymbol(sc);
for (size_t i = 0; i < idents.dim; i++)
{
if (!s)
break;
Identifier *id = (Identifier *)idents.data[i];
s = s->searchX(loc, sc, id);
}
if (s)
{
t = s->getType();
if (!t)
{ error(loc, "%s is not a type", s->toChars());
goto Lerr;
}
}
else
{ error(loc, "cannot resolve .property for %s", toChars());
goto Lerr;
}
}
return t;
Lerr:
return tvoid;
}
d_uns64 TypeTypeof::size(Loc loc)
{
if (exp->type)
return exp->type->size(loc);
else
return TypeQualified::size(loc);
}
/***************************** TypeReturn *****************************/
TypeReturn::TypeReturn(Loc loc)
: TypeQualified(Treturn, loc)
{
}
Type *TypeReturn::syntaxCopy()
{
TypeReturn *t = new TypeReturn(loc);
t->syntaxCopyHelper(this);
t->mod = mod;
return t;
}
Dsymbol *TypeReturn::toDsymbol(Scope *sc)
{
Type *t = semantic(0, sc);
if (t == this)
return NULL;
return t->toDsymbol(sc);
}
Type *TypeReturn::semantic(Loc loc, Scope *sc)
{
Type *t;
if (!sc->func)
{ error(loc, "typeof(return) must be inside function");
goto Lerr;
}
t = sc->func->type->nextOf();
if (mod & MODinvariant)
t = t->invariantOf();
else if (mod & MODconst)
t = t->constOf();
if (idents.dim)
{
Dsymbol *s = t->toDsymbol(sc);
for (size_t i = 0; i < idents.dim; i++)
{
if (!s)
break;
Identifier *id = (Identifier *)idents.data[i];
s = s->searchX(loc, sc, id);
}
if (s)
{
t = s->getType();
if (!t)
{ error(loc, "%s is not a type", s->toChars());
goto Lerr;
}
}
else
{ error(loc, "cannot resolve .property for %s", toChars());
goto Lerr;
}
}
return t;
Lerr:
return terror;
}
void TypeReturn::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring("typeof(return)");
toCBuffer2Helper(buf, hgs);
}
/***************************** TypeEnum *****************************/
TypeEnum::TypeEnum(EnumDeclaration *sym)
: Type(Tenum)
{
this->sym = sym;
}
char *TypeEnum::toChars()
{
if (mod)
return Type::toChars();
return sym->toChars();
}
Type *TypeEnum::syntaxCopy()
{
return this;
}
Type *TypeEnum::semantic(Loc loc, Scope *sc)
{
//printf("TypeEnum::semantic() %s\n", toChars());
sym->semantic(sc);
return merge();
}
d_uns64 TypeEnum::size(Loc loc)
{
if (!sym->memtype)
{
error(loc, "enum %s is forward referenced", sym->toChars());
return 4;
}
return sym->memtype->size(loc);
}
unsigned TypeEnum::alignsize()
{
if (!sym->memtype)
{
#ifdef DEBUG
printf("1: ");
#endif
error(0, "enum %s is forward referenced", sym->toChars());
return 4;
}
return sym->memtype->alignsize();
}
Dsymbol *TypeEnum::toDsymbol(Scope *sc)
{
return sym;
}
Type *TypeEnum::toBasetype()
{
if (!sym->memtype)
{
#ifdef DEBUG
printf("2: ");
#endif
error(sym->loc, "enum %s is forward referenced", sym->toChars());
return tint32;
}
return sym->memtype->toBasetype();
}
void TypeEnum::toDecoBuffer(OutBuffer *buf, int flag)
{
const char *name = sym->mangle();
Type::toDecoBuffer(buf, flag);
buf->printf("%s", name);
}
void TypeEnum::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(sym->toChars());
}
Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars());
#endif
Dsymbol *s = sym->search(e->loc, ident, 0);
if (!s)
{
return getProperty(e->loc, ident);
}
EnumMember *m = s->isEnumMember();
Expression *em = m->value->copy();
em->loc = e->loc;
return em;
}
Expression *TypeEnum::getProperty(Loc loc, Identifier *ident)
{ Expression *e;
if (ident == Id::max)
{
if (!sym->maxval)
goto Lfwd;
e = sym->maxval;
}
else if (ident == Id::min)
{
if (!sym->minval)
goto Lfwd;
e = sym->minval;
}
else if (ident == Id::init)
{
e = defaultInit(loc);
}
else if (ident == Id::stringof)
{ char *s = toChars();
e = new StringExp(loc, s, strlen(s), 'c');
Scope sc;
e = e->semantic(&sc);
}
else
{
e = toBasetype()->getProperty(loc, ident);
}
return e;
Lfwd:
error(loc, "forward reference of %s.%s", toChars(), ident->toChars());
return new IntegerExp(0, 0, this);
}
int TypeEnum::isintegral()
{
return 1;
}
int TypeEnum::isfloating()
{
return 0;
}
int TypeEnum::isunsigned()
{
return sym->memtype->isunsigned();
}
int TypeEnum::isscalar()
{
return 1;
//return sym->memtype->isscalar();
}
MATCH TypeEnum::implicitConvTo(Type *to)
{ MATCH m;
//printf("TypeEnum::implicitConvTo()\n");
if (ty == to->ty && sym == ((TypeEnum *)to)->sym)
m = (mod == to->mod) ? MATCHexact : MATCHconst;
else if (sym->memtype->implicitConvTo(to))
m = MATCHconvert; // match with conversions
else
m = MATCHnomatch; // no match
return m;
}
MATCH TypeEnum::constConv(Type *to)
{
if (equals(to))
return MATCHexact;
if (ty == to->ty && sym == ((TypeEnum *)to)->sym &&
to->mod == MODconst)
return MATCHconst;
return MATCHnomatch;
}
Expression *TypeEnum::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeEnum::defaultInit() '%s'\n", toChars());
#endif
// Initialize to first member of enum
//printf("%s\n", sym->defaultval->type->toChars());
if (!sym->defaultval)
{
error(loc, "forward reference of %s.init", toChars());
return new IntegerExp(0, 0, this);
}
return sym->defaultval;
}
int TypeEnum::isZeroInit()
{
return sym->defaultval->isBool(FALSE);
}
int TypeEnum::hasPointers()
{
return toBasetype()->hasPointers();
}
/***************************** TypeTypedef *****************************/
TypeTypedef::TypeTypedef(TypedefDeclaration *sym)
: Type(Ttypedef)
{
this->sym = sym;
}
Type *TypeTypedef::syntaxCopy()
{
return this;
}
char *TypeTypedef::toChars()
{
return Type::toChars();
}
Type *TypeTypedef::semantic(Loc loc, Scope *sc)
{
//printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem);
sym->semantic(sc);
return merge();
}
d_uns64 TypeTypedef::size(Loc loc)
{
return sym->basetype->size(loc);
}
unsigned TypeTypedef::alignsize()
{
return sym->basetype->alignsize();
}
Dsymbol *TypeTypedef::toDsymbol(Scope *sc)
{
return sym;
}
Type *TypeTypedef::toHeadMutable()
{
if (!mod)
return this;
Type *tb = toBasetype();
Type *t = tb->toHeadMutable();
if (t->equals(tb))
return this;
else
return mutableOf();
}
void TypeTypedef::toDecoBuffer(OutBuffer *buf, int flag)
{
Type::toDecoBuffer(buf, flag);
const char *name = sym->mangle();
buf->printf("%s", name);
}
void TypeTypedef::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
//printf("TypeTypedef::toCBuffer2() '%s'\n", sym->toChars());
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(sym->toChars());
}
Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeTypedef::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars());
#endif
if (ident == Id::init)
{
return Type::dotExp(sc, e, ident);
}
return sym->basetype->dotExp(sc, e, ident);
}
Expression *TypeTypedef::getProperty(Loc loc, Identifier *ident)
{
#if LOGDOTEXP
printf("TypeTypedef::getProperty(ident = '%s') '%s'\n", ident->toChars(), toChars());
#endif
if (ident == Id::init)
{
return Type::getProperty(loc, ident);
}
return sym->basetype->getProperty(loc, ident);
}
int TypeTypedef::isintegral()
{
//printf("TypeTypedef::isintegral()\n");
//printf("sym = '%s'\n", sym->toChars());
//printf("basetype = '%s'\n", sym->basetype->toChars());
return sym->basetype->isintegral();
}
int TypeTypedef::isfloating()
{
return sym->basetype->isfloating();
}
int TypeTypedef::isreal()
{
return sym->basetype->isreal();
}
int TypeTypedef::isimaginary()
{
return sym->basetype->isimaginary();
}
int TypeTypedef::iscomplex()
{
return sym->basetype->iscomplex();
}
int TypeTypedef::isunsigned()
{
return sym->basetype->isunsigned();
}
int TypeTypedef::isscalar()
{
return sym->basetype->isscalar();
}
int TypeTypedef::isAssignable()
{
return sym->basetype->isAssignable();
}
int TypeTypedef::checkBoolean()
{
return sym->basetype->checkBoolean();
}
Type *TypeTypedef::toBasetype()
{
if (sym->inuse)
{
sym->error("circular definition");
sym->basetype = Type::terror;
return Type::terror;
}
sym->inuse = 1;
Type *t = sym->basetype->toBasetype();
sym->inuse = 0;
if (mod == MODconst && !t->isInvariant())
t = t->constOf();
else if (mod == MODinvariant)
t = t->invariantOf();
return t;
}
MATCH TypeTypedef::implicitConvTo(Type *to)
{ MATCH m;
//printf("TypeTypedef::implicitConvTo(to = %s) %s\n", to->toChars(), toChars());
if (equals(to))
m = MATCHexact; // exact match
else if (sym->basetype->implicitConvTo(to))
m = MATCHconvert; // match with conversions
else if (ty == to->ty && sym == ((TypeTypedef *)to)->sym)
{
m = constConv(to);
}
else
m = MATCHnomatch; // no match
return m;
}
MATCH TypeTypedef::constConv(Type *to)
{
if (equals(to))
return MATCHexact;
if (ty == to->ty && sym == ((TypeTypedef *)to)->sym)
return sym->basetype->implicitConvTo(((TypeTypedef *)to)->sym->basetype);
return MATCHnomatch;
}
Expression *TypeTypedef::defaultInit(Loc loc)
{ Expression *e;
Type *bt;
#if LOGDEFAULTINIT
printf("TypeTypedef::defaultInit() '%s'\n", toChars());
#endif
if (sym->init)
{
//sym->init->toExpression()->print();
return sym->init->toExpression();
}
bt = sym->basetype;
e = bt->defaultInit(loc);
e->type = this;
while (bt->ty == Tsarray)
{ TypeSArray *tsa = (TypeSArray *)bt;
e->type = tsa->next;
bt = tsa->next->toBasetype();
}
return e;
}
int TypeTypedef::isZeroInit()
{
if (sym->init)
{
if (sym->init->isVoidInitializer())
return 1; // initialize voids to 0
Expression *e = sym->init->toExpression();
if (e && e->isBool(FALSE))
return 1;
return 0; // assume not
}
if (sym->inuse)
{
sym->error("circular definition");
sym->basetype = Type::terror;
}
sym->inuse = 1;
int result = sym->basetype->isZeroInit();
sym->inuse = 0;
return result;
}
int TypeTypedef::hasPointers()
{
return toBasetype()->hasPointers();
}
/***************************** TypeStruct *****************************/
TypeStruct::TypeStruct(StructDeclaration *sym)
: Type(Tstruct)
{
this->sym = sym;
// LDC
this->unaligned = 0;
}
char *TypeStruct::toChars()
{
//printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco);
if (mod)
return Type::toChars();
TemplateInstance *ti = sym->parent->isTemplateInstance();
if (ti && ti->toAlias() == sym)
{
return ti->toChars();
}
return sym->toChars();
}
Type *TypeStruct::syntaxCopy()
{
return this;
}
Type *TypeStruct::semantic(Loc loc, Scope *sc)
{
//printf("TypeStruct::semantic('%s')\n", sym->toChars());
/* Cannot do semantic for sym because scope chain may not
* be right.
*/
//sym->semantic(sc);
return merge();
}
d_uns64 TypeStruct::size(Loc loc)
{
return sym->size(loc);
}
unsigned TypeStruct::alignsize()
{ unsigned sz;
sym->size(0); // give error for forward references
sz = sym->alignsize;
if (sz > sym->structalign)
sz = sym->structalign;
return sz;
}
Dsymbol *TypeStruct::toDsymbol(Scope *sc)
{
return sym;
}
void TypeStruct::toDecoBuffer(OutBuffer *buf, int flag)
{
const char *name = sym->mangle();
//printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name);
Type::toDecoBuffer(buf, flag);
buf->printf("%s", name);
}
void TypeStruct::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
TemplateInstance *ti = sym->parent->isTemplateInstance();
if (ti && ti->toAlias() == sym)
buf->writestring(ti->toChars());
else
buf->writestring(sym->toChars());
}
Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident)
{ unsigned offset;
Expression *b;
VarDeclaration *v;
Dsymbol *s;
DotVarExp *de;
Declaration *d;
#if LOGDOTEXP
printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (!sym->members)
{
error(e->loc, "struct %s is forward referenced", sym->toChars());
return new IntegerExp(e->loc, 0, Type::tint32);
}
/* If e.tupleof
*/
if (ident == Id::tupleof)
{
/* Create a TupleExp out of the fields of the struct e:
* (e.field0, e.field1, e.field2, ...)
*/
e = e->semantic(sc); // do this before turning on noaccesscheck
Expressions *exps = new Expressions;
exps->reserve(sym->fields.dim);
for (size_t i = 0; i < sym->fields.dim; i++)
{ VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
Expression *fe = new DotVarExp(e->loc, e, v);
exps->push(fe);
}
e = new TupleExp(e->loc, exps);
sc = sc->push();
sc->noaccesscheck = 1;
e = e->semantic(sc);
sc->pop();
return e;
}
if (e->op == TOKdotexp)
{ DotExp *de = (DotExp *)e;
if (de->e1->op == TOKimport)
{
assert(0); // cannot find a case where this happens; leave
// assert in until we do
ScopeExp *se = (ScopeExp *)de->e1;
s = se->sds->search(e->loc, ident, 0);
e = de->e1;
goto L1;
}
}
s = sym->search(e->loc, ident, 0);
L1:
if (!s)
{
if (ident != Id::__sizeof &&
ident != Id::alignof &&
ident != Id::init &&
ident != Id::mangleof &&
ident != Id::stringof &&
ident != Id::offsetof)
{
/* Look for overloaded opDot() to see if we should forward request
* to it.
*/
Dsymbol *fd = search_function(sym, Id::opDot);
if (fd)
{ /* Rewrite e.ident as:
* e.opId().ident
*/
e = build_overload(e->loc, sc, e, NULL, fd->ident);
e = new DotIdExp(e->loc, e, ident);
return e->semantic(sc);
}
}
return Type::dotExp(sc, e, ident);
}
if (!s->isFuncDeclaration()) // because of overloading
s->checkDeprecated(e->loc, sc);
s = s->toAlias();
v = s->isVarDeclaration();
if (v && !v->isDataseg())
{
Expression *ei = v->getConstInitializer();
if (ei)
{ e = ei->copy(); // need to copy it if it's a StringExp
e = e->semantic(sc);
return e;
}
}
if (s->getType())
{
//return new DotTypeExp(e->loc, e, s);
return new TypeExp(e->loc, s->getType());
}
EnumMember *em = s->isEnumMember();
if (em)
{
assert(em->value);
return em->value->copy();
}
TemplateMixin *tm = s->isTemplateMixin();
if (tm)
{
Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
de->type = e->type;
return de;
}
TemplateDeclaration *td = s->isTemplateDeclaration();
if (td)
{
e = new DotTemplateExp(e->loc, e, td);
e->semantic(sc);
return e;
}
TemplateInstance *ti = s->isTemplateInstance();
if (ti)
{ if (!ti->semanticdone)
ti->semantic(sc);
s = ti->inst->toAlias();
if (!s->isTemplateInstance())
goto L1;
Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
de->type = e->type;
return de;
}
d = s->isDeclaration();
#ifdef DEBUG
if (!d)
printf("d = %s '%s'\n", s->kind(), s->toChars());
#endif
assert(d);
if (e->op == TOKtype)
{ FuncDeclaration *fd = sc->func;
if (d->needThis() && fd && fd->vthis)
{
e = new DotVarExp(e->loc, new ThisExp(e->loc), d);
e = e->semantic(sc);
return e;
}
if (d->isTupleDeclaration())
{
e = new TupleExp(e->loc, d->isTupleDeclaration());
e = e->semantic(sc);
return e;
}
return new VarExp(e->loc, d, 1);
}
if (d->isDataseg())
{
// (e, d)
VarExp *ve;
accessCheck(e->loc, sc, e, d);
ve = new VarExp(e->loc, d);
e = new CommaExp(e->loc, e, ve);
e->type = d->type;
return e;
}
if (v)
{
if (v->toParent() != sym)
sym->error(e->loc, "'%s' is not a member", v->toChars());
// *(&e + offset)
accessCheck(e->loc, sc, e, d);
// LDC we don't want dot exprs turned into pointer arithmetic. it complicates things for no apparent gain
#ifndef IN_LLVM
b = new AddrExp(e->loc, e);
b->type = e->type->pointerTo();
b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32));
b->type = v->type->pointerTo();
b = new PtrExp(e->loc, b);
b->type = v->type;
if (e->type->isConst())
b->type = b->type->constOf();
else if (e->type->isInvariant())
b->type = b->type->invariantOf();
return b;
#endif
}
de = new DotVarExp(e->loc, e, d);
return de->semantic(sc);
}
unsigned TypeStruct::memalign(unsigned salign)
{
sym->size(0); // give error for forward references
return sym->structalign;
}
Expression *TypeStruct::defaultInit(Loc loc)
{ Declaration *d;
#if LOGDEFAULTINIT
printf("TypeStruct::defaultInit() '%s'\n", toChars());
#endif
d = new StaticStructInitDeclaration(sym->loc, sym);
assert(d);
d->type = this;
return new VarExp(sym->loc, d);
}
int TypeStruct::isZeroInit()
{
return sym->zeroInit;
}
int TypeStruct::checkBoolean()
{
return FALSE;
}
int TypeStruct::isAssignable()
{
/* If any of the fields are const or invariant,
* then one cannot assign this struct.
*/
for (size_t i = 0; i < sym->fields.dim; i++)
{ VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
if (v->isConst() || v->isInvariant())
return FALSE;
}
return TRUE;
}
int TypeStruct::hasPointers()
{
StructDeclaration *s = sym;
sym->size(0); // give error for forward references
for (size_t i = 0; i < s->fields.dim; i++)
{
Dsymbol *sm = (Dsymbol *)s->fields.data[i];
if (sm->hasPointers())
return TRUE;
}
return FALSE;
}
MATCH TypeStruct::implicitConvTo(Type *to)
{ MATCH m;
//printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to->toChars());
if (ty == to->ty && sym == ((TypeStruct *)to)->sym)
{ m = MATCHexact; // exact match
if (mod != to->mod)
{
if (to->mod == MODconst)
m = MATCHconst;
else
{ /* Check all the fields. If they can all be converted,
* allow the conversion.
*/
for (int i = 0; i < sym->fields.dim; i++)
{ Dsymbol *s = (Dsymbol *)sym->fields.data[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v && v->storage_class & STCfield);
// 'from' type
Type *tvf = v->type;
if (mod == MODconst)
tvf = tvf->constOf();
else if (mod == MODinvariant)
tvf = tvf->invariantOf();
// 'to' type
Type *tv = v->type;
if (to->mod == 0)
tv = tv->mutableOf();
else
{ assert(to->mod == MODinvariant);
tv = tv->invariantOf();
}
//printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), tvf->implicitConvTo(tv));
if (tvf->implicitConvTo(tv) < MATCHconst)
return MATCHnomatch;
}
m = MATCHconst;
}
}
}
else
m = MATCHnomatch; // no match
return m;
}
Type *TypeStruct::toHeadMutable()
{
return this;
}
MATCH TypeStruct::constConv(Type *to)
{
if (equals(to))
return MATCHexact;
if (ty == to->ty && sym == ((TypeStruct *)to)->sym &&
to->mod == MODconst)
return MATCHconst;
return MATCHnomatch;
}
/***************************** TypeClass *****************************/
TypeClass::TypeClass(ClassDeclaration *sym)
: Type(Tclass)
{
this->sym = sym;
}
char *TypeClass::toChars()
{
if (mod)
return Type::toChars();
return sym->toPrettyChars();
}
Type *TypeClass::syntaxCopy()
{
return this;
}
Type *TypeClass::semantic(Loc loc, Scope *sc)
{
//printf("TypeClass::semantic(%s)\n", sym->toChars());
if (sym->scope)
sym->semantic(sym->scope);
return merge();
}
d_uns64 TypeClass::size(Loc loc)
{
return PTRSIZE;
}
Dsymbol *TypeClass::toDsymbol(Scope *sc)
{
return sym;
}
void TypeClass::toDecoBuffer(OutBuffer *buf, int flag)
{
const char *name = sym->mangle();
//printf("TypeClass::toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name);
Type::toDecoBuffer(buf, flag);
buf->printf("%s", name);
}
void TypeClass::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
buf->writestring(sym->toChars());
}
Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident)
{ unsigned offset;
Expression *b;
VarDeclaration *v;
Dsymbol *s;
#if LOGDOTEXP
printf("TypeClass::dotExp(e='%s', ident='%s')\n", e->toChars(), ident->toChars());
#endif
if (e->op == TOKdotexp)
{ DotExp *de = (DotExp *)e;
if (de->e1->op == TOKimport)
{
ScopeExp *se = (ScopeExp *)de->e1;
s = se->sds->search(e->loc, ident, 0);
e = de->e1;
goto L1;
}
}
if (ident == Id::tupleof)
{
/* Create a TupleExp
*/
e = e->semantic(sc); // do this before turning on noaccesscheck
Expressions *exps = new Expressions;
exps->reserve(sym->fields.dim);
for (size_t i = 0; i < sym->fields.dim; i++)
{ VarDeclaration *v = (VarDeclaration *)sym->fields.data[i];
Expression *fe = new DotVarExp(e->loc, e, v);
exps->push(fe);
}
e = new TupleExp(e->loc, exps);
sc = sc->push();
sc->noaccesscheck = 1;
e = e->semantic(sc);
sc->pop();
return e;
}
s = sym->search(e->loc, ident, 0);
L1:
if (!s)
{
// See if it's a base class
ClassDeclaration *cbase;
for (cbase = sym->baseClass; cbase; cbase = cbase->baseClass)
{
if (cbase->ident->equals(ident))
{
e = new DotTypeExp(0, e, cbase);
return e;
}
}
if (ident == Id::classinfo)
{
assert(ClassDeclaration::classinfo);
Type *t = ClassDeclaration::classinfo->type;
if (e->op == TOKtype || e->op == TOKdottype)
{
/* For type.classinfo, we know the classinfo
* at compile time.
*/
if (!sym->vclassinfo)
sym->vclassinfo = new ClassInfoDeclaration(sym);
e = new VarExp(e->loc, sym->vclassinfo);
e = e->addressOf(sc);
e->type = t; // do this so we don't get redundant dereference
}
else
{
/* For class objects, the classinfo reference is the first
* entry in the vtbl[]
*/
#if IN_LLVM
Type* ct;
if (sym->isInterfaceDeclaration()) {
ct = t->pointerTo()->pointerTo()->pointerTo();
}
else {
ct = t->pointerTo()->pointerTo();
}
e = e->castTo(sc, ct);
e = new PtrExp(e->loc, e);
e->type = ct->nextOf();
e = new PtrExp(e->loc, e);
e->type = ct->nextOf()->nextOf();
if (sym->isInterfaceDeclaration())
{
if (sym->isCOMinterface())
{ /* COM interface vtbl[]s are different in that the
* first entry is always pointer to QueryInterface().
* We can't get a .classinfo for it.
*/
error(e->loc, "no .classinfo for COM interface objects");
}
/* For an interface, the first entry in the vtbl[]
* is actually a pointer to an instance of struct Interface.
* The first member of Interface is the .classinfo,
* so add an extra pointer indirection.
*/
e = new PtrExp(e->loc, e);
e->type = ct->nextOf()->nextOf()->nextOf();
}
}
#else
e = new PtrExp(e->loc, e);
e->type = t->pointerTo();
if (sym->isInterfaceDeclaration())
{
if (sym->isCPPinterface())
{ /* C++ interface vtbl[]s are different in that the
* first entry is always pointer to the first virtual
* function, not classinfo.
* We can't get a .classinfo for it.
*/
error(e->loc, "no .classinfo for C++ interface objects");
}
/* For an interface, the first entry in the vtbl[]
* is actually a pointer to an instance of struct Interface.
* The first member of Interface is the .classinfo,
* so add an extra pointer indirection.
*/
e->type = e->type->pointerTo();
e = new PtrExp(e->loc, e);
e->type = t->pointerTo();
}
e = new PtrExp(e->loc, e, t);
}
#endif // !LDC
return e;
}
if (ident == Id::__vptr)
{ /* The pointer to the vtbl[]
* *cast(invariant(void*)**)e
*/
e = e->castTo(sc, tvoidptr->invariantOf()->pointerTo()->pointerTo());
e = new PtrExp(e->loc, e);
e = e->semantic(sc);
return e;
}
if (ident == Id::__monitor)
{ /* The handle to the monitor (call it a void*)
* *(cast(void**)e + 1)
*/
e = e->castTo(sc, tvoidptr->pointerTo());
e = new AddExp(e->loc, e, new IntegerExp(1));
e = new PtrExp(e->loc, e);
e = e->semantic(sc);
return e;
}
if (ident == Id::typeinfo)
{
if (!global.params.useDeprecated)
error(e->loc, ".typeinfo deprecated, use typeid(type)");
return getTypeInfo(sc);
}
if (ident == Id::outer && sym->vthis)
{
s = sym->vthis;
}
else
{
if (ident != Id::__sizeof &&
ident != Id::alignof &&
ident != Id::init &&
ident != Id::mangleof &&
ident != Id::stringof &&
ident != Id::offsetof)
{
/* Look for overloaded opDot() to see if we should forward request
* to it.
*/
Dsymbol *fd = search_function(sym, Id::opDot);
if (fd)
{ /* Rewrite e.ident as:
* e.opId().ident
*/
e = build_overload(e->loc, sc, e, NULL, fd->ident);
e = new DotIdExp(e->loc, e, ident);
return e->semantic(sc);
}
}
return Type::dotExp(sc, e, ident);
}
}
if (!s->isFuncDeclaration()) // because of overloading
s->checkDeprecated(e->loc, sc);
s = s->toAlias();
v = s->isVarDeclaration();
if (v && !v->isDataseg())
{ Expression *ei = v->getConstInitializer();
if (ei)
{ e = ei->copy(); // need to copy it if it's a StringExp
e = e->semantic(sc);
return e;
}
}
if (s->getType())
{
// if (e->op == TOKtype)
return new TypeExp(e->loc, s->getType());
// return new DotTypeExp(e->loc, e, s);
}
EnumMember *em = s->isEnumMember();
if (em)
{
assert(em->value);
return em->value->copy();
}
TemplateMixin *tm = s->isTemplateMixin();
if (tm)
{
Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
de->type = e->type;
return de;
}
TemplateDeclaration *td = s->isTemplateDeclaration();
if (td)
{
e = new DotTemplateExp(e->loc, e, td);
e->semantic(sc);
return e;
}
TemplateInstance *ti = s->isTemplateInstance();
if (ti)
{ if (!ti->semanticdone)
ti->semantic(sc);
s = ti->inst->toAlias();
if (!s->isTemplateInstance())
goto L1;
Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
de->type = e->type;
return de;
}
Declaration *d = s->isDeclaration();
if (!d)
{
e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
return new IntegerExp(e->loc, 1, Type::tint32);
}
if (e->op == TOKtype)
{
/* It's:
* Class.d
*/
if (d->needThis() && (hasThis(sc) || !d->isFuncDeclaration()))
{
if (sc->func)
{
ClassDeclaration *thiscd;
thiscd = sc->func->toParent()->isClassDeclaration();
if (thiscd)
{
ClassDeclaration *cd = e->type->isClassHandle();
if (cd == thiscd)
{
e = new ThisExp(e->loc);
e = new DotTypeExp(e->loc, e, cd);
DotVarExp *de = new DotVarExp(e->loc, e, d);
e = de->semantic(sc);
return e;
}
else if ((!cd || !cd->isBaseOf(thiscd, NULL)) &&
!d->isFuncDeclaration())
e->error("'this' is required, but %s is not a base class of %s", e->type->toChars(), thiscd->toChars());
}
}
/* Rewrite as:
* this.d
*/
DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d);
e = de->semantic(sc);
return e;
}
else if (d->isTupleDeclaration())
{
e = new TupleExp(e->loc, d->isTupleDeclaration());
e = e->semantic(sc);
return e;
}
else
{
VarExp *ve = new VarExp(e->loc, d, 1);
return ve;
}
}
if (d->isDataseg())
{
// (e, d)
VarExp *ve;
accessCheck(e->loc, sc, e, d);
ve = new VarExp(e->loc, d);
e = new CommaExp(e->loc, e, ve);
e->type = d->type;
return e;
}
if (d->parent && d->toParent()->isModule())
{
// (e, d)
VarExp *ve = new VarExp(e->loc, d, 1);
e = new CommaExp(e->loc, e, ve);
e->type = d->type;
return e;
}
DotVarExp *de = new DotVarExp(e->loc, e, d);
return de->semantic(sc);
}
ClassDeclaration *TypeClass::isClassHandle()
{
return sym;
}
int TypeClass::isauto()
{
return sym->isauto;
}
int TypeClass::isBaseOf(Type *t, int *poffset)
{
if (t->ty == Tclass)
{ ClassDeclaration *cd;
cd = ((TypeClass *)t)->sym;
if (sym->isBaseOf(cd, poffset))
return 1;
}
return 0;
}
MATCH TypeClass::implicitConvTo(Type *to)
{
//printf("TypeClass::implicitConvTo(to = '%s') %s\n", to->toChars(), toChars());
MATCH m = constConv(to);
if (m != MATCHnomatch)
return m;
ClassDeclaration *cdto = to->isClassHandle();
if (cdto && cdto->isBaseOf(sym, NULL))
{ //printf("'to' is base\n");
return MATCHconvert;
}
if (global.params.Dversion == 1)
{
// Allow conversion to (void *)
if (to->ty == Tpointer && ((TypePointer *)to)->next->ty == Tvoid)
return MATCHconvert;
}
return MATCHnomatch;
}
MATCH TypeClass::constConv(Type *to)
{
if (equals(to))
return MATCHexact;
if (ty == to->ty && sym == ((TypeClass *)to)->sym &&
to->mod == MODconst)
return MATCHconst;
return MATCHnomatch;
}
Type *TypeClass::toHeadMutable()
{
return this;
}
Expression *TypeClass::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeClass::defaultInit() '%s'\n", toChars());
#endif
Expression *e;
e = new NullExp(loc);
e->type = this;
return e;
}
int TypeClass::isZeroInit()
{
return 1;
}
int TypeClass::checkBoolean()
{
return TRUE;
}
int TypeClass::hasPointers()
{
return TRUE;
}
/***************************** TypeTuple *****************************/
TypeTuple::TypeTuple(Arguments *arguments)
: Type(Ttuple)
{
//printf("TypeTuple(this = %p)\n", this);
this->arguments = arguments;
//printf("TypeTuple() %s\n", toChars());
#ifdef DEBUG
if (arguments)
{
for (size_t i = 0; i < arguments->dim; i++)
{
Argument *arg = (Argument *)arguments->data[i];
assert(arg && arg->type);
}
}
#endif
}
/****************
* Form TypeTuple from the types of the expressions.
* Assume exps[] is already tuple expanded.
*/
TypeTuple::TypeTuple(Expressions *exps)
: Type(Ttuple)
{
Arguments *arguments = new Arguments;
if (exps)
{
arguments->setDim(exps->dim);
for (size_t i = 0; i < exps->dim; i++)
{ Expression *e = (Expression *)exps->data[i];
if (e->type->ty == Ttuple)
e->error("cannot form tuple of tuples");
Argument *arg = new Argument(STCundefined, e->type, NULL, NULL);
arguments->data[i] = (void *)arg;
}
}
this->arguments = arguments;
}
Type *TypeTuple::syntaxCopy()
{
Arguments *args = Argument::arraySyntaxCopy(arguments);
Type *t = new TypeTuple(args);
t->mod = mod;
return t;
}
Type *TypeTuple::semantic(Loc loc, Scope *sc)
{
//printf("TypeTuple::semantic(this = %p)\n", this);
//printf("TypeTuple::semantic() %s\n", toChars());
if (!deco)
deco = merge()->deco;
/* Don't return merge(), because a tuple with one type has the
* same deco as that type.
*/
return this;
}
int TypeTuple::equals(Object *o)
{ Type *t;
t = (Type *)o;
//printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars());
if (this == t)
{
return 1;
}
if (t->ty == Ttuple)
{ TypeTuple *tt = (TypeTuple *)t;
if (arguments->dim == tt->arguments->dim)
{
for (size_t i = 0; i < tt->arguments->dim; i++)
{ Argument *arg1 = (Argument *)arguments->data[i];
Argument *arg2 = (Argument *)tt->arguments->data[i];
if (!arg1->type->equals(arg2->type))
return 0;
}
return 1;
}
}
return 0;
}
Type *TypeTuple::reliesOnTident()
{
if (arguments)
{
for (size_t i = 0; i < arguments->dim; i++)
{
Argument *arg = (Argument *)arguments->data[i];
Type *t = arg->type->reliesOnTident();
if (t)
return t;
}
}
return NULL;
}
#if 0
Type *TypeTuple::makeConst()
{
//printf("TypeTuple::makeConst() %s\n", toChars());
if (cto)
return cto;
TypeTuple *t = (TypeTuple *)Type::makeConst();
t->arguments = new Arguments();
t->arguments->setDim(arguments->dim);
for (size_t i = 0; i < arguments->dim; i++)
{ Argument *arg = (Argument *)arguments->data[i];
Argument *narg = new Argument(arg->storageClass, arg->type->constOf(), arg->ident, arg->defaultArg);
t->arguments->data[i] = (Argument *)narg;
}
return t;
}
#endif
void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
Argument::argsToCBuffer(buf, hgs, arguments, 0);
}
void TypeTuple::toDecoBuffer(OutBuffer *buf, int flag)
{
//printf("TypeTuple::toDecoBuffer() this = %p, %s\n", this, toChars());
Type::toDecoBuffer(buf, flag);
OutBuffer buf2;
Argument::argsToDecoBuffer(&buf2, arguments);
unsigned len = buf2.offset;
buf->printf("%d%.*s", len, len, (char *)buf2.extractData());
}
Expression *TypeTuple::getProperty(Loc loc, Identifier *ident)
{ Expression *e;
#if LOGDOTEXP
printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
#endif
if (ident == Id::length)
{
e = new IntegerExp(loc, arguments->dim, Type::tsize_t);
}
else
{
error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars());
e = new IntegerExp(loc, 1, Type::tint32);
}
return e;
}
/***************************** TypeSlice *****************************/
/* This is so we can slice a TypeTuple */
TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr)
: TypeNext(Tslice, next)
{
//printf("TypeSlice[%s .. %s]\n", lwr->toChars(), upr->toChars());
this->lwr = lwr;
this->upr = upr;
}
Type *TypeSlice::syntaxCopy()
{
Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy());
t->mod = mod;
return t;
}
Type *TypeSlice::semantic(Loc loc, Scope *sc)
{
//printf("TypeSlice::semantic() %s\n", toChars());
next = next->semantic(loc, sc);
if (mod == MODconst && !next->isInvariant())
next = next->constOf();
else if (mod == MODinvariant)
next = next->invariantOf();
//printf("next: %s\n", next->toChars());
Type *tbn = next->toBasetype();
if (tbn->ty != Ttuple)
{ error(loc, "can only slice tuple types, not %s", tbn->toChars());
return Type::terror;
}
TypeTuple *tt = (TypeTuple *)tbn;
lwr = semanticLength(sc, tbn, lwr);
lwr = lwr->optimize(WANTvalue);
uinteger_t i1 = lwr->toUInteger();
upr = semanticLength(sc, tbn, upr);
upr = upr->optimize(WANTvalue);
uinteger_t i2 = upr->toUInteger();
if (!(i1 <= i2 && i2 <= tt->arguments->dim))
{ error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, tt->arguments->dim);
return Type::terror;
}
Arguments *args = new Arguments;
args->reserve(i2 - i1);
for (size_t i = i1; i < i2; i++)
{ Argument *arg = (Argument *)tt->arguments->data[i];
args->push(arg);
}
return new TypeTuple(args);
}
void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps)
{
next->resolve(loc, sc, pe, pt, ps);
if (*pe)
{ // It's really a slice expression
Expression *e;
e = new SliceExp(loc, *pe, lwr, upr);
*pe = e;
}
else if (*ps)
{ Dsymbol *s = *ps;
TupleDeclaration *td = s->isTupleDeclaration();
if (td)
{
/* It's a slice of a TupleDeclaration
*/
ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
sym->parent = sc->scopesym;
sc = sc->push(sym);
lwr = lwr->semantic(sc);
lwr = lwr->optimize(WANTvalue);
uinteger_t i1 = lwr->toUInteger();
upr = upr->semantic(sc);
upr = upr->optimize(WANTvalue);
uinteger_t i2 = upr->toUInteger();
sc = sc->pop();
if (!(i1 <= i2 && i2 <= td->objects->dim))
{ error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, td->objects->dim);
goto Ldefault;
}
if (i1 == 0 && i2 == td->objects->dim)
{
*ps = td;
return;
}
/* Create a new TupleDeclaration which
* is a slice [i1..i2] out of the old one.
*/
Objects *objects = new Objects;
objects->setDim(i2 - i1);
for (size_t i = 0; i < objects->dim; i++)
{
objects->data[i] = td->objects->data[(size_t)i1 + i];
}
TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
*ps = tds;
}
else
goto Ldefault;
}
else
{
Ldefault:
Type::resolve(loc, sc, pe, pt, ps);
}
}
void TypeSlice::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod)
{
if (mod != this->mod)
{ toCBuffer3(buf, hgs, mod);
return;
}
next->toCBuffer2(buf, hgs, this->mod);
buf->printf("[%s .. ", lwr->toChars());
buf->printf("%s]", upr->toChars());
}
/***************************** Argument *****************************/
Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg)
{
this->type = type;
this->ident = ident;
this->storageClass = storageClass;
this->defaultArg = defaultArg;
}
Argument *Argument::syntaxCopy()
{
Argument *a = new Argument(storageClass,
type ? type->syntaxCopy() : NULL,
ident,
defaultArg ? defaultArg->syntaxCopy() : NULL);
return a;
}
Arguments *Argument::arraySyntaxCopy(Arguments *args)
{ Arguments *a = NULL;
if (args)
{
a = new Arguments();
a->setDim(args->dim);
for (size_t i = 0; i < a->dim; i++)
{ Argument *arg = (Argument *)args->data[i];
arg = arg->syntaxCopy();
a->data[i] = (void *)arg;
}
}
return a;
}
char *Argument::argsTypesToChars(Arguments *args, int varargs)
{
OutBuffer *buf = new OutBuffer();
#if 1
HdrGenState hgs;
argsToCBuffer(buf, &hgs, args, varargs);
#else
buf->writeByte('(');
if (args)
{ OutBuffer argbuf;
HdrGenState hgs;
for (int i = 0; i < args->dim; i++)
{ if (i)
buf->writeByte(',');
Argument *arg = (Argument *)args->data[i];
argbuf.reset();
arg->type->toCBuffer2(&argbuf, &hgs, 0);
buf->write(&argbuf);
}
if (varargs)
{
if (i && varargs == 1)
buf->writeByte(',');
buf->writestring("...");
}
}
buf->writeByte(')');
#endif
return buf->toChars();
}
void Argument::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs)
{
buf->writeByte('(');
if (arguments)
{ int i;
OutBuffer argbuf;
for (i = 0; i < arguments->dim; i++)
{
if (i)
buf->writestring(", ");
Argument *arg = (Argument *)arguments->data[i];
if (arg->storageClass & STCout)
buf->writestring("out ");
else if (arg->storageClass & STCref)
buf->writestring((global.params.Dversion == 1)
? (char *)"inout " : (char *)"ref ");
else if (arg->storageClass & STCin)
buf->writestring("in ");
else if (arg->storageClass & STClazy)
buf->writestring("lazy ");
else if (arg->storageClass & STCalias)
buf->writestring("alias ");
else if (arg->storageClass & STCauto)
buf->writestring("auto ");
if (arg->storageClass & STCscope)
buf->writestring("scope ");
if (arg->storageClass & STCconst)
buf->writestring("const ");
if (arg->storageClass & STCinvariant)
buf->writestring("invariant ");
if (arg->storageClass & STCshared)
buf->writestring("shared ");
argbuf.reset();
if (arg->storageClass & STCalias)
{ if (arg->ident)
argbuf.writestring(arg->ident->toChars());
}
else
arg->type->toCBuffer(&argbuf, arg->ident, hgs);
if (arg->defaultArg)
{
argbuf.writestring(" = ");
arg->defaultArg->toCBuffer(&argbuf, hgs);
}
buf->write(&argbuf);
}
if (varargs)
{
if (i && varargs == 1)
buf->writeByte(',');
buf->writestring("...");
}
}
buf->writeByte(')');
}
void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments)
{
//printf("Argument::argsToDecoBuffer()\n");
// Write argument types
if (arguments)
{
size_t dim = Argument::dim(arguments);
for (size_t i = 0; i < dim; i++)
{
Argument *arg = Argument::getNth(arguments, i);
arg->toDecoBuffer(buf);
}
}
}
/****************************************
* Determine if parameter list is really a template parameter list
* (i.e. it has auto or alias parameters)
*/
int Argument::isTPL(Arguments *arguments)
{
//printf("Argument::isTPL()\n");
if (arguments)
{
size_t dim = Argument::dim(arguments);
for (size_t i = 0; i < dim; i++)
{
Argument *arg = Argument::getNth(arguments, i);
if (arg->storageClass & (STCalias | STCauto | STCstatic))
return 1;
}
}
return 0;
}
/****************************************************
* Determine if parameter is a lazy array of delegates.
* If so, return the return type of those delegates.
* If not, return NULL.
*/
Type *Argument::isLazyArray()
{
// if (inout == Lazy)
{
Type *tb = type->toBasetype();
if (tb->ty == Tsarray || tb->ty == Tarray)
{
Type *tel = ((TypeArray *)tb)->next->toBasetype();
if (tel->ty == Tdelegate)
{
TypeDelegate *td = (TypeDelegate *)tel;
TypeFunction *tf = (TypeFunction *)td->next;
if (!tf->varargs && Argument::dim(tf->parameters) == 0)
{
return tf->next; // return type of delegate
}
}
}
}
return NULL;
}
void Argument::toDecoBuffer(OutBuffer *buf)
{
if (storageClass & STCscope)
buf->writeByte('M');
switch (storageClass & (STCin | STCout | STCref | STClazy))
{ case 0:
case STCin:
break;
case STCout:
buf->writeByte('J');
break;
case STCref:
buf->writeByte('K');
break;
case STClazy:
buf->writeByte('L');
break;
default:
#ifdef DEBUG
halt();
#endif
assert(0);
}
#if 0
int mod = 0x100;
if (type->toBasetype()->ty == Tclass)
mod = 0;
type->toDecoBuffer(buf, mod);
#else
//type->toHeadMutable()->toDecoBuffer(buf, 0);
type->toDecoBuffer(buf, 0);
#endif
}
/***************************************
* Determine number of arguments, folding in tuples.
*/
size_t Argument::dim(Arguments *args)
{
size_t n = 0;
if (args)
{
for (size_t i = 0; i < args->dim; i++)
{ Argument *arg = (Argument *)args->data[i];
Type *t = arg->type->toBasetype();
if (t->ty == Ttuple)
{ TypeTuple *tu = (TypeTuple *)t;
n += dim(tu->arguments);
}
else
n++;
}
}
return n;
}
/***************************************
* Get nth Argument, folding in tuples.
* Returns:
* Argument* nth Argument
* NULL not found, *pn gets incremented by the number
* of Arguments
*/
Argument *Argument::getNth(Arguments *args, size_t nth, size_t *pn)
{
if (!args)
return NULL;
size_t n = 0;
for (size_t i = 0; i < args->dim; i++)
{ Argument *arg = (Argument *)args->data[i];
Type *t = arg->type->toBasetype();
if (t->ty == Ttuple)
{ TypeTuple *tu = (TypeTuple *)t;
arg = getNth(tu->arguments, nth - n, &n);
if (arg)
return arg;
}
else if (n == nth)
return arg;
else
n++;
}
if (pn)
*pn += n;
return NULL;
}