Mercurial > projects > ldc
diff dmd/mtype.c @ 159:5acec6b2eef8 trunk
[svn r175] merged dmd 1.029
author | ChristianK |
---|---|
date | Thu, 01 May 2008 15:15:28 +0200 |
parents | 5c17f81fc1c1 |
children | 1856c62af24b |
line wrap: on
line diff
--- a/dmd/mtype.c Thu May 01 13:33:02 2008 +0200 +++ b/dmd/mtype.c Thu May 01 15:15:28 2008 +0200 @@ -1,5339 +1,5288 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 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> -#else -//#define signbit 56 -#endif - -#if __APPLE__ -#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; - -Type *Type::tvoidptr; -Type *Type::basic[TMAX]; -unsigned char Type::mangleChar[TMAX]; -StringTable Type::stringtable; - - -Type::Type(TY ty, Type *next) -{ - this->ty = ty; - this->next = next; - this->deco = NULL; - 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(); - - 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] = '@'; - - 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, - Tbit, Tbool, - Tascii, Twchar, Tdchar }; - - for (i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++) - basic[basetab[i]] = new TypeBasic(basetab[i]); - basic[Terror] = basic[Tint32]; - - tvoidptr = tvoid->pointerTo(); - - if (global.params.is64bit) - { - PTRSIZE = 8; -#if !IN_LLVM - if (global.params.isLinux) - REALSIZE = 10; - else - REALSIZE = 8; -#else - REALSIZE = 8; - REALPAD = 0; -#endif - Tsize_t = Tuns64; - Tptrdiff_t = Tint64; - } - else - { - PTRSIZE = 4; -#if IN_LLVM - REALSIZE = 8; - REALPAD = 0; -#elif TARGET_LINUX - REALSIZE = 12; - REALPAD = 2; -#else - REALSIZE = 10; - REALPAD = 0; -#endif - Tsize_t = Tuns32; - Tptrdiff_t = Tint32; - } -} - -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) -{ - if (next) - next = next->semantic(loc,sc); - return merge(); -} - -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. - */ - -void Type::toDecoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[ty]); - if (next) - { - assert(next != this); - //printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty); - next->toDecoBuffer(buf); - } -} - -/******************************** - * Name mangling. - */ - -void Type::toTypeInfoBuffer(OutBuffer *buf) -{ - assert(0); - buf->writeByte(mangleChar[ty]); -} - -/******************************** - * For pretty-printing a type. - */ - -char *Type::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - buf = new OutBuffer(); - toCBuffer2(buf, NULL, &hgs); - return buf->toChars(); -} - -void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer tbuf; - - toCBuffer2(&tbuf, ident, hgs); - buf->write(&tbuf); -} - -void Type::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring(toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -/************************************ - */ - -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::isbit() -{ - return FALSE; -} - -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; -} - -int Type::checkBoolean() -{ - return isscalar(); -} - -/********************************* - * Check type to see if it is based on a deprecated symbol. - */ - -void Type::checkDeprecated(Loc loc, Scope *sc) -{ - Type *t; - Dsymbol *s; - - for (t = this; t; t = t->next) - { - s = t->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); - //printf("\tthis->next=%p, to->next=%p\n", this->next, to->next); - if (this == to) - return MATCHexact; -// if (to->ty == Tvoid) -// return 1; - 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 = ((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(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; - - //toTypeInfoBuffer(&buf); - if (internal) - { buf.writeByte(mangleChar[ty]); - if (ty == Tarray) - buf.writeByte(mangleChar[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); - 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) -{ - Type *t; - - 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() -{ - if (!next) - return NULL; - else - return next->reliesOnTident(); -} - -/******************************** - * 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; -} - -/* ============================= TypeBasic =========================== */ - -TypeBasic::TypeBasic(TY ty) - : Type(ty, NULL) -{ char *c; - 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); - c = "void"; - break; - - case Tint8: d = Token::toChars(TOKint8); - c = "byte"; - flags |= TFLAGSintegral; - break; - - case Tuns8: d = Token::toChars(TOKuns8); - c = "ubyte"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tint16: d = Token::toChars(TOKint16); - c = "short"; - flags |= TFLAGSintegral; - break; - - case Tuns16: d = Token::toChars(TOKuns16); - c = "ushort"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tint32: d = Token::toChars(TOKint32); - c = "int"; - flags |= TFLAGSintegral; - break; - - case Tuns32: d = Token::toChars(TOKuns32); - c = "uint"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tfloat32: d = Token::toChars(TOKfloat32); - c = "float"; - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Tint64: d = Token::toChars(TOKint64); - c = "long"; - flags |= TFLAGSintegral; - break; - - case Tuns64: d = Token::toChars(TOKuns64); - c = "ulong"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tfloat64: d = Token::toChars(TOKfloat64); - c = "double"; - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Tfloat80: d = Token::toChars(TOKfloat80); - c = "real"; - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Timaginary32: d = Token::toChars(TOKimaginary32); - c = "ifloat"; - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Timaginary64: d = Token::toChars(TOKimaginary64); - c = "idouble"; - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Timaginary80: d = Token::toChars(TOKimaginary80); - c = "ireal"; - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Tcomplex32: d = Token::toChars(TOKcomplex32); - c = "cfloat"; - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - case Tcomplex64: d = Token::toChars(TOKcomplex64); - c = "cdouble"; - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - case Tcomplex80: d = Token::toChars(TOKcomplex80); - c = "creal"; - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - - case Tbit: d = Token::toChars(TOKbit); - c = "bit"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tbool: d = "bool"; - c = d; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tascii: d = Token::toChars(TOKchar); - c = "char"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Twchar: d = Token::toChars(TOKwchar); - c = "wchar"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tdchar: d = Token::toChars(TOKdchar); - c = "dchar"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - default: assert(0); - } - this->dstring = d; - this->cstring = c; - this->flags = flags; - merge(); -} - -Type *TypeBasic::syntaxCopy() -{ - // No semantic analysis done on basic types, no need to copy - return this; -} - - -char *TypeBasic::toChars() -{ - return dstring; -} - -void TypeBasic::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring(cstring); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -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 Tbit: 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; - - switch (ty) - { - case Tfloat80: - case Timaginary80: - case Tcomplex80: - sz = REALSIZE; - 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 Tbit: ivalue = 1; 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 Tbit: 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->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 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::isbit() -{ - return (ty == Tbit); -} - -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 == 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) - : Type(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; - FuncDeclaration *fd; - Expressions *arguments; - char *nm; - static char *name[2] = { "_adReverseChar", "_adReverseWchar" }; - - nm = name[n->ty == Twchar]; - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); - fd->runTimeHack = true; - ec = new VarExp(0, 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; - FuncDeclaration *fd; - Expressions *arguments; - char *nm; - static char *name[2] = { "_adSortChar", "_adSortWchar" }; - - nm = name[n->ty == Twchar]; - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); - fd->runTimeHack = true; - ec = new VarExp(0, 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) - { - Expression *ec; - FuncDeclaration *fd; - Expressions *arguments; - int size = next->size(e->loc); - int dup; - - assert(size); - dup = (ident == Id::dup); - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), dup ? Id::adDup : Id::adReverse); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - if (dup) - arguments->push(getTypeInfo(sc)); - arguments->push(e); - if (!dup) - arguments->push(new IntegerExp(0, size, Type::tint32)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else if (ident == Id::sort) - { - Expression *ec; - FuncDeclaration *fd; - Expressions *arguments; - - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), - (char*)(n->ty == Tbit ? "_adSortBit" : "_adSort")); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - arguments->push(e); - if (next->ty != Tbit) - arguments->push(n->ty == Tsarray - ? n->getTypeInfo(sc) // don't convert to dynamic array - : n->getInternalTypeInfo(sc)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else - { - e = Type::dotExp(sc, e, ident); - } - return e; -} - -void TypeArray::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ -#if 1 - OutBuffer buf2; - toPrettyBracket(&buf2, hgs); - buf->prependstring(buf2.toChars()); - if (ident) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - next->toCBuffer2(buf, NULL, hgs); -#elif 1 - // The D way - Type *t; - OutBuffer buf2; - for (t = this; 1; t = t->next) - { TypeArray *ta; - - ta = dynamic_cast<TypeArray *>(t); - if (!ta) - break; - ta->toPrettyBracket(&buf2, hgs); - } - buf->prependstring(buf2.toChars()); - if (ident) - { - buf2.writestring(ident->toChars()); - } - t->toCBuffer2(buf, NULL, hgs); -#else - // The C way - if (buf->offset) - { buf->bracket('(', ')'); - assert(!ident); - } - else if (ident) - buf->writestring(ident->toChars()); - Type *t = this; - do - { Expression *dim; - buf->writeByte('['); - dim = ((TypeSArray *)t)->dim; - if (dim) - buf->printf("%lld", dim->toInteger()); - buf->writeByte(']'); - t = t->next; - } while (t->ty == Tsarray); - t->toCBuffer2(buf, NULL, hgs); -#endif -} - - -/***************************** 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); - return t; -} - -d_uns64 TypeSArray::size(Loc loc) -{ integer_t sz; - - if (!dim) - return Type::size(loc); - sz = dim->toInteger(); - if (next->toBasetype()->ty == Tbit) // if array of bits - { - if (sz + 31 < sz) - goto Loverflow; - sz = ((sz + 31) & ~31) / 8; // size in bytes, rounded up to 32 bit dwords - } - else - { 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 %jd 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((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(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; - e = new IndexExp(loc, *pe, dim); - *pe = e; - } - else if (*ps) - { Dsymbol *s = *ps; - TupleDeclaration *td = s->isTupleDeclaration(); - if (td) - { - ScopeDsymbol *sym = new ArrayScopeSymbol(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 %ju 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 %ju 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); - Type *tbn = next->toBasetype(); - - if (dim) - { integer_t n, n2; - - dim = semanticLength(sc, tbn, dim); - - dim = dim->optimize(WANTvalue | WANTinterpret); - if (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 %jd 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 %ju 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) -{ - buf->writeByte(mangleChar[ty]); - if (dim) - buf->printf("%ju", dim->toInteger()); - if (next) - next->toDecoBuffer(buf); -} - -void TypeSArray::toTypeInfoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[Tarray]); - if (next) - next->toTypeInfoBuffer(buf); -} - -void TypeSArray::toPrettyBracket(OutBuffer *buf, HdrGenState *hgs) -{ - 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::implicitConvTo(Type *to) -{ - //printf("TypeSArray::implicitConvTo()\n"); - - // Allow implicit conversion of static array to pointer or dynamic array - if ((IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) && - (to->next->ty == Tvoid || next->equals(to->next) - /*|| to->next->isBaseOf(next)*/)) - { - return MATCHconvert; - } - if (to->ty == Tarray) - { int offset = 0; - - if (next->equals(to->next) || - (to->next->isBaseOf(next, &offset) && offset == 0) || - to->next->ty == Tvoid) - return MATCHconvert; - } -#if 0 - if (to->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)to; - - if (next->equals(tsa->next) && dim->equals(tsa->dim)) - { - return MATCHconvert; - } - } -#endif - return Type::implicitConvTo(to); -} - -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); - 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 (next != tn) - //deco = NULL; // redo - return tn->arrayOf(); - return merge(); -} - -void TypeDArray::toDecoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[ty]); - if (next) - next->toDecoBuffer(buf); -} - -void TypeDArray::toTypeInfoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[ty]); - if (next) - next->toTypeInfoBuffer(buf); -} - -void TypeDArray::toPrettyBracket(OutBuffer *buf, HdrGenState *hgs) -{ - 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()\n"); - - // Allow implicit conversion of array to pointer - if (IMPLICIT_ARRAY_TO_PTR && - to->ty == Tpointer && - (to->next->ty == Tvoid || next->equals(to->next) /*|| to->next->isBaseOf(next)*/)) - { - return MATCHconvert; - } - - if (to->ty == Tarray) - { int offset = 0; - - if ((to->next->isBaseOf(next, &offset) && offset == 0) || - to->next->ty == Tvoid) - 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; - this->key = NULL; -} - -Type *TypeAArray::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - Type *ti = index->syntaxCopy(); - if (t == next && ti == index) - t = this; - else - t = new TypeAArray(t, ti); - 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); - - // Compute key type; the purpose of the key type is to - // minimize the permutations of runtime library - // routines as much as possible. - key = index->toBasetype(); - switch (key->ty) - { -#if 0 - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - key = tint32; - break; -#endif - - case Tsarray: -#if 0 - // Convert to Tarray - key = key->next->arrayOf(); -#endif - break; - case Tbit: - case Tbool: - case Tfunction: - case Tvoid: - case Tnone: - error(loc, "can't have associative array key of %s", key->toChars()); - break; - } - next = next->semantic(loc,sc); - 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(); -} - -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; - FuncDeclaration *fd; - Expressions *arguments; - - fd = FuncDeclaration::genCfunc(Type::tsize_t, Id::aaLen); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = fd->type->next; - } - else if (ident == Id::keys) - { - Expression *ec; - FuncDeclaration *fd; - Expressions *arguments; - int size = key->size(e->loc); - - assert(size); - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaKeys); - fd->runTimeHack = true; - ec = new VarExp(0, 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; - FuncDeclaration *fd; - Expressions *arguments; - - fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaValues); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - arguments = new Expressions(); - arguments->push(e); - size_t keysize = key->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; - FuncDeclaration *fd; - Expressions *arguments; - - fd = FuncDeclaration::genCfunc(Type::tvoid->pointerTo(), Id::aaRehash); - fd->runTimeHack = true; - ec = new VarExp(0, fd); - arguments = new Expressions(); - arguments->push(e->addressOf(sc)); - arguments->push(key->getInternalTypeInfo(sc)); - e = new CallExp(e->loc, ec, arguments); - e->type = this; - } - else - { - e = Type::dotExp(sc, e, ident); - } - return e; -} - -void TypeAArray::toDecoBuffer(OutBuffer *buf) -{ - buf->writeByte(mangleChar[ty]); - index->toDecoBuffer(buf); - next->toDecoBuffer(buf); -} - -void TypeAArray::toPrettyBracket(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - { OutBuffer ibuf; - - index->toCBuffer2(&ibuf, NULL, hgs); - buf->write(&ibuf); - } - 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::checkBoolean() -{ - return TRUE; -} - -int TypeAArray::hasPointers() -{ - return TRUE; -} - -/***************************** TypePointer *****************************/ - -TypePointer::TypePointer(Type *t) - : Type(Tpointer, t) -{ -} - -Type *TypePointer::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - t = new TypePointer(t); - 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; - return merge(); -} - - -d_uns64 TypePointer::size(Loc loc) -{ - return PTRSIZE; -} - -void TypePointer::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - //printf("TypePointer::toCBuffer2() next = %d\n", next->ty); - buf->prependstring("*"); - if (ident) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - next->toCBuffer2(buf, NULL, hgs); -} - -MATCH TypePointer::implicitConvTo(Type *to) -{ - //printf("TypePointer::implicitConvTo()\n"); - - if (this == to) - return MATCHexact; - if (to->ty == Tpointer && to->next) - { - if (to->next->ty == Tvoid) - return MATCHconvert; - -#if 0 - if (to->next->isBaseOf(next)) - return MATCHconvert; -#endif - - if (next->ty == Tfunction && to->next->ty == Tfunction) - { TypeFunction *tf; - TypeFunction *tfto; - - tf = (TypeFunction *)(next); - tfto = (TypeFunction *)(to->next); - return tfto->equals(tf) ? MATCHexact : MATCHnomatch; - } - } -// if (to->ty == Tvoid) -// 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) - : Type(Treference, t) -{ - if (t->ty == Tbit) - error(0,"cannot make reference to a bit"); - // BUG: what about references to static arrays? -} - -Type *TypeReference::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - t = new TypeReference(t); - return t; -} - -d_uns64 TypeReference::size(Loc loc) -{ - return PTRSIZE; -} - -void TypeReference::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring("&"); - if (ident) - { - buf->writestring(ident->toChars()); - } - next->toCBuffer2(buf, NULL, hgs); -} - -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; - 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) - : Type(Tfunction, treturn) -{ -//if (!treturn) *(char*)0=0; -// assert(treturn); - this->parameters = parameters; - this->varargs = varargs; - this->linkage = linkage; - this->inuse = 0; - this->llvmRetInPtr = false; - this->llvmUsesThis = false; -} - -Type *TypeFunction::syntaxCopy() -{ - Type *treturn = next ? next->syntaxCopy() : NULL; - Arguments *params = Argument::arraySyntaxCopy(parameters); - Type *t = new TypeFunction(params, treturn, varargs, linkage); - 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; - - if (equals(t)) - goto Lcovariant; - if (ty != Tfunction || t->ty != Tfunction) - goto Ldistinct; - - { - TypeFunction *t1 = (TypeFunction *)this; - TypeFunction *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; - - Type *t1n = t1->next; - Type *t2n = t2->next; - - if (t1n->equals(t2n)) - goto Lcovariant; - if (t1n->ty != Tclass || t2n->ty != Tclass) - goto Lnotcovariant; - - // 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: - //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) -{ 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++; - 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; - default: - assert(0); - } - buf->writeByte(mc); - // 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::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - char *p = NULL; - - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; - 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; - default: - assert(0); - } - } - - if (buf->offset) - { - if (!hgs->hdrgen && p) - buf->prependstring(p); - buf->bracket('(', ')'); - assert(!ident); - } - else - { - if (!hgs->hdrgen && p) - buf->writestring(p); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toHChars2()); - } - } - Argument::argsToCBuffer(buf, hgs, parameters, varargs); - if (next && (!ident || ident->toHChars2() == ident->toChars())) - next->toCBuffer2(buf, NULL, hgs); - 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; - } - } - - 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); - Type *t; - - tf->inuse++; - arg->type = arg->type->semantic(loc,sc); - if (tf->inuse == 1) tf->inuse--; - 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 & STClazy) && t->ty == Tvoid) - error(loc, "cannot have parameter of type %s", arg->type->toChars()); - - if (arg->defaultArg) - { - arg->defaultArg = arg->defaultArg->semantic(sc); - arg->defaultArg = resolveProperties(sc, arg->defaultArg); - arg->defaultArg = arg->defaultArg->implicitCastTo(sc, arg->type); - } - - /* If arg turns out to be a tuple, the number of parameters may - * change. - */ - if (t->ty == Ttuple) - { dim = Argument::dim(tf->parameters); - i--; - } - } - } - tf->deco = tf->merge()->deco; - - if (tf->inuse) - { error(loc, "recursive type"); - tf->inuse = 0; - return terror; - } - - if (tf->varargs == 1 && tf->linkage != LINKd && Argument::dim(tf->parameters) == 0) - error(loc, "variadic functions with non-D linkage must have at least one parameter"); - - /* Don't return merge(), because arg identifiers and default args - * can be different - * even though the types match - */ - return tf; -} - -/******************************** - * 'args' are being matched to function 'this' - * Determine match level. - * Returns: - * MATCHxxxx - */ - -int TypeFunction::callMatch(Expressions *args) -{ - //printf("TypeFunction::callMatch()\n"); - int match = MATCHexact; // assume exact match - - 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++) - { int 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); - 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: - 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 (tb->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(tb->next); -#else - m = arg->implicitConvTo(tb->next); -#endif - if (m == 0) - 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) - : Type(Tfunction, t) -{ - ty = Tdelegate; -} - -Type *TypeDelegate::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - t = new TypeDelegate(t); - 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, Identifier *ident, HdrGenState *hgs) -{ -#if 1 - OutBuffer args; - TypeFunction *tf = (TypeFunction *)next; - - Argument::argsToCBuffer(&args, hgs, tf->parameters, tf->varargs); - buf->prependstring(args.toChars()); - buf->prependstring(" delegate"); - if (ident) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - next->next->toCBuffer2(buf, NULL, hgs); -#else - next->toCBuffer2(buf, Id::delegate, hgs); - if (ident) - { - buf->writestring(ident->toChars()); - } -#endif -} - -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->type = tvoidptr; - return e; - } - else if (ident == Id::funcptr) - { - e = e->addressOf(sc); - e->type = tvoidptr; - e = new AddExp(e->loc, e, new IntegerExp(PTRSIZE)); - e->type = tvoidptr; - e = new PtrExp(e->loc, e); - e->type = next->pointerTo(); - 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, NULL) -{ - 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, Identifier *ident, 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) -{ - Identifier *id = NULL; - int i; - VarDeclaration *v; - EnumMember *em; - TupleDeclaration *td; - Type *t; - 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 = s->toAlias(); - //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - for (i = 0; i < idents.dim; i++) - { Dsymbol *sm; - - id = (Identifier *)idents.data[i]; - sm = s->searchX(loc, sc, id); - //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - //printf("getType = '%s'\n", s->getType()->toChars()); - if (!sm) - { - v = s->isVarDeclaration(); - if (v && id == Id::length) - { - if (v->isConst() && v->getExpInitializer()) - { e = v->getExpInitializer()->exp; - } - else - 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); - 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) - { - // It's not a type, it's an expression - if (v->isConst() && v->getExpInitializer()) - { - ExpInitializer *ei = v->getExpInitializer(); - assert(ei); - *pe = ei->exp->copy(); // make copy so we can change loc - (*pe)->loc = loc; - } - else - { -#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: - 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; - 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); - return t; -} - -void TypeIdentifier::toDecoBuffer(OutBuffer *buf) -{ unsigned len; - char *name; - - name = ident->toChars(); - len = strlen(name); - buf->printf("%c%d%s", mangleChar[ty], len, name); - //buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeIdentifier::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer tmp; - - tmp.writestring(this->ident->toChars()); - toCBuffer2Helper(&tmp, NULL, hgs); - buf->prependstring(tmp.toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -/************************************* - * 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); -} - -/***************************************** - * 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()); - } - } - else - { -#ifdef DEBUG - if (!global.gag) - printf("1: "); -#endif - if (s) - { - s->error(loc, "is used as a type"); - } - 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); - return t; -} - - -void TypeInstance::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer tmp; - - tempinst->toCBuffer(&tmp, hgs); - toCBuffer2Helper(&tmp, NULL, hgs); - buf->prependstring(tmp.toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -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); - //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); - return t; -} - -Dsymbol *TypeTypeof::toDsymbol(Scope *sc) -{ - Type *t; - - t = semantic(0, sc); - if (t == this) - return NULL; - return t->toDsymbol(sc); -} - -void TypeTypeof::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer tmp; - - tmp.writestring("typeof("); - exp->toCBuffer(&tmp, hgs); - tmp.writeByte(')'); - toCBuffer2Helper(&tmp, NULL, hgs); - buf->prependstring(tmp.toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -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--; - t = exp->type; - if (!t) - { - error(loc, "expression (%s) has no type", exp->toChars()); - goto Lerr; - } - } - - 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); -} - - - -/***************************** TypeEnum *****************************/ - -TypeEnum::TypeEnum(EnumDeclaration *sym) - : Type(Tenum, NULL) -{ - this->sym = sym; -} - -char *TypeEnum::toChars() -{ - return sym->toChars(); -} - -Type *TypeEnum::semantic(Loc loc, Scope *sc) -{ - 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) -{ char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeEnum::toTypeInfoBuffer(OutBuffer *buf) -{ - toBasetype()->toTypeInfoBuffer(buf); -} - -void TypeEnum::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring(sym->toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ - EnumMember *m; - Dsymbol *s; - Expression *em; - -#if LOGDOTEXP - printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars()); -#endif - if (!sym->symtab) - goto Lfwd; - s = sym->symtab->lookup(ident); - if (!s) - { - return getProperty(e->loc, ident); - } - m = s->isEnumMember(); - em = m->value->copy(); - em->loc = e->loc; - return em; - -Lfwd: - error(e->loc, "forward reference of %s.%s", toChars(), ident->toChars()); - return new IntegerExp(0, 0, this); -} - -Expression *TypeEnum::getProperty(Loc loc, Identifier *ident) -{ Expression *e; - - if (ident == Id::max) - { - if (!sym->symtab) - goto Lfwd; - e = new IntegerExp(0, sym->maxval, this); - } - else if (ident == Id::min) - { - if (!sym->symtab) - goto Lfwd; - e = new IntegerExp(0, sym->minval, this); - } - else if (ident == Id::init) - { - if (!sym->symtab) - goto Lfwd; - e = defaultInit(loc); - } - else - { - if (!sym->memtype) - goto Lfwd; - e = sym->memtype->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 (this->equals(to)) - m = MATCHexact; // exact match - else if (sym->memtype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions - else - m = MATCHnomatch; // no match - return m; -} - -Expression *TypeEnum::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeEnum::defaultInit() '%s'\n", toChars()); -#endif - // Initialize to first member of enum - Expression *e; - e = new IntegerExp(loc, sym->defaultval, this); - return e; -} - -int TypeEnum::isZeroInit() -{ - return (sym->defaultval == 0); -} - -int TypeEnum::hasPointers() -{ - return toBasetype()->hasPointers(); -} - -/***************************** TypeTypedef *****************************/ - -TypeTypedef::TypeTypedef(TypedefDeclaration *sym) - : Type(Ttypedef, NULL) -{ - this->sym = sym; -} - -Type *TypeTypedef::syntaxCopy() -{ - return this; -} - -char *TypeTypedef::toChars() -{ - return sym->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; -} - -void TypeTypedef::toDecoBuffer(OutBuffer *buf) -{ unsigned len; - char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - //len = strlen(name); - //buf->printf("%c%d%s", mangleChar[ty], len, name); - buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeTypedef::toTypeInfoBuffer(OutBuffer *buf) -{ - sym->basetype->toTypeInfoBuffer(buf); -} - -void TypeTypedef::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - //printf("TypeTypedef::toCBuffer2() '%s'\n", sym->toChars()); - buf->prependstring(sym->toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->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 (ident == Id::init) - { - return Type::getProperty(loc, ident); - } - return sym->basetype->getProperty(loc, ident); -} - -int TypeTypedef::isbit() -{ - return sym->basetype->isbit(); -} - -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::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; - return t; -} - -MATCH TypeTypedef::implicitConvTo(Type *to) -{ MATCH m; - - //printf("TypeTypedef::implicitConvTo()\n"); - if (this->equals(to)) - m = MATCHexact; // exact match - else if (sym->basetype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions - else - m = MATCHnomatch; // no match - return m; -} - -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) - { - e->type = bt->next; - bt = bt->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, NULL) -{ - this->sym = sym; -} - -char *TypeStruct::toChars() -{ - //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco); - 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) -{ unsigned len; - char *name; - - name = sym->mangle(); - //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - //len = strlen(name); - //buf->printf("%c%d%s", mangleChar[ty], len, name); - buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeStruct::toTypeInfoBuffer(OutBuffer *buf) -{ - toDecoBuffer(buf); -} - - -void TypeStruct::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependbyte(' '); - buf->prependstring(toChars()); - if (ident) - buf->writestring(ident->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 (ident == Id::tupleof) - { - /* Create a TupleExp - */ - 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); - e = e->semantic(sc); - return e; - } - - 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; - } - } - - s = sym->search(e->loc, ident, 0); -L1: - if (!s) - { - //return getProperty(e->loc, ident); - return Type::dotExp(sc, e, ident); - } - s = s->toAlias(); - - v = s->isVarDeclaration(); - if (v && v->isConst()) - { ExpInitializer *ei = v->getExpInitializer(); - - if (ei) - { e = ei->exp->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; - - 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); - } - - 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); - 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)); -#if IN_LLVM - // LLVMDC modification - // this is *essential* - ((AddExp*)b)->llvmFieldIndex = true; -#endif - b->type = v->type->pointerTo(); - e = new PtrExp(e->loc, b); - e->type = v->type; - return e; - } - - 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::hasPointers() -{ - StructDeclaration *s = sym; - - sym->size(0); // give error for forward references - if (s->members) - { - for (size_t i = 0; i < s->members->dim; i++) - { - Dsymbol *sm = (Dsymbol *)s->members->data[i]; - if (sm->hasPointers()) - return TRUE; - } - } - return FALSE; -} - - -/***************************** TypeClass *****************************/ - -TypeClass::TypeClass(ClassDeclaration *sym) - : Type(Tclass, NULL) -{ - this->sym = sym; -} - -char *TypeClass::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) -{ unsigned len; - char *name; - - name = sym->mangle(); -// if (name[0] == '_' && name[1] == 'D') -// name += 2; - //printf("TypeClass::toDecoBuffer('%s') = '%s'\n", toChars(), name); - //len = strlen(name); - //buf->printf("%c%d%s", mangleChar[ty], len, name); - buf->printf("%c%s", mangleChar[ty], name); -} - -void TypeClass::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->prependstring(sym->toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ unsigned offset; - - Expression *b; - VarDeclaration *v; - Dsymbol *s; - DotVarExp *de; - Declaration *d; - -#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 - */ - 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); - e = e->semantic(sc); - 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) - { - Type *t; - - assert(ClassDeclaration::classinfo); - 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->next; - e = new PtrExp(e->loc, e); - e->type = ct->next->next; - - 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->next->next->next; - } - -#else - - e = new PtrExp(e->loc, e); - e->type = t->pointerTo(); - 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->type = e->type->pointerTo(); - e = new PtrExp(e->loc, e); - e->type = t->pointerTo(); - } - e = new PtrExp(e->loc, e, t); - -#endif - } - 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 - { - //return getProperty(e->loc, ident); - return Type::dotExp(sc, e, ident); - } - } - s = s->toAlias(); - v = s->isVarDeclaration(); - if (v && v->isConst()) - { ExpInitializer *ei = v->getExpInitializer(); - - if (ei) - { e = ei->exp->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; - - 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(); - 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) - { - VarExp *ve; - - 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); - 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()); - } - } - - 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 - ve = new VarExp(e->loc, d); - 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; - - ve = new VarExp(e->loc, d); - e = new CommaExp(e->loc, e, ve); - e->type = d->type; - return e; - } - - 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('%s')\n", to->toChars()); - if (this == to) - return MATCHexact; - - ClassDeclaration *cdto = to->isClassHandle(); - if (cdto && cdto->isBaseOf(sym, NULL)) - { //printf("is base\n"); - return MATCHconvert; - } - - if (global.params.Dversion == 1) - { - // Allow conversion to (void *) - if (to->ty == Tpointer && to->next->ty == Tvoid) - return MATCHconvert; - } - - return MATCHnomatch; -} - -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, NULL) -{ - //printf("TypeTuple(this = %p)\n", this); - this->arguments = arguments; -#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, NULL) -{ - 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(STCin, 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); - return t; -} - -Type *TypeTuple::semantic(Loc loc, Scope *sc) -{ - //printf("TypeTuple::semantic(this = %p)\n", this); - 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; -} - -void TypeTuple::toCBuffer2(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer buf2; - Argument::argsToCBuffer(&buf2, hgs, arguments, 0); - buf->prependstring(buf2.toChars()); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -void TypeTuple::toDecoBuffer(OutBuffer *buf) -{ - //printf("TypeTuple::toDecoBuffer() this = %p\n", this); - OutBuffer buf2; - Argument::argsToDecoBuffer(&buf2, arguments); - unsigned len = buf2.offset; - buf->printf("%c%d%.*s", mangleChar[ty], 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) - : Type(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()); - return t; -} - -Type *TypeSlice::semantic(Loc loc, Scope *sc) -{ - //printf("TypeSlice::semantic() %s\n", toChars()); - next = next->semantic(loc, sc); - //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 [%ju..%ju] 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(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 [%ju..%ju] 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, Identifier *ident, HdrGenState *hgs) -{ - OutBuffer buf2; - - buf2.printf("[%s .. ", lwr->toChars()); - buf2.printf("%s]", upr->toChars()); - - buf->prependstring(buf2.toChars()); - if (ident) - { - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - next->toCBuffer2(buf, NULL, hgs); -} - -/***************************** Argument *****************************/ - -Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg) -{ - this->type = type; - this->ident = ident; - this->storageClass = storageClass; - this->defaultArg = defaultArg; - this->vardecl = 0; -} - -Argument *Argument::syntaxCopy() -{ - Argument *a = new Argument(storageClass, - type ? type->syntaxCopy() : NULL, - ident, - defaultArg ? defaultArg->syntaxCopy() : NULL); - return a; -} - -Arguments *Argument::arraySyntaxCopy(Arguments *args) -{ Arguments *a = NULL; - - if (args) - { - a = new Arguments(); - a->setDim(args->dim); - for (size_t i = 0; i < a->dim; i++) - { Argument *arg = (Argument *)args->data[i]; - - arg = arg->syntaxCopy(); - a->data[i] = (void *)arg; - } - } - return a; -} - -char *Argument::argsTypesToChars(Arguments *args, int varargs) -{ OutBuffer *buf; - - buf = new OutBuffer(); - - buf->writeByte('('); - if (args) - { int i; - OutBuffer argbuf; - HdrGenState hgs; - - for (i = 0; i < args->dim; i++) - { Argument *arg; - - if (i) - buf->writeByte(','); - arg = (Argument *)args->data[i]; - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, NULL, &hgs); - buf->write(&argbuf); - } - if (varargs) - { - if (i && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } - } - buf->writeByte(')'); - - 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++) - { Argument *arg; - - if (i) - buf->writestring(", "); - 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 & STClazy) - buf->writestring("lazy "); - argbuf.reset(); - arg->type->toCBuffer2(&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 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 = 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); - } - type->toDecoBuffer(buf); -} - -/*************************************** - * 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; -} + +// 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> +#else +//#define signbit 56 +#endif + +#if __APPLE__ +#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; + +Type *Type::tvoidptr; +Type *Type::basic[TMAX]; +unsigned char Type::mangleChar[TMAX]; +StringTable Type::stringtable; + + +Type::Type(TY ty, Type *next) +{ + this->ty = ty; + this->mod = 0; + this->next = next; + this->deco = NULL; +#if V2 + 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(); + + 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] = '@'; + + 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, + Tbit, Tbool, + Tascii, Twchar, Tdchar }; + + for (i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++) + basic[basetab[i]] = new TypeBasic(basetab[i]); + basic[Terror] = basic[Tint32]; + + tvoidptr = tvoid->pointerTo(); + + if (global.params.is64bit) + { + PTRSIZE = 8; +#if !IN_LLVM + if (global.params.isLinux) + REALSIZE = 10; + else + REALSIZE = 8; +#else + REALSIZE = 8; + REALPAD = 0; +#endif + Tsize_t = Tuns64; + Tptrdiff_t = Tint64; + } + else + { + PTRSIZE = 4; +#if IN_LLVM + REALSIZE = 8; + REALPAD = 0; +#elif TARGET_LINUX + REALSIZE = 12; + REALPAD = 2; +#else + REALSIZE = 10; + REALPAD = 0; +#endif + Tsize_t = Tuns32; + Tptrdiff_t = Tint32; + } +} + +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) +{ + if (next) + next = next->semantic(loc,sc); + return merge(); +} + +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. + */ + +void Type::toDecoBuffer(OutBuffer *buf) +{ + buf->writeByte(mangleChar[ty]); + if (next) + { + assert(next != this); + //printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty); + next->toDecoBuffer(buf); + } +} + +/******************************** + * 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) + { char *p; + + switch (this->mod) + { + 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); + } + } +} + + +/************************************ + */ + +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::isbit() +{ + return FALSE; +} + +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; +} + +int Type::checkBoolean() +{ + return isscalar(); +} + +/********************************* + * Check type to see if it is based on a deprecated symbol. + */ + +void Type::checkDeprecated(Loc loc, Scope *sc) +{ + Type *t; + Dsymbol *s; + + for (t = this; t; t = t->next) + { + s = t->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); + //printf("\tthis->next=%p, to->next=%p\n", this->next, to->next); + if (this == to) + return MATCHexact; +// if (to->ty == Tvoid) +// return 1; + 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 = ((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(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; + + //toTypeInfoBuffer(&buf); + if (internal) + { buf.writeByte(mangleChar[ty]); + if (ty == Tarray) + buf.writeByte(mangleChar[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); + 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) +{ + Type *t; + + 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() +{ + if (!next) + return NULL; + else + return next->reliesOnTident(); +} + +/******************************** + * 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; +} + +/* ============================= TypeBasic =========================== */ + +TypeBasic::TypeBasic(TY ty) + : Type(ty, NULL) +{ char *c; + 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); + c = "void"; + break; + + case Tint8: d = Token::toChars(TOKint8); + c = "byte"; + flags |= TFLAGSintegral; + break; + + case Tuns8: d = Token::toChars(TOKuns8); + c = "ubyte"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case Tint16: d = Token::toChars(TOKint16); + c = "short"; + flags |= TFLAGSintegral; + break; + + case Tuns16: d = Token::toChars(TOKuns16); + c = "ushort"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case Tint32: d = Token::toChars(TOKint32); + c = "int"; + flags |= TFLAGSintegral; + break; + + case Tuns32: d = Token::toChars(TOKuns32); + c = "uint"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case Tfloat32: d = Token::toChars(TOKfloat32); + c = "float"; + flags |= TFLAGSfloating | TFLAGSreal; + break; + + case Tint64: d = Token::toChars(TOKint64); + c = "long"; + flags |= TFLAGSintegral; + break; + + case Tuns64: d = Token::toChars(TOKuns64); + c = "ulong"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case Tfloat64: d = Token::toChars(TOKfloat64); + c = "double"; + flags |= TFLAGSfloating | TFLAGSreal; + break; + + case Tfloat80: d = Token::toChars(TOKfloat80); + c = "real"; + flags |= TFLAGSfloating | TFLAGSreal; + break; + + case Timaginary32: d = Token::toChars(TOKimaginary32); + c = "ifloat"; + flags |= TFLAGSfloating | TFLAGSimaginary; + break; + + case Timaginary64: d = Token::toChars(TOKimaginary64); + c = "idouble"; + flags |= TFLAGSfloating | TFLAGSimaginary; + break; + + case Timaginary80: d = Token::toChars(TOKimaginary80); + c = "ireal"; + flags |= TFLAGSfloating | TFLAGSimaginary; + break; + + case Tcomplex32: d = Token::toChars(TOKcomplex32); + c = "cfloat"; + flags |= TFLAGSfloating | TFLAGScomplex; + break; + + case Tcomplex64: d = Token::toChars(TOKcomplex64); + c = "cdouble"; + flags |= TFLAGSfloating | TFLAGScomplex; + break; + + case Tcomplex80: d = Token::toChars(TOKcomplex80); + c = "creal"; + flags |= TFLAGSfloating | TFLAGScomplex; + break; + + + case Tbit: d = Token::toChars(TOKbit); + c = "bit"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case Tbool: d = "bool"; + c = d; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case Tascii: d = Token::toChars(TOKchar); + c = "char"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case Twchar: d = Token::toChars(TOKwchar); + c = "wchar"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + case Tdchar: d = Token::toChars(TOKdchar); + c = "dchar"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; + + default: assert(0); + } + this->dstring = d; + this->cstring = c; + this->flags = flags; + merge(); +} + +Type *TypeBasic::syntaxCopy() +{ + // No semantic analysis done on basic types, no need to copy + return this; +} + + +char *TypeBasic::toChars() +{ + return dstring; +} + +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 Tbit: 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; + + switch (ty) + { + case Tfloat80: + case Timaginary80: + case Tcomplex80: + sz = REALSIZE; + 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 Tbit: ivalue = 1; 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 Tbit: 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->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 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::isbit() +{ + return (ty == Tbit); +} + +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 == 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) + : Type(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; + FuncDeclaration *fd; + Expressions *arguments; + char *nm; + static char *name[2] = { "_adReverseChar", "_adReverseWchar" }; + + nm = name[n->ty == Twchar]; + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); + fd->runTimeHack = true; + ec = new VarExp(0, 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; + FuncDeclaration *fd; + Expressions *arguments; + char *nm; + static char *name[2] = { "_adSortChar", "_adSortWchar" }; + + nm = name[n->ty == Twchar]; + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), nm); + fd->runTimeHack = true; + ec = new VarExp(0, 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) + { + Expression *ec; + FuncDeclaration *fd; + Expressions *arguments; + int size = next->size(e->loc); + int dup; + + assert(size); + dup = (ident == Id::dup); + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), dup ? Id::adDup : Id::adReverse); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + e = e->castTo(sc, n->arrayOf()); // convert to dynamic array + arguments = new Expressions(); + if (dup) + arguments->push(getTypeInfo(sc)); + arguments->push(e); + if (!dup) + arguments->push(new IntegerExp(0, size, Type::tint32)); + e = new CallExp(e->loc, ec, arguments); + e->type = next->arrayOf(); + } + else if (ident == Id::sort) + { + Expression *ec; + FuncDeclaration *fd; + Expressions *arguments; + + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), + (char*)(n->ty == Tbit ? "_adSortBit" : "_adSort")); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + e = e->castTo(sc, n->arrayOf()); // convert to dynamic array + arguments = new Expressions(); + arguments->push(e); + if (next->ty != Tbit) + arguments->push(n->ty == Tsarray + ? n->getTypeInfo(sc) // don't convert to dynamic array + : n->getInternalTypeInfo(sc)); + 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); + return t; +} + +d_uns64 TypeSArray::size(Loc loc) +{ integer_t sz; + + if (!dim) + return Type::size(loc); + sz = dim->toInteger(); + if (next->toBasetype()->ty == Tbit) // if array of bits + { + if (sz + 31 < sz) + goto Loverflow; + sz = ((sz + 31) & ~31) / 8; // size in bytes, rounded up to 32 bit dwords + } + else + { 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 %jd 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((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(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; + e = new IndexExp(loc, *pe, dim); + *pe = e; + } + else if (*ps) + { Dsymbol *s = *ps; + TupleDeclaration *td = s->isTupleDeclaration(); + if (td) + { + ScopeDsymbol *sym = new ArrayScopeSymbol(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 %ju 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 %ju 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); + Type *tbn = next->toBasetype(); + + if (dim) + { integer_t n, n2; + + dim = semanticLength(sc, tbn, dim); + + dim = dim->optimize(WANTvalue | WANTinterpret); + if (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 %jd 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 %ju 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) +{ + buf->writeByte(mangleChar[ty]); + if (dim) + buf->printf("%ju", dim->toInteger()); + if (next) + next->toDecoBuffer(buf); +} + +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::implicitConvTo(Type *to) +{ + //printf("TypeSArray::implicitConvTo()\n"); + + // Allow implicit conversion of static array to pointer or dynamic array + if ((IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) && + (to->next->ty == Tvoid || next->equals(to->next) + /*|| to->next->isBaseOf(next)*/)) + { + return MATCHconvert; + } + if (to->ty == Tarray) + { int offset = 0; + + if (next->equals(to->next) || + (to->next->isBaseOf(next, &offset) && offset == 0) || + to->next->ty == Tvoid) + return MATCHconvert; + } +#if 0 + if (to->ty == Tsarray) + { + TypeSArray *tsa = (TypeSArray *)to; + + if (next->equals(tsa->next) && dim->equals(tsa->dim)) + { + return MATCHconvert; + } + } +#endif + return Type::implicitConvTo(to); +} + +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); + 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 (next != tn) + //deco = NULL; // redo + return tn->arrayOf(); + return merge(); +} + +void TypeDArray::toDecoBuffer(OutBuffer *buf) +{ + buf->writeByte(mangleChar[ty]); + if (next) + next->toDecoBuffer(buf); +} + +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()\n"); + + // Allow implicit conversion of array to pointer + if (IMPLICIT_ARRAY_TO_PTR && + to->ty == Tpointer && + (to->next->ty == Tvoid || next->equals(to->next) /*|| to->next->isBaseOf(next)*/)) + { + return MATCHconvert; + } + + if (to->ty == Tarray) + { int offset = 0; + + if ((to->next->isBaseOf(next, &offset) && offset == 0) || + to->next->ty == Tvoid) + 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; + this->key = NULL; +} + +Type *TypeAArray::syntaxCopy() +{ + Type *t = next->syntaxCopy(); + Type *ti = index->syntaxCopy(); + if (t == next && ti == index) + t = this; + else + t = new TypeAArray(t, ti); + 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); + + // Compute key type; the purpose of the key type is to + // minimize the permutations of runtime library + // routines as much as possible. + key = index->toBasetype(); + switch (key->ty) + { +#if 0 + case Tint8: + case Tuns8: + case Tint16: + case Tuns16: + key = tint32; + break; +#endif + + case Tsarray: +#if 0 + // Convert to Tarray + key = key->next->arrayOf(); +#endif + break; + case Tbit: + case Tbool: + case Tfunction: + case Tvoid: + case Tnone: + error(loc, "can't have associative array key of %s", key->toChars()); + break; + } + next = next->semantic(loc,sc); + 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(); +} + +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; + FuncDeclaration *fd; + Expressions *arguments; + + fd = FuncDeclaration::genCfunc(Type::tsize_t, Id::aaLen); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + arguments = new Expressions(); + arguments->push(e); + e = new CallExp(e->loc, ec, arguments); + e->type = fd->type->next; + } + else if (ident == Id::keys) + { + Expression *ec; + FuncDeclaration *fd; + Expressions *arguments; + int size = key->size(e->loc); + + assert(size); + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaKeys); + fd->runTimeHack = true; + ec = new VarExp(0, 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; + FuncDeclaration *fd; + Expressions *arguments; + + fd = FuncDeclaration::genCfunc(Type::tvoid->arrayOf(), Id::aaValues); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + arguments = new Expressions(); + arguments->push(e); + size_t keysize = key->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; + FuncDeclaration *fd; + Expressions *arguments; + + fd = FuncDeclaration::genCfunc(Type::tvoid->pointerTo(), Id::aaRehash); + fd->runTimeHack = true; + ec = new VarExp(0, fd); + arguments = new Expressions(); + arguments->push(e->addressOf(sc)); + arguments->push(key->getInternalTypeInfo(sc)); + e = new CallExp(e->loc, ec, arguments); + e->type = this; + } + else + { + e = Type::dotExp(sc, e, ident); + } + return e; +} + +void TypeAArray::toDecoBuffer(OutBuffer *buf) +{ + buf->writeByte(mangleChar[ty]); + index->toDecoBuffer(buf); + next->toDecoBuffer(buf); +} + +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::checkBoolean() +{ + return TRUE; +} + +int TypeAArray::hasPointers() +{ + return TRUE; +} + +/***************************** TypePointer *****************************/ + +TypePointer::TypePointer(Type *t) + : Type(Tpointer, t) +{ +} + +Type *TypePointer::syntaxCopy() +{ + Type *t = next->syntaxCopy(); + if (t == next) + t = this; + else + t = new TypePointer(t); + 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; + 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()\n"); + + if (this == to) + return MATCHexact; + if (to->ty == Tpointer && to->next) + { + if (to->next->ty == Tvoid) + return MATCHconvert; + +#if 0 + if (to->next->isBaseOf(next)) + return MATCHconvert; +#endif + + if (next->ty == Tfunction && to->next->ty == Tfunction) + { TypeFunction *tf; + TypeFunction *tfto; + + tf = (TypeFunction *)(next); + tfto = (TypeFunction *)(to->next); + return tfto->equals(tf) ? MATCHexact : MATCHnomatch; + } + } +// if (to->ty == Tvoid) +// 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) + : Type(Treference, t) +{ + if (t->ty == Tbit) + error(0,"cannot make reference to a bit"); + // BUG: what about references to static arrays? +} + +Type *TypeReference::syntaxCopy() +{ + Type *t = next->syntaxCopy(); + if (t == next) + t = this; + else + t = new TypeReference(t); + return t; +} + +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; + 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) + : Type(Tfunction, treturn) +{ +//if (!treturn) *(char*)0=0; +// assert(treturn); + this->parameters = parameters; + this->varargs = varargs; + this->linkage = linkage; + this->inuse = 0; + this->llvmRetInPtr = false; + this->llvmUsesThis = false; +} + +Type *TypeFunction::syntaxCopy() +{ + Type *treturn = next ? next->syntaxCopy() : NULL; + Arguments *params = Argument::arraySyntaxCopy(parameters); + Type *t = new TypeFunction(params, treturn, varargs, linkage); + 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; + + if (equals(t)) + goto Lcovariant; + if (ty != Tfunction || t->ty != Tfunction) + goto Ldistinct; + + { + TypeFunction *t1 = (TypeFunction *)this; + TypeFunction *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; + + Type *t1n = t1->next; + Type *t2n = t2->next; + + if (t1n->equals(t2n)) + goto Lcovariant; + if (t1n->ty != Tclass || t2n->ty != Tclass) + goto Lnotcovariant; + + // 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: + //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) +{ 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++; + 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; + default: + assert(0); + } + buf->writeByte(mc); + // 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) +{ + char *p = NULL; + + if (inuse) + { inuse = 2; // flag error to caller + return; + } + inuse++; + 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; + 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) +{ + 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; + default: + assert(0); + } + } + + if (!hgs->hdrgen && p) + buf->writestring(p); + buf->writestring(" function"); + Argument::argsToCBuffer(buf, hgs, parameters, varargs); + 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; + } + } + + 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); + Type *t; + + tf->inuse++; + arg->type = arg->type->semantic(loc,sc); + if (tf->inuse == 1) tf->inuse--; + 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 & STClazy) && t->ty == Tvoid) + error(loc, "cannot have parameter of type %s", arg->type->toChars()); + + if (arg->defaultArg) + { + arg->defaultArg = arg->defaultArg->semantic(sc); + arg->defaultArg = resolveProperties(sc, arg->defaultArg); + arg->defaultArg = arg->defaultArg->implicitCastTo(sc, arg->type); + } + + /* If arg turns out to be a tuple, the number of parameters may + * change. + */ + if (t->ty == Ttuple) + { dim = Argument::dim(tf->parameters); + i--; + } + } + } + tf->deco = tf->merge()->deco; + + if (tf->inuse) + { error(loc, "recursive type"); + tf->inuse = 0; + return terror; + } + + if (tf->varargs == 1 && tf->linkage != LINKd && Argument::dim(tf->parameters) == 0) + error(loc, "variadic functions with non-D linkage must have at least one parameter"); + + /* Don't return merge(), because arg identifiers and default args + * can be different + * even though the types match + */ + return tf; +} + +/******************************** + * 'args' are being matched to function 'this' + * Determine match level. + * Returns: + * MATCHxxxx + */ + +int TypeFunction::callMatch(Expressions *args) +{ + //printf("TypeFunction::callMatch()\n"); + int match = MATCHexact; // assume exact match + + 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++) + { int 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); + 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: + 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 (tb->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(tb->next); +#else + m = arg->implicitConvTo(tb->next); +#endif + if (m == 0) + 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) + : Type(Tfunction, t) +{ + ty = Tdelegate; +} + +Type *TypeDelegate::syntaxCopy() +{ + Type *t = next->syntaxCopy(); + if (t == next) + t = this; + else + t = new TypeDelegate(t); + 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->type = tvoidptr; + return e; + } + else if (ident == Id::funcptr) + { + e = e->addressOf(sc); + e->type = tvoidptr; + e = new AddExp(e->loc, e, new IntegerExp(PTRSIZE)); + e->type = tvoidptr; + e = new PtrExp(e->loc, e); + e->type = next->pointerTo(); + 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, NULL) +{ + 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) +{ + Identifier *id = NULL; + int i; + VarDeclaration *v; + EnumMember *em; + TupleDeclaration *td; + Type *t; + 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 = s->toAlias(); + //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); + for (i = 0; i < idents.dim; i++) + { Dsymbol *sm; + + id = (Identifier *)idents.data[i]; + sm = s->searchX(loc, sc, id); + //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); + //printf("getType = '%s'\n", s->getType()->toChars()); + if (!sm) + { + v = s->isVarDeclaration(); + if (v && id == Id::length) + { + if (v->isConst() && v->getExpInitializer()) + { e = v->getExpInitializer()->exp; + } + else + 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); + 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) + { + // It's not a type, it's an expression + if (v->isConst() && v->getExpInitializer()) + { + ExpInitializer *ei = v->getExpInitializer(); + assert(ei); + *pe = ei->exp->copy(); // make copy so we can change loc + (*pe)->loc = loc; + } + else + { +#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: + 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; + 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); + return t; +} + +void TypeIdentifier::toDecoBuffer(OutBuffer *buf) +{ unsigned len; + char *name; + + name = ident->toChars(); + len = strlen(name); + buf->printf("%c%d%s", mangleChar[ty], len, name); + //buf->printf("%c%s", mangleChar[ty], 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); +} + +/***************************************** + * 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()); + } + } + else + { +#ifdef DEBUG + if (!global.gag) + printf("1: "); +#endif + if (s) + { + s->error(loc, "is used as a type"); + } + 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); + 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); + //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); + return t; +} + +Dsymbol *TypeTypeof::toDsymbol(Scope *sc) +{ + Type *t; + + t = semantic(0, 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--; + t = exp->type; + if (!t) + { + error(loc, "expression (%s) has no type", exp->toChars()); + goto Lerr; + } + } + + 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); +} + + + +/***************************** TypeEnum *****************************/ + +TypeEnum::TypeEnum(EnumDeclaration *sym) + : Type(Tenum, NULL) +{ + this->sym = sym; +} + +char *TypeEnum::toChars() +{ + return sym->toChars(); +} + +Type *TypeEnum::semantic(Loc loc, Scope *sc) +{ + 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) +{ char *name; + + name = sym->mangle(); +// if (name[0] == '_' && name[1] == 'D') +// name += 2; + buf->printf("%c%s", mangleChar[ty], 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) +{ + EnumMember *m; + Dsymbol *s; + Expression *em; + +#if LOGDOTEXP + printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars()); +#endif + if (!sym->symtab) + goto Lfwd; + s = sym->symtab->lookup(ident); + if (!s) + { + return getProperty(e->loc, ident); + } + m = s->isEnumMember(); + em = m->value->copy(); + em->loc = e->loc; + return em; + +Lfwd: + error(e->loc, "forward reference of %s.%s", toChars(), ident->toChars()); + return new IntegerExp(0, 0, this); +} + +Expression *TypeEnum::getProperty(Loc loc, Identifier *ident) +{ Expression *e; + + if (ident == Id::max) + { + if (!sym->symtab) + goto Lfwd; + e = new IntegerExp(0, sym->maxval, this); + } + else if (ident == Id::min) + { + if (!sym->symtab) + goto Lfwd; + e = new IntegerExp(0, sym->minval, this); + } + else if (ident == Id::init) + { + if (!sym->symtab) + goto Lfwd; + e = defaultInit(loc); + } + else + { + if (!sym->memtype) + goto Lfwd; + e = sym->memtype->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 (this->equals(to)) + m = MATCHexact; // exact match + else if (sym->memtype->implicitConvTo(to)) + m = MATCHconvert; // match with conversions + else + m = MATCHnomatch; // no match + return m; +} + +Expression *TypeEnum::defaultInit(Loc loc) +{ +#if LOGDEFAULTINIT + printf("TypeEnum::defaultInit() '%s'\n", toChars()); +#endif + // Initialize to first member of enum + Expression *e; + e = new IntegerExp(loc, sym->defaultval, this); + return e; +} + +int TypeEnum::isZeroInit() +{ + return (sym->defaultval == 0); +} + +int TypeEnum::hasPointers() +{ + return toBasetype()->hasPointers(); +} + +/***************************** TypeTypedef *****************************/ + +TypeTypedef::TypeTypedef(TypedefDeclaration *sym) + : Type(Ttypedef, NULL) +{ + this->sym = sym; +} + +Type *TypeTypedef::syntaxCopy() +{ + return this; +} + +char *TypeTypedef::toChars() +{ + return sym->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; +} + +void TypeTypedef::toDecoBuffer(OutBuffer *buf) +{ unsigned len; + char *name; + + name = sym->mangle(); +// if (name[0] == '_' && name[1] == 'D') +// name += 2; + //len = strlen(name); + //buf->printf("%c%d%s", mangleChar[ty], len, name); + buf->printf("%c%s", mangleChar[ty], 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 (ident == Id::init) + { + return Type::getProperty(loc, ident); + } + return sym->basetype->getProperty(loc, ident); +} + +int TypeTypedef::isbit() +{ + return sym->basetype->isbit(); +} + +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::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; + return t; +} + +MATCH TypeTypedef::implicitConvTo(Type *to) +{ MATCH m; + + //printf("TypeTypedef::implicitConvTo()\n"); + if (this->equals(to)) + m = MATCHexact; // exact match + else if (sym->basetype->implicitConvTo(to)) + m = MATCHconvert; // match with conversions + else + m = MATCHnomatch; // no match + return m; +} + +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) + { + e->type = bt->next; + bt = bt->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, NULL) +{ + this->sym = sym; +} + +char *TypeStruct::toChars() +{ + //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco); + 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) +{ unsigned len; + char *name; + + name = sym->mangle(); + //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name); +// if (name[0] == '_' && name[1] == 'D') +// name += 2; + //len = strlen(name); + //buf->printf("%c%d%s", mangleChar[ty], len, name); + buf->printf("%c%s", mangleChar[ty], 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 (ident == Id::tupleof) + { + /* Create a TupleExp + */ + 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); + e = e->semantic(sc); + return e; + } + + 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; + } + } + + s = sym->search(e->loc, ident, 0); +L1: + if (!s) + { + //return getProperty(e->loc, ident); + return Type::dotExp(sc, e, ident); + } + s = s->toAlias(); + + v = s->isVarDeclaration(); + if (v && v->isConst()) + { ExpInitializer *ei = v->getExpInitializer(); + + if (ei) + { e = ei->exp->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; + + 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); + } + + 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); + 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)); +#if IN_LLVM + // LLVMDC modification + // this is *essential* + ((AddExp*)b)->llvmFieldIndex = true; +#endif + b->type = v->type->pointerTo(); + e = new PtrExp(e->loc, b); + e->type = v->type; + return e; + } + + 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::hasPointers() +{ + StructDeclaration *s = sym; + + sym->size(0); // give error for forward references + if (s->members) + { + for (size_t i = 0; i < s->members->dim; i++) + { + Dsymbol *sm = (Dsymbol *)s->members->data[i]; + if (sm->hasPointers()) + return TRUE; + } + } + return FALSE; +} + + +/***************************** TypeClass *****************************/ + +TypeClass::TypeClass(ClassDeclaration *sym) + : Type(Tclass, NULL) +{ + this->sym = sym; +} + +char *TypeClass::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) +{ unsigned len; + char *name; + + name = sym->mangle(); +// if (name[0] == '_' && name[1] == 'D') +// name += 2; + //printf("TypeClass::toDecoBuffer('%s') = '%s'\n", toChars(), name); + //len = strlen(name); + //buf->printf("%c%d%s", mangleChar[ty], len, name); + buf->printf("%c%s", mangleChar[ty], 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; + DotVarExp *de; + Declaration *d; + +#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 + */ + 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); + e = e->semantic(sc); + 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) + { + Type *t; + + assert(ClassDeclaration::classinfo); + 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->next; + e = new PtrExp(e->loc, e); + e->type = ct->next->next; + + 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->next->next->next; + } + +#else + + e = new PtrExp(e->loc, e); + e->type = t->pointerTo(); + 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->type = e->type->pointerTo(); + e = new PtrExp(e->loc, e); + e->type = t->pointerTo(); + } + e = new PtrExp(e->loc, e, t); + +#endif + } + 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 + { + //return getProperty(e->loc, ident); + return Type::dotExp(sc, e, ident); + } + } + s = s->toAlias(); + v = s->isVarDeclaration(); + if (v && v->isConst()) + { ExpInitializer *ei = v->getExpInitializer(); + + if (ei) + { e = ei->exp->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; + + 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(); + 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) + { + VarExp *ve; + + 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); + 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()); + } + } + + 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 + ve = new VarExp(e->loc, d); + 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; + + ve = new VarExp(e->loc, d); + e = new CommaExp(e->loc, e, ve); + e->type = d->type; + return e; + } + + 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('%s')\n", to->toChars()); + if (this == to) + return MATCHexact; + + ClassDeclaration *cdto = to->isClassHandle(); + if (cdto && cdto->isBaseOf(sym, NULL)) + { //printf("is base\n"); + return MATCHconvert; + } + + if (global.params.Dversion == 1) + { + // Allow conversion to (void *) + if (to->ty == Tpointer && to->next->ty == Tvoid) + return MATCHconvert; + } + + return MATCHnomatch; +} + +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, NULL) +{ + //printf("TypeTuple(this = %p)\n", this); + this->arguments = arguments; +#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, NULL) +{ + 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(STCin, 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); + return t; +} + +Type *TypeTuple::semantic(Loc loc, Scope *sc) +{ + //printf("TypeTuple::semantic(this = %p)\n", this); + 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; +} + +void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + Argument::argsToCBuffer(buf, hgs, arguments, 0); +} + +void TypeTuple::toDecoBuffer(OutBuffer *buf) +{ + //printf("TypeTuple::toDecoBuffer() this = %p\n", this); + OutBuffer buf2; + Argument::argsToDecoBuffer(&buf2, arguments); + unsigned len = buf2.offset; + buf->printf("%c%d%.*s", mangleChar[ty], 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) + : Type(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()); + return t; +} + +Type *TypeSlice::semantic(Loc loc, Scope *sc) +{ + //printf("TypeSlice::semantic() %s\n", toChars()); + next = next->semantic(loc, sc); + //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 [%ju..%ju] 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(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 [%ju..%ju] 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->vardecl = 0; +} + +Argument *Argument::syntaxCopy() +{ + Argument *a = new Argument(storageClass, + type ? type->syntaxCopy() : NULL, + ident, + defaultArg ? defaultArg->syntaxCopy() : NULL); + return a; +} + +Arguments *Argument::arraySyntaxCopy(Arguments *args) +{ Arguments *a = NULL; + + if (args) + { + a = new Arguments(); + a->setDim(args->dim); + for (size_t i = 0; i < a->dim; i++) + { Argument *arg = (Argument *)args->data[i]; + + arg = arg->syntaxCopy(); + a->data[i] = (void *)arg; + } + } + return a; +} + +char *Argument::argsTypesToChars(Arguments *args, int varargs) +{ OutBuffer *buf; + + buf = new OutBuffer(); + + buf->writeByte('('); + if (args) + { int i; + OutBuffer argbuf; + HdrGenState hgs; + + for (i = 0; i < args->dim; i++) + { Argument *arg; + + if (i) + buf->writeByte(','); + 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(')'); + + 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++) + { Argument *arg; + + if (i) + buf->writestring(", "); + 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 & STClazy) + buf->writestring("lazy "); + argbuf.reset(); + 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 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 = 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); + } + type->toDecoBuffer(buf); +} + +/*************************************** + * 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; +}