Mercurial > projects > ldc
diff dmd2/mtype.c @ 758:f04dde6e882c
Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:38:48 +0100 |
parents | |
children | 9a9f403ab399 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/mtype.c Tue Nov 11 01:38:48 2008 +0100 @@ -0,0 +1,6383 @@ + +// 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 <math.h> + +#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 <math.h> +static double zero = 0; +#elif __MINGW32__ +#include <math.h> +static double zero = 0; +#elif __GNUC__ +#include <math.h> +#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" + +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() +{ unsigned sz; + + //LDC: it's bad that we always have to check LLVM's align and + // dmd's align info match. Can't we somehow get at LLVM's align + // here? + + switch (ty) + { + case Tfloat80: + case Timaginary80: + case Tcomplex80: + if (global.params.cpu == ARCHx86_64) + sz = 16; + else + sz = 4; + break; + + case Tint64: + case Tuns64: + case Tfloat64: + case Timaginary64: + if (global.params.cpu == ARCHx86_64) + sz = 8; + else + sz = 4; + break; + + default: + sz = size(0); + break; + } + return sz; +} + + +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 (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::tint32)); + 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 + 4 - 1) & ~(4 - 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->getTypeInfo(sc)); // LDC, we don't support the getInternalTypeInfo + // optimization arbitrarily, not yet at least... + 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 1; +} + +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; + this->retInPtr = false; + this->usesThis = false; + this->usesNest = false; + this->retAttrs = 0; + this->thisAttrs = 0; + this->reverseParams = false; + this->reverseIndex = 0; +} + +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; + t->retInPtr = retInPtr; + t->usesThis = usesThis; + t->usesNest = usesNest; + t->retAttrs = retAttrs; + t->thisAttrs = thisAttrs; + t->reverseParams = reverseParams; + t->reverseIndex = reverseIndex; + 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 != arg2->storageClass) + 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); + + // make sure default arguments only use variables with lower protection + // this check only catches the common case that the default arg Exp is a VarExp + if(arg->defaultArg->op == TOKvar) + { VarExp *ve = (VarExp *)arg->defaultArg; + if(ve->var->protection != PROTundefined && ve->var->protection < sc->protection) + error(loc, "default argument %s has stronger protection than function %s", ve->var->toChars(), toChars()); + } + } + + /* 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(); +} + +/***************************** 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; +} + +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 + { + 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; +} + +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) +{ Symbol *s; + Declaration *d; + +#if LOGDEFAULTINIT + printf("TypeStruct::defaultInit() '%s'\n", toChars()); +#endif + s = sym->toInitializer(); + d = new SymbolDeclaration(sym->loc, s, 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; + this->llvmAttrs = 0; +} + +Argument *Argument::syntaxCopy() +{ + Argument *a = new Argument(storageClass, + type ? type->syntaxCopy() : NULL, + ident, + defaultArg ? defaultArg->syntaxCopy() : NULL); + a->llvmAttrs = llvmAttrs; + 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 & STCconst) + buf->writestring("const "); + if (arg->storageClass & STCinvariant) + buf->writestring("invariant "); + + 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) +{ + 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; +}