# HG changeset patch # User Robert Clipsham # Date 1243700612 -3600 # Node ID 638d16625da28ae9327b34c1b66c6ac650b00dd7 # Parent 42bd767ec5a4014fa5a65a43c42638dfea83a48c LDC 2 compiles again. diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/access.c --- a/dmd2/access.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/access.c Sat May 30 17:23:32 2009 +0100 @@ -1,424 +1,425 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include -#include - -#include "root.h" -#include "mem.h" - -#include "enum.h" -#include "aggregate.h" -#include "init.h" -#include "attrib.h" -#include "scope.h" -#include "id.h" -#include "mtype.h" -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "module.h" - -#define LOG 0 - -/* Code to do access checks - */ - -int hasPackageAccess(Scope *sc, Dsymbol *s); - -/**************************************** - * Return PROT access for Dsymbol smember in this declaration. - */ - -enum PROT AggregateDeclaration::getAccess(Dsymbol *smember) -{ - return PROTpublic; -} - -enum PROT StructDeclaration::getAccess(Dsymbol *smember) -{ - enum PROT access_ret = PROTnone; - -#if LOG - printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n", - toChars(), smember->toChars()); -#endif - if (smember->toParent() == this) - { - access_ret = smember->prot(); - } - else if (smember->isDeclaration()->isStatic()) - { - access_ret = smember->prot(); - } - return access_ret; -} - -enum PROT ClassDeclaration::getAccess(Dsymbol *smember) -{ - enum PROT access_ret = PROTnone; - -#if LOG - printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", - toChars(), smember->toChars()); -#endif - if (smember->toParent() == this) - { - access_ret = smember->prot(); - } - else - { - enum PROT access; - int i; - - if (smember->isDeclaration()->isStatic()) - { - access_ret = smember->prot(); - } - - for (i = 0; i < baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)baseclasses.data[i]; - - access = b->base->getAccess(smember); - switch (access) - { - case PROTnone: - break; - - case PROTprivate: - access = PROTnone; // private members of base class not accessible - break; - - case PROTpackage: - case PROTprotected: - case PROTpublic: - case PROTexport: - // If access is to be tightened - if (b->protection < access) - access = b->protection; - - // Pick path with loosest access - if (access > access_ret) - access_ret = access; - break; - - default: - assert(0); - } - } - } -#if LOG - printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", - toChars(), smember->toChars(), access_ret); -#endif - return access_ret; -} - -/******************************************************** - * Helper function for ClassDeclaration::accessCheck() - * Returns: - * 0 no access - * 1 access - */ - -static int accessCheckX( - Dsymbol *smember, - Dsymbol *sfunc, - AggregateDeclaration *dthis, - AggregateDeclaration *cdscope) -{ - assert(dthis); - -#if 0 - printf("accessCheckX for %s.%s in function %s() in scope %s\n", - dthis->toChars(), smember->toChars(), - sfunc ? sfunc->toChars() : "NULL", - cdscope ? cdscope->toChars() : "NULL"); -#endif - if (dthis->hasPrivateAccess(sfunc) || - dthis->isFriendOf(cdscope)) - { - if (smember->toParent() == dthis) - return 1; - else - { - ClassDeclaration *cdthis = dthis->isClassDeclaration(); - if (cdthis) - { - for (int i = 0; i < cdthis->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i]; - enum PROT access; - - access = b->base->getAccess(smember); - if (access >= PROTprotected || - accessCheckX(smember, sfunc, b->base, cdscope) - ) - return 1; - - } - } - } - } - else - { - if (smember->toParent() != dthis) - { - ClassDeclaration *cdthis = dthis->isClassDeclaration(); - if (cdthis) - { - for (int i = 0; i < cdthis->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i]; - - if (accessCheckX(smember, sfunc, b->base, cdscope)) - return 1; - } - } - } - } - return 0; -} - -/******************************* - * Do access check for member of this class, this class being the - * type of the 'this' pointer used to access smember. - */ - -void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) -{ - int result; - - FuncDeclaration *f = sc->func; - AggregateDeclaration *cdscope = sc->getStructClassScope(); - enum PROT access; - -#if LOG - printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n", - toChars(), smember->toChars(), - f ? f->toChars() : NULL, - cdscope ? cdscope->toChars() : NULL); -#endif - - Dsymbol *smemberparent = smember->toParent(); - if (!smemberparent || !smemberparent->isAggregateDeclaration()) - { -#if LOG - printf("not an aggregate member\n"); -#endif - return; // then it is accessible - } - - // BUG: should enable this check - //assert(smember->parent->isBaseOf(this, NULL)); - - if (smemberparent == this) - { enum PROT access = smember->prot(); - - result = access >= PROTpublic || - hasPrivateAccess(f) || - isFriendOf(cdscope) || - (access == PROTpackage && hasPackageAccess(sc, this)); -#if LOG - printf("result1 = %d\n", result); -#endif - } - else if ((access = this->getAccess(smember)) >= PROTpublic) - { - result = 1; -#if LOG - printf("result2 = %d\n", result); -#endif - } - else if (access == PROTpackage && hasPackageAccess(sc, this)) - { - result = 1; -#if LOG - printf("result3 = %d\n", result); -#endif - } - else - { - result = accessCheckX(smember, f, this, cdscope); -#if LOG - printf("result4 = %d\n", result); -#endif - } - if (!result) - { - error(loc, "member %s is not accessible", smember->toChars()); -halt(); - } -} - -/**************************************** - * Determine if this is the same or friend of cd. - */ - -int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd) -{ -#if LOG - printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null"); -#endif - if (this == cd) - return 1; - - // Friends if both are in the same module - //if (toParent() == cd->toParent()) - if (cd && getModule() == cd->getModule()) - { -#if LOG - printf("\tin same module\n"); -#endif - return 1; - } - -#if LOG - printf("\tnot friend\n"); -#endif - return 0; -} - -/**************************************** - * Determine if scope sc has package level access to s. - */ - -int hasPackageAccess(Scope *sc, Dsymbol *s) -{ -#if LOG - printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc); -#endif - - for (; s; s = s->parent) - { - if (s->isPackage() && !s->isModule()) - break; - } -#if LOG - if (s) - printf("\tthis is in package '%s'\n", s->toChars()); -#endif - - if (s && s == sc->module->parent) - { -#if LOG - printf("\ts is in same package as sc\n"); -#endif - return 1; - } - - -#if LOG - printf("\tno package access\n"); -#endif - return 0; -} - -/********************************** - * Determine if smember has access to private members of this declaration. - */ - -int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember) -{ - if (smember) - { AggregateDeclaration *cd = NULL; - Dsymbol *smemberparent = smember->toParent(); - if (smemberparent) - cd = smemberparent->isAggregateDeclaration(); - -#if LOG - printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", - toChars(), smember->toChars()); -#endif - - if (this == cd) // smember is a member of this class - { -#if LOG - printf("\tyes 1\n"); -#endif - return 1; // so we get private access - } - - // If both are members of the same module, grant access - while (1) - { Dsymbol *sp = smember->toParent(); - if (sp->isFuncDeclaration() && smember->isFuncDeclaration()) - smember = sp; - else - break; - } - if (!cd && toParent() == smember->toParent()) - { -#if LOG - printf("\tyes 2\n"); -#endif - return 1; - } - if (!cd && getModule() == smember->getModule()) - { -#if LOG - printf("\tyes 3\n"); -#endif - return 1; - } - } -#if LOG - printf("\tno\n"); -#endif - return 0; -} - -/**************************************** - * Check access to d for expression e.d - */ - -void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) -{ -#if LOG - if (e) - { printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars()); - printf("\te->type = %s\n", e->type->toChars()); - } - else - { - //printf("accessCheck(%s)\n", d->toChars()); - } -#endif - if (!e) - { - if (d->prot() == PROTprivate && d->getModule() != sc->module || - d->prot() == PROTpackage && !hasPackageAccess(sc, d)) - - error(loc, "%s %s.%s is not accessible from %s", - d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars()); - } - else if (e->type->ty == Tclass) - { // Do access check - ClassDeclaration *cd; - - cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); -#if 1 - if (e->op == TOKsuper) - { ClassDeclaration *cd2; - - cd2 = sc->func->toParent()->isClassDeclaration(); - if (cd2) - cd = cd2; - } -#endif - cd->accessCheck(loc, sc, d); - } - else if (e->type->ty == Tstruct) - { // Do access check - StructDeclaration *cd; - - cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); - cd->accessCheck(loc, sc, d); - } -} + +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + + +#include +#include +#include + +#include "root.h" +#include "rmem.h" + +#include "enum.h" +#include "aggregate.h" +#include "init.h" +#include "attrib.h" +#include "scope.h" +#include "id.h" +#include "mtype.h" +#include "declaration.h" +#include "aggregate.h" +#include "expression.h" +#include "module.h" + +#define LOG 0 + +/* Code to do access checks + */ + +int hasPackageAccess(Scope *sc, Dsymbol *s); + +/**************************************** + * Return PROT access for Dsymbol smember in this declaration. + */ + +enum PROT AggregateDeclaration::getAccess(Dsymbol *smember) +{ + return PROTpublic; +} + +enum PROT StructDeclaration::getAccess(Dsymbol *smember) +{ + enum PROT access_ret = PROTnone; + +#if LOG + printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n", + toChars(), smember->toChars()); +#endif + if (smember->toParent() == this) + { + access_ret = smember->prot(); + } + else if (smember->isDeclaration()->isStatic()) + { + access_ret = smember->prot(); + } + return access_ret; +} + +enum PROT ClassDeclaration::getAccess(Dsymbol *smember) +{ + enum PROT access_ret = PROTnone; + +#if LOG + printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", + toChars(), smember->toChars()); +#endif + if (smember->toParent() == this) + { + access_ret = smember->prot(); + } + else + { + enum PROT access; + int i; + + if (smember->isDeclaration()->isStatic()) + { + access_ret = smember->prot(); + } + + for (i = 0; i < baseclasses.dim; i++) + { BaseClass *b = (BaseClass *)baseclasses.data[i]; + + access = b->base->getAccess(smember); + switch (access) + { + case PROTnone: + break; + + case PROTprivate: + access = PROTnone; // private members of base class not accessible + break; + + case PROTpackage: + case PROTprotected: + case PROTpublic: + case PROTexport: + // If access is to be tightened + if (b->protection < access) + access = b->protection; + + // Pick path with loosest access + if (access > access_ret) + access_ret = access; + break; + + default: + assert(0); + } + } + } +#if LOG + printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", + toChars(), smember->toChars(), access_ret); +#endif + return access_ret; +} + +/******************************************************** + * Helper function for ClassDeclaration::accessCheck() + * Returns: + * 0 no access + * 1 access + */ + +static int accessCheckX( + Dsymbol *smember, + Dsymbol *sfunc, + AggregateDeclaration *dthis, + AggregateDeclaration *cdscope) +{ + assert(dthis); + +#if 0 + printf("accessCheckX for %s.%s in function %s() in scope %s\n", + dthis->toChars(), smember->toChars(), + sfunc ? sfunc->toChars() : "NULL", + cdscope ? cdscope->toChars() : "NULL"); +#endif + if (dthis->hasPrivateAccess(sfunc) || + dthis->isFriendOf(cdscope)) + { + if (smember->toParent() == dthis) + return 1; + else + { + ClassDeclaration *cdthis = dthis->isClassDeclaration(); + if (cdthis) + { + for (int i = 0; i < cdthis->baseclasses.dim; i++) + { BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i]; + enum PROT access; + + access = b->base->getAccess(smember); + if (access >= PROTprotected || + accessCheckX(smember, sfunc, b->base, cdscope) + ) + return 1; + + } + } + } + } + else + { + if (smember->toParent() != dthis) + { + ClassDeclaration *cdthis = dthis->isClassDeclaration(); + if (cdthis) + { + for (int i = 0; i < cdthis->baseclasses.dim; i++) + { BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i]; + + if (accessCheckX(smember, sfunc, b->base, cdscope)) + return 1; + } + } + } + } + return 0; +} + +/******************************* + * Do access check for member of this class, this class being the + * type of the 'this' pointer used to access smember. + */ + +void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) +{ + int result; + + FuncDeclaration *f = sc->func; + AggregateDeclaration *cdscope = sc->getStructClassScope(); + enum PROT access; + +#if LOG + printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n", + toChars(), smember->toChars(), + f ? f->toChars() : NULL, + cdscope ? cdscope->toChars() : NULL); +#endif + + Dsymbol *smemberparent = smember->toParent(); + if (!smemberparent || !smemberparent->isAggregateDeclaration()) + { +#if LOG + printf("not an aggregate member\n"); +#endif + return; // then it is accessible + } + + // BUG: should enable this check + //assert(smember->parent->isBaseOf(this, NULL)); + + if (smemberparent == this) + { enum PROT access = smember->prot(); + + result = access >= PROTpublic || + hasPrivateAccess(f) || + isFriendOf(cdscope) || + (access == PROTpackage && hasPackageAccess(sc, this)); +#if LOG + printf("result1 = %d\n", result); +#endif + } + else if ((access = this->getAccess(smember)) >= PROTpublic) + { + result = 1; +#if LOG + printf("result2 = %d\n", result); +#endif + } + else if (access == PROTpackage && hasPackageAccess(sc, this)) + { + result = 1; +#if LOG + printf("result3 = %d\n", result); +#endif + } + else + { + result = accessCheckX(smember, f, this, cdscope); +#if LOG + printf("result4 = %d\n", result); +#endif + } + if (!result) + { + error(loc, "member %s is not accessible", smember->toChars()); +halt(); + } +} + +/**************************************** + * Determine if this is the same or friend of cd. + */ + +int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd) +{ +#if LOG + printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null"); +#endif + if (this == cd) + return 1; + + // Friends if both are in the same module + //if (toParent() == cd->toParent()) + if (cd && getModule() == cd->getModule()) + { +#if LOG + printf("\tin same module\n"); +#endif + return 1; + } + +#if LOG + printf("\tnot friend\n"); +#endif + return 0; +} + +/**************************************** + * Determine if scope sc has package level access to s. + */ + +int hasPackageAccess(Scope *sc, Dsymbol *s) +{ +#if LOG + printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc); +#endif + + for (; s; s = s->parent) + { + if (s->isPackage() && !s->isModule()) + break; + } +#if LOG + if (s) + printf("\tthis is in package '%s'\n", s->toChars()); +#endif + + if (s && s == sc->module->parent) + { +#if LOG + printf("\ts is in same package as sc\n"); +#endif + return 1; + } + + +#if LOG + printf("\tno package access\n"); +#endif + return 0; +} + +/********************************** + * Determine if smember has access to private members of this declaration. + */ + +int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember) +{ + if (smember) + { AggregateDeclaration *cd = NULL; + Dsymbol *smemberparent = smember->toParent(); + if (smemberparent) + cd = smemberparent->isAggregateDeclaration(); + +#if LOG + printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", + toChars(), smember->toChars()); +#endif + + if (this == cd) // smember is a member of this class + { +#if LOG + printf("\tyes 1\n"); +#endif + return 1; // so we get private access + } + + // If both are members of the same module, grant access + while (1) + { Dsymbol *sp = smember->toParent(); + if (sp->isFuncDeclaration() && smember->isFuncDeclaration()) + smember = sp; + else + break; + } + if (!cd && toParent() == smember->toParent()) + { +#if LOG + printf("\tyes 2\n"); +#endif + return 1; + } + if (!cd && getModule() == smember->getModule()) + { +#if LOG + printf("\tyes 3\n"); +#endif + return 1; + } + } +#if LOG + printf("\tno\n"); +#endif + return 0; +} + +/**************************************** + * Check access to d for expression e.d + */ + +void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) +{ +#if LOG + if (e) + { printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars()); + printf("\te->type = %s\n", e->type->toChars()); + } + else + { + //printf("accessCheck(%s)\n", d->toChars()); + } +#endif + if (!e) + { + if (d->getModule() != sc->module) + if (d->prot() == PROTprivate || + d->prot() == PROTpackage && !hasPackageAccess(sc, d)) + + error(loc, "%s %s.%s is not accessible from %s", + d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars()); + } + else if (e->type->ty == Tclass) + { // Do access check + ClassDeclaration *cd; + + cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); +#if 1 + if (e->op == TOKsuper) + { ClassDeclaration *cd2; + + cd2 = sc->func->toParent()->isClassDeclaration(); + if (cd2) + cd = cd2; + } +#endif + cd->accessCheck(loc, sc, d); + } + else if (e->type->ty == Tstruct) + { // Do access check + StructDeclaration *cd; + + cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); + cd->accessCheck(loc, sc, d); + } +} diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/aggregate.h --- a/dmd2/aggregate.h Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/aggregate.h Sat May 30 17:23:32 2009 +0100 @@ -1,292 +1,320 @@ - -// 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. - -#ifndef DMD_AGGREGATE_H -#define DMD_AGGREGATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -#include -#include -#include - -struct Identifier; -struct Type; -struct TypeFunction; -struct Expression; -struct FuncDeclaration; -struct CtorDeclaration; -struct DtorDeclaration; -struct InvariantDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct InterfaceDeclaration; -struct ClassInfoDeclaration; -struct VarDeclaration; -struct dt_t; - -namespace llvm -{ - class Type; - class Value; - class Constant; - class ConstantStruct; - class GlobalVariable; -} - -struct AggregateDeclaration : ScopeDsymbol -{ - Type *type; - unsigned storage_class; - enum PROT protection; - Type *handle; // 'this' type - unsigned structsize; // size of struct - unsigned alignsize; // size of struct for alignment purposes - unsigned structalign; // struct member alignment in effect - int hasUnions; // set if aggregate has overlapping fields - Array fields; // VarDeclaration fields - unsigned sizeok; // set when structsize contains valid data - // 0: no size - // 1: size is correct - // 2: cannot determine size; fwd referenced - int isdeprecated; // !=0 if deprecated - Scope *scope; // !=NULL means context to use - - // Special member functions - InvariantDeclaration *inv; // invariant - NewDeclaration *aggNew; // allocator - DeleteDeclaration *aggDelete; // deallocator - -#if DMDV2 - CtorDeclaration *ctor; - CtorDeclaration *defaultCtor; // default constructor -#endif - - FuncDeclarations dtors; // Array of destructors - FuncDeclaration *dtor; // aggregate destructor - -#ifdef IN_GCC - Array methods; // flat list of all methods for debug information -#endif - - AggregateDeclaration(Loc loc, Identifier *id); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - unsigned size(Loc loc); - static void alignmember(unsigned salign, unsigned size, unsigned *poffset); - Type *getType(); - void addField(Scope *sc, VarDeclaration *v); - int isDeprecated(); // is aggregate deprecated? - FuncDeclaration *buildDtor(Scope *sc); - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - // For access checking - virtual PROT getAccess(Dsymbol *smember); // determine access to smember - int isFriendOf(AggregateDeclaration *cd); - int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class? - void accessCheck(Loc loc, Scope *sc, Dsymbol *smember); - - enum PROT prot(); - - // Back end - Symbol *stag; // tag symbol for debug data - Symbol *sinit; - Symbol *toInitializer(); - - AggregateDeclaration *isAggregateDeclaration() { return this; } -}; - -struct AnonymousAggregateDeclaration : AggregateDeclaration -{ - AnonymousAggregateDeclaration() - : AggregateDeclaration(0, NULL) - { - } - - AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; } -}; - -struct StructDeclaration : AggregateDeclaration -{ - int zeroInit; // !=0 if initialize with 0 fill -#if DMDV2 - int hasIdentityAssign; // !=0 if has identity opAssign - FuncDeclaration *cpctor; // generated copy-constructor, if any - - FuncDeclarations postblits; // Array of postblit functions - FuncDeclaration *postblit; // aggregate postblit -#endif - - StructDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *mangle(); - const char *kind(); - int needOpAssign(); - FuncDeclaration *buildOpAssign(Scope *sc); - FuncDeclaration *buildPostBlit(Scope *sc); - FuncDeclaration *buildCpCtor(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - - void toObjFile(int multiobj); // compile to .obj file - void toDt(dt_t **pdt); - void toDebug(); // to symbolic debug info - - StructDeclaration *isStructDeclaration() { return this; } -}; - -struct UnionDeclaration : StructDeclaration -{ - UnionDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - const char *kind(); - - UnionDeclaration *isUnionDeclaration() { return this; } -}; - -struct BaseClass -{ - Type *type; // (before semantic processing) - enum PROT protection; // protection for the base interface - - ClassDeclaration *base; - int offset; // 'this' pointer offset - Array vtbl; // for interfaces: Array of FuncDeclaration's - // making up the vtbl[] - - int baseInterfaces_dim; - BaseClass *baseInterfaces; // if BaseClass is an interface, these - // are a copy of the InterfaceDeclaration::interfaces - - BaseClass(); - BaseClass(Type *type, enum PROT protection); - - int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance); - void copyBaseInterfaces(BaseClasses *); -}; - -#if DMDV2 -#define CLASSINFO_SIZE (0x3C+16) // value of ClassInfo.size -#else -#define CLASSINFO_SIZE (0x3C+12) // value of ClassInfo.size -#endif - -struct ClassDeclaration : AggregateDeclaration -{ - static ClassDeclaration *object; - static ClassDeclaration *classinfo; - - ClassDeclaration *baseClass; // NULL only if this is Object - FuncDeclaration *staticCtor; - FuncDeclaration *staticDtor; - Array vtbl; // Array of FuncDeclaration's making up the vtbl[] - Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] - - BaseClasses baseclasses; // Array of BaseClass's; first is super, - // rest are Interface's - - int interfaces_dim; - BaseClass **interfaces; // interfaces[interfaces_dim] for this class - // (does not include baseClass) - - BaseClasses *vtblInterfaces; // array of base interfaces that have - // their own vtbl[] - - ClassInfoDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration - int com; // !=0 if this is a COM class (meaning - // it derives from IUnknown) - int isauto; // !=0 if this is an auto class - int isabstract; // !=0 if abstract class - - int isnested; // !=0 if is nested - VarDeclaration *vthis; // 'this' parameter if this class is nested - - int inuse; // to prevent recursive attempts - - ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isBaseOf2(ClassDeclaration *cd); - - #define OFFSET_RUNTIME 0x76543210 - virtual int isBaseOf(ClassDeclaration *cd, int *poffset); - - Dsymbol *search(Loc, Identifier *ident, int flags); -#if DMDV2 - int isFuncHidden(FuncDeclaration *fd); -#endif - FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); - void interfaceSemantic(Scope *sc); - int isNested(); - int isCOMclass(); - virtual int isCOMinterface(); -#if DMDV2 - virtual int isCPPinterface(); -#endif - int isAbstract(); - virtual int vtblOffset(); - const char *kind(); - char *mangle(); - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - - void addLocalClass(ClassDeclarations *); - - // Back end - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - unsigned baseVtblOffset(BaseClass *bc); - Symbol *toSymbol(); - Symbol *toVtblSymbol(); - void toDt(dt_t **pdt); - void toDt2(dt_t **pdt, ClassDeclaration *cd); - - Symbol *vtblsym; - - ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } -}; - -struct InterfaceDeclaration : ClassDeclaration -{ -#if DMDV2 - int cpp; // !=0 if this is a C++ interface -#endif - InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - int isBaseOf(ClassDeclaration *cd, int *poffset); - int isBaseOf(BaseClass *bc, int *poffset); - const char *kind(); - int vtblOffset(); -#if DMDV2 - int isCPPinterface(); -#endif - virtual int isCOMinterface(); - - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); - - InterfaceDeclaration *isInterfaceDeclaration() { return this; } -}; - -#endif /* DMD_AGGREGATE_H */ + +// 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. + +#ifndef DMD_AGGREGATE_H +#define DMD_AGGREGATE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "dsymbol.h" + +#if IN_LLVM +#include +#include +#include +#endif + +struct Identifier; +struct Type; +struct TypeFunction; +struct Expression; +struct FuncDeclaration; +struct CtorDeclaration; +struct DtorDeclaration; +struct InvariantDeclaration; +struct NewDeclaration; +struct DeleteDeclaration; +struct InterfaceDeclaration; +struct ClassInfoDeclaration; +struct VarDeclaration; +struct dt_t; + +#if IN_LLVM +namespace llvm +{ + class Type; + class Value; + class Constant; + class ConstantStruct; + class GlobalVariable; +} +#endif + +struct AggregateDeclaration : ScopeDsymbol +{ + Type *type; + unsigned storage_class; + enum PROT protection; + Type *handle; // 'this' type + unsigned structsize; // size of struct + unsigned alignsize; // size of struct for alignment purposes + unsigned structalign; // struct member alignment in effect + int hasUnions; // set if aggregate has overlapping fields + Array fields; // VarDeclaration fields + unsigned sizeok; // set when structsize contains valid data + // 0: no size + // 1: size is correct + // 2: cannot determine size; fwd referenced + int isdeprecated; // !=0 if deprecated + Scope *scope; // !=NULL means context to use + + int isnested; // !=0 if is nested + VarDeclaration *vthis; // 'this' parameter if this aggregate is nested + + // Special member functions + InvariantDeclaration *inv; // invariant + NewDeclaration *aggNew; // allocator + DeleteDeclaration *aggDelete; // deallocator + +#if DMDV2 + //CtorDeclaration *ctor; + Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration + CtorDeclaration *defaultCtor; // default constructor + Dsymbol *aliasthis; // forward unresolved lookups to aliasthis +#endif + + FuncDeclarations dtors; // Array of destructors + FuncDeclaration *dtor; // aggregate destructor + +#ifdef IN_GCC + Array methods; // flat list of all methods for debug information +#endif + + AggregateDeclaration(Loc loc, Identifier *id); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void inlineScan(); + unsigned size(Loc loc); + static void alignmember(unsigned salign, unsigned size, unsigned *poffset); + Type *getType(); + void addField(Scope *sc, VarDeclaration *v); + int isDeprecated(); // is aggregate deprecated? + FuncDeclaration *buildDtor(Scope *sc); + int isNested(); + + void emitComment(Scope *sc); + void toDocBuffer(OutBuffer *buf); + + // For access checking + virtual PROT getAccess(Dsymbol *smember); // determine access to smember + int isFriendOf(AggregateDeclaration *cd); + int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class? + void accessCheck(Loc loc, Scope *sc, Dsymbol *smember); + + enum PROT prot(); + +#if IN_DMD + // Back end + Symbol *stag; // tag symbol for debug data + Symbol *sinit; + Symbol *toInitializer(); +#endif + + AggregateDeclaration *isAggregateDeclaration() { return this; } +}; + +struct AnonymousAggregateDeclaration : AggregateDeclaration +{ + AnonymousAggregateDeclaration() + : AggregateDeclaration(0, NULL) + { + } + + AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; } +}; + +struct StructDeclaration : AggregateDeclaration +{ + int zeroInit; // !=0 if initialize with 0 fill +#if DMDV2 + int hasIdentityAssign; // !=0 if has identity opAssign + FuncDeclaration *cpctor; // generated copy-constructor, if any + + FuncDeclarations postblits; // Array of postblit functions + FuncDeclaration *postblit; // aggregate postblit +#endif + + StructDeclaration(Loc loc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *mangle(); + const char *kind(); + int needOpAssign(); + FuncDeclaration *buildOpAssign(Scope *sc); + FuncDeclaration *buildPostBlit(Scope *sc); + FuncDeclaration *buildCpCtor(Scope *sc); + void toDocBuffer(OutBuffer *buf); + + PROT getAccess(Dsymbol *smember); // determine access to smember + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + void toDt(dt_t **pdt); + void toDebug(); // to symbolic debug info +#endif + + StructDeclaration *isStructDeclaration() { return this; } + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + +struct UnionDeclaration : StructDeclaration +{ + UnionDeclaration(Loc loc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + const char *kind(); + + UnionDeclaration *isUnionDeclaration() { return this; } +}; + +// warning: two classes with the same base class share the same +// BaseClass instance. +struct BaseClass +{ + Type *type; // (before semantic processing) + enum PROT protection; // protection for the base interface + + ClassDeclaration *base; + int offset; // 'this' pointer offset + Array vtbl; // for interfaces: Array of FuncDeclaration's + // making up the vtbl[] + + int baseInterfaces_dim; + BaseClass *baseInterfaces; // if BaseClass is an interface, these + // are a copy of the InterfaceDeclaration::interfaces + + BaseClass(); + BaseClass(Type *type, enum PROT protection); + + int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance); + void copyBaseInterfaces(BaseClasses *); +}; + +#if DMDV2 +#define CLASSINFO_SIZE (0x3C+16+4) // value of ClassInfo.size +#else +#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size +#endif + +struct ClassDeclaration : AggregateDeclaration +{ + static ClassDeclaration *object; + static ClassDeclaration *classinfo; + + ClassDeclaration *baseClass; // NULL only if this is Object + FuncDeclaration *staticCtor; + FuncDeclaration *staticDtor; + Array vtbl; // Array of FuncDeclaration's making up the vtbl[] + Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] + + BaseClasses baseclasses; // Array of BaseClass's; first is super, + // rest are Interface's + + int interfaces_dim; + BaseClass **interfaces; // interfaces[interfaces_dim] for this class + // (does not include baseClass) + + BaseClasses *vtblInterfaces; // array of base interfaces that have + // their own vtbl[] + + ClassInfoDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration + int com; // !=0 if this is a COM class (meaning + // it derives from IUnknown) + int isauto; // !=0 if this is an auto class + int isabstract; // !=0 if abstract class + + int inuse; // to prevent recursive attempts + + ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isBaseOf2(ClassDeclaration *cd); + + #define OFFSET_RUNTIME 0x76543210 + virtual int isBaseOf(ClassDeclaration *cd, int *poffset); + + Dsymbol *search(Loc, Identifier *ident, int flags); +#if DMDV2 + int isFuncHidden(FuncDeclaration *fd); +#endif + FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); + void interfaceSemantic(Scope *sc); + int isCOMclass(); + virtual int isCOMinterface(); +#if DMDV2 + virtual int isCPPinterface(); +#endif + int isAbstract(); + virtual int vtblOffset(); + const char *kind(); + char *mangle(); + void toDocBuffer(OutBuffer *buf); + + PROT getAccess(Dsymbol *smember); // determine access to smember + + void addLocalClass(ClassDeclarations *); + +#if IN_DMD + // Back end + void toObjFile(int multiobj); // compile to .obj file + void toDebug(); + unsigned baseVtblOffset(BaseClass *bc); + Symbol *toSymbol(); + Symbol *toVtblSymbol(); + void toDt(dt_t **pdt); + void toDt2(dt_t **pdt, ClassDeclaration *cd); + + Symbol *vtblsym; +#endif + + ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } + +#if IN_LLVM + virtual void codegen(Ir*); +#endif +}; + +struct InterfaceDeclaration : ClassDeclaration +{ +#if DMDV2 + int cpp; // !=0 if this is a C++ interface +#endif + InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + int isBaseOf(ClassDeclaration *cd, int *poffset); + int isBaseOf(BaseClass *bc, int *poffset); + const char *kind(); + int vtblOffset(); +#if DMDV2 + int isCPPinterface(); +#endif + virtual int isCOMinterface(); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + Symbol *toSymbol(); +#endif + + InterfaceDeclaration *isInterfaceDeclaration() { return this; } + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + +#endif /* DMD_AGGREGATE_H */ diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/aliasthis.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/aliasthis.c Sat May 30 17:23:32 2009 +0100 @@ -0,0 +1,72 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 2009-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include + +#include "mars.h" +#include "identifier.h" +#include "aliasthis.h" +#include "scope.h" +#include "aggregate.h" +#include "dsymbol.h" + +#if DMDV2 + + +AliasThis::AliasThis(Loc loc, Identifier *ident) + : Dsymbol(NULL) // it's anonymous (no identifier) +{ + this->loc = loc; + this->ident = ident; +} + +Dsymbol *AliasThis::syntaxCopy(Dsymbol *s) +{ + assert(!s); + /* Since there is no semantic information stored here, + * we don't need to copy it. + */ + return this; +} + +void AliasThis::semantic(Scope *sc) +{ + Dsymbol *parent = sc->parent; + if (parent) + parent = parent->pastMixin(); + AggregateDeclaration *ad = NULL; + if (parent) + ad = parent->isAggregateDeclaration(); + if (ad) + { + if (ad->aliasthis) + error("there can be only one alias this"); + assert(ad->members); + Dsymbol *s = ad->search(loc, ident, 0); + ad->aliasthis = s; + } + else + error("alias this can only appear in struct or class declaration, not %s", parent ? parent->toChars() : "nowhere"); +} + +const char *AliasThis::kind() +{ + return "alias this"; +} + +void AliasThis::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("alias "); + buf->writestring(ident->toChars()); + buf->writestring(" this;\n"); +} + +#endif diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/aliasthis.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/aliasthis.h Sat May 30 17:23:32 2009 +0100 @@ -0,0 +1,41 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 2009-2009 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. + +#ifndef DMD_ALIASTHIS_H +#define DMD_ALIASTHIS_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "mars.h" +#include "dsymbol.h" + +/**************************************************************/ + +#if DMDV2 + +struct AliasThis : Dsymbol +{ + // alias Identifier this; + Identifier *ident; + + AliasThis(Loc loc, Identifier *ident); + + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + const char *kind(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + AliasThis *isAliasThis() { return this; } +}; + +#endif + +#endif diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/arrayop.c --- a/dmd2/arrayop.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/arrayop.c Sat May 30 17:23:32 2009 +0100 @@ -1,494 +1,505 @@ - -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#if _WIN32 || IN_GCC || IN_LLVM -#include "mem.h" -#else -#include "../root/mem.h" -#endif - -#include "stringtable.h" - -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "declaration.h" -#include "scope.h" -#include "id.h" -#include "module.h" -#include "init.h" - - -/*********************************** - * Construct the array operation expression. - */ - -Expression *BinExp::arrayOp(Scope *sc) -{ - Expressions *arguments = new Expressions(); - - /* The expression to generate an array operation for is mangled - * into a name to use as the array operation function name. - * Mangle in the operands and operators in RPN order, and type. - */ - OutBuffer buf; - buf.writestring("_array"); - buildArrayIdent(&buf, arguments); - buf.writeByte('_'); - - /* Append deco of array element type - */ -#if DMDV2 - buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco); -#else - buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); -#endif - - size_t namelen = buf.offset; - buf.writeByte(0); - char *name = (char *)buf.extractData(); - - /* Look up name in hash table - */ - StringValue *sv = sc->module->arrayfuncs.update(name, namelen); - FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue; - if (!fd) - { -// /* Some of the array op functions are written as library functions, -// * presumably to optimize them with special CPU vector instructions. -// * List those library functions here, in alpha order. -// */ -// static const char *libArrayopFuncs[] = -// { -// "_arrayExpSliceAddass_a", -// "_arrayExpSliceAddass_d", // T[]+=T -// "_arrayExpSliceAddass_f", // T[]+=T -// "_arrayExpSliceAddass_g", -// "_arrayExpSliceAddass_h", -// "_arrayExpSliceAddass_i", -// "_arrayExpSliceAddass_k", -// "_arrayExpSliceAddass_s", -// "_arrayExpSliceAddass_t", -// "_arrayExpSliceAddass_u", -// "_arrayExpSliceAddass_w", -// -// "_arrayExpSliceDivass_d", // T[]/=T -// "_arrayExpSliceDivass_f", // T[]/=T -// -// "_arrayExpSliceMinSliceAssign_a", -// "_arrayExpSliceMinSliceAssign_d", // T[]=T-T[] -// "_arrayExpSliceMinSliceAssign_f", // T[]=T-T[] -// "_arrayExpSliceMinSliceAssign_g", -// "_arrayExpSliceMinSliceAssign_h", -// "_arrayExpSliceMinSliceAssign_i", -// "_arrayExpSliceMinSliceAssign_k", -// "_arrayExpSliceMinSliceAssign_s", -// "_arrayExpSliceMinSliceAssign_t", -// "_arrayExpSliceMinSliceAssign_u", -// "_arrayExpSliceMinSliceAssign_w", -// -// "_arrayExpSliceMinass_a", -// "_arrayExpSliceMinass_d", // T[]-=T -// "_arrayExpSliceMinass_f", // T[]-=T -// "_arrayExpSliceMinass_g", -// "_arrayExpSliceMinass_h", -// "_arrayExpSliceMinass_i", -// "_arrayExpSliceMinass_k", -// "_arrayExpSliceMinass_s", -// "_arrayExpSliceMinass_t", -// "_arrayExpSliceMinass_u", -// "_arrayExpSliceMinass_w", -// -// "_arrayExpSliceMulass_d", // T[]*=T -// "_arrayExpSliceMulass_f", // T[]*=T -// "_arrayExpSliceMulass_i", -// "_arrayExpSliceMulass_k", -// "_arrayExpSliceMulass_s", -// "_arrayExpSliceMulass_t", -// "_arrayExpSliceMulass_u", -// "_arrayExpSliceMulass_w", -// -// "_arraySliceExpAddSliceAssign_a", -// "_arraySliceExpAddSliceAssign_d", // T[]=T[]+T -// "_arraySliceExpAddSliceAssign_f", // T[]=T[]+T -// "_arraySliceExpAddSliceAssign_g", -// "_arraySliceExpAddSliceAssign_h", -// "_arraySliceExpAddSliceAssign_i", -// "_arraySliceExpAddSliceAssign_k", -// "_arraySliceExpAddSliceAssign_s", -// "_arraySliceExpAddSliceAssign_t", -// "_arraySliceExpAddSliceAssign_u", -// "_arraySliceExpAddSliceAssign_w", -// -// "_arraySliceExpDivSliceAssign_d", // T[]=T[]/T -// "_arraySliceExpDivSliceAssign_f", // T[]=T[]/T -// -// "_arraySliceExpMinSliceAssign_a", -// "_arraySliceExpMinSliceAssign_d", // T[]=T[]-T -// "_arraySliceExpMinSliceAssign_f", // T[]=T[]-T -// "_arraySliceExpMinSliceAssign_g", -// "_arraySliceExpMinSliceAssign_h", -// "_arraySliceExpMinSliceAssign_i", -// "_arraySliceExpMinSliceAssign_k", -// "_arraySliceExpMinSliceAssign_s", -// "_arraySliceExpMinSliceAssign_t", -// "_arraySliceExpMinSliceAssign_u", -// "_arraySliceExpMinSliceAssign_w", -// -// "_arraySliceExpMulSliceAddass_d", // T[] += T[]*T -// "_arraySliceExpMulSliceAddass_f", -// "_arraySliceExpMulSliceAddass_r", -// -// "_arraySliceExpMulSliceAssign_d", // T[]=T[]*T -// "_arraySliceExpMulSliceAssign_f", // T[]=T[]*T -// "_arraySliceExpMulSliceAssign_i", -// "_arraySliceExpMulSliceAssign_k", -// "_arraySliceExpMulSliceAssign_s", -// "_arraySliceExpMulSliceAssign_t", -// "_arraySliceExpMulSliceAssign_u", -// "_arraySliceExpMulSliceAssign_w", -// -// "_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T -// "_arraySliceExpMulSliceMinass_f", -// "_arraySliceExpMulSliceMinass_r", -// -// "_arraySliceSliceAddSliceAssign_a", -// "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[] -// "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[] -// "_arraySliceSliceAddSliceAssign_g", -// "_arraySliceSliceAddSliceAssign_h", -// "_arraySliceSliceAddSliceAssign_i", -// "_arraySliceSliceAddSliceAssign_k", -// "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[] -// "_arraySliceSliceAddSliceAssign_s", -// "_arraySliceSliceAddSliceAssign_t", -// "_arraySliceSliceAddSliceAssign_u", -// "_arraySliceSliceAddSliceAssign_w", -// -// "_arraySliceSliceAddass_a", -// "_arraySliceSliceAddass_d", // T[]+=T[] -// "_arraySliceSliceAddass_f", // T[]+=T[] -// "_arraySliceSliceAddass_g", -// "_arraySliceSliceAddass_h", -// "_arraySliceSliceAddass_i", -// "_arraySliceSliceAddass_k", -// "_arraySliceSliceAddass_s", -// "_arraySliceSliceAddass_t", -// "_arraySliceSliceAddass_u", -// "_arraySliceSliceAddass_w", -// -// "_arraySliceSliceMinSliceAssign_a", -// "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[] -// "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[] -// "_arraySliceSliceMinSliceAssign_g", -// "_arraySliceSliceMinSliceAssign_h", -// "_arraySliceSliceMinSliceAssign_i", -// "_arraySliceSliceMinSliceAssign_k", -// "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[] -// "_arraySliceSliceMinSliceAssign_s", -// "_arraySliceSliceMinSliceAssign_t", -// "_arraySliceSliceMinSliceAssign_u", -// "_arraySliceSliceMinSliceAssign_w", -// -// "_arraySliceSliceMinass_a", -// "_arraySliceSliceMinass_d", // T[]-=T[] -// "_arraySliceSliceMinass_f", // T[]-=T[] -// "_arraySliceSliceMinass_g", -// "_arraySliceSliceMinass_h", -// "_arraySliceSliceMinass_i", -// "_arraySliceSliceMinass_k", -// "_arraySliceSliceMinass_s", -// "_arraySliceSliceMinass_t", -// "_arraySliceSliceMinass_u", -// "_arraySliceSliceMinass_w", -// -// "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[] -// "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[] -// "_arraySliceSliceMulSliceAssign_i", -// "_arraySliceSliceMulSliceAssign_k", -// "_arraySliceSliceMulSliceAssign_s", -// "_arraySliceSliceMulSliceAssign_t", -// "_arraySliceSliceMulSliceAssign_u", -// "_arraySliceSliceMulSliceAssign_w", -// -// "_arraySliceSliceMulass_d", // T[]*=T[] -// "_arraySliceSliceMulass_f", // T[]*=T[] -// "_arraySliceSliceMulass_i", -// "_arraySliceSliceMulass_k", -// "_arraySliceSliceMulass_s", -// "_arraySliceSliceMulass_t", -// "_arraySliceSliceMulass_u", -// "_arraySliceSliceMulass_w", -// }; -// -// int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *)); -// if (i == -1) -// { -// #ifdef DEBUG // Make sure our array is alphabetized -// for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++) -// { -// if (strcmp(name, libArrayopFuncs[i]) == 0) -// assert(0); -// } -// #endif - - /* Not in library, so generate it. - * Construct the function body: - * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) - * loopbody; - * return p; - */ - - Arguments *fparams = new Arguments(); - Expression *loopbody = buildArrayLoop(fparams); - Argument *p = (Argument *)fparams->data[0 /*fparams->dim - 1*/]; -#if DMDV1 - // for (size_t i = 0; i < p.length; i++) - Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t)); - Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init); - Statement *s1 = new ForStatement(0, - new DeclarationStatement(0, d), - new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))), - new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)), - new ExpStatement(0, loopbody)); -#else - // foreach (i; 0 .. p.length) - Statement *s1 = new ForeachRangeStatement(0, TOKforeach, - new Argument(0, NULL, Id::p, NULL), - new IntegerExp(0, 0, Type::tint32), - new ArrayLengthExp(0, new IdentifierExp(0, p->ident)), - new ExpStatement(0, loopbody)); -#endif - Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident)); - //printf("s2: %s\n", s2->toChars()); - Statement *fbody = new CompoundStatement(0, s1, s2); - - /* Construct the function - */ - TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc); - //printf("ftype: %s\n", ftype->toChars()); - fd = new FuncDeclaration(0, 0, Lexer::idPool(name), STCundefined, ftype); - fd->fbody = fbody; - fd->protection = PROTprotected; - fd->linkage = LINKd; - - // special attention for array ops - fd->isArrayOp = true; - - sc->module->members->push(fd); - - sc = sc->push(); - sc->parent = sc->module; - sc->stc = 0; - sc->linkage = LINKd; - fd->semantic(sc); - sc->pop(); -// } -// else -// { /* In library, refer to it. -// */ -// // FIXME -// fd = FuncDeclaration::genCfunc(NULL, type, name); -// } - sv->ptrvalue = fd; // cache symbol in hash table - } - - /* Call the function fd(arguments) - */ - Expression *ec = new VarExp(0, fd); - Expression *e = new CallExp(loc, ec, arguments); - e->type = type; - return e; -} - -/****************************************** - * Construct the identifier for the array operation function, - * and build the argument list to pass to it. - */ - -void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - buf->writestring("Exp"); - arguments->shift(this); -} - -void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - buf->writestring("Slice"); - arguments->shift(this); -} - -void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - /* Evaluate assign expressions right to left - */ - e2->buildArrayIdent(buf, arguments); - e1->buildArrayIdent(buf, arguments); - buf->writestring("Assign"); -} - -#define X(Str) \ -void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - e2->buildArrayIdent(buf, arguments); \ - e1->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ - buf->writestring("ass"); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) - -#undef X - -void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - e1->buildArrayIdent(buf, arguments); - buf->writestring("Neg"); -} - -void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - e1->buildArrayIdent(buf, arguments); - buf->writestring("Com"); -} - -#define X(Str) \ -void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - e1->buildArrayIdent(buf, arguments); \ - e2->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) - -#undef X - -/****************************************** - * Construct the inner loop for the array operation function, - * and build the parameter list. - */ - -Expression *Expression::buildArrayLoop(Arguments *fparams) -{ - Identifier *id = Identifier::generateId("c", fparams->dim); - Argument *param = new Argument(0, type, id, NULL); - fparams->shift(param); - Expression *e = new IdentifierExp(0, id); - return e; -} - -Expression *SliceExp::buildArrayLoop(Arguments *fparams) -{ - Identifier *id = Identifier::generateId("p", fparams->dim); - Argument *param = new Argument(STCconst, type, id, NULL); - fparams->shift(param); - Expression *e = new IdentifierExp(0, id); - Expressions *arguments = new Expressions(); - Expression *index = new IdentifierExp(0, Id::p); - arguments->push(index); - e = new ArrayExp(0, e, arguments); - return e; -} - -Expression *AssignExp::buildArrayLoop(Arguments *fparams) -{ - /* Evaluate assign expressions right to left - */ - Expression *ex2 = e2->buildArrayLoop(fparams); - Expression *ex1 = e1->buildArrayLoop(fparams); - Argument *param = (Argument *)fparams->data[0]; - param->storageClass = 0; - Expression *e = new AssignExp(0, ex1, ex2); - return e; -} - -#define X(Str) \ -Expression *Str##AssignExp::buildArrayLoop(Arguments *fparams) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Argument *param = (Argument *)fparams->data[0]; \ - param->storageClass = 0; \ - Expression *e = new Str##AssignExp(0, ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) - -#undef X - -Expression *NegExp::buildArrayLoop(Arguments *fparams) -{ - Expression *ex1 = e1->buildArrayLoop(fparams); - Expression *e = new NegExp(0, ex1); - return e; -} - -Expression *ComExp::buildArrayLoop(Arguments *fparams) -{ - Expression *ex1 = e1->buildArrayLoop(fparams); - Expression *e = new ComExp(0, ex1); - return e; -} - -#define X(Str) \ -Expression *Str##Exp::buildArrayLoop(Arguments *fparams) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *e = new Str##Exp(0, ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) - -#undef X - - + +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include + +#include "rmem.h" + +#include "stringtable.h" + +#include "expression.h" +#include "statement.h" +#include "mtype.h" +#include "declaration.h" +#include "scope.h" +#include "id.h" +#include "module.h" +#include "init.h" + +#if IN_DMD +extern int binary(const char *p , const char **tab, int high); + +/************************************** + * Hash table of array op functions already generated or known about. + */ + +StringTable arrayfuncs; +#endif + +/*********************************** + * Construct the array operation expression. + */ + +Expression *BinExp::arrayOp(Scope *sc) +{ + Expressions *arguments = new Expressions(); + + /* The expression to generate an array operation for is mangled + * into a name to use as the array operation function name. + * Mangle in the operands and operators in RPN order, and type. + */ + OutBuffer buf; + buf.writestring("_array"); + buildArrayIdent(&buf, arguments); + buf.writeByte('_'); + + /* Append deco of array element type + */ +#if DMDV2 + buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco); +#else + buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); +#endif + + size_t namelen = buf.offset; + buf.writeByte(0); + char *name = (char *)buf.extractData(); + + /* Look up name in hash table + */ +#if IN_LLVM + StringValue *sv = sc->module->arrayfuncs.update(name, namelen); +#else + StringValue *sv = arrayfuncs.update(name, namelen); +#endif + FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue; + if (!fd) + { +#if IN_DMD + /* Some of the array op functions are written as library functions, + * presumably to optimize them with special CPU vector instructions. + * List those library functions here, in alpha order. + */ + static const char *libArrayopFuncs[] = + { + "_arrayExpSliceAddass_a", + "_arrayExpSliceAddass_d", // T[]+=T + "_arrayExpSliceAddass_f", // T[]+=T + "_arrayExpSliceAddass_g", + "_arrayExpSliceAddass_h", + "_arrayExpSliceAddass_i", + "_arrayExpSliceAddass_k", + "_arrayExpSliceAddass_s", + "_arrayExpSliceAddass_t", + "_arrayExpSliceAddass_u", + "_arrayExpSliceAddass_w", + + "_arrayExpSliceDivass_d", // T[]/=T + "_arrayExpSliceDivass_f", // T[]/=T + + "_arrayExpSliceMinSliceAssign_a", + "_arrayExpSliceMinSliceAssign_d", // T[]=T-T[] + "_arrayExpSliceMinSliceAssign_f", // T[]=T-T[] + "_arrayExpSliceMinSliceAssign_g", + "_arrayExpSliceMinSliceAssign_h", + "_arrayExpSliceMinSliceAssign_i", + "_arrayExpSliceMinSliceAssign_k", + "_arrayExpSliceMinSliceAssign_s", + "_arrayExpSliceMinSliceAssign_t", + "_arrayExpSliceMinSliceAssign_u", + "_arrayExpSliceMinSliceAssign_w", + + "_arrayExpSliceMinass_a", + "_arrayExpSliceMinass_d", // T[]-=T + "_arrayExpSliceMinass_f", // T[]-=T + "_arrayExpSliceMinass_g", + "_arrayExpSliceMinass_h", + "_arrayExpSliceMinass_i", + "_arrayExpSliceMinass_k", + "_arrayExpSliceMinass_s", + "_arrayExpSliceMinass_t", + "_arrayExpSliceMinass_u", + "_arrayExpSliceMinass_w", + + "_arrayExpSliceMulass_d", // T[]*=T + "_arrayExpSliceMulass_f", // T[]*=T + "_arrayExpSliceMulass_i", + "_arrayExpSliceMulass_k", + "_arrayExpSliceMulass_s", + "_arrayExpSliceMulass_t", + "_arrayExpSliceMulass_u", + "_arrayExpSliceMulass_w", + + "_arraySliceExpAddSliceAssign_a", + "_arraySliceExpAddSliceAssign_d", // T[]=T[]+T + "_arraySliceExpAddSliceAssign_f", // T[]=T[]+T + "_arraySliceExpAddSliceAssign_g", + "_arraySliceExpAddSliceAssign_h", + "_arraySliceExpAddSliceAssign_i", + "_arraySliceExpAddSliceAssign_k", + "_arraySliceExpAddSliceAssign_s", + "_arraySliceExpAddSliceAssign_t", + "_arraySliceExpAddSliceAssign_u", + "_arraySliceExpAddSliceAssign_w", + + "_arraySliceExpDivSliceAssign_d", // T[]=T[]/T + "_arraySliceExpDivSliceAssign_f", // T[]=T[]/T + + "_arraySliceExpMinSliceAssign_a", + "_arraySliceExpMinSliceAssign_d", // T[]=T[]-T + "_arraySliceExpMinSliceAssign_f", // T[]=T[]-T + "_arraySliceExpMinSliceAssign_g", + "_arraySliceExpMinSliceAssign_h", + "_arraySliceExpMinSliceAssign_i", + "_arraySliceExpMinSliceAssign_k", + "_arraySliceExpMinSliceAssign_s", + "_arraySliceExpMinSliceAssign_t", + "_arraySliceExpMinSliceAssign_u", + "_arraySliceExpMinSliceAssign_w", + + "_arraySliceExpMulSliceAddass_d", // T[] += T[]*T + "_arraySliceExpMulSliceAddass_f", + "_arraySliceExpMulSliceAddass_r", + + "_arraySliceExpMulSliceAssign_d", // T[]=T[]*T + "_arraySliceExpMulSliceAssign_f", // T[]=T[]*T + "_arraySliceExpMulSliceAssign_i", + "_arraySliceExpMulSliceAssign_k", + "_arraySliceExpMulSliceAssign_s", + "_arraySliceExpMulSliceAssign_t", + "_arraySliceExpMulSliceAssign_u", + "_arraySliceExpMulSliceAssign_w", + + "_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T + "_arraySliceExpMulSliceMinass_f", + "_arraySliceExpMulSliceMinass_r", + + "_arraySliceSliceAddSliceAssign_a", + "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[] + "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[] + "_arraySliceSliceAddSliceAssign_g", + "_arraySliceSliceAddSliceAssign_h", + "_arraySliceSliceAddSliceAssign_i", + "_arraySliceSliceAddSliceAssign_k", + "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[] + "_arraySliceSliceAddSliceAssign_s", + "_arraySliceSliceAddSliceAssign_t", + "_arraySliceSliceAddSliceAssign_u", + "_arraySliceSliceAddSliceAssign_w", + + "_arraySliceSliceAddass_a", + "_arraySliceSliceAddass_d", // T[]+=T[] + "_arraySliceSliceAddass_f", // T[]+=T[] + "_arraySliceSliceAddass_g", + "_arraySliceSliceAddass_h", + "_arraySliceSliceAddass_i", + "_arraySliceSliceAddass_k", + "_arraySliceSliceAddass_s", + "_arraySliceSliceAddass_t", + "_arraySliceSliceAddass_u", + "_arraySliceSliceAddass_w", + + "_arraySliceSliceMinSliceAssign_a", + "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[] + "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[] + "_arraySliceSliceMinSliceAssign_g", + "_arraySliceSliceMinSliceAssign_h", + "_arraySliceSliceMinSliceAssign_i", + "_arraySliceSliceMinSliceAssign_k", + "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[] + "_arraySliceSliceMinSliceAssign_s", + "_arraySliceSliceMinSliceAssign_t", + "_arraySliceSliceMinSliceAssign_u", + "_arraySliceSliceMinSliceAssign_w", + + "_arraySliceSliceMinass_a", + "_arraySliceSliceMinass_d", // T[]-=T[] + "_arraySliceSliceMinass_f", // T[]-=T[] + "_arraySliceSliceMinass_g", + "_arraySliceSliceMinass_h", + "_arraySliceSliceMinass_i", + "_arraySliceSliceMinass_k", + "_arraySliceSliceMinass_s", + "_arraySliceSliceMinass_t", + "_arraySliceSliceMinass_u", + "_arraySliceSliceMinass_w", + + "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[] + "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[] + "_arraySliceSliceMulSliceAssign_i", + "_arraySliceSliceMulSliceAssign_k", + "_arraySliceSliceMulSliceAssign_s", + "_arraySliceSliceMulSliceAssign_t", + "_arraySliceSliceMulSliceAssign_u", + "_arraySliceSliceMulSliceAssign_w", + + "_arraySliceSliceMulass_d", // T[]*=T[] + "_arraySliceSliceMulass_f", // T[]*=T[] + "_arraySliceSliceMulass_i", + "_arraySliceSliceMulass_k", + "_arraySliceSliceMulass_s", + "_arraySliceSliceMulass_t", + "_arraySliceSliceMulass_u", + "_arraySliceSliceMulass_w", + }; + + int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *)); + if (i == -1) + { +#ifdef DEBUG // Make sure our array is alphabetized + for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++) + { + if (strcmp(name, libArrayopFuncs[i]) == 0) + assert(0); + } +#endif +#endif + /* Not in library, so generate it. + * Construct the function body: + * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) + * loopbody; + * return p; + */ + + Arguments *fparams = new Arguments(); + Expression *loopbody = buildArrayLoop(fparams); + Argument *p = (Argument *)fparams->data[0 /*fparams->dim - 1*/]; +#if DMDV1 + // for (size_t i = 0; i < p.length; i++) + Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t)); + Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init); + Statement *s1 = new ForStatement(0, + new DeclarationStatement(0, d), + new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))), + new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)), + new ExpStatement(0, loopbody)); +#else + // foreach (i; 0 .. p.length) + Statement *s1 = new ForeachRangeStatement(0, TOKforeach, + new Argument(0, NULL, Id::p, NULL), + new IntegerExp(0, 0, Type::tint32), + new ArrayLengthExp(0, new IdentifierExp(0, p->ident)), + new ExpStatement(0, loopbody)); +#endif + Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident)); + //printf("s2: %s\n", s2->toChars()); + Statement *fbody = new CompoundStatement(0, s1, s2); + + /* Construct the function + */ + TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc); + //printf("ftype: %s\n", ftype->toChars()); + fd = new FuncDeclaration(0, 0, Lexer::idPool(name), STCundefined, ftype); + fd->fbody = fbody; + fd->protection = PROTpublic; + fd->linkage = LINKd; + + // special attention for array ops + fd->isArrayOp = true; + + sc->module->importedFrom->members->push(fd); + + sc = sc->push(); + sc->parent = sc->module->importedFrom; + sc->stc = 0; + sc->linkage = LINKc; + fd->semantic(sc); + sc->pop(); +#if IN_DMD + } + else + { /* In library, refer to it. + */ + fd = FuncDeclaration::genCfunc(type, name); + } +#endif + sv->ptrvalue = fd; // cache symbol in hash table + } + + /* Call the function fd(arguments) + */ + Expression *ec = new VarExp(0, fd); + Expression *e = new CallExp(loc, ec, arguments); + e->type = type; + return e; +} + +/****************************************** + * Construct the identifier for the array operation function, + * and build the argument list to pass to it. + */ + +void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + buf->writestring("Exp"); + arguments->shift(this); +} + +void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + buf->writestring("Slice"); + arguments->shift(this); +} + +void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + /* Evaluate assign expressions right to left + */ + e2->buildArrayIdent(buf, arguments); + e1->buildArrayIdent(buf, arguments); + buf->writestring("Assign"); +} + +#define X(Str) \ +void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ +{ \ + /* Evaluate assign expressions right to left \ + */ \ + e2->buildArrayIdent(buf, arguments); \ + e1->buildArrayIdent(buf, arguments); \ + buf->writestring(#Str); \ + buf->writestring("ass"); \ +} + +X(Add) +X(Min) +X(Mul) +X(Div) +X(Mod) +X(Xor) +X(And) +X(Or) + +#undef X + +void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + e1->buildArrayIdent(buf, arguments); + buf->writestring("Neg"); +} + +void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + e1->buildArrayIdent(buf, arguments); + buf->writestring("Com"); +} + +#define X(Str) \ +void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ +{ \ + /* Evaluate assign expressions left to right \ + */ \ + e1->buildArrayIdent(buf, arguments); \ + e2->buildArrayIdent(buf, arguments); \ + buf->writestring(#Str); \ +} + +X(Add) +X(Min) +X(Mul) +X(Div) +X(Mod) +X(Xor) +X(And) +X(Or) + +#undef X + +/****************************************** + * Construct the inner loop for the array operation function, + * and build the parameter list. + */ + +Expression *Expression::buildArrayLoop(Arguments *fparams) +{ + Identifier *id = Identifier::generateId("c", fparams->dim); + Argument *param = new Argument(0, type, id, NULL); + fparams->shift(param); + Expression *e = new IdentifierExp(0, id); + return e; +} + +Expression *SliceExp::buildArrayLoop(Arguments *fparams) +{ + Identifier *id = Identifier::generateId("p", fparams->dim); + Argument *param = new Argument(STCconst, type, id, NULL); + fparams->shift(param); + Expression *e = new IdentifierExp(0, id); + Expressions *arguments = new Expressions(); + Expression *index = new IdentifierExp(0, Id::p); + arguments->push(index); + e = new ArrayExp(0, e, arguments); + return e; +} + +Expression *AssignExp::buildArrayLoop(Arguments *fparams) +{ + /* Evaluate assign expressions right to left + */ + Expression *ex2 = e2->buildArrayLoop(fparams); + Expression *ex1 = e1->buildArrayLoop(fparams); + Argument *param = (Argument *)fparams->data[0]; + param->storageClass = 0; + Expression *e = new AssignExp(0, ex1, ex2); + return e; +} + +#define X(Str) \ +Expression *Str##AssignExp::buildArrayLoop(Arguments *fparams) \ +{ \ + /* Evaluate assign expressions right to left \ + */ \ + Expression *ex2 = e2->buildArrayLoop(fparams); \ + Expression *ex1 = e1->buildArrayLoop(fparams); \ + Argument *param = (Argument *)fparams->data[0]; \ + param->storageClass = 0; \ + Expression *e = new Str##AssignExp(0, ex1, ex2); \ + return e; \ +} + +X(Add) +X(Min) +X(Mul) +X(Div) +X(Mod) +X(Xor) +X(And) +X(Or) + +#undef X + +Expression *NegExp::buildArrayLoop(Arguments *fparams) +{ + Expression *ex1 = e1->buildArrayLoop(fparams); + Expression *e = new NegExp(0, ex1); + return e; +} + +Expression *ComExp::buildArrayLoop(Arguments *fparams) +{ + Expression *ex1 = e1->buildArrayLoop(fparams); + Expression *e = new ComExp(0, ex1); + return e; +} + +#define X(Str) \ +Expression *Str##Exp::buildArrayLoop(Arguments *fparams) \ +{ \ + /* Evaluate assign expressions left to right \ + */ \ + Expression *ex1 = e1->buildArrayLoop(fparams); \ + Expression *ex2 = e2->buildArrayLoop(fparams); \ + Expression *e = new Str##Exp(0, ex1, ex2); \ + return e; \ +} + +X(Add) +X(Min) +X(Mul) +X(Div) +X(Mod) +X(Xor) +X(And) +X(Or) + +#undef X + + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/attrib.c --- a/dmd2/attrib.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/attrib.c Sat May 30 17:23:32 2009 +0100 @@ -1,1483 +1,1553 @@ - -// 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. - -#include -#include -#include - -#if _WIN32 || IN_GCC || IN_LLVM -#include "mem.h" -#elif POSIX -#include "../root/mem.h" -#endif - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "cond.h" -#include "scope.h" -#include "id.h" -#include "expression.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "module.h" -#include "parse.h" -#include "template.h" - -#include "../gen/enums.h" - - -#include "llvm/Support/CommandLine.h" - -static llvm::cl::opt ignoreUnsupportedPragmas("ignore", - llvm::cl::desc("Ignore unsupported pragmas"), - llvm::cl::ZeroOrMore); - - - -extern void obj_includelib(const char *name); -void obj_startaddress(Symbol *s); - - -/********************************* AttribDeclaration ****************************/ - -AttribDeclaration::AttribDeclaration(Array *decl) - : Dsymbol() -{ - this->decl = decl; -} - -Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - return decl; -} - -int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - int m = 0; - Array *d = include(sc, sd); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - m |= s->addMember(sc, sd, m | memnum); - } - } - return m; -} - -void AttribDeclaration::semantic(Scope *sc) -{ - Array *d = include(sc, NULL); - - //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - - s->semantic(sc); - } - } -} - -void AttribDeclaration::semantic2(Scope *sc) -{ - Array *d = include(sc, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->semantic2(sc); - } - } -} - -void AttribDeclaration::semantic3(Scope *sc) -{ - Array *d = include(sc, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->semantic3(sc); - } - } -} - -void AttribDeclaration::inlineScan() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); - s->inlineScan(); - } - } -} - -void AttribDeclaration::addComment(unsigned char *comment) -{ - if (comment) - { - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - } -} - -void AttribDeclaration::emitComment(Scope *sc) -{ - //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); - - /* If generating doc comment, skip this because if we're inside - * a template, then include(NULL, NULL) will fail. - */ -// if (sc->docbuf) -// return; - - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::emitComment %s\n", s->toChars()); - s->emitComment(sc); - } - } -} - -void AttribDeclaration::toObjFile(int multiobj) -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->toObjFile(multiobj); - } - } -} - -int AttribDeclaration::cvMember(unsigned char *p) -{ - int nwritten = 0; - int n; - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - n = s->cvMember(p); - if (p) - p += n; - nwritten += n; - } - } - return nwritten; -} - -int AttribDeclaration::hasPointers() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - if (s->hasPointers()) - return 1; - } - } - return 0; -} - -const char *AttribDeclaration::kind() -{ - return "attribute"; -} - -int AttribDeclaration::oneMember(Dsymbol **ps) -{ - Array *d = include(NULL, NULL); - - return Dsymbol::oneMembers(d, ps); -} - -void AttribDeclaration::checkCtorConstInit() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->checkCtorConstInit(); - } - } -} - -/**************************************** - */ - -void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->addLocalClass(aclasses); - } - } -} - - -void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (decl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - else - buf->writeByte(';'); - buf->writenl(); -} - -/************************* StorageClassDeclaration ****************************/ - -StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl) - : AttribDeclaration(decl) -{ - this->stc = stc; -} - -Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) -{ - StorageClassDeclaration *scd; - - assert(!s); - scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); - return scd; -} - -void StorageClassDeclaration::semantic(Scope *sc) -{ - if (decl) - { unsigned stc_save = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest)) - sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest); - if (stc & (STCconst | STCinvariant | STCmanifest)) - sc->stc &= ~(STCconst | STCinvariant | STCmanifest); - sc->stc |= stc; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->stc = stc_save; - } - else - sc->stc = stc; -} - -void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - struct SCstring - { - int stc; - enum TOK tok; - }; - - static SCstring table[] = - { - { STCauto, TOKauto }, - { STCscope, TOKscope }, - { STCstatic, TOKstatic }, - { STCextern, TOKextern }, - { STCconst, TOKconst }, - { STCinvariant, TOKimmutable }, - { STCshared, TOKshared }, - { STCfinal, TOKfinal }, - { STCabstract, TOKabstract }, - { STCsynchronized, TOKsynchronized }, - { STCdeprecated, TOKdeprecated }, - { STCoverride, TOKoverride }, - { STCnothrow, TOKnothrow }, - { STCpure, TOKpure }, - { STCref, TOKref }, - { STCtls, TOKtls }, - }; - - int written = 0; - for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) - { - if (stc & table[i].stc) - { - if (written) - buf->writeByte(' '); - written = 1; - buf->writestring(Token::toChars(table[i].tok)); - } - } - - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* LinkDeclaration ****************************/ - -LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl) - : AttribDeclaration(decl) -{ - //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); - linkage = p; -} - -Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) -{ - LinkDeclaration *ld; - - assert(!s); - ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); - return ld; -} - -void LinkDeclaration::semantic(Scope *sc) -{ - //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->linkage = linkage_save; - } - else - { - sc->linkage = linkage; - } -} - -void LinkDeclaration::semantic3(Scope *sc) -{ - //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic3(sc); - } - sc->linkage = linkage_save; - } - else - { - sc->linkage = linkage; - } -} - -void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ const char *p; - - switch (linkage) - { - case LINKd: p = "D"; break; - case LINKc: p = "C"; break; - case LINKcpp: p = "C++"; break; - case LINKwindows: p = "Windows"; break; - case LINKpascal: p = "Pascal"; break; - - // LDC - case LINKintrinsic: p = "Intrinsic"; break; - - default: - assert(0); - break; - } - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - AttribDeclaration::toCBuffer(buf, hgs); -} - -char *LinkDeclaration::toChars() -{ - return (char *)"extern ()"; -} - -/********************************* ProtDeclaration ****************************/ - -ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl) - : AttribDeclaration(decl) -{ - protection = p; - //printf("decl = %p\n", decl); -} - -Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) -{ - ProtDeclaration *pd; - - assert(!s); - pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void ProtDeclaration::semantic(Scope *sc) -{ - if (decl) - { enum PROT protection_save = sc->protection; - int explicitProtection_save = sc->explicitProtection; - - sc->protection = protection; - sc->explicitProtection = 1; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->protection = protection_save; - sc->explicitProtection = explicitProtection_save; - } - else - { sc->protection = protection; - sc->explicitProtection = 1; - } -} - -void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ const char *p; - - switch (protection) - { - case PROTprivate: p = "private"; break; - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTpublic: p = "public"; break; - case PROTexport: p = "export"; break; - default: - assert(0); - break; - } - buf->writestring(p); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AlignDeclaration ****************************/ - -AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - salign = sa; -} - -Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) -{ - AlignDeclaration *ad; - - assert(!s); - ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AlignDeclaration::semantic(Scope *sc) -{ -// LDC -// we only support packed structs, as from the spec: align(1) struct Packed { ... } -// other alignments are simply ignored. my tests show this is what llvm-gcc does too ... - - //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); - if (decl) - { unsigned salign_save = sc->structalign; - - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - if (s->isStructDeclaration() && salign == 1) - { - sc->structalign = salign; - s->semantic(sc); - sc->structalign = salign_save; - } - else - { - s->semantic(sc); - } - } - sc->structalign = salign_save; - } - else - assert(0 && "what kind of align use triggers this?"); -} - - -void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("align (%d)", salign); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AnonDeclaration ****************************/ - -AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->isunion = isunion; - this->scope = NULL; - this->sem = 0; -} - -Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) -{ - AnonDeclaration *ad; - - assert(!s); - ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AnonDeclaration::semantic(Scope *sc) -{ - //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; - scope = NULL; - } - - assert(sc->parent); - - Dsymbol *parent = sc->parent->pastMixin(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - - if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) - { - error("can only be a part of an aggregate"); - return; - } - - if (decl) - { - AnonymousAggregateDeclaration aad; - int adisunion; - - if (sc->anonAgg) - { ad = sc->anonAgg; - adisunion = sc->inunion; - } - else - adisunion = ad->isUnionDeclaration() != NULL; - -// printf("\tsc->anonAgg = %p\n", sc->anonAgg); -// printf("\tad = %p\n", ad); -// printf("\taad = %p\n", &aad); - - sc = sc->push(); - sc->anonAgg = &aad; - sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls); - sc->inunion = isunion; - sc->offset = 0; - sc->flags = 0; - aad.structalign = sc->structalign; - aad.parent = ad; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - if (isunion) - sc->offset = 0; - if (aad.sizeok == 2) - { - break; - } - } - sc = sc->pop(); - - // If failed due to forward references, unwind and try again later - if (aad.sizeok == 2) - { - ad->sizeok = 2; - //printf("\tsetting ad->sizeok %p to 2\n", ad); - if (!sc->anonAgg) - { - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - //printf("\tforward reference %p\n", this); - return; - } - if (sem == 0) - { Module::dprogress++; - sem = 1; - //printf("\tcompleted %p\n", this); - } - else - ;//printf("\talready completed %p\n", this); - - // 0 sized structs are set to 1 byte - if (aad.structsize == 0) - { - aad.structsize = 1; - aad.alignsize = 1; - } - - // Align size of anonymous aggregate -//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); - ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); - //ad->structsize = sc->offset; -//printf("sc->offset = %d\n", sc->offset); - - // Add members of aad to ad - //printf("\tadding members of aad (%p) to '%s'\n", &aad, ad->toChars()); - for (unsigned i = 0; i < aad.fields.dim; i++) - { - VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; - - // LDC - v->offset2 = sc->offset; - - v->offset += sc->offset; - - // LDC - if (!v->anonDecl) - v->anonDecl = this; - - ad->fields.push(v); - } - - // Add size of aad to ad - if (adisunion) - { - if (aad.structsize > ad->structsize) - ad->structsize = aad.structsize; - sc->offset = 0; - } - else - { - ad->structsize = sc->offset + aad.structsize; - sc->offset = ad->structsize; - } - - if (ad->alignsize < aad.alignsize) - ad->alignsize = aad.alignsize; - } -} - - -void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf(isunion ? "union" : "struct"); - buf->writestring("\n{\n"); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - //buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writestring("}\n"); -} - -const char *AnonDeclaration::kind() -{ - return (isunion ? "anonymous union" : "anonymous struct"); -} - -/********************************* PragmaDeclaration ****************************/ - -static bool parseStringExp(Expression* e, std::string& res) -{ - StringExp *s = NULL; - - e = e->optimize(WANTvalue); - if (e->op == TOKstring && (s = (StringExp *)e)) - { - char* str = (char*)s->string; - res = str; - return true; - } - return false; -} - -PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->ident = ident; - this->args = args; -} - -Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) -{ - PragmaDeclaration *pd; - - assert(!s); - pd = new PragmaDeclaration(loc, ident, - Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void PragmaDeclaration::semantic(Scope *sc) -{ // Should be merged with PragmaStatement - -#if IN_LLVM - int llvm_internal = 0; - std::string arg1str; - -#endif - - //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKstring) - { - StringExp *se = (StringExp *)e; - fprintf(stdmsg, "%.*s", (int)se->len, se->string); - } - else - error("string expected for message, not '%s'", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - goto Lnodecl; - } - else if (ident == Id::lib) - { - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (Expression *)args->data[0]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } - goto Lnodecl; - } -#if IN_GCC - else if (ident == Id::GNU_asm) - { - if (! args || args->dim != 2) - error("identifier and string expected for asm name"); - else - { - Expression *e; - Declaration *d = NULL; - StringExp *s = NULL; - - e = (Expression *)args->data[0]; - e = e->semantic(sc); - if (e->op == TOKvar) - { - d = ((VarExp *)e)->var; - if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) - d = NULL; - } - if (!d) - error("first argument of GNU_asm must be a function or variable declaration"); - - e = (Expression *)args->data[1]; - e = e->semantic(sc); - e = e->optimize(WANTvalue); - if (e->op == TOKstring && ((StringExp *)e)->sz == 1) - s = ((StringExp *)e); - else - error("second argument of GNU_asm must be a char string"); - - if (d && s) - d->c_ident = Lexer::idPool((char*) s->string); - } - goto Lnodecl; - } -#endif - else if (ident == Id::startaddress) - { - if (!args || args->dim != 1) - error("function name expected for start address"); - else - { - Expression *e = (Expression *)args->data[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - Dsymbol *sa = getDsymbol(e); - if (!sa || !sa->isFuncDeclaration()) - error("function name expected for start address, not '%s'", e->toChars()); - } - goto Lnodecl; - } - - ///////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////// - // LDC -#if IN_LLVM - - // pragma(intrinsic, "string") { funcdecl(s) } - else if (ident == Id::intrinsic) - { - Expression* expr = (Expression *)args->data[0]; - expr = expr->semantic(sc); - if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) - { - error("requires exactly 1 string literal parameter"); - fatal(); - } - llvm_internal = LLVMintrinsic; - } - - // pragma(notypeinfo) { typedecl(s) } - else if (ident == Id::no_typeinfo) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMno_typeinfo; - } - - // pragma(nomoduleinfo) ; - else if (ident == Id::no_moduleinfo) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMno_moduleinfo; - } - - // pragma(alloca) { funcdecl(s) } - else if (ident == Id::Alloca) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMalloca; - } - - // pragma(va_start) { templdecl(s) } - else if (ident == Id::vastart) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_start; - } - - // pragma(va_copy) { funcdecl(s) } - else if (ident == Id::vacopy) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_copy; - } - - // pragma(va_end) { funcdecl(s) } - else if (ident == Id::vaend) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_end; - } - - // pragma(va_arg) { templdecl(s) } - else if (ident == Id::vaarg) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_arg; - } - - // pragma(ldc, "string") { templdecl(s) } - else if (ident == Id::ldc) - { - Expression* expr = (Expression *)args->data[0]; - expr = expr->semantic(sc); - if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) - { - error("requires exactly 1 string literal parameter"); - fatal(); - } - else if (arg1str == "verbose") - { - sc->module->llvmForceLogging = true; - } - else - { - error("command '%s' invalid"); - fatal(); - } - } - -#endif - // LDC - ///////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////// - - else if (ignoreUnsupportedPragmas) - { - if (global.params.verbose) - { - /* Print unrecognized pragmas - */ - printf("pragma %s", ident->toChars()); - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (i == 0) - printf(" ("); - else - printf(","); - printf("%s", e->toChars()); - } - if (args->dim) - printf(")"); - } - printf("\n"); - } - goto Lnodecl; - } - else - error("unrecognized pragma(%s)", ident->toChars()); - - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - -// LDC -#if IN_LLVM - - if (llvm_internal) - { - if (s->llvmInternal) - { - error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars()); - fatal(); - } - switch(llvm_internal) - { - case LLVMintrinsic: - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - fd->llvmInternal = llvm_internal; - fd->intrinsicName = arg1str; - fd->linkage = LINKintrinsic; - ((TypeFunction*)fd->type)->linkage = LINKintrinsic; - } - else if (TemplateDeclaration* td = s->isTemplateDeclaration()) - { - td->llvmInternal = llvm_internal; - td->intrinsicName = arg1str; - } - else - { - error("only allowed on function declarations"); - fatal(); - } - break; - - case LLVMva_start: - case LLVMva_arg: - if (TemplateDeclaration* td = s->isTemplateDeclaration()) - { - if (td->parameters->dim != 1) - { - error("the '%s' pragma template must have exactly one template parameter", ident->toChars()); - fatal(); - } - else if (!td->onemember) - { - error("the '%s' pragma template must have exactly one member", ident->toChars()); - fatal(); - } - else if (td->overnext || td->overroot) - { - error("the '%s' pragma template must not be overloaded", ident->toChars()); - fatal(); - } - td->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma is only allowed on template declarations", ident->toChars()); - fatal(); - } - break; - - case LLVMva_copy: - case LLVMva_end: - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - fd->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma is only allowed on function declarations", ident->toChars()); - fatal(); - } - break; - - case LLVMno_typeinfo: - s->llvmInternal = llvm_internal; - break; - - case LLVMalloca: - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - fd->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars()); - fatal(); - } - break; - - default: - warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); - } - } - -#endif // LDC - - } - } - return; - -Lnodecl: - if (decl) - error("pragma is missing closing ';'"); -} - -int PragmaDeclaration::oneMember(Dsymbol **ps) -{ - *ps = NULL; - return TRUE; -} - -const char *PragmaDeclaration::kind() -{ - return "pragma"; -} - -void PragmaDeclaration::toObjFile(int multiobj) -{ - if (ident == Id::lib) - { - assert(args && args->dim == 1); - - Expression *e = (Expression *)args->data[0]; - - assert(e->op == TOKstring); - - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - obj_includelib(name); - } - else if (ident == Id::startaddress) - { - assert(args && args->dim == 1); - Expression *e = (Expression *)args->data[0]; - Dsymbol *sa = getDsymbol(e); - FuncDeclaration *f = sa->isFuncDeclaration(); - assert(f); - Symbol *s = f->toSymbol(); - assert(0 && "startaddress pragma not implemented"); -// obj_startaddress(s); - } - AttribDeclaration::toObjFile(multiobj); -} - -void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("pragma (%s", ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - AttribDeclaration::toCBuffer(buf, hgs); -} - - -/********************************* ConditionalDeclaration ****************************/ - -ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl) - : AttribDeclaration(decl) -{ - //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); - this->condition = condition; - this->elsedecl = elsedecl; -} - -Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) -{ - ConditionalDeclaration *dd; - - assert(!s); - dd = new ConditionalDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int ConditionalDeclaration::oneMember(Dsymbol **ps) -{ - //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); - if (condition->inc) - { - Array *d = condition->include(NULL, NULL) ? decl : elsedecl; - return Dsymbol::oneMembers(d, ps); - } - *ps = NULL; - return TRUE; -} - -void ConditionalDeclaration::emitComment(Scope *sc) -{ - //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); - if (condition->inc) - { - AttribDeclaration::emitComment(sc); - } -} - -// Decide if 'then' or 'else' code should be included - -Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("ConditionalDeclaration::include()\n"); - assert(condition); - return condition->include(sc, sd) ? decl : elsedecl; -} - - -void ConditionalDeclaration::addComment(unsigned char *comment) -{ - /* Because addComment is called by the parser, if we called - * include() it would define a version before it was used. - * But it's no problem to drill down to both decl and elsedecl, - * so that's the workaround. - */ - - if (comment) - { - Array *d = decl; - - for (int j = 0; j < 2; j++) - { - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - d = elsedecl; - } - } -} - -void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - if (decl || elsedecl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writeByte('}'); - if (elsedecl) - { - buf->writenl(); - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < elsedecl->dim; i++) - { - Dsymbol *s = (Dsymbol *)elsedecl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - } - else - buf->writeByte(':'); - buf->writenl(); -} - -/***************************** StaticIfDeclaration ****************************/ - -StaticIfDeclaration::StaticIfDeclaration(Condition *condition, - Array *decl, Array *elsedecl) - : ConditionalDeclaration(condition, decl, elsedecl) -{ - //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); - sd = NULL; - addisdone = 0; -} - - -Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticIfDeclaration *dd; - - assert(!s); - dd = new StaticIfDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("StaticIfDeclaration::addMember() '%s'\n",toChars()); - /* This is deferred until semantic(), so that - * expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this->sd = sd; - int m = 0; - - if (memnum == 0) - { m = AttribDeclaration::addMember(sc, sd, memnum); - addisdone = 1; - } - return m; -} - - -void StaticIfDeclaration::semantic(Scope *sc) -{ - Array *d = include(sc, sd); - - //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - if (!addisdone) - { AttribDeclaration::addMember(sc, sd, 1); - addisdone = 1; - } - - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - - s->semantic(sc); - } - } -} - -const char *StaticIfDeclaration::kind() -{ - return "static if"; -} - - -/***************************** CompileDeclaration *****************************/ - -CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) - : AttribDeclaration(NULL) -{ - //printf("CompileDeclaration(loc = %d)\n", loc.linnum); - this->loc = loc; - this->exp = exp; - this->sd = NULL; - this->compiled = 0; -} - -Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); - CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy()); - return sc; -} - -int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("CompileDeclaration::addMember(sc = %p, memnum = %d)\n", sc, memnum); - this->sd = sd; - if (memnum == 0) - { /* No members yet, so parse the mixin now - */ - compileIt(sc); - memnum |= AttribDeclaration::addMember(sc, sd, memnum); - compiled = 1; - } - return memnum; -} - -void CompileDeclaration::compileIt(Scope *sc) -{ - //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring) - { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); - } - else - { - StringExp *se = (StringExp *)exp; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - decl = p.parseDeclDefs(0); - if (p.token.value != TOKeof) - exp->error("incomplete mixin declaration (%s)", se->toChars()); - } -} - -void CompileDeclaration::semantic(Scope *sc) -{ - //printf("CompileDeclaration::semantic()\n"); - - if (!compiled) - { - compileIt(sc); - AttribDeclaration::addMember(sc, sd, 0); - compiled = 1; - } - AttribDeclaration::semantic(sc); -} - -void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - buf->writenl(); -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include + +#include "rmem.h" + +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "cond.h" +#include "scope.h" +#include "id.h" +#include "expression.h" +#include "dsymbol.h" +#include "aggregate.h" +#include "module.h" +#include "parse.h" +#include "template.h" + +#if IN_LLVM +#include "../gen/enums.h" + +#include "llvm/Support/CommandLine.h" + +static llvm::cl::opt ignoreUnsupportedPragmas("ignore", + llvm::cl::desc("Ignore unsupported pragmas"), + llvm::cl::ZeroOrMore); + +#endif + + +extern void obj_includelib(const char *name); + +#if IN_DMD +void obj_startaddress(Symbol *s); +#endif + + +/********************************* AttribDeclaration ****************************/ + +AttribDeclaration::AttribDeclaration(Array *decl) + : Dsymbol() +{ + this->decl = decl; +} + +Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + return decl; +} + +int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + int m = 0; + Array *d = include(sc, sd); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + m |= s->addMember(sc, sd, m | memnum); + } + } + return m; +} + +void AttribDeclaration::semantic(Scope *sc) +{ + Array *d = include(sc, NULL); + + //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->semantic(sc); + } + } +} + +void AttribDeclaration::semantic2(Scope *sc) +{ + Array *d = include(sc, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->semantic2(sc); + } + } +} + +void AttribDeclaration::semantic3(Scope *sc) +{ + Array *d = include(sc, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->semantic3(sc); + } + } +} + +void AttribDeclaration::inlineScan() +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); + s->inlineScan(); + } + } +} + +void AttribDeclaration::addComment(unsigned char *comment) +{ + if (comment) + { + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + } +} + +void AttribDeclaration::emitComment(Scope *sc) +{ + //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); + + /* A general problem with this, illustrated by BUGZILLA 2516, + * is that attributes are not transmitted through to the underlying + * member declarations for template bodies, because semantic analysis + * is not done for template declaration bodies + * (only template instantiations). + * Hence, Ddoc omits attributes from template members. + */ + + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::emitComment %s\n", s->toChars()); + s->emitComment(sc); + } + } +} + +#if IN_DMD + +void AttribDeclaration::toObjFile(int multiobj) +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->toObjFile(multiobj); + } + } +} + +int AttribDeclaration::cvMember(unsigned char *p) +{ + int nwritten = 0; + int n; + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + n = s->cvMember(p); + if (p) + p += n; + nwritten += n; + } + } + return nwritten; +} +#endif + +int AttribDeclaration::hasPointers() +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (size_t i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + if (s->hasPointers()) + return 1; + } + } + return 0; +} + +const char *AttribDeclaration::kind() +{ + return "attribute"; +} + +int AttribDeclaration::oneMember(Dsymbol **ps) +{ + Array *d = include(NULL, NULL); + + return Dsymbol::oneMembers(d, ps); +} + +void AttribDeclaration::checkCtorConstInit() +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->checkCtorConstInit(); + } + } +} + +/**************************************** + */ + +void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) +{ + Array *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->addLocalClass(aclasses); + } + } +} + + +void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (decl) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + } + else + buf->writeByte(';'); + buf->writenl(); +} + +/************************* StorageClassDeclaration ****************************/ + +StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl) + : AttribDeclaration(decl) +{ + this->stc = stc; +} + +Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) +{ + StorageClassDeclaration *scd; + + assert(!s); + scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); + return scd; +} + +void StorageClassDeclaration::semantic(Scope *sc) +{ + if (decl) + { unsigned stc_save = sc->stc; + + if (stc & (STCauto | STCscope | STCstatic | STCextern)) + sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern); + sc->stc |= stc; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->stc = stc_save; + } + else + sc->stc = stc; +} + +void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, int stc) +{ + struct SCstring + { + int stc; + enum TOK tok; + }; + + static SCstring table[] = + { + { STCauto, TOKauto }, + { STCscope, TOKscope }, + { STCstatic, TOKstatic }, + { STCextern, TOKextern }, + { STCconst, TOKconst }, + { STCimmutable, TOKimmutable }, + { STCshared, TOKshared }, + { STCfinal, TOKfinal }, + { STCabstract, TOKabstract }, + { STCsynchronized, TOKsynchronized }, + { STCdeprecated, TOKdeprecated }, + { STCoverride, TOKoverride }, + { STCnothrow, TOKnothrow }, + { STCpure, TOKpure }, + { STCref, TOKref }, + { STCtls, TOKtls }, + { STCgshared, TOKgshared }, + { STClazy, TOKlazy }, + { STCalias, TOKalias }, + { STCout, TOKout }, + { STCin, TOKin }, + }; + + for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) + { + if (stc & table[i].stc) + { + buf->writestring(Token::toChars(table[i].tok)); + buf->writeByte(' '); + } + } +} + +void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + stcToCBuffer(buf, stc); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* LinkDeclaration ****************************/ + +LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl) + : AttribDeclaration(decl) +{ + //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); + linkage = p; +} + +Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) +{ + LinkDeclaration *ld; + + assert(!s); + ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); + return ld; +} + +void LinkDeclaration::semantic(Scope *sc) +{ + //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { enum LINK linkage_save = sc->linkage; + + sc->linkage = linkage; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->linkage = linkage_save; + } + else + { + sc->linkage = linkage; + } +} + +void LinkDeclaration::semantic3(Scope *sc) +{ + //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { enum LINK linkage_save = sc->linkage; + + sc->linkage = linkage; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic3(sc); + } + sc->linkage = linkage_save; + } + else + { + sc->linkage = linkage; + } +} + +void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ const char *p; + + switch (linkage) + { + case LINKd: p = "D"; break; + case LINKc: p = "C"; break; + case LINKcpp: p = "C++"; break; + case LINKwindows: p = "Windows"; break; + case LINKpascal: p = "Pascal"; break; + +#if IN_LLVM + case LINKintrinsic: p = "Intrinsic"; break; +#endif + default: + assert(0); + break; + } + buf->writestring("extern ("); + buf->writestring(p); + buf->writestring(") "); + AttribDeclaration::toCBuffer(buf, hgs); +} + +char *LinkDeclaration::toChars() +{ + return (char *)"extern ()"; +} + +/********************************* ProtDeclaration ****************************/ + +ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl) + : AttribDeclaration(decl) +{ + protection = p; + //printf("decl = %p\n", decl); +} + +Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) +{ + ProtDeclaration *pd; + + assert(!s); + pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); + return pd; +} + +void ProtDeclaration::semantic(Scope *sc) +{ + if (decl) + { enum PROT protection_save = sc->protection; + int explicitProtection_save = sc->explicitProtection; + + sc->protection = protection; + sc->explicitProtection = 1; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + } + sc->protection = protection_save; + sc->explicitProtection = explicitProtection_save; + } + else + { sc->protection = protection; + sc->explicitProtection = 1; + } +} + +void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ const char *p; + + switch (protection) + { + case PROTprivate: p = "private"; break; + case PROTpackage: p = "package"; break; + case PROTprotected: p = "protected"; break; + case PROTpublic: p = "public"; break; + case PROTexport: p = "export"; break; + default: + assert(0); + break; + } + buf->writestring(p); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* AlignDeclaration ****************************/ + +AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Array *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + salign = sa; +} + +Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) +{ + AlignDeclaration *ad; + + assert(!s); + ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl)); + return ad; +} + +void AlignDeclaration::semantic(Scope *sc) +{ +// LDC +// we only support packed structs, as from the spec: align(1) struct Packed { ... } +// other alignments are simply ignored. my tests show this is what llvm-gcc does too ... + + //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); + if (decl) + { unsigned salign_save = sc->structalign; +#if IN_DMD + sc->structalign = salign; +#endif + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + if (s->isStructDeclaration() && salign == 1) + { + sc->structalign = salign; + s->semantic(sc); + sc->structalign = salign_save; + } + else + { + s->semantic(sc); + } + } + sc->structalign = salign_save; + } + else + assert(0 && "what kind of align use triggers this?"); +} + + +void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("align (%d)", salign); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* AnonDeclaration ****************************/ + +AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + this->isunion = isunion; + this->scope = NULL; + this->sem = 0; +} + +Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) +{ + AnonDeclaration *ad; + + assert(!s); + ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); + return ad; +} + +void AnonDeclaration::semantic(Scope *sc) +{ + //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; + scope = NULL; + } + + assert(sc->parent); + + Dsymbol *parent = sc->parent->pastMixin(); + AggregateDeclaration *ad = parent->isAggregateDeclaration(); + + if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) + { + error("can only be a part of an aggregate"); + return; + } + + if (decl) + { + AnonymousAggregateDeclaration aad; + int adisunion; + + if (sc->anonAgg) + { ad = sc->anonAgg; + adisunion = sc->inunion; + } + else + adisunion = ad->isUnionDeclaration() != NULL; + +// printf("\tsc->anonAgg = %p\n", sc->anonAgg); +// printf("\tad = %p\n", ad); +// printf("\taad = %p\n", &aad); + + sc = sc->push(); + sc->anonAgg = &aad; + sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); + sc->inunion = isunion; + sc->offset = 0; + sc->flags = 0; + aad.structalign = sc->structalign; + aad.parent = ad; + + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + if (isunion) + sc->offset = 0; + if (aad.sizeok == 2) + { + break; + } + } + sc = sc->pop(); + + // If failed due to forward references, unwind and try again later + if (aad.sizeok == 2) + { + ad->sizeok = 2; + //printf("\tsetting ad->sizeok %p to 2\n", ad); + if (!sc->anonAgg) + { + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + } + //printf("\tforward reference %p\n", this); + return; + } + if (sem == 0) + { Module::dprogress++; + sem = 1; + //printf("\tcompleted %p\n", this); + } + else + ;//printf("\talready completed %p\n", this); + + // 0 sized structs are set to 1 byte + if (aad.structsize == 0) + { + aad.structsize = 1; + aad.alignsize = 1; + } + + // Align size of anonymous aggregate +//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); + ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); + //ad->structsize = sc->offset; +//printf("sc->offset = %d\n", sc->offset); + + // Add members of aad to ad + //printf("\tadding members of aad to '%s'\n", ad->toChars()); + for (unsigned i = 0; i < aad.fields.dim; i++) + { + VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; + +#if IN_LLVM + v->offset2 = sc->offset; +#endif + v->offset += sc->offset; + +#if IN_LLVM + if (!v->anonDecl) + v->anonDecl = this; +#endif + ad->fields.push(v); + } + + // Add size of aad to ad + if (adisunion) + { + if (aad.structsize > ad->structsize) + ad->structsize = aad.structsize; + sc->offset = 0; + } + else + { + ad->structsize = sc->offset + aad.structsize; + sc->offset = ad->structsize; + } + + if (ad->alignsize < aad.alignsize) + ad->alignsize = aad.alignsize; + } +} + + +void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf(isunion ? "union" : "struct"); + buf->writestring("\n{\n"); + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + //buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + } + buf->writestring("}\n"); +} + +const char *AnonDeclaration::kind() +{ + return (isunion ? "anonymous union" : "anonymous struct"); +} + +/********************************* PragmaDeclaration ****************************/ + +static bool parseStringExp(Expression* e, std::string& res) +{ + StringExp *s = NULL; + + e = e->optimize(WANTvalue); + if (e->op == TOKstring && (s = (StringExp *)e)) + { + char* str = (char*)s->string; + res = str; + return true; + } + return false; +} + +PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + this->ident = ident; + this->args = args; +} + +Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); + PragmaDeclaration *pd; + + assert(!s); + pd = new PragmaDeclaration(loc, ident, + Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); + return pd; +} + +void PragmaDeclaration::semantic(Scope *sc) +{ // Should be merged with PragmaStatement + +#if IN_LLVM + int llvm_internal = 0; + std::string arg1str; +#endif + + //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); + if (ident == Id::msg) + { + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + Expression *e = (Expression *)args->data[i]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKstring) + { + StringExp *se = (StringExp *)e; + fprintf(stdmsg, "%.*s", (int)se->len, (char*)se->string); + } + else + error("string expected for message, not '%s'", e->toChars()); + } + fprintf(stdmsg, "\n"); + } + goto Lnodecl; + } + else if (ident == Id::lib) + { + if (!args || args->dim != 1) + error("string expected for library name"); + else + { + Expression *e = (Expression *)args->data[0]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + error("string expected for library name, not '%s'", e->toChars()); + else if (global.params.verbose) + { + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; + printf("library %s\n", name); + mem.free(name); + } + } + goto Lnodecl; + } +#if IN_GCC + else if (ident == Id::GNU_asm) + { + if (! args || args->dim != 2) + error("identifier and string expected for asm name"); + else + { + Expression *e; + Declaration *d = NULL; + StringExp *s = NULL; + + e = (Expression *)args->data[0]; + e = e->semantic(sc); + if (e->op == TOKvar) + { + d = ((VarExp *)e)->var; + if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) + d = NULL; + } + if (!d) + error("first argument of GNU_asm must be a function or variable declaration"); + + e = (Expression *)args->data[1]; + e = e->semantic(sc); + e = e->optimize(WANTvalue); + if (e->op == TOKstring && ((StringExp *)e)->sz == 1) + s = ((StringExp *)e); + else + error("second argument of GNU_asm must be a char string"); + + if (d && s) + d->c_ident = Lexer::idPool((char*) s->string); + } + goto Lnodecl; + } +#endif + else if (ident == Id::startaddress) + { + if (!args || args->dim != 1) + error("function name expected for start address"); + else + { + Expression *e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + Dsymbol *sa = getDsymbol(e); + if (!sa || !sa->isFuncDeclaration()) + error("function name expected for start address, not '%s'", e->toChars()); + } + goto Lnodecl; + } + +// LDC +#if IN_LLVM + + // pragma(intrinsic, "string") { funcdecl(s) } + else if (ident == Id::intrinsic) + { + Expression* expr = (Expression *)args->data[0]; + expr = expr->semantic(sc); + if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) + { + error("requires exactly 1 string literal parameter"); + fatal(); + } + llvm_internal = LLVMintrinsic; + } + + // pragma(notypeinfo) { typedecl(s) } + else if (ident == Id::no_typeinfo) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMno_typeinfo; + } + + // pragma(nomoduleinfo) ; + else if (ident == Id::no_moduleinfo) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMno_moduleinfo; + } + + // pragma(alloca) { funcdecl(s) } + else if (ident == Id::Alloca) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMalloca; + } + + // pragma(va_start) { templdecl(s) } + else if (ident == Id::vastart) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_start; + } + + // pragma(va_copy) { funcdecl(s) } + else if (ident == Id::vacopy) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_copy; + } + + // pragma(va_end) { funcdecl(s) } + else if (ident == Id::vaend) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_end; + } + + // pragma(va_arg) { templdecl(s) } + else if (ident == Id::vaarg) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_arg; + } + + // pragma(ldc, "string") { templdecl(s) } + else if (ident == Id::ldc) + { + Expression* expr = (Expression *)args->data[0]; + expr = expr->semantic(sc); + if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) + { + error("requires exactly 1 string literal parameter"); + fatal(); + } + else if (arg1str == "verbose") + { + sc->module->llvmForceLogging = true; + } + else + { + error("command '%s' invalid", expr->toChars()); + fatal(); + } + } + + // pragma(llvm_inline_asm) { templdecl(s) } + else if (ident == Id::llvm_inline_asm) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMinline_asm; + } + +#endif // LDC + + else if (ignoreUnsupportedPragmas) + { + if (global.params.verbose) + { + /* Print unrecognized pragmas + */ + printf("pragma %s", ident->toChars()); + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + // ignore errors in ignored pragmas. + global.gag++; + unsigned errors_save = global.errors; + + Expression *e = (Expression *)args->data[i]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (i == 0) + printf(" ("); + else + printf(","); + printf("%s", e->toChars()); + + // restore error state. + global.gag--; + global.errors = errors_save; + } + if (args->dim) + printf(")"); + } + printf("\n"); + } + } + else + error("unrecognized pragma(%s)", ident->toChars()); + + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + +// LDC +#if IN_LLVM + + if (llvm_internal) + { + if (s->llvmInternal) + { + error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars()); + fatal(); + } + switch(llvm_internal) + { + case LLVMintrinsic: + if (FuncDeclaration* fd = s->isFuncDeclaration()) + { + fd->llvmInternal = llvm_internal; + fd->intrinsicName = arg1str; + fd->linkage = LINKintrinsic; + ((TypeFunction*)fd->type)->linkage = LINKintrinsic; + } + else if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + td->llvmInternal = llvm_internal; + td->intrinsicName = arg1str; + } + else + { + error("only allowed on function declarations"); + fatal(); + } + break; + + case LLVMva_start: + case LLVMva_arg: + if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + if (td->parameters->dim != 1) + { + error("the '%s' pragma template must have exactly one template parameter", ident->toChars()); + fatal(); + } + else if (!td->onemember) + { + error("the '%s' pragma template must have exactly one member", ident->toChars()); + fatal(); + } + else if (td->overnext || td->overroot) + { + error("the '%s' pragma template must not be overloaded", ident->toChars()); + fatal(); + } + td->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on template declarations", ident->toChars()); + fatal(); + } + break; + + case LLVMva_copy: + case LLVMva_end: + if (FuncDeclaration* fd = s->isFuncDeclaration()) + { + fd->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on function declarations", ident->toChars()); + fatal(); + } + break; + + case LLVMno_typeinfo: + s->llvmInternal = llvm_internal; + break; + + case LLVMalloca: + if (FuncDeclaration* fd = s->isFuncDeclaration()) + { + fd->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars()); + fatal(); + } + break; + + case LLVMinline_asm: + if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + if (td->parameters->dim > 1) + { + error("the '%s' pragma template must have exactly zero or one template parameters", ident->toChars()); + fatal(); + } + else if (!td->onemember) + { + error("the '%s' pragma template must have exactly one member", ident->toChars()); + fatal(); + } + td->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on template declarations", ident->toChars()); + fatal(); + } + break; + + default: + warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); + } + } + +#endif // LDC + + } + } + return; + +Lnodecl: + if (decl) + error("pragma is missing closing ';'"); +} + +int PragmaDeclaration::oneMember(Dsymbol **ps) +{ + *ps = NULL; + return TRUE; +} + +const char *PragmaDeclaration::kind() +{ + return "pragma"; +} + +#if IN_DMD +void PragmaDeclaration::toObjFile(int multiobj) +{ + if (ident == Id::lib) + { + assert(args && args->dim == 1); + + Expression *e = (Expression *)args->data[0]; + + assert(e->op == TOKstring); + + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; +#if OMFOBJ + /* The OMF format allows library names to be inserted + * into the object file. The linker will then automatically + * search that library, too. + */ + obj_includelib(name); +#elif ELFOBJ || MACHOBJ + /* The format does not allow embedded library names, + * so instead append the library name to the list to be passed + * to the linker. + */ + global.params.libfiles->push((void *) name); +#else + error("pragma lib not supported"); +#endif + } +#if DMDV2 + else if (ident == Id::startaddress) + { + assert(args && args->dim == 1); + Expression *e = (Expression *)args->data[0]; + Dsymbol *sa = getDsymbol(e); + FuncDeclaration *f = sa->isFuncDeclaration(); + assert(f); + Symbol *s = f->toSymbol(); + obj_startaddress(s); + } +#endif + AttribDeclaration::toObjFile(multiobj); +} +#endif + +void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("pragma (%s", ident->toChars()); + if (args && args->dim) + { + buf->writestring(", "); + argsToCBuffer(buf, args, hgs); + } + buf->writeByte(')'); + AttribDeclaration::toCBuffer(buf, hgs); +} + + +/********************************* ConditionalDeclaration ****************************/ + +ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl) + : AttribDeclaration(decl) +{ + //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); + this->condition = condition; + this->elsedecl = elsedecl; +} + +Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) +{ + ConditionalDeclaration *dd; + + assert(!s); + dd = new ConditionalDeclaration(condition->syntaxCopy(), + Dsymbol::arraySyntaxCopy(decl), + Dsymbol::arraySyntaxCopy(elsedecl)); + return dd; +} + + +int ConditionalDeclaration::oneMember(Dsymbol **ps) +{ + //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); + if (condition->inc) + { + Array *d = condition->include(NULL, NULL) ? decl : elsedecl; + return Dsymbol::oneMembers(d, ps); + } + *ps = NULL; + return TRUE; +} + +void ConditionalDeclaration::emitComment(Scope *sc) +{ + //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); + if (condition->inc) + { + AttribDeclaration::emitComment(sc); + } + else if (sc->docbuf) + { + /* If generating doc comment, be careful because if we're inside + * a template, then include(NULL, NULL) will fail. + */ + Array *d = decl ? decl : elsedecl; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->emitComment(sc); + } + } +} + +// Decide if 'then' or 'else' code should be included + +Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + //printf("ConditionalDeclaration::include()\n"); + assert(condition); + return condition->include(sc, sd) ? decl : elsedecl; +} + + +void ConditionalDeclaration::addComment(unsigned char *comment) +{ + /* Because addComment is called by the parser, if we called + * include() it would define a version before it was used. + * But it's no problem to drill down to both decl and elsedecl, + * so that's the workaround. + */ + + if (comment) + { + Array *d = decl; + + for (int j = 0; j < 2; j++) + { + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + d = elsedecl; + } + } +} + +void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + condition->toCBuffer(buf, hgs); + if (decl || elsedecl) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + } + buf->writeByte('}'); + if (elsedecl) + { + buf->writenl(); + buf->writestring("else"); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (unsigned i = 0; i < elsedecl->dim; i++) + { + Dsymbol *s = (Dsymbol *)elsedecl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + } + } + else + buf->writeByte(':'); + buf->writenl(); +} + +/***************************** StaticIfDeclaration ****************************/ + +StaticIfDeclaration::StaticIfDeclaration(Condition *condition, + Array *decl, Array *elsedecl) + : ConditionalDeclaration(condition, decl, elsedecl) +{ + //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); + sd = NULL; + addisdone = 0; +} + + +Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticIfDeclaration *dd; + + assert(!s); + dd = new StaticIfDeclaration(condition->syntaxCopy(), + Dsymbol::arraySyntaxCopy(decl), + Dsymbol::arraySyntaxCopy(elsedecl)); + return dd; +} + + +int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("StaticIfDeclaration::addMember() '%s'\n",toChars()); + /* This is deferred until semantic(), so that + * expressions in the condition can refer to declarations + * in the same scope, such as: + * + * template Foo(int i) + * { + * const int j = i + 1; + * static if (j == 3) + * const int k; + * } + */ + this->sd = sd; + int m = 0; + + if (memnum == 0) + { m = AttribDeclaration::addMember(sc, sd, memnum); + addisdone = 1; + } + return m; +} + + +void StaticIfDeclaration::semantic(Scope *sc) +{ + Array *d = include(sc, sd); + + //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); + if (d) + { + if (!addisdone) + { AttribDeclaration::addMember(sc, sd, 1); + addisdone = 1; + } + + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->semantic(sc); + } + } +} + +const char *StaticIfDeclaration::kind() +{ + return "static if"; +} + + +/***************************** CompileDeclaration *****************************/ + +CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) + : AttribDeclaration(NULL) +{ + //printf("CompileDeclaration(loc = %d)\n", loc.linnum); + this->loc = loc; + this->exp = exp; + this->sd = NULL; + this->compiled = 0; +} + +Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); + CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy()); + return sc; +} + +int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("CompileDeclaration::addMember(sc = %p, memnum = %d)\n", sc, memnum); + this->sd = sd; + if (memnum == 0) + { /* No members yet, so parse the mixin now + */ + compileIt(sc); + memnum |= AttribDeclaration::addMember(sc, sd, memnum); + compiled = 1; + } + return memnum; +} + +void CompileDeclaration::compileIt(Scope *sc) +{ + //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue | WANTinterpret); + if (exp->op != TOKstring) + { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); + } + else + { + StringExp *se = (StringExp *)exp; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + decl = p.parseDeclDefs(0); + if (p.token.value != TOKeof) + exp->error("incomplete mixin declaration (%s)", se->toChars()); + } +} + +void CompileDeclaration::semantic(Scope *sc) +{ + //printf("CompileDeclaration::semantic()\n"); + + if (!compiled) + { + compileIt(sc); + AttribDeclaration::addMember(sc, sd, 0); + compiled = 1; + } + AttribDeclaration::semantic(sc); +} + +void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin("); + exp->toCBuffer(buf, hgs); + buf->writestring(");"); + buf->writenl(); +} diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/attrib.h --- a/dmd2/attrib.h Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/attrib.h Sat May 30 17:23:32 2009 +0100 @@ -50,8 +50,14 @@ void toCBuffer(OutBuffer *buf, HdrGenState *hgs); AttribDeclaration *isAttribDeclaration() { return this; } - virtual void toObjFile(int multiobj); // compile to .obj file +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file int cvMember(unsigned char *p); +#endif + +#if IN_LLVM + virtual void codegen(Ir*); +#endif }; struct StorageClassDeclaration: AttribDeclaration @@ -62,6 +68,8 @@ Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + static void stcToCBuffer(OutBuffer *buf, int stc); }; struct LinkDeclaration : AttribDeclaration @@ -107,9 +115,6 @@ void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); - - // LDC - void toObjFile(int multiobj); // compile to .obj file }; struct PragmaDeclaration : AttribDeclaration @@ -122,7 +127,14 @@ int oneMember(Dsymbol **ps); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); + +#if IN_DMD void toObjFile(int multiobj); // compile to .obj file +#endif + +#if IN_LLVM + void codegen(Ir*); +#endif }; struct ConditionalDeclaration : AttribDeclaration diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/backendlicense.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/backendlicense.txt Sat May 30 17:23:32 2009 +0100 @@ -0,0 +1,42 @@ + +The Software is not generally available software. It has not undergone +testing and may contain errors. The Software was not designed to operate +after December 31, 1999. It may be incomplete and it may not function +properly. No support or maintenance is provided with this Software. Do +not install or distribute the Software if +you are not accustomed to using or distributing experimental software. +Do not use this software for life critical applications, or applications +that could cause significant harm or property damage. + +Digital Mars licenses the Software to you on an "AS IS" basis, without +warranty of any kind. DIGITAL MARS AND SYMANTEC HEREBY EXPRESSLY DISCLAIM +ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF MERCHANTABILITY, +NONINFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. You are solely +responsible for determining the appropriateness of using this Software and +assume all risks associated with the use of this Software, including but not +limited to the risks of program errors, damage +to or loss of data, programs or equipment, unavailability or interruption of +operations and third party claims. You agree to defend, indemnify and hold +Digital Mars and Symantec, its subsidiaries, affiliates, directors, officers, +employees and agents harmless from all claims or demands made against them +(and any related losses, damages, expenses +and costs) arising out of your use of the Software. DIGITAL MARS AND SYMANTEC +WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, INCIDENTAL, OR +INDIRECT DAMAGES OR FOR ANY ECONOMIC CONSEQUENTIAL DAMAGES (INCLUDING +LOST PROFITS OR SAVINGS), EVEN IF DIGITAL MARS OR SYMANTEC HAS BEEN ADVISED +OF THE POSSIBILITY OF SUCH DAMAGES. +Digital Mars and Symantec will not be liable for the loss of, or damage to, +your records or data, the records or +data of any third party, or any damages claimed by you based on a third party +claim. + +If you send any messages to Digital Mars, on either the Digital Mars +newsgroups, the Digital Mars mailing list, or via email, you agree not +to make any claims of intellectual +property rights over the contents of those messages. + +The Software is copyrighted and comes with a single user license, +and may not be redistributed. If you wish to obtain a redistribution license, +please contact Digital Mars. + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/builtin.c --- a/dmd2/builtin.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/builtin.c Sat May 30 17:23:32 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -23,12 +23,15 @@ #include "id.h" #include "module.h" +#if DMDV2 + /********************************** - * Determine if function is a builtin one. + * Determine if function is a builtin one that we can + * evaluate at compile time. */ enum BUILTIN FuncDeclaration::isBuiltin() { - static const char FeZe[] = "FeZe"; // real function(real) + static const char FeZe[] = "FNaNbeZe"; // pure nothrow real function(real) //printf("FuncDeclaration::isBuiltin() %s\n", toChars()); if (builtin == BUILTINunknown) @@ -36,10 +39,12 @@ builtin = BUILTINnot; if (parent && parent->isModule()) { + // If it's in the std.math package if (parent->ident == Id::math && parent->parent && parent->parent->ident == Id::std && !parent->parent->parent) { + //printf("deco = %s\n", type->deco); if (strcmp(type->deco, FeZe) == 0) { if (ident == Id::sin) @@ -54,6 +59,13 @@ builtin = BUILTINfabs; //printf("builtin = %d\n", builtin); } + // if float or double versions + else if (strcmp(type->deco, "FNaNbdZd") == 0 || + strcmp(type->deco, "FNaNbfZf") == 0) + { + if (ident == Id::_sqrt) + builtin = BUILTINsqrt; + } } } } @@ -75,28 +87,30 @@ { case BUILTINsin: if (arg0->op == TOKfloat64) - e = new RealExp(0, sinl(arg0->toReal()), Type::tfloat80); + e = new RealExp(0, sinl(arg0->toReal()), arg0->type); break; case BUILTINcos: if (arg0->op == TOKfloat64) - e = new RealExp(0, cosl(arg0->toReal()), Type::tfloat80); + e = new RealExp(0, cosl(arg0->toReal()), arg0->type); break; case BUILTINtan: if (arg0->op == TOKfloat64) - e = new RealExp(0, tanl(arg0->toReal()), Type::tfloat80); + e = new RealExp(0, tanl(arg0->toReal()), arg0->type); break; case BUILTINsqrt: if (arg0->op == TOKfloat64) - e = new RealExp(0, sqrtl(arg0->toReal()), Type::tfloat80); + e = new RealExp(0, sqrtl(arg0->toReal()), arg0->type); break; case BUILTINfabs: if (arg0->op == TOKfloat64) - e = new RealExp(0, fabsl(arg0->toReal()), Type::tfloat80); + e = new RealExp(0, fabsl(arg0->toReal()), arg0->type); break; } return e; } + +#endif diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/cast.c --- a/dmd2/cast.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/cast.c Sat May 30 17:23:32 2009 +0100 @@ -1,1705 +1,1779 @@ - -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#if _WIN32 || IN_GCC || IN_LLVM -#include "mem.h" -#else -#include "../root/mem.h" -#endif - -#include "expression.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" - -/* ==================== implicitCast ====================== */ - -/************************************** - * Do an implicit cast. - * Issue error if it can't be done. - */ - -Expression *Expression::implicitCastTo(Scope *sc, Type *t) -{ - //printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); - - MATCH match = implicitConvTo(t); - if (match) - { TY tyfrom = type->toBasetype()->ty; - TY tyto = t->toBasetype()->ty; - if (global.params.warnings && - Type::impcnvWarn[tyfrom][tyto] && - op != TOKint64) - { - Expression *e = optimize(WANTflags | WANTvalue); - - if (e->op == TOKint64) - return e->implicitCastTo(sc, t); - - if (tyfrom == Tint32 && - (op == TOKadd || op == TOKmin || - op == TOKand || op == TOKor || op == TOKxor) - ) - { - /* This is really only a semi-kludge fix, - * we really should look at the operands of op - * and see if they are narrower types. - * For example, b=b|b and b=b|7 and s=b+b should be allowed, - * but b=b|i should be an error. - */ - ; - } - else - { - warning("%s: implicit conversion of expression (%s) of type %s to %s can cause loss of data", - loc.toChars(), toChars(), type->toChars(), t->toChars()); - } - } -#if DMDV2 - if (match == MATCHconst && t == type->constOf()) - { - Expression *e = copy(); - e->type = t; - return e; - } -#endif - return castTo(sc, t); - } - - Expression *e = optimize(WANTflags | WANTvalue); - if (e != this) - return e->implicitCastTo(sc, t); - -#if 0 -printf("ty = %d\n", type->ty); -print(); -type->print(); -printf("to:\n"); -t->print(); -printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco); -//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t); -fflush(stdout); -#endif - if (!t->deco) - { /* Can happen with: - * enum E { One } - * class A - * { static void fork(EDG dg) { dg(E.One); } - * alias void delegate(E) EDG; - * } - * Should eventually make it work. - */ - error("forward reference to type %s", t->toChars()); - } - else if (t->reliesOnTident()) - error("forward reference to type %s", t->reliesOnTident()->toChars()); - - error("cannot implicitly convert expression (%s) of type %s to %s", - toChars(), type->toChars(), t->toChars()); - return castTo(sc, t); -} - -/******************************************* - * Return !=0 if we can implicitly convert this to type t. - * Don't do the actual cast. - */ - -MATCH Expression::implicitConvTo(Type *t) -{ -#if 0 - printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - //static int nest; if (++nest == 10) halt(); - if (!type) - { error("%s is not an expression", toChars()); - type = Type::terror; - } - Expression *e = optimize(WANTvalue | WANTflags); - if (e->type == t) - return MATCHexact; - if (e != this) - { //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars()); - return e->implicitConvTo(t); - } - MATCH match = type->implicitConvTo(t); - if (match != MATCHnomatch) - return match; -#if 0 - Type *tb = t->toBasetype(); - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - match = type->implicitConvTo(tf->nextOf()); - if (match) - return match; - if (tf->nextOf()->toBasetype()->ty == Tvoid) - return MATCHconvert; - } - } -#endif - return MATCHnomatch; -} - - -MATCH IntegerExp::implicitConvTo(Type *t) -{ -#if 0 - printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH m = type->implicitConvTo(t); - if (m >= MATCHconst) - return m; - - TY ty = type->toBasetype()->ty; - TY toty = t->toBasetype()->ty; - - if (m == MATCHnomatch && t->ty == Tenum) - goto Lno; - - switch (ty) - { - case Tbit: - case Tbool: - value &= 1; - ty = Tint32; - break; - - case Tint8: - value = (signed char)value; - ty = Tint32; - break; - - case Tchar: - case Tuns8: - value &= 0xFF; - ty = Tint32; - break; - - case Tint16: - value = (short)value; - ty = Tint32; - break; - - case Tuns16: - case Twchar: - value &= 0xFFFF; - ty = Tint32; - break; - - case Tint32: - value = (int)value; - break; - - case Tuns32: - case Tdchar: - value &= 0xFFFFFFFF; - ty = Tuns32; - break; - - default: - break; - } - - // Only allow conversion if no change in value - switch (toty) - { - case Tbit: - case Tbool: - if ((value & 1) != value) - goto Lno; - goto Lyes; - - case Tint8: - if ((signed char)value != value) - goto Lno; - goto Lyes; - - case Tchar: - case Tuns8: - //printf("value = %llu %llu\n", (integer_t)(unsigned char)value, value); - if ((unsigned char)value != value) - goto Lno; - goto Lyes; - - case Tint16: - if ((short)value != value) - goto Lno; - goto Lyes; - - case Tuns16: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - - case Tint32: - if (ty == Tuns32) - { - } - else if ((int)value != value) - goto Lno; - goto Lyes; - - case Tuns32: - if (ty == Tint32) - { - } - else if ((unsigned)value != value) - goto Lno; - goto Lyes; - - case Tdchar: - if (value > 0x10FFFFUL) - goto Lno; - goto Lyes; - - case Twchar: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - - case Tfloat32: - { - volatile float f; - if (type->isunsigned()) - { - f = (float)value; - if (f != value) - goto Lno; - } - else - { - f = (float)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat64: - { - volatile double f; - if (type->isunsigned()) - { - f = (double)value; - if (f != value) - goto Lno; - } - else - { - f = (double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat80: - { - volatile long double f; - if (type->isunsigned()) - { - f = (long double)value; - if (f != value) - goto Lno; - } - else - { - f = (long double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tpointer: -//printf("type = %s\n", type->toBasetype()->toChars()); -//printf("t = %s\n", t->toBasetype()->toChars()); - if (ty == Tpointer && - type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty) - { /* Allow things like: - * const char* P = cast(char *)3; - * char* q = P; - */ - goto Lyes; - } - break; - } - return Expression::implicitConvTo(t); - -Lyes: - //printf("MATCHconvert\n"); - return MATCHconvert; - -Lno: - //printf("MATCHnomatch\n"); - return MATCHnomatch; -} - -MATCH NullExp::implicitConvTo(Type *t) -{ -#if 0 - printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", - toChars(), type->toChars(), t->toChars(), committed); -#endif - if (this->type->equals(t)) - return MATCHexact; - - /* Allow implicit conversions from invariant to mutable|const, - * and mutable to invariant. It works because, after all, a null - * doesn't actually point to anything. - */ - if (t->invariantOf()->equals(type->invariantOf())) - return MATCHconst; - - // NULL implicitly converts to any pointer type or dynamic array - if (type->ty == Tpointer && type->nextOf()->ty == Tvoid) - { - if (t->ty == Ttypedef) - t = ((TypeTypedef *)t)->sym->basetype; - if (t->ty == Tpointer || t->ty == Tarray || - t->ty == Taarray || t->ty == Tclass || - t->ty == Tdelegate) - return committed ? MATCHconvert : MATCHexact; - } - return Expression::implicitConvTo(t); -} - -#if DMDV2 -MATCH StructLiteralExp::implicitConvTo(Type *t) -{ -#if 0 - printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH m = Expression::implicitConvTo(t); - if (m != MATCHnomatch) - return m; - if (type->ty == t->ty && type->ty == Tstruct && - ((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym) - { - m = MATCHconst; - for (int i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - Type *te = e->type; - if (t->mod == 0) - te = te->mutableOf(); - else - { assert(t->mod == MODinvariant); - te = te->invariantOf(); - } - MATCH m2 = e->implicitConvTo(te); - //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2); - if (m2 < m) - m = m2; - } - } - return m; -} -#endif - -MATCH StringExp::implicitConvTo(Type *t) -{ MATCH m; - -#if 0 - printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", - toChars(), committed, type->toChars(), t->toChars()); -#endif - if (!committed) - { - if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) - { - return MATCHnomatch; - } - if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer) - { - TY tyn = type->nextOf()->ty; - if (tyn == Tchar || tyn == Twchar || tyn == Tdchar) - { Type *tn; - MATCH m; - - switch (t->ty) - { - case Tsarray: - if (type->ty == Tsarray) - { - if (((TypeSArray *)type)->dim->toInteger() != - ((TypeSArray *)t)->dim->toInteger()) - return MATCHnomatch; - TY tynto = t->nextOf()->ty; - if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) - return MATCHexact; - } - case Tarray: - case Tpointer: - tn = t->nextOf(); - m = MATCHexact; - if (type->nextOf()->mod != tn->mod) - { if (!tn->isConst()) - return MATCHnomatch; - m = MATCHconst; - } - switch (tn->ty) - { - case Tchar: - case Twchar: - case Tdchar: - return m; - } - break; - } - } - } - } - return Expression::implicitConvTo(t); -#if 0 - m = (MATCH)type->implicitConvTo(t); - if (m) - { - return m; - } - - return MATCHnomatch; -#endif -} - -MATCH ArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - -#if 0 - printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - result = MATCHnomatch; - } - - for (int i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - MATCH m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } - else - return Expression::implicitConvTo(t); -} - -MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray) - { - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = (Expression *)keys->data[i]; - MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - e = (Expression *)values->data[i]; - m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } - else - return Expression::implicitConvTo(t); -} - -MATCH AddrExp::implicitConvTo(Type *t) -{ -#if 0 - printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - //printf("\tresult = %d\n", result); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - - t = t->toBasetype(); - - if (e1->op == TOKoverloadset && - (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) - { OverExp *eo = (OverExp *)e1; - FuncDeclaration *f = NULL; - for (int i = 0; i < eo->vars->a.dim; i++) - { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - assert(f2); - if (f2->overloadExactMatch(t->nextOf())) - { if (f) - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol::multiplyDefined(loc, f, f2); - else - f = f2; - result = MATCHexact; - } - } - } - - if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && - t->ty == Tpointer && t->nextOf()->ty == Tfunction && - e1->op == TOKvar) - { -// LDC: it happens for us -#if !IN_LLVM - /* I don't think this can ever happen - - * it should have been - * converted to a SymOffExp. - */ - assert(0); -#endif - VarExp *ve = (VarExp *)e1; - FuncDeclaration *f = ve->var->isFuncDeclaration(); - if (f && f->overloadExactMatch(t->nextOf())) - result = MATCHexact; - } - } - //printf("\tresult = %d\n", result); - return result; -} - -MATCH SymOffExp::implicitConvTo(Type *t) -{ -#if 0 - printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - //printf("\tresult = %d\n", result); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - t = t->toBasetype(); - if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && - (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f) - { f = f->overloadExactMatch(t->nextOf()); - if (f) - { if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) || - (t->ty == Tpointer && !(f->needThis() || f->isNested()))) - { - result = MATCHexact; - } - } - } - } - } - //printf("\tresult = %d\n", result); - return result; -} - -MATCH DelegateExp::implicitConvTo(Type *t) -{ -#if 0 - printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - t = t->toBasetype(); - if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction && - t->ty == Tdelegate && t->nextOf()->ty == Tfunction) - { - if (func && func->overloadExactMatch(t->nextOf())) - result = MATCHexact; - } - } - return result; -} - -MATCH CondExp::implicitConvTo(Type *t) -{ - MATCH m1; - MATCH m2; - - m1 = e1->implicitConvTo(t); - m2 = e2->implicitConvTo(t); - - // Pick the worst match - return (m1 < m2) ? m1 : m2; -} - - -/* ==================== castTo ====================== */ - -/************************************** - * Do an explicit cast. - */ - -Expression *Expression::castTo(Scope *sc, Type *t) -{ - //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars()); -#if 0 - printf("Expression::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - Expression *e = this; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Do (type *) cast of (type [dim]) - if (tb->ty == Tpointer && - typeb->ty == Tsarray - ) - { - //printf("Converting [dim] to *\n"); - - if (typeb->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, e); - } -#if 0 - else if (tb->ty == Tdelegate && type->ty != Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - return toDelegate(sc, tf->nextOf()); - } -#endif - else - { - e = new CastExp(loc, e, tb); - } - } - else - { - e = e->copy(); // because of COW for assignment to e->type - } - assert(e != this); - e->type = t; - //printf("Returning: %s\n", e->toChars()); - return e; -} - - -Expression *RealExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if ((type->isreal() && t->isreal()) || - (type->isimaginary() && t->isimaginary()) - ) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *ComplexExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if (type->iscomplex() && t->iscomplex()) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *NullExp::castTo(Scope *sc, Type *t) -{ NullExp *e; - Type *tb; - - //printf("NullExp::castTo(t = %p)\n", t); - if (type == t) - { - committed = 1; - return this; - } - e = (NullExp *)copy(); - e->committed = 1; - tb = t->toBasetype(); - e->type = type->toBasetype(); - if (tb != e->type) - { - // NULL implicitly converts to any pointer type or dynamic array - if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && - (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || - tb->ty == Tdelegate)) - { -#if 0 - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - return Expression::castTo(sc, t); - } - } -#endif - } - else - { - return e->Expression::castTo(sc, t); - } - } - e->type = t; - return e; -} - -Expression *StringExp::castTo(Scope *sc, Type *t) -{ - /* This follows copy-on-write; any changes to 'this' - * will result in a copy. - * The this->string member is considered immutable. - */ - StringExp *se; - Type *tb; - int copied = 0; - - //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); - - if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) - { - error("cannot convert string literal to void*"); - } - - se = this; - if (!committed) - { se = (StringExp *)copy(); - se->committed = 1; - copied = 1; - } - - if (type == t) - { - return se; - } - - tb = t->toBasetype(); - //printf("\ttype = %s\n", type->toChars()); - if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) - return Expression::castTo(sc, t); - - Type *typeb = type->toBasetype(); - if (typeb == tb) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->type = t; - return se; - } - - if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer) - { if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - goto Lcast; - } - if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer) - { if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - goto Lcast; - } - - if (typeb->nextOf()->size() == tb->nextOf()->size()) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - if (tb->ty == Tsarray) - goto L2; // handle possible change in static array dimension - se->type = t; - return se; - } - - if (committed) - goto Lcast; - -#define X(tf,tt) ((tf) * 256 + (tt)) - { - OutBuffer buffer; - size_t newlen = 0; - int tfty = typeb->nextOf()->toBasetype()->ty; - int ttty = tb->nextOf()->toBasetype()->ty; - switch (X(tfty, ttty)) - { - case X(Tchar, Tchar): - case X(Twchar,Twchar): - case X(Tdchar,Tdchar): - break; - - case X(Tchar, Twchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); - if (p) - error("%s", p); - else - buffer.writeUTF16(c); - } - newlen = buffer.offset / 2; - buffer.writeUTF16(0); - goto L1; - - case X(Tchar, Tdchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); - if (p) - error("%s", p); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Twchar,Tchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); - if (p) - error("%s", p); - else - buffer.writeUTF8(c); - } - newlen = buffer.offset; - buffer.writeUTF8(0); - goto L1; - - case X(Twchar,Tdchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); - if (p) - error("%s", p); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Tdchar,Tchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF8(c); - newlen++; - } - newlen = buffer.offset; - buffer.writeUTF8(0); - goto L1; - - case X(Tdchar,Twchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF16(c); - newlen++; - } - newlen = buffer.offset / 2; - buffer.writeUTF16(0); - goto L1; - - L1: - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->string = buffer.extractData(); - se->len = newlen; - se->sz = tb->nextOf()->size(); - break; - - default: - assert(typeb->nextOf()->size() != tb->nextOf()->size()); - goto Lcast; - } - } -#undef X -L2: - assert(copied); - - // See if need to truncate or extend the literal - if (tb->ty == Tsarray) - { - int dim2 = ((TypeSArray *)tb)->dim->toInteger(); - - //printf("dim from = %d, to = %d\n", se->len, dim2); - - // Changing dimensions - if (dim2 != se->len) - { - // Copy when changing the string literal - unsigned newsz = se->sz; - void *s; - int d; - - d = (dim2 < se->len) ? dim2 : se->len; - s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); - memcpy(s, se->string, d * newsz); - // Extend with 0, add terminating 0 - memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); - se->string = s; - se->len = dim2; - } - } - se->type = t; - return se; - -Lcast: - Expression *e = new CastExp(loc, se, t); - e->type = t; // so semantic() won't be run on e - return e; -} - -Expression *AddrExp::castTo(Scope *sc, Type *t) -{ - Type *tb; - -#if 0 - printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Expression *e = this; - - tb = t->toBasetype(); - type = type->toBasetype(); - if (tb != type) - { - // Look for pointers to functions where the functions are overloaded. - - if (e1->op == TOKoverloadset && - (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) - { OverExp *eo = (OverExp *)e1; - FuncDeclaration *f = NULL; - for (int i = 0; i < eo->vars->a.dim; i++) - { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - assert(f2); - if (f2->overloadExactMatch(t->nextOf())) - { if (f) - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol::multiplyDefined(loc, f, f2); - else - f = f2; - } - } - if (f) - { f->tookAddressOf++; - SymOffExp *se = new SymOffExp(loc, f, 0, 0); - se->semantic(sc); - // Let SymOffExp::castTo() do the heavy lifting - return se->castTo(sc, t); - } - } - - - if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && - tb->ty == Tpointer && tb->nextOf()->ty == Tfunction && - e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - FuncDeclaration *f = ve->var->isFuncDeclaration(); - if (f) - { -// LDC: not in ldc -#if !IN_LLVM - assert(0); // should be SymOffExp instead -#endif - f = f->overloadExactMatch(tb->nextOf()); - if (f) - { - e = new VarExp(loc, f); - e->type = f->type; - e = new AddrExp(loc, e); - e->type = t; - return e; - } - } - } - e = Expression::castTo(sc, t); - } - e->type = t; - return e; -} - - -Expression *TupleExp::castTo(Scope *sc, Type *t) -{ TupleExp *e = (TupleExp *)copy(); - e->exps = (Expressions *)exps->copy(); - for (size_t i = 0; i < e->exps->dim; i++) - { Expression *ex = (Expression *)e->exps->data[i]; - ex = ex->castTo(sc, t); - e->exps->data[i] = (void *)ex; - } - return e; -} - - -Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - ArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray) && - // Not trying to convert non-void[] to void[] - !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - goto L1; - } - - e = (ArrayLiteralExp *)copy(); - e->elements = (Expressions *)elements->copy(); - for (int i = 0; i < elements->dim; i++) - { Expression *ex = (Expression *)elements->data[i]; - ex = ex->castTo(sc, tb->nextOf()); - e->elements->data[i] = (void *)ex; - } - e->type = t; - return e; - } - if (tb->ty == Tpointer && typeb->ty == Tsarray) - { - e = (ArrayLiteralExp *)copy(); - e->type = typeb->nextOf()->pointerTo(); - } -L1: - return e->Expression::castTo(sc, t); -} - -Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) -{ - if (type == t) - return this; - AssocArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray && - tb->nextOf()->toBasetype()->ty != Tvoid) - { - e = (AssocArrayLiteralExp *)copy(); - e->keys = (Expressions *)keys->copy(); - e->values = (Expressions *)values->copy(); - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *ex = (Expression *)values->data[i]; - ex = ex->castTo(sc, tb->nextOf()); - e->values->data[i] = (void *)ex; - - ex = (Expression *)keys->data[i]; - ex = ex->castTo(sc, ((TypeAArray *)tb)->index); - e->keys->data[i] = (void *)ex; - } - e->type = t; - return e; - } -L1: - return e->Expression::castTo(sc, t); -} - -Expression *SymOffExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t && hasOverloads == 0) - return this; - Expression *e; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - if (hasOverloads && - typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction && - (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f) - { - f = f->overloadExactMatch(tb->nextOf()); - if (f) - { - if (tb->ty == Tdelegate && f->needThis() && hasThis(sc)) - { - e = new DelegateExp(loc, new ThisExp(loc), f); - e = e->semantic(sc); - } - else if (tb->ty == Tdelegate && f->isNested()) - { - e = new DelegateExp(loc, new IntegerExp(0), f); - e = e->semantic(sc); - } - else - { - e = new SymOffExp(loc, f, 0); - e->type = t; - } - f->tookAddressOf++; - return e; - } - } - } - e = Expression::castTo(sc, t); - } - else - { e = copy(); - e->type = t; - ((SymOffExp *)e)->hasOverloads = 0; - } - return e; -} - -Expression *DelegateExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - static char msg[] = "cannot form delegate due to covariant return type"; - - Expression *e = this; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Look for delegates to functions where the functions are overloaded. - FuncDeclaration *f; - - if (typeb->ty == Tdelegate && typeb->nextOf()->ty == Tfunction && - tb->ty == Tdelegate && tb->nextOf()->ty == Tfunction) - { - if (func) - { - f = func->overloadExactMatch(tb->nextOf()); - if (f) - { int offset; - if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset) - error("%s", msg); - f->tookAddressOf++; - e = new DelegateExp(loc, e1, f); - e->type = t; - return e; - } - if (func->tintro) - error("%s", msg); - } - } - e = Expression::castTo(sc, t); - } - else - { int offset; - - func->tookAddressOf++; - if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset) - error("%s", msg); - e = copy(); - e->type = t; - } - return e; -} - -Expression *CondExp::castTo(Scope *sc, Type *t) -{ - Expression *e = this; - - if (type != t) - { - if (1 || e1->op == TOKstring || e2->op == TOKstring) - { e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t)); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - -/* ==================== ====================== */ - -/**************************************** - * Scale addition/subtraction to/from pointer. - */ - -Expression *BinExp::scaleFactor(Scope *sc) -{ d_uns64 stride; - Type *t1b = e1->type->toBasetype(); - Type *t2b = e2->type->toBasetype(); - - if (t1b->ty == Tpointer && t2b->isintegral()) - { // Need to adjust operator by the stride - // Replace (ptr + int) with (ptr + (int * stride)) - Type *t = Type::tptrdiff_t; - - stride = t1b->nextOf()->size(loc); - if (!t->equals(t2b)) - e2 = e2->castTo(sc, t); - // LDC: llvm uses typesafe pointer arithmetic - #if !IN_LLVM - e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t)); - #endif - e2->type = t; - type = e1->type; - } - else if (t2b->ty == Tpointer && t1b->isintegral()) - { // Need to adjust operator by the stride - // Replace (int + ptr) with (ptr + (int * stride)) - Type *t = Type::tptrdiff_t; - Expression *e; - - stride = t2b->nextOf()->size(loc); - if (!t->equals(t1b)) - e = e1->castTo(sc, t); - else - e = e1; - #if !IN_LLVM - e = new MulExp(loc, e, new IntegerExp(0, stride, t)); - #endif - e->type = t; - type = e2->type; - e1 = e2; - e2 = e; - } - return this; -} - -/************************************** - * Combine types. - * Output: - * *pt merged type, if *pt is not NULL - * *pe1 rewritten e1 - * *pe2 rewritten e2 - * Returns: - * !=0 success - * 0 failed - */ - -int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2) -{ - //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars()); - //dump(0); - - Expression *e1 = (*pe1)->integralPromotions(sc); - Expression *e2 = (*pe2)->integralPromotions(sc); - - Type *t1 = e1->type; - Type *t2 = e2->type; - assert(t1); - Type *t = t1; - - //if (t1) printf("\tt1 = %s\n", t1->toChars()); - //if (t2) printf("\tt2 = %s\n", t2->toChars()); -#ifdef DEBUG - if (!t2) printf("\te2 = '%s'\n", e2->toChars()); -#endif - assert(t2); - - Type *t1b = t1->toBasetype(); - Type *t2b = t2->toBasetype(); - - TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty]; - if (ty != Terror) - { TY ty1; - TY ty2; - - ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty]; - ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty]; - - if (t1b->ty == ty1) // if no promotions - { - if (t1 == t2) - { - t = t1; - goto Lret; - } - - if (t1b == t2b) - { - t = t1b; - goto Lret; - } - } - - t = Type::basic[ty]; - - t1 = Type::basic[ty1]; - t2 = Type::basic[ty2]; - e1 = e1->castTo(sc, t1); - e2 = e2->castTo(sc, t2); - //printf("after typeCombine():\n"); - //dump(0); - //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); - goto Lret; - } - - t1 = t1b; - t2 = t2b; - -Lagain: - if (t1 == t2) - { - } - else if (t1->ty == Tpointer && t2->ty == Tpointer) - { - // Bring pointers to compatible type - Type *t1n = t1->nextOf(); - Type *t2n = t2->nextOf(); - - if (t1n == t2n) - ; - else if (t1n->ty == Tvoid) // pointers to void are always compatible - t = t2; - else if (t2n->ty == Tvoid) - ; - else if (t1n->mod != t2n->mod) - { - t1 = t1n->mutableOf()->constOf()->pointerTo(); - t2 = t2n->mutableOf()->constOf()->pointerTo(); - t = t1; - goto Lagain; - } - else if (t1n->ty == Tclass && t2n->ty == Tclass) - { ClassDeclaration *cd1 = t1n->isClassHandle(); - ClassDeclaration *cd2 = t2n->isClassHandle(); - int offset; - - if (cd1->isBaseOf(cd2, &offset)) - { - if (offset) - e2 = e2->castTo(sc, t); - } - else if (cd2->isBaseOf(cd1, &offset)) - { - t = t2; - if (offset) - e1 = e1->castTo(sc, t); - } - else - goto Lincompatible; - } - else - goto Lincompatible; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && - e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid) - { /* (T[n] op void*) - * (T[] op void*) - */ - goto Lx1; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && - e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid) - { /* (void* op T[n]) - * (void* op T[]) - */ - goto Lx2; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) - { - goto Lt2; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) - { - goto Lt1; - } - /* If one is mutable and the other invariant, then retry - * with both of them as const - */ - else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) && - (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) && - t1->nextOf()->mod != t2->nextOf()->mod - ) - { - if (t1->ty == Tpointer) - t1 = t1->nextOf()->mutableOf()->constOf()->pointerTo(); - else - t1 = t1->nextOf()->mutableOf()->constOf()->arrayOf(); - - if (t2->ty == Tpointer) - t2 = t2->nextOf()->mutableOf()->constOf()->pointerTo(); - else - t2 = t2->nextOf()->mutableOf()->constOf()->arrayOf(); - t = t1; - goto Lagain; - } - else if (t1->ty == Tclass || t2->ty == Tclass) - { - while (1) - { - int i1 = e2->implicitConvTo(t1); - int i2 = e1->implicitConvTo(t2); - - if (i1 && i2) - { - // We have the case of class vs. void*, so pick class - if (t1->ty == Tpointer) - i1 = 0; - else if (t2->ty == Tpointer) - i2 = 0; - } - - if (i2) - { - goto Lt2; - } - else if (i1) - { - goto Lt1; - } - else if (t1->ty == Tclass && t2->ty == Tclass) - { TypeClass *tc1 = (TypeClass *)t1; - TypeClass *tc2 = (TypeClass *)t2; - - /* Pick 'tightest' type - */ - ClassDeclaration *cd1 = tc1->sym->baseClass; - ClassDeclaration *cd2 = tc2->sym->baseClass; - - if (cd1 && cd2) - { t1 = cd1->type; - t2 = cd2->type; - } - else if (cd1) - t1 = cd1->type; - else if (cd2) - t2 = cd2->type; - else - goto Lincompatible; - } - else - goto Lincompatible; - } - } - else if (t1->ty == Tstruct && t2->ty == Tstruct) - { - if (((TypeStruct *)t1)->sym != ((TypeStruct *)t2)->sym) - goto Lincompatible; - } - else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2)) - { - goto Lt2; - } - else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1)) - { - goto Lt1; - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e2->implicitConvTo(t1->nextOf()->arrayOf())) - { - Lx1: - t = t1->nextOf()->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e1->implicitConvTo(t2->nextOf()->arrayOf())) - { - Lx2: - t = t2->nextOf()->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->isintegral() && t2->isintegral()) - { - assert(0); - } - else if (e1->op == TOKslice && t1->ty == Tarray && - e2->implicitConvTo(t1->nextOf())) - { // T[] op T - e2 = e2->castTo(sc, t1->nextOf()); - t = t1->nextOf()->arrayOf(); - } - else if (e2->op == TOKslice && t2->ty == Tarray && - e1->implicitConvTo(t2->nextOf())) - { // T op T[] - e1 = e1->castTo(sc, t2->nextOf()); - t = t2->nextOf()->arrayOf(); - - //printf("test %s\n", e->toChars()); - e1 = e1->optimize(WANTvalue); - if (e && e->isCommutative() && e1->isConst()) - { /* Swap operands to minimize number of functions generated - */ - //printf("swap %s\n", e->toChars()); - Expression *tmp = e1; - e1 = e2; - e2 = tmp; - } - } - else - { - Lincompatible: - return 0; - } -Lret: - if (!*pt) - *pt = t; - *pe1 = e1; - *pe2 = e2; -#if 0 - printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars()); - if (e1->type) printf("\tt1 = %s\n", e1->type->toChars()); - if (e2->type) printf("\tt2 = %s\n", e2->type->toChars()); - printf("\ttype = %s\n", t->toChars()); -#endif - //dump(0); - return 1; - - -Lt1: - e2 = e2->castTo(sc, t1); - t = t1; - goto Lret; - -Lt2: - e1 = e1->castTo(sc, t2); - t = t2; - goto Lret; -} - -/************************************ - * Bring leaves to common type. - */ - -Expression *BinExp::typeCombine(Scope *sc) -{ - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - - if (op == TOKmin || op == TOKadd) - { - if (t1 == t2 && (t1->ty == Tstruct || t1->ty == Tclass)) - goto Lerror; - } - - if (!typeMerge(sc, this, &type, &e1, &e2)) - goto Lerror; - return this; - -Lerror: - incompatibleTypes(); - type = Type::terror; - return this; -} - -/*********************************** - * Do integral promotions (convertchk). - * Don't convert to - */ - -Expression *Expression::integralPromotions(Scope *sc) -{ - Expression *e = this; - - //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars()); - switch (type->toBasetype()->ty) - { - case Tvoid: - error("void has no value"); - break; - - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - case Tbit: - case Tbool: - case Tchar: - case Twchar: - e = e->castTo(sc, Type::tint32); - break; - - case Tdchar: - e = e->castTo(sc, Type::tuns32); - break; - } - return e; -} - + +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include + +#include "rmem.h" + +#include "expression.h" +#include "mtype.h" +#include "utf.h" +#include "declaration.h" +#include "aggregate.h" + +/* ==================== implicitCast ====================== */ + +/************************************** + * Do an implicit cast. + * Issue error if it can't be done. + */ + +Expression *Expression::implicitCastTo(Scope *sc, Type *t) +{ + //printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); + + MATCH match = implicitConvTo(t); + if (match) + { TY tyfrom = type->toBasetype()->ty; + TY tyto = t->toBasetype()->ty; + if (global.params.warnings && + Type::impcnvWarn[tyfrom][tyto] && + op != TOKint64) + { + Expression *e = optimize(WANTflags | WANTvalue); + + if (e->op == TOKint64) + return e->implicitCastTo(sc, t); + + if (tyfrom == Tint32 && + (op == TOKadd || op == TOKmin || + op == TOKand || op == TOKor || op == TOKxor) + ) + { + /* This is really only a semi-kludge fix, + * we really should look at the operands of op + * and see if they are narrower types. + * For example, b=b|b and b=b|7 and s=b+b should be allowed, + * but b=b|i should be an error. + */ + ; + } + else + { + warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data", + toChars(), type->toChars(), t->toChars()); + } + } +#if DMDV2 + if (match == MATCHconst && t == type->constOf()) + { + Expression *e = copy(); + e->type = t; + return e; + } +#endif + return castTo(sc, t); + } + + Expression *e = optimize(WANTflags | WANTvalue); + if (e != this) + return e->implicitCastTo(sc, t); + +#if 0 +printf("ty = %d\n", type->ty); +print(); +type->print(); +printf("to:\n"); +t->print(); +printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco); +//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t); +fflush(stdout); +#endif + if (!t->deco) + { /* Can happen with: + * enum E { One } + * class A + * { static void fork(EDG dg) { dg(E.One); } + * alias void delegate(E) EDG; + * } + * Should eventually make it work. + */ + error("forward reference to type %s", t->toChars()); + } + else if (t->reliesOnTident()) + error("forward reference to type %s", t->reliesOnTident()->toChars()); + + error("cannot implicitly convert expression (%s) of type %s to %s", + toChars(), type->toChars(), t->toChars()); + return castTo(sc, t); +} + +Expression *StringExp::implicitCastTo(Scope *sc, Type *t) +{ + //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); + unsigned char committed = this->committed; + Expression *e = Expression::implicitCastTo(sc, t); + if (e->op == TOKstring) + { + // Retain polysemous nature if it started out that way + ((StringExp *)e)->committed = committed; + } + return e; +} + +/******************************************* + * Return !=0 if we can implicitly convert this to type t. + * Don't do the actual cast. + */ + +MATCH Expression::implicitConvTo(Type *t) +{ +#if 0 + printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + //static int nest; if (++nest == 10) halt(); + if (!type) + { error("%s is not an expression", toChars()); + type = Type::terror; + } + Expression *e = optimize(WANTvalue | WANTflags); + if (e->type == t) + return MATCHexact; + if (e != this) + { //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars()); + return e->implicitConvTo(t); + } + MATCH match = type->implicitConvTo(t); + if (match != MATCHnomatch) + return match; +#if 0 + Type *tb = t->toBasetype(); + if (tb->ty == Tdelegate) + { TypeDelegate *td = (TypeDelegate *)tb; + TypeFunction *tf = (TypeFunction *)td->nextOf(); + + if (!tf->varargs && + !(tf->arguments && tf->arguments->dim) + ) + { + match = type->implicitConvTo(tf->nextOf()); + if (match) + return match; + if (tf->nextOf()->toBasetype()->ty == Tvoid) + return MATCHconvert; + } + } +#endif + return MATCHnomatch; +} + + +MATCH IntegerExp::implicitConvTo(Type *t) +{ +#if 0 + printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH m = type->implicitConvTo(t); + if (m >= MATCHconst) + return m; + + TY ty = type->toBasetype()->ty; + TY toty = t->toBasetype()->ty; + + if (m == MATCHnomatch && t->ty == Tenum) + goto Lno; + + switch (ty) + { + case Tbit: + case Tbool: + value &= 1; + ty = Tint32; + break; + + case Tint8: + value = (signed char)value; + ty = Tint32; + break; + + case Tchar: + case Tuns8: + value &= 0xFF; + ty = Tint32; + break; + + case Tint16: + value = (short)value; + ty = Tint32; + break; + + case Tuns16: + case Twchar: + value &= 0xFFFF; + ty = Tint32; + break; + + case Tint32: + value = (int)value; + break; + + case Tuns32: + case Tdchar: + value &= 0xFFFFFFFF; + ty = Tuns32; + break; + + default: + break; + } + + // Only allow conversion if no change in value + switch (toty) + { + case Tbit: + case Tbool: + if ((value & 1) != value) + goto Lno; + goto Lyes; + + case Tint8: + if ((signed char)value != value) + goto Lno; + goto Lyes; + + case Tchar: + case Tuns8: + //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); + if ((unsigned char)value != value) + goto Lno; + goto Lyes; + + case Tint16: + if ((short)value != value) + goto Lno; + goto Lyes; + + case Tuns16: + if ((unsigned short)value != value) + goto Lno; + goto Lyes; + + case Tint32: + if (ty == Tuns32) + { + } + else if ((int)value != value) + goto Lno; + goto Lyes; + + case Tuns32: + if (ty == Tint32) + { + } + else if ((unsigned)value != value) + goto Lno; + goto Lyes; + + case Tdchar: + if (value > 0x10FFFFUL) + goto Lno; + goto Lyes; + + case Twchar: + if ((unsigned short)value != value) + goto Lno; + goto Lyes; + + case Tfloat32: + { + volatile float f; + if (type->isunsigned()) + { + f = (float)value; + if (f != value) + goto Lno; + } + else + { + f = (float)(long long)value; + if (f != (long long)value) + goto Lno; + } + goto Lyes; + } + + case Tfloat64: + { + volatile double f; + if (type->isunsigned()) + { + f = (double)value; + if (f != value) + goto Lno; + } + else + { + f = (double)(long long)value; + if (f != (long long)value) + goto Lno; + } + goto Lyes; + } + + case Tfloat80: + { + volatile long double f; + if (type->isunsigned()) + { + f = (long double)value; + if (f != value) + goto Lno; + } + else + { + f = (long double)(long long)value; + if (f != (long long)value) + goto Lno; + } + goto Lyes; + } + + case Tpointer: +//printf("type = %s\n", type->toBasetype()->toChars()); +//printf("t = %s\n", t->toBasetype()->toChars()); + if (ty == Tpointer && + type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty) + { /* Allow things like: + * const char* P = cast(char *)3; + * char* q = P; + */ + goto Lyes; + } + break; + } + return Expression::implicitConvTo(t); + +Lyes: + //printf("MATCHconvert\n"); + return MATCHconvert; + +Lno: + //printf("MATCHnomatch\n"); + return MATCHnomatch; +} + +MATCH NullExp::implicitConvTo(Type *t) +{ +#if 0 + printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", + toChars(), type->toChars(), t->toChars(), committed); +#endif + if (this->type->equals(t)) + return MATCHexact; + + /* Allow implicit conversions from invariant to mutable|const, + * and mutable to invariant. It works because, after all, a null + * doesn't actually point to anything. + */ + if (t->invariantOf()->equals(type->invariantOf())) + return MATCHconst; + + // NULL implicitly converts to any pointer type or dynamic array + if (type->ty == Tpointer && type->nextOf()->ty == Tvoid) + { + if (t->ty == Ttypedef) + t = ((TypeTypedef *)t)->sym->basetype; + if (t->ty == Tpointer || t->ty == Tarray || + t->ty == Taarray || t->ty == Tclass || + t->ty == Tdelegate) + return committed ? MATCHconvert : MATCHexact; + } + return Expression::implicitConvTo(t); +} + +#if DMDV2 +MATCH StructLiteralExp::implicitConvTo(Type *t) +{ +#if 0 + printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH m = Expression::implicitConvTo(t); + if (m != MATCHnomatch) + return m; + if (type->ty == t->ty && type->ty == Tstruct && + ((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym) + { + m = MATCHconst; + for (int i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + Type *te = e->type; + if (t->mod == 0) + te = te->mutableOf(); + else + { assert(t->mod == MODinvariant); + te = te->invariantOf(); + } + MATCH m2 = e->implicitConvTo(te); + //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2); + if (m2 < m) + m = m2; + } + } + return m; +} +#endif + +MATCH StringExp::implicitConvTo(Type *t) +{ MATCH m; + +#if 0 + printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", + toChars(), committed, type->toChars(), t->toChars()); +#endif + if (!committed) + { + if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) + { + return MATCHnomatch; + } + if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer) + { + TY tyn = type->nextOf()->ty; + if (tyn == Tchar || tyn == Twchar || tyn == Tdchar) + { Type *tn; + MATCH m; + + switch (t->ty) + { + case Tsarray: + if (type->ty == Tsarray) + { + if (((TypeSArray *)type)->dim->toInteger() != + ((TypeSArray *)t)->dim->toInteger()) + return MATCHnomatch; + TY tynto = t->nextOf()->ty; + if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) + return MATCHexact; + } + else if (type->ty == Tarray) + { + if (length() > + ((TypeSArray *)t)->dim->toInteger()) + return MATCHnomatch; + TY tynto = t->nextOf()->ty; + if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) + return MATCHexact; + } + case Tarray: + case Tpointer: + tn = t->nextOf(); + m = MATCHexact; + if (type->nextOf()->mod != tn->mod) + { if (!tn->isConst()) + return MATCHnomatch; + m = MATCHconst; + } + switch (tn->ty) + { + case Tchar: + case Twchar: + case Tdchar: + return m; + } + break; + } + } + } + } + return Expression::implicitConvTo(t); +#if 0 + m = (MATCH)type->implicitConvTo(t); + if (m) + { + return m; + } + + return MATCHnomatch; +#endif +} + +MATCH ArrayLiteralExp::implicitConvTo(Type *t) +{ MATCH result = MATCHexact; + +#if 0 + printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if ((tb->ty == Tarray || tb->ty == Tsarray) && + (typeb->ty == Tarray || typeb->ty == Tsarray)) + { + if (tb->ty == Tsarray) + { TypeSArray *tsa = (TypeSArray *)tb; + if (elements->dim != tsa->dim->toInteger()) + result = MATCHnomatch; + } + + for (int i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + MATCH m = (MATCH)e->implicitConvTo(tb->nextOf()); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + } + return result; + } + else + return Expression::implicitConvTo(t); +} + +MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) +{ MATCH result = MATCHexact; + + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if (tb->ty == Taarray && typeb->ty == Taarray) + { + for (size_t i = 0; i < keys->dim; i++) + { Expression *e = (Expression *)keys->data[i]; + MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + e = (Expression *)values->data[i]; + m = (MATCH)e->implicitConvTo(tb->nextOf()); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + } + return result; + } + else + return Expression::implicitConvTo(t); +} + +MATCH AddrExp::implicitConvTo(Type *t) +{ +#if 0 + printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH result; + + result = type->implicitConvTo(t); + //printf("\tresult = %d\n", result); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + + t = t->toBasetype(); + + if (e1->op == TOKoverloadset && + (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) + { OverExp *eo = (OverExp *)e1; + FuncDeclaration *f = NULL; + for (int i = 0; i < eo->vars->a.dim; i++) + { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; + FuncDeclaration *f2 = s->isFuncDeclaration(); + assert(f2); + if (f2->overloadExactMatch(t->nextOf(), m)) + { if (f) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol::multiplyDefined(loc, f, f2); + else + f = f2; + result = MATCHexact; + } + } + } + + if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && + t->ty == Tpointer && t->nextOf()->ty == Tfunction && + e1->op == TOKvar) + { + /* I don't think this can ever happen - + * it should have been + * converted to a SymOffExp. + */ + assert(0); + VarExp *ve = (VarExp *)e1; + FuncDeclaration *f = ve->var->isFuncDeclaration(); + if (f && f->overloadExactMatch(t->nextOf(), m)) + result = MATCHexact; + } + } + //printf("\tresult = %d\n", result); + return result; +} + +MATCH SymOffExp::implicitConvTo(Type *t) +{ +#if 0 + printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH result; + + result = type->implicitConvTo(t); + //printf("\tresult = %d\n", result); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration *f; + + t = t->toBasetype(); + if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && + (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) + { + f = var->isFuncDeclaration(); + if (f) + { f = f->overloadExactMatch(t->nextOf(), m); + if (f) + { if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) || + (t->ty == Tpointer && !(f->needThis() || f->isNested()))) + { + result = MATCHexact; + } + } + } + } + } + //printf("\tresult = %d\n", result); + return result; +} + +MATCH DelegateExp::implicitConvTo(Type *t) +{ +#if 0 + printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH result; + + result = type->implicitConvTo(t); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration *f; + + t = t->toBasetype(); + if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction && + t->ty == Tdelegate && t->nextOf()->ty == Tfunction) + { + if (func && func->overloadExactMatch(t->nextOf(), m)) + result = MATCHexact; + } + } + return result; +} + +MATCH CondExp::implicitConvTo(Type *t) +{ + MATCH m1; + MATCH m2; + + m1 = e1->implicitConvTo(t); + m2 = e2->implicitConvTo(t); + + // Pick the worst match + return (m1 < m2) ? m1 : m2; +} + + +/* ==================== castTo ====================== */ + +/************************************** + * Do an explicit cast. + */ + +Expression *Expression::castTo(Scope *sc, Type *t) +{ + //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars()); +#if 0 + printf("Expression::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + if (type == t) + return this; + Expression *e = this; + Type *tb = t->toBasetype(); + Type *typeb = type->toBasetype(); + if (tb != typeb) + { + // Do (type *) cast of (type [dim]) + if (tb->ty == Tpointer && + typeb->ty == Tsarray + ) + { + //printf("Converting [dim] to *\n"); + + if (typeb->size(loc) == 0) + e = new NullExp(loc); + else + e = new AddrExp(loc, e); + } +#if 0 + else if (tb->ty == Tdelegate && type->ty != Tdelegate) + { + TypeDelegate *td = (TypeDelegate *)tb; + TypeFunction *tf = (TypeFunction *)td->nextOf(); + return toDelegate(sc, tf->nextOf()); + } +#endif + else + { + if (typeb->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)typeb; + if (!(tb->ty == Tstruct && ts->sym == ((TypeStruct *)tb)->sym) && + ts->sym->aliasthis) + { /* Forward the cast to our alias this member, rewrite to: + * cast(to)e1.aliasthis + */ + Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); + Expression *e = new CastExp(loc, e1, tb); + e = e->semantic(sc); + return e; + } + } + else if (typeb->ty == Tclass) + { TypeClass *ts = (TypeClass *)typeb; + if (tb->ty != Tclass && + ts->sym->aliasthis) + { /* Forward the cast to our alias this member, rewrite to: + * cast(to)e1.aliasthis + */ + Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); + Expression *e = new CastExp(loc, e1, tb); + e = e->semantic(sc); + return e; + } + } + e = new CastExp(loc, e, tb); + } + } + else + { + e = e->copy(); // because of COW for assignment to e->type + } + assert(e != this); + e->type = t; + //printf("Returning: %s\n", e->toChars()); + return e; +} + + +Expression *RealExp::castTo(Scope *sc, Type *t) +{ Expression *e = this; + if (type != t) + { + if ((type->isreal() && t->isreal()) || + (type->isimaginary() && t->isimaginary()) + ) + { e = copy(); + e->type = t; + } + else + e = Expression::castTo(sc, t); + } + return e; +} + + +Expression *ComplexExp::castTo(Scope *sc, Type *t) +{ Expression *e = this; + if (type != t) + { + if (type->iscomplex() && t->iscomplex()) + { e = copy(); + e->type = t; + } + else + e = Expression::castTo(sc, t); + } + return e; +} + + +Expression *NullExp::castTo(Scope *sc, Type *t) +{ NullExp *e; + Type *tb; + + //printf("NullExp::castTo(t = %p)\n", t); + if (type == t) + { + committed = 1; + return this; + } + e = (NullExp *)copy(); + e->committed = 1; + tb = t->toBasetype(); + e->type = type->toBasetype(); + if (tb != e->type) + { + // NULL implicitly converts to any pointer type or dynamic array + if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && + (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || + tb->ty == Tdelegate)) + { +#if 0 + if (tb->ty == Tdelegate) + { TypeDelegate *td = (TypeDelegate *)tb; + TypeFunction *tf = (TypeFunction *)td->nextOf(); + + if (!tf->varargs && + !(tf->arguments && tf->arguments->dim) + ) + { + return Expression::castTo(sc, t); + } + } +#endif + } + else + { + return e->Expression::castTo(sc, t); + } + } + e->type = t; + return e; +} + +Expression *StringExp::castTo(Scope *sc, Type *t) +{ + /* This follows copy-on-write; any changes to 'this' + * will result in a copy. + * The this->string member is considered immutable. + */ + StringExp *se; + Type *tb; + int copied = 0; + + //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); + + if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) + { + error("cannot convert string literal to void*"); + } + + se = this; + if (!committed) + { se = (StringExp *)copy(); + se->committed = 1; + copied = 1; + } + + if (type == t) + { + return se; + } + + tb = t->toBasetype(); + //printf("\ttype = %s\n", type->toChars()); + if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) + return Expression::castTo(sc, t); + + Type *typeb = type->toBasetype(); + if (typeb == tb) + { + if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + se->type = t; + return se; + } + + if (committed && tb->ty == Tsarray && typeb->ty == Tarray) + { + se = (StringExp *)copy(); + se->sz = tb->nextOf()->size(); + se->len = (len * sz) / se->sz; + se->committed = 1; + se->type = t; + return se; + } + + if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer) + { if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + goto Lcast; + } + if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer) + { if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + goto Lcast; + } + + if (typeb->nextOf()->size() == tb->nextOf()->size()) + { + if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + if (tb->ty == Tsarray) + goto L2; // handle possible change in static array dimension + se->type = t; + return se; + } + + if (committed) + goto Lcast; + +#define X(tf,tt) ((tf) * 256 + (tt)) + { + OutBuffer buffer; + size_t newlen = 0; + int tfty = typeb->nextOf()->toBasetype()->ty; + int ttty = tb->nextOf()->toBasetype()->ty; + switch (X(tfty, ttty)) + { + case X(Tchar, Tchar): + case X(Twchar,Twchar): + case X(Tdchar,Tdchar): + break; + + case X(Tchar, Twchar): + for (size_t u = 0; u < len;) + { unsigned c; + const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); + if (p) + error("%s", p); + else + buffer.writeUTF16(c); + } + newlen = buffer.offset / 2; + buffer.writeUTF16(0); + goto L1; + + case X(Tchar, Tdchar): + for (size_t u = 0; u < len;) + { unsigned c; + const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); + if (p) + error("%s", p); + buffer.write4(c); + newlen++; + } + buffer.write4(0); + goto L1; + + case X(Twchar,Tchar): + for (size_t u = 0; u < len;) + { unsigned c; + const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); + if (p) + error("%s", p); + else + buffer.writeUTF8(c); + } + newlen = buffer.offset; + buffer.writeUTF8(0); + goto L1; + + case X(Twchar,Tdchar): + for (size_t u = 0; u < len;) + { unsigned c; + const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); + if (p) + error("%s", p); + buffer.write4(c); + newlen++; + } + buffer.write4(0); + goto L1; + + case X(Tdchar,Tchar): + for (size_t u = 0; u < len; u++) + { + unsigned c = ((unsigned *)se->string)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF8(c); + newlen++; + } + newlen = buffer.offset; + buffer.writeUTF8(0); + goto L1; + + case X(Tdchar,Twchar): + for (size_t u = 0; u < len; u++) + { + unsigned c = ((unsigned *)se->string)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF16(c); + newlen++; + } + newlen = buffer.offset / 2; + buffer.writeUTF16(0); + goto L1; + + L1: + if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + se->string = buffer.extractData(); + se->len = newlen; + se->sz = tb->nextOf()->size(); + break; + + default: + assert(typeb->nextOf()->size() != tb->nextOf()->size()); + goto Lcast; + } + } +#undef X +L2: + assert(copied); + + // See if need to truncate or extend the literal + if (tb->ty == Tsarray) + { + int dim2 = ((TypeSArray *)tb)->dim->toInteger(); + + //printf("dim from = %d, to = %d\n", se->len, dim2); + + // Changing dimensions + if (dim2 != se->len) + { + // Copy when changing the string literal + unsigned newsz = se->sz; + void *s; + int d; + + d = (dim2 < se->len) ? dim2 : se->len; + s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); + memcpy(s, se->string, d * newsz); + // Extend with 0, add terminating 0 + memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); + se->string = s; + se->len = dim2; + } + } + se->type = t; + return se; + +Lcast: + Expression *e = new CastExp(loc, se, t); + e->type = t; // so semantic() won't be run on e + return e; +} + +Expression *AddrExp::castTo(Scope *sc, Type *t) +{ + Type *tb; + +#if 0 + printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + Expression *e = this; + + tb = t->toBasetype(); + type = type->toBasetype(); + if (tb != type) + { + // Look for pointers to functions where the functions are overloaded. + + if (e1->op == TOKoverloadset && + (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) + { OverExp *eo = (OverExp *)e1; + FuncDeclaration *f = NULL; + for (int i = 0; i < eo->vars->a.dim; i++) + { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; + FuncDeclaration *f2 = s->isFuncDeclaration(); + assert(f2); + if (f2->overloadExactMatch(t->nextOf(), m)) + { if (f) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol::multiplyDefined(loc, f, f2); + else + f = f2; + } + } + if (f) + { f->tookAddressOf++; + SymOffExp *se = new SymOffExp(loc, f, 0, 0); + se->semantic(sc); + // Let SymOffExp::castTo() do the heavy lifting + return se->castTo(sc, t); + } + } + + + if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && + tb->ty == Tpointer && tb->nextOf()->ty == Tfunction && + e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + FuncDeclaration *f = ve->var->isFuncDeclaration(); + if (f) + { + assert(0); // should be SymOffExp instead + f = f->overloadExactMatch(tb->nextOf(), m); + if (f) + { + e = new VarExp(loc, f); + e->type = f->type; + e = new AddrExp(loc, e); + e->type = t; + return e; + } + } + } + e = Expression::castTo(sc, t); + } + e->type = t; + return e; +} + + +Expression *TupleExp::castTo(Scope *sc, Type *t) +{ TupleExp *e = (TupleExp *)copy(); + e->exps = (Expressions *)exps->copy(); + for (size_t i = 0; i < e->exps->dim; i++) + { Expression *ex = (Expression *)e->exps->data[i]; + ex = ex->castTo(sc, t); + e->exps->data[i] = (void *)ex; + } + return e; +} + + +Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) +{ +#if 0 + printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + if (type == t) + return this; + ArrayLiteralExp *e = this; + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if ((tb->ty == Tarray || tb->ty == Tsarray) && + (typeb->ty == Tarray || typeb->ty == Tsarray) && + // Not trying to convert non-void[] to void[] + !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) + { + if (tb->ty == Tsarray) + { TypeSArray *tsa = (TypeSArray *)tb; + if (elements->dim != tsa->dim->toInteger()) + goto L1; + } + + e = (ArrayLiteralExp *)copy(); + e->elements = (Expressions *)elements->copy(); + for (int i = 0; i < elements->dim; i++) + { Expression *ex = (Expression *)elements->data[i]; + ex = ex->castTo(sc, tb->nextOf()); + e->elements->data[i] = (void *)ex; + } + e->type = t; + return e; + } + if (tb->ty == Tpointer && typeb->ty == Tsarray) + { + Type *tp = typeb->nextOf()->pointerTo(); + if (!tp->equals(e->type)) + { e = (ArrayLiteralExp *)copy(); + e->type = tp; + } + } +L1: + return e->Expression::castTo(sc, t); +} + +Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) +{ + if (type == t) + return this; + AssocArrayLiteralExp *e = this; + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if (tb->ty == Taarray && typeb->ty == Taarray && + tb->nextOf()->toBasetype()->ty != Tvoid) + { + e = (AssocArrayLiteralExp *)copy(); + e->keys = (Expressions *)keys->copy(); + e->values = (Expressions *)values->copy(); + assert(keys->dim == values->dim); + for (size_t i = 0; i < keys->dim; i++) + { Expression *ex = (Expression *)values->data[i]; + ex = ex->castTo(sc, tb->nextOf()); + e->values->data[i] = (void *)ex; + + ex = (Expression *)keys->data[i]; + ex = ex->castTo(sc, ((TypeAArray *)tb)->index); + e->keys->data[i] = (void *)ex; + } + e->type = t; + return e; + } +L1: + return e->Expression::castTo(sc, t); +} + +Expression *SymOffExp::castTo(Scope *sc, Type *t) +{ +#if 0 + printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + if (type == t && hasOverloads == 0) + return this; + Expression *e; + Type *tb = t->toBasetype(); + Type *typeb = type->toBasetype(); + if (tb != typeb) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration *f; + + if (hasOverloads && + typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction && + (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction) + { + f = var->isFuncDeclaration(); + if (f) + { + f = f->overloadExactMatch(tb->nextOf(), m); + if (f) + { + if (tb->ty == Tdelegate && f->needThis() && hasThis(sc)) + { + e = new DelegateExp(loc, new ThisExp(loc), f); + e = e->semantic(sc); + } + else if (tb->ty == Tdelegate && f->isNested()) + { + e = new DelegateExp(loc, new IntegerExp(0), f); + e = e->semantic(sc); + } + else + { + e = new SymOffExp(loc, f, 0); + e->type = t; + } + f->tookAddressOf++; + return e; + } + } + } + e = Expression::castTo(sc, t); + } + else + { e = copy(); + e->type = t; + ((SymOffExp *)e)->hasOverloads = 0; + } + return e; +} + +Expression *DelegateExp::castTo(Scope *sc, Type *t) +{ +#if 0 + printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + static char msg[] = "cannot form delegate due to covariant return type"; + + Expression *e = this; + Type *tb = t->toBasetype(); + Type *typeb = type->toBasetype(); + if (tb != typeb) + { + // Look for delegates to functions where the functions are overloaded. + FuncDeclaration *f; + + if (typeb->ty == Tdelegate && typeb->nextOf()->ty == Tfunction && + tb->ty == Tdelegate && tb->nextOf()->ty == Tfunction) + { + if (func) + { + f = func->overloadExactMatch(tb->nextOf(), m); + if (f) + { int offset; + if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset) + error("%s", msg); + f->tookAddressOf++; + e = new DelegateExp(loc, e1, f); + e->type = t; + return e; + } + if (func->tintro) + error("%s", msg); + } + } + e = Expression::castTo(sc, t); + } + else + { int offset; + + func->tookAddressOf++; + if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset) + error("%s", msg); + e = copy(); + e->type = t; + } + return e; +} + +Expression *CondExp::castTo(Scope *sc, Type *t) +{ + Expression *e = this; + + if (type != t) + { + if (1 || e1->op == TOKstring || e2->op == TOKstring) + { e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t)); + e->type = t; + } + else + e = Expression::castTo(sc, t); + } + return e; +} + +/* ==================== ====================== */ + +/**************************************** + * Scale addition/subtraction to/from pointer. + */ + +Expression *BinExp::scaleFactor(Scope *sc) +{ d_uns64 stride; + Type *t1b = e1->type->toBasetype(); + Type *t2b = e2->type->toBasetype(); + + if (t1b->ty == Tpointer && t2b->isintegral()) + { // Need to adjust operator by the stride + // Replace (ptr + int) with (ptr + (int * stride)) + Type *t = Type::tptrdiff_t; + + stride = t1b->nextOf()->size(loc); + if (!t->equals(t2b)) + e2 = e2->castTo(sc, t); + e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t)); + e2->type = t; + type = e1->type; + } + else if (t2b->ty == Tpointer && t1b->isintegral()) + { // Need to adjust operator by the stride + // Replace (int + ptr) with (ptr + (int * stride)) + Type *t = Type::tptrdiff_t; + Expression *e; + + stride = t2b->nextOf()->size(loc); + if (!t->equals(t1b)) + e = e1->castTo(sc, t); + else + e = e1; + e = new MulExp(loc, e, new IntegerExp(0, stride, t)); + e->type = t; + type = e2->type; + e1 = e2; + e2 = e; + } + return this; +} + +/************************************** + * Combine types. + * Output: + * *pt merged type, if *pt is not NULL + * *pe1 rewritten e1 + * *pe2 rewritten e2 + * Returns: + * !=0 success + * 0 failed + */ + +int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2) +{ + //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars()); + //dump(0); + + Expression *e1 = (*pe1)->integralPromotions(sc); + Expression *e2 = (*pe2)->integralPromotions(sc); + + Type *t1 = e1->type; + Type *t2 = e2->type; + assert(t1); + Type *t = t1; + + //if (t1) printf("\tt1 = %s\n", t1->toChars()); + //if (t2) printf("\tt2 = %s\n", t2->toChars()); +#ifdef DEBUG + if (!t2) printf("\te2 = '%s'\n", e2->toChars()); +#endif + assert(t2); + + Type *t1b = t1->toBasetype(); + Type *t2b = t2->toBasetype(); + + TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty]; + if (ty != Terror) + { TY ty1; + TY ty2; + + ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty]; + ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty]; + + if (t1b->ty == ty1) // if no promotions + { + if (t1 == t2) + { + t = t1; + goto Lret; + } + + if (t1b == t2b) + { + t = t1b; + goto Lret; + } + } + + t = Type::basic[ty]; + + t1 = Type::basic[ty1]; + t2 = Type::basic[ty2]; + e1 = e1->castTo(sc, t1); + e2 = e2->castTo(sc, t2); + //printf("after typeCombine():\n"); + //dump(0); + //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); + goto Lret; + } + + t1 = t1b; + t2 = t2b; + +Lagain: + if (t1 == t2) + { + } + else if (t1->ty == Tpointer && t2->ty == Tpointer) + { + // Bring pointers to compatible type + Type *t1n = t1->nextOf(); + Type *t2n = t2->nextOf(); + + if (t1n == t2n) + ; + else if (t1n->ty == Tvoid) // pointers to void are always compatible + t = t2; + else if (t2n->ty == Tvoid) + ; + else if (t1n->mod != t2n->mod) + { + t1 = t1n->mutableOf()->constOf()->pointerTo(); + t2 = t2n->mutableOf()->constOf()->pointerTo(); + t = t1; + goto Lagain; + } + else if (t1n->ty == Tclass && t2n->ty == Tclass) + { ClassDeclaration *cd1 = t1n->isClassHandle(); + ClassDeclaration *cd2 = t2n->isClassHandle(); + int offset; + + if (cd1->isBaseOf(cd2, &offset)) + { + if (offset) + e2 = e2->castTo(sc, t); + } + else if (cd2->isBaseOf(cd1, &offset)) + { + t = t2; + if (offset) + e1 = e1->castTo(sc, t); + } + else + goto Lincompatible; + } + else + goto Lincompatible; + } + else if ((t1->ty == Tsarray || t1->ty == Tarray) && + e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid) + { /* (T[n] op void*) + * (T[] op void*) + */ + goto Lx1; + } + else if ((t2->ty == Tsarray || t2->ty == Tarray) && + e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid) + { /* (void* op T[n]) + * (void* op T[]) + */ + goto Lx2; + } + else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) + { + goto Lt2; + } + else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) + { + goto Lt1; + } + /* If one is mutable and the other invariant, then retry + * with both of them as const + */ + else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) && + (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) && + t1->nextOf()->mod != t2->nextOf()->mod + ) + { + if (t1->ty == Tpointer) + t1 = t1->nextOf()->mutableOf()->constOf()->pointerTo(); + else + t1 = t1->nextOf()->mutableOf()->constOf()->arrayOf(); + + if (t2->ty == Tpointer) + t2 = t2->nextOf()->mutableOf()->constOf()->pointerTo(); + else + t2 = t2->nextOf()->mutableOf()->constOf()->arrayOf(); + t = t1; + goto Lagain; + } + else if (t1->ty == Tclass || t2->ty == Tclass) + { + while (1) + { + int i1 = e2->implicitConvTo(t1); + int i2 = e1->implicitConvTo(t2); + + if (i1 && i2) + { + // We have the case of class vs. void*, so pick class + if (t1->ty == Tpointer) + i1 = 0; + else if (t2->ty == Tpointer) + i2 = 0; + } + + if (i2) + { + goto Lt2; + } + else if (i1) + { + goto Lt1; + } + else if (t1->ty == Tclass && t2->ty == Tclass) + { TypeClass *tc1 = (TypeClass *)t1; + TypeClass *tc2 = (TypeClass *)t2; + + /* Pick 'tightest' type + */ + ClassDeclaration *cd1 = tc1->sym->baseClass; + ClassDeclaration *cd2 = tc2->sym->baseClass; + + if (cd1 && cd2) + { t1 = cd1->type; + t2 = cd2->type; + } + else if (cd1) + t1 = cd1->type; + else if (cd2) + t2 = cd2->type; + else + goto Lincompatible; + } + else + goto Lincompatible; + } + } + else if (t1->ty == Tstruct && t2->ty == Tstruct) + { + if (((TypeStruct *)t1)->sym != ((TypeStruct *)t2)->sym) + goto Lincompatible; + } + else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2)) + { + goto Lt2; + } + else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1)) + { + goto Lt1; + } + else if (t1->ty == Tsarray && t2->ty == Tsarray && + e2->implicitConvTo(t1->nextOf()->arrayOf())) + { + Lx1: + t = t1->nextOf()->arrayOf(); + e1 = e1->castTo(sc, t); + e2 = e2->castTo(sc, t); + } + else if (t1->ty == Tsarray && t2->ty == Tsarray && + e1->implicitConvTo(t2->nextOf()->arrayOf())) + { + Lx2: + t = t2->nextOf()->arrayOf(); + e1 = e1->castTo(sc, t); + e2 = e2->castTo(sc, t); + } + else if (t1->isintegral() && t2->isintegral()) + { + assert(0); + } + else if (e1->op == TOKslice && t1->ty == Tarray && + e2->implicitConvTo(t1->nextOf())) + { // T[] op T + e2 = e2->castTo(sc, t1->nextOf()); + t = t1->nextOf()->arrayOf(); + } + else if (e2->op == TOKslice && t2->ty == Tarray && + e1->implicitConvTo(t2->nextOf())) + { // T op T[] + e1 = e1->castTo(sc, t2->nextOf()); + t = t2->nextOf()->arrayOf(); + + //printf("test %s\n", e->toChars()); + e1 = e1->optimize(WANTvalue); + if (e && e->isCommutative() && e1->isConst()) + { /* Swap operands to minimize number of functions generated + */ + //printf("swap %s\n", e->toChars()); + Expression *tmp = e1; + e1 = e2; + e2 = tmp; + } + } + else + { + Lincompatible: + return 0; + } +Lret: + if (!*pt) + *pt = t; + *pe1 = e1; + *pe2 = e2; +#if 0 + printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars()); + if (e1->type) printf("\tt1 = %s\n", e1->type->toChars()); + if (e2->type) printf("\tt2 = %s\n", e2->type->toChars()); + printf("\ttype = %s\n", t->toChars()); +#endif + //dump(0); + return 1; + + +Lt1: + e2 = e2->castTo(sc, t1); + t = t1; + goto Lret; + +Lt2: + e1 = e1->castTo(sc, t2); + t = t2; + goto Lret; +} + +/************************************ + * Bring leaves to common type. + */ + +Expression *BinExp::typeCombine(Scope *sc) +{ + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + + if (op == TOKmin || op == TOKadd) + { + if (t1 == t2 && (t1->ty == Tstruct || t1->ty == Tclass)) + goto Lerror; + } + + if (!typeMerge(sc, this, &type, &e1, &e2)) + goto Lerror; + return this; + +Lerror: + incompatibleTypes(); + type = Type::terror; + e1 = new ErrorExp(); + e2 = new ErrorExp(); + return this; +} + +/*********************************** + * Do integral promotions (convertchk). + * Don't convert to + */ + +Expression *Expression::integralPromotions(Scope *sc) +{ + Expression *e = this; + + //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars()); + switch (type->toBasetype()->ty) + { + case Tvoid: + error("void has no value"); + break; + + case Tint8: + case Tuns8: + case Tint16: + case Tuns16: + case Tbit: + case Tbool: + case Tchar: + case Twchar: + e = e->castTo(sc, Type::tint32); + break; + + case Tdchar: + e = e->castTo(sc, Type::tuns32); + break; + } + return e; +} + +/*********************************** + * See if both types are arrays that can be compared + * for equality. Return !=0 if so. + * If they are arrays, but incompatible, issue error. + * This is to enable comparing things like an immutable + * array with a mutable one. + */ + +int arrayTypeCompatible(Loc loc, Type *t1, Type *t2) +{ + t1 = t1->toBasetype(); + t2 = t2->toBasetype(); + + if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && + (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) + { + if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && + t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && + (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) + { + error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars()); + } + return 1; + } + return 0; +} diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/class.c --- a/dmd2/class.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/class.c Sat May 30 17:23:32 2009 +0100 @@ -1,1420 +1,1434 @@ - -// 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. - -#include -#include -#include - -#include "root.h" -#include "mem.h" - -#include "enum.h" -#include "init.h" -#include "attrib.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "mtype.h" -#include "scope.h" -#include "module.h" -#include "expression.h" -#include "statement.h" - -/********************************* ClassDeclaration ****************************/ - -ClassDeclaration *ClassDeclaration::classinfo; -ClassDeclaration *ClassDeclaration::object; - -ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) - : AggregateDeclaration(loc, id) -{ - static char msg[] = "only object.d can define this reserved class name"; - - if (baseclasses) - this->baseclasses = *baseclasses; - baseClass = NULL; - - interfaces_dim = 0; - interfaces = NULL; - - vtblInterfaces = NULL; - - //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim); - - // For forward references - type = new TypeClass(this); - handle = type; - - staticCtor = NULL; - staticDtor = NULL; - - vtblsym = NULL; - vclassinfo = NULL; - - if (id) - { // Look for special class names - - if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof) - error("illegal class name"); - - // BUG: What if this is the wrong TypeInfo, i.e. it is nested? - if (id->toChars()[0] == 'T') - { - if (id == Id::TypeInfo) - { if (Type::typeinfo) - Type::typeinfo->error("%s", msg); - Type::typeinfo = this; - } - - if (id == Id::TypeInfo_Class) - { if (Type::typeinfoclass) - Type::typeinfoclass->error("%s", msg); - Type::typeinfoclass = this; - } - - if (id == Id::TypeInfo_Interface) - { if (Type::typeinfointerface) - Type::typeinfointerface->error("%s", msg); - Type::typeinfointerface = this; - } - - if (id == Id::TypeInfo_Struct) - { if (Type::typeinfostruct) - Type::typeinfostruct->error("%s", msg); - Type::typeinfostruct = this; - } - - if (id == Id::TypeInfo_Typedef) - { if (Type::typeinfotypedef) - Type::typeinfotypedef->error("%s", msg); - Type::typeinfotypedef = this; - } - - if (id == Id::TypeInfo_Pointer) - { if (Type::typeinfopointer) - Type::typeinfopointer->error("%s", msg); - Type::typeinfopointer = this; - } - - if (id == Id::TypeInfo_Array) - { if (Type::typeinfoarray) - Type::typeinfoarray->error("%s", msg); - Type::typeinfoarray = this; - } - - if (id == Id::TypeInfo_StaticArray) - { //if (Type::typeinfostaticarray) - //Type::typeinfostaticarray->error("%s", msg); - Type::typeinfostaticarray = this; - } - - if (id == Id::TypeInfo_AssociativeArray) - { if (Type::typeinfoassociativearray) - Type::typeinfoassociativearray->error("%s", msg); - Type::typeinfoassociativearray = this; - } - - if (id == Id::TypeInfo_Enum) - { if (Type::typeinfoenum) - Type::typeinfoenum->error("%s", msg); - Type::typeinfoenum = this; - } - - if (id == Id::TypeInfo_Function) - { if (Type::typeinfofunction) - Type::typeinfofunction->error("%s", msg); - Type::typeinfofunction = this; - } - - if (id == Id::TypeInfo_Delegate) - { if (Type::typeinfodelegate) - Type::typeinfodelegate->error("%s", msg); - Type::typeinfodelegate = this; - } - - if (id == Id::TypeInfo_Tuple) - { if (Type::typeinfotypelist) - Type::typeinfotypelist->error("%s", msg); - Type::typeinfotypelist = this; - } - -#if DMDV2 - if (id == Id::TypeInfo_Const) - { if (Type::typeinfoconst) - Type::typeinfoconst->error("%s", msg); - Type::typeinfoconst = this; - } - - if (id == Id::TypeInfo_Invariant) - { if (Type::typeinfoinvariant) - Type::typeinfoinvariant->error("%s", msg); - Type::typeinfoinvariant = this; - } -#endif - } - - if (id == Id::Object) - { if (object) - object->error("%s", msg); - object = this; - } - - if (id == Id::ClassInfo) - { if (classinfo) - classinfo->error("%s", msg); - classinfo = this; - } - - if (id == Id::ModuleInfo) - { if (Module::moduleinfo) - Module::moduleinfo->error("%s", msg); - Module::moduleinfo = this; - } - } - - com = 0; - isauto = 0; - isabstract = 0; - isnested = 0; - vthis = NULL; - inuse = 0; -} - -Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) -{ - ClassDeclaration *cd; - - //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - cd = (ClassDeclaration *)s; - else - cd = new ClassDeclaration(loc, ident, NULL); - - cd->storage_class |= storage_class; - - cd->baseclasses.setDim(this->baseclasses.dim); - for (int i = 0; i < cd->baseclasses.dim; i++) - { - BaseClass *b = (BaseClass *)this->baseclasses.data[i]; - BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); - cd->baseclasses.data[i] = b2; - } - - ScopeDsymbol::syntaxCopy(cd); - return cd; -} - -void ClassDeclaration::semantic(Scope *sc) -{ int i; - unsigned offset; - - //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); - //printf("sc->stc = %x\n", sc->stc); - - //{ static int n; if (++n == 20) *(char*)0=0; } - - if (!ident) // if anonymous class - { const char *id = "__anonclass"; - - ident = Identifier::generateId(id); - } - - if (!scope) - { - if (!parent && sc->parent && !sc->parent->isModule()) - parent = sc->parent; - - type = type->semantic(loc, sc); - handle = handle->semantic(loc, sc); - } - if (!members) // if forward reference - { //printf("\tclass '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) - { if (!scope) - { //printf("\tsemantic for '%s' is already completed\n", toChars()); - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } -#ifdef IN_GCC - methods.setDim(0); -#endif - - if (sc->stc & STCdeprecated) - { - isdeprecated = 1; - } - - if (sc->linkage == LINKcpp) - error("cannot create C++ classes"); - - // Expand any tuples in baseclasses[] - for (i = 0; i < baseclasses.dim; ) - { BaseClass *b = (BaseClass *)baseclasses.data[i]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); - - if (tb->ty == Ttuple) - { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; - baseclasses.remove(i); - size_t dim = Argument::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *arg = Argument::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses.insert(i + j, b); - } - } - else - i++; - } - - // See if there's a base class as first in baseclasses[] - if (baseclasses.dim) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (BaseClass *)baseclasses.data[0]; - //b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty != Tclass) - { error("base type must be class or interface, not %s", b->type->toChars()); - baseclasses.remove(0); - } - else - { - tc = (TypeClass *)(tb); - - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; - - tc->checkDeprecated(loc, sc); - } - } - - if (tc->sym->isInterfaceDeclaration()) - ; - else - { - for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) - { - if (cdb == this) - { - error("circular inheritance"); - baseclasses.remove(0); - goto L7; - } - } - if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) - { - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base class, try again later - //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - return; - } - else - { baseClass = tc->sym; - b->base = baseClass; - } - L7: ; - } - } - } - - // Treat the remaining entries in baseclasses as interfaces - // Check for errors, handle forward references - for (i = (baseClass ? 1 : 0); i < baseclasses.dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (BaseClass *)baseclasses.data[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); - baseclasses.remove(i); - continue; - } - else - { - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; - - tc->checkDeprecated(loc, sc); - } - } - - // Check for duplicate interfaces - for (size_t j = (baseClass ? 1 : 0); j < i; j++) - { - BaseClass *b2 = (BaseClass *)baseclasses.data[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - b->base = tc->sym; - if (!b->base->symtab || b->base->scope) - { - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base, try again later - //printf("\ttry later, forward reference of base %s\n", baseClass->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - return; - } - } - i++; - } - - - // If no base class, and this is not an Object, use Object as base class - if (!baseClass && ident != Id::Object) - { - // BUG: what if Object is redefined in an inner scope? - Type *tbase = new TypeIdentifier(0, Id::Object); - BaseClass *b; - TypeClass *tc; - Type *bt; - - if (!object) - { - error("missing or corrupt object.d"); - fatal(); - } - bt = tbase->semantic(loc, sc)->toBasetype(); - b = new BaseClass(bt, PROTpublic); - baseclasses.shift(b); - assert(b->type->ty == Tclass); - tc = (TypeClass *)(b->type); - baseClass = tc->sym; - assert(!baseClass->isInterfaceDeclaration()); - b->base = baseClass; - } - - interfaces_dim = baseclasses.dim; - interfaces = (BaseClass **)baseclasses.data; - - - if (baseClass) - { - if (baseClass->storage_class & STCfinal) - error("cannot inherit from final class %s", baseClass->toChars()); - - interfaces_dim--; - interfaces++; - - // Copy vtbl[] from base class - vtbl.setDim(baseClass->vtbl.dim); - memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim); - - // Inherit properties from base class - com = baseClass->isCOMclass(); - isauto = baseClass->isauto; - vthis = baseClass->vthis; - storage_class |= baseClass->storage_class & (STCconst | STCinvariant); - } - else - { - // No base class, so this is the root of the class hierarchy - vtbl.setDim(0); - vtbl.push(this); // leave room for classinfo as first member - } - - protection = sc->protection; - storage_class |= sc->stc; - - if (sizeok == 0) - { - interfaceSemantic(sc); - - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->addMember(sc, this, 1); - } - - /* If this is a nested class, add the hidden 'this' - * member which is a pointer to the enclosing scope. - */ - if (vthis) // if inheriting from nested class - { // Use the base class's 'this' member - isnested = 1; - if (storage_class & STCstatic) - error("static class cannot inherit from nested class %s", baseClass->toChars()); - if (toParent2() != baseClass->toParent2()) - { - if (toParent2()) - { - error("is nested within %s, but super class %s is nested within %s", - toParent2()->toChars(), - baseClass->toChars(), - baseClass->toParent2()->toChars()); - } - else - { - error("is not nested, but super class %s is nested within %s", - baseClass->toChars(), - baseClass->toParent2()->toChars()); - } - isnested = 0; - } - } - else if (!(storage_class & STCstatic)) - { Dsymbol *s = toParent2(); - if (s) - { - ClassDeclaration *cd = s->isClassDeclaration(); - FuncDeclaration *fd = s->isFuncDeclaration(); - - - if (cd || fd) - { isnested = 1; - Type *t; - if (cd) - t = cd->type; - else if (fd) - { AggregateDeclaration *ad = fd->isMember2(); - if (ad) - t = ad->handle; - else - { - t = new TypePointer(Type::tvoid); - t = t->semantic(0, sc); - } - } - else - assert(0); - assert(!vthis); - vthis = new ThisDeclaration(t); - members->push(vthis); - } - } - } - } - - if (storage_class & (STCauto | STCscope)) - isauto = 1; - if (storage_class & STCabstract) - isabstract = 1; - if (storage_class & STCinvariant) - type = type->invariantOf(); - else if (storage_class & STCconst) - type = type->constOf(); - - sc = sc->push(this); - sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | - STCabstract | STCdeprecated | STCconst | STCinvariant | STCtls); - sc->stc |= storage_class & (STCconst | STCinvariant); - sc->parent = this; - sc->inunion = 0; - - if (isCOMclass()) - sc->linkage = LINKwindows; - sc->protection = PROTpublic; - sc->explicitProtection = 0; - sc->structalign = 8; - structalign = sc->structalign; - if (baseClass) - { sc->offset = baseClass->structsize; - alignsize = baseClass->alignsize; -// if (isnested) -// sc->offset += PTRSIZE; // room for uplevel context pointer - } - else - { sc->offset = PTRSIZE * 2; // allow room for __vptr and __monitor - alignsize = PTRSIZE; - } - structsize = sc->offset; - Scope scsave = *sc; - int members_dim = members->dim; - sizeok = 0; - for (i = 0; i < members_dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc); - } - - if (sizeok == 2) - { // semantic() failed because of forward references. - // Unwind what we did, and defer it for later - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - sc = sc->pop(); - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - - //printf("\tsemantic('%s') failed due to forward references\n", toChars()); - return; - } - - //printf("\tsemantic('%s') successful\n", toChars()); - - structsize = sc->offset; - //members->print(); - - /* Look for special member functions. - * They must be in this class, not in a base class. - */ - ctor = (CtorDeclaration *)search(0, Id::ctor, 0); - if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) - ctor = NULL; - -// dtor = (DtorDeclaration *)search(Id::dtor, 0); -// if (dtor && dtor->toParent() != this) -// dtor = NULL; - -// inv = (InvariantDeclaration *)search(Id::classInvariant, 0); -// if (inv && inv->toParent() != this) -// inv = NULL; - - // Can be in base class - aggNew = (NewDeclaration *)search(0, Id::classNew, 0); - aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); - - // If this class has no constructor, but base class does, create - // a constructor: - // this() { } - if (!ctor && baseClass && baseClass->ctor) - { - //printf("Creating default this(){} for class %s\n", toChars()); - ctor = new CtorDeclaration(loc, 0, NULL, 0); - ctor->fbody = new CompoundStatement(0, new Statements()); - members->push(ctor); - ctor->addMember(sc, this, 1); - *sc = scsave; // why? What about sc->nofree? - sc->offset = structsize; - ctor->semantic(sc); - defaultCtor = ctor; - } - -#if 0 - if (baseClass) - { if (!aggDelete) - aggDelete = baseClass->aggDelete; - if (!aggNew) - aggNew = baseClass->aggNew; - } -#endif - - // Allocate instance of each new interface - for (i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; - unsigned thissize = PTRSIZE; - - alignmember(structalign, thissize, &sc->offset); - assert(b->offset == 0); - b->offset = sc->offset; - - // Take care of single inheritance offsets - while (b->baseInterfaces_dim) - { - b = &b->baseInterfaces[0]; - b->offset = sc->offset; - } - - sc->offset += thissize; - if (alignsize < thissize) - alignsize = thissize; - } - structsize = sc->offset; - sizeok = 1; - Module::dprogress++; - - dtor = buildDtor(sc); - - sc->pop(); - -#if 0 // Do not call until toObjfile() because of forward references - // Fill in base class vtbl[]s - for (i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; - - //b->fillVtbl(this, &b->vtbl, 1); - } -#endif - //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - -void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (!isAnonymous()) - { - buf->printf("%s ", kind()); - buf->writestring(toChars()); - if (baseclasses.dim) - buf->writestring(" : "); - } - for (int i = 0; i < baseclasses.dim; i++) - { - BaseClass *b = (BaseClass *)baseclasses.data[i]; - - if (i) - buf->writeByte(','); - //buf->writestring(b->base->ident->toChars()); - b->type->toCBuffer(buf, NULL, hgs); - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writestring("}"); - buf->writenl(); -} - -#if 0 -void ClassDeclaration::defineRef(Dsymbol *s) -{ - ClassDeclaration *cd; - - AggregateDeclaration::defineRef(s); - cd = s->isClassDeclaration(); - baseType = cd->baseType; - cd->baseType = NULL; -} -#endif - -/********************************************* - * Determine if 'this' is a base class of cd. - * This is used to detect circular inheritance only. - */ - -int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) -{ - if (!cd) - return 0; - //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - for (int i = 0; i < cd->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; - - if (b->base == this || isBaseOf2(b->base)) - return 1; - } - return 0; -} - -/******************************************* - * Determine if 'this' is a base class of cd. - */ - -int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - if (poffset) - *poffset = 0; - while (cd) - { - if (this == cd->baseClass) - return 1; - - /* cd->baseClass might not be set if cd is forward referenced. - */ - if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) - { - cd->error("base class is forward referenced by %s", toChars()); - } - - cd = cd->baseClass; - } - return 0; -} - -Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - Dsymbol *s; - - //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); - if (scope) - semantic(scope); - - if (!members || !symtab || scope) - { error("is forward referenced when looking for '%s'", ident->toChars()); - //*(char*)0=0; - return NULL; - } - - s = ScopeDsymbol::search(loc, ident, flags); - if (!s) - { - // Search bases classes in depth-first, left to right order - - int i; - - for (i = 0; i < baseclasses.dim; i++) - { - BaseClass *b = (BaseClass *)baseclasses.data[i]; - - if (b->base) - { - if (!b->base->symtab) - error("base %s is forward referenced", b->base->ident->toChars()); - else - { - s = b->base->search(loc, ident, flags); - if (s == this) // happens if s is nested in this and derives from this - s = NULL; - else if (s) - break; - } - } - } - } - return s; -} - -/********************************************************** - * fd is in the vtbl[] for this class. - * Return 1 if function is hidden (not findable through search). - */ - -#if DMDV2 -int isf(void *param, FuncDeclaration *fd) -{ - //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); - return param == fd; -} - -int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) -{ - //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); - Dsymbol *s = search(0, fd->ident, 4|2); - if (!s) - { //printf("not found\n"); - /* Because, due to a hack, if there are multiple definitions - * of fd->ident, NULL is returned. - */ - return 0; - } - s = s->toAlias(); - OverloadSet *os = s->isOverloadSet(); - if (os) - { - for (int i = 0; i < os->a.dim; i++) - { Dsymbol *s = (Dsymbol *)os->a.data[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - if (f2 && overloadApply(f2, &isf, fd)) - return 0; - } - return 1; - } - else - { - FuncDeclaration *fdstart = s->isFuncDeclaration(); - //printf("%s fdstart = %p\n", s->kind(), fdstart); - return !overloadApply(fdstart, &isf, fd); - } -} -#endif - -/**************** - * Find virtual function matching identifier and type. - * Used to build virtual function tables for interface implementations. - */ - -FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) -{ - //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); - - ClassDeclaration *cd = this; - Array *vtbl = &cd->vtbl; - while (1) - { - for (size_t i = 0; i < vtbl->dim; i++) - { - FuncDeclaration *fd = (FuncDeclaration *)vtbl->data[i]; - - //printf("\t[%d] = %s\n", i, fd->toChars()); - if (ident == fd->ident && - //tf->equals(fd->type) - fd->type->covariant(tf) == 1 - ) - { //printf("\t\tfound\n"); - return fd; - } - //else printf("\t\t%d\n", fd->type->covariant(tf)); - } - if (!cd) - break; - vtbl = &cd->vtblFinal; - cd = cd->baseClass; - } - - return NULL; -} - -void ClassDeclaration::interfaceSemantic(Scope *sc) -{ - InterfaceDeclaration *id = isInterfaceDeclaration(); - - vtblInterfaces = new BaseClasses(); - vtblInterfaces->reserve(interfaces_dim); - - for (size_t i = 0; i < interfaces_dim; i++) - { - BaseClass *b = interfaces[i]; - - // If this is an interface, and it derives from a COM interface, - // then this is a COM interface too. - if (b->base->isCOMinterface()) - com = 1; - - if (b->base->isCPPinterface() && id) - id->cpp = 1; - - vtblInterfaces->push(b); - b->copyBaseInterfaces(vtblInterfaces); - } -} - -/**************************************** - */ - -int ClassDeclaration::isCOMclass() -{ - return com; -} - -int ClassDeclaration::isCOMinterface() -{ - return 0; -} - -int ClassDeclaration::isCPPinterface() -{ - return 0; -} - - -/**************************************** - */ - -int ClassDeclaration::isAbstract() -{ - if (isabstract) - return TRUE; - for (int i = 1; i < vtbl.dim; i++) - { - FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration(); - - //printf("\tvtbl[%d] = %p\n", i, fd); - if (!fd || fd->isAbstract()) - { - isabstract |= 1; - return TRUE; - } - } - return FALSE; -} - - -/**************************************** - * Returns !=0 if there's an extra member which is the 'this' - * pointer to the enclosing context (enclosing class or function) - */ - -int ClassDeclaration::isNested() -{ - return isnested; -} - -/**************************************** - * Determine if slot 0 of the vtbl[] is reserved for something else. - * For class objects, yes, this is where the classinfo ptr goes. - * For COM interfaces, no. - * For non-COM interfaces, yes, this is where the Interface ptr goes. - */ - -int ClassDeclaration::vtblOffset() -{ - return 1; -} - -/**************************************** - */ - -const char *ClassDeclaration::kind() -{ - return "class"; -} - -/**************************************** - */ - -void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - aclasses->push(this); -} - -/********************************* InterfaceDeclaration ****************************/ - -InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) - : ClassDeclaration(loc, id, baseclasses) -{ - com = 0; - cpp = 0; - if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces - { com = 1; - cpp = 1; // IUnknown is also a C++ interface - } -} - -Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) -{ - InterfaceDeclaration *id; - - if (s) - id = (InterfaceDeclaration *)s; - else - id = new InterfaceDeclaration(loc, ident, NULL); - - ClassDeclaration::syntaxCopy(id); - return id; -} - -void InterfaceDeclaration::semantic(Scope *sc) -{ int i; - - //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); - if (inuse) - return; - if (!scope) - { type = type->semantic(loc, sc); - handle = handle->semantic(loc, sc); - } - if (!members) // if forward reference - { //printf("\tinterface '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) // if already done - { if (!scope) - return; - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - if (sc->stc & STCdeprecated) - { - isdeprecated = 1; - } - - // Expand any tuples in baseclasses[] - for (i = 0; i < baseclasses.dim; ) - { BaseClass *b = (BaseClass *)baseclasses.data[0]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); - - if (tb->ty == Ttuple) - { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; - baseclasses.remove(i); - size_t dim = Argument::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *arg = Argument::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses.insert(i + j, b); - } - } - else - i++; - } - - if (!baseclasses.dim && sc->linkage == LINKcpp) - cpp = 1; - - // Check for errors, handle forward references - for (i = 0; i < baseclasses.dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (BaseClass *)baseclasses.data[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); - baseclasses.remove(i); - continue; - } - else - { - // Check for duplicate interfaces - for (size_t j = 0; j < i; j++) - { - BaseClass *b2 = (BaseClass *)baseclasses.data[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - b->base = tc->sym; - if (b->base == this || isBaseOf2(b->base)) - { - error("circular inheritance of interface"); - baseclasses.remove(i); - continue; - } - if (!b->base->symtab || b->base->scope || b->base->inuse) - { - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base, try again later - //printf("\ttry later, forward reference of base %s\n", b->base->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - return; - } - } -#if 0 - // Inherit const/invariant from base class - storage_class |= b->base->storage_class & (STCconst | STCinvariant); -#endif - i++; - } - - interfaces_dim = baseclasses.dim; - interfaces = (BaseClass **)baseclasses.data; - - interfaceSemantic(sc); - - if (vtblOffset()) - vtbl.push(this); // leave room at vtbl[0] for classinfo - - // Cat together the vtbl[]'s from base interfaces - for (i = 0; i < interfaces_dim; i++) - { BaseClass *b = interfaces[i]; - - // Skip if b has already appeared - for (int k = 0; k < i; k++) - { - if (b == interfaces[i]) - goto Lcontinue; - } - - // Copy vtbl[] from base class - if (b->base->vtblOffset()) - { int d = b->base->vtbl.dim; - if (d > 1) - { - vtbl.reserve(d - 1); - for (int j = 1; j < d; j++) - vtbl.push(b->base->vtbl.data[j]); - } - } - else - { - vtbl.append(&b->base->vtbl); - } - - Lcontinue: - ; - } - - protection = sc->protection; - storage_class |= sc->stc & (STCconst | STCinvariant); - - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->addMember(sc, this, 1); - } - - sc = sc->push(this); - sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | - STCabstract | STCdeprecated | STCconst | STCinvariant | STCtls); - sc->stc |= storage_class & (STCconst | STCinvariant); - sc->parent = this; - if (isCOMinterface()) - sc->linkage = LINKwindows; - else if (isCPPinterface()) - sc->linkage = LINKcpp; - sc->structalign = 8; - structalign = sc->structalign; - sc->offset = PTRSIZE * 2; - inuse++; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc); - } - inuse--; - //members->print(); - sc->pop(); - //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - - -/******************************************* - * Determine if 'this' is a base class of cd. - * (Actually, if it is an interface supported by cd) - * Output: - * *poffset offset to start of class - * OFFSET_RUNTIME must determine offset at runtime - * Returns: - * 0 not a base - * 1 is a base - */ - -int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - unsigned j; - - //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); - assert(!baseClass); - for (j = 0; j < cd->interfaces_dim; j++) - { - BaseClass *b = cd->interfaces[j]; - - //printf("\tbase %s\n", b->base->toChars()); - if (this == b->base) - { - //printf("\tfound at offset %d\n", b->offset); - if (poffset) - { *poffset = b->offset; - if (j && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - } - return 1; - } - if (isBaseOf(b, poffset)) - { if (j && poffset && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - return 1; - } - } - - if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) - return 1; - - if (poffset) - *poffset = 0; - return 0; -} - - -int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) -{ - //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars()); - for (unsigned j = 0; j < bc->baseInterfaces_dim; j++) - { - BaseClass *b = &bc->baseInterfaces[j]; - - if (this == b->base) - { - if (poffset) - { *poffset = b->offset; - } - return 1; - } - if (isBaseOf(b, poffset)) - { - return 1; - } - } - if (poffset) - *poffset = 0; - return 0; -} - -/**************************************** - * Determine if slot 0 of the vtbl[] is reserved for something else. - * For class objects, yes, this is where the ClassInfo ptr goes. - * For COM interfaces, no. - * For non-COM interfaces, yes, this is where the Interface ptr goes. - */ - -int InterfaceDeclaration::vtblOffset() -{ - if (isCOMinterface() || isCPPinterface()) - return 0; - return 1; -} - -int InterfaceDeclaration::isCOMinterface() -{ - return com; -} - -int InterfaceDeclaration::isCPPinterface() -{ - return cpp; -} - -/******************************************* - */ - -const char *InterfaceDeclaration::kind() -{ - return "interface"; -} - - -/******************************** BaseClass *****************************/ - -BaseClass::BaseClass() -{ - memset(this, 0, sizeof(BaseClass)); -} - -BaseClass::BaseClass(Type *type, enum PROT protection) -{ - //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); - this->type = type; - this->protection = protection; - base = NULL; - offset = 0; - - baseInterfaces_dim = 0; - baseInterfaces = NULL; -} - -/**************************************** - * Fill in vtbl[] for base class based on member functions of class cd. - * Input: - * vtbl if !=NULL, fill it in - * newinstance !=0 means all entries must be filled in by members - * of cd, not members of any base classes of cd. - * Returns: - * !=0 if any entries were filled in by members of cd (not exclusively - * by base classes) - */ - -int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance) -{ - ClassDeclaration *id = base; - int j; - int result = 0; - - //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); - if (vtbl) - vtbl->setDim(base->vtbl.dim); - - // first entry is ClassInfo reference - for (j = base->vtblOffset(); j < base->vtbl.dim; j++) - { - FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration(); - FuncDeclaration *fd; - TypeFunction *tf; - - //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); - - assert(ifd); - // Find corresponding function in this class - tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; - fd = cd->findFunc(ifd->ident, tf); - if (fd && !fd->isAbstract()) - { - //printf(" found\n"); - // Check that calling conventions match - if (fd->linkage != ifd->linkage) - fd->error("linkage doesn't match interface function"); - - // Check that it is current - if (newinstance && - fd->toParent() != cd && - ifd->toParent() == base) - cd->error("interface function %s.%s is not implemented", - id->toChars(), ifd->ident->toChars()); - - if (fd->toParent() == cd) - result = 1; - } - else - { - //printf(" not found\n"); - // BUG: should mark this class as abstract? - if (!cd->isAbstract()) - cd->error("interface function %s.%s isn't implemented", - id->toChars(), ifd->ident->toChars()); - fd = NULL; - } - if (vtbl) - vtbl->data[j] = fd; - } - - return result; -} - -void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) -{ - //printf("+copyBaseInterfaces(), %s\n", base->toChars()); -// if (baseInterfaces_dim) -// return; - - baseInterfaces_dim = base->interfaces_dim; - baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass)); - - //printf("%s.copyBaseInterfaces()\n", base->toChars()); - for (int i = 0; i < baseInterfaces_dim; i++) - { - BaseClass *b = &baseInterfaces[i]; - BaseClass *b2 = base->interfaces[i]; - - assert(b2->vtbl.dim == 0); // should not be filled yet - memcpy(b, b2, sizeof(BaseClass)); - - if (i) // single inheritance is i==0 - vtblInterfaces->push(b); // only need for M.I. - b->copyBaseInterfaces(vtblInterfaces); - } - //printf("-copyBaseInterfaces\n"); -} + +// 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. + +#include +#include +#include + +#include "root.h" +#include "rmem.h" + +#include "enum.h" +#include "init.h" +#include "attrib.h" +#include "declaration.h" +#include "aggregate.h" +#include "id.h" +#include "mtype.h" +#include "scope.h" +#include "module.h" +#include "expression.h" +#include "statement.h" + +/********************************* ClassDeclaration ****************************/ + +ClassDeclaration *ClassDeclaration::classinfo; +ClassDeclaration *ClassDeclaration::object; + +ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) + : AggregateDeclaration(loc, id) +{ + static char msg[] = "only object.d can define this reserved class name"; + + if (baseclasses) + this->baseclasses = *baseclasses; + baseClass = NULL; + + interfaces_dim = 0; + interfaces = NULL; + + vtblInterfaces = NULL; + + //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim); + + // For forward references + type = new TypeClass(this); + handle = type; + + staticCtor = NULL; + staticDtor = NULL; + +#if IN_DMD + vtblsym = NULL; +#endif + vclassinfo = NULL; + + if (id) + { // Look for special class names + + if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof) + error("illegal class name"); + + // BUG: What if this is the wrong TypeInfo, i.e. it is nested? + if (id->toChars()[0] == 'T') + { + if (id == Id::TypeInfo) + { if (Type::typeinfo) + Type::typeinfo->error("%s", msg); + Type::typeinfo = this; + } + + if (id == Id::TypeInfo_Class) + { if (Type::typeinfoclass) + Type::typeinfoclass->error("%s", msg); + Type::typeinfoclass = this; + } + + if (id == Id::TypeInfo_Interface) + { if (Type::typeinfointerface) + Type::typeinfointerface->error("%s", msg); + Type::typeinfointerface = this; + } + + if (id == Id::TypeInfo_Struct) + { if (Type::typeinfostruct) + Type::typeinfostruct->error("%s", msg); + Type::typeinfostruct = this; + } + + if (id == Id::TypeInfo_Typedef) + { if (Type::typeinfotypedef) + Type::typeinfotypedef->error("%s", msg); + Type::typeinfotypedef = this; + } + + if (id == Id::TypeInfo_Pointer) + { if (Type::typeinfopointer) + Type::typeinfopointer->error("%s", msg); + Type::typeinfopointer = this; + } + + if (id == Id::TypeInfo_Array) + { if (Type::typeinfoarray) + Type::typeinfoarray->error("%s", msg); + Type::typeinfoarray = this; + } + + if (id == Id::TypeInfo_StaticArray) + { //if (Type::typeinfostaticarray) + //Type::typeinfostaticarray->error("%s", msg); + Type::typeinfostaticarray = this; + } + + if (id == Id::TypeInfo_AssociativeArray) + { if (Type::typeinfoassociativearray) + Type::typeinfoassociativearray->error("%s", msg); + Type::typeinfoassociativearray = this; + } + + if (id == Id::TypeInfo_Enum) + { if (Type::typeinfoenum) + Type::typeinfoenum->error("%s", msg); + Type::typeinfoenum = this; + } + + if (id == Id::TypeInfo_Function) + { if (Type::typeinfofunction) + Type::typeinfofunction->error("%s", msg); + Type::typeinfofunction = this; + } + + if (id == Id::TypeInfo_Delegate) + { if (Type::typeinfodelegate) + Type::typeinfodelegate->error("%s", msg); + Type::typeinfodelegate = this; + } + + if (id == Id::TypeInfo_Tuple) + { if (Type::typeinfotypelist) + Type::typeinfotypelist->error("%s", msg); + Type::typeinfotypelist = this; + } + +#if DMDV2 + if (id == Id::TypeInfo_Const) + { if (Type::typeinfoconst) + Type::typeinfoconst->error("%s", msg); + Type::typeinfoconst = this; + } + + if (id == Id::TypeInfo_Invariant) + { if (Type::typeinfoinvariant) + Type::typeinfoinvariant->error("%s", msg); + Type::typeinfoinvariant = this; + } + + if (id == Id::TypeInfo_Shared) + { if (Type::typeinfoshared) + Type::typeinfoshared->error("%s", msg); + Type::typeinfoshared = this; + } +#endif + } + + if (id == Id::Object) + { if (object) + object->error("%s", msg); + object = this; + } + + if (id == Id::ClassInfo) + { if (classinfo) + classinfo->error("%s", msg); + classinfo = this; + } + + if (id == Id::ModuleInfo) + { if (Module::moduleinfo) + Module::moduleinfo->error("%s", msg); + Module::moduleinfo = this; + } + } + + com = 0; + isauto = 0; + isabstract = 0; + inuse = 0; +} + +Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) +{ + ClassDeclaration *cd; + + //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + cd = (ClassDeclaration *)s; + else + cd = new ClassDeclaration(loc, ident, NULL); + + cd->storage_class |= storage_class; + + cd->baseclasses.setDim(this->baseclasses.dim); + for (int i = 0; i < cd->baseclasses.dim; i++) + { + BaseClass *b = (BaseClass *)this->baseclasses.data[i]; + BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); + cd->baseclasses.data[i] = b2; + } + + ScopeDsymbol::syntaxCopy(cd); + return cd; +} + +void ClassDeclaration::semantic(Scope *sc) +{ int i; + unsigned offset; + + //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); + //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); + //printf("sc->stc = %x\n", sc->stc); + + //{ static int n; if (++n == 20) *(char*)0=0; } + + if (!ident) // if anonymous class + { const char *id = "__anonclass"; + + ident = Identifier::generateId(id); + } + + if (!scope) + { + if (!parent && sc->parent && !sc->parent->isModule()) + parent = sc->parent; + + type = type->semantic(loc, sc); + handle = handle->semantic(loc, sc); + } + if (!members) // if forward reference + { //printf("\tclass '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) + { if (!scope) + { //printf("\tsemantic for '%s' is already completed\n", toChars()); + return; // semantic() already completed + } + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } +#ifdef IN_GCC + methods.setDim(0); +#endif + + if (sc->stc & STCdeprecated) + { + isdeprecated = 1; + } + + if (sc->linkage == LINKcpp) + error("cannot create C++ classes"); + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses.dim; ) + { BaseClass *b = (BaseClass *)baseclasses.data[i]; + b->type = b->type->semantic(loc, sc); + Type *tb = b->type->toBasetype(); + + if (tb->ty == Ttuple) + { TypeTuple *tup = (TypeTuple *)tb; + enum PROT protection = b->protection; + baseclasses.remove(i); + size_t dim = Argument::dim(tup->arguments); + for (size_t j = 0; j < dim; j++) + { Argument *arg = Argument::getNth(tup->arguments, j); + b = new BaseClass(arg->type, protection); + baseclasses.insert(i + j, b); + } + } + else + i++; + } + + // See if there's a base class as first in baseclasses[] + if (baseclasses.dim) + { TypeClass *tc; + BaseClass *b; + Type *tb; + + b = (BaseClass *)baseclasses.data[0]; + //b->type = b->type->semantic(loc, sc); + tb = b->type->toBasetype(); + if (tb->ty != Tclass) + { error("base type must be class or interface, not %s", b->type->toChars()); + baseclasses.remove(0); + } + else + { + tc = (TypeClass *)(tb); + + if (tc->sym->isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc->checkDeprecated(loc, sc); + } + } + + if (tc->sym->isInterfaceDeclaration()) + ; + else + { + for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) + { + if (cdb == this) + { + error("circular inheritance"); + baseclasses.remove(0); + goto L7; + } + } + if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) + { + //error("forward reference of base class %s", baseClass->toChars()); + // Forward reference of base class, try again later + //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + return; + } + else + { baseClass = tc->sym; + b->base = baseClass; + } + L7: ; + } + } + } + + // Treat the remaining entries in baseclasses as interfaces + // Check for errors, handle forward references + for (i = (baseClass ? 1 : 0); i < baseclasses.dim; ) + { TypeClass *tc; + BaseClass *b; + Type *tb; + + b = (BaseClass *)baseclasses.data[i]; + b->type = b->type->semantic(loc, sc); + tb = b->type->toBasetype(); + if (tb->ty == Tclass) + tc = (TypeClass *)tb; + else + tc = NULL; + if (!tc || !tc->sym->isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b->type->toChars()); + baseclasses.remove(i); + continue; + } + else + { + if (tc->sym->isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc->checkDeprecated(loc, sc); + } + } + + // Check for duplicate interfaces + for (size_t j = (baseClass ? 1 : 0); j < i; j++) + { + BaseClass *b2 = (BaseClass *)baseclasses.data[j]; + if (b2->base == tc->sym) + error("inherits from duplicate interface %s", b2->base->toChars()); + } + + b->base = tc->sym; + if (!b->base->symtab || b->base->scope) + { + //error("forward reference of base class %s", baseClass->toChars()); + // Forward reference of base, try again later + //printf("\ttry later, forward reference of base %s\n", baseClass->toChars()); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + return; + } + } + i++; + } + + + // If no base class, and this is not an Object, use Object as base class + if (!baseClass && ident != Id::Object) + { + // BUG: what if Object is redefined in an inner scope? + Type *tbase = new TypeIdentifier(0, Id::Object); + BaseClass *b; + TypeClass *tc; + Type *bt; + + if (!object) + { + error("missing or corrupt object.d"); + fatal(); + } + bt = tbase->semantic(loc, sc)->toBasetype(); + b = new BaseClass(bt, PROTpublic); + baseclasses.shift(b); + assert(b->type->ty == Tclass); + tc = (TypeClass *)(b->type); + baseClass = tc->sym; + assert(!baseClass->isInterfaceDeclaration()); + b->base = baseClass; + } + + interfaces_dim = baseclasses.dim; + interfaces = (BaseClass **)baseclasses.data; + + + if (baseClass) + { + if (baseClass->storage_class & STCfinal) + error("cannot inherit from final class %s", baseClass->toChars()); + + interfaces_dim--; + interfaces++; + + // Copy vtbl[] from base class + vtbl.setDim(baseClass->vtbl.dim); + memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim); + + // Inherit properties from base class + com = baseClass->isCOMclass(); + isauto = baseClass->isauto; + vthis = baseClass->vthis; + storage_class |= baseClass->storage_class & STC_TYPECTOR; + } + else + { + // No base class, so this is the root of the class hierarchy + vtbl.setDim(0); + vtbl.push(this); // leave room for classinfo as first member + } + + protection = sc->protection; + storage_class |= sc->stc; + + if (sizeok == 0) + { + interfaceSemantic(sc); + + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->addMember(sc, this, 1); + } + + /* If this is a nested class, add the hidden 'this' + * member which is a pointer to the enclosing scope. + */ + if (vthis) // if inheriting from nested class + { // Use the base class's 'this' member + isnested = 1; + if (storage_class & STCstatic) + error("static class cannot inherit from nested class %s", baseClass->toChars()); + if (toParent2() != baseClass->toParent2()) + { + if (toParent2()) + { + error("is nested within %s, but super class %s is nested within %s", + toParent2()->toChars(), + baseClass->toChars(), + baseClass->toParent2()->toChars()); + } + else + { + error("is not nested, but super class %s is nested within %s", + baseClass->toChars(), + baseClass->toParent2()->toChars()); + } + isnested = 0; + } + } + else if (!(storage_class & STCstatic)) + { Dsymbol *s = toParent2(); + if (s) + { + AggregateDeclaration *ad = s->isClassDeclaration(); + FuncDeclaration *fd = s->isFuncDeclaration(); + + + if (ad || fd) + { isnested = 1; + Type *t; + if (ad) + t = ad->handle; + else if (fd) + { AggregateDeclaration *ad = fd->isMember2(); + if (ad) + t = ad->handle; + else + { + t = Type::tvoidptr; + } + } + else + assert(0); + if (t->ty == Tstruct) // ref to struct + t = Type::tvoidptr; + assert(!vthis); + vthis = new ThisDeclaration(loc, t); + members->push(vthis); + } + } + } + } + + if (storage_class & (STCauto | STCscope)) + isauto = 1; + if (storage_class & STCabstract) + isabstract = 1; + if (storage_class & STCimmutable) + type = type->invariantOf(); + else if (storage_class & STCconst) + type = type->constOf(); + else if (storage_class & STCshared) + type = type->sharedOf(); + + sc = sc->push(this); + sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | + STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); + sc->stc |= storage_class & STC_TYPECTOR; + sc->parent = this; + sc->inunion = 0; + + if (isCOMclass()) + { +#if _WIN32 + sc->linkage = LINKwindows; +#else + /* This enables us to use COM objects under Linux and + * work with things like XPCOM + */ + sc->linkage = LINKc; +#endif + } + sc->protection = PROTpublic; + sc->explicitProtection = 0; + sc->structalign = 8; + structalign = sc->structalign; + if (baseClass) + { sc->offset = baseClass->structsize; + alignsize = baseClass->alignsize; +// if (isnested) +// sc->offset += PTRSIZE; // room for uplevel context pointer + } + else + { sc->offset = PTRSIZE * 2; // allow room for __vptr and __monitor + alignsize = PTRSIZE; + } + structsize = sc->offset; + Scope scsave = *sc; + int members_dim = members->dim; + sizeok = 0; + for (i = 0; i < members_dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc); + } + + if (sizeok == 2) + { // semantic() failed because of forward references. + // Unwind what we did, and defer it for later + fields.setDim(0); + structsize = 0; + alignsize = 0; + structalign = 0; + + sc = sc->pop(); + + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + + //printf("\tsemantic('%s') failed due to forward references\n", toChars()); + return; + } + + //printf("\tsemantic('%s') successful\n", toChars()); + + structsize = sc->offset; + //members->print(); + + /* Look for special member functions. + * They must be in this class, not in a base class. + */ + ctor = (CtorDeclaration *)search(0, Id::ctor, 0); + if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) + ctor = NULL; + +// dtor = (DtorDeclaration *)search(Id::dtor, 0); +// if (dtor && dtor->toParent() != this) +// dtor = NULL; + +// inv = (InvariantDeclaration *)search(Id::classInvariant, 0); +// if (inv && inv->toParent() != this) +// inv = NULL; + + // Can be in base class + aggNew = (NewDeclaration *)search(0, Id::classNew, 0); + aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); + + // If this class has no constructor, but base class does, create + // a constructor: + // this() { } + if (!ctor && baseClass && baseClass->ctor) + { + //printf("Creating default this(){} for class %s\n", toChars()); + CtorDeclaration *ctor = new CtorDeclaration(loc, 0, NULL, 0); + ctor->fbody = new CompoundStatement(0, new Statements()); + members->push(ctor); + ctor->addMember(sc, this, 1); + *sc = scsave; // why? What about sc->nofree? + sc->offset = structsize; + ctor->semantic(sc); + this->ctor = ctor; + defaultCtor = ctor; + } + +#if 0 + if (baseClass) + { if (!aggDelete) + aggDelete = baseClass->aggDelete; + if (!aggNew) + aggNew = baseClass->aggNew; + } +#endif + + // Allocate instance of each new interface + for (i = 0; i < vtblInterfaces->dim; i++) + { + BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; + unsigned thissize = PTRSIZE; + + alignmember(structalign, thissize, &sc->offset); + assert(b->offset == 0); + b->offset = sc->offset; + + // Take care of single inheritance offsets + while (b->baseInterfaces_dim) + { + b = &b->baseInterfaces[0]; + b->offset = sc->offset; + } + + sc->offset += thissize; + if (alignsize < thissize) + alignsize = thissize; + } + structsize = sc->offset; + sizeok = 1; + Module::dprogress++; + + dtor = buildDtor(sc); + + sc->pop(); + +#if 0 // Do not call until toObjfile() because of forward references + // Fill in base class vtbl[]s + for (i = 0; i < vtblInterfaces->dim; i++) + { + BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; + + //b->fillVtbl(this, &b->vtbl, 1); + } +#endif + //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); +} + +void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (!isAnonymous()) + { + buf->printf("%s ", kind()); + buf->writestring(toChars()); + if (baseclasses.dim) + buf->writestring(" : "); + } + for (int i = 0; i < baseclasses.dim; i++) + { + BaseClass *b = (BaseClass *)baseclasses.data[i]; + + if (i) + buf->writeByte(','); + //buf->writestring(b->base->ident->toChars()); + b->type->toCBuffer(buf, NULL, hgs); + } + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writestring("}"); + buf->writenl(); +} + +#if 0 +void ClassDeclaration::defineRef(Dsymbol *s) +{ + ClassDeclaration *cd; + + AggregateDeclaration::defineRef(s); + cd = s->isClassDeclaration(); + baseType = cd->baseType; + cd->baseType = NULL; +} +#endif + +/********************************************* + * Determine if 'this' is a base class of cd. + * This is used to detect circular inheritance only. + */ + +int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) +{ + if (!cd) + return 0; + //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); + for (int i = 0; i < cd->baseclasses.dim; i++) + { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; + + if (b->base == this || isBaseOf2(b->base)) + return 1; + } + return 0; +} + +/******************************************* + * Determine if 'this' is a base class of cd. + */ + +int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) +{ + //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); + if (poffset) + *poffset = 0; + while (cd) + { + if (this == cd->baseClass) + return 1; + + /* cd->baseClass might not be set if cd is forward referenced. + */ + if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) + { + cd->error("base class is forward referenced by %s", toChars()); + } + + cd = cd->baseClass; + } + return 0; +} + +Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) +{ + Dsymbol *s; + + //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); + if (scope) + semantic(scope); + + if (!members || !symtab || scope) + { error("is forward referenced when looking for '%s'", ident->toChars()); + //*(char*)0=0; + return NULL; + } + + s = ScopeDsymbol::search(loc, ident, flags); + if (!s) + { + // Search bases classes in depth-first, left to right order + + int i; + + for (i = 0; i < baseclasses.dim; i++) + { + BaseClass *b = (BaseClass *)baseclasses.data[i]; + + if (b->base) + { + if (!b->base->symtab) + error("base %s is forward referenced", b->base->ident->toChars()); + else + { + s = b->base->search(loc, ident, flags); + if (s == this) // happens if s is nested in this and derives from this + s = NULL; + else if (s) + break; + } + } + } + } + return s; +} + +/********************************************************** + * fd is in the vtbl[] for this class. + * Return 1 if function is hidden (not findable through search). + */ + +#if DMDV2 +int isf(void *param, FuncDeclaration *fd) +{ + //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); + return param == fd; +} + +int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) +{ + //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); + Dsymbol *s = search(0, fd->ident, 4|2); + if (!s) + { //printf("not found\n"); + /* Because, due to a hack, if there are multiple definitions + * of fd->ident, NULL is returned. + */ + return 0; + } + s = s->toAlias(); + OverloadSet *os = s->isOverloadSet(); + if (os) + { + for (int i = 0; i < os->a.dim; i++) + { Dsymbol *s = (Dsymbol *)os->a.data[i]; + FuncDeclaration *f2 = s->isFuncDeclaration(); + if (f2 && overloadApply(getModule(), f2, &isf, fd)) + return 0; + } + return 1; + } + else + { + FuncDeclaration *fdstart = s->isFuncDeclaration(); + //printf("%s fdstart = %p\n", s->kind(), fdstart); + return !overloadApply(getModule(), fdstart, &isf, fd); + } +} +#endif + +/**************** + * Find virtual function matching identifier and type. + * Used to build virtual function tables for interface implementations. + */ + +FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) +{ + //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); + + ClassDeclaration *cd = this; + Array *vtbl = &cd->vtbl; + while (1) + { + for (size_t i = 0; i < vtbl->dim; i++) + { + FuncDeclaration *fd = ((Dsymbol*)vtbl->data[i])->isFuncDeclaration(); + if (!fd) + continue; // the first entry might be a ClassInfo + + //printf("\t[%d] = %s\n", i, fd->toChars()); + if (ident == fd->ident && + //tf->equals(fd->type) + fd->type->covariant(tf) == 1 + ) + { //printf("\t\tfound\n"); + return fd; + } + //else printf("\t\t%d\n", fd->type->covariant(tf)); + } + if (!cd) + break; + vtbl = &cd->vtblFinal; + cd = cd->baseClass; + } + + return NULL; +} + +void ClassDeclaration::interfaceSemantic(Scope *sc) +{ + InterfaceDeclaration *id = isInterfaceDeclaration(); + + vtblInterfaces = new BaseClasses(); + vtblInterfaces->reserve(interfaces_dim); + + for (size_t i = 0; i < interfaces_dim; i++) + { + BaseClass *b = interfaces[i]; + + // If this is an interface, and it derives from a COM interface, + // then this is a COM interface too. + if (b->base->isCOMinterface()) + com = 1; + + if (b->base->isCPPinterface() && id) + id->cpp = 1; + + vtblInterfaces->push(b); + b->copyBaseInterfaces(vtblInterfaces); + } +} + +/**************************************** + */ + +int ClassDeclaration::isCOMclass() +{ + return com; +} + +int ClassDeclaration::isCOMinterface() +{ + return 0; +} + +int ClassDeclaration::isCPPinterface() +{ + return 0; +} + + +/**************************************** + */ + +int ClassDeclaration::isAbstract() +{ + if (isabstract) + return TRUE; + for (int i = 1; i < vtbl.dim; i++) + { + FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration(); + + //printf("\tvtbl[%d] = %p\n", i, fd); + if (!fd || fd->isAbstract()) + { + isabstract |= 1; + return TRUE; + } + } + return FALSE; +} + + +/**************************************** + * Determine if slot 0 of the vtbl[] is reserved for something else. + * For class objects, yes, this is where the classinfo ptr goes. + * For COM interfaces, no. + * For non-COM interfaces, yes, this is where the Interface ptr goes. + */ + +int ClassDeclaration::vtblOffset() +{ + return 1; +} + +/**************************************** + */ + +const char *ClassDeclaration::kind() +{ + return "class"; +} + +/**************************************** + */ + +void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses) +{ + aclasses->push(this); +} + +/********************************* InterfaceDeclaration ****************************/ + +InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) + : ClassDeclaration(loc, id, baseclasses) +{ + com = 0; + cpp = 0; + if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces + { com = 1; + cpp = 1; // IUnknown is also a C++ interface + } +} + +Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) +{ + InterfaceDeclaration *id; + + if (s) + id = (InterfaceDeclaration *)s; + else + id = new InterfaceDeclaration(loc, ident, NULL); + + ClassDeclaration::syntaxCopy(id); + return id; +} + +void InterfaceDeclaration::semantic(Scope *sc) +{ int i; + + //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); + if (inuse) + return; + if (!scope) + { type = type->semantic(loc, sc); + handle = handle->semantic(loc, sc); + } + if (!members) // if forward reference + { //printf("\tinterface '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) // if already done + { if (!scope) + return; + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + + if (sc->stc & STCdeprecated) + { + isdeprecated = 1; + } + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses.dim; ) + { BaseClass *b = (BaseClass *)baseclasses.data[0]; + b->type = b->type->semantic(loc, sc); + Type *tb = b->type->toBasetype(); + + if (tb->ty == Ttuple) + { TypeTuple *tup = (TypeTuple *)tb; + enum PROT protection = b->protection; + baseclasses.remove(i); + size_t dim = Argument::dim(tup->arguments); + for (size_t j = 0; j < dim; j++) + { Argument *arg = Argument::getNth(tup->arguments, j); + b = new BaseClass(arg->type, protection); + baseclasses.insert(i + j, b); + } + } + else + i++; + } + + if (!baseclasses.dim && sc->linkage == LINKcpp) + cpp = 1; + + // Check for errors, handle forward references + for (i = 0; i < baseclasses.dim; ) + { TypeClass *tc; + BaseClass *b; + Type *tb; + + b = (BaseClass *)baseclasses.data[i]; + b->type = b->type->semantic(loc, sc); + tb = b->type->toBasetype(); + if (tb->ty == Tclass) + tc = (TypeClass *)tb; + else + tc = NULL; + if (!tc || !tc->sym->isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b->type->toChars()); + baseclasses.remove(i); + continue; + } + else + { + // Check for duplicate interfaces + for (size_t j = 0; j < i; j++) + { + BaseClass *b2 = (BaseClass *)baseclasses.data[j]; + if (b2->base == tc->sym) + error("inherits from duplicate interface %s", b2->base->toChars()); + } + + b->base = tc->sym; + if (b->base == this || isBaseOf2(b->base)) + { + error("circular inheritance of interface"); + baseclasses.remove(i); + continue; + } + if (!b->base->symtab || b->base->scope || b->base->inuse) + { + //error("forward reference of base class %s", baseClass->toChars()); + // Forward reference of base, try again later + //printf("\ttry later, forward reference of base %s\n", b->base->toChars()); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + return; + } + } +#if 0 + // Inherit const/invariant from base class + storage_class |= b->base->storage_class & STC_TYPECTOR; +#endif + i++; + } + + interfaces_dim = baseclasses.dim; + interfaces = (BaseClass **)baseclasses.data; + + interfaceSemantic(sc); + + if (vtblOffset()) + vtbl.push(this); // leave room at vtbl[0] for classinfo + + // Cat together the vtbl[]'s from base interfaces + for (i = 0; i < interfaces_dim; i++) + { BaseClass *b = interfaces[i]; + + // Skip if b has already appeared + for (int k = 0; k < i; k++) + { + if (b == interfaces[i]) + goto Lcontinue; + } + + // Copy vtbl[] from base class + if (b->base->vtblOffset()) + { int d = b->base->vtbl.dim; + if (d > 1) + { + vtbl.reserve(d - 1); + for (int j = 1; j < d; j++) + vtbl.push(b->base->vtbl.data[j]); + } + } + else + { + vtbl.append(&b->base->vtbl); + } + + Lcontinue: + ; + } + + protection = sc->protection; + storage_class |= sc->stc & STC_TYPECTOR; + + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->addMember(sc, this, 1); + } + + sc = sc->push(this); + sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | + STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); + sc->stc |= storage_class & STC_TYPECTOR; + sc->parent = this; + if (isCOMinterface()) + sc->linkage = LINKwindows; + else if (isCPPinterface()) + sc->linkage = LINKcpp; + sc->structalign = 8; + structalign = sc->structalign; + sc->offset = PTRSIZE * 2; + inuse++; + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc); + } + inuse--; + //members->print(); + sc->pop(); + //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); +} + + +/******************************************* + * Determine if 'this' is a base class of cd. + * (Actually, if it is an interface supported by cd) + * Output: + * *poffset offset to start of class + * OFFSET_RUNTIME must determine offset at runtime + * Returns: + * 0 not a base + * 1 is a base + */ + +int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) +{ + unsigned j; + + //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); + assert(!baseClass); + for (j = 0; j < cd->interfaces_dim; j++) + { + BaseClass *b = cd->interfaces[j]; + + //printf("\tbase %s\n", b->base->toChars()); + if (this == b->base) + { + //printf("\tfound at offset %d\n", b->offset); + if (poffset) + { *poffset = b->offset; + if (j && cd->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + } + return 1; + } + if (isBaseOf(b, poffset)) + { if (j && poffset && cd->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + return 1; + } + } + + if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) + return 1; + + if (poffset) + *poffset = 0; + return 0; +} + + +int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) +{ + //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars()); + for (unsigned j = 0; j < bc->baseInterfaces_dim; j++) + { + BaseClass *b = &bc->baseInterfaces[j]; + + if (this == b->base) + { + if (poffset) + { *poffset = b->offset; + if (j && bc->base->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + } + return 1; + } + if (isBaseOf(b, poffset)) + { if (j && poffset && bc->base->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + return 1; + } + } + if (poffset) + *poffset = 0; + return 0; +} + +/**************************************** + * Determine if slot 0 of the vtbl[] is reserved for something else. + * For class objects, yes, this is where the ClassInfo ptr goes. + * For COM interfaces, no. + * For non-COM interfaces, yes, this is where the Interface ptr goes. + */ + +int InterfaceDeclaration::vtblOffset() +{ + if (isCOMinterface() || isCPPinterface()) + return 0; + return 1; +} + +int InterfaceDeclaration::isCOMinterface() +{ + return com; +} + +int InterfaceDeclaration::isCPPinterface() +{ + return cpp; +} + +/******************************************* + */ + +const char *InterfaceDeclaration::kind() +{ + return "interface"; +} + + +/******************************** BaseClass *****************************/ + +BaseClass::BaseClass() +{ + memset(this, 0, sizeof(BaseClass)); +} + +BaseClass::BaseClass(Type *type, enum PROT protection) +{ + //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); + this->type = type; + this->protection = protection; + base = NULL; + offset = 0; + + baseInterfaces_dim = 0; + baseInterfaces = NULL; +} + +/**************************************** + * Fill in vtbl[] for base class based on member functions of class cd. + * Input: + * vtbl if !=NULL, fill it in + * newinstance !=0 means all entries must be filled in by members + * of cd, not members of any base classes of cd. + * Returns: + * !=0 if any entries were filled in by members of cd (not exclusively + * by base classes) + */ + +int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance) +{ + ClassDeclaration *id = base; + int j; + int result = 0; + + //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); + if (vtbl) + vtbl->setDim(base->vtbl.dim); + + // first entry is ClassInfo reference + for (j = base->vtblOffset(); j < base->vtbl.dim; j++) + { + FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration(); + FuncDeclaration *fd; + TypeFunction *tf; + + //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); + + assert(ifd); + // Find corresponding function in this class + tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; + fd = cd->findFunc(ifd->ident, tf); + if (fd && !fd->isAbstract()) + { + //printf(" found\n"); + // Check that calling conventions match + if (fd->linkage != ifd->linkage) + fd->error("linkage doesn't match interface function"); + + // Check that it is current + if (newinstance && + fd->toParent() != cd && + ifd->toParent() == base) + cd->error("interface function %s.%s is not implemented", + id->toChars(), ifd->ident->toChars()); + + if (fd->toParent() == cd) + result = 1; + } + else + { + //printf(" not found\n"); + // BUG: should mark this class as abstract? + if (!cd->isAbstract()) + cd->error("interface function %s.%s isn't implemented", + id->toChars(), ifd->ident->toChars()); + fd = NULL; + } + if (vtbl) + vtbl->data[j] = fd; + } + + return result; +} + +void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) +{ + //printf("+copyBaseInterfaces(), %s\n", base->toChars()); +// if (baseInterfaces_dim) +// return; + + baseInterfaces_dim = base->interfaces_dim; + baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass)); + + //printf("%s.copyBaseInterfaces()\n", base->toChars()); + for (int i = 0; i < baseInterfaces_dim; i++) + { + BaseClass *b = &baseInterfaces[i]; + BaseClass *b2 = base->interfaces[i]; + + assert(b2->vtbl.dim == 0); // should not be filled yet + memcpy(b, b2, sizeof(BaseClass)); + + if (i) // single inheritance is i==0 + vtblInterfaces->push(b); // only need for M.I. + b->copyBaseInterfaces(vtblInterfaces); + } + //printf("-copyBaseInterfaces\n"); +} diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/clone.c --- a/dmd2/clone.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/clone.c Sat May 30 17:23:32 2009 +0100 @@ -1,437 +1,443 @@ - -// 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. - -#include -#include - -#include "root.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "declaration.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "statement.h" -#include "init.h" - - -/******************************************* - * We need an opAssign for the struct if - * it has a destructor or a postblit. - * We need to generate one if a user-specified one does not exist. - */ - -int StructDeclaration::needOpAssign() -{ -#define X 0 - if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars()); - if (hasIdentityAssign) - goto Ldontneed; - - if (dtor || postblit) - goto Lneed; - - /* If any of the fields need an opAssign, then we - * need it too. - */ - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - Type *tv = v->type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->needOpAssign()) - goto Lneed; - } - } -Ldontneed: - if (X) printf("\tdontneed\n"); - return 0; - -Lneed: - if (X) printf("\tneed\n"); - return 1; -#undef X -} - -/****************************************** - * Build opAssign for struct. - * S* opAssign(S s) { ... } - */ - -FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) -{ - if (!needOpAssign()) - return NULL; - - //printf("StructDeclaration::buildOpAssign() %s\n", toChars()); - - FuncDeclaration *fop = NULL; - - Argument *param = new Argument(STCnodtor, type, Id::p, NULL); - Arguments *fparams = new Arguments; - fparams->push(param); - Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd); -#if STRUCTTHISREF - ((TypeFunction *)ftype)->isref = 1; -#endif - - fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype); - - Expression *e = NULL; - if (postblit) - { /* Swap: - * tmp = *this; *this = s; tmp.dtor(); - */ - //printf("\tswap copy\n"); - Identifier *idtmp = Lexer::uniqueId("__tmp"); - VarDeclaration *tmp; - AssignExp *ec = NULL; - if (dtor) - { - tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0)); - tmp->noauto = 1; - e = new DeclarationExp(0, tmp); - ec = new AssignExp(0, - new VarExp(0, tmp), -#if STRUCTTHISREF - new ThisExp(0) -#else - new PtrExp(0, new ThisExp(0)) -#endif - ); - ec->op = TOKblit; - e = Expression::combine(e, ec); - } - ec = new AssignExp(0, -#if STRUCTTHISREF - new ThisExp(0), -#else - new PtrExp(0, new ThisExp(0)), -#endif - new IdentifierExp(0, Id::p)); - ec->op = TOKblit; - e = Expression::combine(e, ec); - if (dtor) - { - /* Instead of running the destructor on s, run it - * on tmp. This avoids needing to copy tmp back in to s. - */ - Expression *ec = new DotVarExp(0, new VarExp(0, tmp), dtor, 0); - ec = new CallExp(0, ec); - e = Expression::combine(e, ec); - } - } - else - { /* Do memberwise copy - */ - //printf("\tmemberwise copy\n"); - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - // this.v = s.v; - AssignExp *ec = new AssignExp(0, - new DotVarExp(0, new ThisExp(0), v, 0), - new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0)); - ec->op = TOKblit; - e = Expression::combine(e, ec); - } - } - Statement *s1 = new ExpStatement(0, e); - - /* Add: - * return this; - */ - e = new ThisExp(0); - Statement *s2 = new ReturnStatement(0, e); - - fop->fbody = new CompoundStatement(0, s1, s2); - - members->push(fop); - fop->addMember(sc, this, 1); - - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; - - fop->semantic(sc); - - sc->pop(); - - //printf("-StructDeclaration::buildOpAssign() %s\n", toChars()); - - return fop; -} - -/******************************************* - * Build copy constructor for struct. - * Copy constructors are compiler generated only, and are only - * callable from the compiler. They are not user accessible. - * A copy constructor is: - * void cpctpr(ref S s) - * { - * *this = s; - * this.postBlit(); - * } - * This is done so: - * - postBlit() never sees uninitialized data - * - memcpy can be much more efficient than memberwise copy - * - no fields are overlooked - */ - -FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) -{ - //printf("StructDeclaration::buildCpCtor() %s\n", toChars()); - FuncDeclaration *fcp = NULL; - - /* Copy constructor is only necessary if there is a postblit function, - * otherwise the code generator will just do a bit copy. - */ - if (postblit) - { - //printf("generating cpctor\n"); - - Argument *param = new Argument(STCref, type, Id::p, NULL); - Arguments *fparams = new Arguments; - fparams->push(param); - Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd); - - fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype); - - // Build *this = p; - Expression *e = new ThisExp(0); -#if !STRUCTTHISREF - e = new PtrExp(0, e); -#endif - AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p)); - ea->op = TOKblit; - Statement *s = new ExpStatement(0, ea); - - // Build postBlit(); - e = new VarExp(0, postblit, 0); - e = new CallExp(0, e); - - s = new CompoundStatement(0, s, new ExpStatement(0, e)); - fcp->fbody = s; - - members->push(fcp); - - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; - - fcp->semantic(sc); - - sc->pop(); - } - - return fcp; -} - -/***************************************** - * Create inclusive postblit for struct by aggregating - * all the postblits in postblits[] with the postblits for - * all the members. - * Note the close similarity with AggregateDeclaration::buildDtor(), - * and the ordering changes (runs forward instead of backwards). - */ - -#if DMDV2 -FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) -{ - //printf("StructDeclaration::buildPostBlit() %s\n", toChars()); - Expression *e = NULL; - - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - Type *tv = v->type->toBasetype(); - size_t dim = 1; - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->postblit) - { Expression *ex; - - // this.v - ex = new ThisExp(0); - ex = new DotVarExp(0, ex, v, 0); - - if (dim == 1) - { // this.v.dtor() - ex = new DotVarExp(0, ex, sd->postblit, 0); - ex = new CallExp(0, ex); - } - else - { - // Typeinfo.postblit(cast(void*)&this.v); - Expression *ea = new AddrExp(0, ex); - ea = new CastExp(0, ea, Type::tvoid->pointerTo()); - - Expression *et = v->type->getTypeInfo(sc); - et = new DotIdExp(0, et, Id::postblit); - - ex = new CallExp(0, et, ea); - } - e = Expression::combine(e, ex); // combine in forward order - } - } - } - - /* Build our own "postblit" which executes e - */ - if (e) - { //printf("Building __fieldPostBlit()\n"); - PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit")); - dd->fbody = new ExpStatement(0, e); - dtors.push(dd); - members->push(dd); - dd->semantic(sc); - } - - switch (postblits.dim) - { - case 0: - return NULL; - - case 1: - return (FuncDeclaration *)postblits.data[0]; - - default: - e = NULL; - for (size_t i = 0; i < postblits.dim; i++) - { FuncDeclaration *fd = (FuncDeclaration *)postblits.data[i]; - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, fd, 0); - ex = new CallExp(0, ex); - e = Expression::combine(e, ex); - } - PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit")); - dd->fbody = new ExpStatement(0, e); - members->push(dd); - dd->semantic(sc); - return dd; - } -} - -#endif - -/***************************************** - * Create inclusive destructor for struct/class by aggregating - * all the destructors in dtors[] with the destructors for - * all the members. - * Note the close similarity with StructDeclaration::buildPostBlit(), - * and the ordering changes (runs backward instead of forwards). - */ - -FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) -{ - //printf("AggregateDeclaration::buildDtor() %s\n", toChars()); - Expression *e = NULL; - -#if DMDV2 - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - Type *tv = v->type->toBasetype(); - size_t dim = 1; - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - { Expression *ex; - - // this.v - ex = new ThisExp(0); - ex = new DotVarExp(0, ex, v, 0); - - if (dim == 1) - { // this.v.dtor() - ex = new DotVarExp(0, ex, sd->dtor, 0); - ex = new CallExp(0, ex); - } - else - { - // Typeinfo.destroy(cast(void*)&this.v); - Expression *ea = new AddrExp(0, ex); - ea = new CastExp(0, ea, Type::tvoid->pointerTo()); - - Expression *et = v->type->getTypeInfo(sc); - et = new DotIdExp(0, et, Id::destroy); - - ex = new CallExp(0, et, ea); - } - e = Expression::combine(ex, e); // combine in reverse order - } - } - } - - /* Build our own "destructor" which executes e - */ - if (e) - { //printf("Building __fieldDtor()\n"); - DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor")); - dd->fbody = new ExpStatement(0, e); - dtors.shift(dd); - members->push(dd); - dd->semantic(sc); - } -#endif - - switch (dtors.dim) - { - case 0: - return NULL; - - case 1: - return (FuncDeclaration *)dtors.data[0]; - - default: - e = NULL; - for (size_t i = 0; i < dtors.dim; i++) - { FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i]; - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, fd, 0); - ex = new CallExp(0, ex); - e = Expression::combine(ex, e); - } - DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor")); - dd->fbody = new ExpStatement(0, e); - members->push(dd); - dd->semantic(sc); - return dd; - } -} - - + +// 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. + +#include +#include + +#include "root.h" +#include "aggregate.h" +#include "scope.h" +#include "mtype.h" +#include "declaration.h" +#include "module.h" +#include "id.h" +#include "expression.h" +#include "statement.h" +#include "init.h" + + +/******************************************* + * We need an opAssign for the struct if + * it has a destructor or a postblit. + * We need to generate one if a user-specified one does not exist. + */ + +int StructDeclaration::needOpAssign() +{ +#define X 0 + if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars()); + if (hasIdentityAssign) + goto Ldontneed; + + if (dtor || postblit) + goto Lneed; + + /* If any of the fields need an opAssign, then we + * need it too. + */ + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->needOpAssign()) + goto Lneed; + } + } +Ldontneed: + if (X) printf("\tdontneed\n"); + return 0; + +Lneed: + if (X) printf("\tneed\n"); + return 1; +#undef X +} + +/****************************************** + * Build opAssign for struct. + * S* opAssign(S s) { ... } + */ + +FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) +{ + if (!needOpAssign()) + return NULL; + + //printf("StructDeclaration::buildOpAssign() %s\n", toChars()); + + FuncDeclaration *fop = NULL; + + Argument *param = new Argument(STCnodtor, type, Id::p, NULL); + Arguments *fparams = new Arguments; + fparams->push(param); + Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd); +#if STRUCTTHISREF + ((TypeFunction *)ftype)->isref = 1; +#endif + + fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype); + + Expression *e = NULL; + if (postblit) + { /* Swap: + * tmp = *this; *this = s; tmp.dtor(); + */ + //printf("\tswap copy\n"); + Identifier *idtmp = Lexer::uniqueId("__tmp"); + VarDeclaration *tmp; + AssignExp *ec = NULL; + if (dtor) + { + tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0)); + tmp->noauto = 1; + e = new DeclarationExp(0, tmp); + ec = new AssignExp(0, + new VarExp(0, tmp), +#if STRUCTTHISREF + new ThisExp(0) +#else + new PtrExp(0, new ThisExp(0)) +#endif + ); + ec->op = TOKblit; + e = Expression::combine(e, ec); + } + ec = new AssignExp(0, +#if STRUCTTHISREF + new ThisExp(0), +#else + new PtrExp(0, new ThisExp(0)), +#endif + new IdentifierExp(0, Id::p)); + ec->op = TOKblit; + e = Expression::combine(e, ec); + if (dtor) + { + /* Instead of running the destructor on s, run it + * on tmp. This avoids needing to copy tmp back in to s. + */ + Expression *ec = new DotVarExp(0, new VarExp(0, tmp), dtor, 0); + ec = new CallExp(0, ec); + e = Expression::combine(e, ec); + } + } + else + { /* Do memberwise copy + */ + //printf("\tmemberwise copy\n"); + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + // this.v = s.v; + AssignExp *ec = new AssignExp(0, + new DotVarExp(0, new ThisExp(0), v, 0), + new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0)); + ec->op = TOKblit; + e = Expression::combine(e, ec); + } + } + Statement *s1 = new ExpStatement(0, e); + + /* Add: + * return this; + */ + e = new ThisExp(0); + Statement *s2 = new ReturnStatement(0, e); + + fop->fbody = new CompoundStatement(0, s1, s2); + + members->push(fop); + fop->addMember(sc, this, 1); + + sc = sc->push(); + sc->stc = 0; + sc->linkage = LINKd; + + fop->semantic(sc); + + sc->pop(); + + //printf("-StructDeclaration::buildOpAssign() %s\n", toChars()); + + return fop; +} + +/******************************************* + * Build copy constructor for struct. + * Copy constructors are compiler generated only, and are only + * callable from the compiler. They are not user accessible. + * A copy constructor is: + * void cpctpr(ref S s) + * { + * *this = s; + * this.postBlit(); + * } + * This is done so: + * - postBlit() never sees uninitialized data + * - memcpy can be much more efficient than memberwise copy + * - no fields are overlooked + */ + +FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) +{ + //printf("StructDeclaration::buildCpCtor() %s\n", toChars()); + FuncDeclaration *fcp = NULL; + + /* Copy constructor is only necessary if there is a postblit function, + * otherwise the code generator will just do a bit copy. + */ + if (postblit) + { + //printf("generating cpctor\n"); + + Argument *param = new Argument(STCref, type, Id::p, NULL); + Arguments *fparams = new Arguments; + fparams->push(param); + Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd); + + fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype); + + // Build *this = p; + Expression *e = new ThisExp(0); +#if !STRUCTTHISREF + e = new PtrExp(0, e); +#endif + AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p)); + ea->op = TOKblit; + Statement *s = new ExpStatement(0, ea); + + // Build postBlit(); + e = new VarExp(0, postblit, 0); + e = new CallExp(0, e); + + s = new CompoundStatement(0, s, new ExpStatement(0, e)); + fcp->fbody = s; + + members->push(fcp); + + sc = sc->push(); + sc->stc = 0; + sc->linkage = LINKd; + + fcp->semantic(sc); + + sc->pop(); + } + + return fcp; +} + +/***************************************** + * Create inclusive postblit for struct by aggregating + * all the postblits in postblits[] with the postblits for + * all the members. + * Note the close similarity with AggregateDeclaration::buildDtor(), + * and the ordering changes (runs forward instead of backwards). + */ + +#if DMDV2 +FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) +{ + //printf("StructDeclaration::buildPostBlit() %s\n", toChars()); + Expression *e = NULL; + + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->toBasetype(); + size_t dim = 1; + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + dim *= ((TypeSArray *)tv)->dim->toInteger(); + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->postblit) + { Expression *ex; + + // this.v + ex = new ThisExp(0); + ex = new DotVarExp(0, ex, v, 0); + + if (dim == 1) + { // this.v.postblit() + ex = new DotVarExp(0, ex, sd->postblit, 0); + ex = new CallExp(0, ex); + } + else + { + // Typeinfo.postblit(cast(void*)&this.v); + Expression *ea = new AddrExp(0, ex); + ea = new CastExp(0, ea, Type::tvoid->pointerTo()); + + Expression *et = v->type->getTypeInfo(sc); + et = new DotIdExp(0, et, Id::postblit); + + ex = new CallExp(0, et, ea); + } + e = Expression::combine(e, ex); // combine in forward order + } + } + } + + /* Build our own "postblit" which executes e + */ + if (e) + { //printf("Building __fieldPostBlit()\n"); + PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit")); + dd->fbody = new ExpStatement(0, e); + postblits.shift(dd); + members->push(dd); + dd->semantic(sc); + } + + switch (postblits.dim) + { + case 0: + return NULL; + + case 1: + return (FuncDeclaration *)postblits.data[0]; + + default: + e = NULL; + for (size_t i = 0; i < postblits.dim; i++) + { FuncDeclaration *fd = (FuncDeclaration *)postblits.data[i]; + Expression *ex = new ThisExp(0); + ex = new DotVarExp(0, ex, fd, 0); + ex = new CallExp(0, ex); + e = Expression::combine(e, ex); + } + PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit")); + dd->fbody = new ExpStatement(0, e); + members->push(dd); + dd->semantic(sc); + return dd; + } +} + +#endif + +/***************************************** + * Create inclusive destructor for struct/class by aggregating + * all the destructors in dtors[] with the destructors for + * all the members. + * Note the close similarity with StructDeclaration::buildPostBlit(), + * and the ordering changes (runs backward instead of forwards). + */ + +FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) +{ + //printf("AggregateDeclaration::buildDtor() %s\n", toChars()); + Expression *e = NULL; + +#if DMDV2 + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->toBasetype(); + size_t dim = 1; + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + dim *= ((TypeSArray *)tv)->dim->toInteger(); + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->dtor) + { Expression *ex; + + // this.v + ex = new ThisExp(0); + ex = new DotVarExp(0, ex, v, 0); + + if (dim == 1) + { // this.v.dtor() + ex = new DotVarExp(0, ex, sd->dtor, 0); + ex = new CallExp(0, ex); + } + else + { + // Typeinfo.destroy(cast(void*)&this.v); + Expression *ea = new AddrExp(0, ex); + ea = new CastExp(0, ea, Type::tvoid->pointerTo()); + + Expression *et = v->type->getTypeInfo(sc); + et = new DotIdExp(0, et, Id::destroy); + + ex = new CallExp(0, et, ea); + } + e = Expression::combine(ex, e); // combine in reverse order + } + } + } + + /* Build our own "destructor" which executes e + */ + if (e) + { //printf("Building __fieldDtor()\n"); + DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor")); + dd->fbody = new ExpStatement(0, e); + dtors.shift(dd); + members->push(dd); + dd->semantic(sc); + } +#endif + + switch (dtors.dim) + { + case 0: + return NULL; + + case 1: + return (FuncDeclaration *)dtors.data[0]; + + default: + e = NULL; + for (size_t i = 0; i < dtors.dim; i++) + { FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i]; + Expression *ex = new ThisExp(0); + ex = new DotVarExp(0, ex, fd, 0); + ex = new CallExp(0, ex); + e = Expression::combine(ex, e); + } + DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor")); + dd->fbody = new ExpStatement(0, e); + members->push(dd); + dd->semantic(sc); + return dd; + } +} + + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/cond.c --- a/dmd2/cond.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/cond.c Sat May 30 17:23:32 2009 +0100 @@ -1,391 +1,405 @@ - -// 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. - -#include -#include - -#include "id.h" -#include "init.h" -#include "declaration.h" -#include "identifier.h" -#include "expression.h" -#include "cond.h" -#include "module.h" -#include "template.h" -#include "lexer.h" -#ifdef _DH -#include "mtype.h" -#include "scope.h" -#endif - -int findCondition(Array *ids, Identifier *ident) -{ - if (ids) - { - for (int i = 0; i < ids->dim; i++) - { - const char *id = (const char *)ids->data[i]; - - if (strcmp(id, ident->toChars()) == 0) - return TRUE; - } - } - - return FALSE; -} - -/* ============================================================ */ - -Condition::Condition(Loc loc) -{ - this->loc = loc; - inc = 0; -} - -/* ============================================================ */ - -DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) - : Condition(0) -{ - this->mod = mod; - this->level = level; - this->ident = ident; -} - -Condition *DVCondition::syntaxCopy() -{ - return this; // don't need to copy -} - -/* ============================================================ */ - -void DebugCondition::setGlobalLevel(unsigned level) -{ - global.params.debuglevel = level; -} - -void DebugCondition::addGlobalIdent(const char *ident) -{ - if (!global.params.debugids) - global.params.debugids = new Array(); - global.params.debugids->push((void *)ident); -} - - -DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int DebugCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->debugids, ident)) - inc = 1; - else if (findCondition(global.params.debugids, ident)) - inc = 1; - else - { if (!mod->debugidsNot) - mod->debugidsNot = new Array(); - mod->debugidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.debuglevel || level <= mod->debuglevel) - inc = 1; - } - return (inc == 1); -} - -void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("debug (%s)", ident->toChars()); - else - buf->printf("debug (%u)", level); -} - -/* ============================================================ */ - -void VersionCondition::setGlobalLevel(unsigned level) -{ - global.params.versionlevel = level; -} - -void VersionCondition::checkPredefined(Loc loc, const char *ident) -{ - static const char* reserved[] = - { - "DigitalMars", "LLVM", "LDC", "LLVM64", - "X86", "X86_64", "PPC", "PPC64", - "Windows", "Win32", "Win64", - "linux", "darwin", "Posix", - "LittleEndian", "BigEndian", - "all", - "none", - }; - - for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) - { - if (strcmp(ident, reserved[i]) == 0) - goto Lerror; - } - - if (ident[0] == 'D' && ident[1] == '_') - goto Lerror; - - return; - - Lerror: - error(loc, "version identifier '%s' is reserved and cannot be set", ident); -} - -void VersionCondition::addGlobalIdent(const char *ident) -{ - checkPredefined(0, ident); - addPredefinedGlobalIdent(ident); -} - -void VersionCondition::addPredefinedGlobalIdent(const char *ident) -{ - if (!global.params.versionids) - global.params.versionids = new Array(); - global.params.versionids->push((void *)ident); -} - - -VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int VersionCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); - //if (ident) printf("\tident = '%s'\n", ident->toChars()); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->versionids, ident)) - inc = 1; - else if (findCondition(global.params.versionids, ident)) - inc = 1; - else - { - if (!mod->versionidsNot) - mod->versionidsNot = new Array(); - mod->versionidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.versionlevel || level <= mod->versionlevel) - inc = 1; - } - return (inc == 1); -} - -void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("version (%s)", ident->toChars()); - else - buf->printf("version (%u)", level); -} - - -/**************************** StaticIfCondition *******************************/ - -StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) - : Condition(loc) -{ - this->exp = exp; -} - -Condition *StaticIfCondition::syntaxCopy() -{ - return new StaticIfCondition(loc, exp->syntaxCopy()); -} - -int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) -{ -#if 0 - printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s); - if (s) - { - printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); - } -#endif - if (inc == 0) - { - if (!sc) - { - error(loc, "static if conditional cannot be at global scope"); - inc = 2; - return 0; - } - - sc = sc->push(sc->scopesym); - sc->sd = s; // s gets any addMember() - sc->flags |= SCOPEstaticif; - Expression *e = exp->semantic(sc); - sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - inc = 1; - else if (e->isBool(FALSE)) - inc = 2; - else - { - e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); - inc = 2; - } - } - return (inc == 1); -} - -void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("static if("); - exp->toCBuffer(buf, hgs); - buf->writeByte(')'); -} - - -/**************************** IftypeCondition *******************************/ - -IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) - : Condition(loc) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; -} - -Condition *IftypeCondition::syntaxCopy() -{ - return new IftypeCondition(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL); -} - -int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("IftypeCondition::include()\n"); - if (inc == 0) - { - if (!sc) - { - error(loc, "iftype conditional cannot be at global scope"); - inc = 2; - return 0; - } - unsigned errors = global.errors; - global.gag++; // suppress printing of error messages - targ = targ->semantic(loc, sc); - global.gag--; - if (errors != global.errors) // if any errors happened - { inc = 2; // then condition is false - global.errors = errors; - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - MATCH m; - TemplateTypeParameter tp(loc, id, NULL, NULL); - - TemplateParameters parameters; - parameters.setDim(1); - parameters.data[0] = (void *)&tp; - - Objects dedtypes; - dedtypes.setDim(1); - - m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - inc = 2; - else - { - inc = 1; - Type *tded = (Type *)dedtypes.data[0]; - if (!tded) - tded = targ; - Dsymbol *s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - } - } - else if (id) - { - /* Declare id as an alias for type targ. Evaluate to TRUE - */ - Dsymbol *s = new AliasDeclaration(loc, id, targ); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - inc = 1; - } - else if (tspec) - { - /* Evaluate to TRUE if targ matches tspec - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s\n", targ->toChars()); - //printf("tspec = %s\n", tspec->toChars()); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - inc = 1; - else - inc = 2; - } - else /* == */ - { if (targ->equals(tspec)) - inc = 1; - else - inc = 2; - } - } - else - inc = 1; - //printf("inc = %d\n", inc); - } - return (inc == 1); -} - -void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("iftype("); - targ->toCBuffer(buf, id, hgs); - if (tspec) - { - if (tok == TOKcolon) - buf->writestring(" : "); - else - buf->writestring(" == "); - tspec->toCBuffer(buf, NULL, hgs); - } - buf->writeByte(')'); -} - - + +// 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. + +#include +#include + +#include "id.h" +#include "init.h" +#include "declaration.h" +#include "identifier.h" +#include "expression.h" +#include "cond.h" +#include "module.h" +#include "template.h" +#include "lexer.h" +#ifdef _DH +#include "mtype.h" +#include "scope.h" +#endif + +int findCondition(Array *ids, Identifier *ident) +{ + if (ids) + { + for (int i = 0; i < ids->dim; i++) + { + const char *id = (const char *)ids->data[i]; + + if (strcmp(id, ident->toChars()) == 0) + return TRUE; + } + } + + return FALSE; +} + +/* ============================================================ */ + +Condition::Condition(Loc loc) +{ + this->loc = loc; + inc = 0; +} + +/* ============================================================ */ + +DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) + : Condition(0) +{ + this->mod = mod; + this->level = level; + this->ident = ident; +} + +Condition *DVCondition::syntaxCopy() +{ + return this; // don't need to copy +} + +/* ============================================================ */ + +void DebugCondition::setGlobalLevel(unsigned level) +{ + global.params.debuglevel = level; +} + +void DebugCondition::addGlobalIdent(const char *ident) +{ + if (!global.params.debugids) + global.params.debugids = new Array(); + global.params.debugids->push((void *)ident); +} + + +DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) + : DVCondition(mod, level, ident) +{ +} + +int DebugCondition::include(Scope *sc, ScopeDsymbol *s) +{ + //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); + if (inc == 0) + { + inc = 2; + if (ident) + { + if (findCondition(mod->debugids, ident)) + inc = 1; + else if (findCondition(global.params.debugids, ident)) + inc = 1; + else + { if (!mod->debugidsNot) + mod->debugidsNot = new Array(); + mod->debugidsNot->push(ident->toChars()); + } + } + else if (level <= global.params.debuglevel || level <= mod->debuglevel) + inc = 1; + } + return (inc == 1); +} + +void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (ident) + buf->printf("debug (%s)", ident->toChars()); + else + buf->printf("debug (%u)", level); +} + +/* ============================================================ */ + +void VersionCondition::setGlobalLevel(unsigned level) +{ + global.params.versionlevel = level; +} + +void VersionCondition::checkPredefined(Loc loc, const char *ident) +{ + static const char* reserved[] = + { + "DigitalMars", "X86", "X86_64", + "Windows", "Win32", "Win64", + "linux", +#if DMDV2 + /* Although Posix is predefined by D1, disallowing its + * redefinition breaks makefiles and older builds. + */ + "Posix", + "D_NET", +#endif + "OSX", "FreeBSD", + "Solaris", + "LittleEndian", "BigEndian", + "all", + "none", + + // LDC + "LLVM", "LDC", "LLVM64", + "PPC", "PPC64", + "darwin","solaris","freebsd" + }; + + for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) + { + if (strcmp(ident, reserved[i]) == 0) + goto Lerror; + } + + if (ident[0] == 'D' && ident[1] == '_') + goto Lerror; + + return; + + Lerror: + error(loc, "version identifier '%s' is reserved and cannot be set", ident); +} + +void VersionCondition::addGlobalIdent(const char *ident) +{ + checkPredefined(0, ident); + addPredefinedGlobalIdent(ident); +} + +void VersionCondition::addPredefinedGlobalIdent(const char *ident) +{ + if (!global.params.versionids) + global.params.versionids = new Array(); + global.params.versionids->push((void *)ident); +} + + +VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) + : DVCondition(mod, level, ident) +{ +} + +int VersionCondition::include(Scope *sc, ScopeDsymbol *s) +{ + //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); + //if (ident) printf("\tident = '%s'\n", ident->toChars()); + if (inc == 0) + { + inc = 2; + if (ident) + { + if (findCondition(mod->versionids, ident)) + inc = 1; + else if (findCondition(global.params.versionids, ident)) + inc = 1; + else + { + if (!mod->versionidsNot) + mod->versionidsNot = new Array(); + mod->versionidsNot->push(ident->toChars()); + } + } + else if (level <= global.params.versionlevel || level <= mod->versionlevel) + inc = 1; + } + return (inc == 1); +} + +void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (ident) + buf->printf("version (%s)", ident->toChars()); + else + buf->printf("version (%u)", level); +} + + +/**************************** StaticIfCondition *******************************/ + +StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) + : Condition(loc) +{ + this->exp = exp; +} + +Condition *StaticIfCondition::syntaxCopy() +{ + return new StaticIfCondition(loc, exp->syntaxCopy()); +} + +int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) +{ +#if 0 + printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s); + if (s) + { + printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); + } +#endif + if (inc == 0) + { + if (!sc) + { + error(loc, "static if conditional cannot be at global scope"); + inc = 2; + return 0; + } + + sc = sc->push(sc->scopesym); + sc->sd = s; // s gets any addMember() + sc->flags |= SCOPEstaticif; + Expression *e = exp->semantic(sc); + sc->pop(); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->isBool(TRUE)) + inc = 1; + else if (e->isBool(FALSE)) + inc = 2; + else + { + e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); + inc = 2; + } + } + return (inc == 1); +} + +void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("static if("); + exp->toCBuffer(buf, hgs); + buf->writeByte(')'); +} + + +/**************************** IftypeCondition *******************************/ + +IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) + : Condition(loc) +{ + this->targ = targ; + this->id = id; + this->tok = tok; + this->tspec = tspec; +} + +Condition *IftypeCondition::syntaxCopy() +{ + return new IftypeCondition(loc, + targ->syntaxCopy(), + id, + tok, + tspec ? tspec->syntaxCopy() : NULL); +} + +int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) +{ + //printf("IftypeCondition::include()\n"); + if (inc == 0) + { + if (!sc) + { + error(loc, "iftype conditional cannot be at global scope"); + inc = 2; + return 0; + } + Type *t = targ->trySemantic(loc, sc); + if (t) + targ = t; + else + inc = 2; // condition is false + + if (!t) + { + } + else if (id && tspec) + { + /* Evaluate to TRUE if targ matches tspec. + * If TRUE, declare id as an alias for the specialized type. + */ + + MATCH m; + TemplateTypeParameter tp(loc, id, NULL, NULL); + + TemplateParameters parameters; + parameters.setDim(1); + parameters.data[0] = (void *)&tp; + + Objects dedtypes; + dedtypes.setDim(1); + + m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes); + if (m == MATCHnomatch || + (m != MATCHexact && tok == TOKequal)) + inc = 2; + else + { + inc = 1; + Type *tded = (Type *)dedtypes.data[0]; + if (!tded) + tded = targ; + Dsymbol *s = new AliasDeclaration(loc, id, tded); + s->semantic(sc); + sc->insert(s); + if (sd) + s->addMember(sc, sd, 1); + } + } + else if (id) + { + /* Declare id as an alias for type targ. Evaluate to TRUE + */ + Dsymbol *s = new AliasDeclaration(loc, id, targ); + s->semantic(sc); + sc->insert(s); + if (sd) + s->addMember(sc, sd, 1); + inc = 1; + } + else if (tspec) + { + /* Evaluate to TRUE if targ matches tspec + */ + tspec = tspec->semantic(loc, sc); + //printf("targ = %s\n", targ->toChars()); + //printf("tspec = %s\n", tspec->toChars()); + if (tok == TOKcolon) + { if (targ->implicitConvTo(tspec)) + inc = 1; + else + inc = 2; + } + else /* == */ + { if (targ->equals(tspec)) + inc = 1; + else + inc = 2; + } + } + else + inc = 1; + //printf("inc = %d\n", inc); + } + return (inc == 1); +} + +void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("iftype("); + targ->toCBuffer(buf, id, hgs); + if (tspec) + { + if (tok == TOKcolon) + buf->writestring(" : "); + else + buf->writestring(" == "); + tspec->toCBuffer(buf, NULL, hgs); + } + buf->writeByte(')'); +} + + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/constfold.c --- a/dmd2/constfold.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/constfold.c Sat May 30 17:23:32 2009 +0100 @@ -1,1606 +1,1596 @@ - -// 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. - -#include -#include -#include -#include - -#if __DMC__ -#include -#endif - -#include "mem.h" -#include "root.h" - -#include "mtype.h" -#include "expression.h" -#include "aggregate.h" -#include "declaration.h" - -#ifdef IN_GCC -#include "d-gcc-real.h" - -/* %% fix? */ -extern "C" bool real_isnan (const real_t *); -#endif - -static real_t zero; // work around DMC bug for now - -#define LOG 0 - -Expression *expType(Type *type, Expression *e) -{ - if (type != e->type) - { - e = e->copy(); - e->type = type; - } - return e; -} - -/* ================================== isConst() ============================== */ - -int Expression::isConst() -{ - //printf("Expression::isConst(): %s\n", toChars()); - return 0; -} - -int IntegerExp::isConst() -{ - return 1; -} - -int RealExp::isConst() -{ - return 1; -} - -int ComplexExp::isConst() -{ - return 1; -} - -int SymOffExp::isConst() -{ - return 2; -} - -/* =============================== constFold() ============================== */ - -/* The constFold() functions were redundant with the optimize() ones, - * and so have been folded in with them. - */ - -/* ========================================================================== */ - -Expression *Neg(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->type->isreal()) - { - e = new RealExp(loc, -e1->toReal(), type); - } - else if (e1->type->isimaginary()) - { - e = new RealExp(loc, -e1->toImaginary(), type); - } - else if (e1->type->iscomplex()) - { - e = new ComplexExp(loc, -e1->toComplex(), type); - } - else - e = new IntegerExp(loc, -e1->toInteger(), type); - return e; -} - -Expression *Com(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, ~e1->toInteger(), type); - return e; -} - -Expression *Not(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(0), type); - return e; -} - -Expression *Bool(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(1), type); - return e; -} - -Expression *Add(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - -#if LOG - printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); -#endif - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() + e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 + r2); break; - case 0+1: v = r1 + i2 * I; break; - case 0+2: v = r1 + c2; break; - case 3+0: v = i1 * I + r2; break; - case 3+1: v = (complex_t) ((i1 + i2) * I); break; - case 3+2: v = i1 * I + c2; break; - case 6+0: v = c1 + r2; break; - case 6+1: v = c1 + i2 * I; break; - case 6+2: v = c1 + c2; break; -#else - case 0+0: v = complex_t(r1 + r2, 0); break; - case 0+1: v = complex_t(r1, i2); break; - case 0+2: v = complex_t(r1 + creall(c2), cimagl(c2)); break; - case 3+0: v = complex_t(r2, i1); break; - case 3+1: v = complex_t(0, i1 + i2); break; - case 3+2: v = complex_t(creall(c2), i1 + cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) + r2, cimagl(c2)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) + i2); break; - case 6+2: v = c1 + c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger()); - e->type = type; - } - else if (e2->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e2; - e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger()); - e->type = type; - } - else - e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type); - return e; -} - - -Expression *Min(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() - e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 - r2); break; - case 0+1: v = r1 - i2 * I; break; - case 0+2: v = r1 - c2; break; - case 3+0: v = i1 * I - r2; break; - case 3+1: v = (complex_t) ((i1 - i2) * I); break; - case 3+2: v = i1 * I - c2; break; - case 6+0: v = c1 - r2; break; - case 6+1: v = c1 - i2 * I; break; - case 6+2: v = c1 - c2; break; -#else - case 0+0: v = complex_t(r1 - r2, 0); break; - case 0+1: v = complex_t(r1, -i2); break; - case 0+2: v = complex_t(r1 - creall(c2), -cimagl(c2)); break; - case 3+0: v = complex_t(-r2, i1); break; - case 3+1: v = complex_t(0, i1 - i2); break; - case 3+2: v = complex_t(-creall(c2), i1 - cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) - r2, cimagl(c1)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) - i2); break; - case 6+2: v = c1 - c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger()); - e->type = type; - } - else - { - e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type); - } - return e; -} - -Expression *Mul(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - if (e1->type->isreal()) - { -#if __DMC__ - c = e1->toReal() * e2->toComplex(); -#else - r = e1->toReal(); - c = e2->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e1->type->isimaginary()) - { -#if __DMC__ - c = e1->toImaginary() * I * e2->toComplex(); -#else - r = e1->toImaginary(); - c = e2->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else if (e2->type->isreal()) - { -#if __DMC__ - c = e2->toReal() * e1->toComplex(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - c = e1->toComplex() * e2->toImaginary() * I; -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else - c = e1->toComplex() * e2->toComplex(); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { - e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type); - } - return e; -} - -Expression *Div(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - //e1->type->print(); - //e2->type->print(); - if (e2->type->isreal()) - { - if (e1->type->isreal()) - { - e = new RealExp(loc, e1->toReal() / e2->toReal(), type); - return e; - } -#if __DMC__ - //r = e2->toReal(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / e2->toReal(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(creall(c) / r, cimagl(c) / r); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - //r = e2->toImaginary(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / (e2->toImaginary() * I); -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(cimagl(c) / r, -creall(c) / r); -#endif - } - else - { - c = e1->toComplex() / e2->toComplex(); - } - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) / ((d_uns64) n2); - else - n = n1 / n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Mod(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { - complex_t c; - - if (e2->type->isreal()) - { real_t r2 = e2->toReal(); - -#ifdef __DMC__ - c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2); -#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) - // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! - // arm also doesn't like fmodl - c = complex_t(fmod(e1->toReal(), r2), fmod(e1->toImaginary(), r2)); -#else - c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2)); -#endif - } - else if (e2->type->isimaginary()) - { real_t i2 = e2->toImaginary(); - -#ifdef __DMC__ - c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2); -#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) - // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! - // arm also doesn't like fmodl - c = complex_t(fmod(e1->toReal(), i2), fmod(e1->toImaginary(), i2)); -#else - c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2)); -#endif - } - else - assert(0); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) % ((d_uns64) n2); - else - n = n1 % n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Shl(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type); - return e; -} - -Expression *Shr(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - unsigned count; - integer_t value; - - value = e1->toInteger(); - count = e2->toInteger(); - switch (e1->type->toBasetype()->ty) - { - case Tint8: - value = (d_int8)(value) >> count; - break; - - case Tuns8: - value = (d_uns8)(value) >> count; - break; - - case Tint16: - value = (d_int16)(value) >> count; - break; - - case Tuns16: - value = (d_uns16)(value) >> count; - break; - - case Tint32: - value = (d_int32)(value) >> count; - break; - - case Tuns32: - value = (d_uns32)(value) >> count; - break; - - case Tint64: - value = (d_int64)(value) >> count; - break; - - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - default: - assert(0); - } - e = new IntegerExp(loc, value, type); - return e; -} - -Expression *Ushr(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - unsigned count; - integer_t value; - - value = e1->toInteger(); - count = e2->toInteger(); - switch (e1->type->toBasetype()->ty) - { - case Tint8: - case Tuns8: - assert(0); // no way to trigger this - value = (value & 0xFF) >> count; - break; - - case Tint16: - case Tuns16: - assert(0); // no way to trigger this - value = (value & 0xFFFF) >> count; - break; - - case Tint32: - case Tuns32: - value = (value & 0xFFFFFFFF) >> count; - break; - - case Tint64: - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - default: - assert(0); - } - e = new IntegerExp(loc, value, type); - return e; -} - -Expression *And(Type *type, Expression *e1, Expression *e2) -{ - Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() & e2->toInteger(), type); - return e; -} - -Expression *Or(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type); - return e; -} - -Expression *Xor(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() ^ e2->toInteger(), type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - */ -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - int cmp; - real_t r1; - real_t r2; - - //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - - assert(op == TOKequal || op == TOKnotequal); - - if (e1->op == TOKnull) - { - if (e2->op == TOKnull) - cmp = 1; - else if (e2->op == TOKstring) - { StringExp *es2 = (StringExp *)e2; - cmp = (0 == es2->len); - } - else if (e2->op == TOKarrayliteral) - { ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - cmp = !es2->elements || (0 == es2->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e2->op == TOKnull) - { - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - cmp = (0 == es1->len); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - cmp = !es1->elements || (0 == es1->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - - if (es1->sz != es2->sz) - { - assert(global.errors); - return EXP_CANT_INTERPRET; - } - if (es1->len == es2->len && - memcmp(es1->string, es2->string, es1->sz * es1->len) == 0) - cmp = 1; - else - cmp = 0; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - cmp = 1; // both arrays are empty - else if (!es1->elements || !es2->elements) - cmp = 0; - else if (es1->elements->dim != es2->elements->dim) - cmp = 0; - else - { - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (Expression *)es1->elements->data[i]; - Expression *ee2 = (Expression *)es2->elements->data[i]; - - Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - cmp = v->toInteger(); - if (cmp == 0) - break; - } - } - } - else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { // Swap operands and use common code - Expression *e = e1; - e1 = e2; - e2 = e; - goto Lsa; - } - else if (e1->op == TOKstring && e2->op == TOKarrayliteral) - { - Lsa: - StringExp *es1 = (StringExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - size_t dim1 = es1->len; - size_t dim2 = es2->elements ? es2->elements->dim : 0; - if (dim1 != dim2) - cmp = 0; - else - { - for (size_t i = 0; i < dim1; i++) - { - uinteger_t c = es1->charAt(i); - Expression *ee2 = (Expression *)es2->elements->data[i]; - if (ee2->isConst() != 1) - return EXP_CANT_INTERPRET; - cmp = (c == ee2->toInteger()); - if (cmp == 0) - break; - } - } - } - else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) - { StructLiteralExp *es1 = (StructLiteralExp *)e1; - StructLiteralExp *es2 = (StructLiteralExp *)e2; - - if (es1->sd != es2->sd) - cmp = 0; - else if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - cmp = 1; // both arrays are empty - else if (!es1->elements || !es2->elements) - cmp = 0; - else if (es1->elements->dim != es2->elements->dim) - cmp = 0; - else - { - cmp = 1; - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (Expression *)es1->elements->data[i]; - Expression *ee2 = (Expression *)es2->elements->data[i]; - - if (ee1 == ee2) - continue; - if (!ee1 || !ee2) - { cmp = 0; - break; - } - Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - cmp = v->toInteger(); - if (cmp == 0) - break; - } - } - } -#if 0 // Should handle this - else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { - } -#endif - else if (e1->isConst() != 1 || e2->isConst() != 1) - return EXP_CANT_INTERPRET; - else if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - cmp = (r1 == r2); -#else - if (isnan(r1) || isnan(r2)) // if unordered - { - cmp = 0; - } - else - { - cmp = (r1 == r2); - } -#endif - } - else if (e1->type->iscomplex()) - { - cmp = e1->toComplex() == e2->toComplex(); - } - else if (e1->type->isintegral()) - { - cmp = (e1->toInteger() == e2->toInteger()); - } - else - return EXP_CANT_INTERPRET; - if (op == TOKnotequal) - cmp ^= 1; - e = new IntegerExp(loc, cmp, type); - return e; -} - -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - int cmp; - - if (e1->op == TOKnull && e2->op == TOKnull) - { - cmp = 1; - } - else if (e1->op == TOKsymoff && e2->op == TOKsymoff) - { - SymOffExp *es1 = (SymOffExp *)e1; - SymOffExp *es2 = (SymOffExp *)e2; - - cmp = (es1->var == es2->var && es1->offset == es2->offset); - } - else if (e1->isConst() == 1 && e2->isConst() == 1) - return Equal((op == TOKidentity) ? TOKequal : TOKnotequal, - type, e1, e2); - else - assert(0); - if (op == TOKnotidentity) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - - -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - integer_t n; - real_t r1; - real_t r2; - - //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - - if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - size_t sz = es1->sz; - assert(sz == es2->sz); - - size_t len = es1->len; - if (es2->len < len) - len = es2->len; - - int cmp = memcmp(es1->string, es2->string, sz * len); - if (cmp == 0) - cmp = es1->len - es2->len; - - switch (op) - { - case TOKlt: n = cmp < 0; break; - case TOKle: n = cmp <= 0; break; - case TOKgt: n = cmp > 0; break; - case TOKge: n = cmp >= 0; break; - - case TOKleg: n = 1; break; - case TOKlg: n = cmp != 0; break; - case TOKunord: n = 0; break; - case TOKue: n = cmp == 0; break; - case TOKug: n = cmp > 0; break; - case TOKuge: n = cmp >= 0; break; - case TOKul: n = cmp < 0; break; - case TOKule: n = cmp <= 0; break; - - default: - assert(0); - } - } - else if (e1->isConst() != 1 || e2->isConst() != 1) - return EXP_CANT_INTERPRET; - else if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - // DMC is the only compiler I know of that handles NAN arguments - // correctly in comparisons. - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = r1 <>= r2; break; - case TOKlg: n = r1 <> r2; break; - case TOKunord: n = r1 !<>= r2; break; - case TOKue: n = r1 !<> r2; break; - case TOKug: n = r1 !<= r2; break; - case TOKuge: n = r1 !< r2; break; - case TOKul: n = r1 !>= r2; break; - case TOKule: n = r1 !> r2; break; - - default: - assert(0); - } -#else - // Don't rely on compiler, handle NAN arguments separately -#if IN_GCC - if (real_isnan(&r1) || real_isnan(&r2)) // if unordered -#else - if (isnan(r1) || isnan(r2)) // if unordered -#endif - { - switch (op) - { - case TOKlt: n = 0; break; - case TOKle: n = 0; break; - case TOKgt: n = 0; break; - case TOKge: n = 0; break; - - case TOKleg: n = 0; break; - case TOKlg: n = 0; break; - case TOKunord: n = 1; break; - case TOKue: n = 1; break; - case TOKug: n = 1; break; - case TOKuge: n = 1; break; - case TOKul: n = 1; break; - case TOKule: n = 1; break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = r1 != r2; break; - case TOKunord: n = 0; break; - case TOKue: n = r1 == r2; break; - case TOKug: n = r1 > r2; break; - case TOKuge: n = r1 >= r2; break; - case TOKul: n = r1 < r2; break; - case TOKule: n = r1 <= r2; break; - - default: - assert(0); - } - } -#endif - } - else if (e1->type->iscomplex()) - { - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (e1->type->isunsigned() || e2->type->isunsigned()) - { - switch (op) - { - case TOKlt: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKle: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - case TOKgt: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - - case TOKleg: n = 1; break; - case TOKlg: n = ((d_uns64) n1) != ((d_uns64) n2); break; - case TOKunord: n = 0; break; - case TOKue: n = ((d_uns64) n1) == ((d_uns64) n2); break; - case TOKug: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKuge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - case TOKul: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKule: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = n1 < n2; break; - case TOKle: n = n1 <= n2; break; - case TOKgt: n = n1 > n2; break; - case TOKge: n = n1 >= n2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = n1 != n2; break; - case TOKunord: n = 0; break; - case TOKue: n = n1 == n2; break; - case TOKug: n = n1 > n2; break; - case TOKuge: n = n1 >= n2; break; - case TOKul: n = n1 < n2; break; - case TOKule: n = n1 <= n2; break; - - default: - assert(0); - } - } - } - e = new IntegerExp(loc, n, type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - * to: type to cast to - * type: type to paint the result - */ - -Expression *Cast(Type *type, Type *to, Expression *e1) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); - //printf("\te1->type = %s\n", e1->type->toChars()); - if (e1->type->equals(type) && type->equals(to)) - return e1; - if (e1->type->implicitConvTo(to) >= MATCHconst || - to->implicitConvTo(e1->type) >= MATCHconst) - return expType(to, e1); - - Type *tb = to->toBasetype(); - Type *typeb = type->toBasetype(); - - if (e1->op == TOKstring) - { - if (tb->ty == Tarray && typeb->ty == Tarray && - tb->nextOf()->size() == typeb->nextOf()->size()) - { - return expType(to, e1); - } - } - - if (e1->isConst() != 1) - return EXP_CANT_INTERPRET; - - if (tb->ty == Tbool) - e = new IntegerExp(loc, e1->toInteger() != 0, type); - else if (type->isintegral()) - { - if (e1->type->isfloating()) - { integer_t result; - real_t r = e1->toReal(); - - switch (typeb->ty) - { - case Tint8: result = (d_int8)r; break; - case Tchar: - case Tuns8: result = (d_uns8)r; break; - case Tint16: result = (d_int16)r; break; - case Twchar: - case Tuns16: result = (d_uns16)r; break; - case Tint32: result = (d_int32)r; break; - case Tdchar: - case Tuns32: result = (d_uns32)r; break; - case Tint64: result = (d_int64)r; break; - case Tuns64: result = (d_uns64)r; break; - default: - assert(0); - } - - e = new IntegerExp(loc, result, type); - } - else if (type->isunsigned()) - e = new IntegerExp(loc, e1->toUInteger(), type); - else - e = new IntegerExp(loc, e1->toInteger(), type); - } - else if (tb->isreal()) - { real_t value = e1->toReal(); - - e = new RealExp(loc, value, type); - } - else if (tb->isimaginary()) - { real_t value = e1->toImaginary(); - - e = new RealExp(loc, value, type); - } - else if (tb->iscomplex()) - { complex_t value = e1->toComplex(); - - e = new ComplexExp(loc, value, type); - } - else if (tb->isscalar()) - e = new IntegerExp(loc, e1->toInteger(), type); - else if (tb->ty == Tvoid) - e = EXP_CANT_INTERPRET; - else if (tb->ty == Tstruct && e1->op == TOKint64) - { // Struct = 0; - StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration(); - assert(sd); - Expressions *elements = new Expressions; - for (size_t i = 0; i < sd->fields.dim; i++) - { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - Expression *exp = new IntegerExp(0); - exp = Cast(v->type, v->type, exp); - if (exp == EXP_CANT_INTERPRET) - return exp; - elements->push(exp); - } - e = new StructLiteralExp(loc, sd, elements); - e->type = type; - } - else - { - error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars()); - e = new IntegerExp(loc, 0, Type::tint32); - } - return e; -} - - -Expression *ArrayLength(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - - e = new IntegerExp(loc, es1->len, type); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - size_t dim; - - dim = ale->elements ? ale->elements->dim : 0; - e = new IntegerExp(loc, dim, type); - } - else if (e1->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; - size_t dim = ale->keys->dim; - - e = new IntegerExp(loc, dim, type); - } - else - e = EXP_CANT_INTERPRET; - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Index(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - assert(e1->type); - if (e1->op == TOKstring && e2->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t i = e2->toInteger(); - - if (i >= es1->len) - e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", i, es1->len); - else - { unsigned value = es1->charAt(i); - e = new IntegerExp(loc, value, type); - } - } - else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64) - { TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype(); - uinteger_t length = tsa->dim->toInteger(); - uinteger_t i = e2->toInteger(); - - if (i >= length) - { - e2->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length); - } - else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - e = (Expression *)ale->elements->data[i]; - e->type = type; - } - } - else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64) - { - uinteger_t i = e2->toInteger(); - - if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - if (i >= ale->elements->dim) - { - e2->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); - } - else - { e = (Expression *)ale->elements->data[i]; - e->type = type; - } - } - } - else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2)) - { - AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1; - /* Search the keys backwards, in case there are duplicate keys - */ - for (size_t i = ae->keys->dim; i;) - { - i--; - Expression *ekey = (Expression *)ae->keys->data[i]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); - if (ex == EXP_CANT_INTERPRET) - return ex; - if (ex->isBool(TRUE)) - { e = (Expression *)ae->values->data[i]; - e->type = type; - break; - } - } - } - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - -#if LOG - printf("Slice()\n"); - if (lwr) - { printf("\te1 = %s\n", e1->toChars()); - printf("\tlwr = %s\n", lwr->toChars()); - printf("\tupr = %s\n", upr->toChars()); - } -#endif - if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->len || ilwr > iupr) - e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr); - else - { integer_t value; - void *s; - size_t len = iupr - ilwr; - int sz = es1->sz; - StringExp *es; - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz); - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len, es1->postfix); - es->sz = sz; - es->committed = 1; - es->type = type; - e = es; - } - } - else if (e1->op == TOKarrayliteral && - lwr->op == TOKint64 && upr->op == TOKint64 && - !e1->checkSideEffect(2)) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->elements->dim || ilwr > iupr) - e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr); - else - { - Expressions *elements = new Expressions(); - elements->setDim(iupr - ilwr); - memcpy(elements->data, - es1->elements->data + ilwr, - (iupr - ilwr) * sizeof(es1->elements->data[0])); - e = new ArrayLiteralExp(e1->loc, elements); - e->type = type; - } - } - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Cat(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - Type *t; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - - //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - //printf("\tt1 = %s, t2 = %s\n", t1->toChars(), t2->toChars()); - - if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral)) - { e = e2; - goto L2; - } - else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull) - { e = e1; - L2: - Type *tn = e->type->toBasetype(); - if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { - // Create a StringExp - void *s; - StringExp *es; - size_t len = 1; - int sz = tn->size(); - integer_t v = e->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, &v, sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = 1; - e = es; - } - else - { // Create an ArrayLiteralExp - Expressions *elements = new Expressions(); - elements->push(e); - e = new ArrayLiteralExp(e->loc, elements); - } - e->type = type; - return e; - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - Type *t; - size_t len = es1->len + es2->len; - int sz = es1->sz; - - if (sz != es2->sz) - { - /* Can happen with: - * auto s = "foo"d ~ "bar"c; - */ - assert(global.errors); - return e; - } - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed | es2->committed; - if (es1->committed) - t = es1->type; - else - t = es2->type; - es->type = type; - e = es; - } - else if (e1->op == TOKstring && e2->op == TOKint64) - { - // Concatenate the strings - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es; - Type *t; - size_t len = es1->len + 1; - int sz = es1->sz; - integer_t v = e2->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - memcpy((unsigned char *)s + es1->len * sz, &v, sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed; - t = es1->type; - es->type = type; - e = es; - } - else if (e1->op == TOKint64 && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - Type *t; - size_t len = 1 + es2->len; - int sz = es2->sz; - integer_t v = e1->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, &v, sz); - memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es2->committed; - t = es2->type; - es->type = type; - e = es; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && - t1->nextOf()->equals(t2->nextOf())) - { - // Concatenate the arrays - ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->insert(es1->elements->dim, es2->elements); - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKnull && - t1->nextOf()->equals(t2->nextOf())) - { - e = e1; - goto L3; - } - else if (e1->op == TOKnull && e2->op == TOKarrayliteral && - t1->nextOf()->equals(t2->nextOf())) - { - e = e2; - L3: - // Concatenate the array with null - ArrayLiteralExp *es = (ArrayLiteralExp *)e; - - es = new ArrayLiteralExp(es->loc, (Expressions *)es->elements->copy()); - e = es; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) && - e1->type->toBasetype()->nextOf()->equals(e2->type)) - { - ArrayLiteralExp *es1; - if (e1->op == TOKarrayliteral) - { es1 = (ArrayLiteralExp *)e1; - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->push(e2); - } - else - { - es1 = new ArrayLiteralExp(e1->loc, e2); - } - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e2->type, new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e2->op == TOKarrayliteral && - e2->type->toBasetype()->nextOf()->equals(e1->type)) - { - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy()); - es2->elements->shift(e1); - e = es2; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e1->type, new IntegerExp(loc, es2->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKnull && e2->op == TOKstring) - { - t = e1->type; - e = e2; - goto L1; - } - else if (e1->op == TOKstring && e2->op == TOKnull) - { e = e1; - t = e2->type; - L1: - Type *tb = t->toBasetype(); - if (tb->ty == Tarray && tb->nextOf()->equals(e->type)) - { Expressions *expressions = new Expressions(); - expressions->push(e); - e = new ArrayLiteralExp(loc, expressions); - e->type = t; - } - if (!e->type->equals(type)) - { StringExp *se = (StringExp *)e->copy(); - e = se->castTo(NULL, type); - } - } - return e; -} - -Expression *Ptr(Type *type, Expression *e1) -{ - //printf("Ptr(e1 = %s)\n", e1->toChars()); - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - if (ade->e1->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ade->e1; - unsigned offset = ae->e2->toInteger(); - Expression *e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - } - return EXP_CANT_INTERPRET; -} - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include +#include + +#if __DMC__ +#include +#endif + +#include "rmem.h" +#include "root.h" +#include "port.h" + +#include "mtype.h" +#include "expression.h" +#include "aggregate.h" +#include "declaration.h" + +#if __FreeBSD__ +#define fmodl fmod // hack for now, fix later +#endif + +#define LOG 0 + +Expression *expType(Type *type, Expression *e) +{ + if (type != e->type) + { + e = e->copy(); + e->type = type; + } + return e; +} + +/* ================================== isConst() ============================== */ + +int Expression::isConst() +{ + //printf("Expression::isConst(): %s\n", toChars()); + return 0; +} + +int IntegerExp::isConst() +{ + return 1; +} + +int RealExp::isConst() +{ + return 1; +} + +int ComplexExp::isConst() +{ + return 1; +} + +int SymOffExp::isConst() +{ + return 2; +} + +/* =============================== constFold() ============================== */ + +/* The constFold() functions were redundant with the optimize() ones, + * and so have been folded in with them. + */ + +/* ========================================================================== */ + +Expression *Neg(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + if (e1->type->isreal()) + { + e = new RealExp(loc, -e1->toReal(), type); + } + else if (e1->type->isimaginary()) + { + e = new RealExp(loc, -e1->toImaginary(), type); + } + else if (e1->type->iscomplex()) + { + e = new ComplexExp(loc, -e1->toComplex(), type); + } + else + e = new IntegerExp(loc, -e1->toInteger(), type); + return e; +} + +Expression *Com(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, ~e1->toInteger(), type); + return e; +} + +Expression *Not(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->isBool(0), type); + return e; +} + +Expression *Bool(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->isBool(1), type); + return e; +} + +Expression *Add(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + +#if LOG + printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); +#endif + if (type->isreal()) + { + e = new RealExp(loc, e1->toReal() + e2->toReal(), type); + } + else if (type->isimaginary()) + { + e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type); + } + else if (type->iscomplex()) + { + // This rigamarole is necessary so that -0.0 doesn't get + // converted to +0.0 by doing an extraneous add with +0.0 + complex_t c1; + real_t r1; + real_t i1; + + complex_t c2; + real_t r2; + real_t i2; + + complex_t v; + int x; + + if (e1->type->isreal()) + { r1 = e1->toReal(); + x = 0; + } + else if (e1->type->isimaginary()) + { i1 = e1->toImaginary(); + x = 3; + } + else + { c1 = e1->toComplex(); + x = 6; + } + + if (e2->type->isreal()) + { r2 = e2->toReal(); + } + else if (e2->type->isimaginary()) + { i2 = e2->toImaginary(); + x += 1; + } + else + { c2 = e2->toComplex(); + x += 2; + } + + switch (x) + { +#if __DMC__ + case 0+0: v = (complex_t) (r1 + r2); break; + case 0+1: v = r1 + i2 * I; break; + case 0+2: v = r1 + c2; break; + case 3+0: v = i1 * I + r2; break; + case 3+1: v = (complex_t) ((i1 + i2) * I); break; + case 3+2: v = i1 * I + c2; break; + case 6+0: v = c1 + r2; break; + case 6+1: v = c1 + i2 * I; break; + case 6+2: v = c1 + c2; break; +#else + case 0+0: v = complex_t(r1 + r2, 0); break; + case 0+1: v = complex_t(r1, i2); break; + case 0+2: v = complex_t(r1 + creall(c2), cimagl(c2)); break; + case 3+0: v = complex_t(r2, i1); break; + case 3+1: v = complex_t(0, i1 + i2); break; + case 3+2: v = complex_t(creall(c2), i1 + cimagl(c2)); break; + case 6+0: v = complex_t(creall(c1) + r2, cimagl(c2)); break; + case 6+1: v = complex_t(creall(c1), cimagl(c1) + i2); break; + case 6+2: v = c1 + c2; break; +#endif + default: assert(0); + } + e = new ComplexExp(loc, v, type); + } + else if (e1->op == TOKsymoff) + { + SymOffExp *soe = (SymOffExp *)e1; + e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger()); + e->type = type; + } + else if (e2->op == TOKsymoff) + { + SymOffExp *soe = (SymOffExp *)e2; + e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger()); + e->type = type; + } + else + e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type); + return e; +} + + +Expression *Min(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isreal()) + { + e = new RealExp(loc, e1->toReal() - e2->toReal(), type); + } + else if (type->isimaginary()) + { + e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type); + } + else if (type->iscomplex()) + { + // This rigamarole is necessary so that -0.0 doesn't get + // converted to +0.0 by doing an extraneous add with +0.0 + complex_t c1; + real_t r1; + real_t i1; + + complex_t c2; + real_t r2; + real_t i2; + + complex_t v; + int x; + + if (e1->type->isreal()) + { r1 = e1->toReal(); + x = 0; + } + else if (e1->type->isimaginary()) + { i1 = e1->toImaginary(); + x = 3; + } + else + { c1 = e1->toComplex(); + x = 6; + } + + if (e2->type->isreal()) + { r2 = e2->toReal(); + } + else if (e2->type->isimaginary()) + { i2 = e2->toImaginary(); + x += 1; + } + else + { c2 = e2->toComplex(); + x += 2; + } + + switch (x) + { +#if __DMC__ + case 0+0: v = (complex_t) (r1 - r2); break; + case 0+1: v = r1 - i2 * I; break; + case 0+2: v = r1 - c2; break; + case 3+0: v = i1 * I - r2; break; + case 3+1: v = (complex_t) ((i1 - i2) * I); break; + case 3+2: v = i1 * I - c2; break; + case 6+0: v = c1 - r2; break; + case 6+1: v = c1 - i2 * I; break; + case 6+2: v = c1 - c2; break; +#else + case 0+0: v = complex_t(r1 - r2, 0); break; + case 0+1: v = complex_t(r1, -i2); break; + case 0+2: v = complex_t(r1 - creall(c2), -cimagl(c2)); break; + case 3+0: v = complex_t(-r2, i1); break; + case 3+1: v = complex_t(0, i1 - i2); break; + case 3+2: v = complex_t(-creall(c2), i1 - cimagl(c2)); break; + case 6+0: v = complex_t(creall(c1) - r2, cimagl(c1)); break; + case 6+1: v = complex_t(creall(c1), cimagl(c1) - i2); break; + case 6+2: v = c1 - c2; break; +#endif + default: assert(0); + } + e = new ComplexExp(loc, v, type); + } + else if (e1->op == TOKsymoff) + { + SymOffExp *soe = (SymOffExp *)e1; + e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger()); + e->type = type; + } + else + { + e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type); + } + return e; +} + +Expression *Mul(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isfloating()) + { complex_t c; +#ifdef IN_GCC + real_t r; +#else + d_float80 r; +#endif + + if (e1->type->isreal()) + { +#if __DMC__ + c = e1->toReal() * e2->toComplex(); +#else + r = e1->toReal(); + c = e2->toComplex(); + c = complex_t(r * creall(c), r * cimagl(c)); +#endif + } + else if (e1->type->isimaginary()) + { +#if __DMC__ + c = e1->toImaginary() * I * e2->toComplex(); +#else + r = e1->toImaginary(); + c = e2->toComplex(); + c = complex_t(-r * cimagl(c), r * creall(c)); +#endif + } + else if (e2->type->isreal()) + { +#if __DMC__ + c = e2->toReal() * e1->toComplex(); +#else + r = e2->toReal(); + c = e1->toComplex(); + c = complex_t(r * creall(c), r * cimagl(c)); +#endif + } + else if (e2->type->isimaginary()) + { +#if __DMC__ + c = e1->toComplex() * e2->toImaginary() * I; +#else + r = e2->toImaginary(); + c = e1->toComplex(); + c = complex_t(-r * cimagl(c), r * creall(c)); +#endif + } + else + c = e1->toComplex() * e2->toComplex(); + + if (type->isreal()) + e = new RealExp(loc, creall(c), type); + else if (type->isimaginary()) + e = new RealExp(loc, cimagl(c), type); + else if (type->iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { + e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type); + } + return e; +} + +Expression *Div(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isfloating()) + { complex_t c; +#ifdef IN_GCC + real_t r; +#else + d_float80 r; +#endif + + //e1->type->print(); + //e2->type->print(); + if (e2->type->isreal()) + { + if (e1->type->isreal()) + { + e = new RealExp(loc, e1->toReal() / e2->toReal(), type); + return e; + } +#if __DMC__ + //r = e2->toReal(); + //c = e1->toComplex(); + //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r); + + c = e1->toComplex() / e2->toReal(); +#else + r = e2->toReal(); + c = e1->toComplex(); + c = complex_t(creall(c) / r, cimagl(c) / r); +#endif + } + else if (e2->type->isimaginary()) + { +#if __DMC__ + //r = e2->toImaginary(); + //c = e1->toComplex(); + //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r); + + c = e1->toComplex() / (e2->toImaginary() * I); +#else + r = e2->toImaginary(); + c = e1->toComplex(); + c = complex_t(cimagl(c) / r, -creall(c) / r); +#endif + } + else + { + c = e1->toComplex() / e2->toComplex(); + } + + if (type->isreal()) + e = new RealExp(loc, creall(c), type); + else if (type->isimaginary()) + e = new RealExp(loc, cimagl(c), type); + else if (type->iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { sinteger_t n1; + sinteger_t n2; + sinteger_t n; + + n1 = e1->toInteger(); + n2 = e2->toInteger(); + if (n2 == 0) + { e2->error("divide by 0"); + e2 = new IntegerExp(loc, 1, e2->type); + n2 = 1; + } + if (e1->type->isunsigned() || e2->type->isunsigned()) + n = ((d_uns64) n1) / ((d_uns64) n2); + else + n = n1 / n2; + e = new IntegerExp(loc, n, type); + } + return e; +} + +Expression *Mod(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isfloating()) + { + complex_t c; + + if (e2->type->isreal()) + { real_t r2 = e2->toReal(); + +#ifdef __DMC__ + c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I; +#elif defined(IN_GCC) + c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2); +#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) + // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! + // arm also doesn't like fmodl + c = complex_t(fmod(e1->toReal(), r2), fmod(e1->toImaginary(), r2)); +#else + c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2)); +#endif + } + else if (e2->type->isimaginary()) + { real_t i2 = e2->toImaginary(); + +#ifdef __DMC__ + c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I; +#elif defined(IN_GCC) + c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2); +#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) + // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! + // arm also doesn't like fmodl + c = complex_t(fmod(e1->toReal(), i2), fmod(e1->toImaginary(), i2)); +#else + c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2)); +#endif + } + else + assert(0); + + if (type->isreal()) + e = new RealExp(loc, creall(c), type); + else if (type->isimaginary()) + e = new RealExp(loc, cimagl(c), type); + else if (type->iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { sinteger_t n1; + sinteger_t n2; + sinteger_t n; + + n1 = e1->toInteger(); + n2 = e2->toInteger(); + if (n2 == 0) + { e2->error("divide by 0"); + e2 = new IntegerExp(loc, 1, e2->type); + n2 = 1; + } + if (e1->type->isunsigned() || e2->type->isunsigned()) + n = ((d_uns64) n1) % ((d_uns64) n2); + else + n = n1 % n2; + e = new IntegerExp(loc, n, type); + } + return e; +} + +Expression *Shl(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type); + return e; +} + +Expression *Shr(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + unsigned count; + dinteger_t value; + + value = e1->toInteger(); + count = e2->toInteger(); + switch (e1->type->toBasetype()->ty) + { + case Tint8: + value = (d_int8)(value) >> count; + break; + + case Tuns8: + value = (d_uns8)(value) >> count; + break; + + case Tint16: + value = (d_int16)(value) >> count; + break; + + case Tuns16: + value = (d_uns16)(value) >> count; + break; + + case Tint32: + value = (d_int32)(value) >> count; + break; + + case Tuns32: + value = (d_uns32)(value) >> count; + break; + + case Tint64: + value = (d_int64)(value) >> count; + break; + + case Tuns64: + value = (d_uns64)(value) >> count; + break; + + default: + assert(0); + } + e = new IntegerExp(loc, value, type); + return e; +} + +Expression *Ushr(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + unsigned count; + dinteger_t value; + + value = e1->toInteger(); + count = e2->toInteger(); + switch (e1->type->toBasetype()->ty) + { + case Tint8: + case Tuns8: + assert(0); // no way to trigger this + value = (value & 0xFF) >> count; + break; + + case Tint16: + case Tuns16: + assert(0); // no way to trigger this + value = (value & 0xFFFF) >> count; + break; + + case Tint32: + case Tuns32: + value = (value & 0xFFFFFFFF) >> count; + break; + + case Tint64: + case Tuns64: + value = (d_uns64)(value) >> count; + break; + + default: + assert(0); + } + e = new IntegerExp(loc, value, type); + return e; +} + +Expression *And(Type *type, Expression *e1, Expression *e2) +{ + Expression *e; + e = new IntegerExp(e1->loc, e1->toInteger() & e2->toInteger(), type); + return e; +} + +Expression *Or(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + e = new IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type); + return e; +} + +Expression *Xor(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + e = new IntegerExp(e1->loc, e1->toInteger() ^ e2->toInteger(), type); + return e; +} + +/* Also returns EXP_CANT_INTERPRET if cannot be computed. + */ +Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + int cmp; + real_t r1; + real_t r2; + + //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + + assert(op == TOKequal || op == TOKnotequal); + + if (e1->op == TOKnull) + { + if (e2->op == TOKnull) + cmp = 1; + else if (e2->op == TOKstring) + { StringExp *es2 = (StringExp *)e2; + cmp = (0 == es2->len); + } + else if (e2->op == TOKarrayliteral) + { ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + cmp = !es2->elements || (0 == es2->elements->dim); + } + else + return EXP_CANT_INTERPRET; + } + else if (e2->op == TOKnull) + { + if (e1->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + cmp = (0 == es1->len); + } + else if (e1->op == TOKarrayliteral) + { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + cmp = !es1->elements || (0 == es1->elements->dim); + } + else + return EXP_CANT_INTERPRET; + } + else if (e1->op == TOKstring && e2->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + StringExp *es2 = (StringExp *)e2; + + if (es1->sz != es2->sz) + { + assert(global.errors); + return EXP_CANT_INTERPRET; + } + if (es1->len == es2->len && + memcmp(es1->string, es2->string, es1->sz * es1->len) == 0) + cmp = 1; + else + cmp = 0; + } + else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral) + { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + if ((!es1->elements || !es1->elements->dim) && + (!es2->elements || !es2->elements->dim)) + cmp = 1; // both arrays are empty + else if (!es1->elements || !es2->elements) + cmp = 0; + else if (es1->elements->dim != es2->elements->dim) + cmp = 0; + else + { + for (size_t i = 0; i < es1->elements->dim; i++) + { Expression *ee1 = (Expression *)es1->elements->data[i]; + Expression *ee2 = (Expression *)es2->elements->data[i]; + + Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); + if (v == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + cmp = v->toInteger(); + if (cmp == 0) + break; + } + } + } + else if (e1->op == TOKarrayliteral && e2->op == TOKstring) + { // Swap operands and use common code + Expression *e = e1; + e1 = e2; + e2 = e; + goto Lsa; + } + else if (e1->op == TOKstring && e2->op == TOKarrayliteral) + { + Lsa: + StringExp *es1 = (StringExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + size_t dim1 = es1->len; + size_t dim2 = es2->elements ? es2->elements->dim : 0; + if (dim1 != dim2) + cmp = 0; + else + { + for (size_t i = 0; i < dim1; i++) + { + uinteger_t c = es1->charAt(i); + Expression *ee2 = (Expression *)es2->elements->data[i]; + if (ee2->isConst() != 1) + return EXP_CANT_INTERPRET; + cmp = (c == ee2->toInteger()); + if (cmp == 0) + break; + } + } + } + else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) + { StructLiteralExp *es1 = (StructLiteralExp *)e1; + StructLiteralExp *es2 = (StructLiteralExp *)e2; + + if (es1->sd != es2->sd) + cmp = 0; + else if ((!es1->elements || !es1->elements->dim) && + (!es2->elements || !es2->elements->dim)) + cmp = 1; // both arrays are empty + else if (!es1->elements || !es2->elements) + cmp = 0; + else if (es1->elements->dim != es2->elements->dim) + cmp = 0; + else + { + cmp = 1; + for (size_t i = 0; i < es1->elements->dim; i++) + { Expression *ee1 = (Expression *)es1->elements->data[i]; + Expression *ee2 = (Expression *)es2->elements->data[i]; + + if (ee1 == ee2) + continue; + if (!ee1 || !ee2) + { cmp = 0; + break; + } + Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); + if (v == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + cmp = v->toInteger(); + if (cmp == 0) + break; + } + } + } +#if 0 // Should handle this + else if (e1->op == TOKarrayliteral && e2->op == TOKstring) + { + } +#endif + else if (e1->isConst() != 1 || e2->isConst() != 1) + return EXP_CANT_INTERPRET; + else if (e1->type->isreal()) + { + r1 = e1->toReal(); + r2 = e2->toReal(); + goto L1; + } + else if (e1->type->isimaginary()) + { + r1 = e1->toImaginary(); + r2 = e2->toImaginary(); + L1: +#if __DMC__ + cmp = (r1 == r2); +#else + if (Port::isNan(r1) || Port::isNan(r2)) // if unordered + { + cmp = 0; + } + else + { + cmp = (r1 == r2); + } +#endif + } + else if (e1->type->iscomplex()) + { + cmp = e1->toComplex() == e2->toComplex(); + } + else if (e1->type->isintegral()) + { + cmp = (e1->toInteger() == e2->toInteger()); + } + else + return EXP_CANT_INTERPRET; + if (op == TOKnotequal) + cmp ^= 1; + e = new IntegerExp(loc, cmp, type); + return e; +} + +Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + int cmp; + + if (e1->op == TOKnull && e2->op == TOKnull) + { + cmp = 1; + } + else if (e1->op == TOKsymoff && e2->op == TOKsymoff) + { + SymOffExp *es1 = (SymOffExp *)e1; + SymOffExp *es2 = (SymOffExp *)e2; + + cmp = (es1->var == es2->var && es1->offset == es2->offset); + } + else if (e1->isConst() == 1 && e2->isConst() == 1) + return Equal((op == TOKidentity) ? TOKequal : TOKnotequal, + type, e1, e2); + else + assert(0); + if (op == TOKnotidentity) + cmp ^= 1; + return new IntegerExp(loc, cmp, type); +} + + +Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + dinteger_t n; + real_t r1; + real_t r2; + + //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + + if (e1->op == TOKstring && e2->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + StringExp *es2 = (StringExp *)e2; + size_t sz = es1->sz; + assert(sz == es2->sz); + + size_t len = es1->len; + if (es2->len < len) + len = es2->len; + + int cmp = memcmp(es1->string, es2->string, sz * len); + if (cmp == 0) + cmp = es1->len - es2->len; + + switch (op) + { + case TOKlt: n = cmp < 0; break; + case TOKle: n = cmp <= 0; break; + case TOKgt: n = cmp > 0; break; + case TOKge: n = cmp >= 0; break; + + case TOKleg: n = 1; break; + case TOKlg: n = cmp != 0; break; + case TOKunord: n = 0; break; + case TOKue: n = cmp == 0; break; + case TOKug: n = cmp > 0; break; + case TOKuge: n = cmp >= 0; break; + case TOKul: n = cmp < 0; break; + case TOKule: n = cmp <= 0; break; + + default: + assert(0); + } + } + else if (e1->isConst() != 1 || e2->isConst() != 1) + return EXP_CANT_INTERPRET; + else if (e1->type->isreal()) + { + r1 = e1->toReal(); + r2 = e2->toReal(); + goto L1; + } + else if (e1->type->isimaginary()) + { + r1 = e1->toImaginary(); + r2 = e2->toImaginary(); + L1: +#if __DMC__ + // DMC is the only compiler I know of that handles NAN arguments + // correctly in comparisons. + switch (op) + { + case TOKlt: n = r1 < r2; break; + case TOKle: n = r1 <= r2; break; + case TOKgt: n = r1 > r2; break; + case TOKge: n = r1 >= r2; break; + + case TOKleg: n = r1 <>= r2; break; + case TOKlg: n = r1 <> r2; break; + case TOKunord: n = r1 !<>= r2; break; + case TOKue: n = r1 !<> r2; break; + case TOKug: n = r1 !<= r2; break; + case TOKuge: n = r1 !< r2; break; + case TOKul: n = r1 !>= r2; break; + case TOKule: n = r1 !> r2; break; + + default: + assert(0); + } +#else + // Don't rely on compiler, handle NAN arguments separately + if (Port::isNan(r1) || Port::isNan(r2)) // if unordered + { + switch (op) + { + case TOKlt: n = 0; break; + case TOKle: n = 0; break; + case TOKgt: n = 0; break; + case TOKge: n = 0; break; + + case TOKleg: n = 0; break; + case TOKlg: n = 0; break; + case TOKunord: n = 1; break; + case TOKue: n = 1; break; + case TOKug: n = 1; break; + case TOKuge: n = 1; break; + case TOKul: n = 1; break; + case TOKule: n = 1; break; + + default: + assert(0); + } + } + else + { + switch (op) + { + case TOKlt: n = r1 < r2; break; + case TOKle: n = r1 <= r2; break; + case TOKgt: n = r1 > r2; break; + case TOKge: n = r1 >= r2; break; + + case TOKleg: n = 1; break; + case TOKlg: n = r1 != r2; break; + case TOKunord: n = 0; break; + case TOKue: n = r1 == r2; break; + case TOKug: n = r1 > r2; break; + case TOKuge: n = r1 >= r2; break; + case TOKul: n = r1 < r2; break; + case TOKule: n = r1 <= r2; break; + + default: + assert(0); + } + } +#endif + } + else if (e1->type->iscomplex()) + { + assert(0); + } + else + { sinteger_t n1; + sinteger_t n2; + + n1 = e1->toInteger(); + n2 = e2->toInteger(); + if (e1->type->isunsigned() || e2->type->isunsigned()) + { + switch (op) + { + case TOKlt: n = ((d_uns64) n1) < ((d_uns64) n2); break; + case TOKle: n = ((d_uns64) n1) <= ((d_uns64) n2); break; + case TOKgt: n = ((d_uns64) n1) > ((d_uns64) n2); break; + case TOKge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; + + case TOKleg: n = 1; break; + case TOKlg: n = ((d_uns64) n1) != ((d_uns64) n2); break; + case TOKunord: n = 0; break; + case TOKue: n = ((d_uns64) n1) == ((d_uns64) n2); break; + case TOKug: n = ((d_uns64) n1) > ((d_uns64) n2); break; + case TOKuge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; + case TOKul: n = ((d_uns64) n1) < ((d_uns64) n2); break; + case TOKule: n = ((d_uns64) n1) <= ((d_uns64) n2); break; + + default: + assert(0); + } + } + else + { + switch (op) + { + case TOKlt: n = n1 < n2; break; + case TOKle: n = n1 <= n2; break; + case TOKgt: n = n1 > n2; break; + case TOKge: n = n1 >= n2; break; + + case TOKleg: n = 1; break; + case TOKlg: n = n1 != n2; break; + case TOKunord: n = 0; break; + case TOKue: n = n1 == n2; break; + case TOKug: n = n1 > n2; break; + case TOKuge: n = n1 >= n2; break; + case TOKul: n = n1 < n2; break; + case TOKule: n = n1 <= n2; break; + + default: + assert(0); + } + } + } + e = new IntegerExp(loc, n, type); + return e; +} + +/* Also returns EXP_CANT_INTERPRET if cannot be computed. + * to: type to cast to + * type: type to paint the result + */ + +Expression *Cast(Type *type, Type *to, Expression *e1) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + + //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); + //printf("\te1->type = %s\n", e1->type->toChars()); + if (e1->type->equals(type) && type->equals(to)) + return e1; + if (e1->type->implicitConvTo(to) >= MATCHconst || + to->implicitConvTo(e1->type) >= MATCHconst) + return expType(to, e1); + + Type *tb = to->toBasetype(); + Type *typeb = type->toBasetype(); + + if (e1->op == TOKstring) + { + if (tb->ty == Tarray && typeb->ty == Tarray && + tb->nextOf()->size() == typeb->nextOf()->size()) + { + return expType(to, e1); + } + } + + if (e1->isConst() != 1) + return EXP_CANT_INTERPRET; + + if (tb->ty == Tbool) + e = new IntegerExp(loc, e1->toInteger() != 0, type); + else if (type->isintegral()) + { + if (e1->type->isfloating()) + { dinteger_t result; + real_t r = e1->toReal(); + + switch (typeb->ty) + { + case Tint8: result = (d_int8)r; break; + case Tchar: + case Tuns8: result = (d_uns8)r; break; + case Tint16: result = (d_int16)r; break; + case Twchar: + case Tuns16: result = (d_uns16)r; break; + case Tint32: result = (d_int32)r; break; + case Tdchar: + case Tuns32: result = (d_uns32)r; break; + case Tint64: result = (d_int64)r; break; + case Tuns64: result = (d_uns64)r; break; + default: + assert(0); + } + + e = new IntegerExp(loc, result, type); + } + else if (type->isunsigned()) + e = new IntegerExp(loc, e1->toUInteger(), type); + else + e = new IntegerExp(loc, e1->toInteger(), type); + } + else if (tb->isreal()) + { real_t value = e1->toReal(); + + e = new RealExp(loc, value, type); + } + else if (tb->isimaginary()) + { real_t value = e1->toImaginary(); + + e = new RealExp(loc, value, type); + } + else if (tb->iscomplex()) + { complex_t value = e1->toComplex(); + + e = new ComplexExp(loc, value, type); + } + else if (tb->isscalar()) + e = new IntegerExp(loc, e1->toInteger(), type); + else if (tb->ty == Tvoid) + e = EXP_CANT_INTERPRET; + else if (tb->ty == Tstruct && e1->op == TOKint64) + { // Struct = 0; + StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration(); + assert(sd); + Expressions *elements = new Expressions; + for (size_t i = 0; i < sd->fields.dim; i++) + { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + + Expression *exp = new IntegerExp(0); + exp = Cast(v->type, v->type, exp); + if (exp == EXP_CANT_INTERPRET) + return exp; + elements->push(exp); + } + e = new StructLiteralExp(loc, sd, elements); + e->type = type; + } + else + { + error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars()); + e = new IntegerExp(loc, 0, Type::tint32); + } + return e; +} + + +Expression *ArrayLength(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + if (e1->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + + e = new IntegerExp(loc, es1->len, type); + } + else if (e1->op == TOKarrayliteral) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + size_t dim; + + dim = ale->elements ? ale->elements->dim : 0; + e = new IntegerExp(loc, dim, type); + } + else if (e1->op == TOKassocarrayliteral) + { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; + size_t dim = ale->keys->dim; + + e = new IntegerExp(loc, dim, type); + } + else + e = EXP_CANT_INTERPRET; + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Index(Type *type, Expression *e1, Expression *e2) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + + //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + assert(e1->type); + if (e1->op == TOKstring && e2->op == TOKint64) + { StringExp *es1 = (StringExp *)e1; + uinteger_t i = e2->toInteger(); + + if (i >= es1->len) + e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len); + else + { unsigned value = es1->charAt(i); + e = new IntegerExp(loc, value, type); + } + } + else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64) + { TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype(); + uinteger_t length = tsa->dim->toInteger(); + uinteger_t i = e2->toInteger(); + + if (i >= length) + { e2->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length); + } + else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + e = (Expression *)ale->elements->data[i]; + e->type = type; + } + } + else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64) + { + uinteger_t i = e2->toInteger(); + + if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + if (i >= ale->elements->dim) + { e2->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); + } + else + { e = (Expression *)ale->elements->data[i]; + e->type = type; + } + } + } + else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2)) + { + AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1; + /* Search the keys backwards, in case there are duplicate keys + */ + for (size_t i = ae->keys->dim; i;) + { + i--; + Expression *ekey = (Expression *)ae->keys->data[i]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); + if (ex == EXP_CANT_INTERPRET) + return ex; + if (ex->isBool(TRUE)) + { e = (Expression *)ae->values->data[i]; + e->type = type; + break; + } + } + } + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + +#if LOG + printf("Slice()\n"); + if (lwr) + { printf("\te1 = %s\n", e1->toChars()); + printf("\tlwr = %s\n", lwr->toChars()); + printf("\tupr = %s\n", upr->toChars()); + } +#endif + if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64) + { StringExp *es1 = (StringExp *)e1; + uinteger_t ilwr = lwr->toInteger(); + uinteger_t iupr = upr->toInteger(); + + if (iupr > es1->len || ilwr > iupr) + e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr); + else + { dinteger_t value; + void *s; + size_t len = iupr - ilwr; + int sz = es1->sz; + StringExp *es; + + s = mem.malloc((len + 1) * sz); + memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz); + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len, es1->postfix); + es->sz = sz; + es->committed = 1; + es->type = type; + e = es; + } + } + else if (e1->op == TOKarrayliteral && + lwr->op == TOKint64 && upr->op == TOKint64 && + !e1->checkSideEffect(2)) + { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + uinteger_t ilwr = lwr->toInteger(); + uinteger_t iupr = upr->toInteger(); + + if (iupr > es1->elements->dim || ilwr > iupr) + e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr); + else + { + Expressions *elements = new Expressions(); + elements->setDim(iupr - ilwr); + memcpy(elements->data, + es1->elements->data + ilwr, + (iupr - ilwr) * sizeof(es1->elements->data[0])); + e = new ArrayLiteralExp(e1->loc, elements); + e->type = type; + } + } + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Cat(Type *type, Expression *e1, Expression *e2) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + Type *t; + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + + //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + //printf("\tt1 = %s, t2 = %s\n", t1->toChars(), t2->toChars()); + + if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral)) + { e = e2; + goto L2; + } + else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull) + { e = e1; + L2: + Type *tn = e->type->toBasetype(); + if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) + { + // Create a StringExp + void *s; + StringExp *es; + size_t len = 1; + int sz = tn->size(); + dinteger_t v = e->toInteger(); + + s = mem.malloc((len + 1) * sz); + memcpy((unsigned char *)s, &v, sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = 1; + e = es; + } + else + { // Create an ArrayLiteralExp + Expressions *elements = new Expressions(); + elements->push(e); + e = new ArrayLiteralExp(e->loc, elements); + } + e->type = type; + return e; + } + else if (e1->op == TOKstring && e2->op == TOKstring) + { + // Concatenate the strings + void *s; + StringExp *es1 = (StringExp *)e1; + StringExp *es2 = (StringExp *)e2; + StringExp *es; + Type *t; + size_t len = es1->len + es2->len; + int sz = es1->sz; + + if (sz != es2->sz) + { + /* Can happen with: + * auto s = "foo"d ~ "bar"c; + */ + assert(global.errors); + return e; + } + s = mem.malloc((len + 1) * sz); + memcpy(s, es1->string, es1->len * sz); + memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = es1->committed | es2->committed; + if (es1->committed) + t = es1->type; + else + t = es2->type; + es->type = type; + e = es; + } + else if (e1->op == TOKstring && e2->op == TOKint64) + { + // Concatenate the strings + void *s; + StringExp *es1 = (StringExp *)e1; + StringExp *es; + Type *t; + size_t len = es1->len + 1; + int sz = es1->sz; + dinteger_t v = e2->toInteger(); + + s = mem.malloc((len + 1) * sz); + memcpy(s, es1->string, es1->len * sz); + memcpy((unsigned char *)s + es1->len * sz, &v, sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = es1->committed; + t = es1->type; + es->type = type; + e = es; + } + else if (e1->op == TOKint64 && e2->op == TOKstring) + { + // Concatenate the strings + void *s; + StringExp *es2 = (StringExp *)e2; + StringExp *es; + Type *t; + size_t len = 1 + es2->len; + int sz = es2->sz; + dinteger_t v = e1->toInteger(); + + s = mem.malloc((len + 1) * sz); + memcpy((unsigned char *)s, &v, sz); + memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = es2->committed; + t = es2->type; + es->type = type; + e = es; + } + else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && + t1->nextOf()->equals(t2->nextOf())) + { + // Concatenate the arrays + ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); + es1->elements->insert(es1->elements->dim, es2->elements); + e = es1; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es1->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if (e1->op == TOKarrayliteral && e2->op == TOKnull && + t1->nextOf()->equals(t2->nextOf())) + { + e = e1; + goto L3; + } + else if (e1->op == TOKnull && e2->op == TOKarrayliteral && + t1->nextOf()->equals(t2->nextOf())) + { + e = e2; + L3: + // Concatenate the array with null + ArrayLiteralExp *es = (ArrayLiteralExp *)e; + + es = new ArrayLiteralExp(es->loc, (Expressions *)es->elements->copy()); + e = es; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) && + e1->type->toBasetype()->nextOf()->equals(e2->type)) + { + ArrayLiteralExp *es1; + if (e1->op == TOKarrayliteral) + { es1 = (ArrayLiteralExp *)e1; + es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); + es1->elements->push(e2); + } + else + { + es1 = new ArrayLiteralExp(e1->loc, e2); + } + e = es1; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(e2->type, new IntegerExp(loc, es1->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if (e2->op == TOKarrayliteral && + e2->type->toBasetype()->nextOf()->equals(e1->type)) + { + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy()); + es2->elements->shift(e1); + e = es2; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(e1->type, new IntegerExp(loc, es2->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if (e1->op == TOKnull && e2->op == TOKstring) + { + t = e1->type; + e = e2; + goto L1; + } + else if (e1->op == TOKstring && e2->op == TOKnull) + { e = e1; + t = e2->type; + L1: + Type *tb = t->toBasetype(); + if (tb->ty == Tarray && tb->nextOf()->equals(e->type)) + { Expressions *expressions = new Expressions(); + expressions->push(e); + e = new ArrayLiteralExp(loc, expressions); + e->type = t; + } + if (!e->type->equals(type)) + { StringExp *se = (StringExp *)e->copy(); + e = se->castTo(NULL, type); + } + } + return e; +} + +Expression *Ptr(Type *type, Expression *e1) +{ + //printf("Ptr(e1 = %s)\n", e1->toChars()); + if (e1->op == TOKadd) + { AddExp *ae = (AddExp *)e1; + if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) + { AddrExp *ade = (AddrExp *)ae->e1; + if (ade->e1->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ade->e1; + unsigned offset = ae->e2->toInteger(); + Expression *e = se->getField(type, offset); + if (!e) + e = EXP_CANT_INTERPRET; + return e; + } + } + } + return EXP_CANT_INTERPRET; +} + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/cppmangle.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/cppmangle.c Sat May 30 17:23:32 2009 +0100 @@ -0,0 +1,381 @@ + +// 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. + +#include +#include + +#include "mars.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" + +#if DMDV2 + +/* Do mangling for C++ linkage. + * Follows Itanium C++ ABI 1.86 + * No attempt is made to support mangling of templates, operator + * overloading, or special functions. + * + * So why don't we use the C++ ABI for D name mangling? + * Because D supports a lot of things (like modules) that the C++ + * ABI has no concept of. These affect every D mangled name, + * so nothing would be compatible anyway. + */ + +struct CppMangleState +{ + static Array components; + + int substitute(OutBuffer *buf, void *p); +}; + +Array CppMangleState::components; + + +void writeBase36(OutBuffer *buf, unsigned i) +{ + if (i >= 36) + { + writeBase36(buf, i / 36); + i %= 36; + } + if (i < 10) + buf->writeByte(i + '0'); + else if (i < 36) + buf->writeByte(i - 10 + 'A'); + else + assert(0); +} + +int CppMangleState::substitute(OutBuffer *buf, void *p) +{ + for (size_t i = 0; i < components.dim; i++) + { + if (p == components.data[i]) + { + /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... + */ + buf->writeByte('S'); + if (i) + writeBase36(buf, i - 1); + buf->writeByte('_'); + return 1; + } + } + components.push(p); + return 0; +} + +void source_name(OutBuffer *buf, Dsymbol *s) +{ + char *name = s->ident->toChars(); + buf->printf("%d%s", strlen(name), name); +} + +void prefix_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s) +{ + if (!cms->substitute(buf, s)) + { + Dsymbol *p = s->toParent(); + if (p && !p->isModule()) + { + prefix_name(buf, cms, p); + } + source_name(buf, s); + } +} + +void cpp_mangle_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s) +{ + Dsymbol *p = s->toParent(); + if (p && !p->isModule()) + { + buf->writeByte('N'); + + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd->isConst()) + buf->writeByte('K'); + + prefix_name(buf, cms, p); + source_name(buf, s); + + buf->writeByte('E'); + } + else + source_name(buf, s); +} + + +char *cpp_mangle(Dsymbol *s) +{ + /* + * ::= _Z + * ::= + * ::= + * ::= + */ + + CppMangleState cms; + memset(&cms, 0, sizeof(cms)); + cms.components.setDim(0); + + OutBuffer buf; +#if MACHOBJ + buf.writestring("__Z"); +#else + buf.writestring("_Z"); +#endif + + cpp_mangle_name(&buf, &cms, s); + + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { // add + TypeFunction *tf = (TypeFunction *)fd->type; + assert(tf->ty == Tfunction); + Argument::argsCppMangle(&buf, &cms, tf->parameters, tf->varargs); + } + buf.writeByte(0); + return (char *)buf.extractData(); +} + +/* ============= Type Encodings ============================================= */ + +void Type::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + /* Make this the 'vendor extended type' when there is no + * C++ analog. + * u + */ + if (!cms->substitute(buf, this)) + { assert(deco); + buf->printf("u%d%s", strlen(deco), deco); + } +} + +void TypeBasic::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ char c; + char p = 0; + + /* ABI spec says: + * v void + * w wchar_t + * b bool + * c char + * a signed char + * h unsigned char + * s short + * t unsigned short + * i int + * j unsigned int + * l long + * m unsigned long + * x long long, __int64 + * y unsigned long long, __int64 + * n __int128 + * o unsigned __int128 + * f float + * d double + * e long double, __float80 + * g __float128 + * z ellipsis + * u # vendor extended type + */ + + switch (ty) + { + case Tvoid: c = 'v'; break; + case Tint8: c = 'a'; break; + case Tuns8: c = 'h'; break; + case Tint16: c = 's'; break; + case Tuns16: c = 't'; break; + case Tint32: c = 'i'; break; + case Tuns32: c = 'j'; break; + case Tfloat32: c = 'f'; break; + case Tint64: c = 'x'; break; + case Tuns64: c = 'y'; break; + case Tfloat64: c = 'd'; break; + case Tfloat80: c = 'e'; break; + case Tbool: c = 'b'; break; + case Tchar: c = 'c'; break; + case Twchar: c = 't'; break; + case Tdchar: c = 'w'; break; + + case Timaginary32: p = 'G'; c = 'f'; break; + case Timaginary64: p = 'G'; c = 'd'; break; + case Timaginary80: p = 'G'; c = 'e'; break; + case Tcomplex32: p = 'C'; c = 'f'; break; + case Tcomplex64: p = 'C'; c = 'd'; break; + case Tcomplex80: p = 'C'; c = 'e'; break; + + default: assert(0); + } + if (p) + { + if (cms->substitute(buf, this)) + return; + buf->writeByte(p); + } + buf->writeByte(c); +} + + +void TypeSArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, this)) + { buf->printf("A%ju_", dim ? dim->toInteger() : 0); + next->toCppMangle(buf, cms); + } +} + +void TypeDArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + Type::toCppMangle(buf, cms); +} + + +void TypeAArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + Type::toCppMangle(buf, cms); +} + + +void TypePointer::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, this)) + { buf->writeByte('P'); + next->toCppMangle(buf, cms); + } +} + + +void TypeReference::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, this)) + { buf->writeByte('R'); + next->toCppMangle(buf, cms); + } +} + + +void TypeFunction::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ /* + * ::= F [Y] E + * ::= + + * # types are possible return type, then parameter types + */ + + /* ABI says: + "The type of a non-static member function is considered to be different, + for the purposes of substitution, from the type of a namespace-scope or + static member function whose type appears similar. The types of two + non-static member functions are considered to be different, for the + purposes of substitution, if the functions are members of different + classes. In other words, for the purposes of substitution, the class of + which the function is a member is considered part of the type of + function." + + BUG: Right now, types of functions are never merged, so our simplistic + component matcher always finds them to be different. + We should use Type::equals on these, and use different + TypeFunctions for non-static member functions, and non-static + member functions of different classes. + */ + if (!cms->substitute(buf, this)) + { + buf->writeByte('F'); + if (linkage == LINKc) + buf->writeByte('Y'); + next->toCppMangle(buf, cms); + Argument::argsCppMangle(buf, cms, parameters, varargs); + buf->writeByte('E'); + } +} + + +void TypeDelegate::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + Type::toCppMangle(buf, cms); +} + + +void TypeStruct::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, sym)) + cpp_mangle_name(buf, cms, sym); +} + + +void TypeEnum::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, sym)) + cpp_mangle_name(buf, cms, sym); +} + + +void TypeTypedef::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + Type::toCppMangle(buf, cms); +} + + +void TypeClass::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, this)) + { buf->writeByte('P'); + if (!cms->substitute(buf, sym)) + cpp_mangle_name(buf, cms, sym); + } +} + + + +void Argument::argsCppMangle(OutBuffer *buf, CppMangleState *cms, Arguments *arguments, int varargs) +{ int n = 0; + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { Argument *arg = (Argument *)arguments->data[i]; + Type *t = arg->type; + if (arg->storageClass & (STCout | STCref)) + t = t->referenceTo(); + else if (arg->storageClass & STClazy) + { // Mangle as delegate + Type *td = new TypeFunction(NULL, t, 0, LINKd); + td = new TypeDelegate(td); + t = t->merge(); + } + if (t->ty == Tsarray) + { // Mangle static arrays as pointers + t = t->pointerTo(); + } + t->toCppMangle(buf, cms); + + n++; + } + } + if (varargs) + buf->writestring("z"); + else if (!n) + buf->writeByte('v'); // encode ( ) arguments +} + + +#endif + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/declaration.c --- a/dmd2/declaration.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/declaration.c Sat May 30 17:23:32 2009 +0100 @@ -1,1660 +1,1716 @@ - -// 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. - -#include -#include - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "mtype.h" -#include "template.h" -#include "scope.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "hdrgen.h" - -/********************************* Declaration ****************************/ - -Declaration::Declaration(Identifier *id) - : Dsymbol(id) -{ - type = NULL; - originalType = NULL; - storage_class = STCundefined; - protection = PROTundefined; - linkage = LINKdefault; -} - -void Declaration::semantic(Scope *sc) -{ -} - -const char *Declaration::kind() -{ - return "declaration"; -} - -unsigned Declaration::size(Loc loc) -{ - assert(type); - return type->size(); -} - -int Declaration::isStaticConstructor() -{ - return FALSE; -} - -int Declaration::isStaticDestructor() -{ - return FALSE; -} - -int Declaration::isDelete() -{ - return FALSE; -} - -int Declaration::isDataseg() -{ - return FALSE; -} - -int Declaration::isCodeseg() -{ - return FALSE; -} - -enum PROT Declaration::prot() -{ - return protection; -} - -/************************************* - * Check to see if declaration can be modified in this context (sc). - * Issue error if not. - */ - -#if DMDV2 -void Declaration::checkModify(Loc loc, Scope *sc, Type *t) -{ - if (sc->incontract && isParameter()) - error(loc, "cannot modify parameter '%s' in contract", toChars()); - - if (isCtorinit()) - { // It's only modifiable if inside the right constructor - Dsymbol *s = sc->func; - while (1) - { - FuncDeclaration *fd = NULL; - if (s) - fd = s->isFuncDeclaration(); - if (fd && - ((fd->isCtorDeclaration() && storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) && - fd->toParent() == toParent() - ) - { - VarDeclaration *v = isVarDeclaration(); - assert(v); - v->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else - { - const char *p = isStatic() ? "static " : ""; - error(loc, "can only initialize %sconst %s inside %sconstructor", - p, toChars(), p); - } - } - break; - } - } - else - { - VarDeclaration *v = isVarDeclaration(); - if (v && v->canassign == 0) - { - const char *p = NULL; - if (isConst()) - p = "const"; - else if (isInvariant()) - p = "invariant"; - else if (storage_class & STCmanifest) - p = "manifest constant"; - else if (!t->isAssignable()) - p = "struct with immutable members"; - if (p) - { error(loc, "cannot modify %s", p); - halt(); - } - } - } -} -#endif - - -/********************************* TupleDeclaration ****************************/ - -TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) - : Declaration(id) -{ - this->type = NULL; - this->objects = objects; - this->isexp = 0; - this->tupletype = NULL; -} - -Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); - return NULL; -} - -const char *TupleDeclaration::kind() -{ - return "tuple"; -} - -Type *TupleDeclaration::getType() -{ - /* If this tuple represents a type, return that type - */ - - //printf("TupleDeclaration::getType() %s\n", toChars()); - if (isexp) - return NULL; - if (!tupletype) - { - /* It's only a type tuple if all the Object's are types - */ - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; - - if (o->dyncast() != DYNCAST_TYPE) - { - //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); - return NULL; - } - } - - /* We know it's a type tuple, so build the TypeTuple - */ - Arguments *args = new Arguments(); - args->setDim(objects->dim); - OutBuffer buf; - for (size_t i = 0; i < objects->dim; i++) - { Type *t = (Type *)objects->data[i]; - - //printf("type = %s\n", t->toChars()); -#if 0 - buf.printf("_%s_%d", ident->toChars(), i); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - Argument *arg = new Argument(STCin, t, id, NULL); -#else - Argument *arg = new Argument(0, t, NULL, NULL); -#endif - args->data[i] = (void *)arg; - } - - tupletype = new TypeTuple(args); - } - - return tupletype; -} - -int TupleDeclaration::needThis() -{ - //printf("TupleDeclaration::needThis(%s)\n", toChars()); - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - if (e->op == TOKdsymbol) - { DsymbolExp *ve = (DsymbolExp *)e; - Declaration *d = ve->s->isDeclaration(); - if (d && d->needThis()) - { - return 1; - } - } - } - } - return 0; -} - -/********************************* TypedefDeclaration ****************************/ - -TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) - : Declaration(id) -{ - this->type = new TypeTypedef(this); - this->basetype = basetype->toBasetype(); - this->init = init; -#ifdef _DH - this->htype = NULL; - this->hbasetype = NULL; -#endif - this->sem = 0; - this->inuse = 0; - this->loc = loc; - this->sinit = NULL; -} - -Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *basetype = this->basetype->syntaxCopy(); - - Initializer *init = NULL; - if (this->init) - init = this->init->syntaxCopy(); - - assert(!s); - TypedefDeclaration *st; - st = new TypedefDeclaration(loc, ident, basetype, init); -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - st->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - st->htype = htype->syntaxCopy(); - if (!hbasetype) - { if (basetype) - { hbasetype = basetype->syntaxCopy(); - st->hbasetype = basetype->syntaxCopy(); - } - } - else - st->hbasetype = hbasetype->syntaxCopy(); -#endif - return st; -} - -void TypedefDeclaration::semantic(Scope *sc) -{ - //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); - if (sem == 0) - { sem = 1; - basetype = basetype->semantic(loc, sc); - sem = 2; - type = type->semantic(loc, sc); - if (sc->parent->isFuncDeclaration() && init) - semantic2(sc); - storage_class |= sc->stc & STCdeprecated; - } - else if (sem == 1) - { - error("circular definition"); - } -} - -void TypedefDeclaration::semantic2(Scope *sc) -{ - //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); - if (sem == 2) - { sem = 3; - if (init) - { - init = init->semantic(sc, basetype); - - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - { - if (ie->exp->type == basetype) - ie->exp->type = type; - } - } - } -} - -const char *TypedefDeclaration::kind() -{ - return "typedef"; -} - -Type *TypedefDeclaration::getType() -{ - return type; -} - -void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typedef "); - basetype->toCBuffer(buf, ident, hgs); - if (init) - { - buf->writestring(" = "); - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* AliasDeclaration ****************************/ - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("type = '%s'\n", type->toChars()); - this->loc = loc; - this->type = type; - this->aliassym = NULL; -#ifdef _DH - this->htype = NULL; - this->haliassym = NULL; -#endif - this->overnext = NULL; - this->inSemantic = 0; - assert(type); -} - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); - assert(s != this); - this->loc = loc; - this->type = NULL; - this->aliassym = s; -#ifdef _DH - this->htype = NULL; - this->haliassym = NULL; -#endif - this->overnext = NULL; - this->inSemantic = 0; - assert(s); -} - -Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("AliasDeclaration::syntaxCopy()\n"); - assert(!s); - AliasDeclaration *sa; - if (type) - sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); - else - sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sa->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sa->htype = htype->syntaxCopy(); - if (!haliassym) - { if (aliassym) - { haliassym = aliassym->syntaxCopy(s); - sa->haliassym = aliassym->syntaxCopy(s); - } - } - else - sa->haliassym = haliassym->syntaxCopy(s); -#endif - return sa; -} - -void AliasDeclaration::semantic(Scope *sc) -{ - //printf("AliasDeclaration::semantic() %s\n", toChars()); - if (aliassym) - { - if (aliassym->isTemplateInstance()) - aliassym->semantic(sc); - return; - } - this->inSemantic = 1; - - if (storage_class & STCconst) - error("cannot be const"); - - storage_class |= sc->stc & STCdeprecated; - - // Given: - // alias foo.bar.abc def; - // it is not knowable from the syntax whether this is an alias - // for a type or an alias for a symbol. It is up to the semantic() - // pass to distinguish. - // If it is a type, then type is set and getType() will return that - // type. If it is a symbol, then aliassym is set and type is NULL - - // toAlias() will return aliasssym. - - Dsymbol *s; - Type *t; - Expression *e; - - /* This section is needed because resolve() will: - * const x = 3; - * alias x y; - * try to alias y to 3. - */ - s = type->toDsymbol(sc); - if (s && ((s->getType() && type->equals(s->getType())) || s->isEnumMember())) - goto L2; // it's a symbolic alias - - //printf("alias type is %s\n", type->toChars()); - type->resolve(loc, sc, &e, &t, &s); - if (s) - { - goto L2; - } - else if (e) - { - // Try to convert Expression to Dsymbol - s = getDsymbol(e); - if (s) - goto L2; - - error("cannot alias an expression %s", e->toChars()); - t = e->type; - } - else if (t) - type = t; - if (overnext) - ScopeDsymbol::multiplyDefined(0, this, overnext); - this->inSemantic = 0; - return; - - L2: - //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); - type = NULL; - VarDeclaration *v = s->isVarDeclaration(); - if (v && v->linkage == LINKdefault) - { - error("forward reference of %s", v->toChars()); - s = NULL; - } - else - { - FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); - if (f) - { - if (overnext) - { - FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); - if (!fa->overloadInsert(overnext)) - ScopeDsymbol::multiplyDefined(0, f, overnext); - overnext = NULL; - s = fa; - s->parent = sc->parent; - } - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, s, overnext); - if (s == this) - { - assert(global.errors); - s = NULL; - } - } - aliassym = s; - this->inSemantic = 0; -} - -int AliasDeclaration::overloadInsert(Dsymbol *s) -{ - /* Don't know yet what the aliased symbol is, so assume it can - * be overloaded and check later for correctness. - */ - - //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); - if (overnext == NULL) - { overnext = s; - return TRUE; - } - else - { - return overnext->overloadInsert(s); - } -} - -const char *AliasDeclaration::kind() -{ - return "alias"; -} - -Type *AliasDeclaration::getType() -{ - return type; -} - -Dsymbol *AliasDeclaration::toAlias() -{ - //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); - assert(this != aliassym); - //static int count; if (++count == 10) *(char*)0=0; - if (inSemantic) - { error("recursive alias declaration"); -// return this; - } - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); -#if 0 && _DH - if (hgs->hdrgen) - { - if (haliassym) - { - haliassym->toCBuffer(buf, hgs); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - htype->toCBuffer(buf, ident, hgs); - } - else -#endif - { - if (aliassym) - { - aliassym->toCBuffer(buf, hgs); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - type->toCBuffer(buf, ident, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* VarDeclaration ****************************/ - -VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) - : Declaration(id) -{ - //printf("VarDeclaration('%s')\n", id->toChars()); -#ifdef DEBUG - if (!type && !init) - { printf("VarDeclaration('%s')\n", id->toChars()); - //*(char*)0=0; - } -#endif - assert(type || init); - this->type = type; - this->init = init; -#ifdef _DH - this->htype = NULL; - this->hinit = NULL; -#endif - this->loc = loc; - offset = 0; - noauto = 0; - inuse = 0; - ctorinit = 0; - aliassym = NULL; - onstack = 0; - canassign = 0; - value = NULL; - scope = NULL; - - // LDC - anonDecl = NULL; - offset2 = 0; - nakedUse = false; -} - -Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); - - VarDeclaration *sv; - if (s) - { sv = (VarDeclaration *)s; - } - else - { - Initializer *init = NULL; - if (this->init) - { init = this->init->syntaxCopy(); - //init->isExpInitializer()->exp->print(); - //init->isExpInitializer()->exp->dump(0); - } - - sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); - sv->storage_class = storage_class; - } -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sv->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sv->htype = htype->syntaxCopy(); - if (!hinit) - { if (init) - { hinit = init->syntaxCopy(); - sv->hinit = init->syntaxCopy(); - } - } - else - sv->hinit = hinit->syntaxCopy(); -#endif - return sv; -} - -void VarDeclaration::semantic(Scope *sc) -{ -#if 0 - printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); - printf(" type = %s\n", type ? type->toChars() : "null"); - printf(" stc = x%x\n", sc->stc); - printf(" storage_class = x%x\n", storage_class); - printf("linkage = %d\n", sc->linkage); - //if (strcmp(toChars(), "mul") == 0) halt(); -#endif - - storage_class |= sc->stc; - if (storage_class & STCextern && init) - error("extern symbols cannot have initializers"); - - /* If auto type inference, do the inference - */ - int inferred = 0; - if (!type) - { inuse++; - type = init->inferType(sc); - inuse--; - inferred = 1; - - /* This is a kludge to support the existing syntax for RAII - * declarations. - */ - storage_class &= ~STCauto; - originalType = type; - } - else - { if (!originalType) - originalType = type; - type = type->semantic(loc, sc); - } - //printf(" semantic type = %s\n", type ? type->toChars() : "null"); - - type->checkDeprecated(loc, sc); - linkage = sc->linkage; - this->parent = sc->parent; - //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); - protection = sc->protection; - //printf("sc->stc = %x\n", sc->stc); - //printf("storage_class = x%x\n", storage_class); - - Dsymbol *parent = toParent(); - FuncDeclaration *fd = parent->isFuncDeclaration(); - - Type *tb = type->toBasetype(); - if (tb->ty == Tvoid && !(storage_class & STClazy)) - { error("voids have no value"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tfunction) - { error("cannot be declared to be a function"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tb; - - if (!ts->sym->members) - { - error("no definition of struct %s", ts->toChars()); - } - } - - if (tb->ty == Ttuple) - { /* Instead, declare variables for each of the tuple elements - * and add those. - */ - TypeTuple *tt = (TypeTuple *)tb; - size_t nelems = Argument::dim(tt->arguments); - Objects *exps = new Objects(); - exps->setDim(nelems); - Expression *ie = init ? init->toExpression() : NULL; - - for (size_t i = 0; i < nelems; i++) - { Argument *arg = Argument::getNth(tt->arguments, i); - - OutBuffer buf; - buf.printf("_%s_field_%"PRIuSIZE, ident->toChars(), i); - buf.writeByte(0); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - - Expression *einit = ie; - if (ie && ie->op == TOKtuple) - { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; - } - Initializer *ti = init; - if (einit) - { ti = new ExpInitializer(einit->loc, einit); - } - - VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); - //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); - v->semantic(sc); - - if (sc->scopesym) - { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); - if (sc->scopesym->members) - sc->scopesym->members->push(v); - } - - Expression *e = new DsymbolExp(loc, v); - exps->data[i] = e; - } - TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); - v2->isexp = 1; - aliassym = v2; - return; - } - -Lagain: - if (storage_class & STCinvariant) - { - type = type->invariantOf(); - } - else if (storage_class & (STCconst | STCin)) - { - if (!type->isInvariant()) - type = type->constOf(); - } - else if (type->isConst()) - storage_class |= STCconst; - else if (type->isInvariant()) - storage_class |= STCinvariant; - - if (isSynchronized()) - { - error("variable %s cannot be synchronized", toChars()); - } - else if (isOverride()) - { - error("override cannot be applied to variable"); - } - else if (isAbstract()) - { - error("abstract cannot be applied to variable"); - } - else if (storage_class & STCfinal) - { - error("final cannot be applied to variable"); - } - - if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls)) - { - } - else - { - AggregateDeclaration *aad = sc->anonAgg; - if (!aad) - aad = parent->isAggregateDeclaration(); - if (aad) - { assert(!(storage_class & (STCextern | STCstatic | STCtls))); - - if (storage_class & (STCconst | STCinvariant) && init) - { - if (!type->toBasetype()->isTypeBasic()) - storage_class |= STCstatic; - } - else - aad->addField(sc, this); - } - - InterfaceDeclaration *id = parent->isInterfaceDeclaration(); - if (id) - { - error("field not allowed in interface"); - } - - /* Templates cannot add fields to aggregates - */ - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - AggregateDeclaration *ad = ti->tempdecl->isMember(); - if (ad && storage_class != STCundefined) - { - error("cannot use template to add field to aggregate '%s'", ad->toChars()); - } - } - } - - if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref) - error("only parameters or foreach declarations can be ref"); - - if (type->isauto() && !noauto) - { - if (storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls) || !fd) - { - error("globals, statics, fields, manifest constants, ref and out parameters cannot be auto"); - } - - if (!(storage_class & (STCauto | STCscope))) - { - if (!(storage_class & STCparameter) && ident != Id::withSym) - error("reference to scope class must be scope"); - } - } - - if ((isConst() || isInvariant()) && !init && !fd) - { // Initialize by constructor only - storage_class |= STCctorinit; - } - - if (init) - storage_class |= STCinit; // remember we had an explicit initializer - else if (storage_class & STCmanifest) - error("manifest constants must have initializers"); - - enum TOK op = TOKconstruct; - if (!init && !sc->inunion && !isStatic() && fd && - (!(storage_class & (STCfield | STCin | STCforeach | STCparameter)) || (storage_class & STCout)) && - type->size() != 0) - { - // Provide a default initializer - //printf("Providing default initializer for '%s'\n", toChars()); - if (type->ty == Tstruct && - ((TypeStruct *)type)->sym->zeroInit == 1) - { /* If a struct is all zeros, as a special case - * set it's initializer to the integer 0. - * In AssignExp::toElem(), we check for this and issue - * a memset() to initialize the struct. - * Must do same check in interpreter. - */ - Expression *e = new IntegerExp(loc, 0, Type::tint32); - Expression *e1; - e1 = new VarExp(loc, this); - e = new AssignExp(loc, e1, e); - e->type = e1->type; // don't type check this, it would fail - init = new ExpInitializer(loc, e); - return; - } - else if (type->ty == Ttypedef) - { TypeTypedef *td = (TypeTypedef *)type; - if (td->sym->init) - { init = td->sym->init; - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - // Make copy so we can modify it - init = new ExpInitializer(ie->loc, ie->exp); - } - else - init = getExpInitializer(); - } - else - { - init = getExpInitializer(); - } - // Default initializer is always a blit - op = TOKblit; - } - - if (init) - { - sc = sc->push(); - sc->stc &= ~(STCconst | STCinvariant | STCpure | STCnothrow | STCref | STCshared); - - ArrayInitializer *ai = init->isArrayInitializer(); - if (ai && tb->ty == Taarray) - { - init = ai->toAssocArrayInitializer(); - } - - StructInitializer *si = init->isStructInitializer(); - ExpInitializer *ei = init->isExpInitializer(); - - // See if initializer is a NewExp that can be allocated on the stack - if (ei && isScope() && ei->exp->op == TOKnew) - { NewExp *ne = (NewExp *)ei->exp; - if (!(ne->newargs && ne->newargs->dim)) - { ne->onstack = 1; - onstack = 1; - if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) - onstack = 2; - } - } - - // If inside function, there is no semantic3() call - if (sc->func) - { - // If local variable, use AssignExp to handle all the various - // possibilities. - if (fd && !isStatic() && !(storage_class & STCmanifest) && - !init->isVoidInitializer()) - { - //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); - if (!ei) - { - Expression *e = init->toExpression(); - if (!e) - { - init = init->semantic(sc, type); - e = init->toExpression(); - if (!e) - { error("is not a static and cannot have static initializer"); - return; - } - } - ei = new ExpInitializer(init->loc, e); - init = ei; - } - - Expression *e1 = new VarExp(loc, this); - - Type *t = type->toBasetype(); - if (t->ty == Tsarray) - { - ei->exp = ei->exp->semantic(sc); - if (!ei->exp->implicitConvTo(type)) - { - int dim = ((TypeSArray *)t)->dim->toInteger(); - // If multidimensional static array, treat as one large array - while (1) - { - t = t->nextOf()->toBasetype(); - if (t->ty != Tsarray) - break; - dim *= ((TypeSArray *)t)->dim->toInteger(); - e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); - } - } - e1 = new SliceExp(loc, e1, NULL, NULL); - } - else if (t->ty == Tstruct) - { - ei->exp = ei->exp->semantic(sc); - - /* Look to see if initializer is a call to the constructor - */ - StructDeclaration *sd = ((TypeStruct *)t)->sym; - if (sd->ctor && // there are constructors - ei->exp->type->ty == Tstruct && // rvalue is the same struct - ((TypeStruct *)ei->exp->type)->sym == sd && - ei->exp->op == TOKstar) - { - /* Look for form of constructor call which is: - * *__ctmp.ctor(arguments...) - */ - PtrExp *pe = (PtrExp *)ei->exp; - if (pe->e1->op == TOKcall) - { CallExp *ce = (CallExp *)pe->e1; - if (ce->e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)ce->e1; - if (dve->var->isCtorDeclaration()) - { /* It's a constructor call, currently constructing - * a temporary __ctmp. - */ - /* Before calling the constructor, initialize - * variable with a bit copy of the default - * initializer - */ - Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); - e->op = TOKblit; - e->type = t; - ei->exp = new CommaExp(loc, e, ei->exp); - - /* Replace __ctmp being constructed with e1 - */ - dve->e1 = e1; - return; - } - } - } - } - - if (!ei->exp->implicitConvTo(type)) - { Type *ti = ei->exp->type->toBasetype(); - // Don't cast away invariant or mutability in initializer - if (!(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) - ei->exp = new CastExp(loc, ei->exp, type); - } - } - ei->exp = new AssignExp(loc, e1, ei->exp); - ei->exp->op = op; - canassign++; - ei->exp = ei->exp->semantic(sc); - canassign--; - ei->exp->optimize(WANTvalue); - } - else - { - init = init->semantic(sc, type); - } - } - else if (storage_class & (STCconst | STCinvariant | STCmanifest) || - type->isConst() || type->isInvariant()) - { - /* Because we may need the results of a const declaration in a - * subsequent type, such as an array dimension, before semantic2() - * gets ordinarily run, try to run semantic2() now. - * Ignore failure. - */ - - if (!global.errors && !inferred) - { - unsigned errors = global.errors; - global.gag++; - //printf("+gag\n"); - Expression *e; - Initializer *i2 = init; - inuse++; - if (ei) - { - e = ei->exp->syntaxCopy(); - e = e->semantic(sc); - e = e->implicitCastTo(sc, type); - } - else if (si || ai) - { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type); - } - inuse--; - global.gag--; - //printf("-gag\n"); - if (errors != global.errors) // if errors happened - { - if (global.gag == 0) - global.errors = errors; // act as if nothing happened - - /* Save scope for later use, to try again - */ - scope = new Scope(*sc); - scope->setNoFree(); - } - else if (ei) - { - if (isDataseg()) - /* static const/invariant does CTFE - */ - e = e->optimize(WANTvalue | WANTinterpret); - else - e = e->optimize(WANTvalue); - if (e->op == TOKint64 || e->op == TOKstring) - { - ei->exp = e; // no errors, keep result - } - else - { - /* Save scope for later use, to try again - */ - scope = new Scope(*sc); - scope->setNoFree(); - } - } - else - init = i2; // no errors, keep result - } - } - sc = sc->pop(); - } -} - -void VarDeclaration::semantic2(Scope *sc) -{ - //printf("VarDeclaration::semantic2('%s')\n", toChars()); - if (init && !toParent()->isFuncDeclaration()) - { inuse++; -#if 0 - ExpInitializer *ei = init->isExpInitializer(); - if (ei) - { - ei->exp->dump(0); - printf("type = %p\n", ei->exp->type); - } -#endif - init = init->semantic(sc, type); - inuse--; - } -} - -const char *VarDeclaration::kind() -{ - return "variable"; -} - -Dsymbol *VarDeclaration::toAlias() -{ - //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); - assert(this != aliassym); - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (storage_class & STCconst) - buf->writestring("const "); - if (storage_class & STCstatic) - buf->writestring("static "); - if (storage_class & STCauto) - buf->writestring("auto "); -#if DMDV2 - if (storage_class & STCmanifest) - buf->writestring("manifest "); - if (storage_class & STCinvariant) - buf->writestring("invariant "); - if (storage_class & STCtls) - buf->writestring("__thread "); -#endif - - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (init) - { buf->writestring(" = "); - ExpInitializer *ie = init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -int VarDeclaration::needThis() -{ - //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); - return storage_class & STCfield; -} - -int VarDeclaration::isImportedSymbol() -{ - if (protection == PROTexport && !init && - (storage_class & STCstatic || parent->isModule())) - return TRUE; - return FALSE; -} - -void VarDeclaration::checkCtorConstInit() -{ -#if 0 /* doesn't work if more than one static ctor */ - if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) - error("missing initializer in static constructor for const variable"); -#endif -} - -/************************************ - * Check to see if this variable is actually in an enclosing function - * rather than the current one. - */ - -void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) -{ - if (parent && !isDataseg() && parent != sc->parent && - !(storage_class & STCmanifest)) - { - // The function that this variable is in - FuncDeclaration *fdv = toParent()->isFuncDeclaration(); - // The current function - FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - - if (fdv && fdthis && fdv != fdthis) - { - if (loc.filename) - fdthis->getLevel(loc, fdv); - - for (int i = 0; i < nestedrefs.dim; i++) - { FuncDeclaration *f = (FuncDeclaration *)nestedrefs.data[i]; - if (f == fdthis) - goto L1; - } - fdv->nestedVars.insert(this); - nestedrefs.push(fdthis); - L1: ; - - - for (int i = 0; i < fdv->closureVars.dim; i++) - { Dsymbol *s = (Dsymbol *)fdv->closureVars.data[i]; - if (s == this) - goto L2; - } - - fdv->closureVars.push(this); - L2: ; - - //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); - } - } -} - -/**************************** - * Get ExpInitializer for a variable, if there is one. - */ - -ExpInitializer *VarDeclaration::getExpInitializer() -{ - ExpInitializer *ei; - - if (init) - ei = init->isExpInitializer(); - else - { - Expression *e = type->defaultInit(loc); - if (e) - ei = new ExpInitializer(loc, e); - else - ei = NULL; - } - return ei; -} - -/******************************************* - * If variable has a constant expression initializer, get it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::getConstInitializer() -{ - if ((isConst() || isInvariant() || storage_class & STCmanifest) && - storage_class & STCinit) - { - ExpInitializer *ei = getExpInitializer(); - if (ei) - return ei->exp; - } - - return NULL; -} - -/************************************* - * Return !=0 if we can take the address of this variable. - */ - -int VarDeclaration::canTakeAddressOf() -{ -#if 0 - /* Global variables and struct/class fields of the form: - * const int x = 3; - * are not stored and hence cannot have their address taken. - */ - if ((isConst() || isInvariant()) && - storage_class & STCinit && - (!(storage_class & (STCstatic | STCextern)) || (storage_class & STCfield)) && - (!parent || toParent()->isModule() || toParent()->isTemplateInstance()) && - type->toBasetype()->isTypeBasic() - ) - { - return 0; - } -#else - if (storage_class & STCmanifest) - return 0; -#endif - return 1; -} - -/******************************* - * Does symbol go into data segment? - * Includes extern variables. - */ - -int VarDeclaration::isDataseg() -{ -#if 0 - printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); - printf("%x, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); - printf("parent = '%s'\n", parent->toChars()); -#endif - if (storage_class & STCmanifest) - return 0; - Dsymbol *parent = this->toParent(); - if (!parent && !(storage_class & STCstatic)) - { error("forward referenced"); - type = Type::terror; - return 0; - } - return canTakeAddressOf() && - (storage_class & (STCstatic | STCextern | STCtls) || - toParent()->isModule() || - toParent()->isTemplateInstance()); -} - -int VarDeclaration::hasPointers() -{ - //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); - return (!isDataseg() && type->hasPointers()); -} - -/****************************************** - * Return TRUE if variable needs to call the destructor. - */ - -int VarDeclaration::needsAutoDtor() -{ - //printf("VarDeclaration::needsAutoDtor() %s\n", toChars()); - - if (noauto || storage_class & STCnodtor) - return FALSE; - - // Destructors for structs and arrays of structs - Type *tv = type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - return TRUE; - } - - // Destructors for classes - if (storage_class & (STCauto | STCscope)) - { - if (type->isClassHandle()) - return TRUE; - } - return FALSE; -} - - -/****************************************** - * If a variable has an auto destructor call, return call for it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::callAutoDtor(Scope *sc) -{ Expression *e = NULL; - - //printf("VarDeclaration::callAutoDtor() %s\n", toChars()); - - if (noauto || storage_class & STCnodtor) - return NULL; - - // Destructors for structs and arrays of structs - bool array = false; - Type *tv = type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - array = true; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - { - if (array) - { - // Typeinfo.destroy(cast(void*)&v); - Expression *ea = new SymOffExp(loc, this, 0, 0); - ea = new CastExp(loc, ea, Type::tvoid->pointerTo()); - Expressions *args = new Expressions(); - args->push(ea); - - Expression *et = type->getTypeInfo(sc); - et = new DotIdExp(loc, et, Id::destroy); - - e = new CallExp(loc, et, args); - } - else - { - e = new VarExp(loc, this); - e = new DotVarExp(loc, e, sd->dtor, 0); - e = new CallExp(loc, e); - } - return e; - } - } - - // Destructors for classes - if (storage_class & (STCauto | STCscope)) - { - for (ClassDeclaration *cd = type->isClassHandle(); - cd; - cd = cd->baseClass) - { - /* We can do better if there's a way with onstack - * classes to determine if there's no way the monitor - * could be set. - */ - //if (cd->isInterfaceDeclaration()) - //error("interface %s cannot be scope", cd->toChars()); - if (1 || onstack || cd->dtors.dim) // if any destructors - { - // delete this; - Expression *ec; - - ec = new VarExp(loc, this); - e = new DeleteExp(loc, ec); - e->type = Type::tvoid; - break; - } - } - } - return e; -} - - -/********************************* ClassInfoDeclaration ****************************/ - -ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) - : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) -{ - this->cd = cd; - storage_class = STCstatic; -} - -Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ClassInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* ModuleInfoDeclaration ****************************/ - -ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) - : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL) -{ - this->mod = mod; - storage_class = STCstatic; -} - -Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ModuleInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* TypeInfoDeclaration ****************************/ - -TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) - : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) -{ - this->tinfo = tinfo; - storage_class = STCstatic; - protection = PROTpublic; - linkage = LINKc; -} - -Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void TypeInfoDeclaration::semantic(Scope *sc) -{ - assert(linkage == LINKc); -} - -/***************************** TypeInfoConstDeclaration **********************/ - -#if DMDV2 -TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoInvariantDeclaration **********************/ - -#if DMDV2 -TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoStructDeclaration **********************/ - -TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoClassDeclaration ***********************/ - -TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoInterfaceDeclaration *******************/ - -TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTypedefDeclaration *********************/ - -TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoPointerDeclaration *********************/ - -TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoArrayDeclaration ***********************/ - -TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoStaticArrayDeclaration *****************/ - -TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoAssociativeArrayDeclaration ************/ - -TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoEnumDeclaration ***********************/ - -TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoFunctionDeclaration ********************/ - -TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoDelegateDeclaration ********************/ - -TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTupleDeclaration **********************/ - -TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/********************************* ThisDeclaration ****************************/ - -// For the "this" parameter to member functions - -ThisDeclaration::ThisDeclaration(Type *t) - : VarDeclaration(0, t, Id::This, NULL) -{ - noauto = 1; -} - -Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - - -/********************** StaticStructInitDeclaration ***************************/ - -StaticStructInitDeclaration::StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym) - : Declaration(new Identifier("", TOKidentifier)) -{ - this->loc = loc; - this->dsym = dsym; - storage_class |= STCconst; -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include + +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "mtype.h" +#include "template.h" +#include "scope.h" +#include "aggregate.h" +#include "module.h" +#include "id.h" +#include "expression.h" +#include "hdrgen.h" + +/********************************* Declaration ****************************/ + +Declaration::Declaration(Identifier *id) + : Dsymbol(id) +{ + type = NULL; + originalType = NULL; + storage_class = STCundefined; + protection = PROTundefined; + linkage = LINKdefault; + inuse = 0; +} + +void Declaration::semantic(Scope *sc) +{ +} + +const char *Declaration::kind() +{ + return "declaration"; +} + +unsigned Declaration::size(Loc loc) +{ + assert(type); + return type->size(); +} + +int Declaration::isStaticConstructor() +{ + return FALSE; +} + +int Declaration::isStaticDestructor() +{ + return FALSE; +} + +int Declaration::isDelete() +{ + return FALSE; +} + +int Declaration::isDataseg() +{ + return FALSE; +} + +int Declaration::isThreadlocal() +{ + return FALSE; +} + +int Declaration::isCodeseg() +{ + return FALSE; +} + +enum PROT Declaration::prot() +{ + return protection; +} + +/************************************* + * Check to see if declaration can be modified in this context (sc). + * Issue error if not. + */ + +#if DMDV2 +void Declaration::checkModify(Loc loc, Scope *sc, Type *t) +{ + if (sc->incontract && isParameter()) + error(loc, "cannot modify parameter '%s' in contract", toChars()); + + if (isCtorinit()) + { // It's only modifiable if inside the right constructor + Dsymbol *s = sc->func; + while (1) + { + FuncDeclaration *fd = NULL; + if (s) + fd = s->isFuncDeclaration(); + if (fd && + ((fd->isCtorDeclaration() && storage_class & STCfield) || + (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) && + fd->toParent() == toParent() + ) + { + VarDeclaration *v = isVarDeclaration(); + assert(v); + v->ctorinit = 1; + //printf("setting ctorinit\n"); + } + else + { + if (s) + { s = s->toParent2(); + continue; + } + else + { + const char *p = isStatic() ? "static " : ""; + error(loc, "can only initialize %sconst %s inside %sconstructor", + p, toChars(), p); + } + } + break; + } + } + else + { + VarDeclaration *v = isVarDeclaration(); + if (v && v->canassign == 0) + { + const char *p = NULL; + if (isConst()) + p = "const"; + else if (isInvariant()) + p = "mutable"; + else if (storage_class & STCmanifest) + p = "enum"; + else if (!t->isAssignable()) + p = "struct with immutable members"; + if (p) + { error(loc, "cannot modify %s", p); + } + } + } +} +#endif + + +/********************************* TupleDeclaration ****************************/ + +TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) + : Declaration(id) +{ + this->type = NULL; + this->objects = objects; + this->isexp = 0; + this->tupletype = NULL; +} + +Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); + return NULL; +} + +const char *TupleDeclaration::kind() +{ + return "tuple"; +} + +Type *TupleDeclaration::getType() +{ + /* If this tuple represents a type, return that type + */ + + //printf("TupleDeclaration::getType() %s\n", toChars()); + if (isexp) + return NULL; + if (!tupletype) + { + /* It's only a type tuple if all the Object's are types + */ + for (size_t i = 0; i < objects->dim; i++) + { Object *o = (Object *)objects->data[i]; + + if (o->dyncast() != DYNCAST_TYPE) + { + //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); + return NULL; + } + } + + /* We know it's a type tuple, so build the TypeTuple + */ + Arguments *args = new Arguments(); + args->setDim(objects->dim); + OutBuffer buf; + for (size_t i = 0; i < objects->dim; i++) + { Type *t = (Type *)objects->data[i]; + + //printf("type = %s\n", t->toChars()); +#if 0 + buf.printf("_%s_%d", ident->toChars(), i); + char *name = (char *)buf.extractData(); + Identifier *id = new Identifier(name, TOKidentifier); + Argument *arg = new Argument(STCin, t, id, NULL); +#else + Argument *arg = new Argument(0, t, NULL, NULL); +#endif + args->data[i] = (void *)arg; + } + + tupletype = new TypeTuple(args); + } + + return tupletype; +} + +int TupleDeclaration::needThis() +{ + //printf("TupleDeclaration::needThis(%s)\n", toChars()); + for (size_t i = 0; i < objects->dim; i++) + { Object *o = (Object *)objects->data[i]; + if (o->dyncast() == DYNCAST_EXPRESSION) + { Expression *e = (Expression *)o; + if (e->op == TOKdsymbol) + { DsymbolExp *ve = (DsymbolExp *)e; + Declaration *d = ve->s->isDeclaration(); + if (d && d->needThis()) + { + return 1; + } + } + } + } + return 0; +} + +/********************************* TypedefDeclaration ****************************/ + +TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) + : Declaration(id) +{ + this->type = new TypeTypedef(this); + this->basetype = basetype->toBasetype(); + this->init = init; +#ifdef _DH + this->htype = NULL; + this->hbasetype = NULL; +#endif + this->sem = 0; + this->loc = loc; +#if IN_DMD + this->sinit = NULL; +#endif +} + +Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) +{ + Type *basetype = this->basetype->syntaxCopy(); + + Initializer *init = NULL; + if (this->init) + init = this->init->syntaxCopy(); + + assert(!s); + TypedefDeclaration *st; + st = new TypedefDeclaration(loc, ident, basetype, init); +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + st->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + st->htype = htype->syntaxCopy(); + if (!hbasetype) + { if (basetype) + { hbasetype = basetype->syntaxCopy(); + st->hbasetype = basetype->syntaxCopy(); + } + } + else + st->hbasetype = hbasetype->syntaxCopy(); +#endif + return st; +} + +void TypedefDeclaration::semantic(Scope *sc) +{ + //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); + if (sem == 0) + { sem = 1; + basetype = basetype->semantic(loc, sc); + sem = 2; + type = type->semantic(loc, sc); + if (sc->parent->isFuncDeclaration() && init) + semantic2(sc); + storage_class |= sc->stc & STCdeprecated; + } + else if (sem == 1) + { + error("circular definition"); + } +} + +void TypedefDeclaration::semantic2(Scope *sc) +{ + //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); + if (sem == 2) + { sem = 3; + if (init) + { + init = init->semantic(sc, basetype); + + ExpInitializer *ie = init->isExpInitializer(); + if (ie) + { + if (ie->exp->type == basetype) + ie->exp->type = type; + } + } + } +} + +const char *TypedefDeclaration::kind() +{ + return "typedef"; +} + +Type *TypedefDeclaration::getType() +{ + return type; +} + +void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("typedef "); + basetype->toCBuffer(buf, ident, hgs); + if (init) + { + buf->writestring(" = "); + init->toCBuffer(buf, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +/********************************* AliasDeclaration ****************************/ + +AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) + : Declaration(id) +{ + //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); + //printf("type = '%s'\n", type->toChars()); + this->loc = loc; + this->type = type; + this->aliassym = NULL; +#ifdef _DH + this->htype = NULL; + this->haliassym = NULL; +#endif + this->overnext = NULL; + this->inSemantic = 0; + this->importprot = PROTundefined; + assert(type); +} + +AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) + : Declaration(id) +{ + //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); + assert(s != this); + this->loc = loc; + this->type = NULL; + this->aliassym = s; +#ifdef _DH + this->htype = NULL; + this->haliassym = NULL; +#endif + this->overnext = NULL; + this->inSemantic = 0; + assert(s); +} + +Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("AliasDeclaration::syntaxCopy()\n"); + assert(!s); + AliasDeclaration *sa; + if (type) + sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); + else + sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + sa->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + sa->htype = htype->syntaxCopy(); + if (!haliassym) + { if (aliassym) + { haliassym = aliassym->syntaxCopy(s); + sa->haliassym = aliassym->syntaxCopy(s); + } + } + else + sa->haliassym = haliassym->syntaxCopy(s); +#endif + return sa; +} + +void AliasDeclaration::semantic(Scope *sc) +{ + //printf("AliasDeclaration::semantic() %s\n", toChars()); + if (aliassym) + { + if (aliassym->isTemplateInstance()) + aliassym->semantic(sc); + return; + } + this->inSemantic = 1; + + if (storage_class & STCconst) + error("cannot be const"); + + storage_class |= sc->stc & STCdeprecated; + + // Given: + // alias foo.bar.abc def; + // it is not knowable from the syntax whether this is an alias + // for a type or an alias for a symbol. It is up to the semantic() + // pass to distinguish. + // If it is a type, then type is set and getType() will return that + // type. If it is a symbol, then aliassym is set and type is NULL - + // toAlias() will return aliasssym. + + Dsymbol *s; + Type *t; + Expression *e; + + /* This section is needed because resolve() will: + * const x = 3; + * alias x y; + * try to alias y to 3. + */ + s = type->toDsymbol(sc); + if (s && ((s->getType() && type->equals(s->getType())) || s->isEnumMember())) + goto L2; // it's a symbolic alias + + if (storage_class & STCref) + { // For 'ref' to be attached to function types, and picked + // up by Type::resolve(), it has to go into sc. + sc = sc->push(); + sc->stc |= STCref; + type->resolve(loc, sc, &e, &t, &s); + sc = sc->pop(); + } + else + type->resolve(loc, sc, &e, &t, &s); + if (s) + { + goto L2; + } + else if (e) + { + // Try to convert Expression to Dsymbol + s = getDsymbol(e); + if (s) + goto L2; + + error("cannot alias an expression %s", e->toChars()); + t = e->type; + } + else if (t) + type = t; + if (overnext) + ScopeDsymbol::multiplyDefined(0, this, overnext); + this->inSemantic = 0; + return; + + L2: + //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); + type = NULL; + VarDeclaration *v = s->isVarDeclaration(); + if (v && v->linkage == LINKdefault) + { + error("forward reference of %s", v->toChars()); + s = NULL; + } + else + { + FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); + if (f) + { + if (overnext) + { + FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); + fa->importprot = importprot; + if (!fa->overloadInsert(overnext)) + ScopeDsymbol::multiplyDefined(0, f, overnext); + overnext = NULL; + s = fa; + s->parent = sc->parent; + } + } + if (overnext) + ScopeDsymbol::multiplyDefined(0, s, overnext); + if (s == this) + { + assert(global.errors); + s = NULL; + } + } + aliassym = s; + this->inSemantic = 0; +} + +int AliasDeclaration::overloadInsert(Dsymbol *s) +{ + /* Don't know yet what the aliased symbol is, so assume it can + * be overloaded and check later for correctness. + */ + + //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); + if (overnext == NULL) + { overnext = s; + return TRUE; + } + else + { + return overnext->overloadInsert(s); + } +} + +const char *AliasDeclaration::kind() +{ + return "alias"; +} + +Type *AliasDeclaration::getType() +{ + return type; +} + +Dsymbol *AliasDeclaration::toAlias() +{ + //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); + assert(this != aliassym); + //static int count; if (++count == 10) *(char*)0=0; + if (inSemantic) + { error("recursive alias declaration"); + aliassym = new TypedefDeclaration(loc, ident, Type::terror, NULL); + } + Dsymbol *s = aliassym ? aliassym->toAlias() : this; + return s; +} + +void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("alias "); +#if 0 && _DH + if (hgs->hdrgen) + { + if (haliassym) + { + buf->writestring(haliassym->toChars()); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + } + else + htype->toCBuffer(buf, ident, hgs); + } + else +#endif + { + if (aliassym) + { + aliassym->toCBuffer(buf, hgs); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + } + else + type->toCBuffer(buf, ident, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +/********************************* VarDeclaration ****************************/ + +VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) + : Declaration(id) +{ + //printf("VarDeclaration('%s')\n", id->toChars()); +#ifdef DEBUG + if (!type && !init) + { printf("VarDeclaration('%s')\n", id->toChars()); + //*(char*)0=0; + } +#endif + assert(type || init); + this->type = type; + this->init = init; +#ifdef _DH + this->htype = NULL; + this->hinit = NULL; +#endif + this->loc = loc; + offset = 0; + noauto = 0; + ctorinit = 0; + aliassym = NULL; + onstack = 0; + canassign = 0; + value = NULL; + scope = NULL; +#if IN_LLVM + aggrIndex = 0; + + // LDC + anonDecl = NULL; + offset2 = 0; + + nakedUse = false; +#endif +} + +Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); + + VarDeclaration *sv; + if (s) + { sv = (VarDeclaration *)s; + } + else + { + Initializer *init = NULL; + if (this->init) + { init = this->init->syntaxCopy(); + //init->isExpInitializer()->exp->print(); + //init->isExpInitializer()->exp->dump(0); + } + + sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); + sv->storage_class = storage_class; + } +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + sv->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + sv->htype = htype->syntaxCopy(); + if (!hinit) + { if (init) + { hinit = init->syntaxCopy(); + sv->hinit = init->syntaxCopy(); + } + } + else + sv->hinit = hinit->syntaxCopy(); +#endif + return sv; +} + +void VarDeclaration::semantic(Scope *sc) +{ +#if 0 + printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); + printf(" type = %s\n", type ? type->toChars() : "null"); + printf(" stc = x%x\n", sc->stc); + printf(" storage_class = x%x\n", storage_class); + printf("linkage = %d\n", sc->linkage); + //if (strcmp(toChars(), "mul") == 0) halt(); +#endif + + storage_class |= sc->stc; + if (storage_class & STCextern && init) + error("extern symbols cannot have initializers"); + + /* If auto type inference, do the inference + */ + int inferred = 0; + if (!type) + { inuse++; + type = init->inferType(sc); + inuse--; + inferred = 1; + + /* This is a kludge to support the existing syntax for RAII + * declarations. + */ + storage_class &= ~STCauto; + originalType = type; + } + else + { if (!originalType) + originalType = type; + type = type->semantic(loc, sc); + } + //printf(" semantic type = %s\n", type ? type->toChars() : "null"); + + type->checkDeprecated(loc, sc); + linkage = sc->linkage; + this->parent = sc->parent; + //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); + protection = sc->protection; + //printf("sc->stc = %x\n", sc->stc); + //printf("storage_class = x%x\n", storage_class); + + if (storage_class & STCgshared && global.params.safe && !sc->module->safe) + { + error("__gshared not allowed in safe mode; use shared"); + } + + Dsymbol *parent = toParent(); + FuncDeclaration *fd = parent->isFuncDeclaration(); + + Type *tb = type->toBasetype(); + if (tb->ty == Tvoid && !(storage_class & STClazy)) + { error("voids have no value"); + type = Type::terror; + tb = type; + } + if (tb->ty == Tfunction) + { error("cannot be declared to be a function"); + type = Type::terror; + tb = type; + } + if (tb->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tb; + + if (!ts->sym->members) + { + error("no definition of struct %s", ts->toChars()); + } + } + + if (tb->ty == Ttuple) + { /* Instead, declare variables for each of the tuple elements + * and add those. + */ + TypeTuple *tt = (TypeTuple *)tb; + size_t nelems = Argument::dim(tt->arguments); + Objects *exps = new Objects(); + exps->setDim(nelems); + Expression *ie = init ? init->toExpression() : NULL; + + for (size_t i = 0; i < nelems; i++) + { Argument *arg = Argument::getNth(tt->arguments, i); + + OutBuffer buf; + buf.printf("_%s_field_%zu", ident->toChars(), i); + buf.writeByte(0); + char *name = (char *)buf.extractData(); + Identifier *id = new Identifier(name, TOKidentifier); + + Expression *einit = ie; + if (ie && ie->op == TOKtuple) + { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; + } + Initializer *ti = init; + if (einit) + { ti = new ExpInitializer(einit->loc, einit); + } + + VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); + //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); + v->semantic(sc); + +/* +// removed for LDC since TupleDeclaration::toObj already creates the fields; +// adding them to the scope again leads to duplicates + if (sc->scopesym) + { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); + if (sc->scopesym->members) + sc->scopesym->members->push(v); + } +*/ + Expression *e = new DsymbolExp(loc, v); + exps->data[i] = e; + } + TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); + v2->isexp = 1; + aliassym = v2; + return; + } + +Lagain: + /* Storage class can modify the type + */ + type = type->addStorageClass(storage_class); + + /* Adjust storage class to reflect type + */ + if (type->isConst()) + { storage_class |= STCconst; + if (type->isShared()) + storage_class |= STCshared; + } + else if (type->isInvariant()) + storage_class |= STCimmutable; + else if (type->isShared()) + storage_class |= STCshared; + + if (isSynchronized()) + { + error("variable %s cannot be synchronized", toChars()); + } + else if (isOverride()) + { + error("override cannot be applied to variable"); + } + else if (isAbstract()) + { + error("abstract cannot be applied to variable"); + } + else if (storage_class & STCfinal) + { + error("final cannot be applied to variable"); + } + + if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared)) + { + } + else + { + AggregateDeclaration *aad = sc->anonAgg; + if (!aad) + aad = parent->isAggregateDeclaration(); + if (aad) + { assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); + + if (storage_class & (STCconst | STCimmutable) && init) + { + if (!type->toBasetype()->isTypeBasic()) + storage_class |= STCstatic; + } + else + aad->addField(sc, this); + } + + InterfaceDeclaration *id = parent->isInterfaceDeclaration(); + if (id) + { + error("field not allowed in interface"); + } + + /* Templates cannot add fields to aggregates + */ + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + AggregateDeclaration *ad = ti->tempdecl->isMember(); + if (ad && storage_class != STCundefined) + { + error("cannot use template to add field to aggregate '%s'", ad->toChars()); + } + } + } + + if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref && + ident != Id::This) + { + error("only parameters or foreach declarations can be ref"); + } + + if (type->isauto() && !noauto) + { + if (storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd) + { + error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope"); + } + + if (!(storage_class & (STCauto | STCscope))) + { + if (!(storage_class & STCparameter) && ident != Id::withSym) + error("reference to scope class must be scope"); + } + } + + if ((isConst() || isInvariant()) && !init && !fd) + { // Initialize by constructor only + storage_class |= STCctorinit; + } + + if (init) + storage_class |= STCinit; // remember we had an explicit initializer + else if (storage_class & STCmanifest) + error("manifest constants must have initializers"); + + enum TOK op = TOKconstruct; + if (!init && !sc->inunion && !isStatic() && fd && + (!(storage_class & (STCfield | STCin | STCforeach | STCparameter)) || (storage_class & STCout)) && + type->size() != 0) + { + // Provide a default initializer + //printf("Providing default initializer for '%s'\n", toChars()); + if (type->ty == Tstruct && + ((TypeStruct *)type)->sym->zeroInit == 1) + { /* If a struct is all zeros, as a special case + * set it's initializer to the integer 0. + * In AssignExp::toElem(), we check for this and issue + * a memset() to initialize the struct. + * Must do same check in interpreter. + */ + Expression *e = new IntegerExp(loc, 0, Type::tint32); + Expression *e1; + e1 = new VarExp(loc, this); + e = new AssignExp(loc, e1, e); + e->op = TOKconstruct; + e->type = e1->type; // don't type check this, it would fail + init = new ExpInitializer(loc, e); + return; + } + else if (type->ty == Ttypedef) + { TypeTypedef *td = (TypeTypedef *)type; + if (td->sym->init) + { init = td->sym->init; + ExpInitializer *ie = init->isExpInitializer(); + if (ie) + // Make copy so we can modify it + init = new ExpInitializer(ie->loc, ie->exp); + } + else + init = getExpInitializer(); + } + else + { + init = getExpInitializer(); + } + // Default initializer is always a blit + op = TOKblit; + } + + if (init) + { + sc = sc->push(); + sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref); + + ArrayInitializer *ai = init->isArrayInitializer(); + if (ai && tb->ty == Taarray) + { + init = ai->toAssocArrayInitializer(); + } + + StructInitializer *si = init->isStructInitializer(); + ExpInitializer *ei = init->isExpInitializer(); + + // See if initializer is a NewExp that can be allocated on the stack + if (ei && isScope() && ei->exp->op == TOKnew) + { NewExp *ne = (NewExp *)ei->exp; + if (!(ne->newargs && ne->newargs->dim)) + { ne->onstack = 1; + onstack = 1; + if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) + onstack = 2; + } + } + + // If inside function, there is no semantic3() call + if (sc->func) + { + // If local variable, use AssignExp to handle all the various + // possibilities. + if (fd && + !(storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) && + !init->isVoidInitializer()) + { + //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); + if (!ei) + { + Expression *e = init->toExpression(); + if (!e) + { + init = init->semantic(sc, type); + e = init->toExpression(); + if (!e) + { error("is not a static and cannot have static initializer"); + return; + } + } + ei = new ExpInitializer(init->loc, e); + init = ei; + } + + Expression *e1 = new VarExp(loc, this); + + Type *t = type->toBasetype(); + if (t->ty == Tsarray) + { + ei->exp = ei->exp->semantic(sc); + if (!ei->exp->implicitConvTo(type)) + { + int dim = ((TypeSArray *)t)->dim->toInteger(); + // If multidimensional static array, treat as one large array + while (1) + { + t = t->nextOf()->toBasetype(); + if (t->ty != Tsarray) + break; + dim *= ((TypeSArray *)t)->dim->toInteger(); + e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); + } + } + e1 = new SliceExp(loc, e1, NULL, NULL); + } + else if (t->ty == Tstruct) + { + ei->exp = ei->exp->semantic(sc); + + /* Look to see if initializer is a call to the constructor + */ + StructDeclaration *sd = ((TypeStruct *)t)->sym; + if (sd->ctor && // there are constructors + ei->exp->type->ty == Tstruct && // rvalue is the same struct + ((TypeStruct *)ei->exp->type)->sym == sd && + ei->exp->op == TOKstar) + { + /* Look for form of constructor call which is: + * *__ctmp.ctor(arguments...) + */ + PtrExp *pe = (PtrExp *)ei->exp; + if (pe->e1->op == TOKcall) + { CallExp *ce = (CallExp *)pe->e1; + if (ce->e1->op == TOKdotvar) + { DotVarExp *dve = (DotVarExp *)ce->e1; + if (dve->var->isCtorDeclaration()) + { /* It's a constructor call, currently constructing + * a temporary __ctmp. + */ + /* Before calling the constructor, initialize + * variable with a bit copy of the default + * initializer + */ + Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); + e->op = TOKblit; + e->type = t; + ei->exp = new CommaExp(loc, e, ei->exp); + + /* Replace __ctmp being constructed with e1 + */ + dve->e1 = e1; + return; + } + } + } + } + + if (!ei->exp->implicitConvTo(type)) + { Type *ti = ei->exp->type->toBasetype(); + // Don't cast away invariant or mutability in initializer + if (!(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) + ei->exp = new CastExp(loc, ei->exp, type); + } + } + ei->exp = new AssignExp(loc, e1, ei->exp); + ei->exp->op = op; + canassign++; + ei->exp = ei->exp->semantic(sc); + canassign--; + ei->exp->optimize(WANTvalue); + } + else + { + init = init->semantic(sc, type); + } + } + else if (storage_class & (STCconst | STCimmutable | STCmanifest) || + type->isConst() || type->isInvariant()) + { + /* Because we may need the results of a const declaration in a + * subsequent type, such as an array dimension, before semantic2() + * gets ordinarily run, try to run semantic2() now. + * Ignore failure. + */ + + if (!global.errors && !inferred) + { + unsigned errors = global.errors; + global.gag++; + //printf("+gag\n"); + Expression *e; + Initializer *i2 = init; + inuse++; + if (ei) + { + e = ei->exp->syntaxCopy(); + e = e->semantic(sc); + e = e->implicitCastTo(sc, type); + } + else if (si || ai) + { i2 = init->syntaxCopy(); + i2 = i2->semantic(sc, type); + } + inuse--; + global.gag--; + //printf("-gag\n"); + if (errors != global.errors) // if errors happened + { + if (global.gag == 0) + global.errors = errors; // act as if nothing happened + + /* Save scope for later use, to try again + */ + scope = new Scope(*sc); + scope->setNoFree(); + } + else if (ei) + { + if (isDataseg()) + /* static const/invariant does CTFE + */ + e = e->optimize(WANTvalue | WANTinterpret); + else + e = e->optimize(WANTvalue); + if (e->op == TOKint64 || e->op == TOKstring) + { + ei->exp = e; // no errors, keep result + } + else + { + /* Save scope for later use, to try again + */ + scope = new Scope(*sc); + scope->setNoFree(); + } + } + else + init = i2; // no errors, keep result + } + } + sc = sc->pop(); + } +} + +void VarDeclaration::semantic2(Scope *sc) +{ + //printf("VarDeclaration::semantic2('%s')\n", toChars()); + if (init && !toParent()->isFuncDeclaration()) + { inuse++; +#if 0 + ExpInitializer *ei = init->isExpInitializer(); + if (ei) + { + ei->exp->dump(0); + printf("type = %p\n", ei->exp->type); + } +#endif + init = init->semantic(sc, type); + inuse--; + } +} + +const char *VarDeclaration::kind() +{ + return "variable"; +} + +Dsymbol *VarDeclaration::toAlias() +{ + //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); + assert(this != aliassym); + Dsymbol *s = aliassym ? aliassym->toAlias() : this; + return s; +} + +void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + StorageClassDeclaration::stcToCBuffer(buf, storage_class); + + /* If changing, be sure and fix CompoundDeclarationStatement::toCBuffer() + * too. + */ + if (type) + type->toCBuffer(buf, ident, hgs); + else + buf->writestring(ident->toChars()); + if (init) + { buf->writestring(" = "); + ExpInitializer *ie = init->isExpInitializer(); + if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) + ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); + else + init->toCBuffer(buf, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +int VarDeclaration::needThis() +{ + //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); + return storage_class & STCfield; +} + +int VarDeclaration::isImportedSymbol() +{ + if (protection == PROTexport && !init && + (storage_class & STCstatic || parent->isModule())) + return TRUE; + return FALSE; +} + +void VarDeclaration::checkCtorConstInit() +{ +#if 0 /* doesn't work if more than one static ctor */ + if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) + error("missing initializer in static constructor for const variable"); +#endif +} + +/************************************ + * Check to see if this variable is actually in an enclosing function + * rather than the current one. + */ + +void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) +{ + if (parent && !isDataseg() && parent != sc->parent && + !(storage_class & STCmanifest)) + { + // The function that this variable is in + FuncDeclaration *fdv = toParent()->isFuncDeclaration(); + // The current function + FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); + + if (fdv && fdthis && fdv != fdthis) + { + if (loc.filename) + fdthis->getLevel(loc, fdv); + + for (int i = 0; i < nestedrefs.dim; i++) + { FuncDeclaration *f = (FuncDeclaration *)nestedrefs.data[i]; + if (f == fdthis) + goto L1; + } + nestedrefs.push(fdthis); + L1: ; + + + for (int i = 0; i < fdv->closureVars.dim; i++) + { Dsymbol *s = (Dsymbol *)fdv->closureVars.data[i]; + if (s == this) + goto L2; + } + + fdv->closureVars.push(this); + L2: ; + + //printf("fdthis is %s\n", fdthis->toChars()); + //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); + } + } +} + +/**************************** + * Get ExpInitializer for a variable, if there is one. + */ + +ExpInitializer *VarDeclaration::getExpInitializer() +{ + ExpInitializer *ei; + + if (init) + ei = init->isExpInitializer(); + else + { + Expression *e = type->defaultInit(loc); + if (e) + ei = new ExpInitializer(loc, e); + else + ei = NULL; + } + return ei; +} + +/******************************************* + * If variable has a constant expression initializer, get it. + * Otherwise, return NULL. + */ + +Expression *VarDeclaration::getConstInitializer() +{ + if ((isConst() || isInvariant() || storage_class & STCmanifest) && + storage_class & STCinit) + { + ExpInitializer *ei = getExpInitializer(); + if (ei) + return ei->exp; + } + + return NULL; +} + +/************************************* + * Return !=0 if we can take the address of this variable. + */ + +int VarDeclaration::canTakeAddressOf() +{ +#if 0 + /* Global variables and struct/class fields of the form: + * const int x = 3; + * are not stored and hence cannot have their address taken. + */ + if ((isConst() || isInvariant()) && + storage_class & STCinit && + (!(storage_class & (STCstatic | STCextern)) || (storage_class & STCfield)) && + (!parent || toParent()->isModule() || toParent()->isTemplateInstance()) && + type->toBasetype()->isTypeBasic() + ) + { + return 0; + } +#else + if (storage_class & STCmanifest) + return 0; +#endif + return 1; +} + +/******************************* + * Does symbol go into data segment? + * Includes extern variables. + */ + +int VarDeclaration::isDataseg() +{ +#if 0 + printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); + printf("%x, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); + printf("parent = '%s'\n", parent->toChars()); +#endif + if (storage_class & STCmanifest) + return 0; + Dsymbol *parent = this->toParent(); + if (!parent && !(storage_class & STCstatic)) + { error("forward referenced"); + type = Type::terror; + return 0; + } + return canTakeAddressOf() && + (storage_class & (STCstatic | STCextern | STCtls | STCgshared) || + toParent()->isModule() || + toParent()->isTemplateInstance()); +} + +/************************************ + * Does symbol go into thread local storage? + */ + +int VarDeclaration::isThreadlocal() +{ + //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars()); +#if 0 || TARGET_OSX + /* To be thread-local, must use the __thread storage class. + * BUG: OSX doesn't support thread local yet. + */ + return isDataseg() && + (storage_class & (STCtls | STCconst | STCimmutable | STCshared | STCgshared)) == STCtls; +#else + /* Data defaults to being thread-local. It is not thread-local + * if it is immutable, const or shared. + */ + int i = isDataseg() && + !(storage_class & (STCimmutable | STCconst | STCshared | STCgshared)); + //printf("\treturn %d\n", i); + return i; +#endif +} + +int VarDeclaration::hasPointers() +{ + //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); + return (!isDataseg() && type->hasPointers()); +} + +/****************************************** + * Return TRUE if variable needs to call the destructor. + */ + +int VarDeclaration::needsAutoDtor() +{ + //printf("VarDeclaration::needsAutoDtor() %s\n", toChars()); + + if (noauto || storage_class & STCnodtor) + return FALSE; + + // Destructors for structs and arrays of structs + Type *tv = type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->dtor) + return TRUE; + } + + // Destructors for classes + if (storage_class & (STCauto | STCscope)) + { + if (type->isClassHandle()) + return TRUE; + } + return FALSE; +} + + +/****************************************** + * If a variable has an auto destructor call, return call for it. + * Otherwise, return NULL. + */ + +Expression *VarDeclaration::callAutoDtor(Scope *sc) +{ Expression *e = NULL; + + //printf("VarDeclaration::callAutoDtor() %s\n", toChars()); + + if (noauto || storage_class & STCnodtor) + return NULL; + + // Destructors for structs and arrays of structs + bool array = false; + Type *tv = type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + array = true; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->dtor) + { + if (array) + { + // Typeinfo.destroy(cast(void*)&v); + Expression *ea = new SymOffExp(loc, this, 0, 0); + ea = new CastExp(loc, ea, Type::tvoid->pointerTo()); + Expressions *args = new Expressions(); + args->push(ea); + + Expression *et = type->getTypeInfo(sc); + et = new DotIdExp(loc, et, Id::destroy); + + e = new CallExp(loc, et, args); + } + else + { + e = new VarExp(loc, this); + e = new DotVarExp(loc, e, sd->dtor, 0); + e = new CallExp(loc, e); + } + return e; + } + } + + // Destructors for classes + if (storage_class & (STCauto | STCscope)) + { + for (ClassDeclaration *cd = type->isClassHandle(); + cd; + cd = cd->baseClass) + { + /* We can do better if there's a way with onstack + * classes to determine if there's no way the monitor + * could be set. + */ + //if (cd->isInterfaceDeclaration()) + //error("interface %s cannot be scope", cd->toChars()); + if (1 || onstack || cd->dtors.dim) // if any destructors + { + // delete this; + Expression *ec; + + ec = new VarExp(loc, this); + e = new DeleteExp(loc, ec); + e->type = Type::tvoid; + break; + } + } + } + return e; +} + + +/********************************* ClassInfoDeclaration ****************************/ + +ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) + : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) +{ + this->cd = cd; + storage_class = STCstatic | STCgshared; +} + +Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +void ClassInfoDeclaration::semantic(Scope *sc) +{ +} + +/********************************* ModuleInfoDeclaration ****************************/ + +ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) + : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL) +{ + this->mod = mod; + storage_class = STCstatic | STCgshared; +} + +Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +void ModuleInfoDeclaration::semantic(Scope *sc) +{ +} + +/********************************* TypeInfoDeclaration ****************************/ + +TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) + : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) +{ + this->tinfo = tinfo; + storage_class = STCstatic | STCgshared; + protection = PROTpublic; + linkage = LINKc; +} + +Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +void TypeInfoDeclaration::semantic(Scope *sc) +{ + assert(linkage == LINKc); +} + +/***************************** TypeInfoConstDeclaration **********************/ + +#if DMDV2 +TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} +#endif + +/***************************** TypeInfoInvariantDeclaration **********************/ + +#if DMDV2 +TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} +#endif + +/***************************** TypeInfoSharedDeclaration **********************/ + +#if DMDV2 +TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} +#endif + +/***************************** TypeInfoStructDeclaration **********************/ + +TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoClassDeclaration ***********************/ + +TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoInterfaceDeclaration *******************/ + +TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoTypedefDeclaration *********************/ + +TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoPointerDeclaration *********************/ + +TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoArrayDeclaration ***********************/ + +TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoStaticArrayDeclaration *****************/ + +TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoAssociativeArrayDeclaration ************/ + +TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoEnumDeclaration ***********************/ + +TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoFunctionDeclaration ********************/ + +TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoDelegateDeclaration ********************/ + +TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoTupleDeclaration **********************/ + +TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/********************************* ThisDeclaration ****************************/ + +// For the "this" parameter to member functions + +ThisDeclaration::ThisDeclaration(Loc loc, Type *t) + : VarDeclaration(loc, t, Id::This, NULL) +{ + noauto = 1; +} + +Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +/********************** StaticStructInitDeclaration ***************************/ + +StaticStructInitDeclaration::StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym) + : Declaration(new Identifier("", TOKidentifier)) +{ + this->loc = loc; + this->dsym = dsym; + storage_class |= STCconst; +} diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/declaration.h --- a/dmd2/declaration.h Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/declaration.h Sat May 30 17:23:32 2009 +0100 @@ -1,857 +1,971 @@ - -// 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. - -#ifndef DMD_DECLARATION_H -#define DMD_DECLARATION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include -#include -#include - -#include "dsymbol.h" -#include "lexer.h" -#include "mtype.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -struct LabelStatement; -struct Initializer; -struct Module; -struct InlineScanState; -struct ForeachStatement; -struct FuncDeclaration; -struct ExpInitializer; -struct StructDeclaration; -struct TupleType; -struct InterState; -struct IRState; -struct AnonDeclaration; - -enum PROT; -enum LINK; -enum TOK; -enum MATCH; - -enum STC -{ - STCundefined = 0, - STCstatic = 1, - STCextern = 2, - STCconst = 4, - STCfinal = 8, - STCabstract = 0x10, - STCparameter = 0x20, - STCfield = 0x40, - STCoverride = 0x80, - STCauto = 0x100, - STCsynchronized = 0x200, - STCdeprecated = 0x400, - STCin = 0x800, // in parameter - STCout = 0x1000, // out parameter - STClazy = 0x2000, // lazy parameter - STCforeach = 0x4000, // variable for foreach loop - STCcomdat = 0x8000, // should go into COMDAT record - STCvariadic = 0x10000, // variadic function argument - STCctorinit = 0x20000, // can only be set inside constructor - STCtemplateparameter = 0x40000, // template parameter - STCscope = 0x80000, // template parameter - STCinvariant = 0x100000, - STCref = 0x200000, - STCinit = 0x400000, // has explicit initializer - STCmanifest = 0x800000, // manifest constant - STCnodtor = 0x1000000, // don't run destructor - STCnothrow = 0x2000000, // never throws exceptions - STCpure = 0x4000000, // pure function - STCtls = 0x8000000, // thread local - STCalias = 0x10000000, // alias parameter - STCshared = 0x20000000, // accessible from multiple threads -}; - -struct Match -{ - int count; // number of matches found - MATCH last; // match level of lastf - FuncDeclaration *lastf; // last matching function we found - FuncDeclaration *nextf; // current matching function - FuncDeclaration *anyf; // pick a func, any func, to use for error recovery -}; - -void overloadResolveX(Match *m, FuncDeclaration *f, - Expression *ethis, Expressions *arguments); -int overloadApply(FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param); - -/**************************************************************/ - -struct Declaration : Dsymbol -{ - Type *type; - Type *originalType; // before semantic analysis - unsigned storage_class; - enum PROT protection; - enum LINK linkage; - - Declaration(Identifier *id); - void semantic(Scope *sc); - const char *kind(); - unsigned size(Loc loc); - void checkModify(Loc loc, Scope *sc, Type *t); - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - char *mangle(); - int isStatic() { return storage_class & STCstatic; } - virtual int isStaticConstructor(); - virtual int isStaticDestructor(); - virtual int isDelete(); - virtual int isDataseg(); - virtual int isCodeseg(); - int isCtorinit() { return storage_class & STCctorinit; } - int isFinal() { return storage_class & STCfinal; } - int isAbstract() { return storage_class & STCabstract; } - int isConst() { return storage_class & STCconst; } - int isInvariant() { return storage_class & STCinvariant; } - int isAuto() { return storage_class & STCauto; } - int isScope() { return storage_class & (STCscope | STCauto); } - int isSynchronized() { return storage_class & STCsynchronized; } - int isParameter() { return storage_class & STCparameter; } - int isDeprecated() { return storage_class & STCdeprecated; } - int isOverride() { return storage_class & STCoverride; } - - int isIn() { return storage_class & STCin; } - int isOut() { return storage_class & STCout; } - int isRef() { return storage_class & STCref; } - - enum PROT prot(); - - Declaration *isDeclaration() { return this; } - - // llvm - virtual void toObjFile(int unused = 0); // compile to .obj file -}; - -/**************************************************************/ - -struct TupleDeclaration : Declaration -{ - Objects *objects; - int isexp; // 1: expression tuple - - TypeTuple *tupletype; // !=NULL if this is a type tuple - - TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); - Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); - Type *getType(); - int needThis(); - - TupleDeclaration *isTupleDeclaration() { return this; } - - // LDC we need this - void toObjFile(int multiobj); // compile to .obj file -}; - -/**************************************************************/ - -struct TypedefDeclaration : Declaration -{ - Type *basetype; - Initializer *init; - int sem; // 0: semantic() has not been run - // 1: semantic() is in progress - // 2: semantic() has been run - // 3: semantic2() has been run - int inuse; // used to detect typedef cycles - - TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - char *mangle(); - const char *kind(); - Type *getType(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Type *hbasetype; -#endif - - void toDocBuffer(OutBuffer *buf); - - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); - - TypedefDeclaration *isTypedefDeclaration() { return this; } - - Symbol *sinit; - Symbol *toInitializer(); -}; - -/**************************************************************/ - -struct AliasDeclaration : Declaration -{ - Dsymbol *aliassym; - Dsymbol *overnext; // next in overload list - int inSemantic; - - AliasDeclaration(Loc loc, Identifier *ident, Type *type); - AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); - const char *kind(); - Type *getType(); - Dsymbol *toAlias(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Dsymbol *haliassym; -#endif - - void toDocBuffer(OutBuffer *buf); - - AliasDeclaration *isAliasDeclaration() { return this; } -}; - -/**************************************************************/ - -struct VarDeclaration : Declaration -{ - Initializer *init; - unsigned offset; - int noauto; // no auto semantics - FuncDeclarations nestedrefs; // referenced by these lexically nested functions - int inuse; - int ctorinit; // it has been initialized in a ctor - int onstack; // 1: it has been allocated on the stack - // 2: on stack, run destructor anyway - int canassign; // it can be assigned to - Dsymbol *aliassym; // if redone as alias to another symbol - Expression *value; // when interpreting, this is the value - // (NULL if value not determinable) - Scope *scope; // !=NULL means context to use - - VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Initializer *hinit; -#endif - int needThis(); - int isImportedSymbol(); - int isDataseg(); - int hasPointers(); - int canTakeAddressOf(); - int needsAutoDtor(); - Expression *callAutoDtor(Scope *sc); - ExpInitializer *getExpInitializer(); - Expression *getConstInitializer(); - void checkCtorConstInit(); - void checkNestedReference(Scope *sc, Loc loc); - Dsymbol *toAlias(); - - Symbol *toSymbol(); - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); - - // Eliminate need for dynamic_cast - VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } - - // LDC - AnonDeclaration* anonDecl; - unsigned offset2; - bool nakedUse; -}; - -/**************************************************************/ - -// LDC uses this to denote static struct initializers - -struct StaticStructInitDeclaration : Declaration -{ - StructDeclaration *dsym; - - StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym); - - Symbol *toSymbol(); - - // Eliminate need for dynamic_cast - StaticStructInitDeclaration *isStaticStructInitDeclaration() { return (StaticStructInitDeclaration *)this; } -}; - -struct ClassInfoDeclaration : VarDeclaration -{ - ClassDeclaration *cd; - - ClassInfoDeclaration(ClassDeclaration *cd); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - - Symbol *toSymbol(); - - ClassInfoDeclaration* isClassInfoDeclaration() { return this; } -}; - -struct ModuleInfoDeclaration : VarDeclaration -{ - Module *mod; - - ModuleInfoDeclaration(Module *mod); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - - Symbol *toSymbol(); -}; - -struct TypeInfoDeclaration : VarDeclaration -{ - Type *tinfo; - - TypeInfoDeclaration(Type *tinfo, int internal); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - - Symbol *toSymbol(); - void toObjFile(int multiobj); // compile to .obj file - virtual void toDt(dt_t **pdt); - - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } - - // LDC - virtual void llvmDeclare(); - virtual void llvmDefine(); -}; - -struct TypeInfoStructDeclaration : TypeInfoDeclaration -{ - TypeInfoStructDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoClassDeclaration : TypeInfoDeclaration -{ - TypeInfoClassDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration -{ - TypeInfoInterfaceDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoTypedefDeclaration : TypeInfoDeclaration -{ - TypeInfoTypedefDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoPointerDeclaration : TypeInfoDeclaration -{ - TypeInfoPointerDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoArrayDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoStaticArrayDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoAssociativeArrayDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoEnumDeclaration : TypeInfoDeclaration -{ - TypeInfoEnumDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoFunctionDeclaration : TypeInfoDeclaration -{ - TypeInfoFunctionDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoDelegateDeclaration : TypeInfoDeclaration -{ - TypeInfoDelegateDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoTupleDeclaration : TypeInfoDeclaration -{ - TypeInfoTupleDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -#if DMDV2 -struct TypeInfoConstDeclaration : TypeInfoDeclaration -{ - TypeInfoConstDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; - -struct TypeInfoInvariantDeclaration : TypeInfoDeclaration -{ - TypeInfoInvariantDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); - - // LDC - void llvmDeclare(); - void llvmDefine(); -}; -#endif - -/**************************************************************/ - -struct ThisDeclaration : VarDeclaration -{ - ThisDeclaration(Type *t); - Dsymbol *syntaxCopy(Dsymbol *); -}; - -enum ILS -{ - ILSuninitialized, // not computed yet - ILSno, // cannot inline - ILSyes, // can inline -}; - -/**************************************************************/ -#if DMDV2 - -enum BUILTIN -{ - BUILTINunknown = -1, // not known if this is a builtin - BUILTINnot, // this is not a builtin - BUILTINsin, // std.math.sin - BUILTINcos, // std.math.cos - BUILTINtan, // std.math.tan - BUILTINsqrt, // std.math.sqrt - BUILTINfabs, // std.math.fabs -}; - -Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments); - -#endif - -struct FuncDeclaration : Declaration -{ - Array *fthrows; // Array of Type's of exceptions (not used) - Statement *frequire; - Statement *fensure; - Statement *fbody; - - Identifier *outId; // identifier for out statement - VarDeclaration *vresult; // variable corresponding to outId - LabelDsymbol *returnLabel; // where the return goes - - DsymbolTable *localsymtab; // used to prevent symbols in different - // scopes from having the same name - VarDeclaration *vthis; // 'this' parameter (member and nested) - VarDeclaration *v_arguments; // '_arguments' parameter -#if IN_GCC - VarDeclaration *v_argptr; // '_argptr' variable -#endif - Dsymbols *parameters; // Array of VarDeclaration's for parameters - DsymbolTable *labtab; // statement label symbol table - Declaration *overnext; // next in overload list - Loc endloc; // location of closing curly bracket - int vtblIndex; // for member functions, index into vtbl[] - int naked; // !=0 if naked - int inlineAsm; // !=0 if has inline assembler - ILS inlineStatus; - int inlineNest; // !=0 if nested inline - int cantInterpret; // !=0 if cannot interpret function - int semanticRun; // !=0 if semantic3() had been run - // this function's frame ptr - ForeachStatement *fes; // if foreach body, this is the foreach - int introducing; // !=0 if 'introducing' function - Type *tintro; // if !=NULL, then this is the type - // of the 'introducing' function - // this one is overriding - int inferRetType; // !=0 if return type is to be inferred - Scope *scope; // !=NULL means context to use - - // Things that should really go into Scope - int hasReturnExp; // 1 if there's a return exp; statement - // 2 if there's a throw statement - // 4 if there's an assert(0) - // 8 if there's inline asm - - // Support for NRVO (named return value optimization) - int nrvo_can; // !=0 means we can do it - VarDeclaration *nrvo_var; // variable to replace with shidden - Symbol *shidden; // hidden pointer passed to function - -#if DMDV2 - enum BUILTIN builtin; // set if this is a known, builtin - // function we can evaluate at compile - // time - - int tookAddressOf; // set if someone took the address of - // this function - Dsymbols closureVars; // local variables in this function - // which are referenced by nested - // functions -#else - int nestedFrameRef; // !=0 if nested variables referenced -#endif - - FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); - int overrides(FuncDeclaration *fd); - int findVtblIndex(Array *vtbl, int dim); - int overloadInsert(Dsymbol *s); - FuncDeclaration *overloadExactMatch(Type *t); - FuncDeclaration *overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags = 0); - MATCH leastAsSpecialized(FuncDeclaration *g); - LabelDsymbol *searchLabel(Identifier *ident); - AggregateDeclaration *isThis(); - AggregateDeclaration *isMember2(); - int getLevel(Loc loc, FuncDeclaration *fd); // lexical nesting level difference - void appendExp(Expression *e); - void appendState(Statement *s); - char *mangle(); - int isMain(); - int isWinMain(); - int isDllMain(); - enum BUILTIN isBuiltin(); - int isExport(); - int isImportedSymbol(); - int isAbstract(); - int isCodeseg(); - int isOverloadable(); - virtual int isNested(); - int needThis(); - virtual int isVirtual(); - virtual int isFinal(); - virtual int addPreInvariant(); - virtual int addPostInvariant(); - Expression *interpret(InterState *istate, Expressions *arguments); - void inlineScan(); - int canInline(int hasthis, int hdrscan = 0); - Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); - const char *kind(); - void toDocBuffer(OutBuffer *buf); - FuncDeclaration *isUnique(); - int needsClosure(); - -// LDC: give argument types to runtime functions - static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, const char *name); - static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, Identifier *id); - - Symbol *toSymbol(); - Symbol *toThunkSymbol(int offset); // thunk version - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); - void buildClosure(IRState *irs); - - FuncDeclaration *isFuncDeclaration() { return this; } - - // LDC stuff - - // vars declared in this function that nested funcs reference - // is this is not empty, nestedFrameRef is set and these VarDecls - // probably have nestedref set too, see VarDeclaration::checkNestedReference - std::set nestedVars; - - std::string intrinsicName; - - bool isIntrinsic(); - bool isVaIntrinsic(); - - // we keep our own table of label statements as LabelDsymbolS - // don't always carry their corresponding statement along ... - typedef std::map LabelMap; - LabelMap labmap; - - // if this is an array operation it gets a little special attention - bool isArrayOp; - - // true if overridden with the pragma(allow_inline); stmt - bool allowInlining; -}; - -struct FuncAliasDeclaration : FuncDeclaration -{ - FuncDeclaration *funcalias; - - FuncAliasDeclaration(FuncDeclaration *funcalias); - - FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - const char *kind(); - Symbol *toSymbol(); -}; - -struct FuncLiteralDeclaration : FuncDeclaration -{ - enum TOK tok; // TOKfunction or TOKdelegate - - FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, - ForeachStatement *fes); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *syntaxCopy(Dsymbol *); - int isNested(); - int isVirtual(); - - FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - const char *kind(); -}; - -struct CtorDeclaration : FuncDeclaration -{ Arguments *arguments; - int varargs; - - CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toDocBuffer(OutBuffer *buf); - - CtorDeclaration *isCtorDeclaration() { return this; } -}; - -#if DMDV2 -struct PostBlitDeclaration : FuncDeclaration -{ - PostBlitDeclaration(Loc loc, Loc endloc); - PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - - PostBlitDeclaration *isPostBlitDeclaration() { return this; } -}; -#endif - -struct DtorDeclaration : FuncDeclaration -{ - DtorDeclaration(Loc loc, Loc endloc); - DtorDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - - DtorDeclaration *isDtorDeclaration() { return this; } -}; - -struct StaticCtorDeclaration : FuncDeclaration -{ - StaticCtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticConstructor(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } -}; - -struct StaticDtorDeclaration : FuncDeclaration -{ VarDeclaration *vgate; // 'gate' variable - - StaticDtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticDestructor(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } -}; - -struct InvariantDeclaration : FuncDeclaration -{ - InvariantDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - InvariantDeclaration *isInvariantDeclaration() { return this; } -}; - - -struct UnitTestDeclaration : FuncDeclaration -{ - UnitTestDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - UnitTestDeclaration *isUnitTestDeclaration() { return this; } -}; - -struct NewDeclaration : FuncDeclaration -{ Arguments *arguments; - int varargs; - - NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - - NewDeclaration *isNewDeclaration() { return this; } -}; - - -struct DeleteDeclaration : FuncDeclaration -{ Arguments *arguments; - - DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isDelete(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); -#ifdef _DH - DeleteDeclaration *isDeleteDeclaration() { return this; } -#endif -}; - -#endif /* DMD_DECLARATION_H */ + +// 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. + +#ifndef DMD_DECLARATION_H +#define DMD_DECLARATION_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#if IN_LLVM +#include +#include +#include +#endif + +#include "dsymbol.h" +#include "lexer.h" +#include "mtype.h" + +struct Expression; +struct Statement; +struct LabelDsymbol; +#if IN_LLVM +struct LabelStatement; +#endif +struct Initializer; +struct Module; +struct InlineScanState; +struct ForeachStatement; +struct FuncDeclaration; +struct ExpInitializer; +struct StructDeclaration; +struct TupleType; +struct InterState; +struct IRState; +#if IN_LLVM +struct AnonDeclaration; +#endif + +enum PROT; +enum LINK; +enum TOK; +enum MATCH; + +enum STC +{ + STCundefined = 0, + STCstatic = 1, + STCextern = 2, + STCconst = 4, + STCfinal = 8, + STCabstract = 0x10, + STCparameter = 0x20, + STCfield = 0x40, + STCoverride = 0x80, + STCauto = 0x100, + STCsynchronized = 0x200, + STCdeprecated = 0x400, + STCin = 0x800, // in parameter + STCout = 0x1000, // out parameter + STClazy = 0x2000, // lazy parameter + STCforeach = 0x4000, // variable for foreach loop + STCcomdat = 0x8000, // should go into COMDAT record + STCvariadic = 0x10000, // variadic function argument + STCctorinit = 0x20000, // can only be set inside constructor + STCtemplateparameter = 0x40000, // template parameter + STCscope = 0x80000, // template parameter + STCinvariant = 0x100000, + STCimmutable = 0x100000, + STCref = 0x200000, + STCinit = 0x400000, // has explicit initializer + STCmanifest = 0x800000, // manifest constant + STCnodtor = 0x1000000, // don't run destructor + STCnothrow = 0x2000000, // never throws exceptions + STCpure = 0x4000000, // pure function + STCtls = 0x8000000, // thread local + STCalias = 0x10000000, // alias parameter + STCshared = 0x20000000, // accessible from multiple threads + STCgshared = 0x40000000, // accessible from multiple threads + // but not typed as "shared" + STC_TYPECTOR = (STCconst | STCimmutable | STCshared), +}; + +struct Match +{ + int count; // number of matches found + MATCH last; // match level of lastf + FuncDeclaration *lastf; // last matching function we found + FuncDeclaration *nextf; // current matching function + FuncDeclaration *anyf; // pick a func, any func, to use for error recovery +}; + +void overloadResolveX(Match *m, FuncDeclaration *f, + Expression *ethis, Expressions *arguments, Module* from); +int overloadApply(Module* from, FuncDeclaration *fstart, + int (*fp)(void *, FuncDeclaration *), + void *param); + +/**************************************************************/ + +struct Declaration : Dsymbol +{ + Type *type; + Type *originalType; // before semantic analysis + unsigned storage_class; + enum PROT protection; + enum LINK linkage; + int inuse; // used to detect cycles + + Declaration(Identifier *id); + void semantic(Scope *sc); + const char *kind(); + unsigned size(Loc loc); + void checkModify(Loc loc, Scope *sc, Type *t); + + void emitComment(Scope *sc); + void toDocBuffer(OutBuffer *buf); + + char *mangle(); + int isStatic() { return storage_class & STCstatic; } + virtual int isStaticConstructor(); + virtual int isStaticDestructor(); + virtual int isDelete(); + virtual int isDataseg(); + virtual int isThreadlocal(); + virtual int isCodeseg(); + int isCtorinit() { return storage_class & STCctorinit; } + int isFinal() { return storage_class & STCfinal; } + int isAbstract() { return storage_class & STCabstract; } + int isConst() { return storage_class & STCconst; } + int isInvariant() { return storage_class & STCinvariant; } + int isAuto() { return storage_class & STCauto; } + int isScope() { return storage_class & (STCscope | STCauto); } + int isSynchronized() { return storage_class & STCsynchronized; } + int isParameter() { return storage_class & STCparameter; } + int isDeprecated() { return storage_class & STCdeprecated; } + int isOverride() { return storage_class & STCoverride; } + + int isIn() { return storage_class & STCin; } + int isOut() { return storage_class & STCout; } + int isRef() { return storage_class & STCref; } + + enum PROT prot(); + + Declaration *isDeclaration() { return this; } + +#if IN_LLVM + /// Codegen traversal + virtual void codegen(Ir* ir); +#endif +}; + +/**************************************************************/ + +struct TupleDeclaration : Declaration +{ + Objects *objects; + int isexp; // 1: expression tuple + + TypeTuple *tupletype; // !=NULL if this is a type tuple + + TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); + Dsymbol *syntaxCopy(Dsymbol *); + const char *kind(); + Type *getType(); + int needThis(); + + TupleDeclaration *isTupleDeclaration() { return this; } + +#if IN_LLVM + /// Codegen traversal + void codegen(Ir* ir); +#endif +}; + +/**************************************************************/ + +struct TypedefDeclaration : Declaration +{ + Type *basetype; + Initializer *init; + int sem; // 0: semantic() has not been run + // 1: semantic() is in progress + // 2: semantic() has been run + // 3: semantic2() has been run + + TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + char *mangle(); + const char *kind(); + Type *getType(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Type *hbasetype; +#endif + + void toDocBuffer(OutBuffer *buf); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + void toDebug(); + int cvMember(unsigned char *p); +#endif + + TypedefDeclaration *isTypedefDeclaration() { return this; } + +#if IN_DMD + Symbol *sinit; + Symbol *toInitializer(); +#endif + +#if IN_LLVM + /// Codegen traversal + void codegen(Ir* ir); +#endif +}; + +/**************************************************************/ + +struct AliasDeclaration : Declaration +{ + Dsymbol *aliassym; + Dsymbol *overnext; // next in overload list + int inSemantic; + PROT importprot; // if generated by import, store its protection + + AliasDeclaration(Loc loc, Identifier *ident, Type *type); + AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + int overloadInsert(Dsymbol *s); + const char *kind(); + Type *getType(); + Dsymbol *toAlias(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Dsymbol *haliassym; +#endif + + void toDocBuffer(OutBuffer *buf); + + AliasDeclaration *isAliasDeclaration() { return this; } +}; + +/**************************************************************/ + +struct VarDeclaration : Declaration +{ + Initializer *init; + unsigned offset; + int noauto; // no auto semantics + FuncDeclarations nestedrefs; // referenced by these lexically nested functions + int ctorinit; // it has been initialized in a ctor + int onstack; // 1: it has been allocated on the stack + // 2: on stack, run destructor anyway + int canassign; // it can be assigned to + Dsymbol *aliassym; // if redone as alias to another symbol + Expression *value; // when interpreting, this is the value + // (NULL if value not determinable) + Scope *scope; // !=NULL means context to use + + VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + const char *kind(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Initializer *hinit; +#endif + int needThis(); + int isImportedSymbol(); + int isDataseg(); + int isThreadlocal(); + int hasPointers(); + int canTakeAddressOf(); + int needsAutoDtor(); + Expression *callAutoDtor(Scope *sc); + ExpInitializer *getExpInitializer(); + Expression *getConstInitializer(); + void checkCtorConstInit(); + void checkNestedReference(Scope *sc, Loc loc); + Dsymbol *toAlias(); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + Symbol *toSymbol(); + int cvMember(unsigned char *p); +#endif + + // Eliminate need for dynamic_cast + VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } + +#if IN_LLVM + /// Codegen traversal + virtual void codegen(Ir* ir); + + /// Index into parent aggregate. + /// Set during type generation. + unsigned aggrIndex; + + // FIXME: we're not using these anymore! + AnonDeclaration* anonDecl; + unsigned offset2; + + /// This var is used by a naked function. + bool nakedUse; +#endif +}; + +/**************************************************************/ + +// LDC uses this to denote static struct initializers + +struct StaticStructInitDeclaration : Declaration +{ + StructDeclaration *dsym; + + StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym); + +#if IN_DMD + Symbol *toSymbol(); +#endif + + // Eliminate need for dynamic_cast + StaticStructInitDeclaration *isStaticStructInitDeclaration() { return (StaticStructInitDeclaration *)this; } +}; + +struct ClassInfoDeclaration : VarDeclaration +{ + ClassDeclaration *cd; + + ClassInfoDeclaration(ClassDeclaration *cd); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + +#if IN_DMD + Symbol *toSymbol(); +#endif + + ClassInfoDeclaration* isClassInfoDeclaration() { return this; } +}; + +struct ModuleInfoDeclaration : VarDeclaration +{ + Module *mod; + + ModuleInfoDeclaration(Module *mod); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + +#if IN_DMD + Symbol *toSymbol(); +#endif +}; + +struct TypeInfoDeclaration : VarDeclaration +{ + Type *tinfo; + + TypeInfoDeclaration(Type *tinfo, int internal); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + Symbol *toSymbol(); + virtual void toDt(dt_t **pdt); +#endif + + virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } + +#if IN_LLVM + /// Codegen traversal + void codegen(Ir* ir); + virtual void llvmDefine(); +#endif +}; + +struct TypeInfoStructDeclaration : TypeInfoDeclaration +{ + TypeInfoStructDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoClassDeclaration : TypeInfoDeclaration +{ + TypeInfoClassDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration +{ + TypeInfoInterfaceDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoTypedefDeclaration : TypeInfoDeclaration +{ + TypeInfoTypedefDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoPointerDeclaration : TypeInfoDeclaration +{ + TypeInfoPointerDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoArrayDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoStaticArrayDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoAssociativeArrayDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoEnumDeclaration : TypeInfoDeclaration +{ + TypeInfoEnumDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoFunctionDeclaration : TypeInfoDeclaration +{ + TypeInfoFunctionDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoDelegateDeclaration : TypeInfoDeclaration +{ + TypeInfoDelegateDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoTupleDeclaration : TypeInfoDeclaration +{ + TypeInfoTupleDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +#if DMDV2 +struct TypeInfoConstDeclaration : TypeInfoDeclaration +{ + TypeInfoConstDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoInvariantDeclaration : TypeInfoDeclaration +{ + TypeInfoInvariantDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoSharedDeclaration : TypeInfoDeclaration +{ + TypeInfoSharedDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif +}; +#endif + +/**************************************************************/ + +struct ThisDeclaration : VarDeclaration +{ + ThisDeclaration(Loc loc, Type *t); + Dsymbol *syntaxCopy(Dsymbol *); + ThisDeclaration *isThisDeclaration() { return this; } +}; + +enum ILS +{ + ILSuninitialized, // not computed yet + ILSno, // cannot inline + ILSyes, // can inline +}; + +/**************************************************************/ +#if DMDV2 + +enum BUILTIN +{ + BUILTINunknown = -1, // not known if this is a builtin + BUILTINnot, // this is not a builtin + BUILTINsin, // std.math.sin + BUILTINcos, // std.math.cos + BUILTINtan, // std.math.tan + BUILTINsqrt, // std.math.sqrt + BUILTINfabs, // std.math.fabs +}; + +Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments); + +#endif + +struct FuncDeclaration : Declaration +{ + Array *fthrows; // Array of Type's of exceptions (not used) + Statement *frequire; + Statement *fensure; + Statement *fbody; + + Identifier *outId; // identifier for out statement + VarDeclaration *vresult; // variable corresponding to outId + LabelDsymbol *returnLabel; // where the return goes + + DsymbolTable *localsymtab; // used to prevent symbols in different + // scopes from having the same name + VarDeclaration *vthis; // 'this' parameter (member and nested) + VarDeclaration *v_arguments; // '_arguments' parameter +#if IN_GCC + VarDeclaration *v_argptr; // '_argptr' variable +#endif + Dsymbols *parameters; // Array of VarDeclaration's for parameters + DsymbolTable *labtab; // statement label symbol table + Declaration *overnext; // next in overload list + Loc endloc; // location of closing curly bracket + int vtblIndex; // for member functions, index into vtbl[] + int naked; // !=0 if naked + int inlineAsm; // !=0 if has inline assembler + ILS inlineStatus; + int inlineNest; // !=0 if nested inline + int cantInterpret; // !=0 if cannot interpret function + int semanticRun; // 1 semantic() run + // 2 semantic2() run + // 3 semantic3() started + // 4 semantic3() done + // 5 toObjFile() run + // this function's frame ptr + ForeachStatement *fes; // if foreach body, this is the foreach + int introducing; // !=0 if 'introducing' function + Type *tintro; // if !=NULL, then this is the type + // of the 'introducing' function + // this one is overriding + int inferRetType; // !=0 if return type is to be inferred + Scope *scope; // !=NULL means context to use + + // Things that should really go into Scope + int hasReturnExp; // 1 if there's a return exp; statement + // 2 if there's a throw statement + // 4 if there's an assert(0) + // 8 if there's inline asm + + // Support for NRVO (named return value optimization) + int nrvo_can; // !=0 means we can do it + VarDeclaration *nrvo_var; // variable to replace with shidden +#if IN_DMD + Symbol *shidden; // hidden pointer passed to function +#endif + +#if DMDV2 + enum BUILTIN builtin; // set if this is a known, builtin + // function we can evaluate at compile + // time + + int tookAddressOf; // set if someone took the address of + // this function + Dsymbols closureVars; // local variables in this function + // which are referenced by nested + // functions +#else + int nestedFrameRef; // !=0 if nested variables referenced +#endif + + FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + // called from semantic3 + void varArgs(Scope *sc, TypeFunction*, VarDeclaration *&, VarDeclaration *&); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); + int overrides(FuncDeclaration *fd); + int findVtblIndex(Array *vtbl, int dim); + int overloadInsert(Dsymbol *s); + FuncDeclaration *overloadExactMatch(Type *t, Module* from); + FuncDeclaration *overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags = 0, Module* from=NULL); + MATCH leastAsSpecialized(FuncDeclaration *g); + LabelDsymbol *searchLabel(Identifier *ident); + AggregateDeclaration *isThis(); + AggregateDeclaration *isMember2(); + int getLevel(Loc loc, FuncDeclaration *fd); // lexical nesting level difference + void appendExp(Expression *e); + void appendState(Statement *s); + char *mangle(); + int isMain(); + int isWinMain(); + int isDllMain(); + enum BUILTIN isBuiltin(); + int isExport(); + int isImportedSymbol(); + int isAbstract(); + int isCodeseg(); + int isOverloadable(); + int isPure(); + virtual int isNested(); + int needThis(); + virtual int isVirtual(); + virtual int isFinal(); + virtual int addPreInvariant(); + virtual int addPostInvariant(); + Expression *interpret(InterState *istate, Expressions *arguments); + void inlineScan(); + int canInline(int hasthis, int hdrscan = 0); + Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); + const char *kind(); + void toDocBuffer(OutBuffer *buf); + FuncDeclaration *isUnique(); + int needsClosure(); + +// LDC: give argument types to runtime functions + static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, const char *name); + static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, Identifier *id); + +#if IN_DMD + Symbol *toSymbol(); + Symbol *toThunkSymbol(int offset); // thunk version + void toObjFile(int multiobj); // compile to .obj file + int cvMember(unsigned char *p); + void buildClosure(IRState *irs); // Should this be inside or outside the #if IN_DMD? +#endif + FuncDeclaration *isFuncDeclaration() { return this; } + +#if IN_LLVM + // LDC stuff + + /// Codegen traversal + void codegen(Ir* ir); + + // vars declared in this function that nested funcs reference + // is this is not empty, nestedFrameRef is set and these VarDecls + // probably have nestedref set too, see VarDeclaration::checkNestedReference + std::set nestedVars; + + std::string intrinsicName; + + bool isIntrinsic(); + bool isVaIntrinsic(); + + // we keep our own table of label statements as LabelDsymbolS + // don't always carry their corresponding statement along ... + typedef std::map LabelMap; + LabelMap labmap; + + // if this is an array operation it gets a little special attention + bool isArrayOp; + + // true if overridden with the pragma(allow_inline); stmt + bool allowInlining; +#endif +}; + +FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, + Objects *tiargs, + Expression *ethis, + Expressions *arguments, + int flags); + + +struct FuncAliasDeclaration : FuncDeclaration +{ + FuncDeclaration *funcalias; + PROT importprot; // if generated by import, store its protection + + FuncAliasDeclaration(FuncDeclaration *funcalias); + + FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } + const char *kind(); +#if IN_DMD + Symbol *toSymbol(); +#endif +}; + +struct FuncLiteralDeclaration : FuncDeclaration +{ + enum TOK tok; // TOKfunction or TOKdelegate + + FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, + ForeachStatement *fes); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Dsymbol *syntaxCopy(Dsymbol *); + int isNested(); + int isVirtual(); + + FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } + const char *kind(); +}; + +struct CtorDeclaration : FuncDeclaration +{ Arguments *arguments; + int varargs; + + CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + char *toChars(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void toDocBuffer(OutBuffer *buf); + + CtorDeclaration *isCtorDeclaration() { return this; } +}; + +#if DMDV2 +struct PostBlitDeclaration : FuncDeclaration +{ + PostBlitDeclaration(Loc loc, Loc endloc); + PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + int overloadInsert(Dsymbol *s); + void emitComment(Scope *sc); + + PostBlitDeclaration *isPostBlitDeclaration() { return this; } +}; +#endif + +struct DtorDeclaration : FuncDeclaration +{ + DtorDeclaration(Loc loc, Loc endloc); + DtorDeclaration(Loc loc, Loc endloc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + char *toChars(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + int overloadInsert(Dsymbol *s); + void emitComment(Scope *sc); + + DtorDeclaration *isDtorDeclaration() { return this; } +}; + +struct StaticCtorDeclaration : FuncDeclaration +{ + StaticCtorDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isStaticConstructor(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } +}; + +struct StaticDtorDeclaration : FuncDeclaration +{ VarDeclaration *vgate; // 'gate' variable + + StaticDtorDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isStaticDestructor(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } +}; + +struct InvariantDeclaration : FuncDeclaration +{ + InvariantDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + InvariantDeclaration *isInvariantDeclaration() { return this; } +}; + + +struct UnitTestDeclaration : FuncDeclaration +{ + UnitTestDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + UnitTestDeclaration *isUnitTestDeclaration() { return this; } +}; + +struct NewDeclaration : FuncDeclaration +{ Arguments *arguments; + int varargs; + + NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + + NewDeclaration *isNewDeclaration() { return this; } +}; + + +struct DeleteDeclaration : FuncDeclaration +{ Arguments *arguments; + + DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + int isDelete(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); +#ifdef _DH + DeleteDeclaration *isDeleteDeclaration() { return this; } +#endif +}; + +#endif /* DMD_DECLARATION_H */ diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/doc.c --- a/dmd2/doc.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/doc.c Sat May 30 17:23:32 2009 +0100 @@ -1,2028 +1,2019 @@ - -// 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. - -// This implements the Ddoc capability. - -#include -#include -#include -#include -#include - -#if IN_GCC || IN_LLVM -#include "mem.h" -#else -#if _WIN32 -#include "..\root\mem.h" -#elif POSIX -#include "../root/mem.h" -#else -#error "fix this" -#endif -#endif - -#include "root.h" - -#include "mars.h" -#include "dsymbol.h" -#include "macro.h" -#include "template.h" -#include "lexer.h" -#include "aggregate.h" -#include "declaration.h" -#include "enum.h" -#include "id.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "doc.h" -#include "mtype.h" - -struct Escape -{ - const char *strings[256]; - - static const char *escapeChar(unsigned c); -}; - -struct Section -{ - unsigned char *name; - unsigned namelen; - - unsigned char *body; - unsigned bodylen; - - int nooutput; - - virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct ParamSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct MacroSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct DocComment -{ - Array sections; // Section*[] - - Section *summary; - Section *copyright; - Section *macros; - Macro **pmacrotable; - Escape **pescapetable; - - DocComment(); - - static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); - static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); - static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); - - void parseSections(unsigned char *comment); - void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - - -int cmp(const char *stringz, void *s, size_t slen); -int icmp(const char *stringz, void *s, size_t slen); -int isDitto(unsigned char *comment); -unsigned char *skipwhitespace(unsigned char *p); -unsigned skiptoident(OutBuffer *buf, unsigned i); -unsigned skippastident(OutBuffer *buf, unsigned i); -unsigned skippastURL(OutBuffer *buf, unsigned i); -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); - -static unsigned char ddoc_default[] = "\ -DDOC = \n\ - \n\ - $(TITLE)\n\ - \n\ -

$(TITLE)

\n\ - $(BODY)\n\ -
$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ - \n\ -\n\ -B = $0\n\ -I = $0\n\ -U = $0\n\ -P =

$0

\n\ -DL =
$0
\n\ -DT =
$0
\n\ -DD =
$0
\n\ -TABLE = $0
\n\ -TR = $0\n\ -TH = $0\n\ -TD = $0\n\ -OL =
    $0
\n\ -UL =
    $0
\n\ -LI =
  • $0
  • \n\ -BIG = $0\n\ -SMALL = $0\n\ -BR =
    \n\ -LINK = $0\n\ -LINK2 = $+\n\ -\n\ -RED = $0\n\ -BLUE = $0\n\ -GREEN = $0\n\ -YELLOW =$0\n\ -BLACK = $0\n\ -WHITE = $0\n\ -\n\ -D_CODE =
    $0
    \n\ -D_COMMENT = $(GREEN $0)\n\ -D_STRING = $(RED $0)\n\ -D_KEYWORD = $(BLUE $0)\n\ -D_PSYMBOL = $(U $0)\n\ -D_PARAM = $(I $0)\n\ -\n\ -DDOC_COMMENT = \n\ -DDOC_DECL = $(DT $(BIG $0))\n\ -DDOC_DECL_DD = $(DD $0)\n\ -DDOC_DITTO = $(BR)$0\n\ -DDOC_SECTIONS = $0\n\ -DDOC_SUMMARY = $0$(BR)$(BR)\n\ -DDOC_DESCRIPTION = $0$(BR)$(BR)\n\ -DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SECTION_H = $(B $0)$(BR)\n\ -DDOC_SECTION = $0$(BR)$(BR)\n\ -DDOC_MEMBERS = $(DL $0)\n\ -DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ -DDOC_PARAM_ROW = $(TR $0)\n\ -DDOC_PARAM_ID = $(TD $0)\n\ -DDOC_PARAM_DESC = $(TD $0)\n\ -DDOC_BLANKLINE = $(BR)$(BR)\n\ -\n\ -DDOC_PSYMBOL = $(U $0)\n\ -DDOC_KEYWORD = $(B $0)\n\ -DDOC_PARAM = $(I $0)\n\ -\n\ -ESCAPES = //>/\n\ - /&/&/\n\ -"; - -static char ddoc_decl_s[] = "$(DDOC_DECL "; -static char ddoc_decl_e[] = ")\n"; - -static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD "; -static char ddoc_decl_dd_e[] = ")\n"; - - -/**************************************************** - */ - -void Module::gendocfile() -{ - static OutBuffer mbuf; - static int mbuf_done; - - OutBuffer buf; - - //printf("Module::gendocfile()\n"); - - if (!mbuf_done) // if not already read the ddoc files - { mbuf_done = 1; - - // Use our internal default - mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); - - // Override with DDOCFILE specified in the sc.ini file - char *p = getenv("DDOCFILE"); - if (p) - global.params.ddocfiles->shift(p); - - // Override with the ddoc macro files from the command line - for (int i = 0; i < global.params.ddocfiles->dim; i++) - { - FileName f((char *)global.params.ddocfiles->data[i], 0); - File file(&f); - file.readv(); - // BUG: convert file contents to UTF-8 before use - - //printf("file: '%.*s'\n", file.len, file.buffer); - mbuf.write(file.buffer, file.len); - } - } - DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); - - Scope *sc = Scope::createGlobal(this); // create root scope - sc->docbuf = &buf; - - DocComment *dc = DocComment::parse(sc, this, comment); - dc->pmacrotable = ¯otable; - dc->pescapetable = &escapetable; - - // Generate predefined macros - - // Set the title to be the name of the module - { char *p = toPrettyChars(); - Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); - } - - time_t t; - time(&t); - char *p = ctime(&t); - p = mem.strdup(p); - Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); - Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); - - char *docfilename = docfile->toChars(); - Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); - - if (dc->copyright) - { - dc->copyright->nooutput = 1; - Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); - } - - buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); - if (isDocFile) - { - size_t commentlen = strlen((char *)comment); - if (dc->macros) - { - commentlen = dc->macros->name - comment; - dc->macros->write(dc, sc, this, sc->docbuf); - } - sc->docbuf->write(comment, commentlen); - highlightText(NULL, this, sc->docbuf, 0); - } - else - { - dc->writeSections(sc, this, sc->docbuf); - emitMemberComments(sc); - } - - //printf("BODY= '%.*s'\n", buf.offset, buf.data); - Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); - - OutBuffer buf2; - buf2.writestring("$(DDOC)\n"); - unsigned end = buf2.offset; - macrotable->expand(&buf2, 0, &end, NULL, 0); - -#if 1 - /* Remove all the escape sequences from buf2, - * and make CR-LF the newline. - */ - { - buf.setsize(0); - buf.reserve(buf2.offset); - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - unsigned char c = p[j]; - if (c == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - if (c == '\n') - buf.writeByte('\r'); - else if (c == '\r') - { - buf.writestring("\r\n"); - if (j + 1 < buf2.offset && p[j + 1] == '\n') - { - j++; - } - continue; - } - buf.writeByte(c); - } - } - - // Transfer image to file - assert(docfile); - docfile->setbuffer(buf.data, buf.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#else - /* Remove all the escape sequences from buf2 - */ - { unsigned i = 0; - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - if (p[j] == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - p[i] = p[j]; - i++; - } - buf2.setsize(i); - } - - // Transfer image to file - docfile->setbuffer(buf2.data, buf2.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#endif -} - -/******************************* emitComment **********************************/ - -/* - * Emit doc comment to documentation file - */ - -void Dsymbol::emitDitto(Scope *sc) -{ - //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); - OutBuffer *buf = sc->docbuf; - unsigned o; - OutBuffer b; - - b.writestring("$(DDOC_DITTO "); - o = b.offset; - toDocBuffer(&b); - //printf("b: '%.*s'\n", b.offset, b.data); - /* If 'this' is a function template, then highlightCode() was - * already run by FuncDeclaration::toDocbuffer(). - */ - TemplateDeclaration *td; - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { - } - else - highlightCode(sc, this, &b, o); - b.writeByte(')'); - buf->spread(sc->lastoffset, b.offset); - memcpy(buf->data + sc->lastoffset, b.data, b.offset); - sc->lastoffset += b.offset; -} - -void ScopeDsymbol::emitMemberComments(Scope *sc) -{ - //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); - OutBuffer *buf = sc->docbuf; - - if (members) - { const char *m = "$(DDOC_MEMBERS \n"; - - if (isModule()) - m = "$(DDOC_MODULE_MEMBERS \n"; - else if (isClassDeclaration()) - m = "$(DDOC_CLASS_MEMBERS \n"; - else if (isStructDeclaration()) - m = "$(DDOC_STRUCT_MEMBERS \n"; - else if (isEnumDeclaration()) - m = "$(DDOC_ENUM_MEMBERS \n"; - else if (isTemplateDeclaration()) - m = "$(DDOC_TEMPLATE_MEMBERS \n"; - - unsigned offset1 = buf->offset; // save starting offset - buf->writestring(m); - unsigned offset2 = buf->offset; // to see if we write anything - sc = sc->push(this); - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - //printf("\ts = '%s'\n", s->toChars()); - s->emitComment(sc); - } - sc->pop(); - if (buf->offset == offset2) - { - /* Didn't write out any members, so back out last write - */ - buf->offset = offset1; - } - else - buf->writestring(")\n"); - } -} - -void emitProtection(OutBuffer *buf, PROT prot) -{ - const char *p; - - switch (prot) - { - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTexport: p = "export"; break; - default: p = NULL; break; - } - if (p) - buf->printf("%s ", p); -} - -void Dsymbol::emitComment(Scope *sc) { } -void InvariantDeclaration::emitComment(Scope *sc) { } -#if DMDV2 -void PostBlitDeclaration::emitComment(Scope *sc) { } -#endif -void DtorDeclaration::emitComment(Scope *sc) { } -void StaticCtorDeclaration::emitComment(Scope *sc) { } -void StaticDtorDeclaration::emitComment(Scope *sc) { } -void ClassInfoDeclaration::emitComment(Scope *sc) { } -void ModuleInfoDeclaration::emitComment(Scope *sc) { } -void TypeInfoDeclaration::emitComment(Scope *sc) { } - - -void Declaration::emitComment(Scope *sc) -{ - //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - //printf("type = %p\n", type); - - if (protection == PROTprivate || !ident || - (!type && !isCtorDeclaration() && !isAliasDeclaration())) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -void AggregateDeclaration::emitComment(Scope *sc) -{ - //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void TemplateDeclaration::emitComment(Scope *sc) -{ - //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); - if (prot() == PROTprivate) - return; - - unsigned char *com = comment; - int hasmembers = 1; - - Dsymbol *ss = this; - - if (onemember) - { - ss = onemember->isAggregateDeclaration(); - if (!ss) - { - ss = onemember->isFuncDeclaration(); - if (ss) - { hasmembers = 0; - if (com != ss->comment) - com = Lexer::combineComments(com, ss->comment); - } - else - ss = this; - } - } - - if (!com) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, com); - unsigned o; - - if (!dc) - { - ss->emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - ss->toDocBuffer(buf); - if (ss == this) - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - if (hasmembers) - ((ScopeDsymbol *)ss)->emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumDeclaration::emitComment(Scope *sc) -{ - if (prot() == PROTprivate) - return; -// if (!comment) - { if (isAnonymous() && members) - { - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->emitComment(sc); - } - return; - } - } - if (!comment) - return; - if (isAnonymous()) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumMember::emitComment(Scope *sc) -{ - //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -/******************************* toDocBuffer **********************************/ - -void Dsymbol::toDocBuffer(OutBuffer *buf) -{ - //printf("Dsymbol::toDocbuffer() %s\n", toChars()); - HdrGenState hgs; - - hgs.ddoc = 1; - toCBuffer(buf, &hgs); -} - -void prefix(OutBuffer *buf, Dsymbol *s) -{ - if (s->isDeprecated()) - buf->writestring("deprecated "); - Declaration *d = s->isDeclaration(); - if (d) - { - emitProtection(buf, d->protection); - if (d->isAbstract()) - buf->writestring("abstract "); - if (d->isStatic()) - buf->writestring("static "); - if (d->isConst()) - buf->writestring("const "); -#if DMDV2 - if (d->isInvariant()) - buf->writestring("invariant "); -#endif - if (d->isFinal()) - buf->writestring("final "); - if (d->isSynchronized()) - buf->writestring("synchronized "); - } -} - -void Declaration::toDocBuffer(OutBuffer *buf) -{ - //printf("Declaration::toDocbuffer() %s, originalType = %p\n", toChars(), originalType); - if (ident) - { - prefix(buf, this); - - if (type) - { HdrGenState hgs; - hgs.ddoc = 1; - if (originalType) - { //originalType->print(); - originalType->toCBuffer(buf, ident, &hgs); - } - else - type->toCBuffer(buf, ident, &hgs); - } - else - buf->writestring(ident->toChars()); - buf->writestring(";\n"); - } -} - - -void AliasDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("alias "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void TypedefDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("typedef "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void FuncDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { /* It's a function template - */ - HdrGenState hgs; - unsigned o = buf->offset; - TypeFunction *tf = (TypeFunction *)type; - - hgs.ddoc = 1; - prefix(buf, td); - tf->next->toCBuffer(buf, NULL, &hgs); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - buf->writeByte('('); - for (int i = 0; i < td->origParameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)td->origParameters->data[i]; - if (i) - buf->writestring(", "); - tp->toCBuffer(buf, &hgs); - } - buf->writeByte(')'); - Argument::argsToCBuffer(buf, &hgs, tf->parameters, tf->varargs); - buf->writestring(";\n"); - - highlightCode(NULL, this, buf, o); - } - else - { - Declaration::toDocBuffer(buf); - } - } -} - -void CtorDeclaration::toDocBuffer(OutBuffer *buf) -{ - HdrGenState hgs; - - buf->writestring("this"); - Argument::argsToCBuffer(buf, &hgs, arguments, varargs); - buf->writestring(";\n"); -} - - -void AggregateDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void StructDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - buf->writestring(";\n"); - } -} - -void ClassDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - int any = 0; - for (int i = 0; i < baseclasses.dim; i++) - { BaseClass *bc = (BaseClass *)baseclasses.data[i]; - - if (bc->protection == PROTprivate) - continue; - if (bc->base && bc->base->ident == Id::Object) - continue; - - if (any) - buf->writestring(", "); - else - { buf->writestring(": "); - any = 1; - } - emitProtection(buf, bc->protection); - if (bc->base) - { - buf->writestring(bc->base->toPrettyChars()); - } - else - { - HdrGenState hgs; - bc->type->toCBuffer(buf, NULL, &hgs); - } - } - buf->writestring(";\n"); - } -} - - -void EnumDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void EnumMember::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->writestring(toChars()); - } -} - - -/********************************* DocComment *********************************/ - -DocComment::DocComment() -{ - memset(this, 0, sizeof(DocComment)); -} - -DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) -{ unsigned idlen; - - //printf("parse(%s): '%s'\n", s->toChars(), comment); - if (sc->lastdc && isDitto(comment)) - return NULL; - - DocComment *dc = new DocComment(); - if (!comment) - return dc; - - dc->parseSections(comment); - - for (int i = 0; i < dc->sections.dim; i++) - { Section *s = (Section *)dc->sections.data[i]; - - if (icmp("copyright", s->name, s->namelen) == 0) - { - dc->copyright = s; - } - if (icmp("macros", s->name, s->namelen) == 0) - { - dc->macros = s; - } - } - - sc->lastdc = dc; - return dc; -} - -/***************************************** - * Parse next paragraph out of *pcomment. - * Update *pcomment to point past paragraph. - * Returns NULL if no more paragraphs. - * If paragraph ends in 'identifier:', - * then (*pcomment)[0 .. idlen] is the identifier. - */ - -void DocComment::parseSections(unsigned char *comment) -{ unsigned char *p; - unsigned char *pstart; - unsigned char *pend; - unsigned char *q; - unsigned char *idstart; - unsigned idlen; - - unsigned char *name = NULL; - unsigned namelen = 0; - - //printf("parseSections('%s')\n", comment); - p = comment; - while (*p) - { - p = skipwhitespace(p); - pstart = p; - - /* Find end of section, which is ended by one of: - * 'identifier:' - * '\0' - */ - idlen = 0; - while (1) - { - if (isalpha(*p) || *p == '_') - { - q = p + 1; - while (isalnum(*q) || *q == '_') - q++; - if (*q == ':') // identifier: ends it - { idlen = q - p; - idstart = p; - for (pend = p; pend > pstart; pend--) - { if (pend[-1] == '\n') - break; - } - p = q + 1; - break; - } - } - while (1) - { - if (!*p) - { pend = p; - goto L1; - } - if (*p == '\n') - { p++; - if (*p == '\n' && !summary && !namelen) - { - pend = p; - p++; - goto L1; - } - break; - } - p++; - } - p = skipwhitespace(p); - } - L1: - - if (namelen || pstart < pend) - { - Section *s; - if (icmp("Params", name, namelen) == 0) - s = new ParamSection(); - else if (icmp("Macros", name, namelen) == 0) - s = new MacroSection(); - else - s = new Section(); - s->name = name; - s->namelen = namelen; - s->body = pstart; - s->bodylen = pend - pstart; - s->nooutput = 0; - - //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); - - sections.push(s); - - if (!summary && !namelen) - summary = s; - } - - if (idlen) - { name = idstart; - namelen = idlen; - } - else - { name = NULL; - namelen = 0; - if (!*p) - break; - } - } -} - -void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("DocComment::writeSections()\n"); - if (sections.dim) - { - buf->writestring("$(DDOC_SECTIONS \n"); - for (int i = 0; i < sections.dim; i++) - { Section *sec = (Section *)sections.data[i]; - - if (sec->nooutput) - continue; - //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); - if (sec->namelen || i) - sec->write(this, sc, s, buf); - else - { - buf->writestring("$(DDOC_SUMMARY "); - unsigned o = buf->offset; - buf->write(sec->body, sec->bodylen); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); - } - } - buf->writestring(")\n"); - } - else - { - buf->writestring("$(DDOC_BLANKLINE)\n"); - } -} - -/*************************************************** - */ - -void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - if (namelen) - { - static const char *table[] = - { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", - "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", - "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", - "VERSION" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (icmp(table[i], name, namelen) == 0) - { - buf->printf("$(DDOC_%s ", table[i]); - goto L1; - } - } - - buf->writestring("$(DDOC_SECTION "); - // Replace _ characters with spaces - buf->writestring("$(DDOC_SECTION_H "); - for (unsigned u = 0; u < namelen; u++) - { unsigned char c = name[u]; - buf->writeByte((c == '_') ? ' ' : c); - } - buf->writestring(":)\n"); - } - else - { - buf->writestring("$(DDOC_DESCRIPTION "); - } - L1: - unsigned o = buf->offset; - buf->write(body, bodylen); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - unsigned char *p = body; - unsigned len = bodylen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - unsigned o; - Argument *arg; - - buf->writestring("$(DDOC_PARAMS \n"); - while (p < pend) - { - // Skip to start of macro - for (; 1; p++) - { - switch (*p) - { - case ' ': - case '\t': - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (!(isalpha(*p) || *p == '_')) - { - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - break; - } - tempstart = p; - - while (isalnum(*p) || *p == '_') - p++; - templen = p - tempstart; - - while (*p == ' ' || *p == '\t') - p++; - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - - if (namelen) - { // Output existing param - - L1: - //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - HdrGenState hgs; - buf->writestring("$(DDOC_PARAM_ROW "); - buf->writestring("$(DDOC_PARAM_ID "); - o = buf->offset; - arg = isFunctionParameter(s, namestart, namelen); - if (arg && arg->type && arg->ident) - arg->type->toCBuffer(buf, arg->ident, &hgs); - else - buf->write(namestart, namelen); - highlightCode(sc, s, buf, o); - buf->writestring(")\n"); - - buf->writestring("$(DDOC_PARAM_DESC "); - o = buf->offset; - buf->write(textstart, textlen); - highlightText(sc, s, buf, o); - buf->writestring(")"); - buf->writestring(")\n"); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (*p == ' ' || *p == '\t') - p++; - textstart = p; - - Ltext: - while (*p != '\n') - p++; - textlen = p - textstart; - p++; - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (*p++ != '\n') - ; - } - if (namelen) - goto L1; // write out last one - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("MacroSection::write()\n"); - DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); -} - -/************************************************ - * Parse macros out of Macros: section. - * Macros are of the form: - * name1 = value1 - * - * name2 = value2 - */ - -void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) -{ - unsigned char *p = m; - unsigned len = mlen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - while (p < pend) - { - // Skip to start of macro - for (; 1; p++) - { - if (p >= pend) - goto Ldone; - switch (*p) - { - case ' ': - case '\t': - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (!(isalpha(*p) || *p == '_')) - { - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - break; - } - tempstart = p; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!(isalnum(*p) || *p == '_')) - break; - p++; - } - templen = p - tempstart; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!(*p == ' ' || *p == '\t')) - break; - p++; - } - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - if (p >= pend) - goto Ldone; - - if (namelen) - { // Output existing macro - L1: - //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - if (icmp("ESCAPES", namestart, namelen) == 0) - parseEscapes(pescapetable, textstart, textlen); - else - Macro::define(pmacrotable, namestart, namelen, textstart, textlen); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (p < pend && (*p == ' ' || *p == '\t')) - p++; - textstart = p; - - Ltext: - while (p < pend && *p != '\n') - p++; - textlen = p - textstart; - - // Remove trailing \r if there is one - if (p > m && p[-1] == '\r') - textlen--; - - p++; - //printf("p = %p, pend = %p\n", p, pend); - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (p < pend && *p++ != '\n') - ; - } -Ldone: - if (namelen) - goto L1; // write out last one -} - -/************************************** - * Parse escapes of the form: - * /c/string/ - * where c is a single character. - * Multiple escapes can be separated - * by whitespace and/or commas. - */ - -void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) -{ Escape *escapetable = *pescapetable; - - if (!escapetable) - { escapetable = new Escape; - *pescapetable = escapetable; - } - unsigned char *p = textstart; - unsigned char *pend = p + textlen; - - while (1) - { - while (1) - { - if (p + 4 >= pend) - return; - if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) - break; - p++; - } - if (p[0] != '/' || p[2] != '/') - return; - unsigned char c = p[1]; - p += 3; - unsigned char *start = p; - while (1) - { - if (p >= pend) - return; - if (*p == '/') - break; - p++; - } - size_t len = p - start; - char *s = (char *)memcpy(mem.malloc(len + 1), start, len); - s[len] = 0; - escapetable->strings[c] = s; - //printf("%c = '%s'\n", c, s); - p++; - } -} - - -/****************************************** - * Compare 0-terminated string with length terminated string. - * Return < 0, ==0, > 0 - */ - -int cmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memcmp(stringz, s, slen); -} - -int icmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memicmp(stringz, (char *)s, slen); -} - -/***************************************** - * Return !=0 if comment consists entirely of "ditto". - */ - -int isDitto(unsigned char *comment) -{ - if (comment) - { - unsigned char *p = skipwhitespace(comment); - - if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) - return 1; - } - return 0; -} - -/********************************************** - * Skip white space. - */ - -unsigned char *skipwhitespace(unsigned char *p) -{ - for (; 1; p++) - { switch (*p) - { - case ' ': - case '\t': - case '\n': - continue; - } - break; - } - return p; -} - - -/************************************************ - * Scan forward to one of: - * start of identifier - * beginning of next line - * end of buf - */ - -unsigned skiptoident(OutBuffer *buf, unsigned i) -{ - for (; i < buf->offset; i++) - { - // BUG: handle unicode alpha's - unsigned char c = buf->data[i]; - if (isalpha(c) || c == '_') - break; - if (c == '\n') - break; - } - return i; -} - -/************************************************ - * Scan forward past end of identifier. - */ - -unsigned skippastident(OutBuffer *buf, unsigned i) -{ - for (; i < buf->offset; i++) - { - // BUG: handle unicode alpha's - unsigned char c = buf->data[i]; - if (!(isalnum(c) || c == '_')) - break; - } - return i; -} - - -/************************************************ - * Scan forward past URL starting at i. - * We don't want to highlight parts of a URL. - * Returns: - * i if not a URL - * index just past it if it is a URL - */ - -unsigned skippastURL(OutBuffer *buf, unsigned i) -{ unsigned length = buf->offset - i; - unsigned char *p = &buf->data[i]; - unsigned j; - unsigned sawdot = 0; - - if (length > 7 && memicmp((char *)p, "http://", 7) == 0) - { - j = 7; - } - else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) - { - j = 8; - } - else - goto Lno; - - for (; j < length; j++) - { unsigned char c = p[j]; - if (isalnum(c)) - continue; - if (c == '-' || c == '_' || c == '?' || - c == '=' || c == '%' || c == '&' || - c == '/' || c == '+' || c == '#' || - c == '~') - continue; - if (c == '.') - { - sawdot = 1; - continue; - } - break; - } - if (sawdot) - return i + j; - -Lno: - return i; -} - - -/**************************************************** - */ - -int isKeyword(unsigned char *p, unsigned len) -{ - static const char *table[] = { "true", "false", "null" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (cmp(table[i], p, len) == 0) - return 1; - } - return 0; -} - -/**************************************************** - */ - -Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) -{ - FuncDeclaration *f = s->isFuncDeclaration(); - - /* f->type may be NULL for template members. - */ - if (f && f->type) - { - TypeFunction *tf; - if (f->originalType) - { - tf = (TypeFunction *)f->originalType; - } - else - tf = (TypeFunction *)f->type; - - if (tf->parameters) - { - for (size_t k = 0; k < tf->parameters->dim; k++) - { Argument *arg = (Argument *)tf->parameters->data[k]; - - if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) - { - return arg; - } - } - } - } - return NULL; -} - -/************************************************** - * Highlight text section. - */ - -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - //printf("highlightText()\n"); - const char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned char *p; - const char *se; - - int leadingBlank = 1; - int inCode = 0; - int inComment = 0; // in comment - unsigned iCodeStart; // start of code section - - unsigned iLineStart = offset; - - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - - Lcont: - switch (c) - { - case ' ': - case '\t': - break; - - case '\n': - if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" - { - static char blankline[] = "$(DDOC_BLANKLINE)\n"; - - i = buf->insert(i, blankline, sizeof(blankline) - 1); - } - leadingBlank = 1; - iLineStart = i + 1; - break; - - case '<': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - - // Skip over comments - if (p[1] == '!' && p[2] == '-' && p[3] == '-') - { unsigned j = i + 4; - p += 4; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '-' && p[1] == '-' && p[2] == '>') - { - i = j + 2; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - // Skip over HTML tag - if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) - { unsigned j = i + 2; - p += 2; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '>') - { - i = j; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - L1: - // Replace '<' with '<' character entity - se = Escape::escapeChar('<'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '>': - leadingBlank = 0; - if (inCode) - break; - // Replace '>' with '>' character entity - se = Escape::escapeChar('>'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '&': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - if (p[1] == '#' || isalpha(p[1])) - break; // already a character entity - // Replace '&' with '&' character entity - se = Escape::escapeChar('&'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '-': - /* A line beginning with --- delimits a code section. - * inCode tells us if it is start or end of a code section. - */ - if (leadingBlank) - { int istart = i; - int eollen = 0; - - leadingBlank = 0; - while (1) - { - ++i; - if (i >= buf->offset) - break; - c = buf->data[i]; - if (c == '\n') - { eollen = 1; - break; - } - if (c == '\r') - { - eollen = 1; - if (i + 1 >= buf->offset) - break; - if (buf->data[i + 1] == '\n') - { eollen = 2; - break; - } - } - // BUG: handle UTF PS and LS too - if (c != '-') - goto Lcont; - } - if (i - istart < 3) - goto Lcont; - - // We have the start/end of a code section - - // Remove the entire --- line, including blanks and \n - buf->remove(iLineStart, i - iLineStart + eollen); - i = iLineStart; - - if (inCode) - { - inCode = 0; - // The code section is from iCodeStart to i - OutBuffer codebuf; - - codebuf.write(buf->data + iCodeStart, i - iCodeStart); - codebuf.writeByte(0); - highlightCode2(sc, s, &codebuf, 0); - buf->remove(iCodeStart, i - iCodeStart); - i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); - i = buf->insert(i, ")\n", 2); - i--; - } - else - { static char pre[] = "$(D_CODE \n"; - - inCode = 1; - i = buf->insert(i, pre, sizeof(pre) - 1); - iCodeStart = i; - i--; // place i on > - } - } - break; - - default: - leadingBlank = 0; - if (sc && !inCode && (isalpha(c) || c == '_')) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - unsigned k = skippastURL(buf, i); - if (k > i) - { i = k - 1; - break; - } - - if (buf->data[i] == '_') // leading '_' means no highlight - { - buf->remove(i, 1); - i = j - 1; - } - else - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - break; - } - else if (isKeyword(buf->data + i, j - i)) - { - i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; - break; - } - else - { - if (f && isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - break; - } - } - i = j - 1; - } - } - } - break; - } - } - Ldone: - ; -} - -/************************************************** - * Highlight code for DDOC section. - */ - -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - - //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - const char *se; - - se = Escape::escapeChar(c); - if (se) - { - size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - else if (isalpha(c) || c == '_') - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - continue; - } - else if (f) - { - if (isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - continue; - } - } - i = j - 1; - } - } - } -} - -/**************************************** - */ - -void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) -{ - for (; p < pend; p++) - { const char *s = Escape::escapeChar(*p); - if (s) - buf->writestring(s); - else - buf->writeByte(*p); - } -} - -/************************************************** - * Highlight code for CODE section. - */ - - -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned errorsave = global.errors; - Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); - Token tok; - OutBuffer res; - unsigned char *lastp = buf->data; - const char *highlight; - - //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); - res.reserve(buf->offset); - while (1) - { - lex.scan(&tok); - highlightCode3(&res, lastp, tok.ptr); - highlight = NULL; - switch (tok.value) - { - case TOKidentifier: - if (!sc) - break; - if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) - { - highlight = "$(D_PSYMBOL "; - break; - } - else if (f) - { - if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - highlight = "$(D_PARAM "; - break; - } - } - break; - - case TOKcomment: - highlight = "$(D_COMMENT "; - break; - - case TOKstring: - highlight = "$(D_STRING "; - break; - - default: - if (tok.isKeyword()) - highlight = "$(D_KEYWORD "; - break; - } - if (highlight) - res.writestring(highlight); - highlightCode3(&res, tok.ptr, lex.p); - if (highlight) - res.writeByte(')'); - if (tok.value == TOKeof) - break; - lastp = lex.p; - } - buf->setsize(offset); - buf->write(&res); - global.errors = errorsave; -} - -/*************************************** - * Find character string to replace c with. - */ - -const char *Escape::escapeChar(unsigned c) -{ const char *s; - - switch (c) - { - case '<': - s = "<"; - break; - case '>': - s = ">"; - break; - case '&': - s = "&"; - break; - default: - s = NULL; - break; - } - return s; -} - + +// 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. + +// This implements the Ddoc capability. + +#include +#include +#include +#include +#include + +#include "rmem.h" +#include "root.h" + +#include "mars.h" +#include "dsymbol.h" +#include "macro.h" +#include "template.h" +#include "lexer.h" +#include "aggregate.h" +#include "declaration.h" +#include "enum.h" +#include "id.h" +#include "module.h" +#include "scope.h" +#include "hdrgen.h" +#include "doc.h" +#include "mtype.h" + +struct Escape +{ + const char *strings[256]; + + static const char *escapeChar(unsigned c); +}; + +struct Section +{ + unsigned char *name; + unsigned namelen; + + unsigned char *body; + unsigned bodylen; + + int nooutput; + + virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +struct ParamSection : Section +{ + void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +struct MacroSection : Section +{ + void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + +struct DocComment +{ + Array sections; // Section*[] + + Section *summary; + Section *copyright; + Section *macros; + Macro **pmacrotable; + Escape **pescapetable; + + DocComment(); + + static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); + static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); + static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); + + void parseSections(unsigned char *comment); + void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); +}; + + +int cmp(const char *stringz, void *s, size_t slen); +int icmp(const char *stringz, void *s, size_t slen); +int isDitto(unsigned char *comment); +unsigned char *skipwhitespace(unsigned char *p); +unsigned skiptoident(OutBuffer *buf, unsigned i); +unsigned skippastident(OutBuffer *buf, unsigned i); +unsigned skippastURL(OutBuffer *buf, unsigned i); +void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); +Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); + +static unsigned char ddoc_default[] = "\ +DDOC = \n\ + \n\ + $(TITLE)\n\ + \n\ +

    $(TITLE)

    \n\ + $(BODY)\n\ +
    $(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ + \n\ +\n\ +B = $0\n\ +I = $0\n\ +U = $0\n\ +P =

    $0

    \n\ +DL =
    $0
    \n\ +DT =
    $0
    \n\ +DD =
    $0
    \n\ +TABLE = $0
    \n\ +TR = $0\n\ +TH = $0\n\ +TD = $0\n\ +OL =
      $0
    \n\ +UL =
      $0
    \n\ +LI =
  • $0
  • \n\ +BIG = $0\n\ +SMALL = $0\n\ +BR =
    \n\ +LINK = $0\n\ +LINK2 = $+\n\ +\n\ +RED = $0\n\ +BLUE = $0\n\ +GREEN = $0\n\ +YELLOW =$0\n\ +BLACK = $0\n\ +WHITE = $0\n\ +\n\ +D_CODE =
    $0
    \n\ +D_COMMENT = $(GREEN $0)\n\ +D_STRING = $(RED $0)\n\ +D_KEYWORD = $(BLUE $0)\n\ +D_PSYMBOL = $(U $0)\n\ +D_PARAM = $(I $0)\n\ +\n\ +DDOC_COMMENT = \n\ +DDOC_DECL = $(DT $(BIG $0))\n\ +DDOC_DECL_DD = $(DD $0)\n\ +DDOC_DITTO = $(BR)$0\n\ +DDOC_SECTIONS = $0\n\ +DDOC_SUMMARY = $0$(BR)$(BR)\n\ +DDOC_DESCRIPTION = $0$(BR)$(BR)\n\ +DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\ +DDOC_SECTION_H = $(B $0)$(BR)\n\ +DDOC_SECTION = $0$(BR)$(BR)\n\ +DDOC_MEMBERS = $(DL $0)\n\ +DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ +DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ +DDOC_PARAM_ROW = $(TR $0)\n\ +DDOC_PARAM_ID = $(TD $0)\n\ +DDOC_PARAM_DESC = $(TD $0)\n\ +DDOC_BLANKLINE = $(BR)$(BR)\n\ +\n\ +DDOC_PSYMBOL = $(U $0)\n\ +DDOC_KEYWORD = $(B $0)\n\ +DDOC_PARAM = $(I $0)\n\ +\n\ +ESCAPES = //>/\n\ + /&/&/\n\ +"; + +static char ddoc_decl_s[] = "$(DDOC_DECL "; +static char ddoc_decl_e[] = ")\n"; + +static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD "; +static char ddoc_decl_dd_e[] = ")\n"; + + +/**************************************************** + */ + +void Module::gendocfile() +{ + static OutBuffer mbuf; + static int mbuf_done; + + OutBuffer buf; + + //printf("Module::gendocfile()\n"); + + if (!mbuf_done) // if not already read the ddoc files + { mbuf_done = 1; + + // Use our internal default + mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); + + // Override with DDOCFILE specified in the sc.ini file + char *p = getenv("DDOCFILE"); + if (p) + global.params.ddocfiles->shift(p); + + // Override with the ddoc macro files from the command line + for (int i = 0; i < global.params.ddocfiles->dim; i++) + { + FileName f((char *)global.params.ddocfiles->data[i], 0); + File file(&f); + file.readv(); + // BUG: convert file contents to UTF-8 before use + + //printf("file: '%.*s'\n", file.len, file.buffer); + mbuf.write(file.buffer, file.len); + } + } + DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); + + Scope *sc = Scope::createGlobal(this); // create root scope + sc->docbuf = &buf; + + DocComment *dc = DocComment::parse(sc, this, comment); + dc->pmacrotable = ¯otable; + dc->pescapetable = &escapetable; + + // Generate predefined macros + + // Set the title to be the name of the module + { char *p = toPrettyChars(); + Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); + } + + time_t t; + time(&t); + char *p = ctime(&t); + p = mem.strdup(p); + Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); + Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); + + char *docfilename = docfile->toChars(); + Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); + + if (dc->copyright) + { + dc->copyright->nooutput = 1; + Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); + } + + buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); + if (isDocFile) + { + size_t commentlen = strlen((char *)comment); + if (dc->macros) + { + commentlen = dc->macros->name - comment; + dc->macros->write(dc, sc, this, sc->docbuf); + } + sc->docbuf->write(comment, commentlen); + highlightText(NULL, this, sc->docbuf, 0); + } + else + { + dc->writeSections(sc, this, sc->docbuf); + emitMemberComments(sc); + } + + //printf("BODY= '%.*s'\n", buf.offset, buf.data); + Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); + + OutBuffer buf2; + buf2.writestring("$(DDOC)\n"); + unsigned end = buf2.offset; + macrotable->expand(&buf2, 0, &end, NULL, 0); + +#if 1 + /* Remove all the escape sequences from buf2, + * and make CR-LF the newline. + */ + { + buf.setsize(0); + buf.reserve(buf2.offset); + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + unsigned char c = p[j]; + if (c == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + if (c == '\n') + buf.writeByte('\r'); + else if (c == '\r') + { + buf.writestring("\r\n"); + if (j + 1 < buf2.offset && p[j + 1] == '\n') + { + j++; + } + continue; + } + buf.writeByte(c); + } + } + + // Transfer image to file + assert(docfile); + docfile->setbuffer(buf.data, buf.offset); + docfile->ref = 1; + char *pt = FileName::path(docfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + docfile->writev(); +#else + /* Remove all the escape sequences from buf2 + */ + { unsigned i = 0; + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + if (p[j] == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + p[i] = p[j]; + i++; + } + buf2.setsize(i); + } + + // Transfer image to file + docfile->setbuffer(buf2.data, buf2.offset); + docfile->ref = 1; + char *pt = FileName::path(docfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + docfile->writev(); +#endif +} + +/******************************* emitComment **********************************/ + +/* + * Emit doc comment to documentation file + */ + +void Dsymbol::emitDitto(Scope *sc) +{ + //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); + OutBuffer *buf = sc->docbuf; + unsigned o; + OutBuffer b; + + b.writestring("$(DDOC_DITTO "); + o = b.offset; + toDocBuffer(&b); + //printf("b: '%.*s'\n", b.offset, b.data); + /* If 'this' is a function template, then highlightCode() was + * already run by FuncDeclaration::toDocbuffer(). + */ + TemplateDeclaration *td; + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { + } + else + highlightCode(sc, this, &b, o); + b.writeByte(')'); + buf->spread(sc->lastoffset, b.offset); + memcpy(buf->data + sc->lastoffset, b.data, b.offset); + sc->lastoffset += b.offset; +} + +void ScopeDsymbol::emitMemberComments(Scope *sc) +{ + //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); + OutBuffer *buf = sc->docbuf; + + if (members) + { const char *m = "$(DDOC_MEMBERS \n"; + + if (isModule()) + m = "$(DDOC_MODULE_MEMBERS \n"; + else if (isClassDeclaration()) + m = "$(DDOC_CLASS_MEMBERS \n"; + else if (isStructDeclaration()) + m = "$(DDOC_STRUCT_MEMBERS \n"; + else if (isEnumDeclaration()) + m = "$(DDOC_ENUM_MEMBERS \n"; + else if (isTemplateDeclaration()) + m = "$(DDOC_TEMPLATE_MEMBERS \n"; + + unsigned offset1 = buf->offset; // save starting offset + buf->writestring(m); + unsigned offset2 = buf->offset; // to see if we write anything + sc = sc->push(this); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("\ts = '%s'\n", s->toChars()); + s->emitComment(sc); + } + sc->pop(); + if (buf->offset == offset2) + { + /* Didn't write out any members, so back out last write + */ + buf->offset = offset1; + } + else + buf->writestring(")\n"); + } +} + +void emitProtection(OutBuffer *buf, PROT prot) +{ + const char *p; + + switch (prot) + { + case PROTpackage: p = "package"; break; + case PROTprotected: p = "protected"; break; + case PROTexport: p = "export"; break; + default: p = NULL; break; + } + if (p) + buf->printf("%s ", p); +} + +void Dsymbol::emitComment(Scope *sc) { } +void InvariantDeclaration::emitComment(Scope *sc) { } +#if DMDV2 +void PostBlitDeclaration::emitComment(Scope *sc) { } +#endif +void DtorDeclaration::emitComment(Scope *sc) { } +void StaticCtorDeclaration::emitComment(Scope *sc) { } +void StaticDtorDeclaration::emitComment(Scope *sc) { } +void ClassInfoDeclaration::emitComment(Scope *sc) { } +void ModuleInfoDeclaration::emitComment(Scope *sc) { } +void TypeInfoDeclaration::emitComment(Scope *sc) { } + + +void Declaration::emitComment(Scope *sc) +{ + //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); + //printf("type = %p\n", type); + + if (protection == PROTprivate || !ident || + (!type && !isCtorDeclaration() && !isAliasDeclaration())) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + unsigned o; + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + buf->writestring(ddoc_decl_dd_e); +} + +void AggregateDeclaration::emitComment(Scope *sc) +{ + //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); + if (prot() == PROTprivate) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + toDocBuffer(buf); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + emitMemberComments(sc); + buf->writestring(ddoc_decl_dd_e); +} + +void TemplateDeclaration::emitComment(Scope *sc) +{ + //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); + if (prot() == PROTprivate) + return; + + unsigned char *com = comment; + int hasmembers = 1; + + Dsymbol *ss = this; + + if (onemember) + { + ss = onemember->isAggregateDeclaration(); + if (!ss) + { + ss = onemember->isFuncDeclaration(); + if (ss) + { hasmembers = 0; + if (com != ss->comment) + com = Lexer::combineComments(com, ss->comment); + } + else + ss = this; + } + } + + if (!com) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, com); + unsigned o; + + if (!dc) + { + ss->emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + o = buf->offset; + ss->toDocBuffer(buf); + if (ss == this) + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + if (hasmembers) + ((ScopeDsymbol *)ss)->emitMemberComments(sc); + buf->writestring(ddoc_decl_dd_e); +} + +void EnumDeclaration::emitComment(Scope *sc) +{ + if (prot() == PROTprivate) + return; +// if (!comment) + { if (isAnonymous() && members) + { + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->emitComment(sc); + } + return; + } + } + if (!comment) + return; + if (isAnonymous()) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + toDocBuffer(buf); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + emitMemberComments(sc); + buf->writestring(ddoc_decl_dd_e); +} + +void EnumMember::emitComment(Scope *sc) +{ + //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); + if (prot() == PROTprivate) + return; + if (!comment) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, comment); + unsigned o; + + if (!dc) + { + emitDitto(sc); + return; + } + dc->pmacrotable = &sc->module->macrotable; + + buf->writestring(ddoc_decl_s); + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; + buf->writestring(ddoc_decl_e); + + buf->writestring(ddoc_decl_dd_s); + dc->writeSections(sc, this, buf); + buf->writestring(ddoc_decl_dd_e); +} + +/******************************* toDocBuffer **********************************/ + +void Dsymbol::toDocBuffer(OutBuffer *buf) +{ + //printf("Dsymbol::toDocbuffer() %s\n", toChars()); + HdrGenState hgs; + + hgs.ddoc = 1; + toCBuffer(buf, &hgs); +} + +void prefix(OutBuffer *buf, Dsymbol *s) +{ + if (s->isDeprecated()) + buf->writestring("deprecated "); + Declaration *d = s->isDeclaration(); + if (d) + { + emitProtection(buf, d->protection); + if (d->isAbstract()) + buf->writestring("abstract "); + if (d->isStatic()) + buf->writestring("static "); + if (d->isConst()) + buf->writestring("const "); +#if DMDV2 + if (d->isInvariant()) + buf->writestring("invariant "); +#endif + if (d->isFinal()) + buf->writestring("final "); + if (d->isSynchronized()) + buf->writestring("synchronized "); + } +} + +void Declaration::toDocBuffer(OutBuffer *buf) +{ + //printf("Declaration::toDocbuffer() %s, originalType = %p\n", toChars(), originalType); + if (ident) + { + prefix(buf, this); + + if (type) + { HdrGenState hgs; + hgs.ddoc = 1; + if (originalType) + { //originalType->print(); + originalType->toCBuffer(buf, ident, &hgs); + } + else + type->toCBuffer(buf, ident, &hgs); + } + else + buf->writestring(ident->toChars()); + buf->writestring(";\n"); + } +} + + +void AliasDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { + if (isDeprecated()) + buf->writestring("deprecated "); + + emitProtection(buf, protection); + buf->writestring("alias "); + buf->writestring(toChars()); + buf->writestring(";\n"); + } +} + + +void TypedefDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + if (isDeprecated()) + buf->writestring("deprecated "); + + emitProtection(buf, protection); + buf->writestring("typedef "); + buf->writestring(toChars()); + buf->writestring(";\n"); + } +} + + +void FuncDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { /* It's a function template + */ + HdrGenState hgs; + unsigned o = buf->offset; + TypeFunction *tf = (TypeFunction *)type; + + hgs.ddoc = 1; + prefix(buf, td); + tf->next->toCBuffer(buf, NULL, &hgs); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + buf->writeByte('('); + for (int i = 0; i < td->origParameters->dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)td->origParameters->data[i]; + if (i) + buf->writestring(", "); + tp->toCBuffer(buf, &hgs); + } + buf->writeByte(')'); + Argument::argsToCBuffer(buf, &hgs, tf->parameters, tf->varargs); + buf->writestring(";\n"); + + highlightCode(NULL, this, buf, o); + } + else + { + Declaration::toDocBuffer(buf); + } + } +} + +void CtorDeclaration::toDocBuffer(OutBuffer *buf) +{ + HdrGenState hgs; + + buf->writestring("this"); + Argument::argsToCBuffer(buf, &hgs, arguments, varargs); + buf->writestring(";\n"); +} + + +void AggregateDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + buf->writestring(";\n"); + } +} + +void StructDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { unsigned o = buf->offset; + td->toDocBuffer(buf); + highlightCode(NULL, this, buf, o); + } + else + { + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + } + buf->writestring(";\n"); + } +} + +void ClassDeclaration::toDocBuffer(OutBuffer *buf) +{ + //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); + if (ident) + { +#if 0 + emitProtection(buf, protection); +#endif + TemplateDeclaration *td; + + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { unsigned o = buf->offset; + td->toDocBuffer(buf); + highlightCode(NULL, this, buf, o); + } + else + { + if (isAbstract()) + buf->writestring("abstract "); + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + } + int any = 0; + for (int i = 0; i < baseclasses.dim; i++) + { BaseClass *bc = (BaseClass *)baseclasses.data[i]; + + if (bc->protection == PROTprivate) + continue; + if (bc->base && bc->base->ident == Id::Object) + continue; + + if (any) + buf->writestring(", "); + else + { buf->writestring(": "); + any = 1; + } + emitProtection(buf, bc->protection); + if (bc->base) + { + buf->writestring(bc->base->toPrettyChars()); + } + else + { + HdrGenState hgs; + bc->type->toCBuffer(buf, NULL, &hgs); + } + } + buf->writestring(";\n"); + } +} + + +void EnumDeclaration::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + buf->writestring(";\n"); + } +} + +void EnumMember::toDocBuffer(OutBuffer *buf) +{ + if (ident) + { + buf->writestring(toChars()); + } +} + + +/********************************* DocComment *********************************/ + +DocComment::DocComment() +{ + memset(this, 0, sizeof(DocComment)); +} + +DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) +{ unsigned idlen; + + //printf("parse(%s): '%s'\n", s->toChars(), comment); + if (sc->lastdc && isDitto(comment)) + return NULL; + + DocComment *dc = new DocComment(); + if (!comment) + return dc; + + dc->parseSections(comment); + + for (int i = 0; i < dc->sections.dim; i++) + { Section *s = (Section *)dc->sections.data[i]; + + if (icmp("copyright", s->name, s->namelen) == 0) + { + dc->copyright = s; + } + if (icmp("macros", s->name, s->namelen) == 0) + { + dc->macros = s; + } + } + + sc->lastdc = dc; + return dc; +} + +/***************************************** + * Parse next paragraph out of *pcomment. + * Update *pcomment to point past paragraph. + * Returns NULL if no more paragraphs. + * If paragraph ends in 'identifier:', + * then (*pcomment)[0 .. idlen] is the identifier. + */ + +void DocComment::parseSections(unsigned char *comment) +{ unsigned char *p; + unsigned char *pstart; + unsigned char *pend; + unsigned char *q; + unsigned char *idstart; + unsigned idlen; + + unsigned char *name = NULL; + unsigned namelen = 0; + + //printf("parseSections('%s')\n", comment); + p = comment; + while (*p) + { + p = skipwhitespace(p); + pstart = p; + + /* Find end of section, which is ended by one of: + * 'identifier:' + * '\0' + */ + idlen = 0; + while (1) + { + if (isalpha(*p) || *p == '_') + { + q = p + 1; + while (isalnum(*q) || *q == '_') + q++; + if (*q == ':') // identifier: ends it + { idlen = q - p; + idstart = p; + for (pend = p; pend > pstart; pend--) + { if (pend[-1] == '\n') + break; + } + p = q + 1; + break; + } + } + while (1) + { + if (!*p) + { pend = p; + goto L1; + } + if (*p == '\n') + { p++; + if (*p == '\n' && !summary && !namelen) + { + pend = p; + p++; + goto L1; + } + break; + } + p++; + } + p = skipwhitespace(p); + } + L1: + + if (namelen || pstart < pend) + { + Section *s; + if (icmp("Params", name, namelen) == 0) + s = new ParamSection(); + else if (icmp("Macros", name, namelen) == 0) + s = new MacroSection(); + else + s = new Section(); + s->name = name; + s->namelen = namelen; + s->body = pstart; + s->bodylen = pend - pstart; + s->nooutput = 0; + + //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); + + sections.push(s); + + if (!summary && !namelen) + summary = s; + } + + if (idlen) + { name = idstart; + namelen = idlen; + } + else + { name = NULL; + namelen = 0; + if (!*p) + break; + } + } +} + +void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + //printf("DocComment::writeSections()\n"); + if (sections.dim) + { + buf->writestring("$(DDOC_SECTIONS \n"); + for (int i = 0; i < sections.dim; i++) + { Section *sec = (Section *)sections.data[i]; + + if (sec->nooutput) + continue; + //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); + if (sec->namelen || i) + sec->write(this, sc, s, buf); + else + { + buf->writestring("$(DDOC_SUMMARY "); + unsigned o = buf->offset; + buf->write(sec->body, sec->bodylen); + highlightText(sc, s, buf, o); + buf->writestring(")\n"); + } + } + buf->writestring(")\n"); + } + else + { + buf->writestring("$(DDOC_BLANKLINE)\n"); + } +} + +/*************************************************** + */ + +void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + if (namelen) + { + static const char *table[] = + { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", + "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", + "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", + "VERSION" }; + + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + if (icmp(table[i], name, namelen) == 0) + { + buf->printf("$(DDOC_%s ", table[i]); + goto L1; + } + } + + buf->writestring("$(DDOC_SECTION "); + // Replace _ characters with spaces + buf->writestring("$(DDOC_SECTION_H "); + for (unsigned u = 0; u < namelen; u++) + { unsigned char c = name[u]; + buf->writeByte((c == '_') ? ' ' : c); + } + buf->writestring(":)\n"); + } + else + { + buf->writestring("$(DDOC_DESCRIPTION "); + } + L1: + unsigned o = buf->offset; + buf->write(body, bodylen); + highlightText(sc, s, buf, o); + buf->writestring(")\n"); +} + +/*************************************************** + */ + +void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + unsigned char *p = body; + unsigned len = bodylen; + unsigned char *pend = p + len; + + unsigned char *tempstart; + unsigned templen; + + unsigned char *namestart; + unsigned namelen = 0; // !=0 if line continuation + + unsigned char *textstart; + unsigned textlen; + + unsigned o; + Argument *arg; + + buf->writestring("$(DDOC_PARAMS \n"); + while (p < pend) + { + // Skip to start of macro + for (; 1; p++) + { + switch (*p) + { + case ' ': + case '\t': + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (!(isalpha(*p) || *p == '_')) + { + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + break; + } + tempstart = p; + + while (isalnum(*p) || *p == '_') + p++; + templen = p - tempstart; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; + + if (namelen) + { // Output existing param + + L1: + //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + HdrGenState hgs; + buf->writestring("$(DDOC_PARAM_ROW "); + buf->writestring("$(DDOC_PARAM_ID "); + o = buf->offset; + arg = isFunctionParameter(s, namestart, namelen); + if (arg && arg->type && arg->ident) + arg->type->toCBuffer(buf, arg->ident, &hgs); + else + buf->write(namestart, namelen); + highlightCode(sc, s, buf, o); + buf->writestring(")\n"); + + buf->writestring("$(DDOC_PARAM_DESC "); + o = buf->offset; + buf->write(textstart, textlen); + highlightText(sc, s, buf, o); + buf->writestring(")"); + buf->writestring(")\n"); + namelen = 0; + if (p >= pend) + break; + } + + namestart = tempstart; + namelen = templen; + + while (*p == ' ' || *p == '\t') + p++; + textstart = p; + + Ltext: + while (*p != '\n') + p++; + textlen = p - textstart; + p++; + + Lcont: + continue; + + Lskipline: + // Ignore this line + while (*p++ != '\n') + ; + } + if (namelen) + goto L1; // write out last one + buf->writestring(")\n"); +} + +/*************************************************** + */ + +void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) +{ + //printf("MacroSection::write()\n"); + DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); +} + +/************************************************ + * Parse macros out of Macros: section. + * Macros are of the form: + * name1 = value1 + * + * name2 = value2 + */ + +void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) +{ + unsigned char *p = m; + unsigned len = mlen; + unsigned char *pend = p + len; + + unsigned char *tempstart; + unsigned templen; + + unsigned char *namestart; + unsigned namelen = 0; // !=0 if line continuation + + unsigned char *textstart; + unsigned textlen; + + while (p < pend) + { + // Skip to start of macro + for (; 1; p++) + { + if (p >= pend) + goto Ldone; + switch (*p) + { + case ' ': + case '\t': + continue; + + case '\n': + p++; + goto Lcont; + + default: + if (!(isalpha(*p) || *p == '_')) + { + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + break; + } + tempstart = p; + + while (1) + { + if (p >= pend) + goto Ldone; + if (!(isalnum(*p) || *p == '_')) + break; + p++; + } + templen = p - tempstart; + + while (1) + { + if (p >= pend) + goto Ldone; + if (!(*p == ' ' || *p == '\t')) + break; + p++; + } + + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; + if (p >= pend) + goto Ldone; + + if (namelen) + { // Output existing macro + L1: + //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + if (icmp("ESCAPES", namestart, namelen) == 0) + parseEscapes(pescapetable, textstart, textlen); + else + Macro::define(pmacrotable, namestart, namelen, textstart, textlen); + namelen = 0; + if (p >= pend) + break; + } + + namestart = tempstart; + namelen = templen; + + while (p < pend && (*p == ' ' || *p == '\t')) + p++; + textstart = p; + + Ltext: + while (p < pend && *p != '\n') + p++; + textlen = p - textstart; + + // Remove trailing \r if there is one + if (p > m && p[-1] == '\r') + textlen--; + + p++; + //printf("p = %p, pend = %p\n", p, pend); + + Lcont: + continue; + + Lskipline: + // Ignore this line + while (p < pend && *p++ != '\n') + ; + } +Ldone: + if (namelen) + goto L1; // write out last one +} + +/************************************** + * Parse escapes of the form: + * /c/string/ + * where c is a single character. + * Multiple escapes can be separated + * by whitespace and/or commas. + */ + +void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) +{ Escape *escapetable = *pescapetable; + + if (!escapetable) + { escapetable = new Escape; + *pescapetable = escapetable; + } + unsigned char *p = textstart; + unsigned char *pend = p + textlen; + + while (1) + { + while (1) + { + if (p + 4 >= pend) + return; + if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) + break; + p++; + } + if (p[0] != '/' || p[2] != '/') + return; + unsigned char c = p[1]; + p += 3; + unsigned char *start = p; + while (1) + { + if (p >= pend) + return; + if (*p == '/') + break; + p++; + } + size_t len = p - start; + char *s = (char *)memcpy(mem.malloc(len + 1), start, len); + s[len] = 0; + escapetable->strings[c] = s; + //printf("%c = '%s'\n", c, s); + p++; + } +} + + +/****************************************** + * Compare 0-terminated string with length terminated string. + * Return < 0, ==0, > 0 + */ + +int cmp(const char *stringz, void *s, size_t slen) +{ + size_t len1 = strlen(stringz); + + if (len1 != slen) + return len1 - slen; + return memcmp(stringz, s, slen); +} + +int icmp(const char *stringz, void *s, size_t slen) +{ + size_t len1 = strlen(stringz); + + if (len1 != slen) + return len1 - slen; + return memicmp(stringz, (char *)s, slen); +} + +/***************************************** + * Return !=0 if comment consists entirely of "ditto". + */ + +int isDitto(unsigned char *comment) +{ + if (comment) + { + unsigned char *p = skipwhitespace(comment); + + if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) + return 1; + } + return 0; +} + +/********************************************** + * Skip white space. + */ + +unsigned char *skipwhitespace(unsigned char *p) +{ + for (; 1; p++) + { switch (*p) + { + case ' ': + case '\t': + case '\n': + continue; + } + break; + } + return p; +} + + +/************************************************ + * Scan forward to one of: + * start of identifier + * beginning of next line + * end of buf + */ + +unsigned skiptoident(OutBuffer *buf, unsigned i) +{ + for (; i < buf->offset; i++) + { + // BUG: handle unicode alpha's + unsigned char c = buf->data[i]; + if (isalpha(c) || c == '_') + break; + if (c == '\n') + break; + } + return i; +} + +/************************************************ + * Scan forward past end of identifier. + */ + +unsigned skippastident(OutBuffer *buf, unsigned i) +{ + for (; i < buf->offset; i++) + { + // BUG: handle unicode alpha's + unsigned char c = buf->data[i]; + if (!(isalnum(c) || c == '_')) + break; + } + return i; +} + + +/************************************************ + * Scan forward past URL starting at i. + * We don't want to highlight parts of a URL. + * Returns: + * i if not a URL + * index just past it if it is a URL + */ + +unsigned skippastURL(OutBuffer *buf, unsigned i) +{ unsigned length = buf->offset - i; + unsigned char *p = &buf->data[i]; + unsigned j; + unsigned sawdot = 0; + + if (length > 7 && memicmp((char *)p, "http://", 7) == 0) + { + j = 7; + } + else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) + { + j = 8; + } + else + goto Lno; + + for (; j < length; j++) + { unsigned char c = p[j]; + if (isalnum(c)) + continue; + if (c == '-' || c == '_' || c == '?' || + c == '=' || c == '%' || c == '&' || + c == '/' || c == '+' || c == '#' || + c == '~') + continue; + if (c == '.') + { + sawdot = 1; + continue; + } + break; + } + if (sawdot) + return i + j; + +Lno: + return i; +} + + +/**************************************************** + */ + +int isKeyword(unsigned char *p, unsigned len) +{ + static const char *table[] = { "true", "false", "null" }; + + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + if (cmp(table[i], p, len) == 0) + return 1; + } + return 0; +} + +/**************************************************** + */ + +Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) +{ + FuncDeclaration *f = s->isFuncDeclaration(); + + /* f->type may be NULL for template members. + */ + if (f && f->type) + { + TypeFunction *tf; + if (f->originalType) + { + tf = (TypeFunction *)f->originalType; + } + else + tf = (TypeFunction *)f->type; + + if (tf->parameters) + { + for (size_t k = 0; k < tf->parameters->dim; k++) + { Argument *arg = (Argument *)tf->parameters->data[k]; + + if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) + { + return arg; + } + } + } + } + return NULL; +} + +/************************************************** + * Highlight text section. + */ + +void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + //printf("highlightText()\n"); + const char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + unsigned char *p; + const char *se; + + int leadingBlank = 1; + int inCode = 0; + int inComment = 0; // in comment + unsigned iCodeStart; // start of code section + + unsigned iLineStart = offset; + + for (unsigned i = offset; i < buf->offset; i++) + { unsigned char c = buf->data[i]; + + Lcont: + switch (c) + { + case ' ': + case '\t': + break; + + case '\n': + if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" + { + static char blankline[] = "$(DDOC_BLANKLINE)\n"; + + i = buf->insert(i, blankline, sizeof(blankline) - 1); + } + leadingBlank = 1; + iLineStart = i + 1; + break; + + case '<': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; + + // Skip over comments + if (p[1] == '!' && p[2] == '-' && p[3] == '-') + { unsigned j = i + 4; + p += 4; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '-' && p[1] == '-' && p[2] == '>') + { + i = j + 2; // place on closing '>' + break; + } + j++; + p++; + } + break; + } + + // Skip over HTML tag + if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) + { unsigned j = i + 2; + p += 2; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '>') + { + i = j; // place on closing '>' + break; + } + j++; + p++; + } + break; + } + + L1: + // Replace '<' with '<' character entity + se = Escape::escapeChar('<'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; + + case '>': + leadingBlank = 0; + if (inCode) + break; + // Replace '>' with '>' character entity + se = Escape::escapeChar('>'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; + + case '&': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; + if (p[1] == '#' || isalpha(p[1])) + break; // already a character entity + // Replace '&' with '&' character entity + se = Escape::escapeChar('&'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; + + case '-': + /* A line beginning with --- delimits a code section. + * inCode tells us if it is start or end of a code section. + */ + if (leadingBlank) + { int istart = i; + int eollen = 0; + + leadingBlank = 0; + while (1) + { + ++i; + if (i >= buf->offset) + break; + c = buf->data[i]; + if (c == '\n') + { eollen = 1; + break; + } + if (c == '\r') + { + eollen = 1; + if (i + 1 >= buf->offset) + break; + if (buf->data[i + 1] == '\n') + { eollen = 2; + break; + } + } + // BUG: handle UTF PS and LS too + if (c != '-') + goto Lcont; + } + if (i - istart < 3) + goto Lcont; + + // We have the start/end of a code section + + // Remove the entire --- line, including blanks and \n + buf->remove(iLineStart, i - iLineStart + eollen); + i = iLineStart; + + if (inCode) + { + inCode = 0; + // The code section is from iCodeStart to i + OutBuffer codebuf; + + codebuf.write(buf->data + iCodeStart, i - iCodeStart); + codebuf.writeByte(0); + highlightCode2(sc, s, &codebuf, 0); + buf->remove(iCodeStart, i - iCodeStart); + i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); + i = buf->insert(i, ")\n", 2); + i--; + } + else + { static char pre[] = "$(D_CODE \n"; + + inCode = 1; + i = buf->insert(i, pre, sizeof(pre) - 1); + iCodeStart = i; + i--; // place i on > + } + } + break; + + default: + leadingBlank = 0; + if (sc && !inCode && (isalpha(c) || c == '_')) + { unsigned j; + + j = skippastident(buf, i); + if (j > i) + { + unsigned k = skippastURL(buf, i); + if (k > i) + { i = k - 1; + break; + } + + if (buf->data[i] == '_') // leading '_' means no highlight + { + buf->remove(i, 1); + i = j - 1; + } + else + { + if (cmp(sid, buf->data + i, j - i) == 0) + { + i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; + break; + } + else if (isKeyword(buf->data + i, j - i)) + { + i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; + break; + } + else + { + if (f && isFunctionParameter(f, buf->data + i, j - i)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; + break; + } + } + i = j - 1; + } + } + } + break; + } + } + Ldone: + ; +} + +/************************************************** + * Highlight code for DDOC section. + */ + +void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + + //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); + for (unsigned i = offset; i < buf->offset; i++) + { unsigned char c = buf->data[i]; + const char *se; + + se = Escape::escapeChar(c); + if (se) + { + size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + else if (isalpha(c) || c == '_') + { unsigned j; + + j = skippastident(buf, i); + if (j > i) + { + if (cmp(sid, buf->data + i, j - i) == 0) + { + i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; + continue; + } + else if (f) + { + if (isFunctionParameter(f, buf->data + i, j - i)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; + continue; + } + } + i = j - 1; + } + } + } +} + +/**************************************** + */ + +void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) +{ + for (; p < pend; p++) + { const char *s = Escape::escapeChar(*p); + if (s) + buf->writestring(s); + else + buf->writeByte(*p); + } +} + +/************************************************** + * Highlight code for CODE section. + */ + + +void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) +{ + char *sid = s->ident->toChars(); + FuncDeclaration *f = s->isFuncDeclaration(); + unsigned errorsave = global.errors; + Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); + Token tok; + OutBuffer res; + unsigned char *lastp = buf->data; + const char *highlight; + + //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); + res.reserve(buf->offset); + while (1) + { + lex.scan(&tok); + highlightCode3(&res, lastp, tok.ptr); + highlight = NULL; + switch (tok.value) + { + case TOKidentifier: + if (!sc) + break; + if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) + { + highlight = "$(D_PSYMBOL "; + break; + } + else if (f) + { + if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + highlight = "$(D_PARAM "; + break; + } + } + break; + + case TOKcomment: + highlight = "$(D_COMMENT "; + break; + + case TOKstring: + highlight = "$(D_STRING "; + break; + + default: + if (tok.isKeyword()) + highlight = "$(D_KEYWORD "; + break; + } + if (highlight) + res.writestring(highlight); + highlightCode3(&res, tok.ptr, lex.p); + if (highlight) + res.writeByte(')'); + if (tok.value == TOKeof) + break; + lastp = lex.p; + } + buf->setsize(offset); + buf->write(&res); + global.errors = errorsave; +} + +/*************************************** + * Find character string to replace c with. + */ + +const char *Escape::escapeChar(unsigned c) +{ const char *s; + + switch (c) + { + case '<': + s = "<"; + break; + case '>': + s = ">"; + break; + case '&': + s = "&"; + break; + default: + s = NULL; + break; + } + return s; +} + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/dsymbol.c --- a/dmd2/dsymbol.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/dsymbol.c Sat May 30 17:23:32 2009 +0100 @@ -1,1201 +1,1230 @@ - -// 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. - -#include -#include -#include - -#include "mem.h" - -#include "mars.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "identifier.h" -#include "module.h" -#include "mtype.h" -#include "expression.h" -#include "statement.h" -#include "declaration.h" -#include "id.h" -#include "scope.h" -#include "init.h" -#include "import.h" -#include "template.h" -#include "attrib.h" - -#include "../gen/enums.h" - -/****************************** Dsymbol ******************************/ - -Dsymbol::Dsymbol() -{ - //printf("Dsymbol::Dsymbol(%p)\n", this); - this->ident = NULL; - this->c_ident = NULL; - this->parent = NULL; - this->csym = NULL; - this->isym = NULL; - this->loc = 0; - this->comment = NULL; - - this->llvmInternal = LLVMnone; -} - -Dsymbol::Dsymbol(Identifier *ident) -{ - //printf("Dsymbol::Dsymbol(%p, ident)\n", this); - this->ident = ident; - this->c_ident = NULL; - this->parent = NULL; - this->csym = NULL; - this->isym = NULL; - this->loc = 0; - this->comment = NULL; - - this->llvmInternal = LLVMnone; -} - -int Dsymbol::equals(Object *o) -{ Dsymbol *s; - - if (this == o) - return TRUE; - s = (Dsymbol *)(o); - if (s && ident->equals(s->ident)) - return TRUE; - return FALSE; -} - -/************************************** - * Copy the syntax. - * Used for template instantiations. - * If s is NULL, allocate the new object, otherwise fill it in. - */ - -Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) -{ - print(); - printf("%s %s\n", kind(), toChars()); - assert(0); - return NULL; -} - -/************************************** - * Determine if this symbol is only one. - * Returns: - * FALSE, *ps = NULL: There are 2 or more symbols - * TRUE, *ps = NULL: There are zero symbols - * TRUE, *ps = symbol: The one and only one symbol - */ - -int Dsymbol::oneMember(Dsymbol **ps) -{ - //printf("Dsymbol::oneMember()\n"); - *ps = this; - return TRUE; -} - -/***************************************** - * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. - */ - -int Dsymbol::oneMembers(Array *members, Dsymbol **ps) -{ - //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); - Dsymbol *s = NULL; - - if (members) - { - for (int i = 0; i < members->dim; i++) - { Dsymbol *sx = (Dsymbol *)members->data[i]; - - int x = sx->oneMember(ps); - //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); - if (!x) - { - //printf("\tfalse 1\n"); - assert(*ps == NULL); - return FALSE; - } - if (*ps) - { - if (s) // more than one symbol - { *ps = NULL; - //printf("\tfalse 2\n"); - return FALSE; - } - s = *ps; - } - } - } - *ps = s; // s is the one symbol, NULL if none - //printf("\ttrue\n"); - return TRUE; -} - -/***************************************** - * Is Dsymbol a variable that contains pointers? - */ - -int Dsymbol::hasPointers() -{ - //printf("Dsymbol::hasPointers() %s\n", toChars()); - return 0; -} - -char *Dsymbol::toChars() -{ - return ident ? ident->toChars() : (char *)"__anonymous"; -} - -char *Dsymbol::toPrettyChars() -{ Dsymbol *p; - char *s; - char *q; - size_t len; - - //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); - if (!parent) - return toChars(); - - len = 0; - for (p = this; p; p = p->parent) - len += strlen(p->toChars()) + 1; - - s = (char *)mem.malloc(len); - q = s + len - 1; - *q = 0; - for (p = this; p; p = p->parent) - { - char *t = p->toChars(); - len = strlen(t); - q -= len; - memcpy(q, t, len); - if (q == s) - break; - q--; - *q = '.'; - } - return s; -} - -char *Dsymbol::locToChars() -{ - OutBuffer buf; - char *p; - - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - return loc.toChars(); -} - -const char *Dsymbol::kind() -{ - return "symbol"; -} - -/********************************* - * If this symbol is really an alias for another, - * return that other. - */ - -Dsymbol *Dsymbol::toAlias() -{ - return this; -} - -Dsymbol *Dsymbol::toParent() -{ - return parent ? parent->pastMixin() : NULL; -} - -Dsymbol *Dsymbol::pastMixin() -{ - Dsymbol *s = this; - - //printf("Dsymbol::pastMixin() %s\n", toChars()); - while (s && s->isTemplateMixin()) - s = s->parent; - return s; -} - -/********************************** - * Use this instead of toParent() when looking for the - * 'this' pointer of the enclosing function/class. - */ - -Dsymbol *Dsymbol::toParent2() -{ - Dsymbol *s = parent; - while (s && s->isTemplateInstance()) - s = s->parent; - return s; -} - -TemplateInstance *Dsymbol::inTemplateInstance() -{ - for (Dsymbol *parent = this->parent; parent; parent = parent->parent) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - return ti; - } - return NULL; -} - -int Dsymbol::isAnonymous() -{ - return ident ? 0 : 1; -} - -void Dsymbol::semantic(Scope *sc) -{ - error("%p has no semantic routine", this); -} - -void Dsymbol::semantic2(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -void Dsymbol::semantic3(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -void Dsymbol::inlineScan() -{ - // Most Dsymbols have no further semantic analysis needed -} - -/********************************************* - * Search for ident as member of s. - * Input: - * flags: 1 don't find private members - * 2 don't give error messages - * 4 return NULL if ambiguous - * Returns: - * NULL if not found - */ - -Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - return NULL; -} - -/*************************************** - * Search for identifier id as a member of 'this'. - * id may be a template instance. - * Returns: - * symbol found, NULL if not - */ - -Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) -{ - //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - Dsymbol *s = toAlias(); - Dsymbol *sm; - - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - sm = s->search(loc, id, 0); - break; - - case DYNCAST_DSYMBOL: - { // It's a template instance - //printf("\ttemplate instance id\n"); - Dsymbol *st = (Dsymbol *)id; - TemplateInstance *ti = st->isTemplateInstance(); - id = ti->name; - sm = s->search(loc, id, 0); - if (!sm) - { error("template identifier %s is not a member of %s %s", - id->toChars(), s->kind(), s->toChars()); - return NULL; - } - sm = sm->toAlias(); - TemplateDeclaration *td = sm->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template, it is a %s", id->toChars(), sm->kind()); - return NULL; - } - ti->tempdecl = td; - if (!ti->semanticdone) - ti->semantic(sc); - sm = ti->toAlias(); - break; - } - - default: - assert(0); - } - return sm; -} - -int Dsymbol::overloadInsert(Dsymbol *s) -{ - //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); - return FALSE; -} - -void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(toChars()); -} - -unsigned Dsymbol::size(Loc loc) -{ - error("Dsymbol '%s' has no size\n", toChars()); - return 0; -} - -int Dsymbol::isforwardRef() -{ - return FALSE; -} - -AggregateDeclaration *Dsymbol::isThis() -{ - return NULL; -} - -ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? -{ - Dsymbol *parent = toParent(); - if (parent && parent->isClassDeclaration()) - return (ClassDeclaration *)parent; - return NULL; -} - -void Dsymbol::defineRef(Dsymbol *s) -{ - assert(0); -} - -int Dsymbol::isExport() -{ - return FALSE; -} - -int Dsymbol::isImportedSymbol() -{ - return FALSE; -} - -int Dsymbol::isDeprecated() -{ - return FALSE; -} - -int Dsymbol::isOverloadable() -{ - return 0; -} - -LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? -{ - return NULL; -} - -AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? -{ - //printf("Dsymbol::isMember() %s\n", toChars()); - Dsymbol *parent = toParent(); - //printf("parent is %s %s\n", parent->kind(), parent->toChars()); - return parent ? parent->isAggregateDeclaration() : NULL; -} - -Type *Dsymbol::getType() -{ - return NULL; -} - -int Dsymbol::needThis() -{ - return FALSE; -} - -int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("Dsymbol::addMember('%s')\n", toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); - parent = sd; - if (!isAnonymous()) // no name, so can't add it to symbol table - { - if (!sd->symtab->insert(this)) // if name is already defined - { - Dsymbol *s2; - - s2 = sd->symtab->lookup(ident); - if (!s2->overloadInsert(this)) - { - sd->multiplyDefined(0, this, s2); - } - } - if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) - { - if (ident == Id::__sizeof || ident == Id::alignof || ident == Id::mangleof) - error(".%s property cannot be redefined", ident->toChars()); - } - return 1; - } - return 0; -} - -void Dsymbol::error(const char *format, ...) -{ - //printf("Dsymbol::error()\n"); - if (!global.gag) - { - char *p = locToChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - if (isAnonymous()) - fprintf(stdmsg, "%s ", kind()); - else - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - } - global.errors++; - - //fatal(); -} - -void Dsymbol::error(Loc loc, const char *format, ...) -{ - if (!global.gag) - { - char *p = loc.toChars(); - if (!*p) - p = locToChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - } - - global.errors++; - - //fatal(); -} - -void Dsymbol::checkDeprecated(Loc loc, Scope *sc) -{ - if (!global.params.useDeprecated && isDeprecated()) - { - // Don't complain if we're inside a deprecated symbol's scope - for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) - { if (sp->isDeprecated()) - return; - } - - for (; sc; sc = sc->enclosing) - { - if (sc->scopesym && sc->scopesym->isDeprecated()) - return; - - // If inside a StorageClassDeclaration that is deprecated - if (sc->stc & STCdeprecated) - return; - } - - error(loc, "is deprecated"); - } -} - -/********************************** - * Determine which Module a Dsymbol is in. - */ - -Module *Dsymbol::getModule() -{ - Module *m; - Dsymbol *s; - - //printf("Dsymbol::getModule()\n"); - s = this; - while (s) - { - //printf("\ts = '%s'\n", s->toChars()); - m = s->isModule(); - if (m) - return m; - s = s->parent; - } - return NULL; -} - - -/********************************** - * Determine which Module a Dsymbol will be compiled in. - * This may be different from getModule for templates. - */ - -Module *Dsymbol::getCompilationModule() -{ - Module *m; - TemplateInstance *ti; - Dsymbol *s; - - //printf("Dsymbol::getModule()\n"); - s = this; - while (s) - { - //printf("\ts = '%s'\n", s->toChars()); - m = s->isModule(); - if (m) - return m; - ti = s->isTemplateInstance(); - if (ti && ti->tmodule) - return ti->tmodule; - s = s->parent; - } - return NULL; -} - -/************************************* - */ - -enum PROT Dsymbol::prot() -{ - return PROTpublic; -} - -/************************************* - * Do syntax copy of an array of Dsymbol's. - */ - - -Array *Dsymbol::arraySyntaxCopy(Array *a) -{ - - Array *b = NULL; - if (a) - { - b = a->copy(); - for (int i = 0; i < b->dim; i++) - { - Dsymbol *s = (Dsymbol *)b->data[i]; - - s = s->syntaxCopy(NULL); - b->data[i] = (void *)s; - } - } - return b; -} - - -/**************************************** - * Add documentation comment to Dsymbol. - * Ignore NULL comments. - */ - -void Dsymbol::addComment(unsigned char *comment) -{ - //if (comment) - //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); - - if (!this->comment) - this->comment = comment; -#if 1 - else if (comment && strcmp((char *)comment, (char *)this->comment)) - { // Concatenate the two - this->comment = Lexer::combineComments(this->comment, comment); - } -#endif -} - -/********************************* OverloadSet ****************************/ - -OverloadSet::OverloadSet() - : Dsymbol() -{ -} - -void OverloadSet::push(Dsymbol *s) -{ - a.push(s); -} - -const char *OverloadSet::kind() -{ - return "overloadset"; -} - - -/********************************* ScopeDsymbol ****************************/ - -ScopeDsymbol::ScopeDsymbol() - : Dsymbol() -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -ScopeDsymbol::ScopeDsymbol(Identifier *id) - : Dsymbol(id) -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) -{ - //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); - - ScopeDsymbol *sd; - if (s) - sd = (ScopeDsymbol *)s; - else - sd = new ScopeDsymbol(ident); - sd->members = arraySyntaxCopy(members); - return sd; -} - -Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); - //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; - - // Look in symbols declared in this module - Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; - - // hide private nonlocal symbols - if (flags & 1 && s && s->prot() == PROTprivate) - s = NULL; - - if (s) - { - //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); - } - else if (imports) - { - OverloadSet *a = NULL; - - // Look in imported modules - for (int i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; - Dsymbol *s2; - - // If private import, don't search it - if (flags & 1 && prots[i] == PROTprivate) - continue; - - //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); - /* Don't find private members if ss is a module - */ - s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); - if (!s) - s = s2; - else if (s2 && s != s2) - { - if (s->toAlias() == s2->toAlias()) - { - /* After following aliases, we found the same symbol, - * so it's not an ambiguity. - * But if one alias is deprecated, prefer the other. - */ - if (s->isDeprecated()) - s = s2; - } - else - { - /* Two imports of the same module should be regarded as - * the same. - */ - Import *i1 = s->isImport(); - Import *i2 = s2->isImport(); - if (!(i1 && i2 && - (i1->mod == i2->mod || - (!i1->parent->isImport() && !i2->parent->isImport() && - i1->ident->equals(i2->ident)) - ) - ) - ) - { - /* If both s2 and s are overloadable (though we only - * need to check s once) - */ - if (s2->isOverloadable() && (a || s->isOverloadable())) - { if (!a) - a = new OverloadSet(); - /* Don't add to a[] if s2 is alias of previous sym - */ - for (int j = 0; j < a->a.dim; j++) - { Dsymbol *s3 = (Dsymbol *)a->a.data[j]; - if (s2->toAlias() == s3->toAlias()) - { - if (s3->isDeprecated()) - a->a.data[j] = (void *)s2; - goto Lcontinue; - } - } - a->push(s2); - Lcontinue: - continue; - } - if (flags & 4) // if return NULL on ambiguity - return NULL; - if (!(flags & 2)) - ss->multiplyDefined(loc, s, s2); - break; - } - } - } - } - - /* Build special symbol if we had multiple finds - */ - if (a) - { assert(s); - a->push(s); - s = a; - } - - if (s) - { - Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && - !d->parent->isTemplateMixin() && - !(flags & 2)) - error("%s is private", d->toPrettyChars()); - } - } - return s; -} - -void ScopeDsymbol::importScope(ScopeDsymbol *s, enum PROT protection) -{ - //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); - - // No circular or redundant import's - if (s != this) - { - if (!imports) - imports = new Array(); - else - { - for (int i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss; - - ss = (ScopeDsymbol *) imports->data[i]; - if (ss == s) // if already imported - { - if (protection > prots[i]) - prots[i] = protection; // upgrade access - return; - } - } - } - imports->push(s); - prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); - prots[imports->dim - 1] = protection; - } -} - -int ScopeDsymbol::isforwardRef() -{ - return (members == NULL); -} - -void ScopeDsymbol::defineRef(Dsymbol *s) -{ - ScopeDsymbol *ss; - - ss = s->isScopeDsymbol(); - members = ss->members; - ss->members = NULL; -} - -void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) -{ -#if 0 - printf("ScopeDsymbol::multiplyDefined()\n"); - printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : ""); - printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); -#endif - if (loc.filename) - { ::error(loc, "%s at %s conflicts with %s at %s", - s1->toPrettyChars(), - s1->locToChars(), - s2->toPrettyChars(), - s2->locToChars()); - } - else - { - s1->error(loc, "conflicts with %s %s at %s", - s2->kind(), - s2->toPrettyChars(), - s2->locToChars()); - } -halt(); -} - -Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s) -{ - Dsymbol *sprev; - - // Look to see if we are defining a forward referenced symbol - - sprev = symtab->lookup(s->ident); - assert(sprev); - if (s->equals(sprev)) // if the same symbol - { - if (s->isforwardRef()) // if second declaration is a forward reference - return sprev; - if (sprev->isforwardRef()) - { - sprev->defineRef(s); // copy data from s into sprev - return sprev; - } - } - multiplyDefined(0, s, sprev); - return sprev; -} - -const char *ScopeDsymbol::kind() -{ - return "ScopeDsymbol"; -} - - -/*************************************** - * Determine number of Dsymbols, folding in AttribDeclaration members. - */ - -size_t ScopeDsymbol::dim(Array *members) -{ - size_t n = 0; - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - AttribDeclaration *a = s->isAttribDeclaration(); - - if (a) - { - n += dim(a->decl); - } - else - n++; - } - } - return n; -} - -/*************************************** - * Get nth Dsymbol, folding in AttribDeclaration members. - * Returns: - * Dsymbol* nth Dsymbol - * NULL not found, *pn gets incremented by the number - * of Dsymbols - */ - -Dsymbol *ScopeDsymbol::getNth(Array *members, size_t nth, size_t *pn) -{ - if (!members) - return NULL; - - size_t n = 0; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - AttribDeclaration *a = s->isAttribDeclaration(); - - if (a) - { - s = getNth(a->decl, nth - n, &n); - if (s) - return s; - } - else if (n == nth) - return s; - else - n++; - } - - if (pn) - *pn += n; - return NULL; -} - -/******************************************* - * Look for member of the form: - * const(MemberInfo)[] getMembers(string); - * Returns NULL if not found - */ - -#if DMDV2 -FuncDeclaration *ScopeDsymbol::findGetMembers() -{ - Dsymbol *s = search_function(this, Id::getmembers); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - -#if 0 // Finish - static TypeFunction *tfgetmembers; - - if (!tfgetmembers) - { - Scope sc; - Arguments *arguments = new Arguments; - Arguments *arg = new Argument(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); - arguments->push(arg); - - Type *tret = NULL; - tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); - tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); - } - if (fdx) - fdx = fdx->overloadExactMatch(tfgetmembers); -#endif - if (fdx && fdx->isVirtual()) - fdx = NULL; - - return fdx; -} -#endif - - -/****************************** WithScopeSymbol ******************************/ - -WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) - : ScopeDsymbol() -{ - this->withstate = withstate; -} - -Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - // Acts as proxy to the with class declaration - return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); -} - -/****************************** ArrayScopeSymbol ******************************/ - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e) - : ScopeDsymbol() -{ - assert(e->op == TOKindex || e->op == TOKslice); - exp = e; - type = NULL; - td = NULL; - this->sc = sc; -} - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t) - : ScopeDsymbol() -{ - exp = NULL; - type = t; - td = NULL; - this->sc = sc; -} - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s) - : ScopeDsymbol() -{ - exp = NULL; - type = NULL; - td = s; - this->sc = sc; -} - -Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); - if (ident == Id::length || ident == Id::dollar) - { VarDeclaration **pvar; - Expression *ce; - - L1: - - if (td) - { - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } - - if (type) - { - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } - - if (exp->op == TOKindex) - { - IndexExp *ie = (IndexExp *)exp; - - pvar = &ie->lengthVar; - ce = ie->e1; - } - else if (exp->op == TOKslice) - { - SliceExp *se = (SliceExp *)exp; - - pvar = &se->lengthVar; - ce = se->e1; - } - else - return NULL; - - if (ce->op == TOKtype) - { - Type *t = ((TypeExp *)ce)->type; - if (t->ty == Ttuple) - { type = (TypeTuple *)t; - goto L1; - } - } - - if (!*pvar) - { - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - - if (ce->op == TOKvar) - { // if ce is const, get its initializer - ce = fromConstInitializer(WANTvalue | WANTinterpret, ce); - } - - if (ce->op == TOKstring) - { /* It is for a string literal, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - else if (ce->op == TOKarrayliteral) - { /* It is for an array literal, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - else if (ce->op == TOKtuple) - { /* It is for an expression tuple, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - *pvar = v; - } - (*pvar)->semantic(sc); - return (*pvar); - } - return NULL; -} - - -/****************************** DsymbolTable ******************************/ - -DsymbolTable::DsymbolTable() -{ - tab = new StringTable; -} - -DsymbolTable::~DsymbolTable() -{ - delete tab; -} - -Dsymbol *DsymbolTable::lookup(Identifier *ident) -{ StringValue *sv; - -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - sv = tab->lookup((char*)ident->string, ident->len); - return (Dsymbol *)(sv ? sv->ptrvalue : NULL); -} - -Dsymbol *DsymbolTable::insert(Dsymbol *s) -{ StringValue *sv; - Identifier *ident; - - //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); - ident = s->ident; -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -} - -Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) -{ StringValue *sv; - - //printf("DsymbolTable::insert()\n"); - sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -} - -Dsymbol *DsymbolTable::update(Dsymbol *s) -{ StringValue *sv; - Identifier *ident; - - ident = s->ident; - sv = tab->update(ident->toChars(), ident->len); - sv->ptrvalue = s; - return s; -} - - - - + +// 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. + +#include +#include +#include + +#include "rmem.h" + +#include "mars.h" +#include "dsymbol.h" +#include "aggregate.h" +#include "identifier.h" +#include "module.h" +#include "mtype.h" +#include "expression.h" +#include "statement.h" +#include "declaration.h" +#include "id.h" +#include "scope.h" +#include "init.h" +#include "import.h" +#include "template.h" +#include "attrib.h" + +#if IN_LLVM +#include "../gen/enums.h" +#endif + +/****************************** Dsymbol ******************************/ + +Dsymbol::Dsymbol() +{ + //printf("Dsymbol::Dsymbol(%p)\n", this); + this->ident = NULL; + this->c_ident = NULL; + this->parent = NULL; +#if IN_DMD + this->csym = NULL; + this->isym = NULL; +#endif + this->loc = 0; + this->comment = NULL; + +#if IN_LLVM + this->llvmInternal = LLVMnone; + this->irsym = NULL; +#endif +} + +Dsymbol::Dsymbol(Identifier *ident) +{ + //printf("Dsymbol::Dsymbol(%p, ident)\n", this); + this->ident = ident; + this->c_ident = NULL; + this->parent = NULL; +#if IN_DMD + this->csym = NULL; + this->isym = NULL; +#endif + this->loc = 0; + this->comment = NULL; + +#if IN_LLVM + this->llvmInternal = LLVMnone; + this->irsym = NULL; +#endif +} + +int Dsymbol::equals(Object *o) +{ Dsymbol *s; + + if (this == o) + return TRUE; + s = (Dsymbol *)(o); + if (s && ident->equals(s->ident)) + return TRUE; + return FALSE; +} + +/************************************** + * Copy the syntax. + * Used for template instantiations. + * If s is NULL, allocate the new object, otherwise fill it in. + */ + +Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) +{ + print(); + printf("%s %s\n", kind(), toChars()); + assert(0); + return NULL; +} + +/************************************** + * Determine if this symbol is only one. + * Returns: + * FALSE, *ps = NULL: There are 2 or more symbols + * TRUE, *ps = NULL: There are zero symbols + * TRUE, *ps = symbol: The one and only one symbol + */ + +int Dsymbol::oneMember(Dsymbol **ps) +{ + //printf("Dsymbol::oneMember()\n"); + *ps = this; + return TRUE; +} + +/***************************************** + * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. + */ + +int Dsymbol::oneMembers(Array *members, Dsymbol **ps) +{ + //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); + Dsymbol *s = NULL; + + if (members) + { + for (int i = 0; i < members->dim; i++) + { Dsymbol *sx = (Dsymbol *)members->data[i]; + + int x = sx->oneMember(ps); + //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); + if (!x) + { + //printf("\tfalse 1\n"); + assert(*ps == NULL); + return FALSE; + } + if (*ps) + { + if (s) // more than one symbol + { *ps = NULL; + //printf("\tfalse 2\n"); + return FALSE; + } + s = *ps; + } + } + } + *ps = s; // s is the one symbol, NULL if none + //printf("\ttrue\n"); + return TRUE; +} + +/***************************************** + * Is Dsymbol a variable that contains pointers? + */ + +int Dsymbol::hasPointers() +{ + //printf("Dsymbol::hasPointers() %s\n", toChars()); + return 0; +} + +char *Dsymbol::toChars() +{ + return ident ? ident->toChars() : (char *)"__anonymous"; +} + +char *Dsymbol::toPrettyChars() +{ Dsymbol *p; + char *s; + char *q; + size_t len; + + //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); + if (!parent) + return toChars(); + + len = 0; + for (p = this; p; p = p->parent) + len += strlen(p->toChars()) + 1; + + s = (char *)mem.malloc(len); + q = s + len - 1; + *q = 0; + for (p = this; p; p = p->parent) + { + char *t = p->toChars(); + len = strlen(t); + q -= len; + memcpy(q, t, len); + if (q == s) + break; + q--; + *q = '.'; + } + return s; +} + +char *Dsymbol::locToChars() +{ + OutBuffer buf; + char *p; + + Module *m = getModule(); + + if (m && m->srcfile) + loc.filename = m->srcfile->toChars(); + return loc.toChars(); +} + +const char *Dsymbol::kind() +{ + return "symbol"; +} + +/********************************* + * If this symbol is really an alias for another, + * return that other. + */ + +Dsymbol *Dsymbol::toAlias() +{ + return this; +} + +Dsymbol *Dsymbol::toParent() +{ + return parent ? parent->pastMixin() : NULL; +} + +Dsymbol *Dsymbol::pastMixin() +{ + Dsymbol *s = this; + + //printf("Dsymbol::pastMixin() %s\n", toChars()); + while (s && s->isTemplateMixin()) + s = s->parent; + return s; +} + +/********************************** + * Use this instead of toParent() when looking for the + * 'this' pointer of the enclosing function/class. + */ + +Dsymbol *Dsymbol::toParent2() +{ + Dsymbol *s = parent; + while (s && s->isTemplateInstance()) + s = s->parent; + return s; +} + +TemplateInstance *Dsymbol::inTemplateInstance() +{ + for (Dsymbol *parent = this->parent; parent; parent = parent->parent) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + return ti; + } + return NULL; +} + +int Dsymbol::isAnonymous() +{ + return ident ? 0 : 1; +} + +void Dsymbol::semantic(Scope *sc) +{ + error("%p has no semantic routine", this); +} + +void Dsymbol::semantic2(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +void Dsymbol::semantic3(Scope *sc) +{ + // Most Dsymbols have no further semantic analysis needed +} + +void Dsymbol::inlineScan() +{ + // Most Dsymbols have no further semantic analysis needed +} + +/********************************************* + * Search for ident as member of s. + * Input: + * flags: 1 don't find private members + * 2 don't give error messages + * 4 return NULL if ambiguous + * Returns: + * NULL if not found + */ + +Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); + return NULL; +} + +/*************************************** + * Search for identifier id as a member of 'this'. + * id may be a template instance. + * Returns: + * symbol found, NULL if not + */ + +Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) +{ + //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); + Dsymbol *s = toAlias(); + Dsymbol *sm; + + switch (id->dyncast()) + { + case DYNCAST_IDENTIFIER: + sm = s->search(loc, id, 0); + break; + + case DYNCAST_DSYMBOL: + { // It's a template instance + //printf("\ttemplate instance id\n"); + Dsymbol *st = (Dsymbol *)id; + TemplateInstance *ti = st->isTemplateInstance(); + id = ti->name; + sm = s->search(loc, id, 0); + if (!sm) + { error("template identifier %s is not a member of %s %s", + id->toChars(), s->kind(), s->toChars()); + return NULL; + } + sm = sm->toAlias(); + TemplateDeclaration *td = sm->isTemplateDeclaration(); + if (!td) + { + error("%s is not a template, it is a %s", id->toChars(), sm->kind()); + return NULL; + } + ti->tempdecl = td; + if (!ti->semanticdone) + ti->semantic(sc); + sm = ti->toAlias(); + break; + } + + default: + assert(0); + } + return sm; +} + +int Dsymbol::overloadInsert(Dsymbol *s) +{ + //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); + return FALSE; +} + +void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(toChars()); +} + +unsigned Dsymbol::size(Loc loc) +{ + error("Dsymbol '%s' has no size\n", toChars()); + return 0; +} + +int Dsymbol::isforwardRef() +{ + return FALSE; +} + +AggregateDeclaration *Dsymbol::isThis() +{ + return NULL; +} + +ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? +{ + Dsymbol *parent = toParent(); + if (parent && parent->isClassDeclaration()) + return (ClassDeclaration *)parent; + return NULL; +} + +void Dsymbol::defineRef(Dsymbol *s) +{ + assert(0); +} + +int Dsymbol::isExport() +{ + return FALSE; +} + +int Dsymbol::isImportedSymbol() +{ + return FALSE; +} + +int Dsymbol::isDeprecated() +{ + return FALSE; +} + +int Dsymbol::isOverloadable() +{ + return 0; +} + +LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? +{ + return NULL; +} + +AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? +{ + //printf("Dsymbol::isMember() %s\n", toChars()); + Dsymbol *parent = toParent(); + //printf("parent is %s %s\n", parent->kind(), parent->toChars()); + return parent ? parent->isAggregateDeclaration() : NULL; +} + +Type *Dsymbol::getType() +{ + return NULL; +} + +int Dsymbol::needThis() +{ + return FALSE; +} + +int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("Dsymbol::addMember('%s')\n", toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); + parent = sd; + if (!isAnonymous()) // no name, so can't add it to symbol table + { + if (!sd->symtab->insert(this)) // if name is already defined + { + Dsymbol *s2; + + s2 = sd->symtab->lookup(ident); + if (!s2->overloadInsert(this)) + { + sd->multiplyDefined(0, this, s2); + } + } + if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) + { + if (ident == Id::__sizeof || ident == Id::alignof || ident == Id::mangleof) + error(".%s property cannot be redefined", ident->toChars()); + } + return 1; + } + return 0; +} + +void Dsymbol::error(const char *format, ...) +{ + //printf("Dsymbol::error()\n"); + if (!global.gag) + { + char *p = locToChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + fprintf(stdmsg, "Error: "); + if (isAnonymous()) + fprintf(stdmsg, "%s ", kind()); + else + fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + } + global.errors++; + + //fatal(); +} + +void Dsymbol::error(Loc loc, const char *format, ...) +{ + if (!global.gag) + { + char *p = loc.toChars(); + if (!*p) + p = locToChars(); + + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + fprintf(stdmsg, "Error: "); + fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + } + + global.errors++; + + //fatal(); +} + +void Dsymbol::checkDeprecated(Loc loc, Scope *sc) +{ + if (!global.params.useDeprecated && isDeprecated()) + { + // Don't complain if we're inside a deprecated symbol's scope + for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) + { if (sp->isDeprecated()) + return; + } + + for (; sc; sc = sc->enclosing) + { + if (sc->scopesym && sc->scopesym->isDeprecated()) + return; + + // If inside a StorageClassDeclaration that is deprecated + if (sc->stc & STCdeprecated) + return; + } + + error(loc, "is deprecated"); + } +} + +/********************************** + * Determine which Module a Dsymbol is in. + */ + +Module *Dsymbol::getModule() +{ + Module *m; + Dsymbol *s; + + //printf("Dsymbol::getModule()\n"); + s = this; + while (s) + { + //printf("\ts = '%s'\n", s->toChars()); + m = s->isModule(); + if (m) + return m; + s = s->parent; + } + return NULL; +} + + +/********************************** + * Determine which Module a Dsymbol will be compiled in. + * This may be different from getModule for templates. + */ + +Module *Dsymbol::getCompilationModule() +{ + Module *m; + TemplateInstance *ti; + Dsymbol *s; + + //printf("Dsymbol::getModule()\n"); + s = this; + while (s) + { + //printf("\ts = '%s'\n", s->toChars()); + m = s->isModule(); + if (m) + return m; + ti = s->isTemplateInstance(); + if (ti && ti->tmodule) + return ti->tmodule; + s = s->parent; + } + return NULL; +} + +/************************************* + */ + +enum PROT Dsymbol::prot() +{ + return PROTpublic; +} + +/************************************* + * Do syntax copy of an array of Dsymbol's. + */ + + +Array *Dsymbol::arraySyntaxCopy(Array *a) +{ + + Array *b = NULL; + if (a) + { + b = a->copy(); + for (int i = 0; i < b->dim; i++) + { + Dsymbol *s = (Dsymbol *)b->data[i]; + + s = s->syntaxCopy(NULL); + b->data[i] = (void *)s; + } + } + return b; +} + + +/**************************************** + * Add documentation comment to Dsymbol. + * Ignore NULL comments. + */ + +void Dsymbol::addComment(unsigned char *comment) +{ + //if (comment) + //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); + + if (!this->comment) + this->comment = comment; +#if 1 + else if (comment && strcmp((char *)comment, (char *)this->comment)) + { // Concatenate the two + this->comment = Lexer::combineComments(this->comment, comment); + } +#endif +} + +/********************************* OverloadSet ****************************/ + +OverloadSet::OverloadSet() + : Dsymbol() +{ +} + +void OverloadSet::push(Dsymbol *s) +{ + a.push(s); +} + +const char *OverloadSet::kind() +{ + return "overloadset"; +} + + +/********************************* ScopeDsymbol ****************************/ + +ScopeDsymbol::ScopeDsymbol() + : Dsymbol() +{ + members = NULL; + symtab = NULL; + imports = NULL; + prots = NULL; +} + +ScopeDsymbol::ScopeDsymbol(Identifier *id) + : Dsymbol(id) +{ + members = NULL; + symtab = NULL; + imports = NULL; + prots = NULL; +} + +Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) +{ + //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); + + ScopeDsymbol *sd; + if (s) + sd = (ScopeDsymbol *)s; + else + sd = new ScopeDsymbol(ident); + sd->members = arraySyntaxCopy(members); + return sd; +} + +Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); + //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; + + // Look in symbols declared in this module + Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; + + // hide the aliases generated by selective or renamed private imports + if (s && flags & 1) + if (AliasDeclaration* ad = s->isAliasDeclaration()) + // may be a private alias to a function that is overloaded. these + // are sorted out during overload resolution, accept them here + if (ad->importprot == PROTprivate && !ad->aliassym->isFuncAliasDeclaration()) + s = NULL; + + if (s) + { + //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); + } + else if (imports) + { + OverloadSet *a = NULL; + + // Look in imported modules + for (int i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; + Dsymbol *s2; + + // If private import, don't search it + if (flags & 1 && prots[i] == PROTprivate) + continue; + + //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); + /* Don't find private members if ss is a module + */ + s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); + if (!s) + s = s2; + else if (s2 && s != s2) + { + if (s->toAlias() == s2->toAlias()) + { + /* After following aliases, we found the same symbol, + * so it's not an ambiguity. + * But if one alias is deprecated, prefer the other. + */ + if (s->isDeprecated()) + s = s2; + } + else + { + /* Two imports of the same module should be regarded as + * the same. + */ + Import *i1 = s->isImport(); + Import *i2 = s2->isImport(); + if (!(i1 && i2 && + (i1->mod == i2->mod || + (!i1->parent->isImport() && !i2->parent->isImport() && + i1->ident->equals(i2->ident)) + ) + ) + ) + { + /* If both s2 and s are overloadable (though we only + * need to check s once) + */ + if (s2->isOverloadable() && (a || s->isOverloadable())) + { if (!a) + a = new OverloadSet(); + /* Don't add to a[] if s2 is alias of previous sym + */ + for (int j = 0; j < a->a.dim; j++) + { Dsymbol *s3 = (Dsymbol *)a->a.data[j]; + if (s2->toAlias() == s3->toAlias()) + { + if (s3->isDeprecated()) + a->a.data[j] = (void *)s2; + goto Lcontinue; + } + } + a->push(s2); + Lcontinue: + continue; + } + if (flags & 4) // if return NULL on ambiguity + return NULL; + if (!(flags & 2)) + ss->multiplyDefined(loc, s, s2); + break; + } + } + } + } + + /* Build special symbol if we had multiple finds + */ + if (a) + { assert(s); + a->push(s); + s = a; + } + + if (s) + { + Declaration *d = s->isDeclaration(); + if (d && d->protection == PROTprivate && + !d->parent->isTemplateMixin() && + !(flags & 2)) + error("%s is private", d->toPrettyChars()); + } + } + return s; +} + +void ScopeDsymbol::importScope(ScopeDsymbol *s, enum PROT protection) +{ + //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); + + // No circular or redundant import's + if (s != this) + { + if (!imports) + imports = new Array(); + else + { + for (int i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss; + + ss = (ScopeDsymbol *) imports->data[i]; + if (ss == s) // if already imported + { + if (protection > prots[i]) + prots[i] = protection; // upgrade access + return; + } + } + } + imports->push(s); + prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); + prots[imports->dim - 1] = protection; + } +} + +int ScopeDsymbol::isforwardRef() +{ + return (members == NULL); +} + +void ScopeDsymbol::defineRef(Dsymbol *s) +{ + ScopeDsymbol *ss; + + ss = s->isScopeDsymbol(); + members = ss->members; + ss->members = NULL; +} + +void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) +{ +#if 0 + printf("ScopeDsymbol::multiplyDefined()\n"); + printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : ""); + printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); +#endif + if (loc.filename) + { ::error(loc, "%s at %s conflicts with %s at %s", + s1->toPrettyChars(), + s1->locToChars(), + s2->toPrettyChars(), + s2->locToChars()); + } + else + { + s1->error(loc, "conflicts with %s %s at %s", + s2->kind(), + s2->toPrettyChars(), + s2->locToChars()); + } +} + +Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s) +{ + Dsymbol *sprev; + + // Look to see if we are defining a forward referenced symbol + + sprev = symtab->lookup(s->ident); + assert(sprev); + if (s->equals(sprev)) // if the same symbol + { + if (s->isforwardRef()) // if second declaration is a forward reference + return sprev; + if (sprev->isforwardRef()) + { + sprev->defineRef(s); // copy data from s into sprev + return sprev; + } + } + multiplyDefined(0, s, sprev); + return sprev; +} + +const char *ScopeDsymbol::kind() +{ + return "ScopeDsymbol"; +} + + +/*************************************** + * Determine number of Dsymbols, folding in AttribDeclaration members. + */ + +size_t ScopeDsymbol::dim(Array *members) +{ + size_t n = 0; + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + AttribDeclaration *a = s->isAttribDeclaration(); + + if (a) + { + n += dim(a->decl); + } + else + n++; + } + } + return n; +} + +/*************************************** + * Get nth Dsymbol, folding in AttribDeclaration members. + * Returns: + * Dsymbol* nth Dsymbol + * NULL not found, *pn gets incremented by the number + * of Dsymbols + */ + +Dsymbol *ScopeDsymbol::getNth(Array *members, size_t nth, size_t *pn) +{ + if (!members) + return NULL; + + size_t n = 0; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + AttribDeclaration *a = s->isAttribDeclaration(); + + if (a) + { + s = getNth(a->decl, nth - n, &n); + if (s) + return s; + } + else if (n == nth) + return s; + else + n++; + } + + if (pn) + *pn += n; + return NULL; +} + +/******************************************* + * Look for member of the form: + * const(MemberInfo)[] getMembers(string); + * Returns NULL if not found + */ + +#if DMDV2 +FuncDeclaration *ScopeDsymbol::findGetMembers() +{ + Dsymbol *s = search_function(this, Id::getmembers); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + +#if 0 // Finish + static TypeFunction *tfgetmembers; + + if (!tfgetmembers) + { + Scope sc; + Arguments *arguments = new Arguments; + Arguments *arg = new Argument(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); + arguments->push(arg); + + Type *tret = NULL; + tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); + tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); + } + if (fdx) + fdx = fdx->overloadExactMatch(tfgetmembers); +#endif + if (fdx && fdx->isVirtual()) + fdx = NULL; + + return fdx; +} +#endif + + +/****************************** WithScopeSymbol ******************************/ + +WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) + : ScopeDsymbol() +{ + this->withstate = withstate; +} + +Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) +{ + // Acts as proxy to the with class declaration + return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); +} + +/****************************** ArrayScopeSymbol ******************************/ + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e) + : ScopeDsymbol() +{ + assert(e->op == TOKindex || e->op == TOKslice); + exp = e; + type = NULL; + td = NULL; + this->sc = sc; +} + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t) + : ScopeDsymbol() +{ + exp = NULL; + type = t; + td = NULL; + this->sc = sc; +} + +ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s) + : ScopeDsymbol() +{ + exp = NULL; + type = NULL; + td = s; + this->sc = sc; +} + +Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) +{ + //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); + if (ident == Id::length || ident == Id::dollar) + { VarDeclaration **pvar; + Expression *ce; + + L1: + + if (td) + { /* $ gives the number of elements in the tuple + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } + + if (type) + { /* $ gives the number of type entries in the type tuple + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } + + if (exp->op == TOKindex) + { /* array[index] where index is some function of $ + */ + IndexExp *ie = (IndexExp *)exp; + + pvar = &ie->lengthVar; + ce = ie->e1; + } + else if (exp->op == TOKslice) + { /* array[lwr .. upr] where lwr or upr is some function of $ + */ + SliceExp *se = (SliceExp *)exp; + + pvar = &se->lengthVar; + ce = se->e1; + } + else + /* Didn't find $, look in enclosing scope(s). + */ + return NULL; + + /* If we are indexing into an array that is really a type + * tuple, rewrite this as an index into a type tuple and + * try again. + */ + if (ce->op == TOKtype) + { + Type *t = ((TypeExp *)ce)->type; + if (t->ty == Ttuple) + { type = (TypeTuple *)t; + goto L1; + } + } + + /* *pvar is lazily initialized, so if we refer to $ + * multiple times, it gets set only once. + */ + if (!*pvar) // if not already initialized + { /* Create variable v and set it to the value of $, + * which will be a constant. + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + + if (ce->op == TOKvar) + { // if ce is const, get its initializer + ce = fromConstInitializer(WANTvalue | WANTinterpret, ce); + } + + if (ce->op == TOKstring) + { /* It is for a string literal, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + else if (ce->op == TOKarrayliteral) + { /* It is for an array literal, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + else if (ce->op == TOKtuple) + { /* It is for an expression tuple, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + *pvar = v; + } + (*pvar)->semantic(sc); + return (*pvar); + } + return NULL; +} + + +/****************************** DsymbolTable ******************************/ + +DsymbolTable::DsymbolTable() +{ + tab = new StringTable; +} + +DsymbolTable::~DsymbolTable() +{ + delete tab; +} + +Dsymbol *DsymbolTable::lookup(Identifier *ident) +{ +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + StringValue *sv = tab->lookup((char*)ident->string, ident->len); + return (Dsymbol *)(sv ? sv->ptrvalue : NULL); +} + +Dsymbol *DsymbolTable::insert(Dsymbol *s) +{ StringValue *sv; + Identifier *ident; + + //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); + ident = s->ident; +#ifdef DEBUG + assert(ident); + assert(tab); +#endif + sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +} + +Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) +{ StringValue *sv; + + //printf("DsymbolTable::insert()\n"); + sv = tab->insert(ident->toChars(), ident->len); + if (!sv) + return NULL; // already in table + sv->ptrvalue = s; + return s; +} + +Dsymbol *DsymbolTable::update(Dsymbol *s) +{ StringValue *sv; + Identifier *ident; + + ident = s->ident; + sv = tab->update(ident->toChars(), ident->len); + sv->ptrvalue = s; + return s; +} + + + + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/dsymbol.h --- a/dmd2/dsymbol.h Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/dsymbol.h Sat May 30 17:23:32 2009 +0100 @@ -1,326 +1,352 @@ - -// 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. - -#ifndef DMD_DSYMBOL_H -#define DMD_DSYMBOL_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "mars.h" -#include "arraytypes.h" - -// llvm -#include "../ir/irsymbol.h" - -struct Identifier; -struct Scope; -struct DsymbolTable; -struct Declaration; -struct TupleDeclaration; -struct TypedefDeclaration; -struct AliasDeclaration; -struct AggregateDeclaration; -struct EnumDeclaration; -struct ClassDeclaration; -struct InterfaceDeclaration; -struct StructDeclaration; -struct UnionDeclaration; -struct FuncDeclaration; -struct FuncAliasDeclaration; -struct FuncLiteralDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct VarDeclaration; -struct AttribDeclaration; -struct Symbol; -struct Package; -struct Module; -struct Import; -struct Type; -struct TypeTuple; -struct WithStatement; -struct LabelDsymbol; -struct TemplateDeclaration; -struct TemplateInstance; -struct TemplateMixin; -struct EnumMember; -struct ScopeDsymbol; -struct WithScopeSymbol; -struct ArrayScopeSymbol; -struct StaticStructInitDeclaration; -struct Expression; -struct DeleteDeclaration; -struct HdrGenState; -struct OverloadSet; -struct TypeInfoDeclaration; -struct ClassInfoDeclaration; - -#if IN_GCC -union tree_node; -typedef union tree_node TYPE; -#else -struct TYPE; -#endif - -// llvm -#if IN_LLVM -namespace llvm -{ - class Value; -} -#endif - -enum PROT -{ - PROTundefined, - PROTnone, // no access - PROTprivate, - PROTpackage, - PROTprotected, - PROTpublic, - PROTexport, -}; - - -struct Dsymbol : Object -{ - Identifier *ident; - Identifier *c_ident; - Dsymbol *parent; - Symbol *csym; // symbol for code generator - Symbol *isym; // import version of csym - unsigned char *comment; // documentation comment for this Dsymbol - Loc loc; // where defined - - Dsymbol(); - Dsymbol(Identifier *); - char *toChars(); - char *toPrettyChars(); - char *locToChars(); - int equals(Object *o); - int isAnonymous(); - void error(Loc loc, const char *format, ...); - void error(const char *format, ...); - void checkDeprecated(Loc loc, Scope *sc); - Module *getModule(); - Module *getCompilationModule(); // possibly different for templates - Dsymbol *pastMixin(); - Dsymbol *toParent(); - Dsymbol *toParent2(); - TemplateInstance *inTemplateInstance(); - - int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() - - static Array *arraySyntaxCopy(Array *a); - - virtual const char *kind(); - virtual Dsymbol *toAlias(); // resolve real symbol - virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - virtual void semantic(Scope *sc); - virtual void semantic2(Scope *sc); - virtual void semantic3(Scope *sc); - virtual void inlineScan(); - virtual Dsymbol *search(Loc loc, Identifier *ident, int flags); - Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id); - virtual int overloadInsert(Dsymbol *s); -#ifdef _DH - char *toHChars(); - virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); -#endif - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toDocBuffer(OutBuffer *buf); - virtual unsigned size(Loc loc); - virtual int isforwardRef(); - virtual void defineRef(Dsymbol *s); - virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member - virtual ClassDeclaration *isClassMember(); // are we a member of a class? - virtual int isExport(); // is Dsymbol exported? - virtual int isImportedSymbol(); // is Dsymbol imported? - virtual int isDeprecated(); // is Dsymbol deprecated? - virtual int isOverloadable(); - virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? - virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? - virtual Type *getType(); // is this a type? - virtual char *mangle(); - virtual int needThis(); // need a 'this' pointer? - virtual enum PROT prot(); - virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual int oneMember(Dsymbol **ps); - static int oneMembers(Array *members, Dsymbol **ps); - virtual int hasPointers(); - virtual void addLocalClass(ClassDeclarations *) { } - virtual void checkCtorConstInit() { } - - virtual void addComment(unsigned char *comment); - virtual void emitComment(Scope *sc); - void emitDitto(Scope *sc); - - // Backend - - virtual Symbol *toSymbol(); // to backend symbol - virtual void toObjFile(int multiobj); // compile to .obj file - virtual int cvMember(unsigned char *p); // emit cv debug info for member - - Symbol *toImport(); // to backend import symbol - static Symbol *toImport(Symbol *s); // to backend import symbol - - Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper - - // Eliminate need for dynamic_cast - virtual Package *isPackage() { return NULL; } - virtual Module *isModule() { return NULL; } - virtual EnumMember *isEnumMember() { return NULL; } - virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; } - virtual TemplateInstance *isTemplateInstance() { return NULL; } - virtual TemplateMixin *isTemplateMixin() { return NULL; } - virtual Declaration *isDeclaration() { return NULL; } - virtual TupleDeclaration *isTupleDeclaration() { return NULL; } - virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } - virtual AliasDeclaration *isAliasDeclaration() { return NULL; } - virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } - virtual FuncDeclaration *isFuncDeclaration() { return NULL; } - virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } - virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } - virtual CtorDeclaration *isCtorDeclaration() { return NULL; } - virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } - virtual DtorDeclaration *isDtorDeclaration() { return NULL; } - virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } - virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } - virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } - virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } - virtual NewDeclaration *isNewDeclaration() { return NULL; } - virtual VarDeclaration *isVarDeclaration() { return NULL; } - virtual ClassDeclaration *isClassDeclaration() { return NULL; } - virtual StructDeclaration *isStructDeclaration() { return NULL; } - virtual UnionDeclaration *isUnionDeclaration() { return NULL; } - virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; } - virtual ScopeDsymbol *isScopeDsymbol() { return NULL; } - virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; } - virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } - virtual Import *isImport() { return NULL; } - virtual EnumDeclaration *isEnumDeclaration() { return NULL; } -#ifdef _DH - virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } -#endif - virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } - virtual AttribDeclaration *isAttribDeclaration() { return NULL; } - virtual OverloadSet *isOverloadSet() { return NULL; } - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } - virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } - - // llvm stuff - int llvmInternal; - - IrDsymbol ir; -}; - -// Dsymbol that generates a scope - -struct ScopeDsymbol : Dsymbol -{ - Array *members; // all Dsymbol's in this scope - DsymbolTable *symtab; // members[] sorted into table - - Array *imports; // imported ScopeDsymbol's - unsigned char *prots; // array of PROT, one for each import - - ScopeDsymbol(); - ScopeDsymbol(Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - void importScope(ScopeDsymbol *s, enum PROT protection); - int isforwardRef(); - void defineRef(Dsymbol *s); - static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); - Dsymbol *nameCollision(Dsymbol *s); - const char *kind(); - FuncDeclaration *findGetMembers(); - - void emitMemberComments(Scope *sc); - - static size_t dim(Array *members); - static Dsymbol *getNth(Array *members, size_t nth, size_t *pn = NULL); - - ScopeDsymbol *isScopeDsymbol() { return this; } -}; - -// With statement scope - -struct WithScopeSymbol : ScopeDsymbol -{ - WithStatement *withstate; - - WithScopeSymbol(WithStatement *withstate); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - WithScopeSymbol *isWithScopeSymbol() { return this; } -}; - -// Array Index/Slice scope - -struct ArrayScopeSymbol : ScopeDsymbol -{ - Expression *exp; // IndexExp or SliceExp - TypeTuple *type; // for tuple[length] - TupleDeclaration *td; // for tuples of objects - Scope *sc; - - ArrayScopeSymbol(Scope *sc, Expression *e); - ArrayScopeSymbol(Scope *sc, TypeTuple *t); - ArrayScopeSymbol(Scope *sc, TupleDeclaration *td); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - ArrayScopeSymbol *isArrayScopeSymbol() { return this; } -}; - -// Overload Sets - -struct OverloadSet : Dsymbol -{ - Dsymbols a; // array of Dsymbols - - OverloadSet(); - void push(Dsymbol *s); - OverloadSet *isOverloadSet() { return this; } - const char *kind(); -}; - -// Table of Dsymbol's - -struct DsymbolTable : Object -{ - StringTable *tab; - - DsymbolTable(); - ~DsymbolTable(); - - // Look up Identifier. Return Dsymbol if found, NULL if not. - Dsymbol *lookup(Identifier *ident); - - // Insert Dsymbol in table. Return NULL if already there. - Dsymbol *insert(Dsymbol *s); - - // Look for Dsymbol in table. If there, return it. If not, insert s and return that. - Dsymbol *update(Dsymbol *s); - Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same -}; - -#endif /* DMD_DSYMBOL_H */ + +// 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. + +#ifndef DMD_DSYMBOL_H +#define DMD_DSYMBOL_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "stringtable.h" + +#include "mars.h" +#include "arraytypes.h" + +#if IN_LLVM +#include "../ir/irdsymbol.h" +#endif + +struct Identifier; +struct Scope; +struct DsymbolTable; +struct Declaration; +struct ThisDeclaration; +struct TupleDeclaration; +struct TypedefDeclaration; +struct AliasDeclaration; +struct AggregateDeclaration; +struct EnumDeclaration; +struct ClassDeclaration; +struct InterfaceDeclaration; +struct StructDeclaration; +struct UnionDeclaration; +struct FuncDeclaration; +struct FuncAliasDeclaration; +struct FuncLiteralDeclaration; +struct CtorDeclaration; +struct PostBlitDeclaration; +struct DtorDeclaration; +struct StaticCtorDeclaration; +struct StaticDtorDeclaration; +struct InvariantDeclaration; +struct UnitTestDeclaration; +struct NewDeclaration; +struct VarDeclaration; +struct AttribDeclaration; +#if IN_DMD +struct Symbol; +#endif +struct Package; +struct Module; +struct Import; +struct Type; +struct TypeTuple; +struct WithStatement; +struct LabelDsymbol; +struct TemplateDeclaration; +struct TemplateInstance; +struct TemplateMixin; +struct EnumMember; +struct ScopeDsymbol; +struct WithScopeSymbol; +struct ArrayScopeSymbol; +struct StaticStructInitDeclaration; +struct Expression; +struct DeleteDeclaration; +struct HdrGenState; +struct OverloadSet; +#if IN_LLVM +struct TypeInfoDeclaration; +struct ClassInfoDeclaration; +#endif + +#if IN_DMD +struct Symbol; +#endif + +#if IN_GCC +union tree_node; +typedef union tree_node TYPE; +#else +struct TYPE; +#endif + +#if IN_LLVM +class Ir; +class IrSymbol; +namespace llvm +{ + class Value; +} +#endif +#if IN_DMD +// Back end +struct Classsym; +#endif + +enum PROT +{ + PROTundefined, + PROTnone, // no access + PROTprivate, + PROTpackage, + PROTprotected, + PROTpublic, + PROTexport, +}; + + +struct Dsymbol : Object +{ + Identifier *ident; + Identifier *c_ident; + Dsymbol *parent; +#if IN_DMD + Symbol *csym; // symbol for code generator + Symbol *isym; // import version of csym +#endif + unsigned char *comment; // documentation comment for this Dsymbol + Loc loc; // where defined + + Dsymbol(); + Dsymbol(Identifier *); + char *toChars(); + char *toPrettyChars(); + char *locToChars(); + int equals(Object *o); + int isAnonymous(); + void error(Loc loc, const char *format, ...) IS_PRINTF(3); + void error(const char *format, ...) IS_PRINTF(2); + void checkDeprecated(Loc loc, Scope *sc); + Module *getModule(); // module where declared + Module *getCompilationModule(); // possibly different for templates + Dsymbol *pastMixin(); + Dsymbol *toParent(); + Dsymbol *toParent2(); + TemplateInstance *inTemplateInstance(); + + int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() + + static Array *arraySyntaxCopy(Array *a); + + virtual const char *kind(); + virtual Dsymbol *toAlias(); // resolve real symbol + virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + virtual void semantic(Scope *sc); + virtual void semantic2(Scope *sc); + virtual void semantic3(Scope *sc); + virtual void inlineScan(); + virtual Dsymbol *search(Loc loc, Identifier *ident, int flags); + Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id); + virtual int overloadInsert(Dsymbol *s); +#ifdef _DH + char *toHChars(); + virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); +#endif + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual void toDocBuffer(OutBuffer *buf); + virtual unsigned size(Loc loc); + virtual int isforwardRef(); + virtual void defineRef(Dsymbol *s); + virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member + virtual ClassDeclaration *isClassMember(); // are we a member of a class? + virtual int isExport(); // is Dsymbol exported? + virtual int isImportedSymbol(); // is Dsymbol imported? + virtual int isDeprecated(); // is Dsymbol deprecated? + virtual int isOverloadable(); + virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? + virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? + virtual Type *getType(); // is this a type? + virtual char *mangle(); + virtual int needThis(); // need a 'this' pointer? + virtual enum PROT prot(); + virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees + virtual int oneMember(Dsymbol **ps); + static int oneMembers(Array *members, Dsymbol **ps); + virtual int hasPointers(); + virtual void addLocalClass(ClassDeclarations *) { } + virtual void checkCtorConstInit() { } + + virtual void addComment(unsigned char *comment); + virtual void emitComment(Scope *sc); + void emitDitto(Scope *sc); + +#if IN_DMD + // Backend + + virtual Symbol *toSymbol(); // to backend symbol + virtual void toObjFile(int multiobj); // compile to .obj file + virtual int cvMember(unsigned char *p); // emit cv debug info for member + + Symbol *toImport(); // to backend import symbol + static Symbol *toImport(Symbol *s); // to backend import symbol + + Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper +#endif + + // Eliminate need for dynamic_cast + virtual Package *isPackage() { return NULL; } + virtual Module *isModule() { return NULL; } + virtual EnumMember *isEnumMember() { return NULL; } + virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; } + virtual TemplateInstance *isTemplateInstance() { return NULL; } + virtual TemplateMixin *isTemplateMixin() { return NULL; } + virtual Declaration *isDeclaration() { return NULL; } + virtual ThisDeclaration *isThisDeclaration() { return NULL; } + virtual TupleDeclaration *isTupleDeclaration() { return NULL; } + virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } + virtual AliasDeclaration *isAliasDeclaration() { return NULL; } + virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } + virtual FuncDeclaration *isFuncDeclaration() { return NULL; } + virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } + virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } + virtual CtorDeclaration *isCtorDeclaration() { return NULL; } + virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } + virtual DtorDeclaration *isDtorDeclaration() { return NULL; } + virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } + virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } + virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } + virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } + virtual NewDeclaration *isNewDeclaration() { return NULL; } + virtual VarDeclaration *isVarDeclaration() { return NULL; } + virtual ClassDeclaration *isClassDeclaration() { return NULL; } + virtual StructDeclaration *isStructDeclaration() { return NULL; } + virtual UnionDeclaration *isUnionDeclaration() { return NULL; } + virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; } + virtual ScopeDsymbol *isScopeDsymbol() { return NULL; } + virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; } + virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } + virtual Import *isImport() { return NULL; } + virtual EnumDeclaration *isEnumDeclaration() { return NULL; } +#ifdef _DH + virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } +#endif + virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } + virtual AttribDeclaration *isAttribDeclaration() { return NULL; } + virtual OverloadSet *isOverloadSet() { return NULL; } + virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } + virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } + +#if IN_LLVM + /// Codegen traversal + virtual void codegen(Ir* ir); + + // llvm stuff + int llvmInternal; + + IrDsymbol ir; + IrSymbol* irsym; +#endif +}; + +// Dsymbol that generates a scope + +struct ScopeDsymbol : Dsymbol +{ + Array *members; // all Dsymbol's in this scope + DsymbolTable *symtab; // members[] sorted into table + + Array *imports; // imported ScopeDsymbol's + unsigned char *prots; // array of PROT, one for each import + + ScopeDsymbol(); + ScopeDsymbol(Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + void importScope(ScopeDsymbol *s, enum PROT protection); + int isforwardRef(); + void defineRef(Dsymbol *s); + static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); + Dsymbol *nameCollision(Dsymbol *s); + const char *kind(); + FuncDeclaration *findGetMembers(); + + void emitMemberComments(Scope *sc); + + static size_t dim(Array *members); + static Dsymbol *getNth(Array *members, size_t nth, size_t *pn = NULL); + + ScopeDsymbol *isScopeDsymbol() { return this; } +}; + +// With statement scope + +struct WithScopeSymbol : ScopeDsymbol +{ + WithStatement *withstate; + + WithScopeSymbol(WithStatement *withstate); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + + WithScopeSymbol *isWithScopeSymbol() { return this; } +}; + +// Array Index/Slice scope + +struct ArrayScopeSymbol : ScopeDsymbol +{ + Expression *exp; // IndexExp or SliceExp + TypeTuple *type; // for tuple[length] + TupleDeclaration *td; // for tuples of objects + Scope *sc; + + ArrayScopeSymbol(Scope *sc, Expression *e); + ArrayScopeSymbol(Scope *sc, TypeTuple *t); + ArrayScopeSymbol(Scope *sc, TupleDeclaration *td); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + + ArrayScopeSymbol *isArrayScopeSymbol() { return this; } +}; + +// Overload Sets + +struct OverloadSet : Dsymbol +{ + Dsymbols a; // array of Dsymbols + + OverloadSet(); + void push(Dsymbol *s); + OverloadSet *isOverloadSet() { return this; } + const char *kind(); +}; + +// Table of Dsymbol's + +struct DsymbolTable : Object +{ + StringTable *tab; + + DsymbolTable(); + ~DsymbolTable(); + + // Look up Identifier. Return Dsymbol if found, NULL if not. + Dsymbol *lookup(Identifier *ident); + + // Insert Dsymbol in table. Return NULL if already there. + Dsymbol *insert(Dsymbol *s); + + // Look for Dsymbol in table. If there, return it. If not, insert s and return that. + Dsymbol *update(Dsymbol *s); + Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same +}; + +#endif /* DMD_DSYMBOL_H */ diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/dump.c --- a/dmd2/dump.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/dump.c Sat May 30 17:23:32 2009 +0100 @@ -52,7 +52,7 @@ void IntegerExp::dump(int i) { indent(i); - printf("%p %lld type=%s\n", this, (intmax_t)value, type_print(type)); + printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type)); } void IdentifierExp::dump(int i) diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/entity.c --- a/dmd2/entity.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/entity.c Sat May 30 17:23:32 2009 +0100 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/enum.c --- a/dmd2/enum.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/enum.c Sat May 30 17:23:32 2009 +0100 @@ -30,7 +30,9 @@ maxval = NULL; minval = NULL; defaultval = NULL; +#if IN_DMD sinit = NULL; +#endif scope = NULL; isdeprecated = 0; } diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/enum.h --- a/dmd2/enum.h Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/enum.h Sat May 30 17:23:32 2009 +0100 @@ -1,90 +1,96 @@ - -// 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. - -#ifndef DMD_ENUM_H -#define DMD_ENUM_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -struct Identifier; -struct Type; -struct Expression; -#ifdef _DH -struct HdrGenState; -#endif - - -struct EnumDeclaration : ScopeDsymbol -{ /* enum ident : memtype { ... } - */ - Type *type; // the TypeEnum - Type *memtype; // type of the members - -#if DMDV1 - integer_t maxval; - integer_t minval; - integer_t defaultval; // default initializer -#else - Expression *maxval; - Expression *minval; - Expression *defaultval; // default initializer - - Scope *scope; // !=NULL means context to use -#endif - int isdeprecated; - - EnumDeclaration(Loc loc, Identifier *id, Type *memtype); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - int oneMember(Dsymbol **ps); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *getType(); - const char *kind(); -#if DMDV2 - Dsymbol *search(Loc, Identifier *ident, int flags); -#endif - int isDeprecated(); // is Dsymbol deprecated? - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - EnumDeclaration *isEnumDeclaration() { return this; } - - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); - - Symbol *sinit; - Symbol *toInitializer(); -}; - - -struct EnumMember : Dsymbol -{ - Expression *value; - Type *type; - - EnumMember(Loc loc, Identifier *id, Expression *value, Type *type); - Dsymbol *syntaxCopy(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - EnumMember *isEnumMember() { return this; } -}; - -#endif /* DMD_ENUM_H */ + +// 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. + +#ifndef DMD_ENUM_H +#define DMD_ENUM_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "dsymbol.h" + +struct Identifier; +struct Type; +struct Expression; +#ifdef _DH +struct HdrGenState; +#endif + + +struct EnumDeclaration : ScopeDsymbol +{ /* enum ident : memtype { ... } + */ + Type *type; // the TypeEnum + Type *memtype; // type of the members + +#if DMDV1 + dinteger_t maxval; + dinteger_t minval; + dinteger_t defaultval; // default initializer +#else + Expression *maxval; + Expression *minval; + Expression *defaultval; // default initializer + + Scope *scope; // !=NULL means context to use +#endif + int isdeprecated; + + EnumDeclaration(Loc loc, Identifier *id, Type *memtype); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + int oneMember(Dsymbol **ps); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Type *getType(); + const char *kind(); +#if DMDV2 + Dsymbol *search(Loc, Identifier *ident, int flags); +#endif + int isDeprecated(); // is Dsymbol deprecated? + + void emitComment(Scope *sc); + void toDocBuffer(OutBuffer *buf); + + EnumDeclaration *isEnumDeclaration() { return this; } + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + void toDebug(); + int cvMember(unsigned char *p); + + Symbol *sinit; + Symbol *toInitializer(); +#endif + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + + +struct EnumMember : Dsymbol +{ + Expression *value; + Type *type; + + EnumMember(Loc loc, Identifier *id, Expression *value, Type *type); + Dsymbol *syntaxCopy(Dsymbol *s); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + + void emitComment(Scope *sc); + void toDocBuffer(OutBuffer *buf); + + EnumMember *isEnumMember() { return this; } +}; + +#endif /* DMD_ENUM_H */ diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/expression.c --- a/dmd2/expression.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/expression.c Sat May 30 17:23:32 2009 +0100 @@ -1,9754 +1,10129 @@ - -// 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. - -#include -#include -#include -#include -#if _MSC_VER -#include -#else -#endif -#include - -#if _WIN32 && __DMC__ -extern "C" char * __cdecl __locale_decpoint; -#endif - -#if __MINGW32__ -#ifndef isnan -#define isnan _isnan -#endif -#endif - -#ifdef __APPLE__ -#ifndef isnan -int isnan(double); -#endif -#endif - -#if IN_GCC -// Issues with using -include total.h (defines integer_t) and then complex.h fails... -#undef integer_t -#endif - -#ifdef __APPLE__ -#define integer_t dmd_integer_t -#endif - -#if IN_GCC || IN_LLVM -#include "mem.h" -#elif _WIN32 -#include "..\root\mem.h" -#elif POSIX -#include "../root/mem.h" -#endif - -//#include "port.h" -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "template.h" -#include "utf.h" -#include "enum.h" -#include "scope.h" -#include "statement.h" -#include "declaration.h" -#include "aggregate.h" -#include "import.h" -#include "id.h" -#include "dsymbol.h" -#include "module.h" -#include "attrib.h" -#include "hdrgen.h" -#include "parse.h" - -Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim); -Expression *expandVar(int result, VarDeclaration *v); - -#define LOGSEMANTIC 0 - -/********************************** - * Set operator precedence for each operator. - */ - -// Operator precedence - greater values are higher precedence - -enum PREC -{ - PREC_zero, - PREC_expr, - PREC_assign, - PREC_cond, - PREC_oror, - PREC_andand, - PREC_or, - PREC_xor, - PREC_and, - PREC_equal, - PREC_rel, - PREC_shift, - PREC_add, - PREC_mul, - PREC_unary, - PREC_primary, -}; - -enum PREC precedence[TOKMAX]; - -void initPrecedence() -{ - precedence[TOKdotvar] = PREC_primary; - precedence[TOKimport] = PREC_primary; - precedence[TOKidentifier] = PREC_primary; - precedence[TOKthis] = PREC_primary; - precedence[TOKsuper] = PREC_primary; - precedence[TOKint64] = PREC_primary; - precedence[TOKfloat64] = PREC_primary; - precedence[TOKnull] = PREC_primary; - precedence[TOKstring] = PREC_primary; - precedence[TOKarrayliteral] = PREC_primary; - precedence[TOKtypedot] = PREC_primary; - precedence[TOKtypeid] = PREC_primary; - precedence[TOKis] = PREC_primary; - precedence[TOKassert] = PREC_primary; - precedence[TOKfunction] = PREC_primary; - precedence[TOKvar] = PREC_primary; -#if DMDV2 - precedence[TOKdefault] = PREC_primary; -#endif - - // post - precedence[TOKdotti] = PREC_primary; - precedence[TOKdot] = PREC_primary; -// precedence[TOKarrow] = PREC_primary; - precedence[TOKplusplus] = PREC_primary; - precedence[TOKminusminus] = PREC_primary; - precedence[TOKcall] = PREC_primary; - precedence[TOKslice] = PREC_primary; - precedence[TOKarray] = PREC_primary; - - precedence[TOKaddress] = PREC_unary; - precedence[TOKstar] = PREC_unary; - precedence[TOKneg] = PREC_unary; - precedence[TOKuadd] = PREC_unary; - precedence[TOKnot] = PREC_unary; - precedence[TOKtobool] = PREC_add; - precedence[TOKtilde] = PREC_unary; - precedence[TOKdelete] = PREC_unary; - precedence[TOKnew] = PREC_unary; - precedence[TOKcast] = PREC_unary; - - precedence[TOKmul] = PREC_mul; - precedence[TOKdiv] = PREC_mul; - precedence[TOKmod] = PREC_mul; - - precedence[TOKadd] = PREC_add; - precedence[TOKmin] = PREC_add; - precedence[TOKcat] = PREC_add; - - precedence[TOKshl] = PREC_shift; - precedence[TOKshr] = PREC_shift; - precedence[TOKushr] = PREC_shift; - - precedence[TOKlt] = PREC_rel; - precedence[TOKle] = PREC_rel; - precedence[TOKgt] = PREC_rel; - precedence[TOKge] = PREC_rel; - precedence[TOKunord] = PREC_rel; - precedence[TOKlg] = PREC_rel; - precedence[TOKleg] = PREC_rel; - precedence[TOKule] = PREC_rel; - precedence[TOKul] = PREC_rel; - precedence[TOKuge] = PREC_rel; - precedence[TOKug] = PREC_rel; - precedence[TOKue] = PREC_rel; - precedence[TOKin] = PREC_rel; - - precedence[TOKequal] = PREC_equal; - precedence[TOKnotequal] = PREC_equal; - precedence[TOKidentity] = PREC_equal; - precedence[TOKnotidentity] = PREC_equal; - - precedence[TOKand] = PREC_and; - - precedence[TOKxor] = PREC_xor; - - precedence[TOKor] = PREC_or; - - precedence[TOKandand] = PREC_andand; - - precedence[TOKoror] = PREC_oror; - - precedence[TOKquestion] = PREC_cond; - - precedence[TOKassign] = PREC_assign; - precedence[TOKconstruct] = PREC_assign; - precedence[TOKblit] = PREC_assign; - precedence[TOKaddass] = PREC_assign; - precedence[TOKminass] = PREC_assign; - precedence[TOKcatass] = PREC_assign; - precedence[TOKmulass] = PREC_assign; - precedence[TOKdivass] = PREC_assign; - precedence[TOKmodass] = PREC_assign; - precedence[TOKshlass] = PREC_assign; - precedence[TOKshrass] = PREC_assign; - precedence[TOKushrass] = PREC_assign; - precedence[TOKandass] = PREC_assign; - precedence[TOKorass] = PREC_assign; - precedence[TOKxorass] = PREC_assign; - - precedence[TOKcomma] = PREC_expr; -} - -/************************************************************* - * Given var, we need to get the - * right 'this' pointer if var is in an outer class, but our - * existing 'this' pointer is in an inner class. - * Input: - * e1 existing 'this' - * ad struct or class we need the correct 'this' for - * var the specific member of ad we're accessing - */ - -Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, - Expression *e1, Declaration *var) -{ - //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars()); - L1: - Type *t = e1->type->toBasetype(); - //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars()); - - /* If e1 is not the 'this' pointer for ad - */ - if (ad && - !(t->ty == Tpointer && t->nextOf()->ty == Tstruct && - ((TypeStruct *)t->nextOf())->sym == ad) - && - !(t->ty == Tstruct && - ((TypeStruct *)t)->sym == ad) - ) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - /* e1 is the right this if ad is a base class of e1 - */ - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - /* Only classes can be inner classes with an 'outer' - * member pointing to the enclosing class instance - */ - if (tcd && tcd->isNested()) - { /* e1 is the 'this' pointer for an inner class: tcd. - * Rewrite it as the 'this' pointer for the outer class. - */ - - e1 = new DotVarExp(loc, e1, tcd->vthis); - e1->type = tcd->vthis->type; - // Do not call checkNestedRef() - //e1 = e1->semantic(sc); - - // Skip up over nested functions, and get the enclosing - // class type. - int n = 0; - Dsymbol *s; - for (s = tcd->toParent(); - s && s->isFuncDeclaration(); - s = s->toParent()) - { FuncDeclaration *f = s->isFuncDeclaration(); - if (f->vthis) - { - //printf("rewriting e1 to %s's this\n", f->toChars()); - n++; - - // LDC seems dmd misses it sometimes here :/ - #if DMDV2 - // FIXME!!!! - #else - f->vthis->nestedref = 1; - #endif - - e1 = new VarExp(loc, f->vthis); - } - } - if (s && s->isClassDeclaration()) - { e1->type = s->isClassDeclaration()->type; - if (n > 1) - e1 = e1->semantic(sc); - } - else - e1 = e1->semantic(sc); - goto L1; - } - /* Can't find a path from e1 to ad - */ - e1->error("this for %s needs to be type %s not type %s", - var->toChars(), ad->toChars(), t->toChars()); - } - } - return e1; -} - -/***************************************** - * Determine if 'this' is available. - * If it is, return the FuncDeclaration that has it. - */ - -FuncDeclaration *hasThis(Scope *sc) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - - //printf("hasThis()\n"); - fdthis = sc->parent->isFuncDeclaration(); - //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : ""); - - // Go upwards until we find the enclosing member function - fd = fdthis; - while (1) - { - if (!fd) - { - goto Lno; - } - if (!fd->isNested()) - break; - - Dsymbol *parent = fd->parent; - while (parent) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - parent = ti->parent; - else - break; - } - - fd = fd->parent->isFuncDeclaration(); - } - - if (!fd->isThis()) - { //printf("test '%s'\n", fd->toChars()); - goto Lno; - } - - assert(fd->vthis); - return fd; - -Lno: - return NULL; // don't have 'this' available -} - - -/*************************************** - * Pull out any properties. - */ - -Expression *resolveProperties(Scope *sc, Expression *e) -{ - //printf("resolveProperties(%s)\n", e->toChars()); - if (e->type) - { - Type *t = e->type->toBasetype(); - - if (t->ty == Tfunction || e->op == TOKoverloadset) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - - /* Look for e being a lazy parameter; rewrite as delegate call - */ - else if (e->op == TOKvar) - { VarExp *ve = (VarExp *)e; - - if (ve->var->storage_class & STClazy) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - } - - else if (e->op == TOKdotexp) - { - e->error("expression has no value"); - } - - } - return e; -} - -/****************************** - * Perform semantic() on an array of Expressions. - */ - -void arrayExpressionSemantic(Expressions *exps, Scope *sc) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->semantic(sc); - exps->data[i] = (void *)e; - } - } -} - - -/****************************** - * Perform canThrow() on an array of Expressions. - */ - -#if DMDV2 -int arrayExpressionCanThrow(Expressions *exps) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - if (e && e->canThrow()) - return 1; - } - } - return 0; -} -#endif - -/**************************************** - * Expand tuples. - */ - -void expandTuples(Expressions *exps) -{ - //printf("expandTuples()\n"); - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (Expression *)exps->data[i]; - if (!arg) - continue; - - // Look for tuple with 0 members - if (arg->op == TOKtype) - { TypeExp *e = (TypeExp *)arg; - if (e->type->toBasetype()->ty == Ttuple) - { TypeTuple *tt = (TypeTuple *)e->type->toBasetype(); - - if (!tt->arguments || tt->arguments->dim == 0) - { - exps->remove(i); - if (i == exps->dim) - return; - i--; - continue; - } - } - } - - // Inline expand all the tuples - while (arg->op == TOKtuple) - { TupleExp *te = (TupleExp *)arg; - - exps->remove(i); // remove arg - exps->insert(i, te->exps); // replace with tuple contents - if (i == exps->dim) - return; // empty tuple, no more arguments - arg = (Expression *)exps->data[i]; - } - } - } -} - -/**************************************** - * Preprocess arguments to function. - */ - -void preFunctionArguments(Loc loc, Scope *sc, Expressions *exps) -{ - if (exps) - { - expandTuples(exps); - - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (Expression *)exps->data[i]; - - if (!arg->type) - { -#ifdef DEBUG - if (!global.gag) - printf("1: \n"); -#endif - arg->error("%s is not an expression", arg->toChars()); - arg = new IntegerExp(arg->loc, 0, Type::tint32); - } - - arg = resolveProperties(sc, arg); - exps->data[i] = (void *) arg; - - //arg->rvalue(); -#if 0 - if (arg->type->ty == Tfunction) - { - arg = new AddrExp(arg->loc, arg); - arg = arg->semantic(sc); - exps->data[i] = (void *) arg; - } -#endif - } - } -} - -/********************************************* - * Call copy constructor for struct value argument. - */ -#if DMDV2 -Expression *callCpCtor(Loc loc, Scope *sc, Expression *e) -{ - Type *tb = e->type->toBasetype(); - assert(tb->ty == Tstruct); - StructDeclaration *sd = ((TypeStruct *)tb)->sym; - if (sd->cpctor) - { - /* Create a variable tmp, and replace the argument e with: - * (tmp = e),tmp - * and let AssignExp() handle the construction. - * This is not the most efficent, ideally tmp would be constructed - * directly onto the stack. - */ - Identifier *idtmp = Lexer::uniqueId("__tmp"); - VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); - Expression *ae = new DeclarationExp(loc, tmp); - e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e->semantic(sc); - } - return e; -} -#endif - -/**************************************** - * Now that we know the exact type of the function we're calling, - * the arguments[] need to be adjusted: - * 1. implicitly convert argument to the corresponding parameter type - * 2. add default arguments for any missing arguments - * 3. do default promotions on arguments corresponding to ... - * 4. add hidden _arguments[] argument - * 5. call copy constructor for struct value arguments - */ - -void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) -{ - unsigned n; - - //printf("functionArguments()\n"); - assert(arguments); - size_t nargs = arguments ? arguments->dim : 0; - size_t nparams = Argument::dim(tf->parameters); - - if (nargs > nparams && tf->varargs == 0) - error(loc, "expected %"PRIuSIZE" arguments, not %"PRIuSIZE, nparams, nargs); - - n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) - - int done = 0; - for (size_t i = 0; i < n; i++) - { - Expression *arg; - - if (i < nargs) - arg = (Expression *)arguments->data[i]; - else - arg = NULL; - Type *tb; - - if (i < nparams) - { - Argument *p = Argument::getNth(tf->parameters, i); - - if (!arg) - { - if (!p->defaultArg) - { - if (tf->varargs == 2 && i + 1 == nparams) - goto L2; - error(loc, "expected %"PRIuSIZE" arguments, not %"PRIuSIZE, nparams, nargs); - break; - } - arg = p->defaultArg; -#if DMDV2 - if (arg->op == TOKdefault) - { DefaultInitExp *de = (DefaultInitExp *)arg; - arg = de->resolve(loc, sc); - } - else -#endif - arg = arg->copy(); - arguments->push(arg); - nargs++; - } - - if (tf->varargs == 2 && i + 1 == nparams) - { - //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); - if (arg->implicitConvTo(p->type)) - { - if (nargs != nparams) - error(loc, "expected %"PRIuSIZE" arguments, not %"PRIuSIZE, nparams, nargs); - goto L1; - } - L2: - Type *tb = p->type->toBasetype(); - Type *tret = p->isLazyArray(); - switch (tb->ty) - { - case Tsarray: - case Tarray: - { // Create a static array variable v of type arg->type -#ifdef IN_GCC - /* GCC 4.0 does not like zero length arrays used like - this; pass a null array value instead. Could also - just make a one-element array. */ - if (nargs - i == 0) - { - arg = new NullExp(loc); - break; - } -#endif - Identifier *id = Lexer::uniqueId("__arrayArg"); - Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i)); - t = t->semantic(loc, sc); - VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); - v->semantic(sc); - v->parent = sc->parent; - //sc->insert(v); - - Expression *c = new DeclarationExp(0, v); - c->type = v->type; - - for (size_t u = i; u < nargs; u++) - { Expression *a = (Expression *)arguments->data[u]; - if (tret && !((TypeArray *)tb)->next->equals(a->type)) - a = a->toDelegate(sc, tret); - - Expression *e = new VarExp(loc, v); - e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); - AssignExp *ae = new AssignExp(loc, e, a); - ae->op = TOKconstruct; - if (c) - c = new CommaExp(loc, c, ae); - else - c = ae; - } - arg = new VarExp(loc, v); - if (c) - arg = new CommaExp(loc, c, arg); - break; - } - case Tclass: - { /* Set arg to be: - * new Tclass(arg0, arg1, ..., argn) - */ - Expressions *args = new Expressions(); - args->setDim(nargs - i); - for (size_t u = i; u < nargs; u++) - args->data[u - i] = arguments->data[u]; - arg = new NewExp(loc, NULL, NULL, p->type, args); - break; - } - default: - if (!arg) - { error(loc, "not enough arguments"); - return; - } - break; - } - arg = arg->semantic(sc); - //printf("\targ = '%s'\n", arg->toChars()); - arguments->setDim(i + 1); - done = 1; - } - - L1: - if (!(p->storageClass & STClazy && p->type->ty == Tvoid)) - { - if (p->type != arg->type) - { - //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars()); - arg = arg->implicitCastTo(sc, p->type); - arg = arg->optimize(WANTvalue); - } - } - if (p->storageClass & STCref) - { - arg = arg->toLvalue(sc, arg); - } - else if (p->storageClass & STCout) - { - arg = arg->modifiableLvalue(sc, arg); - } - - tb = arg->type->toBasetype(); - -// LDC we don't want this! -#if !IN_LLVM - // Convert static arrays to pointers - if (tb->ty == Tsarray) - { - arg = arg->checkToPointer(); - } -#endif - - - if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) - { - arg = callCpCtor(loc, sc, arg); - } - - // Convert lazy argument to a delegate - if (p->storageClass & STClazy) - { - arg = arg->toDelegate(sc, p->type); - } - - /* Look for arguments that cannot 'escape' from the called - * function. - */ - if (!tf->parameterEscapes(p)) - { - /* Function literals can only appear once, so if this - * appearance was scoped, there cannot be any others. - */ - if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - fe->fd->tookAddressOf = 0; - } - - /* For passing a delegate to a scoped parameter, - * this doesn't count as taking the address of it. - * We only worry about 'escaping' references to the function. - */ - else if (arg->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)arg; - if (de->e1->op == TOKvar) - { VarExp *ve = (VarExp *)de->e1; - FuncDeclaration *f = ve->var->isFuncDeclaration(); - if (f) - { f->tookAddressOf--; - //printf("tookAddressOf = %d\n", f->tookAddressOf); - } - } - } - } - } - else - { - - // If not D linkage, do promotions - // LDC: don't do promotions on intrinsics - if (tf->linkage != LINKd && tf->linkage != LINKintrinsic) - { - // Promote bytes, words, etc., to ints - arg = arg->integralPromotions(sc); - - // Promote floats to doubles - switch (arg->type->ty) - { - case Tfloat32: - arg = arg->castTo(sc, Type::tfloat64); - break; - - case Timaginary32: - arg = arg->castTo(sc, Type::timaginary64); - break; - } - } - - // Convert static arrays to dynamic arrays - tb = arg->type->toBasetype(); - if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; - Type *ta = ts->next->arrayOf(); - if (ts->size(arg->loc) == 0) - { arg = new NullExp(arg->loc); - arg->type = ta; - } - else - arg = arg->castTo(sc, ta); - } -#if DMDV2 - if (tb->ty == Tstruct) - { - arg = callCpCtor(loc, sc, arg); - } - - // Give error for overloaded function addresses - if (arg->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)arg; - if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) - arg->error("function %s is overloaded", arg->toChars()); - } -#endif - arg->rvalue(); - } - arg = arg->optimize(WANTvalue); - arguments->data[i] = (void *) arg; - if (done) - break; - } - -#if !IN_LLVM - // If D linkage and variadic, add _arguments[] as first argument - if (tf->linkage == LINKd && tf->varargs == 1) - { - Expression *e; - - e = createTypeInfoArray(sc, (Expression **)&arguments->data[nparams], - arguments->dim - nparams); - arguments->insert(0, e); - } -#endif -} - -/************************************************** - * Write expression out to buf, but wrap it - * in ( ) if its precedence is less than pr. - */ - -void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) -{ - //if (precedence[e->op] == 0) e->dump(0); - if (precedence[e->op] < pr) - { - buf->writeByte('('); - e->toCBuffer(buf, hgs); - buf->writeByte(')'); - } - else - e->toCBuffer(buf, hgs); -} - -/************************************************** - * Write out argument list to buf. - */ - -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = (Expression *)arguments->data[i]; - - if (arg) - { if (i) - buf->writeByte(','); - expToCBuffer(buf, hgs, arg, PREC_assign); - } - } - } -} - -/************************************************** - * Write out argument types to buf. - */ - -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ - if (arguments) - { OutBuffer argbuf; - - for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = (Expression *)arguments->data[i]; - - if (i) - buf->writeByte(','); - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, hgs, 0); - buf->write(&argbuf); - } - } -} - -/******************************** Expression **************************/ - -Expression::Expression(Loc loc, enum TOK op, int size) - : loc(loc) -{ - //printf("Expression::Expression(op = %d) this = %p\n", op, this); - this->loc = loc; - this->op = op; - this->size = size; - type = NULL; -} - -Expression *Expression::syntaxCopy() -{ - //printf("Expression::syntaxCopy()\n"); - //dump(0); - return copy(); -} - -/********************************* - * Does *not* do a deep copy. - */ - -Expression *Expression::copy() -{ - Expression *e; - if (!size) - { -#ifdef DEBUG - fprintf(stdmsg, "No expression copy for: %s\n", toChars()); - printf("op = %d\n", op); - dump(0); -#endif - assert(0); - } - e = (Expression *)mem.malloc(size); - //printf("Expression::copy(op = %d) e = %p\n", op, e); - return (Expression *)memcpy(e, this, size); -} - -/************************** - * Semantically analyze Expression. - * Determine types, fold constants, etc. - */ - -Expression *Expression::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("Expression::semantic() %s\n", toChars()); -#endif - if (type) - type = type->semantic(loc, sc); - else - type = Type::tvoid; - return this; -} - -void Expression::print() -{ - fprintf(stdmsg, "%s\n", toChars()); - fflush(stdmsg); -} - -char *Expression::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -void Expression::error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -void Expression::rvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - { error("expression %s is void and has no value", toChars()); -#if 0 - dump(0); - halt(); -#endif - type = Type::tint32; - } -} - -Expression *Expression::combine(Expression *e1, Expression *e2) -{ - if (e1) - { - if (e2) - { - e1 = new CommaExp(e1->loc, e1, e2); - e1->type = e2->type; - } - } - else - e1 = e2; - return e1; -} - -integer_t Expression::toInteger() -{ - //printf("Expression %s\n", Token::toChars(op)); - error("Integer constant expression expected instead of %s", toChars()); - return 0; -} - -uinteger_t Expression::toUInteger() -{ - //printf("Expression %s\n", Token::toChars(op)); - return (uinteger_t)toInteger(); -} - -real_t Expression::toReal() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return 0; -} - -real_t Expression::toImaginary() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return 0; -} - -complex_t Expression::toComplex() -{ - error("Floating point constant expression expected instead of %s", toChars()); -#ifdef IN_GCC - return complex_t(real_t(0)); // %% nicer -#else - return 0; -#endif -} - -void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); -} - -void Expression::toMangleBuffer(OutBuffer *buf) -{ - error("expression %s is not a valid template value argument", toChars()); -} - -/*************************************** - * Return !=0 if expression is an lvalue. - */ - -int Expression::isLvalue() -{ - return 0; -} - -/******************************* - * Give error if we're not an lvalue. - * If we can, convert expression to be an lvalue. - */ - -Expression *Expression::toLvalue(Scope *sc, Expression *e) -{ - if (!e) - e = this; - else if (!loc.filename) - loc = e->loc; - error("%s is not an lvalue", e->toChars()); - return this; -} - -Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars()); - - // See if this expression is a modifiable lvalue (i.e. not const) - if (type && (!type->isMutable() || !type->isAssignable())) - error("%s is not mutable", e->toChars()); - - return toLvalue(sc, e); -} - -/************************************ - * Detect cases where pointers to the stack can 'escape' the - * lifetime of the stack frame. - */ - -void Expression::checkEscape() -{ -} - -void Expression::checkScalar() -{ - if (!type->isscalar()) - error("'%s' is not a scalar, it is a %s", toChars(), type->toChars()); -} - -void Expression::checkNoBool() -{ - if (type->toBasetype()->ty == Tbool) - error("operation not allowed on bool '%s'", toChars()); -} - -Expression *Expression::checkIntegral() -{ - if (!type->isintegral()) - { error("'%s' is not of integral type, it is a %s", toChars(), type->toChars()); - return new IntegerExp(0); - } - return this; -} - -Expression *Expression::checkArithmetic() -{ - if (!type->isintegral() && !type->isfloating()) - { error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); - return new IntegerExp(0); - } - return this; -} - -void Expression::checkDeprecated(Scope *sc, Dsymbol *s) -{ - s->checkDeprecated(loc, sc); -} - -/******************************** - * Check for expressions that have no use. - * Input: - * flag 0 not going to use the result, so issue error message if no - * side effects - * 1 the result of the expression is used, but still check - * for useless subexpressions - * 2 do not issue error messages, just return !=0 if expression - * has side effects - */ - -int Expression::checkSideEffect(int flag) -{ - if (flag == 0) - { if (op == TOKimport) - { - error("%s has no effect", toChars()); - } - else - error("%s has no effect in expression (%s)", - Token::toChars(op), toChars()); - } - return 0; -} - -/***************************** - * Check that expression can be tested for true or false. - */ - -Expression *Expression::checkToBoolean() -{ - // Default is 'yes' - do nothing - -#ifdef DEBUG - if (!type) - dump(0); -#endif - - if (!type->checkBoolean()) - { - error("expression %s of type %s does not have a boolean value", toChars(), type->toChars()); - } - return this; -} - -/**************************** - */ - -Expression *Expression::checkToPointer() -{ - Expression *e; - Type *tb; - - //printf("Expression::checkToPointer()\n"); - e = this; - - // If C static array, convert to pointer - tb = type->toBasetype(); - if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; - if (ts->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, this); - e->type = ts->next->pointerTo(); - } - return e; -} - -/****************************** - * Take address of expression. - */ - -Expression *Expression::addressOf(Scope *sc) -{ - Expression *e; - - //printf("Expression::addressOf()\n"); - e = toLvalue(sc, NULL); - e = new AddrExp(loc, e); - e->type = type->pointerTo(); - return e; -} - -/****************************** - * If this is a reference, dereference it. - */ - -Expression *Expression::deref() -{ - //printf("Expression::deref()\n"); - if (type->ty == Treference) - { Expression *e; - - e = new PtrExp(loc, this); - e->type = ((TypeReference *)type)->next; - return e; - } - return this; -} - -/******************************** - * Does this expression statically evaluate to a boolean TRUE or FALSE? - */ - -int Expression::isBool(int result) -{ - return FALSE; -} - -/******************************** - * Does this expression result in either a 1 or a 0? - */ - -int Expression::isBit() -{ - return FALSE; -} - -/******************************** - * Can this expression throw an exception? - * Valid only after semantic() pass. - */ - -int Expression::canThrow() -{ - return FALSE; -} - - - -Expressions *Expression::arraySyntaxCopy(Expressions *exps) -{ Expressions *a = NULL; - - if (exps) - { - a = new Expressions(); - a->setDim(exps->dim); - for (int i = 0; i < a->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->syntaxCopy(); - a->data[i] = e; - } - } - return a; -} - -/******************************** IntegerExp **************************/ - -IntegerExp::IntegerExp(Loc loc, integer_t value, Type *type) - : Expression(loc, TOKint64, sizeof(IntegerExp)) -{ - //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : ""); - if (type && !type->isscalar()) - { - //printf("%s, loc = %d\n", toChars(), loc.linnum); - error("integral constant must be scalar type, not %s", type->toChars()); - type = Type::terror; - } - this->type = type; - this->value = value; -} - -IntegerExp::IntegerExp(integer_t value) - : Expression(0, TOKint64, sizeof(IntegerExp)) -{ - this->type = Type::tint32; - this->value = value; -} - -int IntegerExp::equals(Object *o) -{ IntegerExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKint64 && - ((ne = (IntegerExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - value == ne->value)) - return 1; - return 0; -} - -char *IntegerExp::toChars() -{ -#if 1 - return Expression::toChars(); -#else - static char buffer[sizeof(value) * 3 + 1]; - sprintf(buffer, "%lld", value); - return buffer; -#endif -} - -integer_t IntegerExp::toInteger() -{ Type *t; - - t = type; - while (t) - { - switch (t->ty) - { - case Tbit: - case Tbool: value = (value != 0); break; - case Tint8: value = (d_int8) value; break; - case Tchar: - case Tuns8: value = (d_uns8) value; break; - case Tint16: value = (d_int16) value; break; - case Twchar: - case Tuns16: value = (d_uns16) value; break; - case Tint32: value = (d_int32) value; break; - case Tdchar: - case Tuns32: value = (d_uns32) value; break; - case Tint64: value = (d_int64) value; break; - case Tuns64: value = (d_uns64) value; break; - case Tpointer: - // FIXME: Other pointer widths than 32 and 64? - if (PTRSIZE == 4) - value = (d_uns32) value; - else - value = (d_uns64) value; - break; - - case Tenum: - { - TypeEnum *te = (TypeEnum *)t; - t = te->sym->memtype; - continue; - } - - case Ttypedef: - { - TypeTypedef *tt = (TypeTypedef *)t; - t = tt->sym->basetype; - continue; - } - - default: - /* This can happen if errors, such as - * the type is painted on like in fromConstInitializer(). - */ - if (!global.errors) - { type->print(); - assert(0); - } - break; - } - break; - } - return value; -} - -real_t IntegerExp::toReal() -{ - Type *t; - - toInteger(); - t = type->toBasetype(); - if (t->ty == Tuns64) - return (real_t)(d_uns64)value; - else - return (real_t)(d_int64)value; -} - -real_t IntegerExp::toImaginary() -{ - return (real_t) 0; -} - -complex_t IntegerExp::toComplex() -{ - return toReal(); -} - -int IntegerExp::isBool(int result) -{ - return result ? value != 0 : value == 0; -} - -Expression *IntegerExp::semantic(Scope *sc) -{ - if (!type) - { - // Determine what the type of this number is - integer_t number = value; - - if (number & 0x8000000000000000LL) - type = Type::tuns64; - else if (number & 0xFFFFFFFF80000000LL) - type = Type::tint64; - else - type = Type::tint32; - } - else - { if (!type->deco) - type = type->semantic(loc, sc); - } - return this; -} - -Expression *IntegerExp::toLvalue(Scope *sc, Expression *e) -{ - if (!e) - e = this; - else if (!loc.filename) - loc = e->loc; - e->error("constant %s is not an lvalue", e->toChars()); - return this; -} - -void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - integer_t v = toInteger(); - - if (type) - { Type *t = type; - - L1: - switch (t->ty) - { - case Tenum: - { TypeEnum *te = (TypeEnum *)t; - buf->printf("cast(%s)", te->sym->toChars()); - t = te->sym->memtype; - goto L1; - } - - case Ttypedef: - { TypeTypedef *tt = (TypeTypedef *)t; - buf->printf("cast(%s)", tt->sym->toChars()); - t = tt->sym->basetype; - goto L1; - } - - case Twchar: // BUG: need to cast(wchar) - case Tdchar: // BUG: need to cast(dchar) - if ((uinteger_t)v > 0xFF) - { - buf->printf("'\\U%08x'", v); - break; - } - case Tchar: - if (v == '\'') - buf->writestring("'\\''"); - else if (isprint(v) && v != '\\') - buf->printf("'%c'", (int)v); - else - buf->printf("'\\x%02x'", (int)v); - break; - - case Tint8: - buf->writestring("cast(byte)"); - goto L2; - - case Tint16: - buf->writestring("cast(short)"); - goto L2; - - case Tint32: - L2: - buf->printf("%d", (int)v); - break; - - case Tuns8: - buf->writestring("cast(ubyte)"); - goto L3; - - case Tuns16: - buf->writestring("cast(ushort)"); - goto L3; - - case Tuns32: - L3: - buf->printf("%du", (unsigned)v); - break; - - case Tint64: - buf->printf("%lldL", v); - break; - - case Tuns64: - L4: - buf->printf("%lluLU", v); - break; - - case Tbit: - case Tbool: - buf->writestring((char *)(v ? "true" : "false")); - break; - - case Tpointer: - buf->writestring("cast("); - buf->writestring(t->toChars()); - buf->writeByte(')'); - // FIXME: Other pointer widths than 32 and 64? - if (PTRSIZE == 4) - goto L3; - else - goto L4; - - default: - /* This can happen if errors, such as - * the type is painted on like in fromConstInitializer(). - */ - if (!global.errors) - { -#ifdef DEBUG - t->print(); -#endif - assert(0); - } - break; - } - } - else if (v & 0x8000000000000000LL) - buf->printf("0x%llx", v); - else - buf->printf("%lld", v); -} - -void IntegerExp::toMangleBuffer(OutBuffer *buf) -{ - if ((sinteger_t)value < 0) - buf->printf("N%lld", -value); - else - buf->printf("%lld", value); -} - -/******************************** RealExp **************************/ - -RealExp::RealExp(Loc loc, real_t value, Type *type) - : Expression(loc, TOKfloat64, sizeof(RealExp)) -{ - //printf("RealExp::RealExp(%Lg)\n", value); - this->value = value; - this->type = type; -} - -char *RealExp::toChars() -{ - char buffer[sizeof(value) * 3 + 8 + 1 + 1]; - -#ifdef IN_GCC - value.format(buffer, sizeof(buffer)); - if (type->isimaginary()) - strcat(buffer, "i"); -#else - sprintf(buffer, type->isimaginary() ? "%Lgi" : "%Lg", value); -#endif - assert(strlen(buffer) < sizeof(buffer)); - return mem.strdup(buffer); -} - -integer_t RealExp::toInteger() -{ -#ifdef IN_GCC - return toReal().toInt(); -#else - return (sinteger_t) toReal(); -#endif -} - -uinteger_t RealExp::toUInteger() -{ -#ifdef IN_GCC - return (uinteger_t) toReal().toInt(); -#else - return (uinteger_t) toReal(); -#endif -} - -real_t RealExp::toReal() -{ - return type->isreal() ? value : 0; -} - -real_t RealExp::toImaginary() -{ - return type->isreal() ? 0 : value; -} - -complex_t RealExp::toComplex() -{ -#ifdef __DMC__ - return toReal() + toImaginary() * I; -#else - return complex_t(toReal(), toImaginary()); -#endif -} - -/******************************** - * Test to see if two reals are the same. - * Regard NaN's as equivalent. - * Regard +0 and -0 as different. - */ - -int RealEquals(real_t x1, real_t x2) -{ - return // special case nans - (isnan(x1) && isnan(x2)) || - // and zero, in order to distinguish +0 from -0 - (x1 == 0 && x2 == 0 && 1./x1 == 1./x2) || - // otherwise just compare - (x1 != 0. && x1 == x2); -} - -int RealExp::equals(Object *o) -{ RealExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKfloat64 && - ((ne = (RealExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - RealEquals(value, ne->value) - ) - ) - return 1; - return 0; -} - -Expression *RealExp::semantic(Scope *sc) -{ - if (!type) - type = Type::tfloat64; - else - type = type->semantic(loc, sc); - return this; -} - -int RealExp::isBool(int result) -{ -#ifdef IN_GCC - return result ? (! value.isZero()) : (value.isZero()); -#else - return result ? (value != 0) - : (value == 0); -#endif -} - -void floatToBuffer(OutBuffer *buf, Type *type, real_t value) -{ - /* In order to get an exact representation, try converting it - * to decimal then back again. If it matches, use it. - * If it doesn't, fall back to hex, which is - * always exact. - */ - char buffer[25]; - sprintf(buffer, "%Lg", value); - assert(strlen(buffer) < sizeof(buffer)); -#if _WIN32 && __DMC__ - char *save = __locale_decpoint; - __locale_decpoint = "."; - real_t r = strtold(buffer, NULL); - __locale_decpoint = save; -#else - real_t r = strtold(buffer, NULL); -#endif - if (r == value) // if exact duplication - buf->writestring(buffer); - else - buf->printf("%La", value); // ensure exact duplication - - if (type) - { - Type *t = type->toBasetype(); - switch (t->ty) - { - case Tfloat32: - case Timaginary32: - case Tcomplex32: - buf->writeByte('F'); - break; - - case Tfloat80: - case Timaginary80: - case Tcomplex80: - buf->writeByte('L'); - break; - - default: - break; - } - if (t->isimaginary()) - buf->writeByte('i'); - } -} - -void RealExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - floatToBuffer(buf, type, value); -} - -void realToMangleBuffer(OutBuffer *buf, real_t value) -{ - /* Rely on %A to get portable mangling. - * Must munge result to get only identifier characters. - * - * Possible values from %A => mangled result - * NAN => NAN - * -INF => NINF - * INF => INF - * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 - * 0X1.9P+2 => 19P2 - */ - - if (isnan(value)) - buf->writestring("NAN"); // no -NAN bugs - else - { - char buffer[32]; - int n = sprintf(buffer, "%LA", value); - assert(n > 0 && n < sizeof(buffer)); - for (int i = 0; i < n; i++) - { char c = buffer[i]; - - switch (c) - { - case '-': - buf->writeByte('N'); - break; - - case '+': - case 'X': - case '.': - break; - - case '0': - if (i < 2) - break; // skip leading 0X - default: - buf->writeByte(c); - break; - } - } - } -} - -void RealExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('e'); - realToMangleBuffer(buf, value); -} - - -/******************************** ComplexExp **************************/ - -ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type) - : Expression(loc, TOKcomplex80, sizeof(ComplexExp)) -{ - this->value = value; - this->type = type; - //printf("ComplexExp::ComplexExp(%s)\n", toChars()); -} - -char *ComplexExp::toChars() -{ - char buffer[sizeof(value) * 3 + 8 + 1]; - -#ifdef IN_GCC - char buf1[sizeof(value) * 3 + 8 + 1]; - char buf2[sizeof(value) * 3 + 8 + 1]; - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); - sprintf(buffer, "(%s+%si)", buf1, buf2); -#else - sprintf(buffer, "(%Lg+%Lgi)", creall(value), cimagl(value)); - assert(strlen(buffer) < sizeof(buffer)); -#endif - return mem.strdup(buffer); -} - -integer_t ComplexExp::toInteger() -{ -#ifdef IN_GCC - return (sinteger_t) toReal().toInt(); -#else - return (sinteger_t) toReal(); -#endif -} - -uinteger_t ComplexExp::toUInteger() -{ -#ifdef IN_GCC - return (uinteger_t) toReal().toInt(); -#else - return (uinteger_t) toReal(); -#endif -} - -real_t ComplexExp::toReal() -{ - return creall(value); -} - -real_t ComplexExp::toImaginary() -{ - return cimagl(value); -} - -complex_t ComplexExp::toComplex() -{ - return value; -} - -int ComplexExp::equals(Object *o) -{ ComplexExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKcomplex80 && - ((ne = (ComplexExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - RealEquals(creall(value), creall(ne->value)) && - RealEquals(cimagl(value), cimagl(ne->value)) - ) - ) - return 1; - return 0; -} - -Expression *ComplexExp::semantic(Scope *sc) -{ - if (!type) - type = Type::tcomplex80; - else - type = type->semantic(loc, sc); - return this; -} - -int ComplexExp::isBool(int result) -{ - if (result) - return (bool)(value); - else - return !value; -} - -void ComplexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - /* Print as: - * (re+imi) - */ -#ifdef IN_GCC - char buf1[sizeof(value) * 3 + 8 + 1]; - char buf2[sizeof(value) * 3 + 8 + 1]; - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); - buf->printf("(%s+%si)", buf1, buf2); -#else - buf->writeByte('('); - floatToBuffer(buf, type, creall(value)); - buf->writeByte('+'); - floatToBuffer(buf, type, cimagl(value)); - buf->writestring("i)"); -#endif -} - -void ComplexExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('c'); - real_t r = toReal(); - realToMangleBuffer(buf, r); - buf->writeByte('c'); // separate the two - r = toImaginary(); - realToMangleBuffer(buf, r); -} - -/******************************** IdentifierExp **************************/ - -IdentifierExp::IdentifierExp(Loc loc, Identifier *ident) - : Expression(loc, TOKidentifier, sizeof(IdentifierExp)) -{ - this->ident = ident; -} - -Expression *IdentifierExp::semantic(Scope *sc) -{ - Dsymbol *s; - Dsymbol *scopesym; - -#if LOGSEMANTIC - printf("IdentifierExp::semantic('%s')\n", ident->toChars()); -#endif - s = sc->search(loc, ident, &scopesym); - if (s) - { Expression *e; - WithScopeSymbol *withsym; - - /* See if the symbol was a member of an enclosing 'with' - */ - withsym = scopesym->isWithScopeSymbol(); - if (withsym) - { - s = s->toAlias(); - - // Same as wthis.ident - if (s->needThis() || s->isTemplateDeclaration()) - { - e = new VarExp(loc, withsym->withstate->wthis); - e = new DotIdExp(loc, e, ident); - } - else - { Type *t = withsym->withstate->wthis->type; - if (t->ty == Tpointer) - t = ((TypePointer *)t)->next; - e = new TypeDotIdExp(loc, t, ident); - } - } - else - { - /* If f is really a function template, - * then replace f with the function template declaration. - */ - FuncDeclaration *f = s->isFuncDeclaration(); - if (f && f->parent) - { TemplateInstance *ti = f->parent->isTemplateInstance(); - - if (ti && - !ti->isTemplateMixin() && - (ti->name == f->ident || - ti->toAlias()->ident == f->ident) - && - ti->tempdecl && ti->tempdecl->onemember) - { - TemplateDeclaration *tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - e = new TemplateExp(loc, tempdecl); - e = e->semantic(sc); - return e; - } - } - // Haven't done overload resolution yet, so pass 1 - e = new DsymbolExp(loc, s, 1); - } - return e->semantic(sc); - } - error("undefined identifier %s", ident->toChars()); - type = Type::terror; - return this; -} - -char *IdentifierExp::toChars() -{ - return ident->toChars(); -} - -void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - buf->writestring(ident->toHChars2()); - else - buf->writestring(ident->toChars()); -} - -int IdentifierExp::isLvalue() -{ - return 1; -} - -Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - return this; -} - -/******************************** DollarExp **************************/ - -DollarExp::DollarExp(Loc loc) - : IdentifierExp(loc, Id::dollar) -{ -} - -/******************************** DsymbolExp **************************/ - -DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads) - : Expression(loc, TOKdsymbol, sizeof(DsymbolExp)) -{ - this->s = s; - this->hasOverloads = hasOverloads; -} - -Expression *DsymbolExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DsymbolExp::semantic('%s')\n", s->toChars()); -#endif - -Lagain: - EnumMember *em; - Expression *e; - VarDeclaration *v; - FuncDeclaration *f; - FuncLiteralDeclaration *fld; - OverloadSet *o; - Declaration *d; - ClassDeclaration *cd; - ClassDeclaration *thiscd = NULL; - Import *imp; - Package *pkg; - Type *t; - - //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); - //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind()); - if (type) - return this; - if (!s->isFuncDeclaration()) // functions are checked after overloading - checkDeprecated(sc, s); - s = s->toAlias(); - //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); - if (!s->isFuncDeclaration()) - checkDeprecated(sc, s); - - if (sc->func) - thiscd = sc->func->parent->isClassDeclaration(); - - // BUG: This should happen after overload resolution for functions, not before - if (s->needThis()) - { - if (hasThis(sc) && !s->isFuncDeclaration()) - { - // Supply an implicit 'this', as in - // this.ident - - DotVarExp *de; - - de = new DotVarExp(loc, new ThisExp(loc), s->isDeclaration()); - return de->semantic(sc); - } - } - - em = s->isEnumMember(); - if (em) - { - e = em->value; - e = e->semantic(sc); - return e; - } - v = s->isVarDeclaration(); - if (v) - { - //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); - if (!type) - { type = v->type; - if (!v->type) - { error("forward reference of %s", v->toChars()); - type = Type::terror; - } - } - e = new VarExp(loc, v); - e->type = type; - e = e->semantic(sc); - return e->deref(); - } - fld = s->isFuncLiteralDeclaration(); - if (fld) - { //printf("'%s' is a function literal\n", fld->toChars()); - e = new FuncExp(loc, fld); - return e->semantic(sc); - } - f = s->isFuncDeclaration(); - if (f) - { //printf("'%s' is a function\n", f->toChars()); - return new VarExp(loc, f, hasOverloads); - } - o = s->isOverloadSet(); - if (o) - { //printf("'%s' is an overload set\n", o->toChars()); - return new OverExp(o); - } - cd = s->isClassDeclaration(); - if (cd && thiscd && cd->isBaseOf(thiscd, NULL) && sc->func->needThis()) - { - // We need to add an implicit 'this' if cd is this class or a base class. - DotTypeExp *dte; - - dte = new DotTypeExp(loc, new ThisExp(loc), s); - return dte->semantic(sc); - } - imp = s->isImport(); - if (imp) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, imp->pkg); - return ie->semantic(sc); - } - pkg = s->isPackage(); - if (pkg) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, pkg); - return ie->semantic(sc); - } - Module *mod = s->isModule(); - if (mod) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, mod); - return ie->semantic(sc); - } - - t = s->getType(); - if (t) - { - return new TypeExp(loc, t); - } - - TupleDeclaration *tup = s->isTupleDeclaration(); - if (tup) - { - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti && !global.errors) - { if (!ti->semanticdone) - ti->semantic(sc); - s = ti->inst->toAlias(); - if (!s->isTemplateInstance()) - goto Lagain; - e = new ScopeExp(loc, ti); - e = e->semantic(sc); - return e; - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { - e = new TemplateExp(loc, td); - e = e->semantic(sc); - return e; - } - -Lerr: - error("%s '%s' is not a variable", s->kind(), s->toChars()); - type = Type::terror; - return this; -} - -char *DsymbolExp::toChars() -{ - return s->toChars(); -} - -void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(s->toChars()); -} - -int DsymbolExp::isLvalue() -{ - return 1; -} - -Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - return this; -} - -/******************************** ThisExp **************************/ - -ThisExp::ThisExp(Loc loc) - : Expression(loc, TOKthis, sizeof(ThisExp)) -{ - var = NULL; -} - -Expression *ThisExp::semantic(Scope *sc) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - int nested = 0; - -#if LOGSEMANTIC - printf("ThisExp::semantic()\n"); -#endif - if (type) - { //assert(global.errors || var); - return this; - } - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (sc->intypeof) - { - // Find enclosing struct or class - for (Dsymbol *s = sc->parent; 1; s = s->parent) - { - ClassDeclaration *cd; - StructDeclaration *sd; - - if (!s) - { - error("%s is not in a struct or class scope", toChars()); - goto Lerr; - } - cd = s->isClassDeclaration(); - if (cd) - { - type = cd->type; - return this; - } - sd = s->isStructDeclaration(); - if (sd) - { -#if STRUCTTHISREF - type = sd->type; -#else - type = sd->type->pointerTo(); -#endif - return this; - } - } - } - - fdthis = sc->parent->isFuncDeclaration(); - fd = hasThis(sc); // fd is the uplevel function with the 'this' variable - if (!fd) - goto Lerr; - - assert(fd->vthis); - var = fd->vthis; - assert(var->parent); - type = var->type; - var->isVarDeclaration()->checkNestedReference(sc, loc); - if (!sc->intypeof) - sc->callSuper |= CSXthis; - return this; - -Lerr: - error("'this' is only defined in non-static member functions, not %s", sc->parent->toChars()); - type = Type::terror; - return this; -} - -int ThisExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); -} - -int ThisExp::isLvalue() -{ - return 1; -} - -Expression *ThisExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -/******************************** SuperExp **************************/ - -SuperExp::SuperExp(Loc loc) - : ThisExp(loc) -{ - op = TOKsuper; -} - -Expression *SuperExp::semantic(Scope *sc) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - ClassDeclaration *cd; - Dsymbol *s; - -#if LOGSEMANTIC - printf("SuperExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (sc->intypeof) - { - // Find enclosing class - for (Dsymbol *s = sc->parent; 1; s = s->parent) - { - ClassDeclaration *cd; - - if (!s) - { - error("%s is not in a class scope", toChars()); - goto Lerr; - } - cd = s->isClassDeclaration(); - if (cd) - { - cd = cd->baseClass; - if (!cd) - { error("class %s has no 'super'", s->toChars()); - goto Lerr; - } - type = cd->type; - return this; - } - } - } - - fdthis = sc->parent->isFuncDeclaration(); - fd = hasThis(sc); - if (!fd) - goto Lerr; - assert(fd->vthis); - var = fd->vthis; - assert(var->parent); - - s = fd->toParent(); - while (s && s->isTemplateInstance()) - s = s->toParent(); - assert(s); - cd = s->isClassDeclaration(); -//printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars()); - if (!cd) - goto Lerr; - if (!cd->baseClass) - { - error("no base class for %s", cd->toChars()); - type = fd->vthis->type; - } - else - { - type = cd->baseClass->type; - } - - var->isVarDeclaration()->checkNestedReference(sc, loc); - - if (!sc->intypeof) - sc->callSuper |= CSXsuper; - return this; - - -Lerr: - error("'super' is only allowed in non-static class member functions"); - type = Type::tint32; - return this; -} - -void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("super"); -} - - -/******************************** NullExp **************************/ - -NullExp::NullExp(Loc loc) - : Expression(loc, TOKnull, sizeof(NullExp)) -{ - committed = 0; -} - -Expression *NullExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("NullExp::semantic('%s')\n", toChars()); -#endif - // NULL is the same as (void *)0 - if (!type) - type = Type::tvoid->pointerTo(); - return this; -} - -int NullExp::isBool(int result) -{ - return result ? FALSE : TRUE; -} - -void NullExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("null"); -} - -void NullExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('n'); -} - -/******************************** StringExp **************************/ - -StringExp::StringExp(Loc loc, char *string) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = strlen(string); - this->sz = 1; - this->committed = 0; - this->postfix = 0; -} - -StringExp::StringExp(Loc loc, void *string, size_t len) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = len; - this->sz = 1; - this->committed = 0; - this->postfix = 0; -} - -StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = len; - this->sz = 1; - this->committed = 0; - this->postfix = postfix; -} - -#if 0 -Expression *StringExp::syntaxCopy() -{ - printf("StringExp::syntaxCopy() %s\n", toChars()); - return copy(); -} -#endif - -int StringExp::equals(Object *o) -{ - //printf("StringExp::equals('%s')\n", o->toChars()); - if (o && o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - - if (e->op == TOKstring) - { - return compare(o) == 0; - } - } - return FALSE; -} - -char *StringExp::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *p; - - memset(&hgs, 0, sizeof(hgs)); - toCBuffer(&buf, &hgs); - buf.writeByte(0); - p = (char *)buf.data; - buf.data = NULL; - return p; -} - -Expression *StringExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("StringExp::semantic() %s\n", toChars()); -#endif - if (!type) - { OutBuffer buffer; - size_t newlen = 0; - const char *p; - size_t u; - unsigned c; - - switch (postfix) - { - case 'd': - for (u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - break; - } - else - { buffer.write4(c); - newlen++; - } - } - buffer.write4(0); - string = buffer.extractData(); - len = newlen; - sz = 4; - type = new TypeSArray(Type::tdchar, new IntegerExp(loc, len, Type::tindex)); - committed = 1; - break; - - case 'w': - for (u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - break; - } - else - { buffer.writeUTF16(c); - newlen++; - if (c >= 0x10000) - newlen++; - } - } - buffer.writeUTF16(0); - string = buffer.extractData(); - len = newlen; - sz = 2; - type = new TypeSArray(Type::twchar, new IntegerExp(loc, len, Type::tindex)); - committed = 1; - break; - - case 'c': - committed = 1; - default: - type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex)); - break; - } - type = type->semantic(loc, sc); - type = type->invariantOf(); - //printf("type = %s\n", type->toChars()); - } - return this; -} - -/**************************************** - * Convert string to char[]. - */ - -StringExp *StringExp::toUTF8(Scope *sc) -{ - if (sz != 1) - { // Convert to UTF-8 string - committed = 0; - Expression *e = castTo(sc, Type::tchar->arrayOf()); - e = e->optimize(WANTvalue); - assert(e->op == TOKstring); - StringExp *se = (StringExp *)e; - assert(se->sz == 1); - return se; - } - return this; -} - -int StringExp::compare(Object *obj) -{ - // Used to sort case statement expressions so we can do an efficient lookup - StringExp *se2 = (StringExp *)(obj); - - // This is a kludge so isExpression() in template.c will return 5 - // for StringExp's. - if (!se2) - return 5; - - assert(se2->op == TOKstring); - - int len1 = len; - int len2 = se2->len; - - if (len1 == len2) - { - switch (sz) - { - case 1: - return strcmp((char *)string, (char *)se2->string); - - case 2: - { unsigned u; - d_wchar *s1 = (d_wchar *)string; - d_wchar *s2 = (d_wchar *)se2->string; - - for (u = 0; u < len; u++) - { - if (s1[u] != s2[u]) - return s1[u] - s2[u]; - } - } - - case 4: - { unsigned u; - d_dchar *s1 = (d_dchar *)string; - d_dchar *s2 = (d_dchar *)se2->string; - - for (u = 0; u < len; u++) - { - if (s1[u] != s2[u]) - return s1[u] - s2[u]; - } - } - break; - - default: - assert(0); - } - } - return len1 - len2; -} - -int StringExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -unsigned StringExp::charAt(size_t i) -{ unsigned value; - - switch (sz) - { - case 1: - value = ((unsigned char *)string)[i]; - break; - - case 2: - value = ((unsigned short *)string)[i]; - break; - - case 4: - value = ((unsigned int *)string)[i]; - break; - - default: - assert(0); - break; - } - return value; -} - -void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('"'); - for (size_t i = 0; i < len; i++) - { unsigned c = charAt(i); - - switch (c) - { - case '"': - case '\\': - if (!hgs->console) - buf->writeByte('\\'); - default: - if (c <= 0xFF) - { if (c <= 0x7F && (isprint(c) || hgs->console)) - buf->writeByte(c); - else - buf->printf("\\x%02x", c); - } - else if (c <= 0xFFFF) - buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); - else - buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x", - c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); - break; - } - } - buf->writeByte('"'); - if (postfix) - buf->writeByte(postfix); -} - -void StringExp::toMangleBuffer(OutBuffer *buf) -{ char m; - OutBuffer tmp; - const char *p; - unsigned c; - size_t u; - unsigned char *q; - unsigned qlen; - - /* Write string in UTF-8 format - */ - switch (sz) - { case 1: - m = 'a'; - q = (unsigned char *)string; - qlen = len; - break; - case 2: - m = 'w'; - for (u = 0; u < len; ) - { - p = utf_decodeWchar((unsigned short *)string, len, &u, &c); - if (p) - error("%s", p); - else - tmp.writeUTF8(c); - } - q = tmp.data; - qlen = tmp.offset; - break; - case 4: - m = 'd'; - for (u = 0; u < len; u++) - { - c = ((unsigned *)string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - tmp.writeUTF8(c); - } - q = tmp.data; - qlen = tmp.offset; - break; - default: - assert(0); - } - buf->writeByte(m); - buf->printf("%d_", qlen); - for (size_t i = 0; i < qlen; i++) - buf->printf("%02x", q[i]); -} - -/************************ ArrayLiteralExp ************************************/ - -// [ e1, e2, e3, ... ] - -ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) - : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) -{ - this->elements = elements; -} - -ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) - : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) -{ - elements = new Expressions; - elements->push(e); -} - -Expression *ArrayLiteralExp::syntaxCopy() -{ - return new ArrayLiteralExp(loc, arraySyntaxCopy(elements)); -} - -Expression *ArrayLiteralExp::semantic(Scope *sc) -{ Expression *e; - Type *t0 = NULL; - -#if LOGSEMANTIC - printf("ArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each element - for (int i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - e = e->semantic(sc); - elements->data[i] = (void *)e; - } - expandTuples(elements); - for (int i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - - if (!e->type) - error("%s has no value", e->toChars()); - e = resolveProperties(sc, e); - - unsigned char committed = 1; - if (e->op == TOKstring) - committed = ((StringExp *)e)->committed; - - if (!t0) - { t0 = e->type; - // Convert any static arrays to dynamic arrays - if (t0->ty == Tsarray) - { - t0 = ((TypeSArray *)t0)->next->arrayOf(); - e = e->implicitCastTo(sc, t0); - } - } - else - e = e->implicitCastTo(sc, t0); - if (!committed && e->op == TOKstring) - { StringExp *se = (StringExp *)e; - se->committed = 0; - } - elements->data[i] = (void *)e; - } - - if (!t0) - t0 = Type::tvoid; - type = new TypeSArray(t0, new IntegerExp(elements->dim)); - type = type->semantic(loc, sc); - return this; -} - -int ArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int ArrayLiteralExp::isBool(int result) -{ - size_t dim = elements ? elements->dim : 0; - return result ? (dim != 0) : (dim == 0); -} - -int ArrayLiteralExp::canThrow() -{ - return 1; // because it can fail allocating memory -} - -void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - argsToCBuffer(buf, elements, hgs); - buf->writeByte(']'); -} - -void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = elements ? elements->dim : 0; - buf->printf("A%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = (Expression *)elements->data[i]; - e->toMangleBuffer(buf); - } -} - -/************************ AssocArrayLiteralExp ************************************/ - -// [ key0 : value0, key1 : value1, ... ] - -AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc, - Expressions *keys, Expressions *values) - : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp)) -{ - assert(keys->dim == values->dim); - this->keys = keys; - this->values = values; -} - -Expression *AssocArrayLiteralExp::syntaxCopy() -{ - return new AssocArrayLiteralExp(loc, - arraySyntaxCopy(keys), arraySyntaxCopy(values)); -} - -Expression *AssocArrayLiteralExp::semantic(Scope *sc) -{ Expression *e; - Type *tkey = NULL; - Type *tvalue = NULL; - -#if LOGSEMANTIC - printf("AssocArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - - // Run semantic() on each element - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - key = key->semantic(sc); - value = value->semantic(sc); - - keys->data[i] = (void *)key; - values->data[i] = (void *)value; - } - expandTuples(keys); - expandTuples(values); - if (keys->dim != values->dim) - { - error("number of keys is %u, must match number of values %u", keys->dim, values->dim); - keys->setDim(0); - values->setDim(0); - } - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - if (!key->type) - error("%s has no value", key->toChars()); - if (!value->type) - error("%s has no value", value->toChars()); - key = resolveProperties(sc, key); - value = resolveProperties(sc, value); - - if (!tkey) - tkey = key->type; - else - key = key->implicitCastTo(sc, tkey); - keys->data[i] = (void *)key; - - if (!tvalue) - tvalue = value->type; - else - value = value->implicitCastTo(sc, tvalue); - values->data[i] = (void *)value; - } - - if (!tkey) - tkey = Type::tvoid; - if (!tvalue) - tvalue = Type::tvoid; - type = new TypeAArray(tvalue, tkey); - type = type->semantic(loc, sc); - return this; -} - -int AssocArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - f |= key->checkSideEffect(2); - f |= value->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int AssocArrayLiteralExp::isBool(int result) -{ - size_t dim = keys->dim; - return result ? (dim != 0) : (dim == 0); -} - -int AssocArrayLiteralExp::canThrow() -{ - return 1; -} - -void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - if (i) - buf->writeByte(','); - expToCBuffer(buf, hgs, key, PREC_assign); - buf->writeByte(':'); - expToCBuffer(buf, hgs, value, PREC_assign); - } - buf->writeByte(']'); -} - -void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = keys->dim; - buf->printf("A%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - key->toMangleBuffer(buf); - value->toMangleBuffer(buf); - } -} - -/************************ StructLiteralExp ************************************/ - -// sd( e1, e2, e3, ... ) - -StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements) - : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp)) -{ - this->sd = sd; - this->elements = elements; - this->sym = NULL; - this->soffset = 0; - this->fillHoles = 1; -} - -Expression *StructLiteralExp::syntaxCopy() -{ - return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements)); -} - -Expression *StructLiteralExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("StructLiteralExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each element - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - if (!e) - continue; - e = e->semantic(sc); - elements->data[i] = (void *)e; - } - expandTuples(elements); - size_t offset = 0; - for (size_t i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - if (!e) - continue; - - if (!e->type) - error("%s has no value", e->toChars()); - e = resolveProperties(sc, e); - if (i >= sd->fields.dim) - { error("more initializers than fields of %s", sd->toChars()); - break; - } - Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - if (v->offset < offset) - error("overlapping initialization for %s", v->toChars()); - offset = v->offset + v->type->size(); - - Type *telem = v->type; - while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray) - { /* Static array initialization, as in: - * T[3][5] = e; - */ - telem = telem->toBasetype()->nextOf(); - } - - e = e->implicitCastTo(sc, telem); - - elements->data[i] = (void *)e; - } - - /* Fill out remainder of elements[] with default initializers for fields[] - */ - for (size_t i = elements->dim; i < sd->fields.dim; i++) - { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - if (v->offset < offset) - { e = NULL; - sd->hasUnions = 1; - } - else - { - if (v->init) - { e = v->init->toExpression(); - if (!e) - error("cannot make expression out of initializer for %s", v->toChars()); - } - else - { e = v->type->defaultInit(); - e->loc = loc; - } - offset = v->offset + v->type->size(); - } - elements->push(e); - } - - type = sd->type; - return this; -} - -/************************************** - * Gets expression at offset of type. - * Returns NULL if not found. - */ - -Expression *StructLiteralExp::getField(Type *type, unsigned offset) -{ - //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n", -// /*toChars()*/"", type->toChars(), offset); - Expression *e = NULL; - int i = getFieldIndex(type, offset); - - if (i != -1) - { - //printf("\ti = %d\n", i); - assert(i < elements->dim); - e = (Expression *)elements->data[i]; - if (e) - { - e = e->copy(); - e->type = type; - } - } - return e; -} - -/************************************ - * Get index of field. - * Returns -1 if not found. - */ - -int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) -{ - /* Find which field offset is by looking at the field offsets - */ - for (size_t i = 0; i < sd->fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - if (offset == v->offset && - type->size() == v->type->size()) - { Expression *e = (Expression *)elements->data[i]; - if (e) - { - return i; - } - break; - } - } - return -1; -} - -int StructLiteralExp::isLvalue() -{ - return 1; -} - -Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - - -int StructLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (!e) - continue; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int StructLiteralExp::canThrow() -{ - return arrayExpressionCanThrow(elements); -} - -void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(sd->toChars()); - buf->writeByte('('); - argsToCBuffer(buf, elements, hgs); - buf->writeByte(')'); -} - -void StructLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = elements ? elements->dim : 0; - buf->printf("S%u", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (e) - e->toMangleBuffer(buf); - else - buf->writeByte('v'); // 'v' for void - } -} - -/************************ TypeDotIdExp ************************************/ - -/* Things like: - * int.size - * foo.size - * (foo).size - * cast(foo).size - */ - -TypeDotIdExp::TypeDotIdExp(Loc loc, Type *type, Identifier *ident) - : Expression(loc, TOKtypedot, sizeof(TypeDotIdExp)) -{ - this->type = type; - this->ident = ident; -} - -Expression *TypeDotIdExp::syntaxCopy() -{ - TypeDotIdExp *te = new TypeDotIdExp(loc, type->syntaxCopy(), ident); - return te; -} - -Expression *TypeDotIdExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("TypeDotIdExp::semantic()\n"); -#endif - e = new DotIdExp(loc, new TypeExp(loc, type), ident); - e = e->semantic(sc); - return e; -} - -void TypeDotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('('); - type->toCBuffer(buf, NULL, hgs); - buf->writeByte(')'); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -/************************************************************/ - -// Mainly just a placeholder - -TypeExp::TypeExp(Loc loc, Type *type) - : Expression(loc, TOKtype, sizeof(TypeExp)) -{ - //printf("TypeExp::TypeExp(%s)\n", type->toChars()); - this->type = type; -} - -Expression *TypeExp::semantic(Scope *sc) -{ - //printf("TypeExp::semantic(%s)\n", type->toChars()); - type = type->semantic(loc, sc); - return this; -} - -void TypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - type->toCBuffer(buf, NULL, hgs); -} - -/************************************************************/ - -// Mainly just a placeholder - -ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *pkg) - : Expression(loc, TOKimport, sizeof(ScopeExp)) -{ - //printf("ScopeExp::ScopeExp(pkg = '%s')\n", pkg->toChars()); - //static int count; if (++count == 38) *(char*)0=0; - this->sds = pkg; -} - -Expression *ScopeExp::syntaxCopy() -{ - ScopeExp *se = new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL)); - return se; -} - -Expression *ScopeExp::semantic(Scope *sc) -{ - TemplateInstance *ti; - ScopeDsymbol *sds2; - -#if LOGSEMANTIC - printf("+ScopeExp::semantic('%s')\n", toChars()); -#endif -Lagain: - ti = sds->isTemplateInstance(); - if (ti && !global.errors) - { Dsymbol *s; - if (!ti->semanticdone) - ti->semantic(sc); - s = ti->inst->toAlias(); - sds2 = s->isScopeDsymbol(); - if (!sds2) - { Expression *e; - - //printf("s = %s, '%s'\n", s->kind(), s->toChars()); - if (ti->withsym) - { - // Same as wthis.s - e = new VarExp(loc, ti->withsym->withstate->wthis); - e = new DotVarExp(loc, e, s->isDeclaration()); - } - else - e = new DsymbolExp(loc, s); - e = e->semantic(sc); - //printf("-1ScopeExp::semantic()\n"); - return e; - } - if (sds2 != sds) - { - sds = sds2; - goto Lagain; - } - //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); - } - else - { - //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); - //printf("\tparent = '%s'\n", sds->parent->toChars()); - sds->semantic(sc); - } - type = Type::tvoid; - //printf("-2ScopeExp::semantic() %s\n", toChars()); - return this; -} - -void ScopeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (sds->isTemplateInstance()) - { - sds->toCBuffer(buf, hgs); - } - else - { - buf->writestring(sds->kind()); - buf->writestring(" "); - buf->writestring(sds->toChars()); - } -} - -/********************** TemplateExp **************************************/ - -// Mainly just a placeholder - -TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td) - : Expression(loc, TOKtemplate, sizeof(TemplateExp)) -{ - //printf("TemplateExp(): %s\n", td->toChars()); - this->td = td; -} - -void TemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(td->toChars()); -} - -void TemplateExp::rvalue() -{ - error("template %s has no value", toChars()); -} - -/********************** NewExp **************************************/ - -/* thisexp.new(newargs) newtype(arguments) */ - -NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs, - Type *newtype, Expressions *arguments) - : Expression(loc, TOKnew, sizeof(NewExp)) -{ - this->thisexp = thisexp; - this->newargs = newargs; - this->newtype = newtype; - this->arguments = arguments; - member = NULL; - allocator = NULL; - onstack = 0; -} - -Expression *NewExp::syntaxCopy() -{ - return new NewExp(loc, - thisexp ? thisexp->syntaxCopy() : NULL, - arraySyntaxCopy(newargs), - newtype->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *NewExp::semantic(Scope *sc) -{ int i; - Type *tb; - ClassDeclaration *cdthis = NULL; - -#if LOGSEMANTIC - printf("NewExp::semantic() %s\n", toChars()); - if (thisexp) - printf("\tthisexp = %s\n", thisexp->toChars()); - printf("\tnewtype: %s\n", newtype->toChars()); -#endif - if (type) // if semantic() already run - return this; - -Lagain: - if (thisexp) - { thisexp = thisexp->semantic(sc); - cdthis = thisexp->type->isClassHandle(); - if (cdthis) - { - sc = sc->push(cdthis); - type = newtype->semantic(loc, sc); - sc = sc->pop(); - } - else - { - error("'this' for nested class must be a class type, not %s", thisexp->type->toChars()); - type = newtype->semantic(loc, sc); - } - } - else - type = newtype->semantic(loc, sc); - newtype = type; // in case type gets cast to something else - tb = type->toBasetype(); - //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco); - - arrayExpressionSemantic(newargs, sc); - preFunctionArguments(loc, sc, newargs); - arrayExpressionSemantic(arguments, sc); - preFunctionArguments(loc, sc, arguments); - - if (thisexp && tb->ty != Tclass) - error("e.new is only for allocating nested classes, not %s", tb->toChars()); - - if (tb->ty == Tclass) - { TypeFunction *tf; - - TypeClass *tc = (TypeClass *)(tb); - ClassDeclaration *cd = tc->sym->isClassDeclaration(); - if (cd->isInterfaceDeclaration()) - error("cannot create instance of interface %s", cd->toChars()); - else if (cd->isAbstract()) - { error("cannot create instance of abstract class %s", cd->toChars()); - for (int i = 0; i < cd->vtbl.dim; i++) - { FuncDeclaration *fd = ((Dsymbol *)cd->vtbl.data[i])->isFuncDeclaration(); - if (fd && fd->isAbstract()) - error("function %s is abstract", fd->toChars()); - } - } - checkDeprecated(sc, cd); - if (cd->isNested()) - { /* We need a 'this' pointer for the nested class. - * Ensure we have the right one. - */ - Dsymbol *s = cd->toParent2(); - ClassDeclaration *cdn = s->isClassDeclaration(); - FuncDeclaration *fdn = s->isFuncDeclaration(); - - //printf("cd isNested, cdn = %s\n", cdn ? cdn->toChars() : "null"); - if (cdn) - { - if (!cdthis) - { - // Supply an implicit 'this' and try again - thisexp = new ThisExp(loc); - for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) - { if (!sp) - { - error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - break; - } - ClassDeclaration *cdp = sp->isClassDeclaration(); - if (!cdp) - continue; - if (cdp == cdn || cdn->isBaseOf(cdp, NULL)) - break; - // Add a '.outer' and try again - thisexp = new DotIdExp(loc, thisexp, Id::outer); - } - if (!global.errors) - goto Lagain; - } - if (cdthis) - { - //printf("cdthis = %s\n", cdthis->toChars()); - if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL)) - error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars()); - } -#if 0 - else - { - for (Dsymbol *sf = sc->func; 1; sf= sf->toParent2()->isFuncDeclaration()) - { - if (!sf) - { - error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - break; - } - printf("sf = %s\n", sf->toChars()); - AggregateDeclaration *ad = sf->isThis(); - if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL))) - break; - } - } -#endif - } - // LDC , check if reachable - else if (fdn) - { - // make sure the parent context fdn of cd is reachable from sc - for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) - { - if (fdn == sp) - break; - FuncDeclaration *fsp = sp ? sp->isFuncDeclaration() : NULL; - if (!sp || (fsp && fsp->isStatic())) - { - error("outer function context of %s is needed to 'new' nested class %s", fdn->toPrettyChars(), cd->toPrettyChars()); - break; - } - } - - } - else - assert(0); - } - else if (thisexp) - error("e.new is only for allocating nested classes"); - - FuncDeclaration *f = cd->ctor; - if (f) - { - assert(f); - f = f->overloadResolve(loc, NULL, arguments); - checkDeprecated(sc, f); - member = f->isCtorDeclaration(); - assert(member); - - cd->accessCheck(loc, sc, member); - - tf = (TypeFunction *)f->type; -// type = tf->next; - - if (!arguments) - arguments = new Expressions(); - functionArguments(loc, sc, tf, arguments); - } - else - { - if (arguments && arguments->dim) - error("no constructor for %s", cd->toChars()); - } - - if (cd->aggNew) - { - // Prepend the size_t size argument to newargs[] - Expression *e = new IntegerExp(loc, cd->size(loc), Type::tsize_t); - if (!newargs) - newargs = new Expressions(); - newargs->shift(e); - - f = cd->aggNew->overloadResolve(loc, NULL, newargs); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - functionArguments(loc, sc, tf, newargs); - } - else - { - if (newargs && newargs->dim) - error("no allocator for %s", cd->toChars()); - } - } - else if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - TypeFunction *tf; - - FuncDeclaration *f = sd->ctor; - if (f && arguments && arguments->dim) - { - assert(f); - f = f->overloadResolve(loc, NULL, arguments); - checkDeprecated(sc, f); - member = f->isCtorDeclaration(); - assert(member); - - sd->accessCheck(loc, sc, member); - - tf = (TypeFunction *)f->type; -// type = tf->next; - - if (!arguments) - arguments = new Expressions(); - functionArguments(loc, sc, tf, arguments); - } - else - { - if (arguments && arguments->dim) - error("no constructor for %s", sd->toChars()); - } - - - if (sd->aggNew) - { - // Prepend the uint size argument to newargs[] - Expression *e = new IntegerExp(loc, sd->size(loc), Type::tuns32); - if (!newargs) - newargs = new Expressions(); - newargs->shift(e); - - f = sd->aggNew->overloadResolve(loc, NULL, newargs); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - functionArguments(loc, sc, tf, newargs); -#if 0 - e = new VarExp(loc, f); - e = new CallExp(loc, e, newargs); - e = e->semantic(sc); - e->type = type->pointerTo(); - return e; -#endif - } - else - { - if (newargs && newargs->dim) - error("no allocator for %s", sd->toChars()); - } - - type = type->pointerTo(); - } - else if (tb->ty == Tarray && (arguments && arguments->dim)) - { - for (size_t i = 0; i < arguments->dim; i++) - { - if (tb->ty != Tarray) - { error("too many arguments for array"); - arguments->dim = i; - break; - } - - Expression *arg = (Expression *)arguments->data[i]; - arg = resolveProperties(sc, arg); - arg = arg->implicitCastTo(sc, Type::tsize_t); - arg = arg->optimize(WANTvalue); - if (arg->op == TOKint64 && (long long)arg->toInteger() < 0) - error("negative array index %s", arg->toChars()); - arguments->data[i] = (void *) arg; - tb = ((TypeDArray *)tb)->next->toBasetype(); - } - } - else if (tb->isscalar()) - { - if (arguments && arguments->dim) - error("no constructor for %s", type->toChars()); - - type = type->pointerTo(); - } - else - { - error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars()); - type = type->pointerTo(); - } - -//printf("NewExp: '%s'\n", toChars()); -//printf("NewExp:type '%s'\n", type->toChars()); - - return this; -} - -int NewExp::checkSideEffect(int flag) -{ - return 1; -} - -int NewExp::canThrow() -{ - return 1; -} - -void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - if (thisexp) - { expToCBuffer(buf, hgs, thisexp, PREC_primary); - buf->writeByte('.'); - } - buf->writestring("new "); - if (newargs && newargs->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, newargs, hgs); - buf->writeByte(')'); - } - newtype->toCBuffer(buf, NULL, hgs); - if (arguments && arguments->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); - } -} - -/********************** NewAnonClassExp **************************************/ - -NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp, - Expressions *newargs, ClassDeclaration *cd, Expressions *arguments) - : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp)) -{ - this->thisexp = thisexp; - this->newargs = newargs; - this->cd = cd; - this->arguments = arguments; -} - -Expression *NewAnonClassExp::syntaxCopy() -{ - return new NewAnonClassExp(loc, - thisexp ? thisexp->syntaxCopy() : NULL, - arraySyntaxCopy(newargs), - (ClassDeclaration *)cd->syntaxCopy(NULL), - arraySyntaxCopy(arguments)); -} - - -Expression *NewAnonClassExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("NewAnonClassExp::semantic() %s\n", toChars()); - //printf("thisexp = %p\n", thisexp); - //printf("type: %s\n", type->toChars()); -#endif - - Expression *d = new DeclarationExp(loc, cd); - d = d->semantic(sc); - - Expression *n = new NewExp(loc, thisexp, newargs, cd->type, arguments); - - Expression *c = new CommaExp(loc, d, n); - return c->semantic(sc); -} - -int NewAnonClassExp::checkSideEffect(int flag) -{ - return 1; -} - -int NewAnonClassExp::canThrow() -{ - return 1; -} - -void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - if (thisexp) - { expToCBuffer(buf, hgs, thisexp, PREC_primary); - buf->writeByte('.'); - } - buf->writestring("new"); - if (newargs && newargs->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, newargs, hgs); - buf->writeByte(')'); - } - buf->writestring(" class "); - if (arguments && arguments->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); - } - //buf->writestring(" { }"); - if (cd) - { - cd->toCBuffer(buf, hgs); - } -} - -/********************** SymbolExp **************************************/ - -SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads) - : Expression(loc, op, size) -{ - assert(var); - this->var = var; - this->hasOverloads = hasOverloads; -} - -/********************** SymOffExp **************************************/ - -SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads) - : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var, hasOverloads) -{ - this->offset = offset; - - VarDeclaration *v = var->isVarDeclaration(); - if (v && v->needThis()) - error("need 'this' for address of %s", v->toChars()); -} - -Expression *SymOffExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("SymOffExp::semantic('%s')\n", toChars()); -#endif - //var->semantic(sc); - if (!type) - type = var->type->pointerTo(); - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - v->checkNestedReference(sc, loc); - } - return this; -} - -int SymOffExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -void SymOffExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg()) - error("escaping reference to local variable %s", v->toChars()); - } -} - -void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (offset) - buf->printf("(& %s+%u)", var->toChars(), offset); - else - buf->printf("& %s", var->toChars()); -} - -/******************************** VarExp **************************/ - -VarExp::VarExp(Loc loc, Declaration *var, int hasOverloads) - : SymbolExp(loc, TOKvar, sizeof(VarExp), var, hasOverloads) -{ - //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars()); - //if (strcmp(var->ident->toChars(), "func") == 0) halt(); - this->type = var->type; -} - -int VarExp::equals(Object *o) -{ VarExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKvar && - ((ne = (VarExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - var == ne->var)) - return 1; - return 0; -} - -Expression *VarExp::semantic(Scope *sc) -{ FuncLiteralDeclaration *fd; - -#if LOGSEMANTIC - printf("VarExp::semantic(%s)\n", toChars()); -#endif - if (!type) - { type = var->type; -#if 0 - if (var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd); - type = new TypeDelegate(tf); - type = type->semantic(loc, sc); - } -#endif - } - - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { -#if 0 - if ((v->isConst() || v->isInvariant()) && - type->toBasetype()->ty != Tsarray && v->init) - { - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - //ei->exp->implicitCastTo(sc, type)->print(); - return ei->exp->implicitCastTo(sc, type); - } - } -#endif - v->checkNestedReference(sc, loc); - } -#if 0 - else if ((fd = var->isFuncLiteralDeclaration()) != NULL) - { Expression *e; - e = new FuncExp(loc, fd); - e->type = type; - return e; - } -#endif - return this; -} - -char *VarExp::toChars() -{ - return var->toChars(); -} - -void VarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(var->toChars()); -} - -void VarExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { Type *tb = v->type->toBasetype(); - // if reference type - if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass) - { - if ((v->isAuto() || v->isScope()) && !v->noauto) - error("escaping reference to auto local %s", v->toChars()); - else if (v->storage_class & STCvariadic) - error("escaping reference to variadic parameter %s", v->toChars()); - } - } -} - -int VarExp::isLvalue() -{ - if (var->storage_class & STClazy) - return 0; - return 1; -} - -Expression *VarExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - if (var->storage_class & STClazy) - error("lazy variables cannot be lvalues"); - return this; -} - -Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("VarExp::modifiableLvalue('%s')\n", var->toChars()); - if (type && type->toBasetype()->ty == Tsarray) - error("cannot change reference to static array '%s'", var->toChars()); - - var->checkModify(loc, sc, type); - - // See if this expression is a modifiable lvalue (i.e. not const) - return toLvalue(sc, e); -} - - -/******************************** OverExp **************************/ - -#if DMDV2 -OverExp::OverExp(OverloadSet *s) - : Expression(loc, TOKoverloadset, sizeof(OverExp)) -{ - //printf("OverExp(this = %p, '%s')\n", this, var->toChars()); - vars = s; - type = Type::tvoid; -} - -int OverExp::isLvalue() -{ - return 1; -} - -Expression *OverExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} -#endif - - -/******************************** TupleExp **************************/ - -TupleExp::TupleExp(Loc loc, Expressions *exps) - : Expression(loc, TOKtuple, sizeof(TupleExp)) -{ - //printf("TupleExp(this = %p)\n", this); - this->exps = exps; - this->type = NULL; -} - - -TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) - : Expression(loc, TOKtuple, sizeof(TupleExp)) -{ - exps = new Expressions(); - type = NULL; - - exps->reserve(tup->objects->dim); - for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = (Object *)tup->objects->data[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { - Expression *e = (Expression *)o; - e = e->syntaxCopy(); - exps->push(e); - } - else if (o->dyncast() == DYNCAST_DSYMBOL) - { - Dsymbol *s = (Dsymbol *)o; - Expression *e = new DsymbolExp(loc, s); - exps->push(e); - } - else if (o->dyncast() == DYNCAST_TYPE) - { - Type *t = (Type *)o; - Expression *e = new TypeExp(loc, t); - exps->push(e); - } - else - { - error("%s is not an expression", o->toChars()); - } - } -} - -int TupleExp::equals(Object *o) -{ TupleExp *ne; - - if (this == o) - return 1; - if (((Expression *)o)->op == TOKtuple) - { - TupleExp *te = (TupleExp *)o; - if (exps->dim != te->exps->dim) - return 0; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e1 = (Expression *)exps->data[i]; - Expression *e2 = (Expression *)te->exps->data[i]; - - if (!e1->equals(e2)) - return 0; - } - return 1; - } - return 0; -} - -Expression *TupleExp::syntaxCopy() -{ - return new TupleExp(loc, arraySyntaxCopy(exps)); -} - -Expression *TupleExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("+TupleExp::semantic(%s)\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each argument - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->semantic(sc); - if (!e->type) - { error("%s has no value", e->toChars()); - e->type = Type::terror; - } - exps->data[i] = (void *)e; - } - - expandTuples(exps); - if (0 && exps->dim == 1) - { - return (Expression *)exps->data[0]; - } - type = new TypeTuple(exps); - //printf("-TupleExp::semantic(%s)\n", toChars()); - return this; -} - -void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("tuple("); - argsToCBuffer(buf, exps, hgs); - buf->writeByte(')'); -} - -int TupleExp::checkSideEffect(int flag) -{ int f = 0; - - for (int i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -int TupleExp::canThrow() -{ - return arrayExpressionCanThrow(exps); -} - -void TupleExp::checkEscape() -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - e->checkEscape(); - } -} - -/******************************** FuncExp *********************************/ - -FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd) - : Expression(loc, TOKfunction, sizeof(FuncExp)) -{ - this->fd = fd; -} - -Expression *FuncExp::syntaxCopy() -{ - return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); -} - -Expression *FuncExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("FuncExp::semantic(%s)\n", toChars()); -#endif - if (!type) - { - fd->semantic(sc); - fd->parent = sc->parent; - if (global.errors) - { - } - else - { - fd->semantic2(sc); - if (!global.errors) - { - fd->semantic3(sc); - - if (!global.errors && global.params.useInline) - fd->inlineScan(); - } - } - - // Type is a "delegate to" or "pointer to" the function literal - if (fd->isNested()) - { - type = new TypeDelegate(fd->type); - type = type->semantic(loc, sc); - } - else - { - type = fd->type->pointerTo(); - } - fd->tookAddressOf++; - } - return this; -} - -char *FuncExp::toChars() -{ - return fd->toChars(); -} - -void FuncExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(fd->toChars()); -} - - -/******************************** DeclarationExp **************************/ - -DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration) - : Expression(loc, TOKdeclaration, sizeof(DeclarationExp)) -{ - this->declaration = declaration; -} - -Expression *DeclarationExp::syntaxCopy() -{ - return new DeclarationExp(loc, declaration->syntaxCopy(NULL)); -} - -Expression *DeclarationExp::semantic(Scope *sc) -{ - if (type) - return this; - -#if LOGSEMANTIC - printf("DeclarationExp::semantic() %s\n", toChars()); -#endif - - /* This is here to support extern(linkage) declaration, - * where the extern(linkage) winds up being an AttribDeclaration - * wrapper. - */ - Dsymbol *s = declaration; - - AttribDeclaration *ad = declaration->isAttribDeclaration(); - if (ad) - { - if (ad->decl && ad->decl->dim == 1) - s = (Dsymbol *)ad->decl->data[0]; - } - - if (s->isVarDeclaration()) - { // Do semantic() on initializer first, so: - // int a = a; - // will be illegal. - declaration->semantic(sc); - s->parent = sc->parent; - } - - //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc); - // Insert into both local scope and function scope. - // Must be unique in both. - if (s->ident) - { - if (!sc->insert(s)) - error("declaration %s is already defined", s->toPrettyChars()); - else if (sc->func) - { VarDeclaration *v = s->isVarDeclaration(); - if (s->isFuncDeclaration() && - !sc->func->localsymtab->insert(s)) - error("declaration %s is already defined in another scope in %s", s->toPrettyChars(), sc->func->toChars()); - else if (!global.params.useDeprecated) - { // Disallow shadowing - - for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing) - { Dsymbol *s2; - - if (scx->scopesym && scx->scopesym->symtab && - (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && - s != s2) - { - error("shadowing declaration %s is deprecated", s->toPrettyChars()); - } - } - } - } - } - if (!s->isVarDeclaration()) - { - declaration->semantic(sc); - s->parent = sc->parent; - } - if (!global.errors) - { - declaration->semantic2(sc); - if (!global.errors) - { - declaration->semantic3(sc); - - if (!global.errors && global.params.useInline) - declaration->inlineScan(); - } - } - - type = Type::tvoid; - return this; -} - -int DeclarationExp::checkSideEffect(int flag) -{ - return 1; -} - -int DeclarationExp::canThrow() -{ - VarDeclaration *v = declaration->isVarDeclaration(); - if (v && v->init) - { ExpInitializer *ie = v->init->isExpInitializer(); - return ie && ie->exp->canThrow(); - } - return 0; -} - -void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - declaration->toCBuffer(buf, hgs); -} - - -/************************ TypeidExp ************************************/ - -/* - * typeid(int) - */ - -TypeidExp::TypeidExp(Loc loc, Type *typeidType) - : Expression(loc, TOKtypeid, sizeof(TypeidExp)) -{ - this->typeidType = typeidType; -} - - -Expression *TypeidExp::syntaxCopy() -{ - return new TypeidExp(loc, typeidType->syntaxCopy()); -} - - -Expression *TypeidExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("TypeidExp::semantic()\n"); -#endif - typeidType = typeidType->semantic(loc, sc); - e = typeidType->getTypeInfo(sc); - if (e->loc.linnum == 0) - e->loc = loc; // so there's at least some line number info - return e; -} - -void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typeid("); - typeidType->toCBuffer(buf, NULL, hgs); - buf->writeByte(')'); -} - -/************************ TraitsExp ************************************/ -#if DMDV2 -/* - * __traits(identifier, args...) - */ - -TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args) - : Expression(loc, TOKtraits, sizeof(TraitsExp)) -{ - this->ident = ident; - this->args = args; -} - - -Expression *TraitsExp::syntaxCopy() -{ - return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args)); -} - - -void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("__traits("); - buf->writestring(ident->toChars()); - if (args) - { - for (int i = 0; i < args->dim; i++) - { - buf->writeByte(','); - Object *oarg = (Object *)args->data[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - } - buf->writeByte(')'); -} -#endif - -/************************************************************/ - -HaltExp::HaltExp(Loc loc) - : Expression(loc, TOKhalt, sizeof(HaltExp)) -{ -} - -Expression *HaltExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("HaltExp::semantic()\n"); -#endif - type = Type::tvoid; - return this; -} - -int HaltExp::checkSideEffect(int flag) -{ - return 1; -} - -void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("halt"); -} - -/************************************************************/ - -IsExp::IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, - Type *tspec, enum TOK tok2, TemplateParameters *parameters) - : Expression(loc, TOKis, sizeof(IsExp)) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; - this->tok2 = tok2; - this->parameters = parameters; -} - -Expression *IsExp::syntaxCopy() -{ - // This section is identical to that in TemplateDeclaration::syntaxCopy() - TemplateParameters *p = NULL; - if (parameters) - { - p = new TemplateParameters(); - p->setDim(parameters->dim); - for (int i = 0; i < p->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - p->data[i] = (void *)tp->syntaxCopy(); - } - } - - return new IsExp(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL, - tok2, - p); -} - -Expression *IsExp::semantic(Scope *sc) -{ Type *tded; - - /* is(targ id tok tspec) - * is(targ id == tok2) - */ - - //printf("IsExp::semantic(%s)\n", toChars()); - if (id && !(sc->flags & SCOPEstaticif)) - error("can only declare type aliases within static if conditionals"); - - unsigned errors_save = global.errors; - global.errors = 0; - global.gag++; // suppress printing of error messages - targ = targ->semantic(loc, sc); - global.gag--; - unsigned gerrors = global.errors; - global.errors = errors_save; - - if (gerrors) // if any errors happened - { // then condition is false - goto Lno; - } - else if (tok2 != TOKreserved) - { - switch (tok2) - { - case TOKtypedef: - if (targ->ty != Ttypedef) - goto Lno; - tded = ((TypeTypedef *)targ)->sym->basetype; - break; - - case TOKstruct: - if (targ->ty != Tstruct) - goto Lno; - if (((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKunion: - if (targ->ty != Tstruct) - goto Lno; - if (!((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKclass: - if (targ->ty != Tclass) - goto Lno; - if (((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKinterface: - if (targ->ty != Tclass) - goto Lno; - if (!((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; -#if DMDV2 - case TOKconst: - if (!targ->isConst()) - goto Lno; - tded = targ; - break; - - case TOKinvariant: - case TOKimmutable: - if (!targ->isInvariant()) - goto Lno; - tded = targ; - break; -#endif - - case TOKsuper: - // If class or interface, get the base class and interfaces - if (targ->ty != Tclass) - goto Lno; - else - { ClassDeclaration *cd = ((TypeClass *)targ)->sym; - Arguments *args = new Arguments; - args->reserve(cd->baseclasses.dim); - for (size_t i = 0; i < cd->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; - args->push(new Argument(STCin, b->type, NULL, NULL)); - } - tded = new TypeTuple(args); - } - break; - - case TOKenum: - if (targ->ty != Tenum) - goto Lno; - tded = ((TypeEnum *)targ)->sym->memtype; - break; - - case TOKdelegate: - if (targ->ty != Tdelegate) - goto Lno; - tded = ((TypeDelegate *)targ)->next; // the underlying function type - break; - - case TOKfunction: - { - if (targ->ty != Tfunction) - goto Lno; - tded = targ; - - /* Generate tuple from function parameter types. - */ - assert(tded->ty == Tfunction); - Arguments *params = ((TypeFunction *)tded)->parameters; - size_t dim = Argument::dim(params); - Arguments *args = new Arguments; - args->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Argument *arg = Argument::getNth(params, i); - assert(arg && arg->type); - args->push(new Argument(arg->storageClass, arg->type, NULL, NULL)); - } - tded = new TypeTuple(args); - break; - } - case TOKreturn: - /* Get the 'return type' for the function, - * delegate, or pointer to function. - */ - if (targ->ty == Tfunction) - tded = ((TypeFunction *)targ)->next; - else if (targ->ty == Tdelegate) - { tded = ((TypeDelegate *)targ)->next; - tded = ((TypeFunction *)tded)->next; - } - else if (targ->ty == Tpointer && - ((TypePointer *)targ)->next->ty == Tfunction) - { tded = ((TypePointer *)targ)->next; - tded = ((TypeFunction *)tded)->next; - } - else - goto Lno; - break; - - default: - assert(0); - } - goto Lyes; - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - MATCH m; - assert(parameters && parameters->dim); - - Objects dedtypes; - dedtypes.setDim(parameters->dim); - dedtypes.zero(); - - m = targ->deduceType(NULL, tspec, parameters, &dedtypes); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - goto Lno; - else - { - tded = (Type *)dedtypes.data[0]; - if (!tded) - tded = targ; - - Objects tiargs; - tiargs.setDim(1); - tiargs.data[0] = (void *)targ; - - for (int i = 1; i < parameters->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - Declaration *s; - - m = tp->matchArg(sc, &tiargs, i, parameters, &dedtypes, &s); - if (m == MATCHnomatch) - goto Lno; - s->semantic(sc); - if (!sc->insert(s)) - error("declaration %s is already defined", s->toChars()); -#if 0 - Object *o = (Object *)dedtypes.data[i]; - Dsymbol *s = TemplateDeclaration::declareParameter(loc, sc, tp, o); -#endif - if (sc->sd) - s->addMember(sc, sc->sd, 1); - } - - goto Lyes; - } - } - else if (id) - { - /* Declare id as an alias for type targ. Evaluate to TRUE - */ - tded = targ; - goto Lyes; - } - else if (tspec) - { - /* Evaluate to TRUE if targ matches tspec - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s\n", targ->toChars()); - //printf("tspec = %s\n", tspec->toChars()); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - goto Lyes; - else - goto Lno; - } - else /* == */ - { if (targ->equals(tspec)) - goto Lyes; - else - goto Lno; - } - } - -Lyes: - if (id) - { - Dsymbol *s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - if (!sc->insert(s)) - error("declaration %s is already defined", s->toChars()); - if (sc->sd) - s->addMember(sc, sc->sd, 1); - } -//printf("Lyes\n"); - return new IntegerExp(loc, 1, Type::tbool); - -Lno: -//printf("Lno\n"); - return new IntegerExp(loc, 0, Type::tbool); -} - -void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("is("); - targ->toCBuffer(buf, id, hgs); - if (tok2 != TOKreserved) - { - buf->printf(" %s %s", Token::toChars(tok), Token::toChars(tok2)); - } - else if (tspec) - { - if (tok == TOKcolon) - buf->writestring(" : "); - else - buf->writestring(" == "); - tspec->toCBuffer(buf, NULL, hgs); - } -#if DMDV2 - if (parameters) - { // First parameter is already output, so start with second - for (int i = 1; i < parameters->dim; i++) - { - buf->writeByte(','); - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - tp->toCBuffer(buf, hgs); - } - } -#endif - buf->writeByte(')'); -} - - -/************************************************************/ - -UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) - : Expression(loc, op, size) -{ - this->e1 = e1; -} - -Expression *UnaExp::syntaxCopy() -{ UnaExp *e; - - e = (UnaExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - return e; -} - -Expression *UnaExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("UnaExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); -// if (!e1->type) -// error("%s has no value", e1->toChars()); - return this; -} - -int UnaExp::canThrow() -{ - return e1->canThrow(); -} - -void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) - : Expression(loc, op, size) -{ - this->e1 = e1; - this->e2 = e2; -} - -Expression *BinExp::syntaxCopy() -{ BinExp *e; - - e = (BinExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - e->e2 = e->e2->syntaxCopy(); - return e; -} - -Expression *BinExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("BinExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); - if (!e1->type && - !(op == TOKassign && e1->op == TOKdottd)) // a.template = e2 - { - error("%s has no value", e1->toChars()); - e1->type = Type::terror; - } - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - e2->type = Type::terror; - } - return this; -} - -Expression *BinExp::semanticp(Scope *sc) -{ - BinExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e2 = resolveProperties(sc, e2); - return this; -} - -/*************************** - * Common semantic routine for some xxxAssignExp's. - */ - -Expression *BinExp::commonSemanticAssign(Scope *sc) -{ Expression *e; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] op= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - error("operator not allowed on bool expression %s", toChars()); - } - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - - if (op == TOKmodass && e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new IntegerExp(0); - } - } - return this; -} - -Expression *BinExp::commonSemanticAssignIntegral(Scope *sc) -{ Expression *e; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] op= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - e2 = e2->implicitCastTo(sc, type); - } - - typeCombine(sc); - e1->checkIntegral(); - e2->checkIntegral(); - } - return this; -} - -int BinExp::checkSideEffect(int flag) -{ - if (op == TOKplusplus || - op == TOKminusminus || - op == TOKassign || - op == TOKconstruct || - op == TOKblit || - op == TOKaddass || - op == TOKminass || - op == TOKcatass || - op == TOKmulass || - op == TOKdivass || - op == TOKmodass || - op == TOKshlass || - op == TOKshrass || - op == TOKushrass || - op == TOKandass || - op == TOKorass || - op == TOKxorass || - op == TOKin || - op == TOKremove) - return 1; - return Expression::checkSideEffect(flag); -} - -void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte(' '); - buf->writestring(Token::toChars(op)); - buf->writeByte(' '); - expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); -} - -int BinExp::isunsigned() -{ - return e1->type->isunsigned() || e2->type->isunsigned(); -} - -int BinExp::canThrow() -{ - return e1->canThrow() || e2->canThrow(); -} - -void BinExp::incompatibleTypes() -{ - error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", - e1->toChars(), Token::toChars(op), e2->toChars(), - e1->type->toChars(), e2->type->toChars()); -} - -/************************************************************/ - -CompileExp::CompileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(CompileExp), e) -{ -} - -Expression *CompileExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("CompileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue | WANTinterpret); - if (e1->op != TOKstring) - { error("argument to mixin must be a string, not (%s)", e1->toChars()); - type = Type::terror; - return this; - } - StringExp *se = (StringExp *)e1; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - //printf("p.loc.linnum = %d\n", p.loc.linnum); - Expression *e = p.parseExpression(); - if (p.token.value != TOKeof) - error("incomplete mixin expression (%s)", se->toChars()); - return e->semantic(sc); -} - -void CompileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -FileExp::FileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(FileExp), e) -{ -} - -Expression *FileExp::semantic(Scope *sc) -{ char *name; - StringExp *se; - -#if LOGSEMANTIC - printf("FileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue); - if (e1->op != TOKstring) - { error("file name argument must be a string, not (%s)", e1->toChars()); - goto Lerror; - } - se = (StringExp *)e1; - se = se->toUTF8(sc); - name = (char *)se->string; - - if (!global.params.fileImppath) - { error("need -Jpath switch to import text file %s", name); - goto Lerror; - } - - if (name != FileName::name(name)) - { error("use -Jpath switch to provide path for filename %s", name); - goto Lerror; - } - - name = FileName::searchPath(global.filePath, name, 0); - if (!name) - { error("file %s cannot be found, check -Jpath", se->toChars()); - goto Lerror; - } - - if (global.params.verbose) - printf("file %s\t(%s)\n", se->string, name); - - { File f(name); - if (f.read()) - { error("cannot read file %s", f.toChars()); - goto Lerror; - } - else - { - f.ref = 1; - se = new StringExp(loc, f.buffer, f.len); - } - } - Lret: - return se->semantic(sc); - - Lerror: - se = new StringExp(loc, (char *)""); - goto Lret; -} - -void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("import("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg) - : UnaExp(loc, TOKassert, sizeof(AssertExp), e) -{ - this->msg = msg; -} - -Expression *AssertExp::syntaxCopy() -{ - AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(), - msg ? msg->syntaxCopy() : NULL); - return ae; -} - -Expression *AssertExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AssertExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - // BUG: see if we can do compile time elimination of the Assert - e1 = e1->optimize(WANTvalue); - e1 = e1->checkToBoolean(); - if (msg) - { - msg = msg->semantic(sc); - msg = resolveProperties(sc, msg); - msg = msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf()); - msg = msg->optimize(WANTvalue); - } - if (e1->isBool(FALSE)) - { - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - fd->hasReturnExp |= 4; - - if (!global.params.useAssert) - { Expression *e = new HaltExp(loc); - e = e->semantic(sc); - return e; - } - } - type = Type::tvoid; - return this; -} - -int AssertExp::checkSideEffect(int flag) -{ - return 1; -} - -int AssertExp::canThrow() -{ - return (global.params.useAssert != 0); -} - -void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("assert("); - expToCBuffer(buf, hgs, e1, PREC_assign); - if (msg) - { - buf->writeByte(','); - expToCBuffer(buf, hgs, msg, PREC_assign); - } - buf->writeByte(')'); -} - -/************************************************************/ - -DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident) - : UnaExp(loc, TOKdot, sizeof(DotIdExp), e) -{ - this->ident = ident; -} - -Expression *DotIdExp::semantic(Scope *sc) -{ Expression *e; - Expression *eleft; - Expression *eright; - -#if LOGSEMANTIC - printf("DotIdExp::semantic(this = %p, '%s')\n", this, toChars()); - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); -#endif - -//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } - -#if 0 - /* Don't do semantic analysis if we'll be converting - * it to a string. - */ - if (ident == Id::stringof) - { char *s = e1->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } -#endif - - /* Special case: rewrite this.id and super.id - * to be classtype.id and baseclasstype.id - * if we have no this pointer. - */ - if ((e1->op == TOKthis || e1->op == TOKsuper) && !hasThis(sc)) - { ClassDeclaration *cd; - StructDeclaration *sd; - AggregateDeclaration *ad; - - ad = sc->getStructClassScope(); - if (ad) - { - cd = ad->isClassDeclaration(); - if (cd) - { - if (e1->op == TOKthis) - { - e = new TypeDotIdExp(loc, cd->type, ident); - return e->semantic(sc); - } - else if (cd->baseClass && e1->op == TOKsuper) - { - e = new TypeDotIdExp(loc, cd->baseClass->type, ident); - return e->semantic(sc); - } - } - else - { - sd = ad->isStructDeclaration(); - if (sd) - { - if (e1->op == TOKthis) - { - e = new TypeDotIdExp(loc, sd->type, ident); - return e->semantic(sc); - } - } - } - } - } - - UnaExp::semantic(sc); - - if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *)e1; - eleft = de->e1; - eright = de->e2; - } - else - { - e1 = resolveProperties(sc, e1); - eleft = NULL; - eright = e1; - } -#if DMDV2 - if (e1->op == TOKtuple && ident == Id::offsetof) - { /* 'distribute' the .offsetof to each of the tuple elements. - */ - TupleExp *te = (TupleExp *)e1; - Expressions *exps = new Expressions(); - exps->setDim(te->exps->dim); - for (int i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)te->exps->data[i]; - e = e->semantic(sc); - e = new DotIdExp(e->loc, e, Id::offsetof); - exps->data[i] = (void *)e; - } - e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKtuple && ident == Id::length) - { - TupleExp *te = (TupleExp *)e1; - e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); - return e; - } - - Type *t1b = e1->type->toBasetype(); - - if (eright->op == TOKimport) // also used for template alias's - { - ScopeExp *ie = (ScopeExp *)eright; - - /* Disable access to another module's private imports. - * The check for 'is sds our current module' is because - * the current module should have access to its own imports. - */ - Dsymbol *s = ie->sds->search(loc, ident, - (ie->sds->isModule() && ie->sds != sc->module) ? 1 : 0); - if (s) - { - s = s->toAlias(); - checkDeprecated(sc, s); - - EnumMember *em = s->isEnumMember(); - if (em) - { - e = em->value; - e = e->semantic(sc); - return e; - } - - VarDeclaration *v = s->isVarDeclaration(); - if (v) - { - //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); - if (v->inuse) - { - error("circular reference to '%s'", v->toChars()); - type = Type::tint32; - return this; - } - type = v->type; -#if 0 - if (v->isConst() || v->isInvariant()) - { - if (v->init) - { - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - //printf("\tei: %p (%s)\n", ei->exp, ei->exp->toChars()); - //ei->exp = ei->exp->semantic(sc); - if (ei->exp->type == type) - { - e = ei->exp->copy(); // make copy so we can change loc - e->loc = loc; - return e; - } - } - } - else if (type->isscalar()) - { - e = type->defaultInit(); - e->loc = loc; - return e; - } - } -#endif - if (v->needThis()) - { - if (!eleft) - eleft = new ThisExp(loc); - e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - } - else - { - e = new VarExp(loc, v); - if (eleft) - { e = new CommaExp(loc, eleft, e); - e->type = v->type; - } - } - return e->deref(); - } - - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - { - //printf("it's a function\n"); - if (f->needThis()) - { - if (!eleft) - eleft = new ThisExp(loc); - e = new DotVarExp(loc, eleft, f); - e = e->semantic(sc); - } - else - { - e = new VarExp(loc, f, 1); - if (eleft) - { e = new CommaExp(loc, eleft, e); - e->type = f->type; - } - } - return e; - } - - OverloadSet *o = s->isOverloadSet(); - if (o) - { //printf("'%s' is an overload set\n", o->toChars()); - return new OverExp(o); - } - - Type *t = s->getType(); - if (t) - { - return new TypeExp(loc, t); - } - - TupleDeclaration *tup = s->isTupleDeclaration(); - if (tup) - { - if (eleft) - error("cannot have e.tuple"); - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - ScopeDsymbol *sds = s->isScopeDsymbol(); - if (sds) - { - //printf("it's a ScopeDsymbol\n"); - e = new ScopeExp(loc, sds); - e = e->semantic(sc); - if (eleft) - e = new DotExp(loc, eleft, e); - return e; - } - - Import *imp = s->isImport(); - if (imp) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, imp->pkg); - return ie->semantic(sc); - } - - // BUG: handle other cases like in IdentifierExp::semantic() -#ifdef DEBUG - printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - assert(0); - } - else if (ident == Id::stringof) - { char *s = ie->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } - error("undefined identifier %s", toChars()); - type = Type::tvoid; - return this; - } - else if (t1b->ty == Tpointer && - ident != Id::init && ident != Id::__sizeof && - ident != Id::alignof && ident != Id::offsetof && - ident != Id::mangleof && ident != Id::stringof) - { /* Rewrite: - * p.ident - * as: - * (*p).ident - */ - e = new PtrExp(loc, e1); - e->type = ((TypePointer *)t1b)->next; - return e->type->dotExp(sc, e, ident); - } - else if (t1b->ty == Tarray || - t1b->ty == Tsarray || - t1b->ty == Taarray) - { /* If ident is not a valid property, rewrite: - * e1.ident - * as: - * .ident(e1) - */ - unsigned errors = global.errors; - global.gag++; - e = e1->type->dotExp(sc, e1, ident); - global.gag--; - if (errors != global.errors) // if failed to find the property - { - global.errors = errors; - e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); - e = new CallExp(loc, e, e1); - } - e = e->semantic(sc); - return e; - } - else - { - e = e1->type->dotExp(sc, e1, ident); - e = e->semantic(sc); - return e; - } -} - -void DotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("DotIdExp::toCBuffer()\n"); - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -/********************** DotTemplateExp ***********************************/ - -// Mainly just a placeholder - -DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td) - : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e) - -{ - this->td = td; -} - -void DotTemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(td->toChars()); -} - - -/************************************************************/ - -DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *v, int hasOverloads) - : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e) -{ - //printf("DotVarExp()\n"); - this->var = v; - this->hasOverloads = hasOverloads; -} - -Expression *DotVarExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotVarExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - var = var->toAlias()->isDeclaration(); - - TupleDeclaration *tup = var->isTupleDeclaration(); - if (tup) - { /* Replace: - * e1.tuple(a, b, c) - * with: - * tuple(e1.a, e1.b, e1.c) - */ - Expressions *exps = new Expressions; - - exps->reserve(tup->objects->dim); - for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = (Object *)tup->objects->data[i]; - if (o->dyncast() != DYNCAST_EXPRESSION) - { - error("%s is not an expression", o->toChars()); - } - else - { - Expression *e = (Expression *)o; - if (e->op != TOKdsymbol) - error("%s is not a member", e->toChars()); - else - { DsymbolExp *ve = (DsymbolExp *)e; - - e = new DotVarExp(loc, e1, ve->s->isDeclaration()); - exps->push(e); - } - } - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - - e1 = e1->semantic(sc); - type = var->type; - if (!type && global.errors) - { // var is goofed up, just return 0 - return new IntegerExp(0); - } - assert(type); - - if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution - { - Type *t1 = e1->type; - if (t1->ty == Tpointer) - t1 = t1->nextOf(); - if (t1->isConst()) - type = type->constOf(); - else if (t1->isInvariant()) - type = type->invariantOf(); - - AggregateDeclaration *ad = var->toParent()->isAggregateDeclaration(); - e1 = getRightThis(loc, sc, ad, e1, var); - if (!sc->noaccesscheck) - accessCheck(loc, sc, e1, var); - - VarDeclaration *v = var->isVarDeclaration(); - Expression *e = expandVar(WANTvalue, v); - if (e) - return e; - } - } - //printf("-DotVarExp::semantic('%s')\n", toChars()); - return this; -} - -int DotVarExp::isLvalue() -{ - return 1; -} - -Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) -{ - //printf("DotVarExp::toLvalue(%s)\n", toChars()); - return this; -} - -Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) -{ -#if 0 - printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); - printf("e1->type = %s\n", e1->type->toChars()); - printf("var->type = %s\n", var->type->toChars()); -#endif - - if (var->isCtorinit()) - { // It's only modifiable if inside the right constructor - Dsymbol *s = sc->func; - while (1) - { - FuncDeclaration *fd = NULL; - if (s) - fd = s->isFuncDeclaration(); - if (fd && - ((fd->isCtorDeclaration() && var->storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) && - fd->toParent() == var->toParent() && - e1->op == TOKthis - ) - { - VarDeclaration *v = var->isVarDeclaration(); - assert(v); - v->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else - { - const char *p = var->isStatic() ? "static " : ""; - error("can only initialize %sconst member %s inside %sconstructor", - p, var->toChars(), p); - } - } - break; - } - } - else - { - Type *t1 = e1->type->toBasetype(); - - if (!t1->isMutable() || - (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || - !var->type->isMutable() || - !var->type->isAssignable() || - var->storage_class & STCmanifest - ) - error("cannot modify const/invariant %s", toChars()); - } - return this; -} - -void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(var->toChars()); -} - -/************************************************************/ - -/* Things like: - * foo.bar!(args) - */ - -DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti) - : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e) -{ - //printf("DotTemplateInstanceExp()\n"); - this->ti = ti; -} - -Expression *DotTemplateInstanceExp::syntaxCopy() -{ - DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, - e1->syntaxCopy(), - (TemplateInstance *)ti->syntaxCopy(NULL)); - return de; -} - -Expression *DotTemplateInstanceExp::semantic(Scope *sc) -{ Dsymbol *s; - Dsymbol *s2; - TemplateDeclaration *td; - Expression *e; - Identifier *id; - Type *t1; - Expression *eleft = NULL; - Expression *eright; - -#if LOGSEMANTIC - printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); -#endif - //e1->print(); - //print(); - e1 = e1->semantic(sc); - t1 = e1->type; - if (t1) - t1 = t1->toBasetype(); - //t1->print(); - - /* Extract the following from e1: - * s: the symbol which ti should be a member of - * eleft: if not NULL, it is the 'this' pointer for ti - */ - - if (e1->op == TOKdotexp) - { DotExp *de = (DotExp *)e1; - eleft = de->e1; - eright = de->e2; - } - else - { eleft = NULL; - eright = e1; - } - if (eright->op == TOKimport) - { - s = ((ScopeExp *)eright)->sds; - } - else if (e1->op == TOKtype) - { - s = t1->isClassHandle(); - if (!s) - { if (t1->ty == Tstruct) - s = ((TypeStruct *)t1)->sym; - else - goto L1; - } - } - else if (t1 && (t1->ty == Tstruct || t1->ty == Tclass)) - { - s = t1->toDsymbol(sc); - eleft = e1; - } - else if (t1 && t1->ty == Tpointer) - { - t1 = ((TypePointer *)t1)->next->toBasetype(); - if (t1->ty != Tstruct) - goto L1; - s = t1->toDsymbol(sc); - eleft = e1; - } - else - { - L1: - error("template %s is not a member of %s", ti->toChars(), e1->toChars()); - goto Lerr; - } - - assert(s); - id = ti->name; - s2 = s->search(loc, id, 0); - if (!s2) - { error("template identifier %s is not a member of %s %s", id->toChars(), s->kind(), s->ident->toChars()); - goto Lerr; - } - s = s2; - s->semantic(sc); - s = s->toAlias(); - td = s->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template", id->toChars()); - goto Lerr; - } - if (global.errors) - goto Lerr; - - ti->tempdecl = td; - - if (eleft) - { Declaration *v; - - ti->semantic(sc); - s = ti->inst->toAlias(); - v = s->isDeclaration(); - if (v) - { e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - return e; - } - } - - e = new ScopeExp(loc, ti); - if (eleft) - { - e = new DotExp(loc, eleft, e); - } - e = e->semantic(sc); - return e; - -Lerr: - return new IntegerExp(loc, 0, Type::tint32); -} - -void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - ti->toCBuffer(buf, hgs); -} - -/************************************************************/ - -DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, int hasOverloads) - : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e) -{ - this->func = f; - this->hasOverloads = hasOverloads; -} - -Expression *DelegateExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DelegateExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - e1 = e1->semantic(sc); - // LDC we need a copy as we store the LLVM tpye in TypeFunction, and delegate/members have different types for 'this' - type = new TypeDelegate(func->type->syntaxCopy()); - type = type->semantic(loc, sc); - AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); - if (func->needThis()) - e1 = getRightThis(loc, sc, ad, e1, func); - } - return this; -} - -void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('&'); - if (!func->isNested()) - { - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - } - buf->writestring(func->toChars()); -} - -/************************************************************/ - -DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s) - : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e) -{ - this->sym = s; - this->type = s->getType(); -} - -Expression *DotTypeExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotTypeExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - return this; -} - -void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(sym->toChars()); -} - -/************************************************************/ - -CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = exps; -} - -CallExp::CallExp(Loc loc, Expression *e) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = NULL; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - arguments->setDim(1); - arguments->data[0] = (void *)earg1; - - this->arguments = arguments; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - arguments->setDim(2); - arguments->data[0] = (void *)earg1; - arguments->data[1] = (void *)earg2; - - this->arguments = arguments; -} - -Expression *CallExp::syntaxCopy() -{ - return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *CallExp::semantic(Scope *sc) -{ - TypeFunction *tf; - FuncDeclaration *f; - int i; - Type *t1; - int istemp; - Objects *targsi = NULL; // initial list of template arguments - -#if LOGSEMANTIC - printf("CallExp::semantic() %s\n", toChars()); -#endif - if (type) - return this; // semantic() already run -#if 0 - if (arguments && arguments->dim) - { - Expression *earg = (Expression *)arguments->data[0]; - earg->print(); - if (earg->type) earg->type->print(); - } -#endif - - if (e1->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)e1; - - e1 = new DotVarExp(de->loc, de->e1, de->func); - return semantic(sc); - } - - /* Transform: - * array.id(args) into .id(array,args) - * aa.remove(arg) into delete aa[arg] - */ - if (e1->op == TOKdot) - { - // BUG: we should handle array.a.b.c.e(args) too - - DotIdExp *dotid = (DotIdExp *)(e1); - dotid->e1 = dotid->e1->semantic(sc); - assert(dotid->e1); - if (dotid->e1->type) - { - TY e1ty = dotid->e1->type->toBasetype()->ty; - if (e1ty == Taarray && dotid->ident == Id::remove) - { - if (!arguments || arguments->dim != 1) - { error("expected key as argument to aa.remove()"); - goto Lagain; - } - Expression *key = (Expression *)arguments->data[0]; - key = key->semantic(sc); - key = resolveProperties(sc, key); - key->rvalue(); - - TypeAArray *taa = (TypeAArray *)dotid->e1->type->toBasetype(); - key = key->implicitCastTo(sc, taa->index); - - return new RemoveExp(loc, dotid->e1, key); - } - else if (e1ty == Tarray || e1ty == Tsarray || e1ty == Taarray) - { - if (!arguments) - arguments = new Expressions(); - arguments->shift(dotid->e1); - e1 = new DotIdExp(dotid->loc, new IdentifierExp(dotid->loc, Id::empty), dotid->ident); - } - } - } - -#if DMDV2 - /* This recognizes: - * foo!(tiargs)(funcargs) - */ - if (e1->op == TOKimport && !e1->type) - { ScopeExp *se = (ScopeExp *)e1; - TemplateInstance *ti = se->sds->isTemplateInstance(); - if (ti && !ti->semanticdone) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); - unsigned errors = global.errors; - global.gag++; - ti->semantic(sc); - global.gag--; - if (errors != global.errors) - { - /* Didn't work, go with partial explicit specialization - */ - global.errors = errors; - targsi = ti->tiargs; - e1 = new IdentifierExp(loc, ti->name); - } - } - } - - /* This recognizes: - * expr.foo!(tiargs)(funcargs) - */ - if (e1->op == TOKdotti && !e1->type) - { DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)e1; - TemplateInstance *ti = se->ti; - if (!ti->semanticdone) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); - Expression *etmp; - unsigned errors = global.errors; - global.gag++; - etmp = e1->semantic(sc); - global.gag--; - if (errors != global.errors) - { - global.errors = errors; - targsi = ti->tiargs; - e1 = new DotIdExp(loc, se->e1, ti->name); - } - else - e1 = etmp; - } - } -#endif - - istemp = 0; -Lagain: - //printf("Lagain: %s\n", toChars()); - f = NULL; - if (e1->op == TOKthis || e1->op == TOKsuper) - { - // semantic() run later for these - } - else - { - UnaExp::semantic(sc); - - /* Look for e1 being a lazy parameter - */ - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - - if (ve->var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd); - TypeDelegate *t = new TypeDelegate(tf); - ve->type = t->semantic(loc, sc); - } - } - - if (e1->op == TOKimport) - { // Perhaps this should be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)e1; - e1 = new DsymbolExp(loc, se->sds); - e1 = e1->semantic(sc); - } -#if 1 // patch for #540 by Oskar Linde - else if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *) e1; - - if (de->e2->op == TOKimport) - { // This should *really* be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)de->e2; - de->e2 = new DsymbolExp(loc, se->sds); - de->e2 = de->e2->semantic(sc); - } - - if (de->e2->op == TOKtemplate) - { TemplateExp *te = (TemplateExp *) de->e2; - e1 = new DotTemplateExp(loc,de->e1,te->td); - } - } -#endif - } - - if (e1->op == TOKcomma) - { - CommaExp *ce = (CommaExp *)e1; - - e1 = ce->e2; - e1->type = ce->type; - ce->e2 = this; - ce->type = NULL; - return ce->semantic(sc); - } - - t1 = NULL; - if (e1->type) - t1 = e1->type->toBasetype(); - - // Check for call operator overload - if (t1) - { AggregateDeclaration *ad; - - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - - // First look for constructor - if (ad->ctor && arguments && arguments->dim) - { - // Create variable that will get constructed - Identifier *idtmp = Lexer::uniqueId("__ctmp"); - VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL); - Expression *av = new DeclarationExp(loc, tmp); - av = new CommaExp(loc, av, new VarExp(loc, tmp)); - - Expression *e = new DotVarExp(loc, av, ad->ctor, 1); - e = new CallExp(loc, e, arguments); -#if !STRUCTTHISREF - /* Constructors return a pointer to the instance - */ - e = new PtrExp(loc, e); -#endif - e = e->semantic(sc); - return e; - } - - // No constructor, look for overload of opCall - if (search_function(ad, Id::call)) - goto L1; // overload of opCall, therefore it's a call - - if (e1->op != TOKtype) - error("%s %s does not overload ()", ad->kind(), ad->toChars()); - /* It's a struct literal - */ - Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments); - e = e->semantic(sc); - e->type = e1->type; // in case e1->type was a typedef - return e; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - L1: - // Rewrite as e1.call(arguments) - Expression *e = new DotIdExp(loc, e1, Id::call); - e = new CallExp(loc, e, arguments); - e = e->semantic(sc); - return e; - } - } - - arrayExpressionSemantic(arguments, sc); - preFunctionArguments(loc, sc, arguments); - - if (e1->op == TOKdotvar && t1->ty == Tfunction || - e1->op == TOKdottd) - { - DotVarExp *dve; - DotTemplateExp *dte; - AggregateDeclaration *ad; - UnaExp *ue = (UnaExp *)(e1); - - if (e1->op == TOKdotvar) - { // Do overload resolution - dve = (DotVarExp *)(e1); - - f = dve->var->isFuncDeclaration(); - assert(f); - f = f->overloadResolve(loc, ue->e1, arguments); - - ad = f->toParent()->isAggregateDeclaration(); - } - else - { dte = (DotTemplateExp *)(e1); - TemplateDeclaration *td = dte->td; - assert(td); - if (!arguments) - // Should fix deduceFunctionTemplate() so it works on NULL argument - arguments = new Expressions(); - f = td->deduceFunctionTemplate(sc, loc, targsi, ue->e1, arguments); - if (!f) - { type = Type::terror; - return this; - } - ad = td->toParent()->isAggregateDeclaration(); - } - if (f->needThis()) - { - ue->e1 = getRightThis(loc, sc, ad, ue->e1, f); - } - - /* Cannot call public functions from inside invariant - * (because then the invariant would have infinite recursion) - */ - if (sc->func && sc->func->isInvariantDeclaration() && - ue->e1->op == TOKthis && - f->addPostInvariant() - ) - { - error("cannot call public/export function %s from invariant", f->toChars()); - } - - checkDeprecated(sc, f); - accessCheck(loc, sc, ue->e1, f); - if (!f->needThis()) - { - VarExp *ve = new VarExp(loc, f); - e1 = new CommaExp(loc, ue->e1, ve); - e1->type = f->type; - } - else - { - if (e1->op == TOKdotvar) - dve->var = f; - else - e1 = new DotVarExp(loc, dte->e1, f); - e1->type = f->type; -#if 0 - printf("ue->e1 = %s\n", ue->e1->toChars()); - printf("f = %s\n", f->toChars()); - printf("t = %s\n", t->toChars()); - printf("e1 = %s\n", e1->toChars()); - printf("e1->type = %s\n", e1->type->toChars()); -#endif - // Const member function can take const/invariant/mutable this - if (!(f->type->isConst())) - { - // Check for const/invariant compatibility - Type *tthis = ue->e1->type->toBasetype(); - if (tthis->ty == Tpointer) - tthis = tthis->nextOf()->toBasetype(); - if (f->type->isInvariant()) - { - if (tthis->mod != MODinvariant) - error("%s can only be called on an invariant object", e1->toChars()); - } - else - { - if (tthis->mod != 0) - { //printf("mod = %x\n", tthis->mod); - error("%s can only be called on a mutable object, not %s", e1->toChars(), tthis->toChars()); - } - } - - /* Cannot call mutable method on a final struct - */ - if (tthis->ty == Tstruct && - ue->e1->op == TOKvar) - { VarExp *v = (VarExp *)ue->e1; - if (v->var->storage_class & STCfinal) - error("cannot call mutable method on final struct"); - } - } - - // See if we need to adjust the 'this' pointer - AggregateDeclaration *ad = f->isThis(); - ClassDeclaration *cd = ue->e1->type->isClassHandle(); - if (ad && cd && ad->isClassDeclaration() && ad != cd && - ue->e1->op != TOKsuper) - { - ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type); - ue->e1 = ue->e1->semantic(sc); - } - } - t1 = e1->type; - } - else if (e1->op == TOKsuper) - { - // Base class constructor call - ClassDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isClassDeclaration(); - if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) - { - error("super class constructor call must be in a constructor"); - type = Type::terror; - return this; - } - else - { - f = cd->baseClass->ctor; - if (!f) - { error("no super class constructor for %s", cd->baseClass->toChars()); - type = Type::terror; - return this; - } - else - { - if (!sc->intypeof) - { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif - if (sc->noctor || sc->callSuper & CSXlabel) - error("constructor calls not allowed in loops or after labels"); - if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) - error("multiple constructor calls"); - sc->callSuper |= CSXany_ctor | CSXsuper_ctor; - } - - f = f->overloadResolve(loc, NULL, arguments); - checkDeprecated(sc, f); - e1 = new DotVarExp(e1->loc, e1, f); - e1 = e1->semantic(sc); - t1 = e1->type; - } - } - } - else if (e1->op == TOKthis) - { - // same class constructor call - ClassDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isClassDeclaration(); - if (!cd || !sc->func->isCtorDeclaration()) - { - error("class constructor call must be in a constructor"); - type = Type::terror; - return this; - } - else - { - if (!sc->intypeof) - { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif - if (sc->noctor || sc->callSuper & CSXlabel) - error("constructor calls not allowed in loops or after labels"); - if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) - error("multiple constructor calls"); - sc->callSuper |= CSXany_ctor | CSXthis_ctor; - } - - f = cd->ctor; - f = f->overloadResolve(loc, NULL, arguments); - checkDeprecated(sc, f); - e1 = new DotVarExp(e1->loc, e1, f); - e1 = e1->semantic(sc); - t1 = e1->type; - - // BUG: this should really be done by checking the static - // call graph - if (f == sc->func) - error("cyclic constructor call"); - } - } - else if (e1->op == TOKoverloadset) - { - OverExp *eo = (OverExp *)e1; - FuncDeclaration *f = NULL; - for (int i = 0; i < eo->vars->a.dim; i++) - { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - if (f2) - { - f2 = f2->overloadResolve(loc, NULL, arguments, 1); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - assert(td); - f2 = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments, 1); - } - if (f2) - { if (f) - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol::multiplyDefined(loc, f, f2); - else - f = f2; - } - } - if (!f) - { /* No overload matches, just set f and rely on error - * message being generated later. - */ - f = (FuncDeclaration *)eo->vars->a.data[0]; - } - e1 = new VarExp(loc, f); - goto Lagain; - } - else if (!t1) - { - error("function expected before (), not '%s'", e1->toChars()); - type = Type::terror; - return this; - } - else if (t1->ty != Tfunction) - { - if (t1->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)t1; - assert(td->next->ty == Tfunction); - tf = (TypeFunction *)(td->next); - goto Lcheckargs; - } - else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction) - { Expression *e; - - e = new PtrExp(loc, e1); - t1 = ((TypePointer *)t1)->next; - e->type = t1; - e1 = e; - } - else if (e1->op == TOKtemplate) - { - TemplateExp *te = (TemplateExp *)e1; - f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); - if (!f) - { type = Type::terror; - return this; - } - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotTemplateExp(loc, (new ThisExp(loc))->semantic(sc), te->td); - goto Lagain; - } - - e1 = new VarExp(loc, f); - goto Lagain; - } - else - { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); - type = Type::terror; - return this; - } - } - else if (e1->op == TOKvar) - { - // Do overload resolution - VarExp *ve = (VarExp *)e1; - - f = ve->var->isFuncDeclaration(); - assert(f); - - if (ve->hasOverloads) - f = f->overloadResolve(loc, NULL, arguments); - checkDeprecated(sc, f); - - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotVarExp(loc, new ThisExp(loc), f); - goto Lagain; - } - - accessCheck(loc, sc, NULL, f); - - ve->var = f; -// ve->hasOverloads = 0; - ve->type = f->type; - t1 = f->type; - } - assert(t1->ty == Tfunction); - tf = (TypeFunction *)(t1); - -Lcheckargs: - assert(tf->ty == Tfunction); - type = tf->next; - - if (!arguments) - arguments = new Expressions(); - functionArguments(loc, sc, tf, arguments); - - assert(type); - - if (f && f->tintro) - { - Type *t = type; - int offset = 0; - TypeFunction *tf = (TypeFunction *)f->tintro; - - if (tf->next->isBaseOf(t, &offset) && offset) - { - type = tf->next; - return castTo(sc, t); - } - } - - return this; -} - -int CallExp::checkSideEffect(int flag) -{ - return 1; -} - -int CallExp::canThrow() -{ - return 1; -} - -int CallExp::isLvalue() -{ - if (type->toBasetype()->ty == Tstruct) - return 1; - Type *tb = e1->type->toBasetype(); - if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) - return 1; // function returns a reference - return 0; -} - -Expression *CallExp::toLvalue(Scope *sc, Expression *e) -{ - if (isLvalue()) - return this; - return Expression::toLvalue(sc, e); -} - -void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); -} - - -/************************************************************/ - -AddrExp::AddrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKaddress, sizeof(AddrExp), e) -{ -} - -Expression *AddrExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AddrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = e1->toLvalue(sc, NULL); - if (!e1->type) - { - error("cannot take address of %s", e1->toChars()); - type = Type::tint32; - return this; - } - type = e1->type->pointerTo(); - - // See if this should really be a delegate - if (e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *f = dve->var->isFuncDeclaration(); - - if (f) - { - if (!dve->hasOverloads) - f->tookAddressOf++; - Expression *e = new DelegateExp(loc, dve->e1, f, dve->hasOverloads); - e = e->semantic(sc); - return e; - } - } - else if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && !v->canTakeAddressOf()) - error("cannot take address of %s", e1->toChars()); - - FuncDeclaration *f = ve->var->isFuncDeclaration(); - - if (f) - { - if (!ve->hasOverloads || - /* Because nested functions cannot be overloaded, - * mark here that we took its address because castTo() - * may not be called with an exact match. - */ - f->toParent2()->isFuncDeclaration()) - f->tookAddressOf++; - - // LDC - if (f && f->isIntrinsic()) - { - error("cannot take the address of intrinsic function %s", e1->toChars()); - return this; - } - - if (f->isNested()) - { - Expression *e = new DelegateExp(loc, e1, f, ve->hasOverloads); - e = e->semantic(sc); - return e; - } - if (f->needThis() && hasThis(sc)) - { - /* Should probably supply 'this' after overload resolution, - * not before. - */ - Expression *ethis = new ThisExp(loc); - Expression *e = new DelegateExp(loc, ethis, f, ve->hasOverloads); - e = e->semantic(sc); - return e; - } - } - } - return optimize(WANTvalue); - } - return this; -} - -/************************************************************/ - -PtrExp::PtrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ - if (e->type) - type = ((TypePointer *)e->type)->next; -} - -PtrExp::PtrExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ - type = t; -} - -Expression *PtrExp::semantic(Scope *sc) -{ Type *tb; - -#if LOGSEMANTIC - printf("PtrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (!e1->type) - printf("PtrExp::semantic('%s')\n", toChars()); - Expression *e = op_overload(sc); - if (e) - return e; - tb = e1->type->toBasetype(); - switch (tb->ty) - { - case Tpointer: - type = ((TypePointer *)tb)->next; - break; - - case Tsarray: - case Tarray: - type = ((TypeArray *)tb)->next; - e1 = e1->castTo(sc, type->pointerTo()); - break; - - default: - error("can only * a pointer, not a '%s'", e1->type->toChars()); - type = Type::tint32; - break; - } - rvalue(); - } - return this; -} - -int PtrExp::isLvalue() -{ - return 1; -} - -Expression *PtrExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - return this; -} - -Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); - - if (e1->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)e1; - se->var->checkModify(loc, sc, type); - //return toLvalue(sc, e); - } - - return Expression::modifiableLvalue(sc, e); -} - - -void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('*'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -NegExp::NegExp(Loc loc, Expression *e) - : UnaExp(loc, TOKneg, sizeof(NegExp), e) -{ -} - -Expression *NegExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("NegExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - - e1->checkNoBool(); - if (e1->op != TOKslice) - e1->checkArithmetic(); - type = e1->type; - } - return this; -} - -/************************************************************/ - -UAddExp::UAddExp(Loc loc, Expression *e) - : UnaExp(loc, TOKuadd, sizeof(UAddExp), e) -{ -} - -Expression *UAddExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("UAddExp::semantic('%s')\n", toChars()); -#endif - assert(!type); - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - e1->checkNoBool(); - e1->checkArithmetic(); - return e1; -} - -/************************************************************/ - -ComExp::ComExp(Loc loc, Expression *e) - : UnaExp(loc, TOKtilde, sizeof(ComExp), e) -{ -} - -Expression *ComExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - - e1->checkNoBool(); - if (e1->op != TOKslice) - e1 = e1->checkIntegral(); - type = e1->type; - } - return this; -} - -/************************************************************/ - -NotExp::NotExp(Loc loc, Expression *e) - : UnaExp(loc, TOKnot, sizeof(NotExp), e) -{ -} - -Expression *NotExp::semantic(Scope *sc) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int NotExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -BoolExp::BoolExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKtobool, sizeof(BoolExp), e) -{ - type = t; -} - -Expression *BoolExp::semantic(Scope *sc) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int BoolExp::isBit() -{ - return TRUE; -} - -/************************************************************/ - -DeleteExp::DeleteExp(Loc loc, Expression *e) - : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e) -{ -} - -Expression *DeleteExp::semantic(Scope *sc) -{ - Type *tb; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->toLvalue(sc, NULL); - type = Type::tvoid; - - tb = e1->type->toBasetype(); - switch (tb->ty) - { case Tclass: - { TypeClass *tc = (TypeClass *)tb; - ClassDeclaration *cd = tc->sym; - - if (cd->isCOMinterface()) - { /* Because COM classes are deleted by IUnknown.Release() - */ - error("cannot delete instance of COM interface %s", cd->toChars()); - } - break; - } - case Tpointer: - tb = ((TypePointer *)tb)->next->toBasetype(); - if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - FuncDeclaration *f = sd->aggDelete; - FuncDeclaration *fd = sd->dtor; - - if (!f && !fd) - break; - - /* Construct: - * ea = copy e1 to a tmp to do side effects only once - * eb = call destructor - * ec = call deallocator - */ - Expression *ea = NULL; - Expression *eb = NULL; - Expression *ec = NULL; - VarDeclaration *v; - - if (fd && f) - { Identifier *id = Lexer::idPool("__tmp"); - v = new VarDeclaration(loc, e1->type, id, new ExpInitializer(loc, e1)); - v->semantic(sc); - v->parent = sc->parent; - ea = new DeclarationExp(loc, v); - ea->type = v->type; - } - - if (fd) - { Expression *e = ea ? new VarExp(loc, v) : e1; - e = new DotVarExp(0, e, fd, 0); - eb = new CallExp(loc, e); - eb = eb->semantic(sc); - } - - if (f) - { - Type *tpv = Type::tvoid->pointerTo(); - Expression *e = ea ? new VarExp(loc, v) : e1->castTo(sc, tpv); - e = new CallExp(loc, new VarExp(loc, f), e); - ec = e->semantic(sc); - } - ea = combine(ea, eb); - ea = combine(ea, ec); - assert(ea); - return ea; - } - break; - - case Tarray: - /* BUG: look for deleting arrays of structs with dtors. - */ - break; - - default: - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - break; - } - error("cannot delete type %s", e1->type->toChars()); - break; - } - - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - { if (!global.params.useDeprecated) - error("delete aa[key] deprecated, use aa.remove(key)"); - } - } - - return this; -} - -int DeleteExp::checkSideEffect(int flag) -{ - return 1; -} - -Expression *DeleteExp::checkToBoolean() -{ - error("delete does not give a boolean result"); - return this; -} - -void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete "); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -CastExp::CastExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = t; - this->tok = TOKreserved; -} - -/* For cast(const) and cast(invariant) - */ -CastExp::CastExp(Loc loc, Expression *e, enum TOK tok) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = NULL; - this->tok = tok; -} - -Expression *CastExp::syntaxCopy() -{ - return to ? new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()) - : new CastExp(loc, e1->syntaxCopy(), tok); -} - - -Expression *CastExp::semantic(Scope *sc) -{ Expression *e; - BinExp *b; - UnaExp *u; - -#if LOGSEMANTIC - printf("CastExp::semantic('%s')\n", toChars()); -#endif - -//static int x; assert(++x < 10); - - if (type) - return this; - UnaExp::semantic(sc); - if (e1->type) // if not a tuple - { - e1 = resolveProperties(sc, e1); - - /* Handle cast(const) and cast(invariant) - */ - if (!to) - { if (tok == TOKconst) - to = e1->type->constOf(); - else if (tok == TOKinvariant || tok == TOKimmutable) - to = e1->type->invariantOf(); - else - assert(0); - } - else - to = to->semantic(loc, sc); - - e = op_overload(sc); - if (e) - { - return e->implicitCastTo(sc, to); - } - - Type *tob = to->toBasetype(); - if (tob->ty == Tstruct && - !tob->equals(e1->type->toBasetype()) && - ((TypeStruct *)to)->sym->search(0, Id::call, 0) - ) - { - /* Look to replace: - * cast(S)t - * with: - * S(t) - */ - - // Rewrite as to.call(e1) - e = new TypeExp(loc, to); - e = new DotIdExp(loc, e, Id::call); - e = new CallExp(loc, e, e1); - e = e->semantic(sc); - return e; - } - } - else if (!to) - { error("cannot cast tuple"); - to = Type::terror; - } - e = e1->castTo(sc, to); - return e; -} - -int CastExp::checkSideEffect(int flag) -{ - /* if not: - * cast(void) - * cast(classtype)func() - */ - if (!to->equals(Type::tvoid) && - !(to->ty == Tclass && e1->op == TOKcall && e1->type->ty == Tclass)) - return Expression::checkSideEffect(flag); - return 1; -} - -void CastExp::checkEscape() -{ Type *tb = type->toBasetype(); - if (tb->ty == Tarray && e1->op == TOKvar && - e1->type->toBasetype()->ty == Tsarray) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !v->isParameter()) - error("escaping reference to local %s", v->toChars()); - } - } -} - -void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("cast("); - if (to) - to->toCBuffer(buf, NULL, hgs); - else - buf->writestring(Token::tochars[tok]); - buf->writeByte(')'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - - -/************************************************************/ - -SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) - : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) -{ - this->upr = upr; - this->lwr = lwr; - lengthVar = NULL; -} - -Expression *SliceExp::syntaxCopy() -{ - Expression *lwr = NULL; - if (this->lwr) - lwr = this->lwr->syntaxCopy(); - - Expression *upr = NULL; - if (this->upr) - upr = this->upr->syntaxCopy(); - - return new SliceExp(loc, e1->syntaxCopy(), lwr, upr); -} - -Expression *SliceExp::semantic(Scope *sc) -{ Expression *e; - AggregateDeclaration *ad; - //FuncDeclaration *fd; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("SliceExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - e = this; - - Type *t = e1->type->toBasetype(); - if (t->ty == Tpointer) - { - if (!lwr || !upr) - error("need upper and lower bound to slice pointer"); - } - else if (t->ty == Tarray) - { - } - else if (t->ty == Tsarray) - { - } - else if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - goto L1; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - - L1: - if (search_function(ad, Id::slice)) - { - // Rewrite as e1.slice(lwr, upr) - e = new DotIdExp(loc, e1, Id::slice); - - if (lwr) - { - assert(upr); - e = new CallExp(loc, e, lwr, upr); - } - else - { assert(!upr); - e = new CallExp(loc, e); - } - e = e->semantic(sc); - return e; - } - goto Lerror; - } - else if (t->ty == Ttuple) - { - if (!lwr && !upr) - return e1; - if (!lwr || !upr) - { error("need upper and lower bound to slice tuple"); - goto Lerror; - } - } - else - goto Lerror; - - if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) - { - sym = new ArrayScopeSymbol(sc, this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - } - - if (lwr) - { lwr = lwr->semantic(sc); - lwr = resolveProperties(sc, lwr); - lwr = lwr->implicitCastTo(sc, Type::tsize_t); - } - if (upr) - { upr = upr->semantic(sc); - upr = resolveProperties(sc, upr); - upr = upr->implicitCastTo(sc, Type::tsize_t); - } - - if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) - sc->pop(); - - if (t->ty == Ttuple) - { - lwr = lwr->optimize(WANTvalue); - upr = upr->optimize(WANTvalue); - uinteger_t i1 = lwr->toUInteger(); - uinteger_t i2 = upr->toUInteger(); - - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) // slicing an expression tuple - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) // slicing a type tuple - { tup = (TypeTuple *)t; - length = Argument::dim(tup->arguments); - } - else - assert(0); - - if (i1 <= i2 && i2 <= length) - { size_t j1 = (size_t) i1; - size_t j2 = (size_t) i2; - - if (e1->op == TOKtuple) - { Expressions *exps = new Expressions; - exps->setDim(j2 - j1); - for (size_t i = 0; i < j2 - j1; i++) - { Expression *e = (Expression *)te->exps->data[j1 + i]; - exps->data[i] = (void *)e; - } - e = new TupleExp(loc, exps); - } - else - { Arguments *args = new Arguments; - args->reserve(j2 - j1); - for (size_t i = j1; i < j2; i++) - { Argument *arg = Argument::getNth(tup->arguments, i); - args->push(arg); - } - e = new TypeExp(e1->loc, new TypeTuple(args)); - } - e = e->semantic(sc); - } - else - { - error("string slice [%llu .. %llu] is out of bounds", i1, i2); - e = e1; - } - return e; - } - - type = t->nextOf()->arrayOf(); - return e; - -Lerror: - char *s; - if (t->ty == Tvoid) - s = e1->toChars(); - else - s = t->toChars(); - error("%s cannot be sliced with []", s); - type = Type::terror; - return e; -} - -void SliceExp::checkEscape() -{ - e1->checkEscape(); -} - -int SliceExp::isLvalue() -{ - return 1; -} - -Expression *SliceExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("slice expression %s is not a modifiable lvalue", toChars()); - return this; -} - -void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('['); - if (upr || lwr) - { - if (lwr) - expToCBuffer(buf, hgs, lwr, PREC_assign); - else - buf->writeByte('0'); - buf->writestring(".."); - if (upr) - expToCBuffer(buf, hgs, upr, PREC_assign); - else - buf->writestring("length"); // BUG: should be array.length - } - buf->writeByte(']'); -} - -/********************** ArrayLength **************************************/ - -ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) - : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1) -{ -} - -Expression *ArrayLengthExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("ArrayLengthExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - type = Type::tsize_t; - } - return this; -} - -void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writestring(".length"); -} - -/*********************** ArrayExp *************************************/ - -// e1 [ i1, i2, i3, ... ] - -ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args) - : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1) -{ - arguments = args; -} - -Expression *ArrayExp::syntaxCopy() -{ - return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - -Expression *ArrayExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - -#if LOGSEMANTIC - printf("ArrayExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - t1 = e1->type->toBasetype(); - if (t1->ty != Tclass && t1->ty != Tstruct) - { // Convert to IndexExp - if (arguments->dim != 1) - error("only one index allowed to index %s", t1->toChars()); - e = new IndexExp(loc, e1, (Expression *)arguments->data[0]); - return e->semantic(sc); - } - - // Run semantic() on each argument - for (size_t i = 0; i < arguments->dim; i++) - { e = (Expression *)arguments->data[i]; - - e = e->semantic(sc); - if (!e->type) - error("%s has no value", e->toChars()); - arguments->data[i] = (void *)e; - } - - expandTuples(arguments); - assert(arguments && arguments->dim); - - e = op_overload(sc); - if (!e) - { error("no [] operator overload for type %s", e1->type->toChars()); - e = e1; - } - return e; -} - - -int ArrayExp::isLvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - return 0; - return 1; -} - -Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) -{ - if (type && type->toBasetype()->ty == Tvoid) - error("voids have no value"); - return this; -} - - -void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(']'); -} - -/************************* DotExp ***********************************/ - -DotExp::DotExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2) -{ -} - -Expression *DotExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotExp::semantic('%s')\n", toChars()); - if (type) printf("\ttype = %s\n", type->toChars()); -#endif - e1 = e1->semantic(sc); - e2 = e2->semantic(sc); - if (e2->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)e2; - TemplateDeclaration *td = se->sds->isTemplateDeclaration(); - if (td) - { Expression *e = new DotTemplateExp(loc, e1, td); - e = e->semantic(sc); - return e; - } - } - if (!type) - type = e2->type; - return this; -} - - -/************************* CommaExp ***********************************/ - -CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2) -{ -} - -Expression *CommaExp::semantic(Scope *sc) -{ - if (!type) - { BinExp::semanticp(sc); - type = e2->type; - } - return this; -} - -void CommaExp::checkEscape() -{ - e2->checkEscape(); -} - -int CommaExp::isLvalue() -{ - return e2->isLvalue(); -} - -Expression *CommaExp::toLvalue(Scope *sc, Expression *e) -{ - e2 = e2->toLvalue(sc, NULL); - return this; -} - -Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) -{ - e2 = e2->modifiableLvalue(sc, e); - return this; -} - -int CommaExp::isBool(int result) -{ - return e2->isBool(result); -} - -int CommaExp::checkSideEffect(int flag) -{ - if (flag == 2) - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - else - { - // Don't check e1 until we cast(void) the a,b code generation - return e2->checkSideEffect(flag); - } -} - -/************************** IndexExp **********************************/ - -// e1 [ e2 ] - -IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2) -{ - //printf("IndexExp::IndexExp('%s')\n", toChars()); - lengthVar = NULL; - modifiable = 0; // assume it is an rvalue -} - -Expression *IndexExp::semantic(Scope *sc) -{ Expression *e; - BinExp *b; - UnaExp *u; - Type *t1; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("IndexExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - if (!e1->type) - e1 = e1->semantic(sc); - assert(e1->type); // semantic() should already be run on it - e = this; - - // Note that unlike C we do not implement the int[ptr] - - t1 = e1->type->toBasetype(); - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - { // Create scope for 'length' variable - sym = new ArrayScopeSymbol(sc, this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - } - - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - e2->type = Type::terror; - } - e2 = resolveProperties(sc, e2); - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - sc = sc->pop(); - - switch (t1->ty) - { - case Tpointer: - case Tarray: - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e->type = ((TypeNext *)t1)->next; - break; - - case Tsarray: - { - e2 = e2->implicitCastTo(sc, Type::tsize_t); - - TypeSArray *tsa = (TypeSArray *)t1; - -#if 0 // Don't do now, because it might be short-circuit evaluated - // Do compile time array bounds checking if possible - e2 = e2->optimize(WANTvalue); - if (e2->op == TOKint64) - { - integer_t index = e2->toInteger(); - integer_t length = tsa->dim->toInteger(); - if (index < 0 || index >= length) - error("array index [%lld] is outside array bounds [0 .. %lld]", - index, length); - } -#endif - e->type = t1->nextOf(); - break; - } - - case Taarray: - { TypeAArray *taa = (TypeAArray *)t1; - - e2 = e2->implicitCastTo(sc, taa->index); // type checking - type = taa->next; - break; - } - - case Ttuple: - { - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e2 = e2->optimize(WANTvalue | WANTinterpret); - uinteger_t index = e2->toUInteger(); - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) - { - tup = (TypeTuple *)t1; - length = Argument::dim(tup->arguments); - } - else - assert(0); - - if (index < length) - { - - if (e1->op == TOKtuple) - e = (Expression *)te->exps->data[(size_t)index]; - else - e = new TypeExp(e1->loc, Argument::getNth(tup->arguments, (size_t)index)->type); - } - else - { - error("array index [%llu] is outside array bounds [0 .. %"PRIuSIZE"]", - index, length); - e = e1; - } - break; - } - - default: - error("%s must be an array or pointer type, not %s", - e1->toChars(), e1->type->toChars()); - type = Type::tint32; - break; - } - return e; -} - -int IndexExp::isLvalue() -{ - return 1; -} - -Expression *IndexExp::toLvalue(Scope *sc, Expression *e) -{ -// if (type && type->toBasetype()->ty == Tvoid) -// error("voids have no value"); - return this; -} - -Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); - modifiable = 1; - if (e1->op == TOKstring) - error("string literals are immutable"); - if (type && !type->isMutable()) - error("%s isn't mutable", e->toChars()); - if (e1->type->toBasetype()->ty == Taarray) - e1 = e1->modifiableLvalue(sc, e1); - return toLvalue(sc, e); -} - -void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - expToCBuffer(buf, hgs, e2, PREC_assign); - buf->writeByte(']'); -} - - -/************************* PostExp ***********************************/ - -PostExp::PostExp(enum TOK op, Loc loc, Expression *e) - : BinExp(loc, op, sizeof(PostExp), e, - new IntegerExp(loc, 1, Type::tint32)) -{ -} - -Expression *PostExp::semantic(Scope *sc) -{ Expression *e = this; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e = this; - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer) - e = scaleFactor(sc); - else - e2 = e2->castTo(sc, e1->type); - e->type = e1->type; - } - return e; -} - -void PostExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writestring((op == TOKplusplus) ? (char *)"++" : (char *)"--"); -} - -/************************************************************/ - -/* op can be TOKassign, TOKconstruct, or TOKblit */ - -AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) -{ - ismemset = 0; -} - -Expression *AssignExp::semantic(Scope *sc) -{ - Expression *e1old = e1; - -#if LOGSEMANTIC - printf("AssignExp::semantic('%s')\n", toChars()); -#endif - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); - //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op)); - - if (type) - return this; - - if (e2->op == TOKcomma) - { /* Rewrite to get rid of the comma from rvalue - */ - AssignExp *ea = new AssignExp(loc, e1, ((CommaExp *)e2)->e2); - ea->op = op; - Expression *e = new CommaExp(loc, ((CommaExp *)e2)->e1, ea); - return e->semantic(sc); - } - - /* Look for operator overloading of a[i]=value. - * Do it before semantic() otherwise the a[i] will have been - * converted to a.opIndex() already. - */ - if (e1->op == TOKarray) - { - ArrayExp *ae = (ArrayExp *)e1; - AggregateDeclaration *ad; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - Type *t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L1; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L1: - // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) - if (search_function(ad, Id::indexass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); - Expressions *a = (Expressions *)ae->arguments->copy(); - - a->insert(0, e2); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite (a[i] = value) to (a.opIndex(i, value)) - if (search_function(ad, id)) - { Expression *e = new DotIdExp(loc, ae->e1, id); - - if (1 || !global.params.useDeprecated) - error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); - - e = new CallExp(loc, e, (Expression *)ae->arguments->data[0], e2); - e = e->semantic(sc); - return e; - } - } - } - } - /* Look for operator overloading of a[i..j]=value. - * Do it before semantic() otherwise the a[i..j] will have been - * converted to a.opSlice() already. - */ - if (e1->op == TOKslice) - { Type *t1; - SliceExp *ae = (SliceExp *)e1; - AggregateDeclaration *ad; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - ae->e1 = resolveProperties(sc, ae->e1); - t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L2; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L2: - // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j)) - if (search_function(ad, Id::sliceass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); - Expressions *a = new Expressions(); - - a->push(e2); - if (ae->lwr) - { a->push(ae->lwr); - assert(ae->upr); - a->push(ae->upr); - } - else - assert(!ae->upr); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - } - } - - BinExp::semantic(sc); - - if (e1->op == TOKdottd) - { // Rewrite a.b=e2, when b is a template, as a.b(e2) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; - } - - e2 = resolveProperties(sc, e2); - assert(e1->type); - - /* Rewrite tuple assignment as a tuple of assignments. - */ - if (e1->op == TOKtuple && e2->op == TOKtuple) - { TupleExp *tup1 = (TupleExp *)e1; - TupleExp *tup2 = (TupleExp *)e2; - size_t dim = tup1->exps->dim; - if (dim != tup2->exps->dim) - { - error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); - } - else - { Expressions *exps = new Expressions; - exps->setDim(dim); - - for (int i = 0; i < dim; i++) - { Expression *ex1 = (Expression *)tup1->exps->data[i]; - Expression *ex2 = (Expression *)tup2->exps->data[i]; - exps->data[i] = (void *) new AssignExp(loc, ex1, ex2); - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - } - - Type *t1 = e1->type->toBasetype(); - - if (t1->ty == Tfunction) - { // Rewrite f=value to f(value) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; - } - - /* If it is an assignment from a 'foreign' type, - * check for operator overloading. - */ - if (t1->ty == Tstruct) - { - StructDeclaration *sd = ((TypeStruct *)t1)->sym; - if (op == TOKassign) - { - Expression *e = op_overload(sc); - if (e) - return e; - } - else if (op == TOKconstruct) - { Type *t2 = e2->type->toBasetype(); - if (t2->ty == Tstruct && - sd == ((TypeStruct *)t2)->sym && - sd->cpctor) - { /* We have a copy constructor for this - */ - if (e2->op == TOKvar || e2->op == TOKstar) - { /* Write as: - * e1.cpctor(e2); - */ - Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); - e = new CallExp(loc, e, e2); - return e->semantic(sc); - } - else if (e2->op == TOKquestion) - { /* Write as: - * a ? e1 = b : e1 = c; - */ - CondExp *ec = (CondExp *)e2; - AssignExp *ea1 = new AssignExp(ec->e1->loc, e1, ec->e1); - ea1->op = op; - AssignExp *ea2 = new AssignExp(ec->e1->loc, e1, ec->e2); - ea2->op = op; - Expression *e = new CondExp(loc, ec->econd, ea1, ea2); - return e->semantic(sc); - } - } - } - } - else if (t1->ty == Tclass) - { // Disallow assignment operator overloads for same type - if (!e2->type->implicitConvTo(e1->type)) - { - Expression *e = op_overload(sc); - if (e) - return e; - } - } - - if (t1->ty == Tsarray) - { // Convert e1 to e1[] - Expression *e = new SliceExp(e1->loc, e1, NULL, NULL); - e1 = e->semantic(sc); - t1 = e1->type->toBasetype(); - } - - e2->rvalue(); - - if (e1->op == TOKarraylength) - { - // e1 is not an lvalue, but we let code generator handle it - ArrayLengthExp *ale = (ArrayLengthExp *)e1; - - ale->e1 = ale->e1->modifiableLvalue(sc, e1); - } - else if (e1->op == TOKslice) - { - Type *tn = e1->type->nextOf(); - if (tn && !tn->isMutable() && op != TOKconstruct) - error("slice %s is not mutable", e1->toChars()); - } - else - { // Try to do a decent error message with the expression - // before it got constant folded - if (e1->op != TOKvar) - e1 = e1->optimize(WANTvalue); - - if (op != TOKconstruct) - e1 = e1->modifiableLvalue(sc, e1old); - } - - Type *t2 = e2->type; - if (e1->op == TOKslice && - t1->nextOf() && - e2->implicitConvTo(t1->nextOf()) - ) - { // memset - ismemset = 1; // make it easy for back end to tell what this is - e2 = e2->implicitCastTo(sc, t1->nextOf()); - } - else if (t1->ty == Tsarray) - { - /* Should have already converted e1 => e1[] - */ - assert(0); - //error("cannot assign to static array %s", e1->toChars()); - } - else if (e1->op == TOKslice) - { - e2 = e2->implicitCastTo(sc, e1->type->constOf()); - } - else - { - e2 = e2->implicitCastTo(sc, e1->type); - } - - /* Look for array operations - */ - if (e1->op == TOKslice && !ismemset && - (e2->op == TOKadd || e2->op == TOKmin || - e2->op == TOKmul || e2->op == TOKdiv || - e2->op == TOKmod || e2->op == TOKxor || - e2->op == TOKand || e2->op == TOKor || - e2->op == TOKtilde || e2->op == TOKneg)) - { - type = e1->type; - return arrayOp(sc); - } - - type = e1->type; - assert(type); - return this; -} - -Expression *AssignExp::checkToBoolean() -{ - // Things like: - // if (a = b) ... - // are usually mistakes. - - error("'=' does not give a boolean result"); - return this; -} - -/************************************************************/ - -AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2) -{ -} - -Expression *AddAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if (e1->op == TOKslice) - { - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - else - { - e1 = e1->modifiableLvalue(sc, e1); - } - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - typeCombine(sc); - e = this; - } - else - { - e1->checkScalar(); - e1->checkNoBool(); - if (tb1->ty == Tpointer && tb2->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tbit || tb1->ty == Tbool) - { -#if 0 - // Need to rethink this - if (e1->op != TOKvar) - { // Rewrite e1+=e2 to (v=&e1),*v=*v+e2 - VarDeclaration *v; - Expression *ea; - Expression *ex; - - Identifier *id = Lexer::uniqueId("__name"); - - v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - - ea = new AddrExp(loc, e1); - ea = new AssignExp(loc, new VarExp(loc, v), ea); - - ex = new VarExp(loc, v); - ex = new PtrExp(loc, ex); - e = new AddExp(loc, ex, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, ex->syntaxCopy(), e); - - e = new CommaExp(loc, ea, e); - } - else -#endif - { // Rewrite e1+=e2 to e1=e1+e2 - // BUG: doesn't account for side effects in e1 - // BUG: other assignment operators for bits aren't handled at all - e = new AddExp(loc, e1, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, e1->syntaxCopy(), e); - } - e = e->semantic(sc); - } - else - { - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (type->isreal() || type->isimaginary()) - { - assert(global.errors || e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - } - return e; -} - -/************************************************************/ - -MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2) -{ -} - -Expression *MinAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] -= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer && e2->type->isintegral()) - e = scaleFactor(sc); - else - { - e1 = e1->checkArithmetic(); - e2 = e2->checkArithmetic(); - type = e1->type; - typeCombine(sc); - if (type->isreal() || type->isimaginary()) - { - assert(e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - return e; -} - -/************************************************************/ - -CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2) -{ -} - -Expression *CatAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { SliceExp *se = (SliceExp *)e1; - - if (se->e1->type->toBasetype()->ty == Tsarray) - error("cannot append to static array %s", se->e1->type->toChars()); - } - - e1 = e1->modifiableLvalue(sc, e1); - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - e2->rvalue(); - - if ((tb1->ty == Tarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - (e2->implicitConvTo(e1->type) || - tb2->nextOf()->implicitConvTo(tb1->nextOf())) - ) - { // Append array - e2 = e2->castTo(sc, e1->type); - type = e1->type; - e = this; - } - else if ((tb1->ty == Tarray) && - e2->implicitConvTo(tb1->nextOf()) - ) - { // Append element - e2 = e2->castTo(sc, tb1->nextOf()); - type = e1->type; - e = this; - } - else - { - error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars()); - type = Type::tint32; - e = this; - } - return e; -} - -/************************************************************/ - -MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2) -{ -} - -Expression *MulAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] -= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (e2->type->isfloating()) - { Type *t1; - Type *t2; - - t1 = e1->type; - t2 = e2->type; - if (t1->isreal()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - e2 = e2->castTo(sc, t1); - } - } - else if (t1->isimaginary()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - } - } - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - return this; -} - -/************************************************************/ - -DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2) -{ -} - -Expression *DivAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] -= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (e2->type->isimaginary()) - { Type *t1; - Type *t2; - - t1 = e1->type; - if (t1->isreal()) - { // x/iv = i(-x/v) - // Therefore, the result is 0 - e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1)); - e2->type = t1; - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - else if (t1->isimaginary()) - { Expression *e; - - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - } - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - - return this; -} - -/************************************************************/ - -ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2) -{ -} - -Expression *ModAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssign(sc); -} - -/************************************************************/ - -ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2) -{ -} - -Expression *ShlAssignExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlAssignExp::semantic()\n"); - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - return this; -} - -/************************************************************/ - -ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2) -{ -} - -Expression *ShrAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - return this; -} - -/************************************************************/ - -UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2) -{ -} - -Expression *UshrAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - return this; -} - -/************************************************************/ - -AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2) -{ -} - -Expression *AndAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2) -{ -} - -Expression *OrAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2) -{ -} - -Expression *XorAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************* AddExp *****************************/ - -AddExp::AddExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2) -{ -} - -Expression *AddExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("AddExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - e = this; - } - else if (tb1->ty == Tpointer && e2->type->isintegral() || - tb2->ty == Tpointer && e1->type->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tpointer && tb2->ty == Tpointer) - { - incompatibleTypes(); - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if ((e1->type->isreal() && e2->type->isimaginary()) || - (e1->type->isimaginary() && e2->type->isreal())) - { - switch (type->toBasetype()->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - e = this; - } - return e; - } - return this; -} - -/************************************************************/ - -MinExp::MinExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2) -{ -} - -Expression *MinExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - -#if LOGSEMANTIC - printf("MinExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - e = this; - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if (t1->ty == Tpointer) - { - if (t2->ty == Tpointer) - { // Need to divide the result by the stride - // Replace (ptr - ptr) with (ptr - ptr) / stride - d_int64 stride; - Expression *e; - - typeCombine(sc); // make sure pointer types are compatible - type = Type::tptrdiff_t; - stride = t2->nextOf()->size(); - if (stride == 0) - { - e = new IntegerExp(loc, 0, Type::tptrdiff_t); - } - else - { - e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t)); - e->type = Type::tptrdiff_t; - } - return e; - } - else if (t2->isintegral()) - e = scaleFactor(sc); - else - { error("incompatible types for minus"); - return new IntegerExp(0); - } - } - else if (t2->ty == Tpointer) - { - type = e2->type; - error("can't subtract pointer from %s", e1->type->toChars()); - return new IntegerExp(0); - } - else - { - typeCombine(sc); - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->isreal() && t2->isimaginary()) || - (t1->isimaginary() && t2->isreal())) - { - switch (type->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - } - return e; -} - -/************************* CatExp *****************************/ - -CatExp::CatExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2) -{ -} - -Expression *CatExp::semantic(Scope *sc) -{ Expression *e; - - //printf("CatExp::semantic() %s\n", toChars()); - if (!type) - { - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - - /* BUG: Should handle things like: - * char c; - * c ~ ' ' - * ' ' ~ c; - */ - -#if 0 - e1->type->print(); - e2->type->print(); -#endif - if ((tb1->ty == Tsarray || tb1->ty == Tarray) && - e2->type->implicitConvTo(tb1->nextOf()) >= MATCHconst) - { - type = tb1->nextOf()->arrayOf(); - if (tb2->ty == Tarray) - { // Make e2 into [e2] - e2 = new ArrayLiteralExp(e2->loc, e2); - e2->type = type; - } - return this; - } - else if ((tb2->ty == Tsarray || tb2->ty == Tarray) && - e1->type->implicitConvTo(tb2->nextOf()) >= MATCHconst) - { - type = tb2->nextOf()->arrayOf(); - if (tb1->ty == Tarray) - { // Make e1 into [e1] - e1 = new ArrayLiteralExp(e1->loc, e1); - e1->type = type; - } - return this; - } - - if ((tb1->ty == Tsarray || tb1->ty == Tarray) && - (tb2->ty == Tsarray || tb2->ty == Tarray) && - (tb1->nextOf()->mod || tb2->nextOf()->mod) && - (tb1->nextOf()->mod != tb2->nextOf()->mod) - ) - { - Type *t1 = tb1->nextOf()->mutableOf()->constOf()->arrayOf(); - Type *t2 = tb2->nextOf()->mutableOf()->constOf()->arrayOf(); - if (e1->op == TOKstring && !((StringExp *)e1)->committed) - e1->type = t1; - else - e1 = e1->castTo(sc, t1); - if (e2->op == TOKstring && !((StringExp *)e2)->committed) - e2->type = t2; - else - e2 = e2->castTo(sc, t2); - } - - typeCombine(sc); - type = type->toHeadMutable(); - - Type *tb = type->toBasetype(); - if (tb->ty == Tsarray) - type = tb->nextOf()->arrayOf(); - if (type->ty == Tarray && tb1->nextOf() && tb2->nextOf() && - tb1->nextOf()->mod != tb2->nextOf()->mod) - { - type = type->nextOf()->toHeadMutable()->arrayOf(); - } -#if 0 - e1->type->print(); - e2->type->print(); - type->print(); - print(); -#endif - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (e1->op == TOKstring && e2->op == TOKstring) - e = optimize(WANTvalue); - else if ((t1->ty == Tarray || t1->ty == Tsarray) && - (t2->ty == Tarray || t2->ty == Tsarray)) - { - e = this; - } - else - { - //printf("(%s) ~ (%s)\n", e1->toChars(), e2->toChars()); - error("Can only concatenate arrays, not (%s ~ %s)", - e1->type->toChars(), e2->type->toChars()); - type = Type::tint32; - e = this; - } - e->type = e->type->semantic(loc, sc); - return e; - } - return this; -} - -/************************************************************/ - -MulExp::MulExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2) -{ -} - -Expression *MulExp::semantic(Scope *sc) -{ Expression *e; - -#if 0 - printf("MulExp::semantic() %s\n", toChars()); -#endif - if (type) - { - return this; - } - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkArithmetic(); - e2->checkArithmetic(); - } - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { Expression *e; - - switch (t1->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - - // iy * iv = -yv - e1->type = type; - e2->type = type; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -DivExp::DivExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2) -{ -} - -Expression *DivExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkArithmetic(); - e2->checkArithmetic(); - } - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - if (t2->isimaginary()) - { Expression *e; - - // x/iv = i(-x/v) - e2->type = t1; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { - switch (t1->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -ModExp::ModExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2) -{ -} - -Expression *ModExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkArithmetic(); - e2->checkArithmetic(); - } - if (type->isfloating()) - { type = e1->type; - if (e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new IntegerExp(0); - } - } - return this; -} - -/************************************************************/ - -ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2) -{ -} - -Expression *ShlExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlExp::semantic(), type = %p\n", type); - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2) -{ -} - -Expression *ShrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2) -{ -} - -Expression *UshrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -AndExp::AndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKand, sizeof(AndExp), e1, e2) -{ -} - -Expression *AndExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkIntegral(); - e2->checkIntegral(); - } - } - } - return this; -} - -/************************************************************/ - -OrExp::OrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKor, sizeof(OrExp), e1, e2) -{ -} - -Expression *OrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkIntegral(); - e2->checkIntegral(); - } - } - } - return this; -} - -/************************************************************/ - -XorExp::XorExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2) -{ -} - -Expression *XorExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkIntegral(); - e2->checkIntegral(); - } - } - } - return this; -} - - -/************************************************************/ - -OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2) -{ -} - -Expression *OrOrExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for AndAnd - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(TRUE)) - { - return new IntegerExp(loc, 1, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - type = Type::tboolean; - if (e1->type->ty == Tvoid) - type = Type::tvoid; - if (e2->op == TOKtype || e2->op == TOKimport) - error("%s is not an expression", e2->toChars()); - return this; -} - -Expression *OrOrExp::checkToBoolean() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int OrOrExp::isBit() -{ - return TRUE; -} - -int OrOrExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - } - else - { e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2) -{ -} - -Expression *AndAndExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for OrOr - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(FALSE)) - { - return new IntegerExp(loc, 0, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - type = Type::tboolean; - if (e1->type->ty == Tvoid) - type = Type::tvoid; - if (e2->op == TOKtype || e2->op == TOKimport) - error("%s is not an expression", e2->toChars()); - return this; -} - -Expression *AndAndExp::checkToBoolean() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int AndAndExp::isBit() -{ - return TRUE; -} - -int AndAndExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - } - else - { - e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -InExp::InExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKin, sizeof(InExp), e1, e2) -{ -} - -Expression *InExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - //type = Type::tboolean; - Type *t2b = e2->type->toBasetype(); - if (t2b->ty != Taarray) - { - error("rvalue of in expression must be an associative array, not %s", e2->type->toChars()); - type = Type::terror; - } - else - { - TypeAArray *ta = (TypeAArray *)t2b; - - // Convert key to type of key - e1 = e1->implicitCastTo(sc, ta->index); - - // Return type is pointer to value - type = ta->nextOf()->pointerTo(); - } - return this; -} - -int InExp::isBit() -{ - return FALSE; -} - - -/************************************************************/ - -/* This deletes the key e1 from the associative array e2 - */ - -RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) -{ - type = Type::tvoid; -} - -/************************************************************/ - -CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(CmpExp), e1, e2) -{ -} - -Expression *CmpExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - -#if LOGSEMANTIC - printf("CmpExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - - if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || - e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) - { - error("do not use null when comparing class types"); - } - - e = op_overload(sc); - if (e) - { - e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32)); - e = e->semantic(sc); - return e; - } - - typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && - (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) - { - if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && - t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && - (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) - error("array comparison type mismatch, %s vs %s", t1->nextOf()->toChars(), t2->nextOf()->toChars()); - e = this; - } - else if (t1->ty == Tstruct || t2->ty == Tstruct || - (t1->ty == Tclass && t2->ty == Tclass)) - { - if (t2->ty == Tstruct) - error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars()); - else - error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars()); - e = this; - } -#if 1 - else if (t1->iscomplex() || t2->iscomplex()) - { - error("compare not defined for complex operands"); - e = new IntegerExp(0); - } -#endif - else - e = this; - //printf("CmpExp: %s\n", e->toChars()); - return e; -} - -int CmpExp::isBit() -{ - return TRUE; -} - - -/************************************************************/ - -EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(EqualExp), e1, e2) -{ - assert(op == TOKequal || op == TOKnotequal); -} - -Expression *EqualExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - - //printf("EqualExp::semantic('%s')\n", toChars()); - if (type) - return this; - - BinExp::semanticp(sc); - - /* Before checking for operator overloading, check to see if we're - * comparing the addresses of two statics. If so, we can just see - * if they are the same symbol. - */ - if (e1->op == TOKaddress && e2->op == TOKaddress) - { AddrExp *ae1 = (AddrExp *)e1; - AddrExp *ae2 = (AddrExp *)e2; - - if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) - { VarExp *ve1 = (VarExp *)ae1->e1; - VarExp *ve2 = (VarExp *)ae2->e1; - - if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) - { - // They are the same, result is 'true' for ==, 'false' for != - e = new IntegerExp(loc, (op == TOKequal), Type::tboolean); - return e; - } - } - } - - if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || - e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) - { - error("use '%s' instead of '%s' when comparing with null", - Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity), - Token::toChars(op)); - } - - //if (e2->op != TOKnull) - { - e = op_overload(sc); - if (e) - { - if (op == TOKnotequal) - { - e = new NotExp(e->loc, e); - e = e->semantic(sc); - } - return e; - } - } - - e = typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - - if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && - (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) - { - if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && - t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && - (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) - error("array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars()); - } - else - { - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - } - return e; -} - -int EqualExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -IdentityExp::IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(IdentityExp), e1, e2) -{ -} - -Expression *IdentityExp::semantic(Scope *sc) -{ - if (type) - return this; - - BinExp::semanticp(sc); - type = Type::tboolean; - typeCombine(sc); - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - return this; -} - -int IdentityExp::isBit() -{ - return TRUE; -} - - -/****************************************************************/ - -CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2) - : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2) -{ - this->econd = econd; -} - -Expression *CondExp::syntaxCopy() -{ - return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy()); -} - - -Expression *CondExp::semantic(Scope *sc) -{ Type *t1; - Type *t2; - unsigned cs0; - unsigned cs1; - -#if LOGSEMANTIC - printf("CondExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - econd = econd->semantic(sc); - econd = resolveProperties(sc, econd); - econd = econd->checkToPointer(); - econd = econd->checkToBoolean(); - -#if 0 /* this cannot work right because the types of e1 and e2 - * both contribute to the type of the result. - */ - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate what we don't have to. - */ - econd = econd->optimize(WANTflags); - if (econd->isBool(TRUE)) - { - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - return e1; - } - else if (econd->isBool(FALSE)) - { - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - return e2; - } - } -#endif - - - cs0 = sc->callSuper; - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - cs1 = sc->callSuper; - sc->callSuper = cs0; - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - sc->mergeCallSuper(loc, cs1); - - - // If either operand is void, the result is void - t1 = e1->type; - t2 = e2->type; - if (t1->ty == Tvoid || t2->ty == Tvoid) - type = Type::tvoid; - else if (t1 == t2) - type = t1; - else - { - typeCombine(sc); - switch (e1->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e2 = e2->castTo(sc, e1->type); - break; - } - switch (e2->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e1 = e1->castTo(sc, e2->type); - break; - } - if (type->toBasetype()->ty == Tarray) - { - e1 = e1->castTo(sc, type); - e2 = e2->castTo(sc, type); - } - } -#if 0 - printf("res: %s\n", type->toChars()); - printf("e1 : %s\n", e1->type->toChars()); - printf("e2 : %s\n", e2->type->toChars()); -#endif - return this; -} - -int CondExp::isLvalue() -{ - return e1->isLvalue() && e2->isLvalue(); -} - -Expression *CondExp::toLvalue(Scope *sc, Expression *ex) -{ - PtrExp *e; - - // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) - e = new PtrExp(loc, this, type); - - e1 = e1->addressOf(sc); - //e1 = e1->toLvalue(sc, NULL); - - e2 = e2->addressOf(sc); - //e2 = e2->toLvalue(sc, NULL); - - typeCombine(sc); - - type = e2->type; - return e; -} - -Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("conditional expression %s is not a modifiable lvalue", toChars()); - return this; -} - -void CondExp::checkEscape() -{ - e1->checkEscape(); - e2->checkEscape(); -} - - -Expression *CondExp::checkToBoolean() -{ - e1 = e1->checkToBoolean(); - e2 = e2->checkToBoolean(); - return this; -} - -int CondExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return econd->checkSideEffect(2) || - e1->checkSideEffect(2) || - e2->checkSideEffect(2); - } - else - { - econd->checkSideEffect(1); - e1->checkSideEffect(flag); - return e2->checkSideEffect(flag); - } -} - -int CondExp::canThrow() -{ - return econd->canThrow() || e1->canThrow() || e2->canThrow(); -} - - -void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, econd, PREC_oror); - buf->writestring(" ? "); - expToCBuffer(buf, hgs, e1, PREC_expr); - buf->writestring(" : "); - expToCBuffer(buf, hgs, e2, PREC_cond); -} - - -/****************************************************************/ - -DefaultInitExp::DefaultInitExp(Loc loc, enum TOK subop, int size) - : Expression(loc, TOKdefault, size) -{ - this->subop = subop; -} - -void DefaultInitExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(subop)); -} - -/****************************************************************/ - -FileInitExp::FileInitExp(Loc loc) - : DefaultInitExp(loc, TOKfile, sizeof(FileInitExp)) -{ -} - -Expression *FileInitExp::semantic(Scope *sc) -{ - //printf("FileInitExp::semantic()\n"); - type = Type::tchar->invariantOf()->arrayOf(); - return this; -} - -Expression *FileInitExp::resolve(Loc loc, Scope *sc) -{ - //printf("FileInitExp::resolve() %s\n", toChars()); - char *s = loc.filename ? loc.filename : sc->module->ident->toChars(); - Expression *e = new StringExp(loc, s); - e = e->semantic(sc); - e = e->castTo(sc, type); - return e; -} - -/****************************************************************/ - -LineInitExp::LineInitExp(Loc loc) - : DefaultInitExp(loc, TOKline, sizeof(LineInitExp)) -{ -} - -Expression *LineInitExp::semantic(Scope *sc) -{ - type = Type::tint32; - return this; -} - -Expression *LineInitExp::resolve(Loc loc, Scope *sc) -{ - Expression *e = new IntegerExp(loc, loc.linnum, Type::tint32); - e = e->castTo(sc, type); - return e; -} - -/****************************************************************/ -/****************************************************************/ -/****************************************************************/ - -#if IN_LLVM - -// Strictly LDC specific stuff - -GEPExp::GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx) - : UnaExp(loc, TOKgep, sizeof(GEPExp), e) -{ - index = idx; - ident = id; -} - -void GEPExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -Expression* GEPExp::toLvalue(Scope* sc, Expression* e) -{ - // GEP's are always lvalues, at least in the "LLVM sense" ... - return this; -} - -#endif - -/****************************************************************/ -/****************************************************************/ -/****************************************************************/ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include +#include +#include +#include +#if _MSC_VER +#include +#else +#if IN_DMD +#include +#endif +#endif + +#if _WIN32 && __DMC__ +extern "C" char * __cdecl __locale_decpoint; +#endif + +#if __MINGW32__ +#ifndef isnan +#define isnan _isnan +#endif +#endif + +#ifdef __APPLE__ +#ifndef isnan +int isnan(double); +#endif +#endif + +#include "rmem.h" +#if IN_DMD +#include "port.h" +#endif +#include "mtype.h" +#include "init.h" +#include "expression.h" +#include "template.h" +#include "utf.h" +#include "enum.h" +#include "scope.h" +#include "statement.h" +#include "declaration.h" +#include "aggregate.h" +#include "import.h" +#include "id.h" +#include "dsymbol.h" +#include "module.h" +#include "attrib.h" +#include "hdrgen.h" +#include "parse.h" + +#if IN_DMD +Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim); +#endif +Expression *expandVar(int result, VarDeclaration *v); + +#define LOGSEMANTIC 0 + +/********************************** + * Set operator precedence for each operator. + */ + +// Operator precedence - greater values are higher precedence + +enum PREC +{ + PREC_zero, + PREC_expr, + PREC_assign, + PREC_cond, + PREC_oror, + PREC_andand, + PREC_or, + PREC_xor, + PREC_and, + PREC_equal, + PREC_rel, + PREC_shift, + PREC_add, + PREC_mul, + PREC_unary, + PREC_primary, +}; + +enum PREC precedence[TOKMAX]; + +void initPrecedence() +{ + precedence[TOKdotvar] = PREC_primary; + precedence[TOKimport] = PREC_primary; + precedence[TOKidentifier] = PREC_primary; + precedence[TOKthis] = PREC_primary; + precedence[TOKsuper] = PREC_primary; + precedence[TOKint64] = PREC_primary; + precedence[TOKfloat64] = PREC_primary; + precedence[TOKnull] = PREC_primary; + precedence[TOKstring] = PREC_primary; + precedence[TOKarrayliteral] = PREC_primary; + precedence[TOKtypeid] = PREC_primary; + precedence[TOKis] = PREC_primary; + precedence[TOKassert] = PREC_primary; + precedence[TOKfunction] = PREC_primary; + precedence[TOKvar] = PREC_primary; +#if DMDV2 + precedence[TOKdefault] = PREC_primary; +#endif + + // post + precedence[TOKdotti] = PREC_primary; + precedence[TOKdot] = PREC_primary; +// precedence[TOKarrow] = PREC_primary; + precedence[TOKplusplus] = PREC_primary; + precedence[TOKminusminus] = PREC_primary; + precedence[TOKcall] = PREC_primary; + precedence[TOKslice] = PREC_primary; + precedence[TOKarray] = PREC_primary; + + precedence[TOKaddress] = PREC_unary; + precedence[TOKstar] = PREC_unary; + precedence[TOKneg] = PREC_unary; + precedence[TOKuadd] = PREC_unary; + precedence[TOKnot] = PREC_unary; + precedence[TOKtobool] = PREC_add; + precedence[TOKtilde] = PREC_unary; + precedence[TOKdelete] = PREC_unary; + precedence[TOKnew] = PREC_unary; + precedence[TOKcast] = PREC_unary; + + precedence[TOKmul] = PREC_mul; + precedence[TOKdiv] = PREC_mul; + precedence[TOKmod] = PREC_mul; + + precedence[TOKadd] = PREC_add; + precedence[TOKmin] = PREC_add; + precedence[TOKcat] = PREC_add; + + precedence[TOKshl] = PREC_shift; + precedence[TOKshr] = PREC_shift; + precedence[TOKushr] = PREC_shift; + + precedence[TOKlt] = PREC_rel; + precedence[TOKle] = PREC_rel; + precedence[TOKgt] = PREC_rel; + precedence[TOKge] = PREC_rel; + precedence[TOKunord] = PREC_rel; + precedence[TOKlg] = PREC_rel; + precedence[TOKleg] = PREC_rel; + precedence[TOKule] = PREC_rel; + precedence[TOKul] = PREC_rel; + precedence[TOKuge] = PREC_rel; + precedence[TOKug] = PREC_rel; + precedence[TOKue] = PREC_rel; + precedence[TOKin] = PREC_rel; + +#if 0 + precedence[TOKequal] = PREC_equal; + precedence[TOKnotequal] = PREC_equal; + precedence[TOKidentity] = PREC_equal; + precedence[TOKnotidentity] = PREC_equal; +#else + /* Note that we changed precedence, so that < and != have the same + * precedence. This change is in the parser, too. + */ + precedence[TOKequal] = PREC_rel; + precedence[TOKnotequal] = PREC_rel; + precedence[TOKidentity] = PREC_rel; + precedence[TOKnotidentity] = PREC_rel; +#endif + + precedence[TOKand] = PREC_and; + + precedence[TOKxor] = PREC_xor; + + precedence[TOKor] = PREC_or; + + precedence[TOKandand] = PREC_andand; + + precedence[TOKoror] = PREC_oror; + + precedence[TOKquestion] = PREC_cond; + + precedence[TOKassign] = PREC_assign; + precedence[TOKconstruct] = PREC_assign; + precedence[TOKblit] = PREC_assign; + precedence[TOKaddass] = PREC_assign; + precedence[TOKminass] = PREC_assign; + precedence[TOKcatass] = PREC_assign; + precedence[TOKmulass] = PREC_assign; + precedence[TOKdivass] = PREC_assign; + precedence[TOKmodass] = PREC_assign; + precedence[TOKshlass] = PREC_assign; + precedence[TOKshrass] = PREC_assign; + precedence[TOKushrass] = PREC_assign; + precedence[TOKandass] = PREC_assign; + precedence[TOKorass] = PREC_assign; + precedence[TOKxorass] = PREC_assign; + + precedence[TOKcomma] = PREC_expr; +} + +/************************************************************* + * Given var, we need to get the + * right 'this' pointer if var is in an outer class, but our + * existing 'this' pointer is in an inner class. + * Input: + * e1 existing 'this' + * ad struct or class we need the correct 'this' for + * var the specific member of ad we're accessing + */ + +Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, + Expression *e1, Declaration *var) +{ + //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars()); + L1: + Type *t = e1->type->toBasetype(); + //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars()); + + /* If e1 is not the 'this' pointer for ad + */ + if (ad && + !(t->ty == Tpointer && t->nextOf()->ty == Tstruct && + ((TypeStruct *)t->nextOf())->sym == ad) + && + !(t->ty == Tstruct && + ((TypeStruct *)t)->sym == ad) + ) + { + ClassDeclaration *cd = ad->isClassDeclaration(); + ClassDeclaration *tcd = t->isClassHandle(); + + /* e1 is the right this if ad is a base class of e1 + */ + if (!cd || !tcd || + !(tcd == cd || cd->isBaseOf(tcd, NULL)) + ) + { + /* Only classes can be inner classes with an 'outer' + * member pointing to the enclosing class instance + */ + if (tcd && tcd->isNested()) + { /* e1 is the 'this' pointer for an inner class: tcd. + * Rewrite it as the 'this' pointer for the outer class. + */ + + e1 = new DotVarExp(loc, e1, tcd->vthis); + e1->type = tcd->vthis->type; + // Do not call checkNestedRef() + //e1 = e1->semantic(sc); + + // Skip up over nested functions, and get the enclosing + // class type. + int n = 0; + Dsymbol *s; + for (s = tcd->toParent(); + s && s->isFuncDeclaration(); + s = s->toParent()) + { FuncDeclaration *f = s->isFuncDeclaration(); + if (f->vthis) + { + //printf("rewriting e1 to %s's this\n", f->toChars()); + n++; + + // LDC seems dmd misses it sometimes here :/ + //f->vthis->nestedrefs = 1; + + e1 = new VarExp(loc, f->vthis); + } + } + if (s && s->isClassDeclaration()) + { e1->type = s->isClassDeclaration()->type; + if (n > 1) + e1 = e1->semantic(sc); + } + else + e1 = e1->semantic(sc); + goto L1; + } + /* Can't find a path from e1 to ad + */ + e1->error("this for %s needs to be type %s not type %s", + var->toChars(), ad->toChars(), t->toChars()); + } + } + return e1; +} + +/***************************************** + * Determine if 'this' is available. + * If it is, return the FuncDeclaration that has it. + */ + +FuncDeclaration *hasThis(Scope *sc) +{ FuncDeclaration *fd; + FuncDeclaration *fdthis; + + //printf("hasThis()\n"); + fdthis = sc->parent->isFuncDeclaration(); + //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : ""); + + // Go upwards until we find the enclosing member function + fd = fdthis; + while (1) + { + if (!fd) + { + goto Lno; + } + if (!fd->isNested()) + break; + + Dsymbol *parent = fd->parent; + while (parent) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + parent = ti->parent; + else + break; + } + + fd = fd->parent->isFuncDeclaration(); + } + + if (!fd->isThis()) + { //printf("test '%s'\n", fd->toChars()); + goto Lno; + } + + assert(fd->vthis); + return fd; + +Lno: + return NULL; // don't have 'this' available +} + + +/*************************************** + * Pull out any properties. + */ + +Expression *resolveProperties(Scope *sc, Expression *e) +{ + //printf("resolveProperties(%s)\n", e->toChars()); + if (e->type) + { + Type *t = e->type->toBasetype(); + + if (t->ty == Tfunction || e->op == TOKoverloadset) + { + e = new CallExp(e->loc, e); + e = e->semantic(sc); + } + + /* Look for e being a lazy parameter; rewrite as delegate call + */ + else if (e->op == TOKvar) + { VarExp *ve = (VarExp *)e; + + if (ve->var->storage_class & STClazy) + { + e = new CallExp(e->loc, e); + e = e->semantic(sc); + } + } + + else if (e->op == TOKdotexp) + { + e->error("expression has no value"); + } + + } + return e; +} + +/****************************** + * Perform semantic() on an array of Expressions. + */ + +void arrayExpressionSemantic(Expressions *exps, Scope *sc) +{ + if (exps) + { + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->semantic(sc); + exps->data[i] = (void *)e; + } + } +} + + +/****************************** + * Perform canThrow() on an array of Expressions. + */ + +#if DMDV2 +int arrayExpressionCanThrow(Expressions *exps) +{ + if (exps) + { + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + if (e && e->canThrow()) + return 1; + } + } + return 0; +} +#endif + +/**************************************** + * Expand tuples. + */ + +void expandTuples(Expressions *exps) +{ + //printf("expandTuples()\n"); + if (exps) + { + for (size_t i = 0; i < exps->dim; i++) + { Expression *arg = (Expression *)exps->data[i]; + if (!arg) + continue; + + // Look for tuple with 0 members + if (arg->op == TOKtype) + { TypeExp *e = (TypeExp *)arg; + if (e->type->toBasetype()->ty == Ttuple) + { TypeTuple *tt = (TypeTuple *)e->type->toBasetype(); + + if (!tt->arguments || tt->arguments->dim == 0) + { + exps->remove(i); + if (i == exps->dim) + return; + i--; + continue; + } + } + } + + // Inline expand all the tuples + while (arg->op == TOKtuple) + { TupleExp *te = (TupleExp *)arg; + + exps->remove(i); // remove arg + exps->insert(i, te->exps); // replace with tuple contents + if (i == exps->dim) + return; // empty tuple, no more arguments + arg = (Expression *)exps->data[i]; + } + } + } +} + +/**************************************** + * Preprocess arguments to function. + */ + +void preFunctionArguments(Loc loc, Scope *sc, Expressions *exps) +{ + if (exps) + { + expandTuples(exps); + + for (size_t i = 0; i < exps->dim; i++) + { Expression *arg = (Expression *)exps->data[i]; + + if (!arg->type) + { +#ifdef DEBUG + if (!global.gag) + printf("1: \n"); +#endif + arg->error("%s is not an expression", arg->toChars()); + arg = new IntegerExp(arg->loc, 0, Type::tint32); + } + + arg = resolveProperties(sc, arg); + exps->data[i] = (void *) arg; + + //arg->rvalue(); +#if 0 + if (arg->type->ty == Tfunction) + { + arg = new AddrExp(arg->loc, arg); + arg = arg->semantic(sc); + exps->data[i] = (void *) arg; + } +#endif + } + } +} + +/********************************************* + * Call copy constructor for struct value argument. + */ +#if DMDV2 +Expression *callCpCtor(Loc loc, Scope *sc, Expression *e) +{ + Type *tb = e->type->toBasetype(); + assert(tb->ty == Tstruct); + StructDeclaration *sd = ((TypeStruct *)tb)->sym; + if (sd->cpctor) + { + /* Create a variable tmp, and replace the argument e with: + * (tmp = e),tmp + * and let AssignExp() handle the construction. + * This is not the most efficent, ideally tmp would be constructed + * directly onto the stack. + */ + Identifier *idtmp = Lexer::uniqueId("__tmp"); + VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); + Expression *ae = new DeclarationExp(loc, tmp); + e = new CommaExp(loc, ae, new VarExp(loc, tmp)); + e = e->semantic(sc); + } + return e; +} +#endif + +/**************************************** + * Now that we know the exact type of the function we're calling, + * the arguments[] need to be adjusted: + * 1. implicitly convert argument to the corresponding parameter type + * 2. add default arguments for any missing arguments + * 3. do default promotions on arguments corresponding to ... + * 4. add hidden _arguments[] argument + * 5. call copy constructor for struct value arguments + */ + +void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) +{ + unsigned n; + + //printf("functionArguments()\n"); + assert(arguments); + size_t nargs = arguments ? arguments->dim : 0; + size_t nparams = Argument::dim(tf->parameters); + + if (nargs > nparams && tf->varargs == 0) + error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars()); + + n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) + + int done = 0; + for (size_t i = 0; i < n; i++) + { + Expression *arg; + + if (i < nargs) + arg = (Expression *)arguments->data[i]; + else + arg = NULL; + Type *tb; + + if (i < nparams) + { + Argument *p = Argument::getNth(tf->parameters, i); + + if (!arg) + { + if (!p->defaultArg) + { + if (tf->varargs == 2 && i + 1 == nparams) + goto L2; + error(loc, "expected %zu function arguments, not %zu", nparams, nargs); + break; + } + arg = p->defaultArg; +#if DMDV2 + if (arg->op == TOKdefault) + { DefaultInitExp *de = (DefaultInitExp *)arg; + arg = de->resolve(loc, sc); + } + else +#endif + arg = arg->copy(); + arguments->push(arg); + nargs++; + } + + if (tf->varargs == 2 && i + 1 == nparams) + { + //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); + if (arg->implicitConvTo(p->type)) + { + if (nargs != nparams) + error(loc, "expected %zu function arguments, not %zu", nparams, nargs); + goto L1; + } + L2: + Type *tb = p->type->toBasetype(); + Type *tret = p->isLazyArray(); + switch (tb->ty) + { + case Tsarray: + case Tarray: + { // Create a static array variable v of type arg->type +#ifdef IN_GCC + /* GCC 4.0 does not like zero length arrays used like + this; pass a null array value instead. Could also + just make a one-element array. */ + if (nargs - i == 0) + { + arg = new NullExp(loc); + break; + } +#endif + Identifier *id = Lexer::uniqueId("__arrayArg"); + Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i)); + t = t->semantic(loc, sc); + VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); + v->semantic(sc); + v->parent = sc->parent; + //sc->insert(v); + + Expression *c = new DeclarationExp(0, v); + c->type = v->type; + + for (size_t u = i; u < nargs; u++) + { Expression *a = (Expression *)arguments->data[u]; + if (tret && !((TypeArray *)tb)->next->equals(a->type)) + a = a->toDelegate(sc, tret); + + Expression *e = new VarExp(loc, v); + e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); + AssignExp *ae = new AssignExp(loc, e, a); +#if DMDV2 + ae->op = TOKconstruct; +#endif + if (c) + c = new CommaExp(loc, c, ae); + else + c = ae; + } + arg = new VarExp(loc, v); + if (c) + arg = new CommaExp(loc, c, arg); + break; + } + case Tclass: + { /* Set arg to be: + * new Tclass(arg0, arg1, ..., argn) + */ + Expressions *args = new Expressions(); + args->setDim(nargs - i); + for (size_t u = i; u < nargs; u++) + args->data[u - i] = arguments->data[u]; + arg = new NewExp(loc, NULL, NULL, p->type, args); + break; + } + default: + if (!arg) + { error(loc, "not enough arguments"); + return; + } + break; + } + arg = arg->semantic(sc); + //printf("\targ = '%s'\n", arg->toChars()); + arguments->setDim(i + 1); + done = 1; + } + + L1: + if (!(p->storageClass & STClazy && p->type->ty == Tvoid)) + { + if (p->type != arg->type) + { + //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars()); + arg = arg->implicitCastTo(sc, p->type); + arg = arg->optimize(WANTvalue); + } + } + if (p->storageClass & STCref) + { + arg = arg->toLvalue(sc, arg); + } + else if (p->storageClass & STCout) + { + arg = arg->modifiableLvalue(sc, arg); + } + +// LDC we don't want this! +#if !IN_LLVM + // Convert static arrays to pointers + tb = arg->type->toBasetype(); + if (tb->ty == Tsarray) + { + arg = arg->checkToPointer(); + } +#endif +#if DMDV2 + if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) + { + arg = callCpCtor(loc, sc, arg); + } +#endif + + // Convert lazy argument to a delegate + if (p->storageClass & STClazy) + { + arg = arg->toDelegate(sc, p->type); + } +#if DMDV2 + /* Look for arguments that cannot 'escape' from the called + * function. + */ + if (!tf->parameterEscapes(p)) + { + /* Function literals can only appear once, so if this + * appearance was scoped, there cannot be any others. + */ + if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + fe->fd->tookAddressOf = 0; + } + + /* For passing a delegate to a scoped parameter, + * this doesn't count as taking the address of it. + * We only worry about 'escaping' references to the function. + */ + else if (arg->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)arg; + if (de->e1->op == TOKvar) + { VarExp *ve = (VarExp *)de->e1; + FuncDeclaration *f = ve->var->isFuncDeclaration(); + if (f) + { f->tookAddressOf--; + //printf("tookAddressOf = %d\n", f->tookAddressOf); + } + } + } + } +#endif + } + else + { + + // If not D linkage, do promotions + // LDC: don't do promotions on intrinsics + if (tf->linkage != LINKd && tf->linkage != LINKintrinsic) + { + // Promote bytes, words, etc., to ints + arg = arg->integralPromotions(sc); + + // Promote floats to doubles + switch (arg->type->ty) + { + case Tfloat32: + arg = arg->castTo(sc, Type::tfloat64); + break; + + case Timaginary32: + arg = arg->castTo(sc, Type::timaginary64); + break; + } + } + + // Convert static arrays to dynamic arrays + tb = arg->type->toBasetype(); + if (tb->ty == Tsarray) + { TypeSArray *ts = (TypeSArray *)tb; + Type *ta = ts->next->arrayOf(); + if (ts->size(arg->loc) == 0) + { arg = new NullExp(arg->loc); + arg->type = ta; + } + else + arg = arg->castTo(sc, ta); + } +#if DMDV2 + if (tb->ty == Tstruct) + { + arg = callCpCtor(loc, sc, arg); + } + + // Give error for overloaded function addresses + if (arg->op == TOKsymoff) + { SymOffExp *se = (SymOffExp *)arg; + if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) + arg->error("function %s is overloaded", arg->toChars()); + } +#endif + arg->rvalue(); + } + arg = arg->optimize(WANTvalue); + arguments->data[i] = (void *) arg; + if (done) + break; + } + +#if !IN_LLVM + // If D linkage and variadic, add _arguments[] as first argument + if (tf->linkage == LINKd && tf->varargs == 1) + { + Expression *e; + + e = createTypeInfoArray(sc, (Expression **)&arguments->data[nparams], + arguments->dim - nparams); + arguments->insert(0, e); + } +#endif +} + +/************************************************** + * Write expression out to buf, but wrap it + * in ( ) if its precedence is less than pr. + */ + +void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) +{ + //if (precedence[e->op] == 0) e->dump(0); + if (precedence[e->op] < pr || + /* Despite precedence, we don't allow aop] == pr)) + { + buf->writeByte('('); + e->toCBuffer(buf, hgs); + buf->writeByte(')'); + } + else + e->toCBuffer(buf, hgs); +} + +/************************************************** + * Write out argument list to buf. + */ + +void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) +{ + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { Expression *arg = (Expression *)arguments->data[i]; + + if (arg) + { if (i) + buf->writeByte(','); + expToCBuffer(buf, hgs, arg, PREC_assign); + } + } + } +} + +/************************************************** + * Write out argument types to buf. + */ + +void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) +{ + if (arguments) + { OutBuffer argbuf; + + for (size_t i = 0; i < arguments->dim; i++) + { Expression *arg = (Expression *)arguments->data[i]; + + if (i) + buf->writeByte(','); + argbuf.reset(); + arg->type->toCBuffer2(&argbuf, hgs, 0); + buf->write(&argbuf); + } + } +} + +/******************************** Expression **************************/ + +Expression::Expression(Loc loc, enum TOK op, int size) + : loc(loc) +{ + //printf("Expression::Expression(op = %d) this = %p\n", op, this); + this->loc = loc; + this->op = op; + this->size = size; + type = NULL; +} + +Expression *Expression::syntaxCopy() +{ + //printf("Expression::syntaxCopy()\n"); + //dump(0); + return copy(); +} + +/********************************* + * Does *not* do a deep copy. + */ + +Expression *Expression::copy() +{ + Expression *e; + if (!size) + { +#ifdef DEBUG + fprintf(stdmsg, "No expression copy for: %s\n", toChars()); + printf("op = %d\n", op); + dump(0); +#endif + assert(0); + } + e = (Expression *)mem.malloc(size); + //printf("Expression::copy(op = %d) e = %p\n", op, e); + return (Expression *)memcpy(e, this, size); +} + +/************************** + * Semantically analyze Expression. + * Determine types, fold constants, etc. + */ + +Expression *Expression::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("Expression::semantic() %s\n", toChars()); +#endif + if (type) + type = type->semantic(loc, sc); + else + type = Type::tvoid; + return this; +} + +/********************************** + * Try to run semantic routines. + * If they fail, return NULL. + */ + +Expression *Expression::trySemantic(Scope *sc) +{ + unsigned errors = global.errors; + global.gag++; + Expression *e = semantic(sc); + global.gag--; + if (errors != global.errors) + { + global.errors = errors; + e = NULL; + } + return e; +} + +void Expression::print() +{ + fprintf(stdmsg, "%s\n", toChars()); + fflush(stdmsg); +} + +char *Expression::toChars() +{ OutBuffer *buf; + HdrGenState hgs; + + memset(&hgs, 0, sizeof(hgs)); + buf = new OutBuffer(); + toCBuffer(buf, &hgs); + return buf->toChars(); +} + +void Expression::error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + ::verror(loc, format, ap); + va_end( ap ); +} + +void Expression::warning(const char *format, ...) +{ + if (global.params.warnings && !global.gag) + { + va_list ap; + va_start(ap, format); + ::vwarning(loc, format, ap); + va_end( ap ); + } +} + +void Expression::rvalue() +{ + if (type && type->toBasetype()->ty == Tvoid) + { error("expression %s is void and has no value", toChars()); +#if 0 + dump(0); + halt(); +#endif + type = Type::tint32; + } +} + +Expression *Expression::combine(Expression *e1, Expression *e2) +{ + if (e1) + { + if (e2) + { + e1 = new CommaExp(e1->loc, e1, e2); + e1->type = e2->type; + } + } + else + e1 = e2; + return e1; +} + +dinteger_t Expression::toInteger() +{ + //printf("Expression %s\n", Token::toChars(op)); + error("Integer constant expression expected instead of %s", toChars()); + return 0; +} + +uinteger_t Expression::toUInteger() +{ + //printf("Expression %s\n", Token::toChars(op)); + return (uinteger_t)toInteger(); +} + +real_t Expression::toReal() +{ + error("Floating point constant expression expected instead of %s", toChars()); + return 0; +} + +real_t Expression::toImaginary() +{ + error("Floating point constant expression expected instead of %s", toChars()); + return 0; +} + +complex_t Expression::toComplex() +{ + error("Floating point constant expression expected instead of %s", toChars()); +#ifdef IN_GCC + return complex_t(real_t(0)); // %% nicer +#else + return 0; +#endif +} + +void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); +} + +void Expression::toMangleBuffer(OutBuffer *buf) +{ + error("expression %s is not a valid template value argument", toChars()); +} + +/*************************************** + * Return !=0 if expression is an lvalue. + */ +#if DMDV2 +int Expression::isLvalue() +{ + return 0; +} +#endif + +/******************************* + * Give error if we're not an lvalue. + * If we can, convert expression to be an lvalue. + */ + +Expression *Expression::toLvalue(Scope *sc, Expression *e) +{ + if (!e) + e = this; + else if (!loc.filename) + loc = e->loc; + error("%s is not an lvalue", e->toChars()); + return this; +} + +Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars()); + + // See if this expression is a modifiable lvalue (i.e. not const) +#if DMDV2 + if (type && (!type->isMutable() || !type->isAssignable())) + error("%s is not mutable", e->toChars()); +#endif + return toLvalue(sc, e); +} + +/************************************ + * Detect cases where pointers to the stack can 'escape' the + * lifetime of the stack frame. + */ + +void Expression::checkEscape() +{ +} + +void Expression::checkScalar() +{ + if (!type->isscalar()) + error("'%s' is not a scalar, it is a %s", toChars(), type->toChars()); +} + +void Expression::checkNoBool() +{ + if (type->toBasetype()->ty == Tbool) + error("operation not allowed on bool '%s'", toChars()); +} + +Expression *Expression::checkIntegral() +{ + if (!type->isintegral()) + { error("'%s' is not of integral type, it is a %s", toChars(), type->toChars()); + return new ErrorExp(); + } + return this; +} + +Expression *Expression::checkArithmetic() +{ + if (!type->isintegral() && !type->isfloating()) + { error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); + return new ErrorExp(); + } + return this; +} + +void Expression::checkDeprecated(Scope *sc, Dsymbol *s) +{ + s->checkDeprecated(loc, sc); +} + +#if DMDV2 +void Expression::checkPurity(Scope *sc, FuncDeclaration *f) +{ +#if 1 + if (sc->func) + { + FuncDeclaration *outerfunc=sc->func; + while (outerfunc->toParent2() && outerfunc->toParent2()->isFuncDeclaration()) + { + outerfunc = outerfunc->toParent2()->isFuncDeclaration(); + } + if (outerfunc->isPure() && !sc->intypeof && (!f->isNested() && !f->isPure())) + error("pure function '%s' cannot call impure function '%s'\n", + sc->func->toChars(), f->toChars()); + } +#else + if (sc->func && sc->func->isPure() && !sc->intypeof && !f->isPure()) + error("pure function '%s' cannot call impure function '%s'\n", + sc->func->toChars(), f->toChars()); +#endif +} +#endif + +/******************************** + * Check for expressions that have no use. + * Input: + * flag 0 not going to use the result, so issue error message if no + * side effects + * 1 the result of the expression is used, but still check + * for useless subexpressions + * 2 do not issue error messages, just return !=0 if expression + * has side effects + */ + +int Expression::checkSideEffect(int flag) +{ + if (flag == 0) + { if (op == TOKimport) + { + error("%s has no effect", toChars()); + } + else + error("%s has no effect in expression (%s)", + Token::toChars(op), toChars()); + } + return 0; +} + +/***************************** + * Check that expression can be tested for true or false. + */ + +Expression *Expression::checkToBoolean() +{ + // Default is 'yes' - do nothing + +#ifdef DEBUG + if (!type) + dump(0); +#endif + + if (!type->checkBoolean()) + { + error("expression %s of type %s does not have a boolean value", toChars(), type->toChars()); + } + return this; +} + +/**************************** + */ + +Expression *Expression::checkToPointer() +{ + Expression *e; + Type *tb; + + //printf("Expression::checkToPointer()\n"); + e = this; + + // If C static array, convert to pointer + tb = type->toBasetype(); + if (tb->ty == Tsarray) + { TypeSArray *ts = (TypeSArray *)tb; + if (ts->size(loc) == 0) + e = new NullExp(loc); + else + e = new AddrExp(loc, this); + e->type = ts->next->pointerTo(); + } + return e; +} + +/****************************** + * Take address of expression. + */ + +Expression *Expression::addressOf(Scope *sc) +{ + Expression *e; + + //printf("Expression::addressOf()\n"); + e = toLvalue(sc, NULL); + e = new AddrExp(loc, e); + e->type = type->pointerTo(); + return e; +} + +/****************************** + * If this is a reference, dereference it. + */ + +Expression *Expression::deref() +{ + //printf("Expression::deref()\n"); + if (type->ty == Treference) + { Expression *e; + + e = new PtrExp(loc, this); + e->type = ((TypeReference *)type)->next; + return e; + } + return this; +} + +/******************************** + * Does this expression statically evaluate to a boolean TRUE or FALSE? + */ + +int Expression::isBool(int result) +{ + return FALSE; +} + +/******************************** + * Does this expression result in either a 1 or a 0? + */ + +int Expression::isBit() +{ + return FALSE; +} + +/******************************** + * Can this expression throw an exception? + * Valid only after semantic() pass. + */ + +int Expression::canThrow() +{ +#if DMDV2 + return FALSE; +#else + return TRUE; +#endif +} + + + +Expressions *Expression::arraySyntaxCopy(Expressions *exps) +{ Expressions *a = NULL; + + if (exps) + { + a = new Expressions(); + a->setDim(exps->dim); + for (int i = 0; i < a->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->syntaxCopy(); + a->data[i] = e; + } + } + return a; +} + +/******************************** IntegerExp **************************/ + +IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type) + : Expression(loc, TOKint64, sizeof(IntegerExp)) +{ + //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : ""); + if (type && !type->isscalar()) + { + //printf("%s, loc = %d\n", toChars(), loc.linnum); + error("integral constant must be scalar type, not %s", type->toChars()); + type = Type::terror; + } + this->type = type; + this->value = value; +} + +IntegerExp::IntegerExp(dinteger_t value) + : Expression(0, TOKint64, sizeof(IntegerExp)) +{ + this->type = Type::tint32; + this->value = value; +} + +int IntegerExp::equals(Object *o) +{ IntegerExp *ne; + + if (this == o || + (((Expression *)o)->op == TOKint64 && + ((ne = (IntegerExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && + value == ne->value)) + return 1; + return 0; +} + +char *IntegerExp::toChars() +{ +#if 1 + return Expression::toChars(); +#else + static char buffer[sizeof(value) * 3 + 1]; + + sprintf(buffer, "%jd", value); + return buffer; +#endif +} + +dinteger_t IntegerExp::toInteger() +{ Type *t; + + t = type; + while (t) + { + switch (t->ty) + { + case Tbit: + case Tbool: value = (value != 0); break; + case Tint8: value = (d_int8) value; break; + case Tchar: + case Tuns8: value = (d_uns8) value; break; + case Tint16: value = (d_int16) value; break; + case Twchar: + case Tuns16: value = (d_uns16) value; break; + case Tint32: value = (d_int32) value; break; + case Tdchar: + case Tuns32: value = (d_uns32) value; break; + case Tint64: value = (d_int64) value; break; + case Tuns64: value = (d_uns64) value; break; + case Tpointer: + if (PTRSIZE == 4) + value = (d_uns32) value; + else if (PTRSIZE == 8) + value = (d_uns64) value; + else + assert(0); + break; + + case Tenum: + { + TypeEnum *te = (TypeEnum *)t; + t = te->sym->memtype; + continue; + } + + case Ttypedef: + { + TypeTypedef *tt = (TypeTypedef *)t; + t = tt->sym->basetype; + continue; + } + + default: + /* This can happen if errors, such as + * the type is painted on like in fromConstInitializer(). + */ + if (!global.errors) + { type->print(); + assert(0); + } + break; + } + break; + } + return value; +} + +real_t IntegerExp::toReal() +{ + Type *t; + + toInteger(); + t = type->toBasetype(); + if (t->ty == Tuns64) + return (real_t)(d_uns64)value; + else + return (real_t)(d_int64)value; +} + +real_t IntegerExp::toImaginary() +{ + return (real_t) 0; +} + +complex_t IntegerExp::toComplex() +{ + return toReal(); +} + +int IntegerExp::isBool(int result) +{ + return result ? value != 0 : value == 0; +} + +Expression *IntegerExp::semantic(Scope *sc) +{ + if (!type) + { + // Determine what the type of this number is + dinteger_t number = value; + + if (number & 0x8000000000000000LL) + type = Type::tuns64; + else if (number & 0xFFFFFFFF80000000LL) + type = Type::tint64; + else + type = Type::tint32; + } + else + { if (!type->deco) + type = type->semantic(loc, sc); + } + return this; +} + +Expression *IntegerExp::toLvalue(Scope *sc, Expression *e) +{ + if (!e) + e = this; + else if (!loc.filename) + loc = e->loc; + e->error("constant %s is not an lvalue", e->toChars()); + return this; +} + +void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + dinteger_t v = toInteger(); + + if (type) + { Type *t = type; + + L1: + switch (t->ty) + { + case Tenum: + { TypeEnum *te = (TypeEnum *)t; + buf->printf("cast(%s)", te->sym->toChars()); + t = te->sym->memtype; + goto L1; + } + + case Ttypedef: + { TypeTypedef *tt = (TypeTypedef *)t; + buf->printf("cast(%s)", tt->sym->toChars()); + t = tt->sym->basetype; + goto L1; + } + + case Twchar: // BUG: need to cast(wchar) + case Tdchar: // BUG: need to cast(dchar) + if ((uinteger_t)v > 0xFF) + { + buf->printf("'\\U%08x'", (unsigned)v); + break; + } + case Tchar: + if (v == '\'') + buf->writestring("'\\''"); + else if (isprint(v) && v != '\\') + buf->printf("'%c'", (int)v); + else + buf->printf("'\\x%02x'", (int)v); + break; + + case Tint8: + buf->writestring("cast(byte)"); + goto L2; + + case Tint16: + buf->writestring("cast(short)"); + goto L2; + + case Tint32: + L2: + buf->printf("%d", (int)v); + break; + + case Tuns8: + buf->writestring("cast(ubyte)"); + goto L3; + + case Tuns16: + buf->writestring("cast(ushort)"); + goto L3; + + case Tuns32: + L3: + buf->printf("%du", (unsigned)v); + break; + + case Tint64: + buf->printf("%jdL", v); + break; + + case Tuns64: + L4: + buf->printf("%juLU", v); + break; + + case Tbit: + case Tbool: + buf->writestring((char *)(v ? "true" : "false")); + break; + + case Tpointer: + buf->writestring("cast("); + buf->writestring(t->toChars()); + buf->writeByte(')'); + if (PTRSIZE == 4) + goto L3; + else if (PTRSIZE == 8) + goto L4; + else + assert(0); + + default: + /* This can happen if errors, such as + * the type is painted on like in fromConstInitializer(). + */ + if (!global.errors) + { +#ifdef DEBUG + t->print(); +#endif + assert(0); + } + break; + } + } + else if (v & 0x8000000000000000LL) + buf->printf("0x%jx", v); + else + buf->printf("%jd", v); +} + +void IntegerExp::toMangleBuffer(OutBuffer *buf) +{ + if ((sinteger_t)value < 0) + buf->printf("N%jd", -value); + else + buf->printf("%jd", value); +} + +/******************************** ErrorExp **************************/ + +/* Use this expression for error recovery. + * It should behave as a 'sink' to prevent further cascaded error messages. + */ + +ErrorExp::ErrorExp() + : IntegerExp(0, 0, Type::terror) +{ +} + +void ErrorExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("__error"); +} + +/******************************** RealExp **************************/ + +RealExp::RealExp(Loc loc, real_t value, Type *type) + : Expression(loc, TOKfloat64, sizeof(RealExp)) +{ + //printf("RealExp::RealExp(%Lg)\n", value); + this->value = value; + this->type = type; +} + +char *RealExp::toChars() +{ + char buffer[sizeof(value) * 3 + 8 + 1 + 1]; + +#ifdef IN_GCC + value.format(buffer, sizeof(buffer)); + if (type->isimaginary()) + strcat(buffer, "i"); +#else + sprintf(buffer, type->isimaginary() ? "%Lgi" : "%Lg", value); +#endif + assert(strlen(buffer) < sizeof(buffer)); + return mem.strdup(buffer); +} + +dinteger_t RealExp::toInteger() +{ +#ifdef IN_GCC + return toReal().toInt(); +#else + return (sinteger_t) toReal(); +#endif +} + +uinteger_t RealExp::toUInteger() +{ +#ifdef IN_GCC + return (uinteger_t) toReal().toInt(); +#else + return (uinteger_t) toReal(); +#endif +} + +real_t RealExp::toReal() +{ + return type->isreal() ? value : 0; +} + +real_t RealExp::toImaginary() +{ + return type->isreal() ? 0 : value; +} + +complex_t RealExp::toComplex() +{ +#ifdef __DMC__ + return toReal() + toImaginary() * I; +#else + return complex_t(toReal(), toImaginary()); +#endif +} + +/******************************** + * Test to see if two reals are the same. + * Regard NaN's as equivalent. + * Regard +0 and -0 as different. + */ + +int RealEquals(real_t x1, real_t x2) +{ +//#if 1 +// return (Port::isNan(x1) && Port::isNan(x2)) || +//#elif __APPLE__ +#if __APPLE__ + return (__inline_isnan(x1) && __inline_isnan(x2)) || +#else + return // special case nans + (isnan(x1) && isnan(x2)) || +#endif + // and zero, in order to distinguish +0 from -0 + (x1 == 0 && x2 == 0 && 1./x1 == 1./x2) || + // otherwise just compare + (x1 != 0. && x1 == x2); +} + +int RealExp::equals(Object *o) +{ RealExp *ne; + + if (this == o || + (((Expression *)o)->op == TOKfloat64 && + ((ne = (RealExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && + RealEquals(value, ne->value) + ) + ) + return 1; + return 0; +} + +Expression *RealExp::semantic(Scope *sc) +{ + if (!type) + type = Type::tfloat64; + else + type = type->semantic(loc, sc); + return this; +} + +int RealExp::isBool(int result) +{ +#ifdef IN_GCC + return result ? (! value.isZero()) : (value.isZero()); +#else + return result ? (value != 0) + : (value == 0); +#endif +} + +void floatToBuffer(OutBuffer *buf, Type *type, real_t value) +{ + /* In order to get an exact representation, try converting it + * to decimal then back again. If it matches, use it. + * If it doesn't, fall back to hex, which is + * always exact. + */ + char buffer[25]; + sprintf(buffer, "%Lg", value); + assert(strlen(buffer) < sizeof(buffer)); +#if _WIN32 && __DMC__ + char *save = __locale_decpoint; + __locale_decpoint = "."; + real_t r = strtold(buffer, NULL); + __locale_decpoint = save; +#else + real_t r = strtold(buffer, NULL); +#endif + if (r == value) // if exact duplication + buf->writestring(buffer); + else + buf->printf("%La", value); // ensure exact duplication + + if (type) + { + Type *t = type->toBasetype(); + switch (t->ty) + { + case Tfloat32: + case Timaginary32: + case Tcomplex32: + buf->writeByte('F'); + break; + + case Tfloat80: + case Timaginary80: + case Tcomplex80: + buf->writeByte('L'); + break; + + default: + break; + } + if (t->isimaginary()) + buf->writeByte('i'); + } +} + +void RealExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + floatToBuffer(buf, type, value); +} + +void realToMangleBuffer(OutBuffer *buf, real_t value) +{ + /* Rely on %A to get portable mangling. + * Must munge result to get only identifier characters. + * + * Possible values from %A => mangled result + * NAN => NAN + * -INF => NINF + * INF => INF + * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 + * 0X1.9P+2 => 19P2 + */ + +//#if 1 +// if (Port::isNan(value)) +//#elif __APPLE__ +#if __APPLE__ + if (__inline_isnan(value)) +#else + if (isnan(value)) +#endif + buf->writestring("NAN"); // no -NAN bugs + else + { + char buffer[32]; + int n = sprintf(buffer, "%LA", value); + assert(n > 0 && n < sizeof(buffer)); + for (int i = 0; i < n; i++) + { char c = buffer[i]; + + switch (c) + { + case '-': + buf->writeByte('N'); + break; + + case '+': + case 'X': + case '.': + break; + + case '0': + if (i < 2) + break; // skip leading 0X + default: + buf->writeByte(c); + break; + } + } + } +} + +void RealExp::toMangleBuffer(OutBuffer *buf) +{ + buf->writeByte('e'); + realToMangleBuffer(buf, value); +} + + +/******************************** ComplexExp **************************/ + +ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type) + : Expression(loc, TOKcomplex80, sizeof(ComplexExp)) +{ + this->value = value; + this->type = type; + //printf("ComplexExp::ComplexExp(%s)\n", toChars()); +} + +char *ComplexExp::toChars() +{ + char buffer[sizeof(value) * 3 + 8 + 1]; + +#ifdef IN_GCC + char buf1[sizeof(value) * 3 + 8 + 1]; + char buf2[sizeof(value) * 3 + 8 + 1]; + creall(value).format(buf1, sizeof(buf1)); + cimagl(value).format(buf2, sizeof(buf2)); + sprintf(buffer, "(%s+%si)", buf1, buf2); +#else + sprintf(buffer, "(%Lg+%Lgi)", creall(value), cimagl(value)); + assert(strlen(buffer) < sizeof(buffer)); +#endif + return mem.strdup(buffer); +} + +dinteger_t ComplexExp::toInteger() +{ +#ifdef IN_GCC + return (sinteger_t) toReal().toInt(); +#else + return (sinteger_t) toReal(); +#endif +} + +uinteger_t ComplexExp::toUInteger() +{ +#ifdef IN_GCC + return (uinteger_t) toReal().toInt(); +#else + return (uinteger_t) toReal(); +#endif +} + +real_t ComplexExp::toReal() +{ + return creall(value); +} + +real_t ComplexExp::toImaginary() +{ + return cimagl(value); +} + +complex_t ComplexExp::toComplex() +{ + return value; +} + +int ComplexExp::equals(Object *o) +{ ComplexExp *ne; + + if (this == o || + (((Expression *)o)->op == TOKcomplex80 && + ((ne = (ComplexExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && + RealEquals(creall(value), creall(ne->value)) && + RealEquals(cimagl(value), cimagl(ne->value)) + ) + ) + return 1; + return 0; +} + +Expression *ComplexExp::semantic(Scope *sc) +{ + if (!type) + type = Type::tcomplex80; + else + type = type->semantic(loc, sc); + return this; +} + +int ComplexExp::isBool(int result) +{ + if (result) + return (bool)(value); + else + return !value; +} + +void ComplexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + /* Print as: + * (re+imi) + */ +#ifdef IN_GCC + char buf1[sizeof(value) * 3 + 8 + 1]; + char buf2[sizeof(value) * 3 + 8 + 1]; + creall(value).format(buf1, sizeof(buf1)); + cimagl(value).format(buf2, sizeof(buf2)); + buf->printf("(%s+%si)", buf1, buf2); +#else + buf->writeByte('('); + floatToBuffer(buf, type, creall(value)); + buf->writeByte('+'); + floatToBuffer(buf, type, cimagl(value)); + buf->writestring("i)"); +#endif +} + +void ComplexExp::toMangleBuffer(OutBuffer *buf) +{ + buf->writeByte('c'); + real_t r = toReal(); + realToMangleBuffer(buf, r); + buf->writeByte('c'); // separate the two + r = toImaginary(); + realToMangleBuffer(buf, r); +} + +/******************************** IdentifierExp **************************/ + +IdentifierExp::IdentifierExp(Loc loc, Identifier *ident) + : Expression(loc, TOKidentifier, sizeof(IdentifierExp)) +{ + this->ident = ident; +} + +Expression *IdentifierExp::semantic(Scope *sc) +{ + Dsymbol *s; + Dsymbol *scopesym; + +#if LOGSEMANTIC + printf("IdentifierExp::semantic('%s')\n", ident->toChars()); +#endif + s = sc->search(loc, ident, &scopesym); + if (s) + { Expression *e; + WithScopeSymbol *withsym; + + /* See if the symbol was a member of an enclosing 'with' + */ + withsym = scopesym->isWithScopeSymbol(); + if (withsym) + { + s = s->toAlias(); + + // Same as wthis.ident + if (s->needThis() || s->isTemplateDeclaration()) + { + e = new VarExp(loc, withsym->withstate->wthis); + e = new DotIdExp(loc, e, ident); + } + else + { Type *t = withsym->withstate->wthis->type; + if (t->ty == Tpointer) + t = ((TypePointer *)t)->next; + e = typeDotIdExp(loc, t, ident); + } + } + else + { + /* If f is really a function template, + * then replace f with the function template declaration. + */ + FuncDeclaration *f = s->isFuncDeclaration(); + if (f && f->parent) + { TemplateInstance *ti = f->parent->isTemplateInstance(); + + if (ti && + !ti->isTemplateMixin() && + (ti->name == f->ident || + ti->toAlias()->ident == f->ident) + && + ti->tempdecl && ti->tempdecl->onemember) + { + TemplateDeclaration *tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + e = new TemplateExp(loc, tempdecl); + e = e->semantic(sc); + return e; + } + } + // Haven't done overload resolution yet, so pass 1 + e = new DsymbolExp(loc, s, 1); + } + return e->semantic(sc); + } + error("undefined identifier %s", ident->toChars()); + type = Type::terror; + return this; +} + +char *IdentifierExp::toChars() +{ + return ident->toChars(); +} + +void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + buf->writestring(ident->toHChars2()); + else + buf->writestring(ident->toChars()); +} + +#if DMDV2 +int IdentifierExp::isLvalue() +{ + return 1; +} +#endif + +Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e) +{ +#if 0 + tym = tybasic(e1->ET->Tty); + if (!(tyscalar(tym) || + tym == TYstruct || + tym == TYarray && e->Eoper == TOKaddr)) + synerr(EM_lvalue); // lvalue expected +#endif + return this; +} + +/******************************** DollarExp **************************/ + +DollarExp::DollarExp(Loc loc) + : IdentifierExp(loc, Id::dollar) +{ +} + +/******************************** DsymbolExp **************************/ + +DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads) + : Expression(loc, TOKdsymbol, sizeof(DsymbolExp)) +{ + this->s = s; + this->hasOverloads = hasOverloads; +} + +Expression *DsymbolExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DsymbolExp::semantic('%s')\n", s->toChars()); +#endif + +Lagain: + EnumMember *em; + Expression *e; + VarDeclaration *v; + FuncDeclaration *f; + FuncLiteralDeclaration *fld; + OverloadSet *o; + Declaration *d; + ClassDeclaration *cd; + ClassDeclaration *thiscd = NULL; + Import *imp; + Package *pkg; + Type *t; + + //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); + //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind()); + if (type) + return this; + if (!s->isFuncDeclaration()) // functions are checked after overloading + checkDeprecated(sc, s); + s = s->toAlias(); + //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); + if (!s->isFuncDeclaration()) + checkDeprecated(sc, s); + + if (sc->func) + thiscd = sc->func->parent->isClassDeclaration(); + + // BUG: This should happen after overload resolution for functions, not before + if (s->needThis()) + { + if (hasThis(sc) +#if DMDV2 + && !s->isFuncDeclaration() +#endif + ) + { + // Supply an implicit 'this', as in + // this.ident + + DotVarExp *de; + + de = new DotVarExp(loc, new ThisExp(loc), s->isDeclaration()); + return de->semantic(sc); + } + } + + em = s->isEnumMember(); + if (em) + { + e = em->value; + e = e->semantic(sc); + return e; + } + v = s->isVarDeclaration(); + if (v) + { + //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); + if (!type) + { type = v->type; + if (!v->type) + { error("forward reference of %s", v->toChars()); + type = Type::terror; + } + } + e = new VarExp(loc, v); + e->type = type; + e = e->semantic(sc); + return e->deref(); + } + fld = s->isFuncLiteralDeclaration(); + if (fld) + { //printf("'%s' is a function literal\n", fld->toChars()); + e = new FuncExp(loc, fld); + return e->semantic(sc); + } + f = s->isFuncDeclaration(); + if (f) + { //printf("'%s' is a function\n", f->toChars()); + return new VarExp(loc, f, hasOverloads); + } + o = s->isOverloadSet(); + if (o) + { //printf("'%s' is an overload set\n", o->toChars()); + return new OverExp(o); + } + cd = s->isClassDeclaration(); + if (cd && thiscd && cd->isBaseOf(thiscd, NULL) && sc->func->needThis()) + { + // We need to add an implicit 'this' if cd is this class or a base class. + DotTypeExp *dte; + + dte = new DotTypeExp(loc, new ThisExp(loc), s); + return dte->semantic(sc); + } + imp = s->isImport(); + if (imp) + { + if (!imp->pkg) + { error("forward reference of import %s", imp->toChars()); + return this; + } + ScopeExp *ie = new ScopeExp(loc, imp->pkg); + return ie->semantic(sc); + } + pkg = s->isPackage(); + if (pkg) + { + ScopeExp *ie; + + ie = new ScopeExp(loc, pkg); + return ie->semantic(sc); + } + Module *mod = s->isModule(); + if (mod) + { + ScopeExp *ie; + + ie = new ScopeExp(loc, mod); + return ie->semantic(sc); + } + + t = s->getType(); + if (t) + { + return new TypeExp(loc, t); + } + + TupleDeclaration *tup = s->isTupleDeclaration(); + if (tup) + { + e = new TupleExp(loc, tup); + e = e->semantic(sc); + return e; + } + + TemplateInstance *ti = s->isTemplateInstance(); + if (ti && !global.errors) + { if (!ti->semanticdone) + ti->semantic(sc); + s = ti->inst->toAlias(); + if (!s->isTemplateInstance()) + goto Lagain; + e = new ScopeExp(loc, ti); + e = e->semantic(sc); + return e; + } + + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td) + { + e = new TemplateExp(loc, td); + e = e->semantic(sc); + return e; + } + +Lerr: + error("%s '%s' is not a variable", s->kind(), s->toChars()); + type = Type::terror; + return this; +} + +char *DsymbolExp::toChars() +{ + return s->toChars(); +} + +void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(s->toChars()); +} + +#if DMDV2 +int DsymbolExp::isLvalue() +{ + return 1; +} +#endif + +Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) +{ +#if 0 + tym = tybasic(e1->ET->Tty); + if (!(tyscalar(tym) || + tym == TYstruct || + tym == TYarray && e->Eoper == TOKaddr)) + synerr(EM_lvalue); // lvalue expected +#endif + return this; +} + +/******************************** ThisExp **************************/ + +ThisExp::ThisExp(Loc loc) + : Expression(loc, TOKthis, sizeof(ThisExp)) +{ + //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); + var = NULL; +} + +Expression *ThisExp::semantic(Scope *sc) +{ FuncDeclaration *fd; + FuncDeclaration *fdthis; + int nested = 0; + +#if LOGSEMANTIC + printf("ThisExp::semantic()\n"); +#endif + if (type) + { //assert(global.errors || var); + return this; + } + + /* Special case for typeof(this) and typeof(super) since both + * should work even if they are not inside a non-static member function + */ + if (sc->intypeof) + { + // Find enclosing struct or class + for (Dsymbol *s = sc->parent; 1; s = s->parent) + { + if (!s) + { + error("%s is not in a class or struct scope", toChars()); + goto Lerr; + } + ClassDeclaration *cd = s->isClassDeclaration(); + if (cd) + { + type = cd->type; + return this; + } + StructDeclaration *sd = s->isStructDeclaration(); + if (sd) + { +#if STRUCTTHISREF + type = sd->type; +#else + type = sd->type->pointerTo(); +#endif + return this; + } + } + } + + fdthis = sc->parent->isFuncDeclaration(); + fd = hasThis(sc); // fd is the uplevel function with the 'this' variable + if (!fd) + goto Lerr; + + assert(fd->vthis); + var = fd->vthis; + assert(var->parent); + type = var->type; + var->isVarDeclaration()->checkNestedReference(sc, loc); + if (!sc->intypeof) + sc->callSuper |= CSXthis; + return this; + +Lerr: + error("'this' is only defined in non-static member functions, not %s", sc->parent->toChars()); + type = Type::terror; + return this; +} + +int ThisExp::isBool(int result) +{ + return result ? TRUE : FALSE; +} + +void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this"); +} + +#if DMDV2 +int ThisExp::isLvalue() +{ + return 1; +} +#endif + +Expression *ThisExp::toLvalue(Scope *sc, Expression *e) +{ + return this; +} + +/******************************** SuperExp **************************/ + +SuperExp::SuperExp(Loc loc) + : ThisExp(loc) +{ + op = TOKsuper; +} + +Expression *SuperExp::semantic(Scope *sc) +{ FuncDeclaration *fd; + FuncDeclaration *fdthis; + ClassDeclaration *cd; + Dsymbol *s; + +#if LOGSEMANTIC + printf("SuperExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + /* Special case for typeof(this) and typeof(super) since both + * should work even if they are not inside a non-static member function + */ + if (sc->intypeof) + { + // Find enclosing class + for (Dsymbol *s = sc->parent; 1; s = s->parent) + { + ClassDeclaration *cd; + + if (!s) + { + error("%s is not in a class scope", toChars()); + goto Lerr; + } + cd = s->isClassDeclaration(); + if (cd) + { + cd = cd->baseClass; + if (!cd) + { error("class %s has no 'super'", s->toChars()); + goto Lerr; + } + type = cd->type; + return this; + } + } + } + + fdthis = sc->parent->isFuncDeclaration(); + fd = hasThis(sc); + if (!fd) + goto Lerr; + assert(fd->vthis); + var = fd->vthis; + assert(var->parent); + + s = fd->toParent(); + while (s && s->isTemplateInstance()) + s = s->toParent(); + assert(s); + cd = s->isClassDeclaration(); +//printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars()); + if (!cd) + goto Lerr; + if (!cd->baseClass) + { + error("no base class for %s", cd->toChars()); + type = fd->vthis->type; + } + else + { + type = cd->baseClass->type; + } + + var->isVarDeclaration()->checkNestedReference(sc, loc); + + if (!sc->intypeof) + sc->callSuper |= CSXsuper; + return this; + + +Lerr: + error("'super' is only allowed in non-static class member functions"); + type = Type::tint32; + return this; +} + +void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("super"); +} + + +/******************************** NullExp **************************/ + +NullExp::NullExp(Loc loc) + : Expression(loc, TOKnull, sizeof(NullExp)) +{ + committed = 0; +} + +Expression *NullExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("NullExp::semantic('%s')\n", toChars()); +#endif + // NULL is the same as (void *)0 + if (!type) + type = Type::tvoid->pointerTo(); + return this; +} + +int NullExp::isBool(int result) +{ + return result ? FALSE : TRUE; +} + +void NullExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("null"); +} + +void NullExp::toMangleBuffer(OutBuffer *buf) +{ + buf->writeByte('n'); +} + +/******************************** StringExp **************************/ + +StringExp::StringExp(Loc loc, char *string) + : Expression(loc, TOKstring, sizeof(StringExp)) +{ + this->string = string; + this->len = strlen(string); + this->sz = 1; + this->committed = 0; + this->postfix = 0; +} + +StringExp::StringExp(Loc loc, void *string, size_t len) + : Expression(loc, TOKstring, sizeof(StringExp)) +{ + this->string = string; + this->len = len; + this->sz = 1; + this->committed = 0; + this->postfix = 0; +} + +StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix) + : Expression(loc, TOKstring, sizeof(StringExp)) +{ + this->string = string; + this->len = len; + this->sz = 1; + this->committed = 0; + this->postfix = postfix; +} + +#if 0 +Expression *StringExp::syntaxCopy() +{ + printf("StringExp::syntaxCopy() %s\n", toChars()); + return copy(); +} +#endif + +int StringExp::equals(Object *o) +{ + //printf("StringExp::equals('%s')\n", o->toChars()); + if (o && o->dyncast() == DYNCAST_EXPRESSION) + { Expression *e = (Expression *)o; + + if (e->op == TOKstring) + { + return compare(o) == 0; + } + } + return FALSE; +} + +char *StringExp::toChars() +{ + OutBuffer buf; + HdrGenState hgs; + char *p; + + memset(&hgs, 0, sizeof(hgs)); + toCBuffer(&buf, &hgs); + buf.writeByte(0); + p = (char *)buf.data; + buf.data = NULL; + return p; +} + +Expression *StringExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("StringExp::semantic() %s\n", toChars()); +#endif + if (!type) + { OutBuffer buffer; + size_t newlen = 0; + const char *p; + size_t u; + unsigned c; + + switch (postfix) + { + case 'd': + for (u = 0; u < len;) + { + p = utf_decodeChar((unsigned char *)string, len, &u, &c); + if (p) + { error("%s", p); + break; + } + else + { buffer.write4(c); + newlen++; + } + } + buffer.write4(0); + string = buffer.extractData(); + len = newlen; + sz = 4; + //type = new TypeSArray(Type::tdchar, new IntegerExp(loc, len, Type::tindex)); + type = new TypeDArray(Type::tdchar->invariantOf()); + committed = 1; + break; + + case 'w': + for (u = 0; u < len;) + { + p = utf_decodeChar((unsigned char *)string, len, &u, &c); + if (p) + { error("%s", p); + break; + } + else + { buffer.writeUTF16(c); + newlen++; + if (c >= 0x10000) + newlen++; + } + } + buffer.writeUTF16(0); + string = buffer.extractData(); + len = newlen; + sz = 2; + //type = new TypeSArray(Type::twchar, new IntegerExp(loc, len, Type::tindex)); + type = new TypeDArray(Type::twchar->invariantOf()); + committed = 1; + break; + + case 'c': + committed = 1; + default: + //type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex)); + type = new TypeDArray(Type::tchar->invariantOf()); + break; + } + type = type->semantic(loc, sc); + //type = type->invariantOf(); + //printf("type = %s\n", type->toChars()); + } + return this; +} + +/********************************** + * Return length of string. + */ + +size_t StringExp::length() +{ + size_t result = 0; + dchar_t c; + const char *p; + + switch (sz) + { + case 1: + for (size_t u = 0; u < len;) + { + p = utf_decodeChar((unsigned char *)string, len, &u, &c); + if (p) + { error("%s", p); + break; + } + else + result++; + } + break; + + case 2: + for (size_t u = 0; u < len;) + { + p = utf_decodeWchar((unsigned short *)string, len, &u, &c); + if (p) + { error("%s", p); + break; + } + else + result++; + } + break; + + case 4: + result = len; + break; + + default: + assert(0); + } + return result; +} + +/**************************************** + * Convert string to char[]. + */ + +StringExp *StringExp::toUTF8(Scope *sc) +{ + if (sz != 1) + { // Convert to UTF-8 string + committed = 0; + Expression *e = castTo(sc, Type::tchar->arrayOf()); + e = e->optimize(WANTvalue); + assert(e->op == TOKstring); + StringExp *se = (StringExp *)e; + assert(se->sz == 1); + return se; + } + return this; +} + +int StringExp::compare(Object *obj) +{ + // Used to sort case statement expressions so we can do an efficient lookup + StringExp *se2 = (StringExp *)(obj); + + // This is a kludge so isExpression() in template.c will return 5 + // for StringExp's. + if (!se2) + return 5; + + assert(se2->op == TOKstring); + + int len1 = len; + int len2 = se2->len; + + if (len1 == len2) + { + switch (sz) + { + case 1: + return strcmp((char *)string, (char *)se2->string); + + case 2: + { unsigned u; + d_wchar *s1 = (d_wchar *)string; + d_wchar *s2 = (d_wchar *)se2->string; + + for (u = 0; u < len; u++) + { + if (s1[u] != s2[u]) + return s1[u] - s2[u]; + } + } + + case 4: + { unsigned u; + d_dchar *s1 = (d_dchar *)string; + d_dchar *s2 = (d_dchar *)se2->string; + + for (u = 0; u < len; u++) + { + if (s1[u] != s2[u]) + return s1[u] - s2[u]; + } + } + break; + + default: + assert(0); + } + } + return len1 - len2; +} + +int StringExp::isBool(int result) +{ + return result ? TRUE : FALSE; +} + +unsigned StringExp::charAt(size_t i) +{ unsigned value; + + switch (sz) + { + case 1: + value = ((unsigned char *)string)[i]; + break; + + case 2: + value = ((unsigned short *)string)[i]; + break; + + case 4: + value = ((unsigned int *)string)[i]; + break; + + default: + assert(0); + break; + } + return value; +} + +void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('"'); + for (size_t i = 0; i < len; i++) + { unsigned c = charAt(i); + + switch (c) + { + case '"': + case '\\': + if (!hgs->console) + buf->writeByte('\\'); + default: + if (c <= 0xFF) + { if (c <= 0x7F && (isprint(c) || hgs->console)) + buf->writeByte(c); + else + buf->printf("\\x%02x", c); + } + else if (c <= 0xFFFF) + buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); + else + buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x", + c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); + break; + } + } + buf->writeByte('"'); + if (postfix) + buf->writeByte(postfix); +} + +void StringExp::toMangleBuffer(OutBuffer *buf) +{ char m; + OutBuffer tmp; + const char *p; + unsigned c; + size_t u; + unsigned char *q; + unsigned qlen; + + /* Write string in UTF-8 format + */ + switch (sz) + { case 1: + m = 'a'; + q = (unsigned char *)string; + qlen = len; + break; + case 2: + m = 'w'; + for (u = 0; u < len; ) + { + p = utf_decodeWchar((unsigned short *)string, len, &u, &c); + if (p) + error("%s", p); + else + tmp.writeUTF8(c); + } + q = tmp.data; + qlen = tmp.offset; + break; + case 4: + m = 'd'; + for (u = 0; u < len; u++) + { + c = ((unsigned *)string)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + tmp.writeUTF8(c); + } + q = tmp.data; + qlen = tmp.offset; + break; + default: + assert(0); + } + buf->writeByte(m); + buf->printf("%d_", qlen); + for (size_t i = 0; i < qlen; i++) + buf->printf("%02x", q[i]); +} + +/************************ ArrayLiteralExp ************************************/ + +// [ e1, e2, e3, ... ] + +ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) + : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) +{ + this->elements = elements; +} + +ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) + : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) +{ + elements = new Expressions; + elements->push(e); +} + +Expression *ArrayLiteralExp::syntaxCopy() +{ + return new ArrayLiteralExp(loc, arraySyntaxCopy(elements)); +} + +Expression *ArrayLiteralExp::semantic(Scope *sc) +{ Expression *e; + Type *t0 = NULL; + +#if LOGSEMANTIC + printf("ArrayLiteralExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + // Run semantic() on each element + for (int i = 0; i < elements->dim; i++) + { e = (Expression *)elements->data[i]; + e = e->semantic(sc); + elements->data[i] = (void *)e; + } + expandTuples(elements); + for (int i = 0; i < elements->dim; i++) + { e = (Expression *)elements->data[i]; + + if (!e->type) + error("%s has no value", e->toChars()); + e = resolveProperties(sc, e); + + unsigned char committed = 1; + if (e->op == TOKstring) + committed = ((StringExp *)e)->committed; + + if (!t0) + { t0 = e->type; + // Convert any static arrays to dynamic arrays + if (t0->ty == Tsarray) + { + t0 = ((TypeSArray *)t0)->next->arrayOf(); + e = e->implicitCastTo(sc, t0); + } + } + else + e = e->implicitCastTo(sc, t0); + if (!committed && e->op == TOKstring) + { StringExp *se = (StringExp *)e; + se->committed = 0; + } + elements->data[i] = (void *)e; + } + + if (!t0) + t0 = Type::tvoid; + type = new TypeSArray(t0, new IntegerExp(elements->dim)); + type = type->semantic(loc, sc); + return this; +} + +int ArrayLiteralExp::checkSideEffect(int flag) +{ int f = 0; + + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + + f |= e->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +int ArrayLiteralExp::isBool(int result) +{ + size_t dim = elements ? elements->dim : 0; + return result ? (dim != 0) : (dim == 0); +} + +#if DMDV2 +int ArrayLiteralExp::canThrow() +{ + return 1; // because it can fail allocating memory +} +#endif + +void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('['); + argsToCBuffer(buf, elements, hgs); + buf->writeByte(']'); +} + +void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf) +{ + size_t dim = elements ? elements->dim : 0; + buf->printf("A%zu", dim); + for (size_t i = 0; i < dim; i++) + { Expression *e = (Expression *)elements->data[i]; + e->toMangleBuffer(buf); + } +} + +/************************ AssocArrayLiteralExp ************************************/ + +// [ key0 : value0, key1 : value1, ... ] + +AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc, + Expressions *keys, Expressions *values) + : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp)) +{ + assert(keys->dim == values->dim); + this->keys = keys; + this->values = values; +} + +Expression *AssocArrayLiteralExp::syntaxCopy() +{ + return new AssocArrayLiteralExp(loc, + arraySyntaxCopy(keys), arraySyntaxCopy(values)); +} + +Expression *AssocArrayLiteralExp::semantic(Scope *sc) +{ Expression *e; + Type *tkey = NULL; + Type *tvalue = NULL; + +#if LOGSEMANTIC + printf("AssocArrayLiteralExp::semantic('%s')\n", toChars()); +#endif + + // Run semantic() on each element + for (size_t i = 0; i < keys->dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + key = key->semantic(sc); + value = value->semantic(sc); + + keys->data[i] = (void *)key; + values->data[i] = (void *)value; + } + expandTuples(keys); + expandTuples(values); + if (keys->dim != values->dim) + { + error("number of keys is %u, must match number of values %u", keys->dim, values->dim); + keys->setDim(0); + values->setDim(0); + } + for (size_t i = 0; i < keys->dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + if (!key->type) + error("%s has no value", key->toChars()); + if (!value->type) + error("%s has no value", value->toChars()); + key = resolveProperties(sc, key); + value = resolveProperties(sc, value); + + if (!tkey) + tkey = key->type; + else + key = key->implicitCastTo(sc, tkey); + keys->data[i] = (void *)key; + + if (!tvalue) + tvalue = value->type; + else + value = value->implicitCastTo(sc, tvalue); + values->data[i] = (void *)value; + } + + if (!tkey) + tkey = Type::tvoid; + if (!tvalue) + tvalue = Type::tvoid; + type = new TypeAArray(tvalue, tkey); + type = type->semantic(loc, sc); + return this; +} + +int AssocArrayLiteralExp::checkSideEffect(int flag) +{ int f = 0; + + for (size_t i = 0; i < keys->dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + f |= key->checkSideEffect(2); + f |= value->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +int AssocArrayLiteralExp::isBool(int result) +{ + size_t dim = keys->dim; + return result ? (dim != 0) : (dim == 0); +} + +#if DMDV2 +int AssocArrayLiteralExp::canThrow() +{ + return 1; +} +#endif + +void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('['); + for (size_t i = 0; i < keys->dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + if (i) + buf->writeByte(','); + expToCBuffer(buf, hgs, key, PREC_assign); + buf->writeByte(':'); + expToCBuffer(buf, hgs, value, PREC_assign); + } + buf->writeByte(']'); +} + +void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) +{ + size_t dim = keys->dim; + buf->printf("A%zu", dim); + for (size_t i = 0; i < dim; i++) + { Expression *key = (Expression *)keys->data[i]; + Expression *value = (Expression *)values->data[i]; + + key->toMangleBuffer(buf); + value->toMangleBuffer(buf); + } +} + +/************************ StructLiteralExp ************************************/ + +// sd( e1, e2, e3, ... ) + +StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements) + : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp)) +{ + this->sd = sd; + this->elements = elements; +#if IN_DMD + this->sym = NULL; +#endif + this->soffset = 0; + this->fillHoles = 1; +} + +Expression *StructLiteralExp::syntaxCopy() +{ + return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements)); +} + +Expression *StructLiteralExp::semantic(Scope *sc) +{ Expression *e; + int nfields = sd->fields.dim - sd->isnested; + +#if LOGSEMANTIC + printf("StructLiteralExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + // Run semantic() on each element + for (size_t i = 0; i < elements->dim; i++) + { e = (Expression *)elements->data[i]; + if (!e) + continue; + e = e->semantic(sc); + elements->data[i] = (void *)e; + } + expandTuples(elements); + size_t offset = 0; + for (size_t i = 0; i < elements->dim; i++) + { e = (Expression *)elements->data[i]; + if (!e) + continue; + + if (!e->type) + error("%s has no value", e->toChars()); + e = resolveProperties(sc, e); + if (i >= nfields) + { error("more initializers than fields of %s", sd->toChars()); + break; + } + Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + if (v->offset < offset) + error("overlapping initialization for %s", v->toChars()); + offset = v->offset + v->type->size(); + + Type *telem = v->type; + while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray) + { /* Static array initialization, as in: + * T[3][5] = e; + */ + telem = telem->toBasetype()->nextOf(); + } + + e = e->implicitCastTo(sc, telem); + + elements->data[i] = (void *)e; + } + + /* Fill out remainder of elements[] with default initializers for fields[] + */ + for (size_t i = elements->dim; i < nfields; i++) + { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + assert(!v->isThisDeclaration()); + + if (v->offset < offset) + { e = NULL; + sd->hasUnions = 1; + } + else + { + if (v->init) + { e = v->init->toExpression(); + if (!e) + error("cannot make expression out of initializer for %s", v->toChars()); + } + else + { e = v->type->defaultInit(); + e->loc = loc; + } + offset = v->offset + v->type->size(); + } + elements->push(e); + } + + type = sd->type; + return this; +} + +/************************************** + * Gets expression at offset of type. + * Returns NULL if not found. + */ + +Expression *StructLiteralExp::getField(Type *type, unsigned offset) +{ + //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n", +// /*toChars()*/"", type->toChars(), offset); + Expression *e = NULL; + int i = getFieldIndex(type, offset); + + if (i != -1) + { + //printf("\ti = %d\n", i); + assert(i < elements->dim); + e = (Expression *)elements->data[i]; + if (e) + { + e = e->copy(); + e->type = type; + } + } + return e; +} + +/************************************ + * Get index of field. + * Returns -1 if not found. + */ + +int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) +{ + /* Find which field offset is by looking at the field offsets + */ + if (elements->dim) + { + for (size_t i = 0; i < sd->fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + + if (offset == v->offset && + type->size() == v->type->size()) + { Expression *e = (Expression *)elements->data[i]; + if (e) + { + return i; + } + break; + } + } + } + return -1; +} + +#if DMDV2 +int StructLiteralExp::isLvalue() +{ + return 1; +} +#endif + +/* +Removed in LDC. See declaration. +Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) +{ + return this; +} +*/ + + +int StructLiteralExp::checkSideEffect(int flag) +{ int f = 0; + + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + if (!e) + continue; + + f |= e->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +#if DMDV2 +int StructLiteralExp::canThrow() +{ + return arrayExpressionCanThrow(elements); +} +#endif + +void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(sd->toChars()); + buf->writeByte('('); + argsToCBuffer(buf, elements, hgs); + buf->writeByte(')'); +} + +void StructLiteralExp::toMangleBuffer(OutBuffer *buf) +{ + size_t dim = elements ? elements->dim : 0; + buf->printf("S%zu", dim); + for (size_t i = 0; i < dim; i++) + { Expression *e = (Expression *)elements->data[i]; + if (e) + e->toMangleBuffer(buf); + else + buf->writeByte('v'); // 'v' for void + } +} + +/************************ TypeDotIdExp ************************************/ + +/* Things like: + * int.size + * foo.size + * (foo).size + * cast(foo).size + */ + +Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident) +{ + return new DotIdExp(loc, new TypeExp(loc, type), ident); +} + + +/************************************************************/ + +// Mainly just a placeholder + +TypeExp::TypeExp(Loc loc, Type *type) + : Expression(loc, TOKtype, sizeof(TypeExp)) +{ + //printf("TypeExp::TypeExp(%s)\n", type->toChars()); + this->type = type; +} + +Expression *TypeExp::syntaxCopy() +{ + //printf("TypeExp::syntaxCopy()\n"); + return new TypeExp(loc, type->syntaxCopy()); +} + +Expression *TypeExp::semantic(Scope *sc) +{ + //printf("TypeExp::semantic(%s)\n", type->toChars()); + type = type->semantic(loc, sc); + return this; +} + +void TypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + type->toCBuffer(buf, NULL, hgs); +} + +/************************************************************/ + +// Mainly just a placeholder + +ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *pkg) + : Expression(loc, TOKimport, sizeof(ScopeExp)) +{ + //printf("ScopeExp::ScopeExp(pkg = '%s')\n", pkg->toChars()); + //static int count; if (++count == 38) *(char*)0=0; + this->sds = pkg; +} + +Expression *ScopeExp::syntaxCopy() +{ + ScopeExp *se = new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL)); + return se; +} + +Expression *ScopeExp::semantic(Scope *sc) +{ + TemplateInstance *ti; + ScopeDsymbol *sds2; + +#if LOGSEMANTIC + printf("+ScopeExp::semantic('%s')\n", toChars()); +#endif +Lagain: + ti = sds->isTemplateInstance(); + if (ti && !global.errors) + { Dsymbol *s; + if (!ti->semanticdone) + ti->semantic(sc); + s = ti->inst->toAlias(); + sds2 = s->isScopeDsymbol(); + if (!sds2) + { Expression *e; + + //printf("s = %s, '%s'\n", s->kind(), s->toChars()); + if (ti->withsym) + { + // Same as wthis.s + e = new VarExp(loc, ti->withsym->withstate->wthis); + e = new DotVarExp(loc, e, s->isDeclaration()); + } + else + e = new DsymbolExp(loc, s); + e = e->semantic(sc); + //printf("-1ScopeExp::semantic()\n"); + return e; + } + if (sds2 != sds) + { + sds = sds2; + goto Lagain; + } + //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); + } + else + { + //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); + //printf("\tparent = '%s'\n", sds->parent->toChars()); + sds->semantic(sc); + } + type = Type::tvoid; + //printf("-2ScopeExp::semantic() %s\n", toChars()); + return this; +} + +void ScopeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (sds->isTemplateInstance()) + { + sds->toCBuffer(buf, hgs); + } + else + { + buf->writestring(sds->kind()); + buf->writestring(" "); + buf->writestring(sds->toChars()); + } +} + +/********************** TemplateExp **************************************/ + +// Mainly just a placeholder + +TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td) + : Expression(loc, TOKtemplate, sizeof(TemplateExp)) +{ + //printf("TemplateExp(): %s\n", td->toChars()); + this->td = td; +} + +void TemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(td->toChars()); +} + +void TemplateExp::rvalue() +{ + error("template %s has no value", toChars()); +} + +/********************** NewExp **************************************/ + +/* thisexp.new(newargs) newtype(arguments) */ + +NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs, + Type *newtype, Expressions *arguments) + : Expression(loc, TOKnew, sizeof(NewExp)) +{ + this->thisexp = thisexp; + this->newargs = newargs; + this->newtype = newtype; + this->arguments = arguments; + member = NULL; + allocator = NULL; + onstack = 0; +} + +Expression *NewExp::syntaxCopy() +{ + return new NewExp(loc, + thisexp ? thisexp->syntaxCopy() : NULL, + arraySyntaxCopy(newargs), + newtype->syntaxCopy(), arraySyntaxCopy(arguments)); +} + + +Expression *NewExp::semantic(Scope *sc) +{ int i; + Type *tb; + ClassDeclaration *cdthis = NULL; + +#if LOGSEMANTIC + printf("NewExp::semantic() %s\n", toChars()); + if (thisexp) + printf("\tthisexp = %s\n", thisexp->toChars()); + printf("\tnewtype: %s\n", newtype->toChars()); +#endif + if (type) // if semantic() already run + return this; + +Lagain: + if (thisexp) + { thisexp = thisexp->semantic(sc); + cdthis = thisexp->type->isClassHandle(); + if (cdthis) + { + sc = sc->push(cdthis); + type = newtype->semantic(loc, sc); + sc = sc->pop(); + } + else + { + error("'this' for nested class must be a class type, not %s", thisexp->type->toChars()); + type = newtype->semantic(loc, sc); + } + } + else + type = newtype->semantic(loc, sc); + newtype = type; // in case type gets cast to something else + tb = type->toBasetype(); + //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco); + + arrayExpressionSemantic(newargs, sc); + preFunctionArguments(loc, sc, newargs); + arrayExpressionSemantic(arguments, sc); + preFunctionArguments(loc, sc, arguments); + + if (thisexp && tb->ty != Tclass) + error("e.new is only for allocating nested classes, not %s", tb->toChars()); + + if (tb->ty == Tclass) + { TypeFunction *tf; + + TypeClass *tc = (TypeClass *)(tb); + ClassDeclaration *cd = tc->sym->isClassDeclaration(); + if (cd->isInterfaceDeclaration()) + error("cannot create instance of interface %s", cd->toChars()); + else if (cd->isAbstract()) + { error("cannot create instance of abstract class %s", cd->toChars()); + for (int i = 0; i < cd->vtbl.dim; i++) + { FuncDeclaration *fd = ((Dsymbol *)cd->vtbl.data[i])->isFuncDeclaration(); + if (fd && fd->isAbstract()) + error("function %s is abstract", fd->toChars()); + } + } + checkDeprecated(sc, cd); + if (cd->isNested()) + { /* We need a 'this' pointer for the nested class. + * Ensure we have the right one. + */ + Dsymbol *s = cd->toParent2(); + ClassDeclaration *cdn = s->isClassDeclaration(); + FuncDeclaration *fdn = s->isFuncDeclaration(); + + //printf("cd isNested, cdn = %s\n", cdn ? cdn->toChars() : "null"); + if (cdn) + { + if (!cdthis) + { + // Supply an implicit 'this' and try again + thisexp = new ThisExp(loc); + for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) + { if (!sp) + { + error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); + break; + } + ClassDeclaration *cdp = sp->isClassDeclaration(); + if (!cdp) + continue; + if (cdp == cdn || cdn->isBaseOf(cdp, NULL)) + break; + // Add a '.outer' and try again + thisexp = new DotIdExp(loc, thisexp, Id::outer); + } + if (!global.errors) + goto Lagain; + } + if (cdthis) + { + //printf("cdthis = %s\n", cdthis->toChars()); + if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL)) + error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars()); + } +#if 0 + else + { + for (Dsymbol *sf = sc->func; 1; sf= sf->toParent2()->isFuncDeclaration()) + { + if (!sf) + { + error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); + break; + } + printf("sf = %s\n", sf->toChars()); + AggregateDeclaration *ad = sf->isThis(); + if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL))) + break; + } + } +#endif + } + else if (fdn) // Possible problems here, no obvious solution when merging + { /* The nested class cd is nested inside a function, + * we'll let getEthis() look for errors. + */ + //printf("nested class %s is nested inside function %s, we're in %s\n", cd->toChars(), fdn->toChars(), sc->func->toChars()); + if (thisexp) + // Because thisexp cannot be a function frame pointer + error("e.new is only for allocating nested classes"); + } + else + assert(0); + } + else if (thisexp) + error("e.new is only for allocating nested classes"); + + FuncDeclaration *f = NULL; + if (cd->ctor) + f = resolveFuncCall(sc, loc, cd->ctor, NULL, NULL, arguments, 0); + if (f) + { + checkDeprecated(sc, f); + member = f->isCtorDeclaration(); + assert(member); + + cd->accessCheck(loc, sc, member); + + tf = (TypeFunction *)f->type; + + if (!arguments) + arguments = new Expressions(); + functionArguments(loc, sc, tf, arguments); + } + else + { + if (arguments && arguments->dim) + error("no constructor for %s", cd->toChars()); + } + + if (cd->aggNew) + { + // Prepend the size argument to newargs[] + Expression *e = new IntegerExp(loc, cd->size(loc), Type::tsize_t); + if (!newargs) + newargs = new Expressions(); + newargs->shift(e); + + f = cd->aggNew->overloadResolve(loc, NULL, newargs); + allocator = f->isNewDeclaration(); + assert(allocator); + + tf = (TypeFunction *)f->type; + functionArguments(loc, sc, tf, newargs); + } + else + { + if (newargs && newargs->dim) + error("no allocator for %s", cd->toChars()); + } + } + else if (tb->ty == Tstruct) + { + TypeStruct *ts = (TypeStruct *)tb; + StructDeclaration *sd = ts->sym; + TypeFunction *tf; + + FuncDeclaration *f = NULL; + if (sd->ctor) + f = resolveFuncCall(sc, loc, sd->ctor, NULL, NULL, arguments, 0); + if (f) + { + checkDeprecated(sc, f); + member = f->isCtorDeclaration(); + assert(member); + + sd->accessCheck(loc, sc, member); + + tf = (TypeFunction *)f->type; +// type = tf->next; + + if (!arguments) + arguments = new Expressions(); + functionArguments(loc, sc, tf, arguments); + } + else + { + if (arguments && arguments->dim) + error("no constructor for %s", sd->toChars()); + } + + + if (sd->aggNew) + { + // Prepend the uint size argument to newargs[] + Expression *e = new IntegerExp(loc, sd->size(loc), Type::tuns32); + if (!newargs) + newargs = new Expressions(); + newargs->shift(e); + + f = sd->aggNew->overloadResolve(loc, NULL, newargs); + allocator = f->isNewDeclaration(); + assert(allocator); + + tf = (TypeFunction *)f->type; + functionArguments(loc, sc, tf, newargs); +#if 0 + e = new VarExp(loc, f); + e = new CallExp(loc, e, newargs); + e = e->semantic(sc); + e->type = type->pointerTo(); + return e; +#endif + } + else + { + if (newargs && newargs->dim) + error("no allocator for %s", sd->toChars()); + } + + type = type->pointerTo(); + } + else if (tb->ty == Tarray && (arguments && arguments->dim)) + { + for (size_t i = 0; i < arguments->dim; i++) + { + if (tb->ty != Tarray) + { error("too many arguments for array"); + arguments->dim = i; + break; + } + + Expression *arg = (Expression *)arguments->data[i]; + arg = resolveProperties(sc, arg); + arg = arg->implicitCastTo(sc, Type::tsize_t); + arg = arg->optimize(WANTvalue); + if (arg->op == TOKint64 && (long long)arg->toInteger() < 0) + error("negative array index %s", arg->toChars()); + arguments->data[i] = (void *) arg; + tb = ((TypeDArray *)tb)->next->toBasetype(); + } + } + else if (tb->isscalar()) + { + if (arguments && arguments->dim) + error("no constructor for %s", type->toChars()); + + type = type->pointerTo(); + } + else + { + error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars()); + type = type->pointerTo(); + } + +//printf("NewExp: '%s'\n", toChars()); +//printf("NewExp:type '%s'\n", type->toChars()); + + return this; +} + +int NewExp::checkSideEffect(int flag) +{ + return 1; +} + +#if DMDV2 +int NewExp::canThrow() +{ + return 1; +} +#endif + +void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + if (thisexp) + { expToCBuffer(buf, hgs, thisexp, PREC_primary); + buf->writeByte('.'); + } + buf->writestring("new "); + if (newargs && newargs->dim) + { + buf->writeByte('('); + argsToCBuffer(buf, newargs, hgs); + buf->writeByte(')'); + } + newtype->toCBuffer(buf, NULL, hgs); + if (arguments && arguments->dim) + { + buf->writeByte('('); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(')'); + } +} + +/********************** NewAnonClassExp **************************************/ + +NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp, + Expressions *newargs, ClassDeclaration *cd, Expressions *arguments) + : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp)) +{ + this->thisexp = thisexp; + this->newargs = newargs; + this->cd = cd; + this->arguments = arguments; +} + +Expression *NewAnonClassExp::syntaxCopy() +{ + return new NewAnonClassExp(loc, + thisexp ? thisexp->syntaxCopy() : NULL, + arraySyntaxCopy(newargs), + (ClassDeclaration *)cd->syntaxCopy(NULL), + arraySyntaxCopy(arguments)); +} + + +Expression *NewAnonClassExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("NewAnonClassExp::semantic() %s\n", toChars()); + //printf("thisexp = %p\n", thisexp); + //printf("type: %s\n", type->toChars()); +#endif + + Expression *d = new DeclarationExp(loc, cd); + d = d->semantic(sc); + + Expression *n = new NewExp(loc, thisexp, newargs, cd->type, arguments); + + Expression *c = new CommaExp(loc, d, n); + return c->semantic(sc); +} + +int NewAnonClassExp::checkSideEffect(int flag) +{ + return 1; +} + +#if DMDV2 +int NewAnonClassExp::canThrow() +{ + return 1; +} +#endif + +void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + if (thisexp) + { expToCBuffer(buf, hgs, thisexp, PREC_primary); + buf->writeByte('.'); + } + buf->writestring("new"); + if (newargs && newargs->dim) + { + buf->writeByte('('); + argsToCBuffer(buf, newargs, hgs); + buf->writeByte(')'); + } + buf->writestring(" class "); + if (arguments && arguments->dim) + { + buf->writeByte('('); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(')'); + } + //buf->writestring(" { }"); + if (cd) + { + cd->toCBuffer(buf, hgs); + } +} + +/********************** SymbolExp **************************************/ + +#if DMDV2 +SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads) + : Expression(loc, op, size) +{ + assert(var); + this->var = var; + this->hasOverloads = hasOverloads; +} +#endif + +/********************** SymOffExp **************************************/ + +SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads) + : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var, hasOverloads) +{ + this->offset = offset; + m = NULL; + VarDeclaration *v = var->isVarDeclaration(); + if (v && v->needThis()) + error("need 'this' for address of %s", v->toChars()); +} + +Expression *SymOffExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("SymOffExp::semantic('%s')\n", toChars()); +#endif + //var->semantic(sc); + m = sc->module; + if (!type) + type = var->type->pointerTo(); + VarDeclaration *v = var->isVarDeclaration(); + if (v) + v->checkNestedReference(sc, loc); + return this; +} + +int SymOffExp::isBool(int result) +{ + return result ? TRUE : FALSE; +} + +void SymOffExp::checkEscape() +{ + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { + if (!v->isDataseg()) + error("escaping reference to local variable %s", v->toChars()); + } +} + +void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (offset) + buf->printf("(& %s+%u)", var->toChars(), offset); + else + buf->printf("& %s", var->toChars()); +} + +/******************************** VarExp **************************/ + +VarExp::VarExp(Loc loc, Declaration *var, int hasOverloads) + : SymbolExp(loc, TOKvar, sizeof(VarExp), var, hasOverloads) +{ + //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars()); + //if (strcmp(var->ident->toChars(), "func") == 0) halt(); + this->type = var->type; +} + +int VarExp::equals(Object *o) +{ VarExp *ne; + + if (this == o || + (((Expression *)o)->op == TOKvar && + ((ne = (VarExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && + var == ne->var)) + return 1; + return 0; +} + +Expression *VarExp::semantic(Scope *sc) +{ FuncLiteralDeclaration *fd; + +#if LOGSEMANTIC + printf("VarExp::semantic(%s)\n", toChars()); +#endif + if (!type) + { type = var->type; +#if 0 + if (var->storage_class & STClazy) + { + TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd); + type = new TypeDelegate(tf); + type = type->semantic(loc, sc); + } +#endif + } + /* Fix for 1161 doesn't work because it causes protection + * problems when instantiating imported templates passing private + * variables as alias template parameters. + */ + //accessCheck(loc, sc, NULL, var); + + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { +#if 0 + if ((v->isConst() || v->isInvariant()) && + type->toBasetype()->ty != Tsarray && v->init) + { + ExpInitializer *ei = v->init->isExpInitializer(); + if (ei) + { + //ei->exp->implicitCastTo(sc, type)->print(); + return ei->exp->implicitCastTo(sc, type); + } + } +#endif + v->checkNestedReference(sc, loc); +#if DMDV2 +#if 1 + if (sc->func) + { + /* Determine if sc->func is pure or if any function that + * encloses it is also pure. + */ + bool hasPureParent = false; + for (FuncDeclaration *outerfunc = sc->func; outerfunc;) + { + if (outerfunc->isPure()) + { + hasPureParent = true; + break; + } + Dsymbol *parent = outerfunc->toParent2(); + if (!parent) + break; + outerfunc = parent->isFuncDeclaration(); + } + + /* If ANY of its enclosing functions are pure, + * it cannot do anything impure. + * If it is pure, it cannot access any mutable variables other + * than those inside itself + */ + if (hasPureParent && !sc->intypeof && v->isDataseg() && + !v->isInvariant()) + { + error("pure function '%s' cannot access mutable static data '%s'", + sc->func->toChars(), v->toChars()); + } + else if (sc->func->isPure() && sc->parent != v->parent && + !sc->intypeof && !v->isInvariant() && + !(v->storage_class & STCmanifest)) + { + error("pure nested function '%s' cannot access mutable data '%s'", + sc->func->toChars(), v->toChars()); + if (v->isEnumDeclaration()) + error("enum"); + } + } +#else + if (sc->func && sc->func->isPure() && !sc->intypeof) + { + if (v->isDataseg() && !v->isInvariant()) + error("pure function '%s' cannot access mutable static data '%s'", sc->func->toChars(), v->toChars()); + } +#endif +#endif + } +#if 0 + else if ((fd = var->isFuncLiteralDeclaration()) != NULL) + { Expression *e; + e = new FuncExp(loc, fd); + e->type = type; + return e; + } +#endif + return this; +} + +char *VarExp::toChars() +{ + return var->toChars(); +} + +void VarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(var->toChars()); +} + +void VarExp::checkEscape() +{ + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { Type *tb = v->type->toBasetype(); + // if reference type + if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass) + { + if ((v->isAuto() || v->isScope()) && !v->noauto) + error("escaping reference to scope local %s", v->toChars()); + else if (v->storage_class & STCvariadic) + error("escaping reference to variadic parameter %s", v->toChars()); + } + } +} + +#if DMDV2 +int VarExp::isLvalue() +{ + if (var->storage_class & STClazy) + return 0; + return 1; +} +#endif + +Expression *VarExp::toLvalue(Scope *sc, Expression *e) +{ +#if 0 + tym = tybasic(e1->ET->Tty); + if (!(tyscalar(tym) || + tym == TYstruct || + tym == TYarray && e->Eoper == TOKaddr)) + synerr(EM_lvalue); // lvalue expected +#endif + if (var->storage_class & STClazy) + error("lazy variables cannot be lvalues"); + return this; +} + +Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("VarExp::modifiableLvalue('%s')\n", var->toChars()); + if (type && type->toBasetype()->ty == Tsarray) + error("cannot change reference to static array '%s'", var->toChars()); + + var->checkModify(loc, sc, type); + + // See if this expression is a modifiable lvalue (i.e. not const) + return toLvalue(sc, e); +} + + +/******************************** OverExp **************************/ + +#if DMDV2 +OverExp::OverExp(OverloadSet *s) + : Expression(loc, TOKoverloadset, sizeof(OverExp)) +{ + //printf("OverExp(this = %p, '%s')\n", this, var->toChars()); + vars = s; + type = Type::tvoid; +} + +int OverExp::isLvalue() +{ + return 1; +} + +Expression *OverExp::toLvalue(Scope *sc, Expression *e) +{ + return this; +} +#endif + + +/******************************** TupleExp **************************/ + +TupleExp::TupleExp(Loc loc, Expressions *exps) + : Expression(loc, TOKtuple, sizeof(TupleExp)) +{ + //printf("TupleExp(this = %p)\n", this); + this->exps = exps; + this->type = NULL; +} + + +TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) + : Expression(loc, TOKtuple, sizeof(TupleExp)) +{ + exps = new Expressions(); + type = NULL; + + exps->reserve(tup->objects->dim); + for (size_t i = 0; i < tup->objects->dim; i++) + { Object *o = (Object *)tup->objects->data[i]; + if (o->dyncast() == DYNCAST_EXPRESSION) + { + Expression *e = (Expression *)o; + e = e->syntaxCopy(); + exps->push(e); + } + else if (o->dyncast() == DYNCAST_DSYMBOL) + { + Dsymbol *s = (Dsymbol *)o; + Expression *e = new DsymbolExp(loc, s); + exps->push(e); + } + else if (o->dyncast() == DYNCAST_TYPE) + { + Type *t = (Type *)o; + Expression *e = new TypeExp(loc, t); + exps->push(e); + } + else + { + error("%s is not an expression", o->toChars()); + } + } +} + +int TupleExp::equals(Object *o) +{ TupleExp *ne; + + if (this == o) + return 1; + if (((Expression *)o)->op == TOKtuple) + { + TupleExp *te = (TupleExp *)o; + if (exps->dim != te->exps->dim) + return 0; + for (size_t i = 0; i < exps->dim; i++) + { Expression *e1 = (Expression *)exps->data[i]; + Expression *e2 = (Expression *)te->exps->data[i]; + + if (!e1->equals(e2)) + return 0; + } + return 1; + } + return 0; +} + +Expression *TupleExp::syntaxCopy() +{ + return new TupleExp(loc, arraySyntaxCopy(exps)); +} + +Expression *TupleExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("+TupleExp::semantic(%s)\n", toChars()); +#endif + if (type) + return this; + + // Run semantic() on each argument + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->semantic(sc); + if (!e->type) + { error("%s has no value", e->toChars()); + e->type = Type::terror; + } + exps->data[i] = (void *)e; + } + + expandTuples(exps); + if (0 && exps->dim == 1) + { + return (Expression *)exps->data[0]; + } + type = new TypeTuple(exps); + //printf("-TupleExp::semantic(%s)\n", toChars()); + return this; +} + +void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("tuple("); + argsToCBuffer(buf, exps, hgs); + buf->writeByte(')'); +} + +int TupleExp::checkSideEffect(int flag) +{ int f = 0; + + for (int i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + f |= e->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +#if DMDV2 +int TupleExp::canThrow() +{ + return arrayExpressionCanThrow(exps); +} +#endif + +void TupleExp::checkEscape() +{ + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + e->checkEscape(); + } +} + +/******************************** FuncExp *********************************/ + +FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd) + : Expression(loc, TOKfunction, sizeof(FuncExp)) +{ + this->fd = fd; +} + +Expression *FuncExp::syntaxCopy() +{ + return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); +} + +Expression *FuncExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("FuncExp::semantic(%s)\n", toChars()); +#endif + if (!type) + { + fd->semantic(sc); + //fd->parent = sc->parent; + if (global.errors) + { + } + else + { + fd->semantic2(sc); + if (!global.errors) + { + fd->semantic3(sc); + + if (!global.errors && global.params.useInline) + fd->inlineScan(); + } + } + + // Type is a "delegate to" or "pointer to" the function literal + if (fd->isNested()) + { + type = new TypeDelegate(fd->type); + type = type->semantic(loc, sc); + } + else + { + type = fd->type->pointerTo(); + } + fd->tookAddressOf++; + } + return this; +} + +char *FuncExp::toChars() +{ + return fd->toChars(); +} + +void FuncExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + fd->toCBuffer(buf, hgs); + //buf->writestring(fd->toChars()); +} + + +/******************************** DeclarationExp **************************/ + +DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration) + : Expression(loc, TOKdeclaration, sizeof(DeclarationExp)) +{ + this->declaration = declaration; +} + +Expression *DeclarationExp::syntaxCopy() +{ + return new DeclarationExp(loc, declaration->syntaxCopy(NULL)); +} + +Expression *DeclarationExp::semantic(Scope *sc) +{ + if (type) + return this; + +#if LOGSEMANTIC + printf("DeclarationExp::semantic() %s\n", toChars()); +#endif + + /* This is here to support extern(linkage) declaration, + * where the extern(linkage) winds up being an AttribDeclaration + * wrapper. + */ + Dsymbol *s = declaration; + + AttribDeclaration *ad = declaration->isAttribDeclaration(); + if (ad) + { + if (ad->decl && ad->decl->dim == 1) + s = (Dsymbol *)ad->decl->data[0]; + } + + if (s->isVarDeclaration()) + { // Do semantic() on initializer first, so: + // int a = a; + // will be illegal. + declaration->semantic(sc); + s->parent = sc->parent; + } + + //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc); + // Insert into both local scope and function scope. + // Must be unique in both. + if (s->ident) + { + if (!sc->insert(s)) + error("declaration %s is already defined", s->toPrettyChars()); + else if (sc->func) + { VarDeclaration *v = s->isVarDeclaration(); + if (s->isFuncDeclaration() && + !sc->func->localsymtab->insert(s)) + error("declaration %s is already defined in another scope in %s", s->toPrettyChars(), sc->func->toChars()); + else if (!global.params.useDeprecated) + { // Disallow shadowing + + for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing) + { Dsymbol *s2; + + if (scx->scopesym && scx->scopesym->symtab && + (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && + s != s2) + { + error("shadowing declaration %s is deprecated", s->toPrettyChars()); + } + } + } + } + } + if (!s->isVarDeclaration()) + { + declaration->semantic(sc); + s->parent = sc->parent; + } + if (!global.errors) + { + declaration->semantic2(sc); + if (!global.errors) + { + declaration->semantic3(sc); + + if (!global.errors && global.params.useInline) + declaration->inlineScan(); + } + } + + type = Type::tvoid; + return this; +} + +int DeclarationExp::checkSideEffect(int flag) +{ + return 1; +} + +#if DMDV2 +int DeclarationExp::canThrow() +{ + VarDeclaration *v = declaration->isVarDeclaration(); + if (v && v->init) + { ExpInitializer *ie = v->init->isExpInitializer(); + return ie && ie->exp->canThrow(); + } + return 0; +} +#endif + +void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + declaration->toCBuffer(buf, hgs); +} + + +/************************ TypeidExp ************************************/ + +/* + * typeid(int) + */ + +TypeidExp::TypeidExp(Loc loc, Type *typeidType) + : Expression(loc, TOKtypeid, sizeof(TypeidExp)) +{ + this->typeidType = typeidType; +} + + +Expression *TypeidExp::syntaxCopy() +{ + return new TypeidExp(loc, typeidType->syntaxCopy()); +} + + +Expression *TypeidExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("TypeidExp::semantic()\n"); +#endif + typeidType = typeidType->semantic(loc, sc); + e = typeidType->getTypeInfo(sc); + if (e->loc.linnum == 0) + e->loc = loc; // so there's at least some line number info + return e; +} + +void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("typeid("); + typeidType->toCBuffer(buf, NULL, hgs); + buf->writeByte(')'); +} + +/************************ TraitsExp ************************************/ +#if DMDV2 +/* + * __traits(identifier, args...) + */ + +TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args) + : Expression(loc, TOKtraits, sizeof(TraitsExp)) +{ + this->ident = ident; + this->args = args; +} + + +Expression *TraitsExp::syntaxCopy() +{ + return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args)); +} + + +void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("__traits("); + buf->writestring(ident->toChars()); + if (args) + { + for (int i = 0; i < args->dim; i++) + { + buf->writeByte(','); + Object *oarg = (Object *)args->data[i]; + ObjectToCBuffer(buf, hgs, oarg); + } + } + buf->writeByte(')'); +} +#endif + +/************************************************************/ + +HaltExp::HaltExp(Loc loc) + : Expression(loc, TOKhalt, sizeof(HaltExp)) +{ +} + +Expression *HaltExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("HaltExp::semantic()\n"); +#endif + type = Type::tvoid; + return this; +} + +int HaltExp::checkSideEffect(int flag) +{ + return 1; +} + +void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("halt"); +} + +/************************************************************/ + +IsExp::IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, + Type *tspec, enum TOK tok2, TemplateParameters *parameters) + : Expression(loc, TOKis, sizeof(IsExp)) +{ + this->targ = targ; + this->id = id; + this->tok = tok; + this->tspec = tspec; + this->tok2 = tok2; + this->parameters = parameters; +} + +Expression *IsExp::syntaxCopy() +{ + // This section is identical to that in TemplateDeclaration::syntaxCopy() + TemplateParameters *p = NULL; + if (parameters) + { + p = new TemplateParameters(); + p->setDim(parameters->dim); + for (int i = 0; i < p->dim; i++) + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + p->data[i] = (void *)tp->syntaxCopy(); + } + } + + return new IsExp(loc, + targ->syntaxCopy(), + id, + tok, + tspec ? tspec->syntaxCopy() : NULL, + tok2, + p); +} + +Expression *IsExp::semantic(Scope *sc) +{ Type *tded; + + /* is(targ id tok tspec) + * is(targ id == tok2) + */ + + //printf("IsExp::semantic(%s)\n", toChars()); + if (id && !(sc->flags & SCOPEstaticif)) + error("can only declare type aliases within static if conditionals"); + + Type *t = targ->trySemantic(loc, sc); + if (!t) + goto Lno; // errors, so condition is false + targ = t; + if (tok2 != TOKreserved) + { + switch (tok2) + { + case TOKtypedef: + if (targ->ty != Ttypedef) + goto Lno; + tded = ((TypeTypedef *)targ)->sym->basetype; + break; + + case TOKstruct: + if (targ->ty != Tstruct) + goto Lno; + if (((TypeStruct *)targ)->sym->isUnionDeclaration()) + goto Lno; + tded = targ; + break; + + case TOKunion: + if (targ->ty != Tstruct) + goto Lno; + if (!((TypeStruct *)targ)->sym->isUnionDeclaration()) + goto Lno; + tded = targ; + break; + + case TOKclass: + if (targ->ty != Tclass) + goto Lno; + if (((TypeClass *)targ)->sym->isInterfaceDeclaration()) + goto Lno; + tded = targ; + break; + + case TOKinterface: + if (targ->ty != Tclass) + goto Lno; + if (!((TypeClass *)targ)->sym->isInterfaceDeclaration()) + goto Lno; + tded = targ; + break; +#if DMDV2 + case TOKconst: + if (!targ->isConst()) + goto Lno; + tded = targ; + break; + + case TOKinvariant: + case TOKimmutable: + if (!targ->isInvariant()) + goto Lno; + tded = targ; + break; +#endif + + case TOKsuper: + // If class or interface, get the base class and interfaces + if (targ->ty != Tclass) + goto Lno; + else + { ClassDeclaration *cd = ((TypeClass *)targ)->sym; + Arguments *args = new Arguments; + args->reserve(cd->baseclasses.dim); + for (size_t i = 0; i < cd->baseclasses.dim; i++) + { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; + args->push(new Argument(STCin, b->type, NULL, NULL)); + } + tded = new TypeTuple(args); + } + break; + + case TOKenum: + if (targ->ty != Tenum) + goto Lno; + tded = ((TypeEnum *)targ)->sym->memtype; + break; + + case TOKdelegate: + if (targ->ty != Tdelegate) + goto Lno; + tded = ((TypeDelegate *)targ)->next; // the underlying function type + break; + + case TOKfunction: + { + if (targ->ty != Tfunction) + goto Lno; + tded = targ; + + /* Generate tuple from function parameter types. + */ + assert(tded->ty == Tfunction); + Arguments *params = ((TypeFunction *)tded)->parameters; + size_t dim = Argument::dim(params); + Arguments *args = new Arguments; + args->reserve(dim); + for (size_t i = 0; i < dim; i++) + { Argument *arg = Argument::getNth(params, i); + assert(arg && arg->type); + args->push(new Argument(arg->storageClass, arg->type, NULL, NULL)); + } + tded = new TypeTuple(args); + break; + } + case TOKreturn: + /* Get the 'return type' for the function, + * delegate, or pointer to function. + */ + if (targ->ty == Tfunction) + tded = ((TypeFunction *)targ)->next; + else if (targ->ty == Tdelegate) + { tded = ((TypeDelegate *)targ)->next; + tded = ((TypeFunction *)tded)->next; + } + else if (targ->ty == Tpointer && + ((TypePointer *)targ)->next->ty == Tfunction) + { tded = ((TypePointer *)targ)->next; + tded = ((TypeFunction *)tded)->next; + } + else + goto Lno; + break; + + default: + assert(0); + } + goto Lyes; + } + else if (id && tspec) + { + /* Evaluate to TRUE if targ matches tspec. + * If TRUE, declare id as an alias for the specialized type. + */ + + MATCH m; + assert(parameters && parameters->dim); + + Objects dedtypes; + dedtypes.setDim(parameters->dim); + dedtypes.zero(); + + m = targ->deduceType(NULL, tspec, parameters, &dedtypes); + if (m == MATCHnomatch || + (m != MATCHexact && tok == TOKequal)) + { + goto Lno; + } + else + { + tded = (Type *)dedtypes.data[0]; + if (!tded) + tded = targ; + + Objects tiargs; + tiargs.setDim(1); + tiargs.data[0] = (void *)targ; + + /* Declare trailing parameters + */ + for (int i = 1; i < parameters->dim; i++) + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + Declaration *s = NULL; + + m = tp->matchArg(sc, &tiargs, i, parameters, &dedtypes, &s); + if (m == MATCHnomatch) + goto Lno; + s->semantic(sc); + if (!sc->insert(s)) + error("declaration %s is already defined", s->toChars()); +#if 0 + Object *o = (Object *)dedtypes.data[i]; + Dsymbol *s = TemplateDeclaration::declareParameter(loc, sc, tp, o); +#endif + if (sc->sd) + s->addMember(sc, sc->sd, 1); + } + + goto Lyes; + } + } + else if (id) + { + /* Declare id as an alias for type targ. Evaluate to TRUE + */ + tded = targ; + goto Lyes; + } + else if (tspec) + { + /* Evaluate to TRUE if targ matches tspec + * is(targ == tspec) + * is(targ : tspec) + */ + tspec = tspec->semantic(loc, sc); + //printf("targ = %s\n", targ->toChars()); + //printf("tspec = %s\n", tspec->toChars()); + if (tok == TOKcolon) + { if (targ->implicitConvTo(tspec)) + goto Lyes; + else + goto Lno; + } + else /* == */ + { if (targ->equals(tspec)) + goto Lyes; + else + goto Lno; + } + } + +Lyes: + if (id) + { + Dsymbol *s = new AliasDeclaration(loc, id, tded); + s->semantic(sc); + if (!sc->insert(s)) + error("declaration %s is already defined", s->toChars()); + if (sc->sd) + s->addMember(sc, sc->sd, 1); + } +//printf("Lyes\n"); + return new IntegerExp(loc, 1, Type::tbool); + +Lno: +//printf("Lno\n"); + return new IntegerExp(loc, 0, Type::tbool); +} + +void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("is("); + targ->toCBuffer(buf, id, hgs); + if (tok2 != TOKreserved) + { + buf->printf(" %s %s", Token::toChars(tok), Token::toChars(tok2)); + } + else if (tspec) + { + if (tok == TOKcolon) + buf->writestring(" : "); + else + buf->writestring(" == "); + tspec->toCBuffer(buf, NULL, hgs); + } +#if DMDV2 + if (parameters) + { // First parameter is already output, so start with second + for (int i = 1; i < parameters->dim; i++) + { + buf->writeByte(','); + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + tp->toCBuffer(buf, hgs); + } + } +#endif + buf->writeByte(')'); +} + + +/************************************************************/ + +UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) + : Expression(loc, op, size) +{ + this->e1 = e1; +} + +Expression *UnaExp::syntaxCopy() +{ UnaExp *e; + + e = (UnaExp *)copy(); + e->type = NULL; + e->e1 = e->e1->syntaxCopy(); + return e; +} + +Expression *UnaExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("UnaExp::semantic('%s')\n", toChars()); +#endif + e1 = e1->semantic(sc); +// if (!e1->type) +// error("%s has no value", e1->toChars()); + return this; +} + +#if DMDV2 +int UnaExp::canThrow() +{ + return e1->canThrow(); +} +#endif + +void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + +/************************************************************/ + +BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) + : Expression(loc, op, size) +{ + this->e1 = e1; + this->e2 = e2; +} + +Expression *BinExp::syntaxCopy() +{ BinExp *e; + + e = (BinExp *)copy(); + e->type = NULL; + e->e1 = e->e1->syntaxCopy(); + e->e2 = e->e2->syntaxCopy(); + return e; +} + +Expression *BinExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("BinExp::semantic('%s')\n", toChars()); +#endif + e1 = e1->semantic(sc); + if (!e1->type && + !(op == TOKassign && e1->op == TOKdottd)) // a.template = e2 + { + error("%s has no value", e1->toChars()); + e1->type = Type::terror; + } + e2 = e2->semantic(sc); + if (!e2->type) + { + error("%s has no value", e2->toChars()); + e2->type = Type::terror; + } + return this; +} + +Expression *BinExp::semanticp(Scope *sc) +{ + BinExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e2 = resolveProperties(sc, e2); + return this; +} + +/*************************** + * Common semantic routine for some xxxAssignExp's. + */ + +Expression *BinExp::commonSemanticAssign(Scope *sc) +{ Expression *e; + + if (!type) + { + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKslice) + { // T[] op= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + type = e1->type; + if (type->toBasetype()->ty == Tbool) + { + error("operator not allowed on bool expression %s", toChars()); + } + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + + if (op == TOKmodass && e2->type->iscomplex()) + { error("cannot perform modulo complex arithmetic"); + return new ErrorExp(); + } + } + return this; +} + +Expression *BinExp::commonSemanticAssignIntegral(Scope *sc) +{ Expression *e; + + if (!type) + { + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKslice) + { // T[] op= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + type = e1->type; + if (type->toBasetype()->ty == Tbool) + { + e2 = e2->implicitCastTo(sc, type); + } + + typeCombine(sc); + e1->checkIntegral(); + e2->checkIntegral(); + } + return this; +} + +int BinExp::checkSideEffect(int flag) +{ + if (op == TOKplusplus || + op == TOKminusminus || + op == TOKassign || + op == TOKconstruct || + op == TOKblit || + op == TOKaddass || + op == TOKminass || + op == TOKcatass || + op == TOKmulass || + op == TOKdivass || + op == TOKmodass || + op == TOKshlass || + op == TOKshrass || + op == TOKushrass || + op == TOKandass || + op == TOKorass || + op == TOKxorass || + op == TOKin || + op == TOKremove) + return 1; + return Expression::checkSideEffect(flag); +} + +void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writeByte(' '); + buf->writestring(Token::toChars(op)); + buf->writeByte(' '); + expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); +} + +int BinExp::isunsigned() +{ + return e1->type->isunsigned() || e2->type->isunsigned(); +} + +#if DMDV2 +int BinExp::canThrow() +{ + return e1->canThrow() || e2->canThrow(); +} +#endif + +void BinExp::incompatibleTypes() +{ + error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", + e1->toChars(), Token::toChars(op), e2->toChars(), + e1->type->toChars(), e2->type->toChars()); +} + +/************************************************************/ + +CompileExp::CompileExp(Loc loc, Expression *e) + : UnaExp(loc, TOKmixin, sizeof(CompileExp), e) +{ +} + +Expression *CompileExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("CompileExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->optimize(WANTvalue | WANTinterpret); + if (e1->op != TOKstring) + { error("argument to mixin must be a string, not (%s)", e1->toChars()); + type = Type::terror; + return this; + } + StringExp *se = (StringExp *)e1; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + //printf("p.loc.linnum = %d\n", p.loc.linnum); + Expression *e = p.parseExpression(); + if (p.token.value != TOKeof) + error("incomplete mixin expression (%s)", se->toChars()); + return e->semantic(sc); +} + +void CompileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin("); + expToCBuffer(buf, hgs, e1, PREC_assign); + buf->writeByte(')'); +} + +/************************************************************/ + +FileExp::FileExp(Loc loc, Expression *e) + : UnaExp(loc, TOKmixin, sizeof(FileExp), e) +{ +} + +Expression *FileExp::semantic(Scope *sc) +{ char *name; + StringExp *se; + +#if LOGSEMANTIC + printf("FileExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->optimize(WANTvalue); + if (e1->op != TOKstring) + { error("file name argument must be a string, not (%s)", e1->toChars()); + goto Lerror; + } + se = (StringExp *)e1; + se = se->toUTF8(sc); + name = (char *)se->string; + + if (!global.params.fileImppath) + { error("need -Jpath switch to import text file %s", name); + goto Lerror; + } + + if (name != FileName::name(name)) + { error("use -Jpath switch to provide path for filename %s", name); + goto Lerror; + } + + name = FileName::searchPath(global.filePath, name, 0); + if (!name) + { error("file %s cannot be found, check -Jpath", se->toChars()); + goto Lerror; + } + + if (global.params.verbose) + printf("file %s\t(%s)\n", (char*)se->string, name); + + { File f(name); + if (f.read()) + { error("cannot read file %s", f.toChars()); + goto Lerror; + } + else + { + f.ref = 1; + se = new StringExp(loc, f.buffer, f.len); + } + } + Lret: + return se->semantic(sc); + + Lerror: + se = new StringExp(loc, (char *)""); + goto Lret; +} + +void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("import("); + expToCBuffer(buf, hgs, e1, PREC_assign); + buf->writeByte(')'); +} + +/************************************************************/ + +AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg) + : UnaExp(loc, TOKassert, sizeof(AssertExp), e) +{ + this->msg = msg; +} + +Expression *AssertExp::syntaxCopy() +{ + AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(), + msg ? msg->syntaxCopy() : NULL); + return ae; +} + +Expression *AssertExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("AssertExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + // BUG: see if we can do compile time elimination of the Assert + e1 = e1->optimize(WANTvalue); + e1 = e1->checkToBoolean(); + if (msg) + { + msg = msg->semantic(sc); + msg = resolveProperties(sc, msg); + msg = msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf()); + msg = msg->optimize(WANTvalue); + } + if (e1->isBool(FALSE)) + { + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + fd->hasReturnExp |= 4; + + if (!global.params.useAssert) + { Expression *e = new HaltExp(loc); + e = e->semantic(sc); + return e; + } + } + type = Type::tvoid; + return this; +} + +int AssertExp::checkSideEffect(int flag) +{ + return 1; +} + +#if DMDV2 +int AssertExp::canThrow() +{ + /* assert()s are non-recoverable errors, so functions that + * use them can be considered "nothrow" + */ + return 0; //(global.params.useAssert != 0); +} +#endif + +void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("assert("); + expToCBuffer(buf, hgs, e1, PREC_assign); + if (msg) + { + buf->writeByte(','); + expToCBuffer(buf, hgs, msg, PREC_assign); + } + buf->writeByte(')'); +} + +/************************************************************/ + +DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident) + : UnaExp(loc, TOKdot, sizeof(DotIdExp), e) +{ + this->ident = ident; +} + +Expression *DotIdExp::semantic(Scope *sc) +{ Expression *e; + Expression *eleft; + Expression *eright; + +#if LOGSEMANTIC + printf("DotIdExp::semantic(this = %p, '%s')\n", this, toChars()); + //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); +#endif + +//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } + +#if 0 + /* Don't do semantic analysis if we'll be converting + * it to a string. + */ + if (ident == Id::stringof) + { char *s = e1->toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + e = e->semantic(sc); + return e; + } +#endif + + /* Special case: rewrite this.id and super.id + * to be classtype.id and baseclasstype.id + * if we have no this pointer. + */ + if ((e1->op == TOKthis || e1->op == TOKsuper) && !hasThis(sc)) + { ClassDeclaration *cd; + StructDeclaration *sd; + AggregateDeclaration *ad; + + ad = sc->getStructClassScope(); + if (ad) + { + cd = ad->isClassDeclaration(); + if (cd) + { + if (e1->op == TOKthis) + { + e = typeDotIdExp(loc, cd->type, ident); + return e->semantic(sc); + } + else if (cd->baseClass && e1->op == TOKsuper) + { + e = typeDotIdExp(loc, cd->baseClass->type, ident); + return e->semantic(sc); + } + } + else + { + sd = ad->isStructDeclaration(); + if (sd) + { + if (e1->op == TOKthis) + { + e = typeDotIdExp(loc, sd->type, ident); + return e->semantic(sc); + } + } + } + } + } + + UnaExp::semantic(sc); + + if (e1->op == TOKdotexp) + { + DotExp *de = (DotExp *)e1; + eleft = de->e1; + eright = de->e2; + } + else + { + e1 = resolveProperties(sc, e1); + eleft = NULL; + eright = e1; + } +#if DMDV2 + if (e1->op == TOKtuple && ident == Id::offsetof) + { /* 'distribute' the .offsetof to each of the tuple elements. + */ + TupleExp *te = (TupleExp *)e1; + Expressions *exps = new Expressions(); + exps->setDim(te->exps->dim); + for (int i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)te->exps->data[i]; + e = e->semantic(sc); + e = new DotIdExp(e->loc, e, Id::offsetof); + exps->data[i] = (void *)e; + } + e = new TupleExp(loc, exps); + e = e->semantic(sc); + return e; + } +#endif + + if (e1->op == TOKtuple && ident == Id::length) + { + TupleExp *te = (TupleExp *)e1; + e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); + return e; + } + + if (e1->op == TOKdottd) + { + error("template %s does not have property %s", e1->toChars(), ident->toChars()); + return e1; + } + + if (!e1->type) + { + error("expression %s does not have property %s", e1->toChars(), ident->toChars()); + return e1; + } + + Type *t1b = e1->type->toBasetype(); + + if (eright->op == TOKimport) // also used for template alias's + { + ScopeExp *ie = (ScopeExp *)eright; + + /* Disable access to another module's private imports. + * The check for 'is sds our current module' is because + * the current module should have access to its own imports. + */ + Dsymbol *s = ie->sds->search(loc, ident, + (ie->sds->isModule() && ie->sds != sc->module) ? 1 : 0); + if (s) + { + s = s->toAlias(); + checkDeprecated(sc, s); + + EnumMember *em = s->isEnumMember(); + if (em) + { + e = em->value; + e = e->semantic(sc); + return e; + } + + VarDeclaration *v = s->isVarDeclaration(); + if (v) + { + //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); + if (v->inuse) + { + error("circular reference to '%s'", v->toChars()); + type = Type::tint32; + return this; + } + type = v->type; + if (v->needThis()) + { + if (!eleft) + eleft = new ThisExp(loc); + e = new DotVarExp(loc, eleft, v); + e = e->semantic(sc); + } + else + { + e = new VarExp(loc, v); + if (eleft) + { e = new CommaExp(loc, eleft, e); + e->type = v->type; + } + } + return e->deref(); + } + + FuncDeclaration *f = s->isFuncDeclaration(); + if (f) + { + //printf("it's a function\n"); + if (f->needThis()) + { + if (!eleft) + eleft = new ThisExp(loc); + e = new DotVarExp(loc, eleft, f); + e = e->semantic(sc); + } + else + { + e = new VarExp(loc, f, 1); + if (eleft) + { e = new CommaExp(loc, eleft, e); + e->type = f->type; + } + } + return e; + } +#if DMDV2 + OverloadSet *o = s->isOverloadSet(); + if (o) + { //printf("'%s' is an overload set\n", o->toChars()); + return new OverExp(o); + } +#endif + + Type *t = s->getType(); + if (t) + { + return new TypeExp(loc, t); + } + + TupleDeclaration *tup = s->isTupleDeclaration(); + if (tup) + { + if (eleft) + error("cannot have e.tuple"); + e = new TupleExp(loc, tup); + e = e->semantic(sc); + return e; + } + + ScopeDsymbol *sds = s->isScopeDsymbol(); + if (sds) + { + //printf("it's a ScopeDsymbol\n"); + e = new ScopeExp(loc, sds); + e = e->semantic(sc); + if (eleft) + e = new DotExp(loc, eleft, e); + return e; + } + + Import *imp = s->isImport(); + if (imp) + { + ScopeExp *ie; + + ie = new ScopeExp(loc, imp->pkg); + return ie->semantic(sc); + } + + // BUG: handle other cases like in IdentifierExp::semantic() +#ifdef DEBUG + printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind()); +#endif + assert(0); + } + else if (ident == Id::stringof) + { char *s = ie->toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + e = e->semantic(sc); + return e; + } + error("undefined identifier %s", toChars()); + type = Type::tvoid; + return this; + } + else if (t1b->ty == Tpointer && + ident != Id::init && ident != Id::__sizeof && + ident != Id::alignof && ident != Id::offsetof && + ident != Id::mangleof && ident != Id::stringof) + { /* Rewrite: + * p.ident + * as: + * (*p).ident + */ + e = new PtrExp(loc, e1); + e->type = ((TypePointer *)t1b)->next; + return e->type->dotExp(sc, e, ident); + } +#if DMDV2 + else if (t1b->ty == Tarray || + t1b->ty == Tsarray || + t1b->ty == Taarray) + { /* If ident is not a valid property, rewrite: + * e1.ident + * as: + * .ident(e1) + */ + unsigned errors = global.errors; + global.gag++; + e = e1->type->dotExp(sc, e1, ident); + global.gag--; + if (errors != global.errors) // if failed to find the property + { + global.errors = errors; + e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); + e = new CallExp(loc, e, e1); + } + e = e->semantic(sc); + return e; + } +#endif + else + { + e = e1->type->dotExp(sc, e1, ident); + e = e->semantic(sc); + return e; + } +} + +void DotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + //printf("DotIdExp::toCBuffer()\n"); + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(ident->toChars()); +} + +/********************** DotTemplateExp ***********************************/ + +// Mainly just a placeholder + +DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td) + : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e) + +{ + this->td = td; +} + +void DotTemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(td->toChars()); +} + + +/************************************************************/ + +DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *v, int hasOverloads) + : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e) +{ + //printf("DotVarExp()\n"); + this->var = v; + this->hasOverloads = hasOverloads; +} + +Expression *DotVarExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotVarExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + var = var->toAlias()->isDeclaration(); + + TupleDeclaration *tup = var->isTupleDeclaration(); + if (tup) + { /* Replace: + * e1.tuple(a, b, c) + * with: + * tuple(e1.a, e1.b, e1.c) + */ + Expressions *exps = new Expressions; + + exps->reserve(tup->objects->dim); + for (size_t i = 0; i < tup->objects->dim; i++) + { Object *o = (Object *)tup->objects->data[i]; + if (o->dyncast() != DYNCAST_EXPRESSION) + { + error("%s is not an expression", o->toChars()); + } + else + { + Expression *e = (Expression *)o; + if (e->op != TOKdsymbol) + error("%s is not a member", e->toChars()); + else + { DsymbolExp *ve = (DsymbolExp *)e; + + e = new DotVarExp(loc, e1, ve->s->isDeclaration()); + exps->push(e); + } + } + } + Expression *e = new TupleExp(loc, exps); + e = e->semantic(sc); + return e; + } + + e1 = e1->semantic(sc); + type = var->type; + if (!type && global.errors) + { // var is goofed up, just return 0 + return new ErrorExp(); + } + assert(type); + + if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution + { + Type *t1 = e1->type; + if (t1->ty == Tpointer) + t1 = t1->nextOf(); + + type = type->addMod(t1->mod); + + Dsymbol *vparent = var->toParent(); + AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL; + e1 = getRightThis(loc, sc, ad, e1, var); + if (!sc->noaccesscheck) + accessCheck(loc, sc, e1, var); + + VarDeclaration *v = var->isVarDeclaration(); + Expression *e = expandVar(WANTvalue, v); + if (e) + return e; + } + } + //printf("-DotVarExp::semantic('%s')\n", toChars()); + return this; +} + +#if DMDV2 +int DotVarExp::isLvalue() +{ + return 1; +} +#endif + +Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) +{ + //printf("DotVarExp::toLvalue(%s)\n", toChars()); + return this; +} + +Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) +{ +#if 0 + printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); + printf("e1->type = %s\n", e1->type->toChars()); + printf("var->type = %s\n", var->type->toChars()); +#endif + + if (var->isCtorinit()) + { // It's only modifiable if inside the right constructor + Dsymbol *s = sc->func; + while (1) + { + FuncDeclaration *fd = NULL; + if (s) + fd = s->isFuncDeclaration(); + if (fd && + ((fd->isCtorDeclaration() && var->storage_class & STCfield) || + (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) && + fd->toParent() == var->toParent() && + e1->op == TOKthis + ) + { + VarDeclaration *v = var->isVarDeclaration(); + assert(v); + v->ctorinit = 1; + //printf("setting ctorinit\n"); + } + else + { + if (s) + { s = s->toParent2(); + continue; + } + else + { + const char *p = var->isStatic() ? "static " : ""; + error("can only initialize %sconst member %s inside %sconstructor", + p, var->toChars(), p); + } + } + break; + } + } +#if DMDV2 + else + { + Type *t1 = e1->type->toBasetype(); + + if (!t1->isMutable() || + (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || + !var->type->isMutable() || + !var->type->isAssignable() || + var->storage_class & STCmanifest + ) + error("cannot modify const/immutable expression %s", toChars()); + } +#endif + return this; +} + +void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(var->toChars()); +} + +/************************************************************/ + +/* Things like: + * foo.bar!(args) + */ + +DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti) + : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e) +{ + //printf("DotTemplateInstanceExp()\n"); + this->ti = ti; +} + +Expression *DotTemplateInstanceExp::syntaxCopy() +{ + DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, + e1->syntaxCopy(), + (TemplateInstance *)ti->syntaxCopy(NULL)); + return de; +} + +Expression *DotTemplateInstanceExp::semantic(Scope *sc) +{ Dsymbol *s; + Dsymbol *s2; + TemplateDeclaration *td; + Expression *e; + Identifier *id; + Type *t1; + Expression *eleft = NULL; + Expression *eright; + +#if LOGSEMANTIC + printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); +#endif + //e1->print(); + //print(); + e1 = e1->semantic(sc); + t1 = e1->type; + if (t1) + t1 = t1->toBasetype(); + //t1->print(); + + /* Extract the following from e1: + * s: the symbol which ti should be a member of + * eleft: if not NULL, it is the 'this' pointer for ti + */ + + if (e1->op == TOKdotexp) + { DotExp *de = (DotExp *)e1; + eleft = de->e1; + eright = de->e2; + } + else + { eleft = NULL; + eright = e1; + } + if (eright->op == TOKimport) + { + s = ((ScopeExp *)eright)->sds; + } + else if (e1->op == TOKtype) + { + s = t1->isClassHandle(); + if (!s) + { if (t1->ty == Tstruct) + s = ((TypeStruct *)t1)->sym; + else + goto L1; + } + } + else if (t1 && (t1->ty == Tstruct || t1->ty == Tclass)) + { + s = t1->toDsymbol(sc); + eleft = e1; + } + else if (t1 && t1->ty == Tpointer) + { + t1 = ((TypePointer *)t1)->next->toBasetype(); + if (t1->ty != Tstruct) + goto L1; + s = t1->toDsymbol(sc); + eleft = e1; + } + else + { + L1: + error("template %s is not a member of %s", ti->toChars(), e1->toChars()); + goto Lerr; + } + + assert(s); + id = ti->name; + s2 = s->search(loc, id, 0); + if (!s2) + { + if (!s->ident) + error("template identifier %s is not a member of undefined %s", id->toChars(), s->kind()); + else + error("template identifier %s is not a member of %s %s", id->toChars(), s->kind(), s->ident->toChars()); + goto Lerr; + } + s = s2; + s->semantic(sc); + s = s->toAlias(); + td = s->isTemplateDeclaration(); + if (!td) + { + error("%s is not a template", id->toChars()); + goto Lerr; + } + if (global.errors) + goto Lerr; + + ti->tempdecl = td; + + if (eleft) + { Declaration *v; + + ti->semantic(sc); + s = ti->inst->toAlias(); + v = s->isDeclaration(); + if (v) + { e = new DotVarExp(loc, eleft, v); + e = e->semantic(sc); + return e; + } + } + + e = new ScopeExp(loc, ti); + if (eleft) + { + e = new DotExp(loc, eleft, e); + } + e = e->semantic(sc); + return e; + +Lerr: + return new ErrorExp(); +} + +void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + ti->toCBuffer(buf, hgs); +} + +/************************************************************/ + +DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, int hasOverloads) + : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e) +{ + this->func = f; + this->hasOverloads = hasOverloads; +} + +Expression *DelegateExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DelegateExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + m = sc->module; + e1 = e1->semantic(sc); + // LDC we need a copy as we store the LLVM tpye in TypeFunction, and delegate/members have different types for 'this' + type = new TypeDelegate(func->type->syntaxCopy()); + type = type->semantic(loc, sc); + AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); + if (func->needThis()) + e1 = getRightThis(loc, sc, ad, e1, func); + } + return this; +} + +void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('&'); + if (!func->isNested()) + { + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + } + buf->writestring(func->toChars()); +} + +/************************************************************/ + +DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s) + : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e) +{ + this->sym = s; + this->type = s->getType(); +} + +Expression *DotTypeExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotTypeExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + return this; +} + +void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(sym->toChars()); +} + +/************************************************************/ + +CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + this->arguments = exps; +} + +CallExp::CallExp(Loc loc, Expression *e) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + this->arguments = NULL; +} + +CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + Expressions *arguments = new Expressions(); + arguments->setDim(1); + arguments->data[0] = (void *)earg1; + + this->arguments = arguments; +} + +CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + Expressions *arguments = new Expressions(); + arguments->setDim(2); + arguments->data[0] = (void *)earg1; + arguments->data[1] = (void *)earg2; + + this->arguments = arguments; +} + +Expression *CallExp::syntaxCopy() +{ + return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); +} + + +Expression *CallExp::semantic(Scope *sc) +{ + TypeFunction *tf; + FuncDeclaration *f; + int i; + Type *t1; + int istemp; + Objects *targsi = NULL; // initial list of template arguments + TemplateInstance *tierror = NULL; + +#if LOGSEMANTIC + printf("CallExp::semantic() %s\n", toChars()); +#endif + if (type) + return this; // semantic() already run +#if 0 + if (arguments && arguments->dim) + { + Expression *earg = (Expression *)arguments->data[0]; + earg->print(); + if (earg->type) earg->type->print(); + } +#endif + + if (e1->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)e1; + + e1 = new DotVarExp(de->loc, de->e1, de->func); + return semantic(sc); + } + + /* Transform: + * array.id(args) into .id(array,args) + * aa.remove(arg) into delete aa[arg] + */ + if (e1->op == TOKdot) + { + // BUG: we should handle array.a.b.c.e(args) too + + DotIdExp *dotid = (DotIdExp *)(e1); + dotid->e1 = dotid->e1->semantic(sc); + assert(dotid->e1); + if (dotid->e1->type) + { + TY e1ty = dotid->e1->type->toBasetype()->ty; + if (e1ty == Taarray && dotid->ident == Id::remove) + { + if (!arguments || arguments->dim != 1) + { error("expected key as argument to aa.remove()"); + goto Lagain; + } + Expression *key = (Expression *)arguments->data[0]; + key = key->semantic(sc); + key = resolveProperties(sc, key); + key->rvalue(); + + TypeAArray *taa = (TypeAArray *)dotid->e1->type->toBasetype(); + key = key->implicitCastTo(sc, taa->index); + + return new RemoveExp(loc, dotid->e1, key); + } + else if (e1ty == Tarray || e1ty == Tsarray || e1ty == Taarray) + { + if (!arguments) + arguments = new Expressions(); + arguments->shift(dotid->e1); +#if DMDV2 + e1 = new DotIdExp(dotid->loc, new IdentifierExp(dotid->loc, Id::empty), dotid->ident); +#else + e1 = new IdentifierExp(dotid->loc, dotid->ident); +#endif + } + } + } + +#if DMDV2 + /* This recognizes: + * foo!(tiargs)(funcargs) + */ + if (e1->op == TOKimport && !e1->type) + { ScopeExp *se = (ScopeExp *)e1; + TemplateInstance *ti = se->sds->isTemplateInstance(); + if (ti && !ti->semanticdone) + { + /* Attempt to instantiate ti. If that works, go with it. + * If not, go with partial explicit specialization. + */ + ti->semanticTiargs(sc); + unsigned errors = global.errors; + global.gag++; + ti->semantic(sc); + global.gag--; + if (errors != global.errors) + { + /* Didn't work, go with partial explicit specialization + */ + global.errors = errors; + targsi = ti->tiargs; + tierror = ti; // for error reporting + e1 = new IdentifierExp(loc, ti->name); + } + } + } + + /* This recognizes: + * expr.foo!(tiargs)(funcargs) + */ + if (e1->op == TOKdotti && !e1->type) + { DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)e1; + TemplateInstance *ti = se->ti; + if (!ti->semanticdone) + { + /* Attempt to instantiate ti. If that works, go with it. + * If not, go with partial explicit specialization. + */ + ti->semanticTiargs(sc); + Expression *etmp = e1->trySemantic(sc); + if (etmp) + e1 = etmp; // it worked + else // didn't work + { + targsi = ti->tiargs; + tierror = ti; // for error reporting + e1 = new DotIdExp(loc, se->e1, ti->name); + } + } + } +#endif + + istemp = 0; +Lagain: + //printf("Lagain: %s\n", toChars()); + f = NULL; + if (e1->op == TOKthis || e1->op == TOKsuper) + { + // semantic() run later for these + } + else + { + UnaExp::semantic(sc); + + /* Look for e1 being a lazy parameter + */ + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + + if (ve->var->storage_class & STClazy) + { + TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd); + TypeDelegate *t = new TypeDelegate(tf); + ve->type = t->semantic(loc, sc); + } + } + + if (e1->op == TOKimport) + { // Perhaps this should be moved to ScopeExp::semantic() + ScopeExp *se = (ScopeExp *)e1; + e1 = new DsymbolExp(loc, se->sds); + e1 = e1->semantic(sc); + } +#if 1 // patch for #540 by Oskar Linde + else if (e1->op == TOKdotexp) + { + DotExp *de = (DotExp *) e1; + + if (de->e2->op == TOKimport) + { // This should *really* be moved to ScopeExp::semantic() + ScopeExp *se = (ScopeExp *)de->e2; + de->e2 = new DsymbolExp(loc, se->sds); + de->e2 = de->e2->semantic(sc); + } + + if (de->e2->op == TOKtemplate) + { TemplateExp *te = (TemplateExp *) de->e2; + e1 = new DotTemplateExp(loc,de->e1,te->td); + } + } +#endif + } + + if (e1->op == TOKcomma) + { + CommaExp *ce = (CommaExp *)e1; + + e1 = ce->e2; + e1->type = ce->type; + ce->e2 = this; + ce->type = NULL; + return ce->semantic(sc); + } + + t1 = NULL; + if (e1->type) + t1 = e1->type->toBasetype(); + + // Check for call operator overload + if (t1) + { AggregateDeclaration *ad; + + if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; + + // First look for constructor + if (ad->ctor && arguments && arguments->dim) + { + // Create variable that will get constructed + Identifier *idtmp = Lexer::uniqueId("__ctmp"); + VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL); + Expression *av = new DeclarationExp(loc, tmp); + av = new CommaExp(loc, av, new VarExp(loc, tmp)); + + Expression *e; + CtorDeclaration *cf = ad->ctor->isCtorDeclaration(); + if (cf) + e = new DotVarExp(loc, av, cf, 1); + else + { TemplateDeclaration *td = ad->ctor->isTemplateDeclaration(); + assert(td); + e = new DotTemplateExp(loc, av, td); + } + e = new CallExp(loc, e, arguments); +#if !STRUCTTHISREF + /* Constructors return a pointer to the instance + */ + e = new PtrExp(loc, e); +#endif + e = e->semantic(sc); + return e; + } + + // No constructor, look for overload of opCall + if (search_function(ad, Id::call)) + goto L1; // overload of opCall, therefore it's a call + + if (e1->op != TOKtype) + error("%s %s does not overload ()", ad->kind(), ad->toChars()); + /* It's a struct literal + */ + Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments); + e = e->semantic(sc); + e->type = e1->type; // in case e1->type was a typedef + return e; + } + else if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + goto L1; + L1: + // Rewrite as e1.call(arguments) + Expression *e = new DotIdExp(loc, e1, Id::call); + e = new CallExp(loc, e, arguments); + e = e->semantic(sc); + return e; + } + } + + arrayExpressionSemantic(arguments, sc); + preFunctionArguments(loc, sc, arguments); + + if (e1->op == TOKdotvar && t1->ty == Tfunction || + e1->op == TOKdottd) + { + DotVarExp *dve; + DotTemplateExp *dte; + AggregateDeclaration *ad; + UnaExp *ue = (UnaExp *)(e1); + + if (e1->op == TOKdotvar) + { // Do overload resolution + dve = (DotVarExp *)(e1); + + f = dve->var->isFuncDeclaration(); + assert(f); + f = f->overloadResolve(loc, ue->e1, arguments); + + ad = f->toParent()->isAggregateDeclaration(); + } + else + { dte = (DotTemplateExp *)(e1); + TemplateDeclaration *td = dte->td; + assert(td); + if (!arguments) + // Should fix deduceFunctionTemplate() so it works on NULL argument + arguments = new Expressions(); + f = td->deduceFunctionTemplate(sc, loc, targsi, ue->e1, arguments); + if (!f) + { type = Type::terror; + return this; + } + ad = td->toParent()->isAggregateDeclaration(); + } + if (f->needThis()) + { + ue->e1 = getRightThis(loc, sc, ad, ue->e1, f); + } + + /* Cannot call public functions from inside invariant + * (because then the invariant would have infinite recursion) + */ + if (sc->func && sc->func->isInvariantDeclaration() && + ue->e1->op == TOKthis && + f->addPostInvariant() + ) + { + error("cannot call public/export function %s from immutable", f->toChars()); + } + + checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif + accessCheck(loc, sc, ue->e1, f); + if (!f->needThis()) + { + VarExp *ve = new VarExp(loc, f); + e1 = new CommaExp(loc, ue->e1, ve); + e1->type = f->type; + } + else + { + if (e1->op == TOKdotvar) + dve->var = f; + else + e1 = new DotVarExp(loc, dte->e1, f); + e1->type = f->type; +#if 0 + printf("ue->e1 = %s\n", ue->e1->toChars()); + printf("f = %s\n", f->toChars()); + printf("t = %s\n", t->toChars()); + printf("e1 = %s\n", e1->toChars()); + printf("e1->type = %s\n", e1->type->toChars()); +#endif + // Const member function can take const/immutable/mutable this + if (!(f->type->isConst())) + { + // Check for const/immutable compatibility + Type *tthis = ue->e1->type->toBasetype(); + if (tthis->ty == Tpointer) + tthis = tthis->nextOf()->toBasetype(); + if (f->type->isInvariant()) + { + if (tthis->mod != MODinvariant) + error("%s can only be called on an invariant object", e1->toChars()); + } + else + { + if (tthis->mod != 0) + { //printf("mod = %x\n", tthis->mod); + error("%s can only be called on a mutable object, not %s", e1->toChars(), tthis->toChars()); + } + } + + /* Cannot call mutable method on a final struct + */ + if (tthis->ty == Tstruct && + ue->e1->op == TOKvar) + { VarExp *v = (VarExp *)ue->e1; + if (v->var->storage_class & STCfinal) + error("cannot call mutable method on final struct"); + } + } + + // See if we need to adjust the 'this' pointer + AggregateDeclaration *ad = f->isThis(); + ClassDeclaration *cd = ue->e1->type->isClassHandle(); + if (ad && cd && ad->isClassDeclaration() && ad != cd && + ue->e1->op != TOKsuper) + { + ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type); + ue->e1 = ue->e1->semantic(sc); + } + } + t1 = e1->type; + } + else if (e1->op == TOKsuper) + { + // Base class constructor call + ClassDeclaration *cd = NULL; + + if (sc->func) + cd = sc->func->toParent()->isClassDeclaration(); + if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) + { + error("super class constructor call must be in a constructor"); + type = Type::terror; + return this; + } + else + { + if (!cd->baseClass->ctor) + { error("no super class constructor for %s", cd->baseClass->toChars()); + type = Type::terror; + return this; + } + else + { + if (!sc->intypeof) + { +#if 0 + if (sc->callSuper & (CSXthis | CSXsuper)) + error("reference to this before super()"); +#endif + if (sc->noctor || sc->callSuper & CSXlabel) + error("constructor calls not allowed in loops or after labels"); + if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) + error("multiple constructor calls"); + sc->callSuper |= CSXany_ctor | CSXsuper_ctor; + } + + f = resolveFuncCall(sc, loc, cd->baseClass->ctor, NULL, NULL, arguments, 0); + checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif + e1 = new DotVarExp(e1->loc, e1, f); + e1 = e1->semantic(sc); + t1 = e1->type; + } + } + } + else if (e1->op == TOKthis) + { + // same class constructor call + AggregateDeclaration *cd = NULL; + + if (sc->func) + cd = sc->func->toParent()->isAggregateDeclaration(); + if (!cd || !sc->func->isCtorDeclaration()) + { + error("constructor call must be in a constructor"); + type = Type::terror; + return this; + } + else + { + if (!sc->intypeof) + { +#if 0 + if (sc->callSuper & (CSXthis | CSXsuper)) + error("reference to this before super()"); +#endif + if (sc->noctor || sc->callSuper & CSXlabel) + error("constructor calls not allowed in loops or after labels"); + if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) + error("multiple constructor calls"); + sc->callSuper |= CSXany_ctor | CSXthis_ctor; + } + + f = resolveFuncCall(sc, loc, cd->ctor, NULL, NULL, arguments, 0); + checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif + e1 = new DotVarExp(e1->loc, e1, f); + e1 = e1->semantic(sc); + t1 = e1->type; + + // BUG: this should really be done by checking the static + // call graph + if (f == sc->func) + error("cyclic constructor call"); + } + } + else if (e1->op == TOKoverloadset) + { + OverExp *eo = (OverExp *)e1; + FuncDeclaration *f = NULL; + for (int i = 0; i < eo->vars->a.dim; i++) + { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; + FuncDeclaration *f2 = s->isFuncDeclaration(); + if (f2) + { + f2 = f2->overloadResolve(loc, NULL, arguments, 1); + } + else + { TemplateDeclaration *td = s->isTemplateDeclaration(); + assert(td); + f2 = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments, 1); + } + if (f2) + { if (f) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol::multiplyDefined(loc, f, f2); + else + f = f2; + } + } + if (!f) + { /* No overload matches, just set f and rely on error + * message being generated later. + */ + f = (FuncDeclaration *)eo->vars->a.data[0]; + } + e1 = new VarExp(loc, f); + goto Lagain; + } + else if (!t1) + { + error("function expected before (), not '%s'", e1->toChars()); + type = Type::terror; + return this; + } + else if (t1->ty != Tfunction) + { + if (t1->ty == Tdelegate) + { TypeDelegate *td = (TypeDelegate *)t1; + assert(td->next->ty == Tfunction); + tf = (TypeFunction *)(td->next); + if (sc->func && sc->func->isPure() && !tf->ispure) + { + error("pure function '%s' cannot call impure delegate '%s'", sc->func->toChars(), e1->toChars()); + } + goto Lcheckargs; + } + else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction) + { Expression *e; + + e = new PtrExp(loc, e1); + t1 = ((TypePointer *)t1)->next; + if (sc->func && sc->func->isPure() && !((TypeFunction *)t1)->ispure) + { + error("pure function '%s' cannot call impure function pointer '%s'", sc->func->toChars(), e1->toChars()); + } + e->type = t1; + e1 = e; + } + else if (e1->op == TOKtemplate) + { + TemplateExp *te = (TemplateExp *)e1; + f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); + if (!f) + { if (tierror) + tierror->error("errors instantiating template"); // give better error message + type = Type::terror; + return this; + } + if (f->needThis() && hasThis(sc)) + { + // Supply an implicit 'this', as in + // this.ident + + e1 = new DotTemplateExp(loc, (new ThisExp(loc))->semantic(sc), te->td); + goto Lagain; + } + + e1 = new VarExp(loc, f); + goto Lagain; + } + else + { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); + type = Type::terror; + return this; + } + } + else if (e1->op == TOKvar) + { + // Do overload resolution + VarExp *ve = (VarExp *)e1; + + f = ve->var->isFuncDeclaration(); + assert(f); + + if (ve->hasOverloads) + f = f->overloadResolve(loc, NULL, arguments); + checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif + + if (f->needThis() && hasThis(sc)) + { + // Supply an implicit 'this', as in + // this.ident + + e1 = new DotVarExp(loc, new ThisExp(loc), f); + goto Lagain; + } + + accessCheck(loc, sc, NULL, f); + + ve->var = f; +// ve->hasOverloads = 0; + ve->type = f->type; + t1 = f->type; + } + assert(t1->ty == Tfunction); + tf = (TypeFunction *)(t1); + +Lcheckargs: + assert(tf->ty == Tfunction); + type = tf->next; + + if (!arguments) + arguments = new Expressions(); + functionArguments(loc, sc, tf, arguments); + + if (!type) + { + error("forward reference to inferred return type of function call %s", toChars()); + type = Type::terror; + } + + if (f && f->tintro) + { + Type *t = type; + int offset = 0; + TypeFunction *tf = (TypeFunction *)f->tintro; + + if (tf->next->isBaseOf(t, &offset) && offset) + { + type = tf->next; + return castTo(sc, t); + } + } + + return this; +} + +int CallExp::checkSideEffect(int flag) +{ +#if DMDV2 + if (flag != 2) + return 1; + + if (e1->checkSideEffect(2)) + return 1; + + /* If any of the arguments have side effects, this expression does + */ + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e->checkSideEffect(2)) + return 1; + } + + /* If calling a function or delegate that is typed as pure, + * then this expression has no side effects. + */ + Type *t = e1->type->toBasetype(); + if (t->ty == Tfunction && ((TypeFunction *)t)->ispure) + return 0; + if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->ispure) + return 0; +#endif + return 1; +} + +#if DMDV2 +int CallExp::canThrow() +{ + //printf("CallExp::canThrow() %s\n", toChars()); + if (e1->canThrow()) + return 1; + + /* If any of the arguments can throw, then this expression can throw + */ + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e && e->canThrow()) + return 1; + } + + if (global.errors && !e1->type) + return 0; // error recovery + + /* If calling a function or delegate that is typed as nothrow, + * then this expression cannot throw. + * Note that pure functions can throw. + */ + Type *t = e1->type->toBasetype(); + if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) + return 0; + if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) + return 0; + + return 1; +} +#endif + +#if DMDV2 +int CallExp::isLvalue() +{ +// if (type->toBasetype()->ty == Tstruct) +// return 1; + Type *tb = e1->type->toBasetype(); + if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) + return 1; // function returns a reference + return 0; +} +#endif + +Expression *CallExp::toLvalue(Scope *sc, Expression *e) +{ + if (isLvalue()) + return this; + return Expression::toLvalue(sc, e); +} + +void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writeByte('('); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(')'); +} + + +/************************************************************/ + +AddrExp::AddrExp(Loc loc, Expression *e) + : UnaExp(loc, TOKaddress, sizeof(AddrExp), e) +{ + m = NULL; +} + +Expression *AddrExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("AddrExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + m = sc->module; + UnaExp::semantic(sc); + e1 = e1->toLvalue(sc, NULL); + if (!e1->type) + { + error("cannot take address of %s", e1->toChars()); + type = Type::tint32; + return this; + } + type = e1->type->pointerTo(); + + // See if this should really be a delegate + if (e1->op == TOKdotvar) + { + DotVarExp *dve = (DotVarExp *)e1; + FuncDeclaration *f = dve->var->isFuncDeclaration(); + + if (f) + { + if (!dve->hasOverloads) + f->tookAddressOf++; + Expression *e = new DelegateExp(loc, dve->e1, f, dve->hasOverloads); + e = e->semantic(sc); + return e; + } + } + else if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && !v->canTakeAddressOf()) + error("cannot take address of %s", e1->toChars()); + + FuncDeclaration *f = ve->var->isFuncDeclaration(); + + if (f) + { + if (!ve->hasOverloads || + /* Because nested functions cannot be overloaded, + * mark here that we took its address because castTo() + * may not be called with an exact match. + */ + f->toParent2()->isFuncDeclaration()) + f->tookAddressOf++; + if (f->isNested()) + { + Expression *e = new DelegateExp(loc, e1, f, ve->hasOverloads); + e = e->semantic(sc); + return e; + } + if (f->needThis() && hasThis(sc)) + { + /* Should probably supply 'this' after overload resolution, + * not before. + */ + Expression *ethis = new ThisExp(loc); + Expression *e = new DelegateExp(loc, ethis, f, ve->hasOverloads); + e = e->semantic(sc); + return e; + } + } + } + return optimize(WANTvalue); + } + return this; +} + +/************************************************************/ + +PtrExp::PtrExp(Loc loc, Expression *e) + : UnaExp(loc, TOKstar, sizeof(PtrExp), e) +{ + if (e->type) + type = ((TypePointer *)e->type)->next; +} + +PtrExp::PtrExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKstar, sizeof(PtrExp), e) +{ + type = t; +} + +Expression *PtrExp::semantic(Scope *sc) +{ Type *tb; + +#if LOGSEMANTIC + printf("PtrExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + if (!e1->type) + printf("PtrExp::semantic('%s')\n", toChars()); + Expression *e = op_overload(sc); + if (e) + return e; + tb = e1->type->toBasetype(); + switch (tb->ty) + { + case Tpointer: + type = ((TypePointer *)tb)->next; + break; + + case Tsarray: + case Tarray: + type = ((TypeArray *)tb)->next; + e1 = e1->castTo(sc, type->pointerTo()); + break; + + default: + error("can only * a pointer, not a '%s'", e1->type->toChars()); + type = Type::tint32; + break; + } + rvalue(); + } + return this; +} + +#if DMDV2 +int PtrExp::isLvalue() +{ + return 1; +} +#endif + +Expression *PtrExp::toLvalue(Scope *sc, Expression *e) +{ +#if 0 + tym = tybasic(e1->ET->Tty); + if (!(tyscalar(tym) || + tym == TYstruct || + tym == TYarray && e->Eoper == TOKaddr)) + synerr(EM_lvalue); // lvalue expected +#endif + return this; +} + +#if DMDV2 +Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); + + if (e1->op == TOKsymoff) + { SymOffExp *se = (SymOffExp *)e1; + se->var->checkModify(loc, sc, type); + //return toLvalue(sc, e); + } + + return Expression::modifiableLvalue(sc, e); +} +#endif + +void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('*'); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + +/************************************************************/ + +NegExp::NegExp(Loc loc, Expression *e) + : UnaExp(loc, TOKneg, sizeof(NegExp), e) +{ +} + +Expression *NegExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("NegExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e = op_overload(sc); + if (e) + return e; + + e1->checkNoBool(); + if (e1->op != TOKslice) + e1->checkArithmetic(); + type = e1->type; + } + return this; +} + +/************************************************************/ + +UAddExp::UAddExp(Loc loc, Expression *e) + : UnaExp(loc, TOKuadd, sizeof(UAddExp), e) +{ +} + +Expression *UAddExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("UAddExp::semantic('%s')\n", toChars()); +#endif + assert(!type); + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e = op_overload(sc); + if (e) + return e; + e1->checkNoBool(); + e1->checkArithmetic(); + return e1; +} + +/************************************************************/ + +ComExp::ComExp(Loc loc, Expression *e) + : UnaExp(loc, TOKtilde, sizeof(ComExp), e) +{ +} + +Expression *ComExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e = op_overload(sc); + if (e) + return e; + + e1->checkNoBool(); + if (e1->op != TOKslice) + e1 = e1->checkIntegral(); + type = e1->type; + } + return this; +} + +/************************************************************/ + +NotExp::NotExp(Loc loc, Expression *e) + : UnaExp(loc, TOKnot, sizeof(NotExp), e) +{ +} + +Expression *NotExp::semantic(Scope *sc) +{ + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToBoolean(); + type = Type::tboolean; + return this; +} + +int NotExp::isBit() +{ + return TRUE; +} + + + +/************************************************************/ + +BoolExp::BoolExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKtobool, sizeof(BoolExp), e) +{ + type = t; +} + +Expression *BoolExp::semantic(Scope *sc) +{ + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToBoolean(); + type = Type::tboolean; + return this; +} + +int BoolExp::isBit() +{ + return TRUE; +} + +/************************************************************/ + +DeleteExp::DeleteExp(Loc loc, Expression *e) + : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e) +{ +} + +Expression *DeleteExp::semantic(Scope *sc) +{ + Type *tb; + + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->toLvalue(sc, NULL); + type = Type::tvoid; + + tb = e1->type->toBasetype(); + switch (tb->ty) + { case Tclass: + { TypeClass *tc = (TypeClass *)tb; + ClassDeclaration *cd = tc->sym; + + if (cd->isCOMinterface()) + { /* Because COM classes are deleted by IUnknown.Release() + */ + error("cannot delete instance of COM interface %s", cd->toChars()); + } + break; + } + case Tpointer: + tb = ((TypePointer *)tb)->next->toBasetype(); + if (tb->ty == Tstruct) + { + TypeStruct *ts = (TypeStruct *)tb; + StructDeclaration *sd = ts->sym; + FuncDeclaration *f = sd->aggDelete; + FuncDeclaration *fd = sd->dtor; + + if (!f && !fd) + break; + + /* Construct: + * ea = copy e1 to a tmp to do side effects only once + * eb = call destructor + * ec = call deallocator + */ + Expression *ea = NULL; + Expression *eb = NULL; + Expression *ec = NULL; + VarDeclaration *v; + + if (fd && f) + { Identifier *id = Lexer::idPool("__tmp"); + v = new VarDeclaration(loc, e1->type, id, new ExpInitializer(loc, e1)); + v->semantic(sc); + v->parent = sc->parent; + ea = new DeclarationExp(loc, v); + ea->type = v->type; + } + + if (fd) + { Expression *e = ea ? new VarExp(loc, v) : e1; + e = new DotVarExp(0, e, fd, 0); + eb = new CallExp(loc, e); + eb = eb->semantic(sc); + } + + if (f) + { + Type *tpv = Type::tvoid->pointerTo(); + Expression *e = ea ? new VarExp(loc, v) : e1->castTo(sc, tpv); + e = new CallExp(loc, new VarExp(loc, f), e); + ec = e->semantic(sc); + } + ea = combine(ea, eb); + ea = combine(ea, ec); + assert(ea); + return ea; + } + break; + + case Tarray: + /* BUG: look for deleting arrays of structs with dtors. + */ + break; + + default: + if (e1->op == TOKindex) + { + IndexExp *ae = (IndexExp *)(e1); + Type *tb1 = ae->e1->type->toBasetype(); + if (tb1->ty == Taarray) + break; + } + error("cannot delete type %s", e1->type->toChars()); + break; + } + + if (e1->op == TOKindex) + { + IndexExp *ae = (IndexExp *)(e1); + Type *tb1 = ae->e1->type->toBasetype(); + if (tb1->ty == Taarray) + { if (!global.params.useDeprecated) + error("delete aa[key] deprecated, use aa.remove(key)"); + } + } + + return this; +} + +int DeleteExp::checkSideEffect(int flag) +{ + return 1; +} + +Expression *DeleteExp::checkToBoolean() +{ + error("delete does not give a boolean result"); + return this; +} + +void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("delete "); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + +/************************************************************/ + +CastExp::CastExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKcast, sizeof(CastExp), e) +{ + to = t; + this->mod = ~0; +} + +#if DMDV2 +/* For cast(const) and cast(immutable) + */ +CastExp::CastExp(Loc loc, Expression *e, unsigned mod) + : UnaExp(loc, TOKcast, sizeof(CastExp), e) +{ + to = NULL; + this->mod = mod; +} +#endif + +Expression *CastExp::syntaxCopy() +{ + return to ? new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()) + : new CastExp(loc, e1->syntaxCopy(), mod); +} + + +Expression *CastExp::semantic(Scope *sc) +{ Expression *e; + BinExp *b; + UnaExp *u; + +#if LOGSEMANTIC + printf("CastExp::semantic('%s')\n", toChars()); +#endif + +//static int x; assert(++x < 10); + + if (type) + return this; + UnaExp::semantic(sc); + if (e1->type) // if not a tuple + { + e1 = resolveProperties(sc, e1); + + if (!to) + { + /* Handle cast(const) and cast(immutable), etc. + */ + to = e1->type->castMod(mod); + } + else + to = to->semantic(loc, sc); + + if (!to->equals(e1->type)) + { + e = op_overload(sc); + if (e) + { + return e->implicitCastTo(sc, to); + } + } + + Type *t1b = e1->type->toBasetype(); + Type *tob = to->toBasetype(); + if (tob->ty == Tstruct && + !tob->equals(t1b) && + ((TypeStruct *)tob)->sym->search(0, Id::call, 0) + ) + { + /* Look to replace: + * cast(S)t + * with: + * S(t) + */ + + // Rewrite as to.call(e1) + e = new TypeExp(loc, to); + e = new DotIdExp(loc, e, Id::call); + e = new CallExp(loc, e, e1); + e = e->semantic(sc); + return e; + } + } + else if (!to) + { error("cannot cast tuple"); + to = Type::terror; + } + + if (global.params.safe && !sc->module->safe && !sc->intypeof) + { // Disallow unsafe casts + Type *tob = to->toBasetype(); + Type *t1b = e1->type->toBasetype(); + if (!t1b->isMutable() && tob->isMutable()) + { // Cast not mutable to mutable + Lunsafe: + error("cast from %s to %s not allowed in safe mode", e1->type->toChars(), to->toChars()); + } + else if (t1b->isShared() && !tob->isShared()) + // Cast away shared + goto Lunsafe; + else if (tob->ty == Tpointer) + { if (t1b->ty != Tpointer) + goto Lunsafe; + Type *tobn = tob->nextOf()->toBasetype(); + Type *t1bn = t1b->nextOf()->toBasetype(); + + if (!t1bn->isMutable() && tobn->isMutable()) + // Cast away pointer to not mutable + goto Lunsafe; + + if (t1bn->isShared() && !tobn->isShared()) + // Cast away pointer to shared + goto Lunsafe; + + if (tobn->isTypeBasic() && tobn->size() < t1bn->size()) + // Allow things like casting a long* to an int* + ; + else if (tobn->ty != Tvoid) + // Cast to a pointer other than void* + goto Lunsafe; + } + + // BUG: Check for casting array types, such as void[] to int*[] + } + + e = e1->castTo(sc, to); + return e; +} + +int CastExp::checkSideEffect(int flag) +{ + /* if not: + * cast(void) + * cast(classtype)func() + */ + if (!to->equals(Type::tvoid) && + !(to->ty == Tclass && e1->op == TOKcall && e1->type->ty == Tclass)) + return Expression::checkSideEffect(flag); + return 1; +} + +void CastExp::checkEscape() +{ Type *tb = type->toBasetype(); + if (tb->ty == Tarray && e1->op == TOKvar && + e1->type->toBasetype()->ty == Tsarray) + { VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v) + { + if (!v->isDataseg() && !v->isParameter()) + error("escaping reference to local %s", v->toChars()); + } + } +} + +void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("cast("); +#if DMDV1 + to->toCBuffer(buf, NULL, hgs); +#else + if (to) + to->toCBuffer(buf, NULL, hgs); + else + { + switch (mod) + { case 0: + break; + case MODconst: + buf->writestring(Token::tochars[TOKconst]); + break; + case MODinvariant: + buf->writestring(Token::tochars[TOKimmutable]); + break; + case MODshared: + buf->writestring(Token::tochars[TOKshared]); + break; + case MODshared | MODconst: + buf->writestring(Token::tochars[TOKshared]); + buf->writeByte(' '); + buf->writestring(Token::tochars[TOKconst]); + break; + default: + assert(0); + } + } +#endif + buf->writeByte(')'); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + + +/************************************************************/ + +SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) + : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) +{ + this->upr = upr; + this->lwr = lwr; + lengthVar = NULL; +} + +Expression *SliceExp::syntaxCopy() +{ + Expression *lwr = NULL; + if (this->lwr) + lwr = this->lwr->syntaxCopy(); + + Expression *upr = NULL; + if (this->upr) + upr = this->upr->syntaxCopy(); + + return new SliceExp(loc, e1->syntaxCopy(), lwr, upr); +} + +Expression *SliceExp::semantic(Scope *sc) +{ Expression *e; + AggregateDeclaration *ad; + //FuncDeclaration *fd; + ScopeDsymbol *sym; + +#if LOGSEMANTIC + printf("SliceExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + e = this; + + Type *t = e1->type->toBasetype(); + if (t->ty == Tpointer) + { + if (!lwr || !upr) + error("need upper and lower bound to slice pointer"); + } + else if (t->ty == Tarray) + { + } + else if (t->ty == Tsarray) + { + } + else if (t->ty == Tclass) + { + ad = ((TypeClass *)t)->sym; + goto L1; + } + else if (t->ty == Tstruct) + { + ad = ((TypeStruct *)t)->sym; + + L1: + if (search_function(ad, Id::slice)) + { + // Rewrite as e1.slice(lwr, upr) + e = new DotIdExp(loc, e1, Id::slice); + + if (lwr) + { + assert(upr); + e = new CallExp(loc, e, lwr, upr); + } + else + { assert(!upr); + e = new CallExp(loc, e); + } + e = e->semantic(sc); + return e; + } + goto Lerror; + } + else if (t->ty == Ttuple) + { + if (!lwr && !upr) + return e1; + if (!lwr || !upr) + { error("need upper and lower bound to slice tuple"); + goto Lerror; + } + } + else + goto Lerror; + + if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) + { + sym = new ArrayScopeSymbol(sc, this); + sym->loc = loc; + sym->parent = sc->scopesym; + sc = sc->push(sym); + } + + if (lwr) + { lwr = lwr->semantic(sc); + lwr = resolveProperties(sc, lwr); + lwr = lwr->implicitCastTo(sc, Type::tsize_t); + } + if (upr) + { upr = upr->semantic(sc); + upr = resolveProperties(sc, upr); + upr = upr->implicitCastTo(sc, Type::tsize_t); + } + + if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) + sc->pop(); + + if (t->ty == Ttuple) + { + lwr = lwr->optimize(WANTvalue); + upr = upr->optimize(WANTvalue); + uinteger_t i1 = lwr->toUInteger(); + uinteger_t i2 = upr->toUInteger(); + + size_t length; + TupleExp *te; + TypeTuple *tup; + + if (e1->op == TOKtuple) // slicing an expression tuple + { te = (TupleExp *)e1; + length = te->exps->dim; + } + else if (e1->op == TOKtype) // slicing a type tuple + { tup = (TypeTuple *)t; + length = Argument::dim(tup->arguments); + } + else + assert(0); + + if (i1 <= i2 && i2 <= length) + { size_t j1 = (size_t) i1; + size_t j2 = (size_t) i2; + + if (e1->op == TOKtuple) + { Expressions *exps = new Expressions; + exps->setDim(j2 - j1); + for (size_t i = 0; i < j2 - j1; i++) + { Expression *e = (Expression *)te->exps->data[j1 + i]; + exps->data[i] = (void *)e; + } + e = new TupleExp(loc, exps); + } + else + { Arguments *args = new Arguments; + args->reserve(j2 - j1); + for (size_t i = j1; i < j2; i++) + { Argument *arg = Argument::getNth(tup->arguments, i); + args->push(arg); + } + e = new TypeExp(e1->loc, new TypeTuple(args)); + } + e = e->semantic(sc); + } + else + { + error("string slice [%ju .. %ju] is out of bounds", i1, i2); + e = new ErrorExp(); + } + return e; + } + + if (t->ty == Tarray) + { + type = e1->type; + } + else + type = t->nextOf()->arrayOf(); + return e; + +Lerror: + char *s; + if (t->ty == Tvoid) + s = e1->toChars(); + else + s = t->toChars(); + error("%s cannot be sliced with []", s); + e = new ErrorExp(); + return e; +} + +void SliceExp::checkEscape() +{ + e1->checkEscape(); +} + +#if DMDV2 +int SliceExp::isLvalue() +{ + return 1; +} +#endif + +Expression *SliceExp::toLvalue(Scope *sc, Expression *e) +{ + return this; +} + +Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) +{ + error("slice expression %s is not a modifiable lvalue", toChars()); + return this; +} + +void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writeByte('['); + if (upr || lwr) + { + if (lwr) + expToCBuffer(buf, hgs, lwr, PREC_assign); + else + buf->writeByte('0'); + buf->writestring(".."); + if (upr) + expToCBuffer(buf, hgs, upr, PREC_assign); + else + buf->writestring("length"); // BUG: should be array.length + } + buf->writeByte(']'); +} + +/********************** ArrayLength **************************************/ + +ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) + : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1) +{ +} + +Expression *ArrayLengthExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("ArrayLengthExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + type = Type::tsize_t; + } + return this; +} + +void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writestring(".length"); +} + +/*********************** ArrayExp *************************************/ + +// e1 [ i1, i2, i3, ... ] + +ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args) + : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1) +{ + arguments = args; +} + +Expression *ArrayExp::syntaxCopy() +{ + return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); +} + +Expression *ArrayExp::semantic(Scope *sc) +{ Expression *e; + Type *t1; + +#if LOGSEMANTIC + printf("ArrayExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + t1 = e1->type->toBasetype(); + if (t1->ty != Tclass && t1->ty != Tstruct) + { // Convert to IndexExp + if (arguments->dim != 1) + error("only one index allowed to index %s", t1->toChars()); + e = new IndexExp(loc, e1, (Expression *)arguments->data[0]); + return e->semantic(sc); + } + + // Run semantic() on each argument + for (size_t i = 0; i < arguments->dim; i++) + { e = (Expression *)arguments->data[i]; + + e = e->semantic(sc); + if (!e->type) + error("%s has no value", e->toChars()); + arguments->data[i] = (void *)e; + } + + expandTuples(arguments); + assert(arguments && arguments->dim); + + e = op_overload(sc); + if (!e) + { error("no [] operator overload for type %s", e1->type->toChars()); + e = e1; + } + return e; +} + +#if DMDV2 +int ArrayExp::isLvalue() +{ + if (type && type->toBasetype()->ty == Tvoid) + return 0; + return 1; +} +#endif + +Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) +{ + if (type && type->toBasetype()->ty == Tvoid) + error("voids have no value"); + return this; +} + + +void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('['); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(']'); +} + +/************************* DotExp ***********************************/ + +DotExp::DotExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2) +{ +} + +Expression *DotExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotExp::semantic('%s')\n", toChars()); + if (type) printf("\ttype = %s\n", type->toChars()); +#endif + e1 = e1->semantic(sc); + e2 = e2->semantic(sc); + if (e2->op == TOKimport) + { + ScopeExp *se = (ScopeExp *)e2; + TemplateDeclaration *td = se->sds->isTemplateDeclaration(); + if (td) + { Expression *e = new DotTemplateExp(loc, e1, td); + e = e->semantic(sc); + return e; + } + } + if (!type) + type = e2->type; + return this; +} + + +/************************* CommaExp ***********************************/ + +CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2) +{ +} + +Expression *CommaExp::semantic(Scope *sc) +{ + if (!type) + { BinExp::semanticp(sc); + type = e2->type; + } + return this; +} + +void CommaExp::checkEscape() +{ + e2->checkEscape(); +} + +#if DMDV2 +int CommaExp::isLvalue() +{ + return e2->isLvalue(); +} +#endif + +Expression *CommaExp::toLvalue(Scope *sc, Expression *e) +{ + e2 = e2->toLvalue(sc, NULL); + return this; +} + +Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) +{ + e2 = e2->modifiableLvalue(sc, e); + return this; +} + +int CommaExp::isBool(int result) +{ + return e2->isBool(result); +} + +int CommaExp::checkSideEffect(int flag) +{ + if (flag == 2) + return e1->checkSideEffect(2) || e2->checkSideEffect(2); + else + { + // Don't check e1 until we cast(void) the a,b code generation + return e2->checkSideEffect(flag); + } +} + +/************************** IndexExp **********************************/ + +// e1 [ e2 ] + +IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2) +{ + //printf("IndexExp::IndexExp('%s')\n", toChars()); + lengthVar = NULL; + modifiable = 0; // assume it is an rvalue +} + +Expression *IndexExp::semantic(Scope *sc) +{ Expression *e; + BinExp *b; + UnaExp *u; + Type *t1; + ScopeDsymbol *sym; + +#if LOGSEMANTIC + printf("IndexExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + if (!e1->type) + e1 = e1->semantic(sc); + assert(e1->type); // semantic() should already be run on it + e = this; + + // Note that unlike C we do not implement the int[ptr] + + t1 = e1->type->toBasetype(); + + if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) + { // Create scope for 'length' variable + sym = new ArrayScopeSymbol(sc, this); + sym->loc = loc; + sym->parent = sc->scopesym; + sc = sc->push(sym); + } + + e2 = e2->semantic(sc); + if (!e2->type) + { + error("%s has no value", e2->toChars()); + e2->type = Type::terror; + } + e2 = resolveProperties(sc, e2); + + if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) + sc = sc->pop(); + + switch (t1->ty) + { + case Tpointer: + case Tarray: + e2 = e2->implicitCastTo(sc, Type::tsize_t); + e->type = ((TypeNext *)t1)->next; + break; + + case Tsarray: + { + e2 = e2->implicitCastTo(sc, Type::tsize_t); + + TypeSArray *tsa = (TypeSArray *)t1; + +#if 0 // Don't do now, because it might be short-circuit evaluated + // Do compile time array bounds checking if possible + e2 = e2->optimize(WANTvalue); + if (e2->op == TOKint64) + { + dinteger_t index = e2->toInteger(); + dinteger_t length = tsa->dim->toInteger(); + if (index < 0 || index >= length) + error("array index [%lld] is outside array bounds [0 .. %lld]", + index, length); + } +#endif + e->type = t1->nextOf(); + break; + } + + case Taarray: + { TypeAArray *taa = (TypeAArray *)t1; + if (!arrayTypeCompatible(e2->loc, e2->type, taa->index)) + { + e2 = e2->implicitCastTo(sc, taa->index); // type checking + } + type = taa->next; + break; + } + + case Ttuple: + { + e2 = e2->implicitCastTo(sc, Type::tsize_t); + e2 = e2->optimize(WANTvalue | WANTinterpret); + uinteger_t index = e2->toUInteger(); + size_t length; + TupleExp *te; + TypeTuple *tup; + + if (e1->op == TOKtuple) + { te = (TupleExp *)e1; + length = te->exps->dim; + } + else if (e1->op == TOKtype) + { + tup = (TypeTuple *)t1; + length = Argument::dim(tup->arguments); + } + else + assert(0); + + if (index < length) + { + + if (e1->op == TOKtuple) + e = (Expression *)te->exps->data[(size_t)index]; + else + e = new TypeExp(e1->loc, Argument::getNth(tup->arguments, (size_t)index)->type); + } + else + { + error("array index [%ju] is outside array bounds [0 .. %zu]", + index, length); + e = e1; + } + break; + } + + default: + error("%s must be an array or pointer type, not %s", + e1->toChars(), e1->type->toChars()); + type = Type::tint32; + break; + } + return e; +} + +#if DMDV2 +int IndexExp::isLvalue() +{ + return 1; +} +#endif + +Expression *IndexExp::toLvalue(Scope *sc, Expression *e) +{ +// if (type && type->toBasetype()->ty == Tvoid) +// error("voids have no value"); + return this; +} + +Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); + modifiable = 1; + if (e1->op == TOKstring) + error("string literals are immutable"); + if (type && !type->isMutable()) + error("%s isn't mutable", e->toChars()); + if (e1->type->toBasetype()->ty == Taarray) + e1 = e1->modifiableLvalue(sc, e1); + return toLvalue(sc, e); +} + +void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('['); + expToCBuffer(buf, hgs, e2, PREC_assign); + buf->writeByte(']'); +} + + +/************************* PostExp ***********************************/ + +PostExp::PostExp(enum TOK op, Loc loc, Expression *e) + : BinExp(loc, op, sizeof(PostExp), e, + new IntegerExp(loc, 1, Type::tint32)) +{ +} + +Expression *PostExp::semantic(Scope *sc) +{ Expression *e = this; + + if (!type) + { + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e = this; + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + if (e1->type->ty == Tpointer) + e = scaleFactor(sc); + else + e2 = e2->castTo(sc, e1->type); + e->type = e1->type; + } + return e; +} + +void PostExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writestring((op == TOKplusplus) ? (char *)"++" : (char *)"--"); +} + +/************************************************************/ + +/* op can be TOKassign, TOKconstruct, or TOKblit */ + +AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) +{ + ismemset = 0; +} + +Expression *AssignExp::semantic(Scope *sc) +{ + Expression *e1old = e1; + +#if LOGSEMANTIC + printf("AssignExp::semantic('%s')\n", toChars()); +#endif + //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); + //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op)); + + if (type) + return this; + + if (e2->op == TOKcomma) + { /* Rewrite to get rid of the comma from rvalue + */ + AssignExp *ea = new AssignExp(loc, e1, ((CommaExp *)e2)->e2); + ea->op = op; + Expression *e = new CommaExp(loc, ((CommaExp *)e2)->e1, ea); + return e->semantic(sc); + } + + /* Look for operator overloading of a[i]=value. + * Do it before semantic() otherwise the a[i] will have been + * converted to a.opIndex() already. + */ + if (e1->op == TOKarray) + { + ArrayExp *ae = (ArrayExp *)e1; + AggregateDeclaration *ad; + Identifier *id = Id::index; + + ae->e1 = ae->e1->semantic(sc); + Type *t1 = ae->e1->type->toBasetype(); + if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; + goto L1; + } + else if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + L1: + // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) + if (search_function(ad, Id::indexass)) + { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); + Expressions *a = (Expressions *)ae->arguments->copy(); + + a->insert(0, e2); + e = new CallExp(loc, e, a); + e = e->semantic(sc); + return e; + } + else + { + // Rewrite (a[i] = value) to (a.opIndex(i, value)) + if (search_function(ad, id)) + { Expression *e = new DotIdExp(loc, ae->e1, id); + + if (1 || !global.params.useDeprecated) + error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); + + e = new CallExp(loc, e, (Expression *)ae->arguments->data[0], e2); + e = e->semantic(sc); + return e; + } + } + } + } + /* Look for operator overloading of a[i..j]=value. + * Do it before semantic() otherwise the a[i..j] will have been + * converted to a.opSlice() already. + */ + if (e1->op == TOKslice) + { Type *t1; + SliceExp *ae = (SliceExp *)e1; + AggregateDeclaration *ad; + Identifier *id = Id::index; + + ae->e1 = ae->e1->semantic(sc); + ae->e1 = resolveProperties(sc, ae->e1); + t1 = ae->e1->type->toBasetype(); + if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; + goto L2; + } + else if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + L2: + // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j)) + if (search_function(ad, Id::sliceass)) + { Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); + Expressions *a = new Expressions(); + + a->push(e2); + if (ae->lwr) + { a->push(ae->lwr); + assert(ae->upr); + a->push(ae->upr); + } + else + assert(!ae->upr); + e = new CallExp(loc, e, a); + e = e->semantic(sc); + return e; + } + } + } + + BinExp::semantic(sc); + + if (e1->op == TOKdottd) + { // Rewrite a.b=e2, when b is a template, as a.b(e2) + Expression *e = new CallExp(loc, e1, e2); + e = e->semantic(sc); + return e; + } + + e2 = resolveProperties(sc, e2); + assert(e1->type); + + /* Rewrite tuple assignment as a tuple of assignments. + */ + if (e1->op == TOKtuple && e2->op == TOKtuple) + { TupleExp *tup1 = (TupleExp *)e1; + TupleExp *tup2 = (TupleExp *)e2; + size_t dim = tup1->exps->dim; + if (dim != tup2->exps->dim) + { + error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); + } + else + { Expressions *exps = new Expressions; + exps->setDim(dim); + + for (int i = 0; i < dim; i++) + { Expression *ex1 = (Expression *)tup1->exps->data[i]; + Expression *ex2 = (Expression *)tup2->exps->data[i]; + exps->data[i] = (void *) new AssignExp(loc, ex1, ex2); + } + Expression *e = new TupleExp(loc, exps); + e = e->semantic(sc); + return e; + } + } + + Type *t1 = e1->type->toBasetype(); + + if (t1->ty == Tfunction) + { // Rewrite f=value to f(value) + Expression *e = new CallExp(loc, e1, e2); + e = e->semantic(sc); + return e; + } + + /* If it is an assignment from a 'foreign' type, + * check for operator overloading. + */ + if (t1->ty == Tstruct) + { + StructDeclaration *sd = ((TypeStruct *)t1)->sym; + if (op == TOKassign) + { + Expression *e = op_overload(sc); + if (e) + return e; + } + else if (op == TOKconstruct) + { Type *t2 = e2->type->toBasetype(); + if (t2->ty == Tstruct && + sd == ((TypeStruct *)t2)->sym && + sd->cpctor) + { /* We have a copy constructor for this + */ + if (e2->op == TOKvar || e2->op == TOKstar) + { /* Write as: + * e1.cpctor(e2); + */ + Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); + e = new CallExp(loc, e, e2); + return e->semantic(sc); + } + else if (e2->op == TOKquestion) + { /* Write as: + * a ? e1 = b : e1 = c; + */ + CondExp *ec = (CondExp *)e2; + AssignExp *ea1 = new AssignExp(ec->e1->loc, e1, ec->e1); + ea1->op = op; + AssignExp *ea2 = new AssignExp(ec->e1->loc, e1, ec->e2); + ea2->op = op; + Expression *e = new CondExp(loc, ec->econd, ea1, ea2); + return e->semantic(sc); + } + } + } + } + else if (t1->ty == Tclass) + { // Disallow assignment operator overloads for same type + if (!e2->type->implicitConvTo(e1->type)) + { + Expression *e = op_overload(sc); + if (e) + return e; + } + } + + if (t1->ty == Tsarray) + { // Convert e1 to e1[] + Expression *e = new SliceExp(e1->loc, e1, NULL, NULL); + e1 = e->semantic(sc); + t1 = e1->type->toBasetype(); + } + + e2->rvalue(); + + if (e1->op == TOKarraylength) + { + // e1 is not an lvalue, but we let code generator handle it + ArrayLengthExp *ale = (ArrayLengthExp *)e1; + + ale->e1 = ale->e1->modifiableLvalue(sc, e1); + } + else if (e1->op == TOKslice) + { + Type *tn = e1->type->nextOf(); + if (tn && !tn->isMutable() && op != TOKconstruct) + error("slice %s is not mutable", e1->toChars()); + } + else + { // Try to do a decent error message with the expression + // before it got constant folded + if (e1->op != TOKvar) + e1 = e1->optimize(WANTvalue); + + if (op != TOKconstruct) + e1 = e1->modifiableLvalue(sc, e1old); + } + + Type *t2 = e2->type; + if (e1->op == TOKslice && + t1->nextOf() && + e2->implicitConvTo(t1->nextOf()) + ) + { // memset + ismemset = 1; // make it easy for back end to tell what this is + e2 = e2->implicitCastTo(sc, t1->nextOf()); + } + else if (t1->ty == Tsarray) + { + /* Should have already converted e1 => e1[] + */ + assert(0); + //error("cannot assign to static array %s", e1->toChars()); + } + else if (e1->op == TOKslice) + { + e2 = e2->implicitCastTo(sc, e1->type->constOf()); + } + else + { + e2 = e2->implicitCastTo(sc, e1->type); + } + + /* Look for array operations + */ + if (e1->op == TOKslice && !ismemset && + (e2->op == TOKadd || e2->op == TOKmin || + e2->op == TOKmul || e2->op == TOKdiv || + e2->op == TOKmod || e2->op == TOKxor || + e2->op == TOKand || e2->op == TOKor || + e2->op == TOKtilde || e2->op == TOKneg)) + { + type = e1->type; + return arrayOp(sc); + } + + type = e1->type; + assert(type); + return this; +} + +Expression *AssignExp::checkToBoolean() +{ + // Things like: + // if (a = b) ... + // are usually mistakes. + + error("'=' does not give a boolean result"); + return this; +} + +/************************************************************/ + +AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2) +{ +} + +Expression *AddAssignExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + if (e1->op == TOKslice) + { + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + else + { + e1 = e1->modifiableLvalue(sc, e1); + } + + if ((tb1->ty == Tarray || tb1->ty == Tsarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) && + tb1->nextOf()->equals(tb2->nextOf()) + ) + { + type = e1->type; + typeCombine(sc); + e = this; + } + else + { + e1->checkScalar(); + e1->checkNoBool(); + if (tb1->ty == Tpointer && tb2->isintegral()) + e = scaleFactor(sc); + else if (tb1->ty == Tbit || tb1->ty == Tbool) + { +#if 0 + // Need to rethink this + if (e1->op != TOKvar) + { // Rewrite e1+=e2 to (v=&e1),*v=*v+e2 + VarDeclaration *v; + Expression *ea; + Expression *ex; + + Identifier *id = Lexer::uniqueId("__name"); + + v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); + v->semantic(sc); + if (!sc->insert(v)) + assert(0); + v->parent = sc->func; + + ea = new AddrExp(loc, e1); + ea = new AssignExp(loc, new VarExp(loc, v), ea); + + ex = new VarExp(loc, v); + ex = new PtrExp(loc, ex); + e = new AddExp(loc, ex, e2); + e = new CastExp(loc, e, e1->type); + e = new AssignExp(loc, ex->syntaxCopy(), e); + + e = new CommaExp(loc, ea, e); + } + else +#endif + { // Rewrite e1+=e2 to e1=e1+e2 + // BUG: doesn't account for side effects in e1 + // BUG: other assignment operators for bits aren't handled at all + e = new AddExp(loc, e1, e2); + e = new CastExp(loc, e, e1->type); + e = new AssignExp(loc, e1->syntaxCopy(), e); + } + e = e->semantic(sc); + } + else + { + type = e1->type; + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + if (type->isreal() || type->isimaginary()) + { + assert(global.errors || e2->type->isfloating()); + e2 = e2->castTo(sc, e1->type); + } + e = this; + + if (e2->type->iscomplex() && !type->iscomplex()) + error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); + } + } + return e; +} + +/************************************************************/ + +MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2) +{ +} + +Expression *MinAssignExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKslice) + { // T[] -= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + if (e1->type->ty == Tpointer && e2->type->isintegral()) + e = scaleFactor(sc); + else + { + e1 = e1->checkArithmetic(); + e2 = e2->checkArithmetic(); + type = e1->type; + typeCombine(sc); + if (type->isreal() || type->isimaginary()) + { + assert(e2->type->isfloating()); + e2 = e2->castTo(sc, e1->type); + } + e = this; + + if (e2->type->iscomplex() && !type->iscomplex()) + error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); + } + return e; +} + +/************************************************************/ + +CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2) +{ +} + +Expression *CatAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKslice) + { SliceExp *se = (SliceExp *)e1; + + if (se->e1->type->toBasetype()->ty == Tsarray) + error("cannot append to static array %s", se->e1->type->toChars()); + } + + e1 = e1->modifiableLvalue(sc, e1); + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + e2->rvalue(); + + if ((tb1->ty == Tarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) && + (e2->implicitConvTo(e1->type) || + tb2->nextOf()->implicitConvTo(tb1->nextOf())) + ) + { // Append array + e2 = e2->castTo(sc, e1->type); + type = e1->type; + e = this; + } + else if ((tb1->ty == Tarray) && + e2->implicitConvTo(tb1->nextOf()) + ) + { // Append element + e2 = e2->castTo(sc, tb1->nextOf()); + type = e1->type; + e = this; + } + else + { + error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars()); + type = Type::tint32; + e = this; + } + return e; +} + +/************************************************************/ + +MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2) +{ +} + +Expression *MulAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKslice) + { // T[] -= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + if (e2->type->isfloating()) + { Type *t1; + Type *t2; + + t1 = e1->type; + t2 = e2->type; + if (t1->isreal()) + { + if (t2->isimaginary() || t2->iscomplex()) + { + e2 = e2->castTo(sc, t1); + } + } + else if (t1->isimaginary()) + { + if (t2->isimaginary() || t2->iscomplex()) + { + switch (t1->ty) + { + case Timaginary32: t2 = Type::tfloat32; break; + case Timaginary64: t2 = Type::tfloat64; break; + case Timaginary80: t2 = Type::tfloat80; break; + default: + assert(0); + } + e2 = e2->castTo(sc, t2); + } + } + + if (e2->type->iscomplex() && !type->iscomplex()) + error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); + } + return this; +} + +/************************************************************/ + +DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2) +{ +} + +Expression *DivAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKslice) + { // T[] -= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + if (e2->type->isimaginary()) + { Type *t1; + Type *t2; + + t1 = e1->type; + if (t1->isreal()) + { // x/iv = i(-x/v) + // Therefore, the result is 0 + e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1)); + e2->type = t1; + e = new AssignExp(loc, e1, e2); + e->type = t1; + return e; + } + else if (t1->isimaginary()) + { Expression *e; + + switch (t1->ty) + { + case Timaginary32: t2 = Type::tfloat32; break; + case Timaginary64: t2 = Type::tfloat64; break; + case Timaginary80: t2 = Type::tfloat80; break; + default: + assert(0); + } + e2 = e2->castTo(sc, t2); + e = new AssignExp(loc, e1, e2); + e->type = t1; + return e; + } + } + + if (e2->type->iscomplex() && !type->iscomplex()) + error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); + + return this; +} + +/************************************************************/ + +ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2) +{ +} + +Expression *ModAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssign(sc); +} + +/************************************************************/ + +ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2) +{ +} + +Expression *ShlAssignExp::semantic(Scope *sc) +{ Expression *e; + + //printf("ShlAssignExp::semantic()\n"); + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkIntegral(); + e2 = e2->checkIntegral(); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LDC + return this; +} + +/************************************************************/ + +ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2) +{ +} + +Expression *ShrAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkIntegral(); + e2 = e2->checkIntegral(); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LDC + return this; +} + +/************************************************************/ + +UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2) +{ +} + +Expression *UshrAssignExp::semantic(Scope *sc) +{ Expression *e; + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkIntegral(); + e2 = e2->checkIntegral(); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LDC + return this; +} + +/************************************************************/ + +AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2) +{ +} + +Expression *AndAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssignIntegral(sc); +} + +/************************************************************/ + +OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2) +{ +} + +Expression *OrAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssignIntegral(sc); +} + +/************************************************************/ + +XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2) +{ +} + +Expression *XorAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssignIntegral(sc); +} + +/************************* AddExp *****************************/ + +AddExp::AddExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2) +{ +} + +Expression *AddExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("AddExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + BinExp::semanticp(sc); + + e = op_overload(sc); + if (e) + return e; + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + if ((tb1->ty == Tarray || tb1->ty == Tsarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) && + tb1->nextOf()->equals(tb2->nextOf()) + ) + { + type = e1->type; + e = this; + } + else if (tb1->ty == Tpointer && e2->type->isintegral() || + tb2->ty == Tpointer && e1->type->isintegral()) + e = scaleFactor(sc); + else if (tb1->ty == Tpointer && tb2->ty == Tpointer) + { + incompatibleTypes(); + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + if ((e1->type->isreal() && e2->type->isimaginary()) || + (e1->type->isimaginary() && e2->type->isreal())) + { + switch (type->toBasetype()->ty) + { + case Tfloat32: + case Timaginary32: + type = Type::tcomplex32; + break; + + case Tfloat64: + case Timaginary64: + type = Type::tcomplex64; + break; + + case Tfloat80: + case Timaginary80: + type = Type::tcomplex80; + break; + + default: + assert(0); + } + } + e = this; + } + return e; + } + return this; +} + +/************************************************************/ + +MinExp::MinExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2) +{ +} + +Expression *MinExp::semantic(Scope *sc) +{ Expression *e; + Type *t1; + Type *t2; + +#if LOGSEMANTIC + printf("MinExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + BinExp::semanticp(sc); + + e = op_overload(sc); + if (e) + return e; + + e = this; + t1 = e1->type->toBasetype(); + t2 = e2->type->toBasetype(); + if (t1->ty == Tpointer) + { + if (t2->ty == Tpointer) + { // Need to divide the result by the stride + // Replace (ptr - ptr) with (ptr - ptr) / stride + d_int64 stride; + Expression *e; + + typeCombine(sc); // make sure pointer types are compatible + type = Type::tptrdiff_t; + stride = t2->nextOf()->size(); + if (stride == 0) + { + e = new IntegerExp(loc, 0, Type::tptrdiff_t); + } + else + { + e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t)); + e->type = Type::tptrdiff_t; + } + return e; + } + else if (t2->isintegral()) + e = scaleFactor(sc); + else + { error("incompatible types for minus"); + return new ErrorExp(); + } + } + else if (t2->ty == Tpointer) + { + type = e2->type; + error("can't subtract pointer from %s", e1->type->toChars()); + return new ErrorExp(); + } + else + { + typeCombine(sc); + t1 = e1->type->toBasetype(); + t2 = e2->type->toBasetype(); + if ((t1->isreal() && t2->isimaginary()) || + (t1->isimaginary() && t2->isreal())) + { + switch (type->ty) + { + case Tfloat32: + case Timaginary32: + type = Type::tcomplex32; + break; + + case Tfloat64: + case Timaginary64: + type = Type::tcomplex64; + break; + + case Tfloat80: + case Timaginary80: + type = Type::tcomplex80; + break; + + default: + assert(0); + } + } + } + return e; +} + +/************************* CatExp *****************************/ + +CatExp::CatExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2) +{ +} + +Expression *CatExp::semantic(Scope *sc) +{ Expression *e; + + //printf("CatExp::semantic() %s\n", toChars()); + if (!type) + { + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + + /* BUG: Should handle things like: + * char c; + * c ~ ' ' + * ' ' ~ c; + */ + +#if 0 + e1->type->print(); + e2->type->print(); +#endif + if ((tb1->ty == Tsarray || tb1->ty == Tarray) && + e2->type->implicitConvTo(tb1->nextOf()) >= MATCHconst) + { + type = tb1->nextOf()->arrayOf(); + if (tb2->ty == Tarray) + { // Make e2 into [e2] + e2 = new ArrayLiteralExp(e2->loc, e2); + e2->type = type; + } + return this; + } + else if ((tb2->ty == Tsarray || tb2->ty == Tarray) && + e1->type->implicitConvTo(tb2->nextOf()) >= MATCHconst) + { + type = tb2->nextOf()->arrayOf(); + if (tb1->ty == Tarray) + { // Make e1 into [e1] + e1 = new ArrayLiteralExp(e1->loc, e1); + e1->type = type; + } + return this; + } + + if ((tb1->ty == Tsarray || tb1->ty == Tarray) && + (tb2->ty == Tsarray || tb2->ty == Tarray) && + (tb1->nextOf()->mod || tb2->nextOf()->mod) && + (tb1->nextOf()->mod != tb2->nextOf()->mod) + ) + { + Type *t1 = tb1->nextOf()->mutableOf()->constOf()->arrayOf(); + Type *t2 = tb2->nextOf()->mutableOf()->constOf()->arrayOf(); + if (e1->op == TOKstring && !((StringExp *)e1)->committed) + e1->type = t1; + else + e1 = e1->castTo(sc, t1); + if (e2->op == TOKstring && !((StringExp *)e2)->committed) + e2->type = t2; + else + e2 = e2->castTo(sc, t2); + } + + typeCombine(sc); + type = type->toHeadMutable(); + + Type *tb = type->toBasetype(); + if (tb->ty == Tsarray) + type = tb->nextOf()->arrayOf(); + if (type->ty == Tarray && tb1->nextOf() && tb2->nextOf() && + tb1->nextOf()->mod != tb2->nextOf()->mod) + { + type = type->nextOf()->toHeadMutable()->arrayOf(); + } +#if 0 + e1->type->print(); + e2->type->print(); + type->print(); + print(); +#endif + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + if (e1->op == TOKstring && e2->op == TOKstring) + e = optimize(WANTvalue); + else if ((t1->ty == Tarray || t1->ty == Tsarray) && + (t2->ty == Tarray || t2->ty == Tsarray)) + { + e = this; + } + else + { + //printf("(%s) ~ (%s)\n", e1->toChars(), e2->toChars()); + error("Can only concatenate arrays, not (%s ~ %s)", + e1->type->toChars(), e2->type->toChars()); + type = Type::tint32; + e = this; + } + e->type = e->type->semantic(loc, sc); + return e; + } + return this; +} + +/************************************************************/ + +MulExp::MulExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2) +{ +} + +Expression *MulExp::semantic(Scope *sc) +{ Expression *e; + +#if 0 + printf("MulExp::semantic() %s\n", toChars()); +#endif + if (type) + { + return this; + } + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + if (e1->op != TOKslice && e2->op != TOKslice) + { e1->checkArithmetic(); + e2->checkArithmetic(); + } + if (type->isfloating()) + { Type *t1 = e1->type; + Type *t2 = e2->type; + + if (t1->isreal()) + { + type = t2; + } + else if (t2->isreal()) + { + type = t1; + } + else if (t1->isimaginary()) + { + if (t2->isimaginary()) + { Expression *e; + + switch (t1->ty) + { + case Timaginary32: type = Type::tfloat32; break; + case Timaginary64: type = Type::tfloat64; break; + case Timaginary80: type = Type::tfloat80; break; + default: assert(0); + } + + // iy * iv = -yv + e1->type = type; + e2->type = type; + e = new NegExp(loc, this); + e = e->semantic(sc); + return e; + } + else + type = t2; // t2 is complex + } + else if (t2->isimaginary()) + { + type = t1; // t1 is complex + } + } + return this; +} + +/************************************************************/ + +DivExp::DivExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2) +{ +} + +Expression *DivExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + if (e1->op != TOKslice && e2->op != TOKslice) + { e1->checkArithmetic(); + e2->checkArithmetic(); + } + if (type->isfloating()) + { Type *t1 = e1->type; + Type *t2 = e2->type; + + if (t1->isreal()) + { + type = t2; + if (t2->isimaginary()) + { Expression *e; + + // x/iv = i(-x/v) + e2->type = t1; + e = new NegExp(loc, this); + e = e->semantic(sc); + return e; + } + } + else if (t2->isreal()) + { + type = t1; + } + else if (t1->isimaginary()) + { + if (t2->isimaginary()) + { + switch (t1->ty) + { + case Timaginary32: type = Type::tfloat32; break; + case Timaginary64: type = Type::tfloat64; break; + case Timaginary80: type = Type::tfloat80; break; + default: assert(0); + } + } + else + type = t2; // t2 is complex + } + else if (t2->isimaginary()) + { + type = t1; // t1 is complex + } + } + return this; +} + +/************************************************************/ + +ModExp::ModExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2) +{ +} + +Expression *ModExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + if (e1->op != TOKslice && e2->op != TOKslice) + { e1->checkArithmetic(); + e2->checkArithmetic(); + } + if (type->isfloating()) + { type = e1->type; + if (e2->type->iscomplex()) + { error("cannot perform modulo complex arithmetic"); + return new ErrorExp(); + } + } + return this; +} + +/************************************************************/ + +ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2) +{ +} + +Expression *ShlExp::semantic(Scope *sc) +{ Expression *e; + + //printf("ShlExp::semantic(), type = %p\n", type); + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + e1 = e1->checkIntegral(); + e2 = e2->checkIntegral(); + e1 = e1->integralPromotions(sc); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LDC + type = e1->type; + } + return this; +} + +/************************************************************/ + +ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2) +{ +} + +Expression *ShrExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + e1 = e1->checkIntegral(); + e2 = e2->checkIntegral(); + e1 = e1->integralPromotions(sc); + e2 = e2->castTo(sc, Type::tshiftcnt); + type = e1->type; + } + return this; +} + +/************************************************************/ + +UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2) +{ +} + +Expression *UshrExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + e1 = e1->checkIntegral(); + e2 = e2->checkIntegral(); + e1 = e1->integralPromotions(sc); + e2 = e2->castTo(sc, Type::tshiftcnt); + type = e1->type; + } + return this; +} + +/************************************************************/ + +AndExp::AndExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKand, sizeof(AndExp), e1, e2) +{ +} + +Expression *AndExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + if (e1->type->toBasetype()->ty == Tbool && + e2->type->toBasetype()->ty == Tbool) + { + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + if (e1->op != TOKslice && e2->op != TOKslice) + { e1->checkIntegral(); + e2->checkIntegral(); + } + } + } + return this; +} + +/************************************************************/ + +OrExp::OrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKor, sizeof(OrExp), e1, e2) +{ +} + +Expression *OrExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + if (e1->type->toBasetype()->ty == Tbool && + e2->type->toBasetype()->ty == Tbool) + { + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + if (e1->op != TOKslice && e2->op != TOKslice) + { e1->checkIntegral(); + e2->checkIntegral(); + } + } + } + return this; +} + +/************************************************************/ + +XorExp::XorExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2) +{ +} + +Expression *XorExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + if (e1->type->toBasetype()->ty == Tbool && + e2->type->toBasetype()->ty == Tbool) + { + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + if (e1->op != TOKslice && e2->op != TOKslice) + { e1->checkIntegral(); + e2->checkIntegral(); + } + } + } + return this; +} + + +/************************************************************/ + +OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2) +{ +} + +Expression *OrOrExp::semantic(Scope *sc) +{ + unsigned cs1; + + // same as for AndAnd + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToPointer(); + e1 = e1->checkToBoolean(); + cs1 = sc->callSuper; + + if (sc->flags & SCOPEstaticif) + { + /* If in static if, don't evaluate e2 if we don't have to. + */ + e1 = e1->optimize(WANTflags); + if (e1->isBool(TRUE)) + { + return new IntegerExp(loc, 1, Type::tboolean); + } + } + + e2 = e2->semantic(sc); + sc->mergeCallSuper(loc, cs1); + e2 = resolveProperties(sc, e2); + e2 = e2->checkToPointer(); + + type = Type::tboolean; + if (e2->type->ty == Tvoid) + type = Type::tvoid; + if (e2->op == TOKtype || e2->op == TOKimport) + error("%s is not an expression", e2->toChars()); + return this; +} + +Expression *OrOrExp::checkToBoolean() +{ + e2 = e2->checkToBoolean(); + return this; +} + +int OrOrExp::isBit() +{ + return TRUE; +} + +int OrOrExp::checkSideEffect(int flag) +{ + if (flag == 2) + { + return e1->checkSideEffect(2) || e2->checkSideEffect(2); + } + else + { e1->checkSideEffect(1); + return e2->checkSideEffect(flag); + } +} + +/************************************************************/ + +AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2) +{ +} + +Expression *AndAndExp::semantic(Scope *sc) +{ + unsigned cs1; + + // same as for OrOr + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToPointer(); + e1 = e1->checkToBoolean(); + cs1 = sc->callSuper; + + if (sc->flags & SCOPEstaticif) + { + /* If in static if, don't evaluate e2 if we don't have to. + */ + e1 = e1->optimize(WANTflags); + if (e1->isBool(FALSE)) + { + return new IntegerExp(loc, 0, Type::tboolean); + } + } + + e2 = e2->semantic(sc); + sc->mergeCallSuper(loc, cs1); + e2 = resolveProperties(sc, e2); + e2 = e2->checkToPointer(); + + type = Type::tboolean; + if (e2->type->ty == Tvoid) + type = Type::tvoid; + if (e2->op == TOKtype || e2->op == TOKimport) + error("%s is not an expression", e2->toChars()); + return this; +} + +Expression *AndAndExp::checkToBoolean() +{ + e2 = e2->checkToBoolean(); + return this; +} + +int AndAndExp::isBit() +{ + return TRUE; +} + +int AndAndExp::checkSideEffect(int flag) +{ + if (flag == 2) + { + return e1->checkSideEffect(2) || e2->checkSideEffect(2); + } + else + { + e1->checkSideEffect(1); + return e2->checkSideEffect(flag); + } +} + +/************************************************************/ + +InExp::InExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKin, sizeof(InExp), e1, e2) +{ +} + +Expression *InExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + //type = Type::tboolean; + Type *t2b = e2->type->toBasetype(); + if (t2b->ty != Taarray) + { + error("rvalue of in expression must be an associative array, not %s", e2->type->toChars()); + type = Type::terror; + } + else + { + TypeAArray *ta = (TypeAArray *)t2b; + + // Special handling for array keys + if (!arrayTypeCompatible(e1->loc, e1->type, ta->index)) + { + // Convert key to type of key + e1 = e1->implicitCastTo(sc, ta->index); + } + + // Return type is pointer to value + type = ta->nextOf()->pointerTo(); + } + return this; +} + +int InExp::isBit() +{ + return FALSE; +} + + +/************************************************************/ + +/* This deletes the key e1 from the associative array e2 + */ + +RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) +{ + type = Type::tvoid; +} + +/************************************************************/ + +CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, op, sizeof(CmpExp), e1, e2) +{ +} + +Expression *CmpExp::semantic(Scope *sc) +{ Expression *e; + Type *t1; + Type *t2; + +#if LOGSEMANTIC + printf("CmpExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + BinExp::semanticp(sc); + + if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || + e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) + { + error("do not use null when comparing class types"); + } + + e = op_overload(sc); + if (e) + { + if (!e->type->isscalar() && e->type->equals(e1->type)) + { + error("recursive opCmp expansion"); + e = new ErrorExp(); + } + else + { e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32)); + e = e->semantic(sc); + } + return e; + } + + typeCombine(sc); + type = Type::tboolean; + + // Special handling for array comparisons + t1 = e1->type->toBasetype(); + t2 = e2->type->toBasetype(); + if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && + (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) + { + if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && + t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && + (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) + error("array comparison type mismatch, %s vs %s", t1->nextOf()->toChars(), t2->nextOf()->toChars()); + e = this; + } + else if (t1->ty == Tstruct || t2->ty == Tstruct || + (t1->ty == Tclass && t2->ty == Tclass)) + { + if (t2->ty == Tstruct) + error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars()); + else + error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars()); + e = this; + } +#if 1 + else if (t1->iscomplex() || t2->iscomplex()) + { + error("compare not defined for complex operands"); + e = new ErrorExp(); + } +#endif + else + e = this; + //printf("CmpExp: %s\n", e->toChars()); + return e; +} + +int CmpExp::isBit() +{ + return TRUE; +} + + +/************************************************************/ + +EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, op, sizeof(EqualExp), e1, e2) +{ + assert(op == TOKequal || op == TOKnotequal); +} + +Expression *EqualExp::semantic(Scope *sc) +{ Expression *e; + Type *t1; + Type *t2; + + //printf("EqualExp::semantic('%s')\n", toChars()); + if (type) + return this; + + BinExp::semanticp(sc); + + /* Before checking for operator overloading, check to see if we're + * comparing the addresses of two statics. If so, we can just see + * if they are the same symbol. + */ + if (e1->op == TOKaddress && e2->op == TOKaddress) + { AddrExp *ae1 = (AddrExp *)e1; + AddrExp *ae2 = (AddrExp *)e2; + + if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) + { VarExp *ve1 = (VarExp *)ae1->e1; + VarExp *ve2 = (VarExp *)ae2->e1; + + if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) + { + // They are the same, result is 'true' for ==, 'false' for != + e = new IntegerExp(loc, (op == TOKequal), Type::tboolean); + return e; + } + } + } + + if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || + e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) + { + error("use '%s' instead of '%s' when comparing with null", + Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity), + Token::toChars(op)); + } + + //if (e2->op != TOKnull) + { + e = op_overload(sc); + if (e) + { + if (op == TOKnotequal) + { + e = new NotExp(e->loc, e); + e = e->semantic(sc); + } + return e; + } + } + + e = typeCombine(sc); + type = Type::tboolean; + + // Special handling for array comparisons + if (!arrayTypeCompatible(loc, e1->type, e2->type)) + { + if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) + { + // Cast both to complex + e1 = e1->castTo(sc, Type::tcomplex80); + e2 = e2->castTo(sc, Type::tcomplex80); + } + } + return e; +} + +int EqualExp::isBit() +{ + return TRUE; +} + + + +/************************************************************/ + +IdentityExp::IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, op, sizeof(IdentityExp), e1, e2) +{ +} + +Expression *IdentityExp::semantic(Scope *sc) +{ + if (type) + return this; + + BinExp::semanticp(sc); + type = Type::tboolean; + typeCombine(sc); + if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) + { + // Cast both to complex + e1 = e1->castTo(sc, Type::tcomplex80); + e2 = e2->castTo(sc, Type::tcomplex80); + } + return this; +} + +int IdentityExp::isBit() +{ + return TRUE; +} + + +/****************************************************************/ + +CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2) + : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2) +{ + this->econd = econd; +} + +Expression *CondExp::syntaxCopy() +{ + return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy()); +} + + +Expression *CondExp::semantic(Scope *sc) +{ Type *t1; + Type *t2; + unsigned cs0; + unsigned cs1; + +#if LOGSEMANTIC + printf("CondExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + econd = econd->semantic(sc); + econd = resolveProperties(sc, econd); + econd = econd->checkToPointer(); + econd = econd->checkToBoolean(); + +#if 0 /* this cannot work right because the types of e1 and e2 + * both contribute to the type of the result. + */ + if (sc->flags & SCOPEstaticif) + { + /* If in static if, don't evaluate what we don't have to. + */ + econd = econd->optimize(WANTflags); + if (econd->isBool(TRUE)) + { + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + return e1; + } + else if (econd->isBool(FALSE)) + { + e2 = e2->semantic(sc); + e2 = resolveProperties(sc, e2); + return e2; + } + } +#endif + + + cs0 = sc->callSuper; + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + cs1 = sc->callSuper; + sc->callSuper = cs0; + e2 = e2->semantic(sc); + e2 = resolveProperties(sc, e2); + sc->mergeCallSuper(loc, cs1); + + + // If either operand is void, the result is void + t1 = e1->type; + t2 = e2->type; + if (t1->ty == Tvoid || t2->ty == Tvoid) + type = Type::tvoid; + else if (t1 == t2) + type = t1; + else + { + typeCombine(sc); + switch (e1->type->toBasetype()->ty) + { + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: + e2 = e2->castTo(sc, e1->type); + break; + } + switch (e2->type->toBasetype()->ty) + { + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: + e1 = e1->castTo(sc, e2->type); + break; + } + if (type->toBasetype()->ty == Tarray) + { + e1 = e1->castTo(sc, type); + e2 = e2->castTo(sc, type); + } + } +#if 0 + printf("res: %s\n", type->toChars()); + printf("e1 : %s\n", e1->type->toChars()); + printf("e2 : %s\n", e2->type->toChars()); +#endif + return this; +} + +#if DMDV2 +int CondExp::isLvalue() +{ + return e1->isLvalue() && e2->isLvalue(); +} +#endif + +Expression *CondExp::toLvalue(Scope *sc, Expression *ex) +{ + PtrExp *e; + + // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) + e = new PtrExp(loc, this, type); + + e1 = e1->addressOf(sc); + //e1 = e1->toLvalue(sc, NULL); + + e2 = e2->addressOf(sc); + //e2 = e2->toLvalue(sc, NULL); + + typeCombine(sc); + + type = e2->type; + return e; +} + +Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e) +{ + error("conditional expression %s is not a modifiable lvalue", toChars()); + return this; +} + +void CondExp::checkEscape() +{ + e1->checkEscape(); + e2->checkEscape(); +} + + +Expression *CondExp::checkToBoolean() +{ + e1 = e1->checkToBoolean(); + e2 = e2->checkToBoolean(); + return this; +} + +int CondExp::checkSideEffect(int flag) +{ + if (flag == 2) + { + return econd->checkSideEffect(2) || + e1->checkSideEffect(2) || + e2->checkSideEffect(2); + } + else + { + econd->checkSideEffect(1); + e1->checkSideEffect(flag); + return e2->checkSideEffect(flag); + } +} + +#if DMDV2 +int CondExp::canThrow() +{ + return econd->canThrow() || e1->canThrow() || e2->canThrow(); +} +#endif + +void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, econd, PREC_oror); + buf->writestring(" ? "); + expToCBuffer(buf, hgs, e1, PREC_expr); + buf->writestring(" : "); + expToCBuffer(buf, hgs, e2, PREC_cond); +} + +/************************************************************/ + +#if IN_LLVM + +// Strictly LDC specific stuff + +GEPExp::GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx) + : UnaExp(loc, TOKgep, sizeof(GEPExp), e) +{ + index = idx; + ident = id; +} + +void GEPExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(ident->toChars()); +} + +Expression* GEPExp::toLvalue(Scope* sc, Expression* e) +{ + // GEP's are always lvalues, at least in the "LLVM sense" ... + return this; +} + +#endif + +/****************************************************************/ + +DefaultInitExp::DefaultInitExp(Loc loc, enum TOK subop, int size) + : Expression(loc, TOKdefault, size) +{ + this->subop = subop; +} + +void DefaultInitExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(subop)); +} + +/****************************************************************/ + +FileInitExp::FileInitExp(Loc loc) + : DefaultInitExp(loc, TOKfile, sizeof(FileInitExp)) +{ +} + +Expression *FileInitExp::semantic(Scope *sc) +{ + //printf("FileInitExp::semantic()\n"); + type = Type::tchar->invariantOf()->arrayOf(); + return this; +} + +Expression *FileInitExp::resolve(Loc loc, Scope *sc) +{ + //printf("FileInitExp::resolve() %s\n", toChars()); + const char *s = loc.filename ? loc.filename : sc->module->ident->toChars(); + Expression *e = new StringExp(loc, (char *)s); + e = e->semantic(sc); + e = e->castTo(sc, type); + return e; +} + +/****************************************************************/ + +LineInitExp::LineInitExp(Loc loc) + : DefaultInitExp(loc, TOKline, sizeof(LineInitExp)) +{ +} + +Expression *LineInitExp::semantic(Scope *sc) +{ + type = Type::tint32; + return this; +} + +Expression *LineInitExp::resolve(Loc loc, Scope *sc) +{ + Expression *e = new IntegerExp(loc, loc.linnum, Type::tint32); + e = e->castTo(sc, type); + return e; +} + + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/expression.h --- a/dmd2/expression.h Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/expression.h Sat May 30 17:23:32 2009 +0100 @@ -1,1619 +1,1973 @@ - -// 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. - -#ifndef DMD_EXPRESSION_H -#define DMD_EXPRESSION_H - -#include "mars.h" -#include "identifier.h" -#include "lexer.h" -#include "arraytypes.h" - -struct Type; -struct Scope; -struct TupleDeclaration; -struct VarDeclaration; -struct FuncDeclaration; -struct FuncLiteralDeclaration; -struct Declaration; -struct CtorDeclaration; -struct NewDeclaration; -struct Dsymbol; -struct Import; -struct Module; -struct ScopeDsymbol; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct Expression; -struct Declaration; -struct AggregateDeclaration; -struct StructDeclaration; -struct TemplateInstance; -struct TemplateDeclaration; -struct ClassDeclaration; -struct HdrGenState; -struct BinExp; -struct InterState; -struct Symbol; // back end symbol -struct OverloadSet; -namespace llvm -{ - class Constant; - class ConstantInt; -} - -enum TOK; - -// Back end -struct IRState; -struct dt_t; - -#if IN_LLVM -struct DValue; -typedef DValue elem; -#else -#ifdef IN_GCC -union tree_node; typedef union tree_node elem; -#else -struct elem; -#endif -#endif - -void initPrecedence(); - -Expression *resolveProperties(Scope *sc, Expression *e); -void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); -Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id); -Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid); -void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr); -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void expandTuples(Expressions *exps); -FuncDeclaration *hasThis(Scope *sc); -Expression *fromConstInitializer(int result, Expression *e); -int arrayExpressionCanThrow(Expressions *exps); - -struct Expression : Object -{ - Loc loc; // file location - enum TOK op; // handy to minimize use of dynamic_cast - Type *type; // !=NULL means that semantic() has been run - int size; // # of bytes in Expression so we can copy() it - - Expression(Loc loc, enum TOK op, int size); - Expression *copy(); - virtual Expression *syntaxCopy(); - virtual Expression *semantic(Scope *sc); - - int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() - - void print(); - char *toChars(); - virtual void dump(int indent); - void error(const char *format, ...); - virtual void rvalue(); - - static Expression *combine(Expression *e1, Expression *e2); - static Expressions *arraySyntaxCopy(Expressions *exps); - - virtual integer_t toInteger(); - virtual uinteger_t toUInteger(); - virtual real_t toReal(); - virtual real_t toImaginary(); - virtual complex_t toComplex(); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toMangleBuffer(OutBuffer *buf); - virtual int isLvalue(); - virtual Expression *toLvalue(Scope *sc, Expression *e); - virtual Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *implicitCastTo(Scope *sc, Type *t); - virtual MATCH implicitConvTo(Type *t); - virtual Expression *castTo(Scope *sc, Type *t); - virtual void checkEscape(); - void checkScalar(); - void checkNoBool(); - Expression *checkIntegral(); - Expression *checkArithmetic(); - void checkDeprecated(Scope *sc, Dsymbol *s); - virtual Expression *checkToBoolean(); - Expression *checkToPointer(); - Expression *addressOf(Scope *sc); - Expression *deref(); - Expression *integralPromotions(Scope *sc); - - Expression *toDelegate(Scope *sc, Type *t); - virtual void scanForNestedRef(Scope *sc); - - virtual Expression *optimize(int result); - #define WANTflags 1 - #define WANTvalue 2 - #define WANTinterpret 4 - - virtual Expression *interpret(InterState *istate); - - virtual int isConst(); - virtual int isBool(int result); - virtual int isBit(); - virtual int checkSideEffect(int flag); - virtual int canThrow(); - - virtual int inlineCost(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Expression *inlineScan(InlineScanState *iss); - - // For operator overloading - virtual int isCommutative(); - virtual Identifier *opId(); - virtual Identifier *opId_r(); - - // For array ops - virtual void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - virtual Expression *buildArrayLoop(Arguments *fparams); - - // Back end - virtual elem *toElem(IRState *irs); - virtual dt_t **toDt(dt_t **pdt); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct IntegerExp : Expression -{ - integer_t value; - - IntegerExp(Loc loc, integer_t value, Type *type); - IntegerExp(integer_t value); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - char *toChars(); - void dump(int indent); - integer_t toInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - int isConst(); - int isBool(int result); - MATCH implicitConvTo(Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *toLvalue(Scope *sc, Expression *e); - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct RealExp : Expression -{ - real_t value; - - RealExp(Loc loc, real_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - char *toChars(); - integer_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Expression *castTo(Scope *sc, Type *t); - int isConst(); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct ComplexExp : Expression -{ - complex_t value; - - ComplexExp(Loc loc, complex_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - char *toChars(); - integer_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Expression *castTo(Scope *sc, Type *t); - int isConst(); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); -#ifdef _DH - OutBuffer hexp; -#endif - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct IdentifierExp : Expression -{ - Identifier *ident; - Declaration *var; - - IdentifierExp(Loc loc, Identifier *ident); - IdentifierExp(Loc loc, Declaration *var); - Expression *semantic(Scope *sc); - char *toChars(); - void dump(int indent); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct DollarExp : IdentifierExp -{ - DollarExp(Loc loc); -}; - -struct DsymbolExp : Expression -{ - Dsymbol *s; - int hasOverloads; - - DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads = 0); - Expression *semantic(Scope *sc); - char *toChars(); - void dump(int indent); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct ThisExp : Expression -{ - Declaration *var; - - ThisExp(Loc loc); - Expression *semantic(Scope *sc); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - - elem *toElem(IRState *irs); -}; - -struct SuperExp : ThisExp -{ - SuperExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); -}; - -struct NullExp : Expression -{ - unsigned char committed; // !=0 if type is committed - - NullExp(Loc loc); - Expression *semantic(Scope *sc); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *interpret(InterState *istate); - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct StringExp : Expression -{ - void *string; // char, wchar, or dchar data - size_t len; // number of chars, wchars, or dchars - unsigned char sz; // 1: char, 2: wchar, 4: dchar - unsigned char committed; // !=0 if type is committed - unsigned char postfix; // 'c', 'w', 'd' - - StringExp(Loc loc, char *s); - StringExp(Loc loc, void *s, size_t len); - StringExp(Loc loc, void *s, size_t len, unsigned char postfix); - //Expression *syntaxCopy(); - int equals(Object *o); - char *toChars(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - StringExp *toUTF8(Scope *sc); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - int compare(Object *obj); - int isBool(int result); - unsigned charAt(size_t i); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -// Tuple - -struct TupleExp : Expression -{ - Expressions *exps; - - TupleExp(Loc loc, Expressions *exps); - TupleExp(Loc loc, TupleDeclaration *tup); - Expression *syntaxCopy(); - int equals(Object *o); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - void checkEscape(); - int checkSideEffect(int flag); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - Expression *castTo(Scope *sc, Type *t); - elem *toElem(IRState *irs); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -struct ArrayLiteralExp : Expression -{ - Expressions *elements; - - ArrayLiteralExp(Loc loc, Expressions *elements); - ArrayLiteralExp(Loc loc, Expression *e); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int isBool(int result); - elem *toElem(IRState *irs); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - dt_t **toDt(dt_t **pdt); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct AssocArrayLiteralExp : Expression -{ - Expressions *keys; - Expressions *values; - - AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int isBool(int result); - elem *toElem(IRState *irs); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct StructLiteralExp : Expression -{ - StructDeclaration *sd; // which aggregate this is for - Expressions *elements; // parallels sd->fields[] with - // NULL entries for fields to skip - - Symbol *sym; // back end symbol to initialize with literal - size_t soffset; // offset from start of s - int fillHoles; // fill alignment 'holes' with zero - - StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *getField(Type *type, unsigned offset); - int getFieldIndex(Type *type, unsigned offset); - elem *toElem(IRState *irs); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - dt_t **toDt(dt_t **pdt); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - int canThrow(); - MATCH implicitConvTo(Type *t); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct TypeDotIdExp : Expression -{ - Identifier *ident; - - TypeDotIdExp(Loc loc, Type *type, Identifier *ident); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); -}; - -struct TypeExp : Expression -{ - TypeExp(Loc loc, Type *type); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - elem *toElem(IRState *irs); -}; - -struct ScopeExp : Expression -{ - ScopeDsymbol *sds; - - ScopeExp(Loc loc, ScopeDsymbol *sds); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - elem *toElem(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct TemplateExp : Expression -{ - TemplateDeclaration *td; - - TemplateExp(Loc loc, TemplateDeclaration *td); - void rvalue(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct NewExp : Expression -{ - /* thisexp.new(newargs) newtype(arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - Type *newtype; - Expressions *arguments; // Array of Expression's - - CtorDeclaration *member; // constructor function - NewDeclaration *allocator; // allocator function - int onstack; // allocate on stack - - NewExp(Loc loc, Expression *thisexp, Expressions *newargs, - Type *newtype, Expressions *arguments); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - elem *toElem(IRState *irs); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - int canThrow(); - - //int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); -}; - -struct NewAnonClassExp : Expression -{ - /* thisexp.new(newargs) class baseclasses { } (arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - ClassDeclaration *cd; // class being instantiated - Expressions *arguments; // Array of Expression's to call class constructor - - NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs, - ClassDeclaration *cd, Expressions *arguments); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int canThrow(); -}; - -struct SymbolExp : Expression -{ - Declaration *var; - int hasOverloads; - - SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads); - - elem *toElem(IRState *irs); -}; - -// Offset from symbol - -struct SymOffExp : SymbolExp -{ - unsigned offset; - - SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads = 0); - Expression *semantic(Scope *sc); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isConst(); - int isBool(int result); - Expression *doInline(InlineDoState *ids); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); - - dt_t **toDt(dt_t **pdt); - - // LDC - elem *toElem(IRState* irs); -}; - -// Variable - -struct VarExp : SymbolExp -{ - VarExp(Loc loc, Declaration *var, int hasOverloads = 0); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void dump(int indent); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void checkEscape(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - dt_t **toDt(dt_t **pdt); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); - virtual elem *toElem(IRState* irs); -}; - -#if DMDV2 -// Overload Set - -struct OverExp : Expression -{ - OverloadSet *vars; - - OverExp(OverloadSet *s); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; -#endif - -// Function/Delegate literal - -struct FuncExp : Expression -{ - FuncLiteralDeclaration *fd; - - FuncExp(Loc loc, FuncLiteralDeclaration *fd); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void scanForNestedRef(Scope *sc); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); - - int inlineCost(InlineCostState *ics); - //Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -// Declaration of a symbol - -struct DeclarationExp : Expression -{ - Dsymbol *declaration; - - DeclarationExp(Loc loc, Dsymbol *declaration); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); - void scanForNestedRef(Scope *sc); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -struct TypeidExp : Expression -{ - Type *typeidType; - - TypeidExp(Loc loc, Type *typeidType); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#if DMDV2 -struct TraitsExp : Expression -{ - Identifier *ident; - Objects *args; - - TraitsExp(Loc loc, Identifier *ident, Objects *args); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; -#endif - -struct HaltExp : Expression -{ - HaltExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int checkSideEffect(int flag); - - elem *toElem(IRState *irs); -}; - -struct IsExp : Expression -{ - /* is(targ id tok tspec) - * is(targ id == tok2) - */ - Type *targ; - Identifier *id; // can be NULL - enum TOK tok; // ':' or '==' - Type *tspec; // can be NULL - enum TOK tok2; // 'struct', 'union', 'typedef', etc. - TemplateParameters *parameters; - - IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec, - enum TOK tok2, TemplateParameters *parameters); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -/****************************************************************/ - -struct UnaExp : Expression -{ - Expression *e1; - - UnaExp(Loc loc, enum TOK op, int size, Expression *e1); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - void dump(int indent); - void scanForNestedRef(Scope *sc); - Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); // doesn't need to be virtual -}; - -struct BinExp : Expression -{ - Expression *e1; - Expression *e2; - - BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *semanticp(Scope *sc); - Expression *commonSemanticAssign(Scope *sc); - Expression *commonSemanticAssignIntegral(Scope *sc); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *scaleFactor(Scope *sc); - Expression *typeCombine(Scope *sc); - Expression *optimize(int result); - int isunsigned(); - void incompatibleTypes(); - void dump(int indent); - void scanForNestedRef(Scope *sc); - Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)); - Expression *interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)); - Expression *interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); - int canThrow(); - Expression *arrayOp(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); - - elem *toElemBin(IRState *irs, int op); -}; - -struct BinAssignExp : BinExp -{ - BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); - int checkSideEffect(int flag); -}; - -/****************************************************************/ - -struct CompileExp : UnaExp -{ - CompileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileExp : UnaExp -{ - FileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AssertExp : UnaExp -{ - Expression *msg; - - AssertExp(Loc loc, Expression *e, Expression *msg = NULL); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - int canThrow(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - elem *toElem(IRState *irs); -}; - -struct DotIdExp : UnaExp -{ - Identifier *ident; - - DotIdExp(Loc loc, Expression *e, Identifier *ident); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int i); -}; - -struct DotTemplateExp : UnaExp -{ - TemplateDeclaration *td; - - DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct DotVarExp : UnaExp -{ - Declaration *var; - int hasOverloads; - - DotVarExp(Loc loc, Expression *e, Declaration *var, int hasOverloads = 0); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); - elem *toElem(IRState *irs); - - //LDC: since we don't convert abc.def -> *(&abc + ABC.def.offsetof) - // these are needed - Expression *optimize(int result); - Expression *interpret(InterState *istate); -}; - -struct DotTemplateInstanceExp : UnaExp -{ - TemplateInstance *ti; - - DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -}; - -struct DelegateExp : UnaExp -{ - FuncDeclaration *func; - int hasOverloads; - - DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, int hasOverloads = 0); - Expression *semantic(Scope *sc); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); - - int inlineCost(InlineCostState *ics); - elem *toElem(IRState *irs); -}; - -struct DotTypeExp : UnaExp -{ - Dsymbol *sym; // symbol that represents a type - - DotTypeExp(Loc loc, Expression *e, Dsymbol *sym); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); -}; - -struct CallExp : UnaExp -{ - Expressions *arguments; // function arguments - - CallExp(Loc loc, Expression *e, Expressions *exps); - CallExp(Loc loc, Expression *e); - CallExp(Loc loc, Expression *e, Expression *earg1); - CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); - elem *toElem(IRState *irs); - void scanForNestedRef(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -struct AddrExp : UnaExp -{ - AddrExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - elem *toElem(IRState *irs); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *optimize(int result); - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct PtrExp : UnaExp -{ - PtrExp(Loc loc, Expression *e); - PtrExp(Loc loc, Expression *e, Type *t); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); -}; - -struct NegExp : UnaExp -{ - NegExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - Identifier *opId(); - - elem *toElem(IRState *irs); -}; - -struct UAddExp : UnaExp -{ - UAddExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - - // For operator overloading - Identifier *opId(); -}; - -struct ComExp : UnaExp -{ - ComExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - Identifier *opId(); - - elem *toElem(IRState *irs); -}; - -struct NotExp : UnaExp -{ - NotExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - elem *toElem(IRState *irs); -}; - -struct BoolExp : UnaExp -{ - BoolExp(Loc loc, Expression *e, Type *type); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - elem *toElem(IRState *irs); -}; - -struct DeleteExp : UnaExp -{ - DeleteExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); -}; - -struct CastExp : UnaExp -{ - // Possible to cast to one type while painting to another type - Type *to; // type to cast to - enum TOK tok; // TOKconst or TOKinvariant - - CastExp(Loc loc, Expression *e, Type *t); - CastExp(Loc loc, Expression *e, enum TOK tok); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); - - // For operator overloading - Identifier *opId(); - - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - - -struct SliceExp : UnaExp -{ - Expression *upr; // NULL if implicit 0 - Expression *lwr; // NULL if implicit [length - 1] - VarDeclaration *lengthVar; - - SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void checkEscape(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void dump(int indent); - elem *toElem(IRState *irs); - void scanForNestedRef(Scope *sc); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -struct ArrayLengthExp : UnaExp -{ - ArrayLengthExp(Loc loc, Expression *e1); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - elem *toElem(IRState *irs); -}; - -// e1[a0,a1,a2,a3,...] - -struct ArrayExp : UnaExp -{ - Expressions *arguments; // Array of Expression's - - ArrayExp(Loc loc, Expression *e1, Expressions *arguments); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - - // For operator overloading - Identifier *opId(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -/****************************************************************/ - -struct DotExp : BinExp -{ - DotExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); -}; - -struct CommaExp : BinExp -{ - CommaExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - void checkEscape(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - int isBool(int result); - int checkSideEffect(int flag); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - elem *toElem(IRState *irs); -}; - -struct IndexExp : BinExp -{ - VarDeclaration *lengthVar; - int modifiable; - - IndexExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - Expression *doInline(InlineDoState *ids); - void scanForNestedRef(Scope *sc); - - elem *toElem(IRState *irs); - - // LDC - virtual llvm::Constant *toConstElem(IRState *irs); -}; - -/* For both i++ and i-- - */ -struct PostExp : BinExp -{ - PostExp(enum TOK op, Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Identifier *opId(); // For operator overloading - elem *toElem(IRState *irs); -}; - -struct AssignExp : BinExp -{ int ismemset; // !=0 if setting the contents of an array - - AssignExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - Expression *interpret(InterState *istate); - Identifier *opId(); // For operator overloading - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - elem *toElem(IRState *irs); -}; - -#define ASSIGNEXP(op) \ -struct op##AssignExp : BinExp \ -{ \ - op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ - Expression *semantic(Scope *sc); \ - Expression *interpret(InterState *istate); \ - X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ - X(Expression *buildArrayLoop(Arguments *fparams);) \ - \ - Identifier *opId(); /* For operator overloading */ \ - \ - elem *toElem(IRState *irs); \ -}; - -#define X(a) a -ASSIGNEXP(Add) -ASSIGNEXP(Min) -ASSIGNEXP(Mul) -ASSIGNEXP(Div) -ASSIGNEXP(Mod) -ASSIGNEXP(And) -ASSIGNEXP(Or) -ASSIGNEXP(Xor) -#undef X - -#define X(a) - -ASSIGNEXP(Shl) -ASSIGNEXP(Shr) -ASSIGNEXP(Ushr) -ASSIGNEXP(Cat) - -#undef X -#undef ASSIGNEXP - -struct AddExp : BinExp -{ - AddExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct MinExp : BinExp -{ - MinExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct CatExp : BinExp -{ - CatExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct MulExp : BinExp -{ - MulExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct DivExp : BinExp -{ - DivExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct ModExp : BinExp -{ - ModExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct ShlExp : BinExp -{ - ShlExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct ShrExp : BinExp -{ - ShrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct UshrExp : BinExp -{ - UshrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct AndExp : BinExp -{ - AndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct OrExp : BinExp -{ - OrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct XorExp : BinExp -{ - XorExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct OrOrExp : BinExp -{ - OrOrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - elem *toElem(IRState *irs); -}; - -struct AndAndExp : BinExp -{ - AndAndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - elem *toElem(IRState *irs); -}; - -struct CmpExp : BinExp -{ - CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - - elem *toElem(IRState *irs); -}; - -struct InExp : BinExp -{ - InExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isBit(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - - elem *toElem(IRState *irs); -}; - -struct RemoveExp : BinExp -{ - RemoveExp(Loc loc, Expression *e1, Expression *e2); - elem *toElem(IRState *irs); -}; - -// == and != - -struct EqualExp : BinExp -{ - EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - - elem *toElem(IRState *irs); -}; - -// === and !=== - -struct IdentityExp : BinExp -{ - IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - elem *toElem(IRState *irs); -}; - -/****************************************************************/ - -struct CondExp : BinExp -{ - Expression *econd; - - CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void checkEscape(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *checkToBoolean(); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - elem *toElem(IRState *irs); -}; - -#if DMDV2 -/****************************************************************/ - -struct DefaultInitExp : Expression -{ - enum TOK subop; // which of the derived classes this is - - DefaultInitExp(Loc loc, enum TOK subop, int size); - virtual Expression *resolve(Loc loc, Scope *sc) = 0; - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileInitExp : DefaultInitExp -{ - FileInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolve(Loc loc, Scope *sc); -}; - -struct LineInitExp : DefaultInitExp -{ - LineInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolve(Loc loc, Scope *sc); -}; -#endif - -/****************************************************************/ - -#if IN_LLVM - -// this stuff is strictly LDC - -struct GEPExp : UnaExp -{ - unsigned index; - Identifier* ident; - - GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *toLvalue(Scope *sc, Expression *e); - - elem *toElem(IRState *irs); - llvm::Constant *toConstElem(IRState *irs); -}; - -#endif - -/****************************************************************/ - -/* Special values used by the interpreter - */ -#define EXP_CANT_INTERPRET ((Expression *)1) -#define EXP_CONTINUE_INTERPRET ((Expression *)2) -#define EXP_BREAK_INTERPRET ((Expression *)3) -#define EXP_GOTO_INTERPRET ((Expression *)4) -#define EXP_VOID_INTERPRET ((Expression *)5) - -Expression *expType(Type *type, Expression *e); - -Expression *Neg(Type *type, Expression *e1); -Expression *Com(Type *type, Expression *e1); -Expression *Not(Type *type, Expression *e1); -Expression *Bool(Type *type, Expression *e1); -Expression *Cast(Type *type, Type *to, Expression *e1); -Expression *ArrayLength(Type *type, Expression *e1); -Expression *Ptr(Type *type, Expression *e1); - -Expression *Add(Type *type, Expression *e1, Expression *e2); -Expression *Min(Type *type, Expression *e1, Expression *e2); -Expression *Mul(Type *type, Expression *e1, Expression *e2); -Expression *Div(Type *type, Expression *e1, Expression *e2); -Expression *Mod(Type *type, Expression *e1, Expression *e2); -Expression *Shl(Type *type, Expression *e1, Expression *e2); -Expression *Shr(Type *type, Expression *e1, Expression *e2); -Expression *Ushr(Type *type, Expression *e1, Expression *e2); -Expression *And(Type *type, Expression *e1, Expression *e2); -Expression *Or(Type *type, Expression *e1, Expression *e2); -Expression *Xor(Type *type, Expression *e1, Expression *e2); -Expression *Index(Type *type, Expression *e1, Expression *e2); -Expression *Cat(Type *type, Expression *e1, Expression *e2); - -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); - -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); - -#endif /* DMD_EXPRESSION_H */ + +// 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. + +#ifndef DMD_EXPRESSION_H +#define DMD_EXPRESSION_H + +#include "mars.h" +#include "identifier.h" +#include "lexer.h" +#include "arraytypes.h" + +struct Type; +struct Scope; +struct TupleDeclaration; +struct VarDeclaration; +struct FuncDeclaration; +struct FuncLiteralDeclaration; +struct Declaration; +struct CtorDeclaration; +struct NewDeclaration; +struct Dsymbol; +struct Import; +struct Module; +struct ScopeDsymbol; +struct InlineCostState; +struct InlineDoState; +struct InlineScanState; +struct Expression; +struct Declaration; +struct AggregateDeclaration; +struct StructDeclaration; +struct TemplateInstance; +struct TemplateDeclaration; +struct ClassDeclaration; +struct HdrGenState; +struct BinExp; +struct InterState; +#if IN_DMD +struct Symbol; // back end symbol +#endif +struct OverloadSet; + +enum TOK; + +#if IN_DMD +// Back end +struct IRState; +struct dt_t; +#endif + +#ifdef IN_GCC +union tree_node; typedef union tree_node elem; +#endif +#if IN_DMD +struct elem; +#endif + +#if IN_LLVM +struct IRState; +struct DValue; +namespace llvm { + class Constant; + class ConstantInt; +} +#endif + +void initPrecedence(); + +Expression *resolveProperties(Scope *sc, Expression *e); +void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); +Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id); +Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid); +void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr, Module *from); +void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); +void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); +void expandTuples(Expressions *exps); +FuncDeclaration *hasThis(Scope *sc); +Expression *fromConstInitializer(int result, Expression *e); +int arrayExpressionCanThrow(Expressions *exps); + +struct Expression : Object +{ + Loc loc; // file location + enum TOK op; // handy to minimize use of dynamic_cast + Type *type; // !=NULL means that semantic() has been run + int size; // # of bytes in Expression so we can copy() it + + Expression(Loc loc, enum TOK op, int size); + Expression *copy(); + virtual Expression *syntaxCopy(); + virtual Expression *semantic(Scope *sc); + Expression *trySemantic(Scope *sc); + + int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() + + void print(); + char *toChars(); + virtual void dump(int indent); + void error(const char *format, ...) IS_PRINTF(2); + void warning(const char *format, ...) IS_PRINTF(2); + virtual void rvalue(); + + static Expression *combine(Expression *e1, Expression *e2); + static Expressions *arraySyntaxCopy(Expressions *exps); + + virtual dinteger_t toInteger(); + virtual uinteger_t toUInteger(); + virtual real_t toReal(); + virtual real_t toImaginary(); + virtual complex_t toComplex(); + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual void toMangleBuffer(OutBuffer *buf); + virtual int isLvalue(); + virtual Expression *toLvalue(Scope *sc, Expression *e); + virtual Expression *modifiableLvalue(Scope *sc, Expression *e); + virtual Expression *implicitCastTo(Scope *sc, Type *t); + virtual MATCH implicitConvTo(Type *t); + virtual Expression *castTo(Scope *sc, Type *t); + virtual void checkEscape(); + void checkScalar(); + void checkNoBool(); + Expression *checkIntegral(); + Expression *checkArithmetic(); + void checkDeprecated(Scope *sc, Dsymbol *s); + void checkPurity(Scope *sc, FuncDeclaration *f); + virtual Expression *checkToBoolean(); + Expression *checkToPointer(); + Expression *addressOf(Scope *sc); + Expression *deref(); + Expression *integralPromotions(Scope *sc); + + Expression *toDelegate(Scope *sc, Type *t); + virtual void scanForNestedRef(Scope *sc); + + virtual Expression *optimize(int result); + #define WANTflags 1 + #define WANTvalue 2 + #define WANTinterpret 4 + + virtual Expression *interpret(InterState *istate); + + virtual int isConst(); + virtual int isBool(int result); + virtual int isBit(); + virtual int checkSideEffect(int flag); + virtual int canThrow(); + + virtual int inlineCost(InlineCostState *ics); + virtual Expression *doInline(InlineDoState *ids); + virtual Expression *inlineScan(InlineScanState *iss); + + // For operator overloading + virtual int isCommutative(); + virtual Identifier *opId(); + virtual Identifier *opId_r(); + + // For array ops + virtual void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + virtual Expression *buildArrayLoop(Arguments *fparams); + +#if IN_DMD + // Back end + virtual elem *toElem(IRState *irs); + virtual dt_t **toDt(dt_t **pdt); +#endif + +#if IN_LLVM + virtual DValue* toElem(IRState* irs); + virtual llvm::Constant *toConstElem(IRState *irs); + virtual void cacheLvalue(IRState* irs); + + llvm::Value* cachedLvalue; +#endif +}; + +struct IntegerExp : Expression +{ + dinteger_t value; + + IntegerExp(Loc loc, dinteger_t value, Type *type); + IntegerExp(dinteger_t value); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + char *toChars(); + void dump(int indent); + dinteger_t toInteger(); + real_t toReal(); + real_t toImaginary(); + complex_t toComplex(); + int isConst(); + int isBool(int result); + MATCH implicitConvTo(Type *t); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + Expression *toLvalue(Scope *sc, Expression *e); +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct ErrorExp : IntegerExp +{ + ErrorExp(); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct RealExp : Expression +{ + real_t value; + + RealExp(Loc loc, real_t value, Type *type); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + char *toChars(); + dinteger_t toInteger(); + uinteger_t toUInteger(); + real_t toReal(); + real_t toImaginary(); + complex_t toComplex(); + Expression *castTo(Scope *sc, Type *t); + int isConst(); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct ComplexExp : Expression +{ + complex_t value; + + ComplexExp(Loc loc, complex_t value, Type *type); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + char *toChars(); + dinteger_t toInteger(); + uinteger_t toUInteger(); + real_t toReal(); + real_t toImaginary(); + complex_t toComplex(); + Expression *castTo(Scope *sc, Type *t); + int isConst(); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); +#ifdef _DH + OutBuffer hexp; +#endif +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct IdentifierExp : Expression +{ + Identifier *ident; + Declaration *var; + + IdentifierExp(Loc loc, Identifier *ident); + IdentifierExp(Loc loc, Declaration *var); + Expression *semantic(Scope *sc); + char *toChars(); + void dump(int indent); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); +}; + +struct DollarExp : IdentifierExp +{ + DollarExp(Loc loc); +}; + +struct DsymbolExp : Expression +{ + Dsymbol *s; + int hasOverloads; + + DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads = 0); + Expression *semantic(Scope *sc); + char *toChars(); + void dump(int indent); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); +}; + +struct ThisExp : Expression +{ + Declaration *var; + + ThisExp(Loc loc); + Expression *semantic(Scope *sc); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct SuperExp : ThisExp +{ + SuperExp(Loc loc); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); +}; + +struct NullExp : Expression +{ + unsigned char committed; // !=0 if type is committed + + NullExp(Loc loc); + Expression *semantic(Scope *sc); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + Expression *interpret(InterState *istate); +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct StringExp : Expression +{ + void *string; // char, wchar, or dchar data + size_t len; // number of chars, wchars, or dchars + unsigned char sz; // 1: char, 2: wchar, 4: dchar + unsigned char committed; // !=0 if type is committed + unsigned char postfix; // 'c', 'w', 'd' + + StringExp(Loc loc, char *s); + StringExp(Loc loc, void *s, size_t len); + StringExp(Loc loc, void *s, size_t len, unsigned char postfix); + //Expression *syntaxCopy(); + int equals(Object *o); + char *toChars(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + size_t length(); + StringExp *toUTF8(Scope *sc); + Expression *implicitCastTo(Scope *sc, Type *t); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + int compare(Object *obj); + int isBool(int result); + unsigned charAt(size_t i); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +// Tuple + +struct TupleExp : Expression +{ + Expressions *exps; + + TupleExp(Loc loc, Expressions *exps); + TupleExp(Loc loc, TupleDeclaration *tup); + Expression *syntaxCopy(); + int equals(Object *o); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + void checkEscape(); + int checkSideEffect(int flag); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + Expression *castTo(Scope *sc, Type *t); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct ArrayLiteralExp : Expression +{ + Expressions *elements; + + ArrayLiteralExp(Loc loc, Expressions *elements); + ArrayLiteralExp(Loc loc, Expression *e); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int isBool(int result); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + void scanForNestedRef(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct AssocArrayLiteralExp : Expression +{ + Expressions *keys; + Expressions *values; + + AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int isBool(int result); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + void scanForNestedRef(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct StructLiteralExp : Expression +{ + StructDeclaration *sd; // which aggregate this is for + Expressions *elements; // parallels sd->fields[] with + // NULL entries for fields to skip + +#if IN_DMD + Symbol *sym; // back end symbol to initialize with literal +#endif + size_t soffset; // offset from start of s + int fillHoles; // fill alignment 'holes' with zero + + StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *getField(Type *type, unsigned offset); + int getFieldIndex(Type *type, unsigned offset); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + void scanForNestedRef(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isLvalue(); + // LDC: struct literals aren't lvalues! Taking their address can lead to + // incorrect behavior, see LDC#218, DMD#2682 + // Expression *toLvalue(Scope *sc, Expression *e); + int canThrow(); + MATCH implicitConvTo(Type *t); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident); +#if IN_DMD +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif + +struct TypeExp : Expression +{ + TypeExp(Loc loc, Type *type); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct ScopeExp : Expression +{ + ScopeDsymbol *sds; + + ScopeExp(Loc loc, ScopeDsymbol *sds); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct TemplateExp : Expression +{ + TemplateDeclaration *td; + + TemplateExp(Loc loc, TemplateDeclaration *td); + void rvalue(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct NewExp : Expression +{ + /* thisexp.new(newargs) newtype(arguments) + */ + Expression *thisexp; // if !NULL, 'this' for class being allocated + Expressions *newargs; // Array of Expression's to call new operator + Type *newtype; + Expressions *arguments; // Array of Expression's + + CtorDeclaration *member; // constructor function + NewDeclaration *allocator; // allocator function + int onstack; // allocate on stack + + NewExp(Loc loc, Expression *thisexp, Expressions *newargs, + Type *newtype, Expressions *arguments); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + int canThrow(); + + //int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct NewAnonClassExp : Expression +{ + /* thisexp.new(newargs) class baseclasses { } (arguments) + */ + Expression *thisexp; // if !NULL, 'this' for class being allocated + Expressions *newargs; // Array of Expression's to call new operator + ClassDeclaration *cd; // class being instantiated + Expressions *arguments; // Array of Expression's to call class constructor + + NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs, + ClassDeclaration *cd, Expressions *arguments); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int canThrow(); +}; + +struct SymbolExp : Expression +{ + Declaration *var; + int hasOverloads; + + SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +// Offset from symbol + +struct SymOffExp : SymbolExp +{ + unsigned offset; + Module* m; // starting point for overload resolution + + SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads = 0); + Expression *semantic(Scope *sc); + void checkEscape(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isConst(); + int isBool(int result); + Expression *doInline(InlineDoState *ids); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + void scanForNestedRef(Scope *sc); + +#if IN_DMD + dt_t **toDt(dt_t **pdt); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +// Variable + +struct VarExp : SymbolExp +{ + VarExp(Loc loc, Declaration *var, int hasOverloads = 0); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void dump(int indent); + char *toChars(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void checkEscape(); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); +#if IN_DMD + dt_t **toDt(dt_t **pdt); +#endif + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); + void cacheLvalue(IRState* irs); +#endif +}; + +#if DMDV2 +// Overload Set + +struct OverExp : Expression +{ + OverloadSet *vars; + + OverExp(OverloadSet *s); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); +}; +#endif + +// Function/Delegate literal + +struct FuncExp : Expression +{ + FuncLiteralDeclaration *fd; + + FuncExp(Loc loc, FuncLiteralDeclaration *fd); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void scanForNestedRef(Scope *sc); + char *toChars(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + + int inlineCost(InlineCostState *ics); + //Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +// Declaration of a symbol + +struct DeclarationExp : Expression +{ + Dsymbol *declaration; + + DeclarationExp(Loc loc, Dsymbol *declaration); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + void scanForNestedRef(Scope *sc); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct TypeidExp : Expression +{ + Type *typeidType; + + TypeidExp(Loc loc, Type *typeidType); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +#if DMDV2 +struct TraitsExp : Expression +{ + Identifier *ident; + Objects *args; + + TraitsExp(Loc loc, Identifier *ident, Objects *args); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; +#endif + +struct HaltExp : Expression +{ + HaltExp(Loc loc); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int checkSideEffect(int flag); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct IsExp : Expression +{ + /* is(targ id tok tspec) + * is(targ id == tok2) + */ + Type *targ; + Identifier *id; // can be NULL + enum TOK tok; // ':' or '==' + Type *tspec; // can be NULL + enum TOK tok2; // 'struct', 'union', 'typedef', etc. + TemplateParameters *parameters; + + IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec, + enum TOK tok2, TemplateParameters *parameters); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +/****************************************************************/ + +struct UnaExp : Expression +{ + Expression *e1; + + UnaExp(Loc loc, enum TOK op, int size, Expression *e1); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + void dump(int indent); + void scanForNestedRef(Scope *sc); + Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + + Expression *op_overload(Scope *sc); // doesn't need to be virtual +}; + +struct BinExp : Expression +{ + Expression *e1; + Expression *e2; + + BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *semanticp(Scope *sc); + Expression *commonSemanticAssign(Scope *sc); + Expression *commonSemanticAssignIntegral(Scope *sc); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *scaleFactor(Scope *sc); + Expression *typeCombine(Scope *sc); + Expression *optimize(int result); + int isunsigned(); + void incompatibleTypes(); + void dump(int indent); + void scanForNestedRef(Scope *sc); + Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)); + Expression *interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)); + Expression *interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); + int canThrow(); + Expression *arrayOp(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + + Expression *op_overload(Scope *sc); + +#if IN_DMD + elem *toElemBin(IRState *irs, int op); +#endif +}; + +struct BinAssignExp : BinExp +{ + BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); + int checkSideEffect(int flag); +}; + +/****************************************************************/ + +struct CompileExp : UnaExp +{ + CompileExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct FileExp : UnaExp +{ + FileExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct AssertExp : UnaExp +{ + Expression *msg; + + AssertExp(Loc loc, Expression *e, Expression *msg = NULL); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + int canThrow(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct DotIdExp : UnaExp +{ + Identifier *ident; + + DotIdExp(Loc loc, Expression *e, Identifier *ident); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int i); +}; + +struct DotTemplateExp : UnaExp +{ + TemplateDeclaration *td; + + DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct DotVarExp : UnaExp +{ + Declaration *var; + int hasOverloads; + + DotVarExp(Loc loc, Expression *e, Declaration *var, int hasOverloads = 0); + Expression *semantic(Scope *sc); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); + void cacheLvalue(IRState* irs); +#endif +}; + +struct DotTemplateInstanceExp : UnaExp +{ + TemplateInstance *ti; + + DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); +}; + +struct DelegateExp : UnaExp +{ + FuncDeclaration *func; + Module* m; // starting point for overload resolution + int hasOverloads; + + DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, int hasOverloads = 0); + Expression *semantic(Scope *sc); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); + + int inlineCost(InlineCostState *ics); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct DotTypeExp : UnaExp +{ + Dsymbol *sym; // symbol that represents a type + + DotTypeExp(Loc loc, Expression *e, Dsymbol *sym); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct CallExp : UnaExp +{ + Expressions *arguments; // function arguments + + CallExp(Loc loc, Expression *e, Expressions *exps); + CallExp(Loc loc, Expression *e); + CallExp(Loc loc, Expression *e, Expression *earg1); + CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + void scanForNestedRef(Scope *sc); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct AddrExp : UnaExp +{ + Module* m; // starting point for overload resolution + + AddrExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + Expression *optimize(int result); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct PtrExp : UnaExp +{ + PtrExp(Loc loc, Expression *e); + PtrExp(Loc loc, Expression *e, Type *t); + Expression *semantic(Scope *sc); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + +#if IN_LLVM + DValue* toElem(IRState* irs); + void cacheLvalue(IRState* irs); +#endif +}; + +struct NegExp : UnaExp +{ + NegExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + Identifier *opId(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct UAddExp : UnaExp +{ + UAddExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + + // For operator overloading + Identifier *opId(); +}; + +struct ComExp : UnaExp +{ + ComExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + Identifier *opId(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct NotExp : UnaExp +{ + NotExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct BoolExp : UnaExp +{ + BoolExp(Loc loc, Expression *e, Type *type); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct DeleteExp : UnaExp +{ + DeleteExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct CastExp : UnaExp +{ + // Possible to cast to one type while painting to another type + Type *to; // type to cast to + unsigned mod; // MODxxxxx + + CastExp(Loc loc, Expression *e, Type *t); + CastExp(Loc loc, Expression *e, unsigned mod); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + void checkEscape(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + + // For operator overloading + Identifier *opId(); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + + +struct SliceExp : UnaExp +{ + Expression *upr; // NULL if implicit 0 + Expression *lwr; // NULL if implicit [length - 1] + VarDeclaration *lengthVar; + + SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void checkEscape(); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void dump(int indent); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + void scanForNestedRef(Scope *sc); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct ArrayLengthExp : UnaExp +{ + ArrayLengthExp(Loc loc, Expression *e1); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +// e1[a0,a1,a2,a3,...] + +struct ArrayExp : UnaExp +{ + Expressions *arguments; // Array of Expression's + + ArrayExp(Loc loc, Expression *e1, Expressions *arguments); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + + // For operator overloading + Identifier *opId(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); +}; + +/****************************************************************/ + +struct DotExp : BinExp +{ + DotExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); +}; + +struct CommaExp : BinExp +{ + CommaExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + void checkEscape(); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + int isBool(int result); + int checkSideEffect(int flag); + Expression *optimize(int result); + Expression *interpret(InterState *istate); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct IndexExp : BinExp +{ + VarDeclaration *lengthVar; + int modifiable; + + IndexExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + Expression *doInline(InlineDoState *ids); + void scanForNestedRef(Scope *sc); + +#if IN_DMD + elem *toElem(IRState *irs); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); + void cacheLvalue(IRState* irs); +#endif +}; + +/* For both i++ and i-- + */ +struct PostExp : BinExp +{ + PostExp(enum TOK op, Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Identifier *opId(); // For operator overloading +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct AssignExp : BinExp +{ int ismemset; // !=0 if setting the contents of an array + + AssignExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(); + Expression *interpret(InterState *istate); + Identifier *opId(); // For operator overloading + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +#if IN_DMD +#define ASSIGNEXP_TOELEM elem *toElem(IRState *irs); +#elif IN_LLVM +#define ASSIGNEXP_TOELEM DValue* toElem(IRState *irs); +#else +#define ASSIGNEXP_TOELEM +#endif + +#define ASSIGNEXP(op) \ +struct op##AssignExp : BinExp \ +{ \ + op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ + Expression *semantic(Scope *sc); \ + Expression *interpret(InterState *istate); \ + X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ + X(Expression *buildArrayLoop(Arguments *fparams);) \ + \ + Identifier *opId(); /* For operator overloading */ \ + \ + ASSIGNEXP_TOELEM \ +}; + +#define X(a) a +ASSIGNEXP(Add) +ASSIGNEXP(Min) +ASSIGNEXP(Mul) +ASSIGNEXP(Div) +ASSIGNEXP(Mod) +ASSIGNEXP(And) +ASSIGNEXP(Or) +ASSIGNEXP(Xor) +#undef X + +#define X(a) + +ASSIGNEXP(Shl) +ASSIGNEXP(Shr) +ASSIGNEXP(Ushr) +ASSIGNEXP(Cat) + +#undef X +#undef ASSIGNEXP +#undef ASSIGNEXP_TOELEM + +struct AddExp : BinExp +{ + AddExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct MinExp : BinExp +{ + MinExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct CatExp : BinExp +{ + CatExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct MulExp : BinExp +{ + MulExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct DivExp : BinExp +{ + DivExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct ModExp : BinExp +{ + ModExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct ShlExp : BinExp +{ + ShlExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct ShrExp : BinExp +{ + ShrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct UshrExp : BinExp +{ + UshrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct AndExp : BinExp +{ + AndExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct OrExp : BinExp +{ + OrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct XorExp : BinExp +{ + XorExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct OrOrExp : BinExp +{ + OrOrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(); + int isBit(); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct AndAndExp : BinExp +{ + AndAndExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(); + int isBit(); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct CmpExp : BinExp +{ + CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct InExp : BinExp +{ + InExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + int isBit(); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct RemoveExp : BinExp +{ + RemoveExp(Loc loc, Expression *e1, Expression *e2); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +// == and != + +struct EqualExp : BinExp +{ + EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +// === and !=== + +struct IdentityExp : BinExp +{ + IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + int isBit(); + Expression *optimize(int result); + Expression *interpret(InterState *istate); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +/****************************************************************/ + +struct CondExp : BinExp +{ + Expression *econd; + + CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void checkEscape(); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + Expression *checkToBoolean(); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + void scanForNestedRef(Scope *sc); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +#if DMDV2 +/****************************************************************/ + +struct DefaultInitExp : Expression +{ + enum TOK subop; // which of the derived classes this is + + DefaultInitExp(Loc loc, enum TOK subop, int size); + virtual Expression *resolve(Loc loc, Scope *sc) = 0; + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct FileInitExp : DefaultInitExp +{ + FileInitExp(Loc loc); + Expression *semantic(Scope *sc); + Expression *resolve(Loc loc, Scope *sc); +}; + +struct LineInitExp : DefaultInitExp +{ + LineInitExp(Loc loc); + Expression *semantic(Scope *sc); + Expression *resolve(Loc loc, Scope *sc); +}; +#endif + +/****************************************************************/ + +#if IN_LLVM + +// this stuff is strictly LDC + +struct GEPExp : UnaExp +{ + unsigned index; + Identifier* ident; + + GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *toLvalue(Scope *sc, Expression *e); + + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +}; + +#endif + +/****************************************************************/ + +/* Special values used by the interpreter + */ +#define EXP_CANT_INTERPRET ((Expression *)1) +#define EXP_CONTINUE_INTERPRET ((Expression *)2) +#define EXP_BREAK_INTERPRET ((Expression *)3) +#define EXP_GOTO_INTERPRET ((Expression *)4) +#define EXP_VOID_INTERPRET ((Expression *)5) + +Expression *expType(Type *type, Expression *e); + +Expression *Neg(Type *type, Expression *e1); +Expression *Com(Type *type, Expression *e1); +Expression *Not(Type *type, Expression *e1); +Expression *Bool(Type *type, Expression *e1); +Expression *Cast(Type *type, Type *to, Expression *e1); +Expression *ArrayLength(Type *type, Expression *e1); +Expression *Ptr(Type *type, Expression *e1); + +Expression *Add(Type *type, Expression *e1, Expression *e2); +Expression *Min(Type *type, Expression *e1, Expression *e2); +Expression *Mul(Type *type, Expression *e1, Expression *e2); +Expression *Div(Type *type, Expression *e1, Expression *e2); +Expression *Mod(Type *type, Expression *e1, Expression *e2); +Expression *Shl(Type *type, Expression *e1, Expression *e2); +Expression *Shr(Type *type, Expression *e1, Expression *e2); +Expression *Ushr(Type *type, Expression *e1, Expression *e2); +Expression *And(Type *type, Expression *e1, Expression *e2); +Expression *Or(Type *type, Expression *e1, Expression *e2); +Expression *Xor(Type *type, Expression *e1, Expression *e2); +Expression *Index(Type *type, Expression *e1, Expression *e2); +Expression *Cat(Type *type, Expression *e1, Expression *e2); + +Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); +Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); +Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); + +Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); + +#endif /* DMD_EXPRESSION_H */ diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/func.c --- a/dmd2/func.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/func.c Sat May 30 17:23:32 2009 +0100 @@ -1,3108 +1,3319 @@ -// 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. - -#include -#include - -#include "mars.h" -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "expression.h" -#include "scope.h" -#include "mtype.h" -#include "aggregate.h" -#include "identifier.h" -#include "id.h" -#include "module.h" -#include "statement.h" -#include "template.h" -#include "hdrgen.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -/********************************* FuncDeclaration ****************************/ - -FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) - : Declaration(id) -{ - //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - this->storage_class = storage_class; - this->type = type; - this->loc = loc; - this->endloc = endloc; - fthrows = NULL; - frequire = NULL; - outId = NULL; - vresult = NULL; - returnLabel = NULL; - fensure = NULL; - fbody = NULL; - localsymtab = NULL; - vthis = NULL; - v_arguments = NULL; -#if IN_GCC - v_argptr = NULL; -#endif - parameters = NULL; - labtab = NULL; - overnext = NULL; - vtblIndex = -1; - hasReturnExp = 0; - naked = 0; - inlineStatus = ILSuninitialized; - inlineNest = 0; - inlineAsm = 0; - cantInterpret = 0; - semanticRun = 0; - fes = NULL; - introducing = 0; - tintro = NULL; - /* The type given for "infer the return type" is a TypeFunction with - * NULL for the return type. - */ - inferRetType = (type && type->nextOf() == NULL); - scope = NULL; - hasReturnExp = 0; - nrvo_can = 1; - nrvo_var = NULL; - shidden = NULL; - builtin = BUILTINunknown; - tookAddressOf = 0; - - // LDC - isArrayOp = false; - allowInlining = false; -} - -Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncDeclaration *f; - - //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncDeclaration *)s; - else - f = new FuncDeclaration(loc, endloc, ident, (enum STC) storage_class, type->syntaxCopy()); - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - // LDC - f->intrinsicName = intrinsicName; - - return f; -} - - -// Do the semantic analysis on the external interface to the function. - -void FuncDeclaration::semantic(Scope *sc) -{ TypeFunction *f; - StructDeclaration *sd; - ClassDeclaration *cd; - InterfaceDeclaration *id; - Dsymbol *pd; - -#if 0 - printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); - if (isFuncLiteralDeclaration()) - printf("\tFuncLiteralDeclaration()\n"); - printf("sc->parent = %s\n", sc->parent->toChars()); - printf("type: %p, %s\n", type, type->toChars()); -#endif - - storage_class |= sc->stc & ~STCref; - //printf("function storage_class = x%x\n", storage_class); - - if (!originalType) - originalType = type; - if (!type->deco && type->nextOf()) - { -#if 1 - /* Apply const and invariant storage class - * to the function type - */ - type = type->semantic(loc, sc); - if (storage_class & STCinvariant) - { // Don't use toInvariant(), as that will do a merge() - type = type->makeInvariant(); - type->deco = type->merge()->deco; - } - else if (storage_class & STCconst) - { - if (!type->isInvariant()) - { // Don't use toConst(), as that will do a merge() - type = type->makeConst(); - type->deco = type->merge()->deco; - } - } -#else - if (storage_class & (STCconst | STCinvariant)) - { - /* Apply const and invariant storage class - * to the function's return type - */ - Type *tn = type->nextOf(); - if (storage_class & STCconst) - tn = tn->makeConst(); - if (storage_class & STCinvariant) - tn = tn->makeInvariant(); - ((TypeNext *)type)->next = tn; - } - - type = type->semantic(loc, sc); -#endif - } - //type->print(); - if (type->ty != Tfunction) - { - error("%s must be a function", toChars()); - return; - } - f = (TypeFunction *)(type); - - size_t nparams = Argument::dim(f->parameters); - - linkage = sc->linkage; -// if (!parent) - { - //parent = sc->scopesym; - parent = sc->parent; - } - protection = sc->protection; - Dsymbol *parent = toParent(); - - if (storage_class & STCscope) - error("functions cannot be scope"); - - if (isAbstract() && !isVirtual()) - error("non-virtual functions cannot be abstract"); - - if ((f->isConst() || f->isInvariant()) && !isThis()) - error("without 'this' cannot be const/invariant"); - - if (isAbstract() && isFinal()) - error("cannot be both final and abstract"); -#if 0 - if (isAbstract() && fbody) - error("abstract functions cannot have bodies"); -#endif - -#if 0 - if (isStaticConstructor() || isStaticDestructor()) - { - if (!isStatic() || type->nextOf()->ty != Tvoid) - error("static constructors / destructors must be static void"); - if (f->arguments && f->arguments->dim) - error("static constructors / destructors must have empty parameter list"); - // BUG: check for invalid storage classes - } -#endif - -#ifdef IN_GCC - AggregateDeclaration *ad; - - ad = parent->isAggregateDeclaration(); - if (ad) - ad->methods.push(this); -#endif - sd = parent->isStructDeclaration(); - if (sd) - { - if (isCtorDeclaration()) - { - return; - } -#if 0 - // Verify no constructors, destructors, etc. - if (isCtorDeclaration() - //||isDtorDeclaration() - //|| isInvariantDeclaration() - //|| isUnitTestDeclaration() - ) - { - error("special member functions not allowed for %ss", sd->kind()); - } - - if (!sd->inv) - sd->inv = isInvariantDeclaration(); - - if (!sd->aggNew) - sd->aggNew = isNewDeclaration(); - - if (isDelete()) - { - if (sd->aggDelete) - error("multiple delete's for struct %s", sd->toChars()); - sd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - } - - id = parent->isInterfaceDeclaration(); - if (id) - { - storage_class |= STCabstract; - - if (isCtorDeclaration() || - isPostBlitDeclaration() || - isDtorDeclaration() || - isInvariantDeclaration() || - isUnitTestDeclaration() || isNewDeclaration() || isDelete()) - error("special function not allowed in interface %s", id->toChars()); - if (fbody) - error("function body is not abstract in interface %s", id->toChars()); - } - - /* Template member functions aren't virtual: - * interface TestInterface { void tpl(T)(); } - * and so won't work in interfaces - */ - if ((pd = toParent()) != NULL && - pd->isTemplateInstance() && - (pd = toParent2()) != NULL && - (id = pd->isInterfaceDeclaration()) != NULL) - { - error("template member function not allowed in interface %s", id->toChars()); - } - - cd = parent->isClassDeclaration(); - if (cd) - { int vi; - CtorDeclaration *ctor; - DtorDeclaration *dtor; - InvariantDeclaration *inv; - - if (isCtorDeclaration()) - { -// ctor = (CtorDeclaration *)this; -// if (!cd->ctor) -// cd->ctor = ctor; - return; - } - -#if 0 - dtor = isDtorDeclaration(); - if (dtor) - { - if (cd->dtor) - error("multiple destructors for class %s", cd->toChars()); - cd->dtor = dtor; - } - - inv = isInvariantDeclaration(); - if (inv) - { - cd->inv = inv; - } - - if (isNewDeclaration()) - { - if (!cd->aggNew) - cd->aggNew = (NewDeclaration *)(this); - } - - if (isDelete()) - { - if (cd->aggDelete) - error("multiple delete's for class %s", cd->toChars()); - cd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - - if (storage_class & STCabstract) - cd->isabstract = 1; - - // if static function, do not put in vtbl[] - if (!isVirtual()) - { - //printf("\tnot virtual\n"); - goto Ldone; - } - - // Find index of existing function in vtbl[] to override - vi = findVtblIndex(&cd->vtbl, cd->baseClass ? cd->baseClass->vtbl.dim : 0); - switch (vi) - { - case -1: - /* Didn't find one, so - * This is an 'introducing' function which gets a new - * slot in the vtbl[]. - */ - - // Verify this doesn't override previous final function - if (cd->baseClass) - { Dsymbol *s = cd->baseClass->search(loc, ident, 0); - if (s) - { - FuncDeclaration *f = s->isFuncDeclaration(); - f = f->overloadExactMatch(type); - if (f && f->isFinal() && f->prot() != PROTprivate) - error("cannot override final function %s", f->toPrettyChars()); - } - } - - if (isFinal()) - { - cd->vtblFinal.push(this); - } - else - { - // Append to end of vtbl[] - //printf("\tintroducing function\n"); - introducing = 1; - vi = cd->vtbl.dim; - cd->vtbl.push(this); - vtblIndex = vi; - } - break; - - case -2: // can't determine because of fwd refs - cd->sizeok = 2; // can't finish due to forward reference - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)cd->vtbl.data[vi]; - // This function is covariant with fdv - if (fdv->isFinal()) - error("cannot override final function %s", fdv->toPrettyChars()); - -#if DMDV2 - if (!isOverride() && global.params.warnings) - warning("%s: overrides base class function %s, but is not marked with 'override'", locToChars(), fdv->toPrettyChars()); -#endif - - if (fdv->toParent() == parent) - { - // If both are mixins, then error. - // If either is not, the one that is not overrides - // the other. - if (fdv->parent->isClassDeclaration()) - break; - if (!this->parent->isClassDeclaration() -#if !BREAKABI - && !isDtorDeclaration() -#endif -#if DMDV2 - && !isPostBlitDeclaration() -#endif - ) - error("multiple overrides of same function"); - } - cd->vtbl.data[vi] = (void *)this; - vtblIndex = vi; - - /* This works by whenever this function is called, - * it actually returns tintro, which gets dynamically - * cast to type. But we know that tintro is a base - * of type, so we could optimize it by not doing a - * dynamic cast, but just subtracting the isBaseOf() - * offset if the value is != null. - */ - - if (fdv->tintro) - tintro = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - tintro = fdv->type; - } - } - break; - } - } - - /* Go through all the interface bases. - * If this function is covariant with any members of those interface - * functions, set the tintro. - */ - for (int i = 0; i < cd->interfaces_dim; i++) - { - BaseClass *b = cd->interfaces[i]; - vi = findVtblIndex(&b->base->vtbl, b->base->vtbl.dim); - switch (vi) - { - case -1: - break; - - case -2: - cd->sizeok = 2; // can't finish due to forward reference - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; - Type *ti = NULL; - - if (fdv->tintro) - ti = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - ti = fdv->type; -#if 0 - if (offset) - ti = fdv->type; - else if (type->nextOf()->ty == Tclass) - { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; - if (cdn && cdn->sizeok != 1) - ti = fdv->type; - } -#endif - } - } - if (ti) - { - if (tintro && !tintro->equals(ti)) - { - error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); - } - tintro = ti; - } - goto L2; - } - } - } - - if (introducing && isOverride()) - { - error("does not override any function"); - } - - L2: ; - } - else if (isOverride() && !parent->isTemplateInstance()) - error("override only applies to class member functions"); - - /* Do not allow template instances to add virtual functions - * to a class. - */ - if (isVirtual()) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - ClassDeclaration *cd = ti->tempdecl->isClassMember(); - if (cd) - { - error("cannot use template to add virtual function to class '%s'", cd->toChars()); - } - } - } - - if (isMain()) - { - // Check parameters to see if they are either () or (char[][] args) - switch (nparams) - { - case 0: - break; - - case 1: - { - Argument *arg0 = Argument::getNth(f->parameters, 0); - if (arg0->type->ty != Tarray || - arg0->type->nextOf()->ty != Tarray || - arg0->type->nextOf()->nextOf()->ty != Tchar || - arg0->storageClass & (STCout | STCref | STClazy)) - goto Lmainerr; - break; - } - - default: - goto Lmainerr; - } - - if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) - error("must return int or void, not %s", f->nextOf()->toChars()); - if (f->varargs) - { - Lmainerr: - error("parameters must be main() or main(char[][] args)"); - } - } - - if (ident == Id::assign && (sd || cd)) - { // Disallow identity assignment operator. - - // opAssign(...) - if (nparams == 0) - { if (f->varargs == 1) - goto Lassignerr; - } - else - { - Argument *arg0 = Argument::getNth(f->parameters, 0); - Type *t0 = arg0->type->toBasetype(); - Type *tb = sd ? sd->type : cd->type; - if (arg0->type->implicitConvTo(tb) || - (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) - ) - { - if (nparams == 1) - goto Lassignerr; - Argument *arg1 = Argument::getNth(f->parameters, 1); - if (arg1->defaultArg) - goto Lassignerr; - } - } - } - -Ldone: - /* Save scope for possible later use (if we need the - * function internals) - */ - scope = new Scope(*sc); - scope->setNoFree(); - return; - -Lassignerr: - if (sd) - { - sd->hasIdentityAssign = 1; // don't need to generate it - goto Ldone; - } - error("identity assignment operator overload is illegal"); -} - -void FuncDeclaration::semantic2(Scope *sc) -{ -} - -// Do the semantic analysis on the internals of the function. - -void FuncDeclaration::semantic3(Scope *sc) -{ TypeFunction *f; - AggregateDeclaration *ad; - VarDeclaration *argptr = NULL; - VarDeclaration *_arguments = NULL; - - if (!parent) - { - if (global.errors) - return; - //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); - assert(0); - } - //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); - //fflush(stdout); - //{ static int x; if (++x == 2) *(char*)0=0; } - //printf("\tlinkage = %d\n", sc->linkage); - - //printf(" sc->incontract = %d\n", sc->incontract); - if (semanticRun) - return; - semanticRun = 1; - - if (!type || type->ty != Tfunction) - return; - f = (TypeFunction *)(type); - - // Check the 'throws' clause - if (fthrows) - { - for (int i = 0; i < fthrows->dim; i++) - { - Type *t = (Type *)fthrows->data[i]; - - t = t->semantic(loc, sc); - if (!t->isClassHandle()) - error("can only throw classes, not %s", t->toChars()); - } - } - - if (fbody || frequire) - { - /* Symbol table into which we place parameters and nested functions, - * solely to diagnose name collisions. - */ - localsymtab = new DsymbolTable(); - - // Establish function scope - ScopeDsymbol *ss = new ScopeDsymbol(); - ss->parent = sc->scopesym; - Scope *sc2 = sc->push(ss); - sc2->func = this; - sc2->parent = this; - sc2->callSuper = 0; - sc2->sbreak = NULL; - sc2->scontinue = NULL; - sc2->sw = NULL; - sc2->fes = fes; - sc2->linkage = LINKd; - sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STCconst | STCfinal | STCinvariant | STCtls); - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - sc2->structalign = 8; - sc2->incontract = 0; - sc2->tf = NULL; - sc2->tfOfTry = NULL; - sc2->noctor = 0; - - // Declare 'this' - ad = isThis(); - if (ad) - { VarDeclaration *v; - - if (isFuncLiteralDeclaration() && isNested()) - { - error("literals cannot be class members"); - return; - } - else - { - assert(!isNested()); // can't be both member and nested - assert(ad->handle); - Type *thandle = ad->handle; - if (storage_class & STCconst || type->isConst()) - { -#if STRUCTTHISREF - thandle = thandle->constOf(); -#else - if (thandle->ty == Tclass) - thandle = thandle->constOf(); - else - { assert(thandle->ty == Tpointer); - thandle = thandle->nextOf()->constOf()->pointerTo(); - } -#endif - } - else if (storage_class & STCinvariant || type->isInvariant()) - { -#if STRUCTTHISREF - thandle = thandle->invariantOf(); -#else - if (thandle->ty == Tclass) - thandle = thandle->invariantOf(); - else - { assert(thandle->ty == Tpointer); - thandle = thandle->nextOf()->invariantOf()->pointerTo(); - } -#endif - } - v = new ThisDeclaration(thandle); - v->storage_class |= STCparameter; -#if STRUCTTHISREF - if (thandle->ty == Tstruct) - v->storage_class |= STCref; -#endif - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - } - else if (isNested()) - { - /* The 'this' for a nested function is the link to the - * enclosing function's stack frame. - * Note that nested functions and member functions are disjoint. - */ - VarDeclaration *v = new ThisDeclaration(Type::tvoid->pointerTo()); - v->storage_class |= STCparameter; - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - - // Declare hidden variable _arguments[] and _argptr - if (f->varargs == 1) - { Type *t; - - if (f->linkage == LINKd) - { // Declare _arguments[] -#if BREAKABI - v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); - v_arguments->storage_class = STCparameter; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; - - //t = Type::typeinfo->type->constOf()->arrayOf(); - t = Type::typeinfo->type->arrayOf(); - _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - _arguments->semantic(sc2); - sc2->insert(_arguments); - _arguments->parent = this; -#else - t = Type::typeinfo->type->arrayOf(); - v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; -#endif - } - if (f->linkage == LINKd || (parameters && parameters->dim)) - { // Declare _argptr -#if IN_GCC - t = d_gcc_builtin_va_list_d_type; -#else - t = Type::tvoid->pointerTo(); -#endif - argptr = new VarDeclaration(0, t, Id::_argptr, NULL); - argptr->semantic(sc2); - sc2->insert(argptr); - argptr->parent = this; - } - } - - // Propagate storage class from tuple parameters to their element-parameters. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Argument *arg = (Argument *)f->parameters->data[i]; - - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Argument::dim(t->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *narg = Argument::getNth(t->arguments, j); - narg->storageClass = arg->storageClass; - } - } - } - } - - /* Declare all the function parameters as variables - * and install them in parameters[] - */ - size_t nparams = Argument::dim(f->parameters); - if (nparams) - { /* parameters[] has all the tuples removed, as the back end - * doesn't know about tuples - */ - parameters = new Dsymbols(); - parameters->reserve(nparams); - for (size_t i = 0; i < nparams; i++) - { - Argument *arg = Argument::getNth(f->parameters, i); - Identifier *id = arg->ident; - if (!id) - { - /* Generate identifier for un-named parameter, - * because we need it later on. - */ - arg->ident = id = Identifier::generateId("_param_", i); - } - VarDeclaration *v = new VarDeclaration(loc, arg->type, id, NULL); - //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); - v->storage_class |= STCparameter; - if (f->varargs == 2 && i + 1 == nparams) - v->storage_class |= STCvariadic; - v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy | STCfinal | STCconst | STCinvariant | STCnodtor); - v->semantic(sc2); - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - parameters->push(v); - localsymtab->insert(v); - v->parent = this; - } - } - - // Declare the tuple symbols and put them in the symbol table, - // but not in parameters[]. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Argument *arg = (Argument *)f->parameters->data[i]; - - if (!arg->ident) - continue; // never used, so ignore - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Argument::dim(t->arguments); - Objects *exps = new Objects(); - exps->setDim(dim); - for (size_t j = 0; j < dim; j++) - { Argument *narg = Argument::getNth(t->arguments, j); - assert(narg->ident); - VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); - assert(v); - Expression *e = new VarExp(v->loc, v); - exps->data[j] = (void *)e; - } - assert(arg->ident); - TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); - //printf("declaring tuple %s\n", v->toChars()); - v->isexp = 1; - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - localsymtab->insert(v); - v->parent = this; - } - } - } - - /* Do the semantic analysis on the [in] preconditions and - * [out] postconditions. - */ - sc2->incontract++; - - if (frequire) - { /* frequire is composed of the [in] contracts - */ - // BUG: need to error if accessing out parameters - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - // BUG: verify that all in and ref parameters are read - frequire = frequire->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (fensure || addPostInvariant()) - { /* fensure is composed of the [out] contracts - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - sc2 = sc2->push(sym); - - assert(type->nextOf()); - if (type->nextOf()->ty == Tvoid) - { - if (outId) - error("void functions have no result"); - } - else - { - if (!outId) - outId = Id::result; // provide a default - } - - if (outId) - { // Declare result variable - VarDeclaration *v; - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - v->noauto = 1; - sc2->incontract--; - v->semantic(sc2); - sc2->incontract++; - if (!sc2->insert(v)) - error("out result %s is already defined", v->toChars()); - v->parent = this; - vresult = v; - - // vresult gets initialized with the function return value - // in ReturnStatement::semantic() - } - - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - if (fensure) - { fensure = fensure->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (!global.params.useOut) - { fensure = NULL; // discard - vresult = NULL; - } - - // Postcondition invariant - if (addPostInvariant()) - { - Expression *e = NULL; - if (isCtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - Expression *v = new ThisExp(0); - v->type = vthis->type; -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - e = new AssertExp(0, v); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - if (fensure) - fensure = new CompoundStatement(0, s, fensure); - else - fensure = s; - } - } - - if (fensure) - { returnLabel = new LabelDsymbol(Id::returnLabel); - LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); - ls->isReturnLabel = 1; - returnLabel->statement = ls; - } - sc2 = sc2->pop(); - } - - sc2->incontract--; - - if (fbody) - { ClassDeclaration *cd = isClassMember(); - - /* If this is a class constructor - */ - if (isCtorDeclaration() && cd) - { - for (int i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - v->ctorinit = 0; - } - } - - if (inferRetType || f->retStyle() != RETstack) - nrvo_can = 0; - - fbody = fbody->semantic(sc2); - - if (inferRetType) - { // If no return type inferred yet, then infer a void - if (!type->nextOf()) - { - ((TypeFunction *)type)->next = Type::tvoid; - type = type->semantic(loc, sc); - } - f = (TypeFunction *)type; - } - - if (isStaticCtorDeclaration()) - { /* It's a static constructor. Ensure that all - * ctor consts were initialized. - */ - - Dsymbol *p = toParent(); - ScopeDsymbol *ad = p->isScopeDsymbol(); - if (!ad) - { - error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); - } - else - { - for (int i = 0; i < ad->members->dim; i++) - { Dsymbol *s = (Dsymbol *)ad->members->data[i]; - - s->checkCtorConstInit(); - } - } - } - - if (isCtorDeclaration() && cd) - { - //printf("callSuper = x%x\n", sc2->callSuper); - - // Verify that all the ctorinit fields got initialized - if (!(sc2->callSuper & CSXthis_ctor)) - { - for (int i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - if (v->ctorinit == 0 && v->isCtorinit()) - error("missing initializer for final field %s", v->toChars()); - } - } - - if (!(sc2->callSuper & CSXany_ctor) && - cd->baseClass && cd->baseClass->ctor) - { - sc2->callSuper = 0; - - // Insert implicit super() at start of fbody - Expression *e1 = new SuperExp(0); - Expression *e = new CallExp(0, e1); - - unsigned errors = global.errors; - global.gag++; - e = e->semantic(sc2); - global.gag--; - if (errors != global.errors) - error("no match for implicit super() call in constructor"); - - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, s, fbody); - } - } - else if (fes) - { // For foreach(){} body, append a return 0; - Expression *e = new IntegerExp(0); - Statement *s = new ReturnStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - assert(!returnLabel); - } - else if (!hasReturnExp && type->nextOf()->ty != Tvoid) - error("expected to return a value of type %s", type->nextOf()->toChars()); - else if (!inlineAsm) - { - int offend = fbody ? fbody->blockExit() & BEfallthru : TRUE; - //int offend = fbody ? fbody->fallOffEnd() : TRUE; - - if (type->nextOf()->ty == Tvoid) - { - if (offend && isMain()) - { // Add a return 0; statement - Statement *s = new ReturnStatement(0, new IntegerExp(0)); - fbody = new CompoundStatement(0, fbody, s); - } - } - else - { - if (offend) - { Expression *e; - - if (global.params.warnings) - { warning("%s: no return at end of function", locToChars()); - } - - if (global.params.useAssert && - !global.params.useInline) - { /* Add an assert(0, msg); where the missing return - * should be. - */ - e = new AssertExp( - endloc, - new IntegerExp(0), - new StringExp(loc, (char *)"missing return expression") - ); - } - else - e = new HaltExp(endloc); - e = new CommaExp(0, e, type->nextOf()->defaultInit()); - e = e->semantic(sc2); - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - } - } - } - } - - { - Statements *a = new Statements(); - - // Merge in initialization of 'out' parameters - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - if (v->storage_class & STCout) - { - assert(v->init); - ExpInitializer *ie = v->init->isExpInitializer(); - assert(ie); - a->push(new ExpStatement(0, ie->exp)); - } - } - } - -// we'll handle variadics ourselves -#if !IN_LLVM - if (argptr) - { // Initialize _argptr to point past non-variadic arg -#if IN_GCC - // Handled in FuncDeclaration::toObjFile - v_argptr = argptr; - v_argptr->init = new VoidInitializer(loc); -#else - Expression *e1; - Expression *e; - Type *t = argptr->type; - VarDeclaration *p; - unsigned offset; - - e1 = new VarExp(0, argptr); - if (parameters && parameters->dim) - p = (VarDeclaration *)parameters->data[parameters->dim - 1]; - else - p = v_arguments; // last parameter is _arguments[] - offset = p->type->size(); - offset = (offset + 3) & ~3; // assume stack aligns on 4 - e = new SymOffExp(0, p, offset); - e = new AssignExp(0, e1, e); - e->type = t; - a->push(new ExpStatement(0, e)); -#endif // IN_GCC - } - - if (_arguments) - { - /* Advance to elements[] member of TypeInfo_Tuple with: - * _arguments = v_arguments.elements; - */ - Expression *e = new VarExp(0, v_arguments); - e = new DotIdExp(0, e, Id::elements); - Expression *e1 = new VarExp(0, _arguments); - e = new AssignExp(0, e1, e); - e->op = TOKconstruct; - e = e->semantic(sc); - a->push(new ExpStatement(0, e)); - } - -#endif // !IN_LLVM - - // Merge contracts together with body into one compound statement - -#ifdef _DH - if (frequire && global.params.useIn) - { frequire->incontract = 1; - a->push(frequire); - } -#else - if (frequire && global.params.useIn) - a->push(frequire); -#endif - - // Precondition invariant - if (addPreInvariant()) - { - Expression *e = NULL; - if (isDtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - Expression *v = new ThisExp(0); - v->type = vthis->type; -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - Expression *se = new StringExp(0, (char *)"null this"); - se = se->semantic(sc); - se->type = Type::tchar->arrayOf(); - e = new AssertExp(loc, v, se); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - a->push(s); - } - } - - if (fbody) - a->push(fbody); - - if (fensure) - { - a->push(returnLabel->statement); - - if (type->nextOf()->ty != Tvoid) - { - // Create: return vresult; - assert(vresult); - Expression *e = new VarExp(0, vresult); - if (tintro) - { e = e->implicitCastTo(sc, tintro->nextOf()); - e = e->semantic(sc); - } - ReturnStatement *s = new ReturnStatement(0, e); - a->push(s); - } - } - - fbody = new CompoundStatement(0, a); - - /* Append destructor calls for parameters as finally blocks. - */ - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - - if (v->storage_class & (STCref | STCout)) - continue; - - /* Don't do this for static arrays, since static - * arrays are called by reference. Remove this - * when we change them to call by value. - */ - if (v->type->toBasetype()->ty == Tsarray) - continue; - - Expression *e = v->callAutoDtor(sc); - if (e) - { Statement *s = new ExpStatement(0, e); - s = s->semantic(sc); - if (fbody->blockExit() == BEfallthru) - fbody = new CompoundStatement(0, fbody, s); - else - fbody = new TryFinallyStatement(0, fbody, s); - } - } - } - } - - sc2->callSuper = 0; - sc2->pop(); - } - semanticRun = 2; -} - -void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); - - type->toCBuffer(buf, ident, hgs); - bodyToCBuffer(buf, hgs); -} - - -void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (fbody && - (!hgs->hdrgen || hgs->tpltMember || canInline(1,1)) - ) - { buf->writenl(); - - // in{} - if (frequire) - { buf->writestring("in"); - buf->writenl(); - frequire->toCBuffer(buf, hgs); - } - - // out{} - if (fensure) - { buf->writestring("out"); - if (outId) - { buf->writebyte('('); - buf->writestring(outId->toChars()); - buf->writebyte(')'); - } - buf->writenl(); - fensure->toCBuffer(buf, hgs); - } - - if (frequire || fensure) - { buf->writestring("body"); - buf->writenl(); - } - - buf->writebyte('{'); - buf->writenl(); - fbody->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { buf->writeByte(';'); - buf->writenl(); - } -} - -/**************************************************** - * Determine if 'this' overrides fd. - * Return !=0 if it does. - */ - -int FuncDeclaration::overrides(FuncDeclaration *fd) -{ int result = 0; - - if (fd->ident == ident) - { - int cov = type->covariant(fd->type); - if (cov) - { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); - ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); - - if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) - result = 1; - } - } - return result; -} - -/************************************************* - * Find index of function in vtbl[0..dim] that - * this function overrides. - * Returns: - * -1 didn't find one - * -2 can't determine because of forward references - */ - -int FuncDeclaration::findVtblIndex(Array *vtbl, int dim) -{ - for (int vi = 0; vi < dim; vi++) - { - FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration(); - if (fdv && fdv->ident == ident) - { - int cov = type->covariant(fdv->type); - //printf("\tbaseclass cov = %d\n", cov); - switch (cov) - { - case 0: // types are distinct - break; - - case 1: - return vi; - - case 2: - //type->print(); - //fdv->type->print(); - //printf("%s %s\n", type->deco, fdv->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); - break; - - case 3: - return -2; // forward references - - default: - assert(0); - } - } - } - return -1; -} - -/**************************************************** - * Overload this FuncDeclaration with the new one f. - * Return !=0 if successful; i.e. no conflict. - */ - -int FuncDeclaration::overloadInsert(Dsymbol *s) -{ - FuncDeclaration *f; - AliasDeclaration *a; - - //printf("FuncDeclaration::overloadInsert(%s)\n", s->toChars()); - a = s->isAliasDeclaration(); - if (a) - { - if (overnext) - return overnext->overloadInsert(a); - if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) - { - //printf("\ta = '%s'\n", a->type->toChars()); - return FALSE; - } - overnext = a; - //printf("\ttrue: no conflict\n"); - return TRUE; - } - f = s->isFuncDeclaration(); - if (!f) - return FALSE; - -#if 0 - /* Disable this check because: - * const void foo(); - * semantic() isn't run yet on foo(), so the const hasn't been - * applied yet. - */ - if (type) - { printf("type = %s\n", type->toChars()); - printf("f->type = %s\n", f->type->toChars()); - } - if (type && f->type && // can be NULL for overloaded constructors - f->type->covariant(type) && - f->type->mod == type->mod && - !isFuncAliasDeclaration()) - { - //printf("\tfalse: conflict %s\n", kind()); - return FALSE; - } -#endif - - if (overnext) - return overnext->overloadInsert(f); - overnext = f; - //printf("\ttrue: no conflict\n"); - return TRUE; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -/*************************************************** - * Visit each overloaded function in turn, and call - * (*fp)(param, f) on it. - * Exit when no more, or (*fp)(param, f) returns 1. - * Returns: - * 0 continue - * 1 done - */ - -int overloadApply(FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param) -{ - FuncDeclaration *f; - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) - { - if (overloadApply(fa->funcalias, fp, param)) - return 1; - next = fa->overnext; - } - else - { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - } - else - { - f = d->isFuncDeclaration(); - if (!f) - { d->error("is aliased to a function"); - break; // BUG: should print error message? - } - if ((*fp)(param, f)) - return 1; - - next = f->overnext; - } - } - } - return 0; -} - -/******************************************** - * If there are no overloads of function f, return that function, - * otherwise return NULL. - */ - -static int fpunique(void *param, FuncDeclaration *f) -{ FuncDeclaration **pf = (FuncDeclaration **)param; - - if (*pf) - { *pf = NULL; - return 1; // ambiguous, done - } - else - { *pf = f; - return 0; - } -} - -FuncDeclaration *FuncDeclaration::isUnique() -{ FuncDeclaration *result = NULL; - - overloadApply(this, &fpunique, &result); - return result; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -struct Param1 -{ - Type *t; // type to match - FuncDeclaration *f; // return value -}; - -int fp1(void *param, FuncDeclaration *f) -{ Param1 *p = (Param1 *)param; - Type *t = p->t; - - if (t->equals(f->type)) - { p->f = f; - return 1; - } - -#if DMDV2 - /* Allow covariant matches, if it's just a const conversion - * of the return type - */ - if (t->ty == Tfunction) - { TypeFunction *tf = (TypeFunction *)f->type; - if (tf->covariant(t) == 1 && - tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) - { - p->f = f; - return 1; - } - } -#endif - return 0; -} - -FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t) -{ - Param1 p; - p.t = t; - p.f = NULL; - overloadApply(this, &fp1, &p); - return p.f; -} - - -/******************************************** - * Decide which function matches the arguments best. - */ - -struct Param2 -{ - Match *m; - Expression *ethis; - Expressions *arguments; -}; - -int fp2(void *param, FuncDeclaration *f) -{ Param2 *p = (Param2 *)param; - Match *m = p->m; - Expressions *arguments = p->arguments; - MATCH match; - - if (f != m->lastf) // skip duplicates - { - m->anyf = f; - TypeFunction *tf = (TypeFunction *)f->type; - match = (MATCH) tf->callMatch(f->needThis() ? p->ethis : NULL, arguments); - //printf("match = %d\n", match); - if (match != MATCHnomatch) - { - if (match > m->last) - goto LfIsBetter; - - if (match < m->last) - goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - if (m->lastf->overrides(f)) - goto LlastIsBetter; - else if (f->overrides(m->lastf)) - goto LfIsBetter; - - /* Try to disambiguate using template-style partial ordering rules. - * In essence, if f() and g() are ambiguous, if f() can call g(), - * but g() cannot call f(), then pick f(). - * This is because f() is "more specialized." - */ - { - MATCH c1 = f->leastAsSpecialized(m->lastf); - MATCH c2 = m->lastf->leastAsSpecialized(f); - //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) - goto LfIsBetter; - if (c1 < c2) - goto LlastIsBetter; - } - - Lambiguous: - m->nextf = f; - m->count++; - return 0; - - LfIsBetter: - m->last = match; - m->lastf = f; - m->count = 1; - return 0; - - LlastIsBetter: - return 0; - } - } - return 0; -} - -void overloadResolveX(Match *m, FuncDeclaration *fstart, - Expression *ethis, Expressions *arguments) -{ - Param2 p; - p.m = m; - p.ethis = ethis; - p.arguments = arguments; - overloadApply(fstart, &fp2, &p); -} - - -FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags) -{ - TypeFunction *tf; - Match m; - -#if 0 -printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); -if (arguments) -{ int i; - - for (i = 0; i < arguments->dim; i++) - { Expression *arg; - - arg = (Expression *)arguments->data[i]; - assert(arg->type); - printf("\t%s: ", arg->toChars()); - arg->type->print(); - } -} -#endif - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - overloadResolveX(&m, this, ethis, arguments); - - if (m.count == 1) // exactly one match - { - return m.lastf; - } - else - { - OutBuffer buf; - - if (arguments) - { - HdrGenState hgs; - - argExpTypesToCBuffer(&buf, arguments, &hgs); - } - - if (m.last == MATCHnomatch) - { - if (flags & 1) // if do not print error messages - return NULL; // no match - - tf = (TypeFunction *)type; - - //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); - error(loc, "%s does not match parameter types (%s)", - Argument::argsTypesToChars(tf->parameters, tf->varargs), - buf.toChars()); - return m.anyf; // as long as it's not a FuncAliasDeclaration - } - else - { -#if 1 - TypeFunction *t1 = (TypeFunction *)m.lastf->type; - TypeFunction *t2 = (TypeFunction *)m.nextf->type; - - error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", - buf.toChars(), - m.lastf->toPrettyChars(), Argument::argsTypesToChars(t1->parameters, t1->varargs), - m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs)); -#else - error(loc, "overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); -#endif - return m.lastf; - } - } -} - -/************************************* - * Determine partial specialization order of 'this' vs g. - * This is very similar to TemplateDeclaration::leastAsSpecialized(). - * Returns: - * match 'this' is at least as specialized as g - * 0 g is more specialized than 'this' - */ - -MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) -{ -#define LOG_LEASTAS 0 - -#if LOG_LEASTAS - printf("%s.leastAsSpecialized(%s)\n", toChars(), g->toChars()); -#endif - - /* This works by calling g() with f()'s parameters, and - * if that is possible, then f() is at least as specialized - * as g() is. - */ - - TypeFunction *tf = (TypeFunction *)type; - TypeFunction *tg = (TypeFunction *)g->type; - size_t nfparams = Argument::dim(tf->parameters); - size_t ngparams = Argument::dim(tg->parameters); - MATCH match = MATCHexact; - - /* If both functions have a 'this' pointer, and the mods are not - * the same and g's is not const, then this is less specialized. - */ - if (needThis() && g->needThis()) - { - if (tf->mod != tg->mod) - { - if (tg->mod == MODconst) - match = MATCHconst; - else - return MATCHnomatch; - } - } - - /* Create a dummy array of arguments out of the parameters to f() - */ - Expressions args; - args.setDim(nfparams); - for (int u = 0; u < nfparams; u++) - { - Argument *p = Argument::getNth(tf->parameters, u); - Expression *e; - if (p->storageClass & (STCref | STCout)) - { - e = new IdentifierExp(0, p->ident); - e->type = p->type; - } - else - e = p->type->defaultInit(); - args.data[u] = e; - } - - MATCH m = (MATCH) tg->callMatch(NULL, &args); - if (m) - { - /* A variadic parameter list is less specialized than a - * non-variadic one. - */ - if (tf->varargs && !tg->varargs) - goto L1; // less specialized - -#if LOG_LEASTAS - printf(" matches %d, so is least as specialized\n", m); -#endif - return m; - } - L1: -#if LOG_LEASTAS - printf(" doesn't match, so is not as specialized\n"); -#endif - return MATCHnomatch; -} - -/******************************** - * Labels are in a separate scope, one per function. - */ - -LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident) -{ Dsymbol *s; - - if (!labtab) - labtab = new DsymbolTable(); // guess we need one - - s = labtab->lookup(ident); - if (!s) - { - s = new LabelDsymbol(ident); - labtab->insert(s); - } - return (LabelDsymbol *)s; -} - -/**************************************** - * If non-static member function that has a 'this' pointer, - * return the aggregate it is a member of. - * Otherwise, return NULL. - */ - -AggregateDeclaration *FuncDeclaration::isThis() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); - ad = NULL; - if ((storage_class & STCstatic) == 0) - { - ad = isMember2(); - } - //printf("-FuncDeclaration::isThis() %p\n", ad); - return ad; -} - -AggregateDeclaration *FuncDeclaration::isMember2() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isMember2() '%s'\n", toChars()); - ad = NULL; - for (Dsymbol *s = this; s; s = s->parent) - { -//printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind()); - ad = s->isMember(); - if (ad) -{ //printf("test4\n"); - break; -} - if (!s->parent || - (!s->parent->isTemplateInstance())) -{ //printf("test5\n"); - break; -} - } - //printf("-FuncDeclaration::isMember2() %p\n", ad); - return ad; -} - -/***************************************** - * Determine lexical level difference from 'this' to nested function 'fd'. - * Error if this cannot call fd. - * Returns: - * 0 same level - * -1 increase nesting by 1 (fd is nested within 'this') - * >0 decrease nesting by number - */ - -int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) -{ int level; - Dsymbol *s; - Dsymbol *fdparent; - - //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); - fdparent = fd->toParent2(); - if (fdparent == this) - return -1; - s = this; - level = 0; - while (fd != s && fdparent != s->toParent2()) - { - //printf("\ts = '%s'\n", s->toChars()); - FuncDeclaration *thisfd = s->isFuncDeclaration(); - if (thisfd) - { if (!thisfd->isNested() && !thisfd->vthis) - goto Lerr; - } - else - { - ClassDeclaration *thiscd = s->isClassDeclaration(); - if (thiscd) - { if (!thiscd->isNested()) - goto Lerr; - } - else - goto Lerr; - } - - s = s->toParent2(); - assert(s); - level++; - } - return level; - -Lerr: - error(loc, "cannot access frame of function %s", fd->toChars()); - return 1; -} - -void FuncDeclaration::appendExp(Expression *e) -{ Statement *s; - - s = new ExpStatement(0, e); - appendState(s); -} - -void FuncDeclaration::appendState(Statement *s) -{ CompoundStatement *cs; - - if (!fbody) - { Statements *a; - - a = new Statements(); - fbody = new CompoundStatement(0, a); - } - cs = fbody->isCompoundStatement(); - cs->statements->push(s); -} - - -int FuncDeclaration::isMain() -{ - return ident == Id::main && - linkage != LINKc && !isMember() && !isNested(); -} - -int FuncDeclaration::isWinMain() -{ - //printf("FuncDeclaration::isWinMain() %s\n", toChars()); -#if 0 - int x = ident == Id::WinMain && - linkage != LINKc && !isMember(); - printf("%s\n", x ? "yes" : "no"); - return x; -#else - return ident == Id::WinMain && - linkage != LINKc && !isMember(); -#endif -} - -int FuncDeclaration::isDllMain() -{ - return ident == Id::DllMain && - linkage != LINKc && !isMember(); -} - -int FuncDeclaration::isExport() -{ - return protection == PROTexport; -} - -int FuncDeclaration::isImportedSymbol() -{ - //printf("isImportedSymbol()\n"); - //printf("protection = %d\n", protection); - return (protection == PROTexport) && !fbody; -} - -// Determine if function goes into virtual function pointer table - -int FuncDeclaration::isVirtual() -{ -#if 0 - printf("FuncDeclaration::isVirtual(%s)\n", toChars()); - printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration()); -#endif - return isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration(); -} - -int FuncDeclaration::isFinal() -{ - ClassDeclaration *cd; -#if 0 - printf("FuncDeclaration::isFinal(%s)\n", toChars()); - printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - (cd = toParent()->isClassDeclaration()) != NULL && - cd->storage_class & STCfinal); -#endif - return isMember() && - (Declaration::isFinal() || - ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); -} - -int FuncDeclaration::isAbstract() -{ - return storage_class & STCabstract; -} - -int FuncDeclaration::isCodeseg() -{ - return TRUE; // functions are always in the code segment -} - -int FuncDeclaration::isOverloadable() -{ - return 1; // functions can be overloaded -} - -// Determine if function needs -// a static frame pointer to its lexically enclosing function - -int FuncDeclaration::isNested() -{ - //if (!toParent()) - //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); - //printf("\ttoParent2() = '%s'\n", toParent2()->toChars()); - return ((storage_class & STCstatic) == 0) && - (toParent2()->isFuncDeclaration() != NULL); -} - -int FuncDeclaration::needThis() -{ - //printf("FuncDeclaration::needThis() '%s'\n", toChars()); - int i = isThis() != NULL; - //printf("\t%d\n", i); - if (!i && isFuncAliasDeclaration()) - i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); - return i; -} - -int FuncDeclaration::addPreInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked && - ident != Id::cpctor); -} - -int FuncDeclaration::addPostInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - ad->inv && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked && - ident != Id::cpctor); -} - -/********************************** - * Generate a FuncDeclaration for a runtime library function. - */ - -// -// LDC: Adjusted to give argument info to the runtime function decl. -// - -FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, const char *name) -{ - return genCfunc(args, treturn, Lexer::idPool(name)); -} - -FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, Identifier *id) -{ - FuncDeclaration *fd; - TypeFunction *tf; - Dsymbol *s; - static DsymbolTable *st = NULL; - - //printf("genCfunc(name = '%s')\n", id->toChars()); - //printf("treturn\n\t"); treturn->print(); - - // See if already in table - if (!st) - st = new DsymbolTable(); - s = st->lookup(id); - if (s) - { - fd = s->isFuncDeclaration(); - assert(fd); - assert(fd->type->nextOf()->equals(treturn)); - } - else - { - tf = new TypeFunction(args, treturn, 0, LINKc); - fd = new FuncDeclaration(0, 0, id, STCstatic, tf); - fd->protection = PROTpublic; - fd->linkage = LINKc; - - st->insert(fd); - } - return fd; -} - -const char *FuncDeclaration::kind() -{ - return "function"; -} - -/******************************* - * Look at all the variables in this function that are referenced - * by nested functions, and determine if a closure needs to be - * created for them. - */ - -#if DMDV2 -int FuncDeclaration::needsClosure() -{ - /* Need a closure for all the closureVars[] if any of the - * closureVars[] are accessed by a - * function that escapes the scope of this function. - * We take the conservative approach and decide that any function that: - * 1) is a virtual function - * 2) has its address taken - * 3) has a parent that escapes - * - * Note that since a non-virtual function can be called by - * a virtual one, if that non-virtual function accesses a closure - * var, the closure still has to be taken. Hence, we check for isThis() - * instead of isVirtual(). (thanks to David Friedman) - */ - - //printf("FuncDeclaration::needsClosure() %s\n", toChars()); - for (int i = 0; i < closureVars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)closureVars.data[i]; - assert(v->isVarDeclaration()); - //printf("\tv = %s\n", v->toChars()); - - for (int j = 0; j < v->nestedrefs.dim; j++) - { FuncDeclaration *f = (FuncDeclaration *)v->nestedrefs.data[j]; - assert(f != this); - - //printf("\t\tf = %s, %d, %d\n", f->toChars(), f->isVirtual(), f->tookAddressOf); - if (f->isThis() || f->tookAddressOf) - goto Lyes; // assume f escapes this function's scope - - // Look to see if any parents of f that are below this escape - for (Dsymbol *s = f->parent; s && s != this; s = s->parent) - { - f = s->isFuncDeclaration(); - if (f && (f->isThis() || f->tookAddressOf)) - goto Lyes; - } - } - } - return 0; - -Lyes: - //printf("\tneeds closure\n"); - return 1; -} -#endif - -/****************************** FuncAliasDeclaration ************************/ - -// Used as a way to import a set of functions from another scope into this one. - -FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) - : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, - (enum STC)funcalias->storage_class, funcalias->type) -{ - assert(funcalias != this); - this->funcalias = funcalias; -} - -const char *FuncAliasDeclaration::kind() -{ - return "function alias"; -} - - -/****************************** FuncLiteralDeclaration ************************/ - -FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, - enum TOK tok, ForeachStatement *fes) - : FuncDeclaration(loc, endloc, NULL, STCundefined, type) -{ - const char *id; - - if (fes) - id = "__foreachbody"; - else if (tok == TOKdelegate) - id = "__dgliteral"; - else - id = "__funcliteral"; - this->ident = Identifier::generateId(id); - this->tok = tok; - this->fes = fes; - //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); -} - -Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncLiteralDeclaration *f; - - //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncLiteralDeclaration *)s; - else - f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); - FuncDeclaration::syntaxCopy(f); - return f; -} - -int FuncLiteralDeclaration::isNested() -{ - //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); - return (tok == TOKdelegate); -} - -int FuncLiteralDeclaration::isVirtual() -{ - return FALSE; -} - -const char *FuncLiteralDeclaration::kind() -{ - // GCC requires the (char*) casts - return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; -} - -void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - static Identifier *idfunc; - static Identifier *iddel; - - if (!idfunc) - idfunc = new Identifier("function", 0); - if (!iddel) - iddel = new Identifier("delegate", 0); - - type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* CtorDeclaration ****************************/ - -CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; - //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); -} - -Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) -{ - CtorDeclaration *f; - - f = new CtorDeclaration(loc, endloc, NULL, varargs); - - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - f->arguments = Argument::arraySyntaxCopy(arguments); - return f; -} - - -void CtorDeclaration::semantic(Scope *sc) -{ - AggregateDeclaration *ad; - Type *tret; - - //printf("CtorDeclaration::semantic()\n"); - if (type) - return; - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static constructor - - parent = sc->parent; - Dsymbol *parent = toParent(); - ad = parent->isAggregateDeclaration(); - if (!ad || parent->isUnionDeclaration()) - { - error("constructors are only for class or struct definitions"); - fatal(); - tret = Type::tvoid; - } - else - { tret = ad->handle; - assert(tret); - } - type = new TypeFunction(arguments, tret, varargs, LINKd); -#if STRUCTTHISREF - if (ad && ad->isStructDeclaration()) - ((TypeFunction *)type)->isref = 1; -#endif - if (!originalType) - originalType = type; - - sc->flags |= SCOPEctor; - type = type->semantic(loc, sc); - sc->flags &= ~SCOPEctor; - - // Append: - // return this; - // to the function body - if (fbody) - { - Expression *e = new ThisExp(0); - Statement *s = new ReturnStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - } - - FuncDeclaration::semantic(sc); - - sc->pop(); - - // See if it's the default constructor - if (ad && varargs == 0 && Argument::dim(arguments) == 0) - { if (ad->isStructDeclaration()) - error("default constructor not allowed for structs"); - else - ad->defaultCtor = this; - } -} - -const char *CtorDeclaration::kind() -{ - return "constructor"; -} - -char *CtorDeclaration::toChars() -{ - return (char *)"this"; -} - -int CtorDeclaration::isVirtual() -{ - return FALSE; -} - -int CtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int CtorDeclaration::addPostInvariant() -{ - return (vthis && global.params.useInvariants); -} - - -void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); - Argument::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - -/********************************* PostBlitDeclaration ****************************/ - -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::_postblit, STCundefined, NULL) -{ -} - -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void PostBlitDeclaration::semantic(Scope *sc) -{ - //printf("PostBlitDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - parent = sc->parent; - Dsymbol *parent = toParent(); - StructDeclaration *ad = parent->isStructDeclaration(); - if (!ad) - { - error("post blits are only for struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - } - else if (ident == Id::_postblit) - ad->postblits.push(this); - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not static - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int PostBlitDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload postblits -} - -int PostBlitDeclaration::addPreInvariant() -{ - return FALSE; -} - -int PostBlitDeclaration::addPostInvariant() -{ - return (vthis && global.params.useInvariants); -} - -int PostBlitDeclaration::isVirtual() -{ - return FALSE; -} - -void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("=this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* DtorDeclaration ****************************/ - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) -{ -} - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void DtorDeclaration::semantic(Scope *sc) -{ - //printf("DtorDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - parent = sc->parent; - Dsymbol *parent = toParent(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("destructors are only for class/struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - fatal(); - } - else if (ident == Id::dtor) - ad->dtors.push(this); - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static destructor - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int DtorDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload destructors -} - -int DtorDeclaration::addPreInvariant() -{ - return (vthis && global.params.useInvariants); -} - -int DtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -int DtorDeclaration::isVirtual() -{ - /* This should be FALSE so that dtor's don't get put into the vtbl[], - * but doing so will require recompiling everything. - */ -#if BREAKABI - return FALSE; -#else - return FuncDeclaration::isVirtual(); -#endif -} - -void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticCtorDeclaration ****************************/ - -StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticCtor"), STCstatic, NULL) -{ -} - -Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticCtorDeclaration *scd; - - assert(!s); - scd = new StaticCtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(scd); -} - - -void StaticCtorDeclaration::semantic(Scope *sc) -{ - //printf("StaticCtorDeclaration::semantic()\n"); - - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance()) - { - /* Add this prefix to the function: - * static int gate; - * if (++gate != 1) return; - * Note that this is not thread safe; should not have threads - * during static construction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = STCstatic; - Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp(1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticCtorDeclaration::isThis() -{ - return NULL; -} - -int StaticCtorDeclaration::isStaticConstructor() -{ - return TRUE; -} - -int StaticCtorDeclaration::isVirtual() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - { buf->writestring("static this();\n"); - return; - } - buf->writestring("static this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticDtorDeclaration ****************************/ - -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticDtor"), STCstatic, NULL) -{ - vgate = NULL; -} - -Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticDtorDeclaration *sdd; - - assert(!s); - sdd = new StaticDtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(sdd); -} - - -void StaticDtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - cd = sc->scopesym->isClassDeclaration(); - if (!cd) - { - } - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance()) - { - /* Add this prefix to the function: - * static int gate; - * if (--gate != 0) return; - * Increment gate during constructor execution. - * Note that this is not thread safe; should not have threads - * during static destruction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = STCstatic; - Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(0)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - vgate = v; - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticDtorDeclaration::isThis() -{ - return NULL; -} - -int StaticDtorDeclaration::isStaticDestructor() -{ - return TRUE; -} - -int StaticDtorDeclaration::isVirtual() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("static ~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* InvariantDeclaration ****************************/ - -InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) -{ -} - -Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) -{ - InvariantDeclaration *id; - - assert(!s); - id = new InvariantDeclaration(loc, endloc); - FuncDeclaration::syntaxCopy(id); - return id; -} - - -void InvariantDeclaration::semantic(Scope *sc) -{ - AggregateDeclaration *ad; - Type *tret; - - parent = sc->parent; - Dsymbol *parent = toParent(); - ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("invariants only are for struct/union/class definitions"); - return; - } - else if (ad->inv && ad->inv != this) - { - error("more than one invariant for %s", ad->toChars()); - } - ad->inv = this; - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static invariant - sc->incontract++; - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int InvariantDeclaration::isVirtual() -{ - return FALSE; -} - -int InvariantDeclaration::addPreInvariant() -{ - return FALSE; -} - -int InvariantDeclaration::addPostInvariant() -{ - return FALSE; -} - -void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("invariant"); - bodyToCBuffer(buf, hgs); -} - - -/********************************* UnitTestDeclaration ****************************/ - -/******************************* - * Generate unique unittest function Id so we can have multiple - * instances per module. - */ - -static Identifier *unitTestId() -{ - return Lexer::uniqueId("__unittest"); -} - -UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) -{ -} - -Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) -{ - UnitTestDeclaration *utd; - - assert(!s); - utd = new UnitTestDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(utd); -} - - -void UnitTestDeclaration::semantic(Scope *sc) -{ - if (global.params.useUnitTests) - { - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - Scope *sc2 = sc->push(); - sc2->linkage = LINKd; - FuncDeclaration::semantic(sc2); - sc2->pop(); - } - - // We're going to need ModuleInfo even if the unit tests are not - // compiled in, because other modules may import this module and refer - // to this ModuleInfo. - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - m->needmoduleinfo = 1; -} - -AggregateDeclaration *UnitTestDeclaration::isThis() -{ - return NULL; -} - -int UnitTestDeclaration::isVirtual() -{ - return FALSE; -} - -int UnitTestDeclaration::addPreInvariant() -{ - return FALSE; -} - -int UnitTestDeclaration::addPostInvariant() -{ - return FALSE; -} - -void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("unittest"); - bodyToCBuffer(buf, hgs); -} - -/********************************* NewDeclaration ****************************/ - -NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; -} - -Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) -{ - NewDeclaration *f; - - f = new NewDeclaration(loc, endloc, NULL, varargs); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Argument::arraySyntaxCopy(arguments); - - return f; -} - - -void NewDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - //printf("NewDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - tret = Type::tvoid->pointerTo(); - type = new TypeFunction(arguments, tret, varargs, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is at least one argument of type uint - TypeFunction *tf = (TypeFunction *)type; - if (Argument::dim(tf->parameters) < 1) - { - error("at least one argument of type size_t expected"); - } - else - { - Argument *a = Argument::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tsize_t)) - error("first argument must be type size_t, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *NewDeclaration::kind() -{ - return "allocator"; -} - -int NewDeclaration::isVirtual() -{ - return FALSE; -} - -int NewDeclaration::addPreInvariant() -{ - return FALSE; -} - -int NewDeclaration::addPostInvariant() -{ - return FALSE; -} - -void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("new"); - Argument::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* DeleteDeclaration ****************************/ - -DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments) - : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) -{ - this->arguments = arguments; -} - -Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) -{ - DeleteDeclaration *f; - - f = new DeleteDeclaration(loc, endloc, NULL); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Argument::arraySyntaxCopy(arguments); - - return f; -} - - -void DeleteDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - - //printf("DeleteDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is only one argument of type void* - TypeFunction *tf = (TypeFunction *)type; - if (Argument::dim(tf->parameters) != 1) - { - error("one argument of type void* expected"); - } - else - { - Argument *a = Argument::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tvoid->pointerTo())) - error("one argument of type void* expected, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *DeleteDeclaration::kind() -{ - return "deallocator"; -} - -int DeleteDeclaration::isDelete() -{ - return TRUE; -} - -int DeleteDeclaration::isVirtual() -{ - return FALSE; -} - -int DeleteDeclaration::addPreInvariant() -{ - return FALSE; -} - -int DeleteDeclaration::addPostInvariant() -{ - return FALSE; -} - -void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete"); - Argument::argsToCBuffer(buf, hgs, arguments, 0); - bodyToCBuffer(buf, hgs); -} - - - - +// 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. + +#include +#include + +#include "mars.h" +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "expression.h" +#include "scope.h" +#include "mtype.h" +#include "aggregate.h" +#include "identifier.h" +#include "id.h" +#include "module.h" +#include "statement.h" +#include "template.h" +#include "hdrgen.h" + +#ifdef IN_GCC +#include "d-dmd-gcc.h" +#endif + +/********************************* FuncDeclaration ****************************/ + +FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) + : Declaration(id) +{ + //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); + //printf("storage_class = x%x\n", storage_class); + this->storage_class = storage_class; + this->type = type; + this->loc = loc; + this->endloc = endloc; + fthrows = NULL; + frequire = NULL; + outId = NULL; + vresult = NULL; + returnLabel = NULL; + fensure = NULL; + fbody = NULL; + localsymtab = NULL; + vthis = NULL; + v_arguments = NULL; +#if IN_GCC + v_argptr = NULL; +#endif + parameters = NULL; + labtab = NULL; + overnext = NULL; + vtblIndex = -1; + hasReturnExp = 0; + naked = 0; + inlineStatus = ILSuninitialized; + inlineNest = 0; + inlineAsm = 0; + cantInterpret = 0; + semanticRun = 0; + fes = NULL; + introducing = 0; + tintro = NULL; + /* The type given for "infer the return type" is a TypeFunction with + * NULL for the return type. + */ + inferRetType = (type && type->nextOf() == NULL); + scope = NULL; + hasReturnExp = 0; + nrvo_can = 1; + nrvo_var = NULL; +#if IN_DMD + shidden = NULL; +#endif + + builtin = BUILTINunknown; + tookAddressOf = 0; + +#if IN_LLVM + // LDC + isArrayOp = false; + allowInlining = false; + + // function types in ldc don't merge if the context parameter differs + // so we actually don't care about the function declaration, but only + // what kind of context parameter it has. + // however, this constructor is usually called from the parser, which + // unfortunately doesn't provide the information needed to get to the + // aggregate type. So we have to stick with the FuncDeclaration and + // just be sure we don't actually rely on the symbol it points to, + // but rather just the type of its context parameter. + // this means some function might have a function type pointing to + // another function declaration + + if (type) + { + assert(type->ty == Tfunction && "invalid function type"); + TypeFunction* tf = (TypeFunction*)type; + if (tf->funcdecl == NULL) + tf->funcdecl = this; + } +#endif +} + +Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) +{ + FuncDeclaration *f; + + //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + f = (FuncDeclaration *)s; + else + f = new FuncDeclaration(loc, endloc, ident, (enum STC) storage_class, type->syntaxCopy()); + f->outId = outId; + f->frequire = frequire ? frequire->syntaxCopy() : NULL; + f->fensure = fensure ? fensure->syntaxCopy() : NULL; + f->fbody = fbody ? fbody->syntaxCopy() : NULL; + assert(!fthrows); // deprecated + + // LDC + f->intrinsicName = intrinsicName; + + return f; +} + + +// Do the semantic analysis on the external interface to the function. + +void FuncDeclaration::semantic(Scope *sc) +{ TypeFunction *f; + StructDeclaration *sd; + ClassDeclaration *cd; + InterfaceDeclaration *id; + Dsymbol *pd; + +#if 0 + printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); + if (isFuncLiteralDeclaration()) + printf("\tFuncLiteralDeclaration()\n"); + printf("sc->parent = %s, parent = %s\n", sc->parent->toChars(), parent ? parent->toChars() : ""); + printf("type: %p, %s\n", type, type->toChars()); +#endif + + if (semanticRun && isFuncLiteralDeclaration()) + { + /* Member functions that have return types that are + * forward references can have semantic() run more than + * once on them. + * See test\interface2.d, test20 + */ + return; + } + assert(semanticRun <= 1); + semanticRun = 1; + + storage_class |= sc->stc & ~STCref; + //printf("function storage_class = x%x\n", storage_class); + + if (!originalType) + originalType = type; + if (!type->deco && type->nextOf()) + { + /* Apply const and invariant storage class + * to the function type + */ + type = type->semantic(loc, sc); + unsigned stc = storage_class; + if (type->isInvariant()) + stc |= STCimmutable; + if (type->isConst()) + stc |= STCconst; + if (type->isShared()) + stc |= STCshared; + switch (stc & STC_TYPECTOR) + { + case STCimmutable: + case STCimmutable | STCconst: + case STCimmutable | STCconst | STCshared: + case STCimmutable | STCshared: + // Don't use toInvariant(), as that will do a merge() + type = type->makeInvariant(); + type->deco = type->merge()->deco; + break; + + case STCconst: + type = type->makeConst(); + type->deco = type->merge()->deco; + break; + + case STCshared | STCconst: + type = type->makeSharedConst(); + type->deco = type->merge()->deco; + break; + + case STCshared: + type = type->makeShared(); + type->deco = type->merge()->deco; + break; + + case 0: + break; + + default: + assert(0); + } + } + //type->print(); + if (type->ty != Tfunction) + { + error("%s must be a function", toChars()); + return; + } + f = (TypeFunction *)(type); + + size_t nparams = Argument::dim(f->parameters); + + linkage = sc->linkage; +// if (!parent) + { + //parent = sc->scopesym; + parent = sc->parent; + } + protection = sc->protection; + Dsymbol *parent = toParent(); + + if (storage_class & STCscope) + error("functions cannot be scope"); + + if (isAbstract() && !isVirtual()) + error("non-virtual functions cannot be abstract"); + + if ((f->isConst() || f->isInvariant()) && !isThis()) + error("without 'this' cannot be const/immutable"); + + if (isAbstract() && isFinal()) + error("cannot be both final and abstract"); +#if 0 + if (isAbstract() && fbody) + error("abstract functions cannot have bodies"); +#endif + +#if 0 + if (isStaticConstructor() || isStaticDestructor()) + { + if (!isStatic() || type->nextOf()->ty != Tvoid) + error("static constructors / destructors must be static void"); + if (f->arguments && f->arguments->dim) + error("static constructors / destructors must have empty parameter list"); + // BUG: check for invalid storage classes + } +#endif + +#ifdef IN_GCC + AggregateDeclaration *ad; + + ad = parent->isAggregateDeclaration(); + if (ad) + ad->methods.push(this); +#endif + sd = parent->isStructDeclaration(); + if (sd) + { + if (isCtorDeclaration()) + { + return; + } +#if 0 + // Verify no constructors, destructors, etc. + if (isCtorDeclaration() + //||isDtorDeclaration() + //|| isInvariantDeclaration() + //|| isUnitTestDeclaration() + ) + { + error("special member functions not allowed for %ss", sd->kind()); + } + + if (!sd->inv) + sd->inv = isInvariantDeclaration(); + + if (!sd->aggNew) + sd->aggNew = isNewDeclaration(); + + if (isDelete()) + { + if (sd->aggDelete) + error("multiple delete's for struct %s", sd->toChars()); + sd->aggDelete = (DeleteDeclaration *)(this); + } +#endif + } + + id = parent->isInterfaceDeclaration(); + if (id) + { + storage_class |= STCabstract; + + if (isCtorDeclaration() || + isPostBlitDeclaration() || + isDtorDeclaration() || + isInvariantDeclaration() || + isUnitTestDeclaration() || isNewDeclaration() || isDelete()) + error("special function not allowed in interface %s", id->toChars()); + if (fbody) + error("function body is not abstract in interface %s", id->toChars()); + } + + /* Template member functions aren't virtual: + * interface TestInterface { void tpl(T)(); } + * and so won't work in interfaces + */ + if ((pd = toParent()) != NULL && + pd->isTemplateInstance() && + (pd = toParent2()) != NULL && + (id = pd->isInterfaceDeclaration()) != NULL) + { + error("template member function not allowed in interface %s", id->toChars()); + } + + cd = parent->isClassDeclaration(); + if (cd) + { int vi; + CtorDeclaration *ctor; + DtorDeclaration *dtor; + InvariantDeclaration *inv; + + if (isCtorDeclaration()) + { +// ctor = (CtorDeclaration *)this; +// if (!cd->ctor) +// cd->ctor = ctor; + return; + } + +#if 0 + dtor = isDtorDeclaration(); + if (dtor) + { + if (cd->dtor) + error("multiple destructors for class %s", cd->toChars()); + cd->dtor = dtor; + } + + inv = isInvariantDeclaration(); + if (inv) + { + cd->inv = inv; + } + + if (isNewDeclaration()) + { + if (!cd->aggNew) + cd->aggNew = (NewDeclaration *)(this); + } + + if (isDelete()) + { + if (cd->aggDelete) + error("multiple delete's for class %s", cd->toChars()); + cd->aggDelete = (DeleteDeclaration *)(this); + } +#endif + + if (storage_class & STCabstract) + cd->isabstract = 1; + + // if static function, do not put in vtbl[] + if (!isVirtual()) + { + //printf("\tnot virtual\n"); + goto Ldone; + } + + // Find index of existing function in vtbl[] to override + vi = findVtblIndex(&cd->vtbl, cd->baseClass ? cd->baseClass->vtbl.dim : 0); + switch (vi) + { + case -1: + /* Didn't find one, so + * This is an 'introducing' function which gets a new + * slot in the vtbl[]. + */ + + // Verify this doesn't override previous final function + if (cd->baseClass) + { Dsymbol *s = cd->baseClass->search(loc, ident, 0); + if (s) + { + FuncDeclaration *f = s->isFuncDeclaration(); + f = f->overloadExactMatch(type, getModule()); + if (f && f->isFinal() && f->prot() != PROTprivate) + error("cannot override final function %s", f->toPrettyChars()); + } + } + + if (isFinal()) + { + if (isOverride()) + error("does not override any function"); + cd->vtblFinal.push(this); + } + else + { + // Append to end of vtbl[] + //printf("\tintroducing function\n"); + introducing = 1; + vi = cd->vtbl.dim; + cd->vtbl.push(this); + vtblIndex = vi; + } + break; + + case -2: // can't determine because of fwd refs + cd->sizeok = 2; // can't finish due to forward reference + return; + + default: + { FuncDeclaration *fdv = (FuncDeclaration *)cd->vtbl.data[vi]; + // This function is covariant with fdv + if (fdv->isFinal()) + error("cannot override final function %s", fdv->toPrettyChars()); + +#if DMDV2 + if (!isOverride()) + warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); +#endif + + if (fdv->toParent() == parent) + { + // If both are mixins, then error. + // If either is not, the one that is not overrides + // the other. + if (fdv->parent->isClassDeclaration()) + break; + if (!this->parent->isClassDeclaration() +#if !BREAKABI + && !isDtorDeclaration() +#endif +#if DMDV2 + && !isPostBlitDeclaration() +#endif + ) + error("multiple overrides of same function"); + } + cd->vtbl.data[vi] = (void *)this; + vtblIndex = vi; + + /* This works by whenever this function is called, + * it actually returns tintro, which gets dynamically + * cast to type. But we know that tintro is a base + * of type, so we could optimize it by not doing a + * dynamic cast, but just subtracting the isBaseOf() + * offset if the value is != null. + */ + + if (fdv->tintro) + tintro = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) + { + tintro = fdv->type; + } + } + break; + } + } + + /* Go through all the interface bases. + * If this function is covariant with any members of those interface + * functions, set the tintro. + */ + for (int i = 0; i < cd->interfaces_dim; i++) + { + BaseClass *b = cd->interfaces[i]; + vi = findVtblIndex(&b->base->vtbl, b->base->vtbl.dim); + switch (vi) + { + case -1: + break; + + case -2: + cd->sizeok = 2; // can't finish due to forward reference + return; + + default: + { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; + Type *ti = NULL; + + if (fdv->tintro) + ti = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) + { + ti = fdv->type; +#if 0 + if (offset) + ti = fdv->type; + else if (type->nextOf()->ty == Tclass) + { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; + if (cdn && cdn->sizeok != 1) + ti = fdv->type; + } +#endif + } + } + if (ti) + { + if (tintro && !tintro->equals(ti)) + { + error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); + } + tintro = ti; + } + goto L2; + } + } + } + + if (introducing && isOverride()) + { + error("does not override any function"); + } + + L2: ; + } + else if (isOverride() && !parent->isTemplateInstance()) + error("override only applies to class member functions"); + + /* Do not allow template instances to add virtual functions + * to a class. + */ + if (isVirtual()) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + ClassDeclaration *cd = ti->tempdecl->isClassMember(); + if (cd) + { + error("cannot use template to add virtual function to class '%s'", cd->toChars()); + } + } + } + + if (isMain()) + { + // Check parameters to see if they are either () or (char[][] args) + switch (nparams) + { + case 0: + break; + + case 1: + { + Argument *arg0 = Argument::getNth(f->parameters, 0); + if (arg0->type->ty != Tarray || + arg0->type->nextOf()->ty != Tarray || + arg0->type->nextOf()->nextOf()->ty != Tchar || + arg0->storageClass & (STCout | STCref | STClazy)) + goto Lmainerr; + break; + } + + default: + goto Lmainerr; + } + + if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) + error("must return int or void, not %s", f->nextOf()->toChars()); + if (f->varargs) + { + Lmainerr: + error("parameters must be main() or main(char[][] args)"); + } + } + + if (ident == Id::assign && (sd || cd)) + { // Disallow identity assignment operator. + + // opAssign(...) + if (nparams == 0) + { if (f->varargs == 1) + goto Lassignerr; + } + else + { + Argument *arg0 = Argument::getNth(f->parameters, 0); + Type *t0 = arg0->type->toBasetype(); + Type *tb = sd ? sd->type : cd->type; + if (arg0->type->implicitConvTo(tb) || + (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) + ) + { + if (nparams == 1) + goto Lassignerr; + Argument *arg1 = Argument::getNth(f->parameters, 1); + if (arg1->defaultArg) + goto Lassignerr; + } + } + } + +Ldone: + /* Save scope for possible later use (if we need the + * function internals) + */ + scope = new Scope(*sc); + scope->setNoFree(); + return; + +Lassignerr: + if (sd) + { + sd->hasIdentityAssign = 1; // don't need to generate it + goto Ldone; + } + error("identity assignment operator overload is illegal"); +} + +void FuncDeclaration::semantic2(Scope *sc) +{ +} + +// Do the semantic analysis on the internals of the function. + +void FuncDeclaration::semantic3(Scope *sc) +{ TypeFunction *f; + VarDeclaration *argptr = NULL; + VarDeclaration *_arguments = NULL; + + if (!parent) + { + if (global.errors) + return; + //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); + assert(0); + } + //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); + //fflush(stdout); + //printf("storage class = x%x %x\n", sc->stc, storage_class); + //{ static int x; if (++x == 2) *(char*)0=0; } + //printf("\tlinkage = %d\n", sc->linkage); + + //printf(" sc->incontract = %d\n", sc->incontract); + if (semanticRun >= 3) + return; + semanticRun = 3; + + if (!type || type->ty != Tfunction) + return; + f = (TypeFunction *)(type); + size_t nparams = Argument::dim(f->parameters); + + // Check the 'throws' clause + if (fthrows) + { + for (int i = 0; i < fthrows->dim; i++) + { + Type *t = (Type *)fthrows->data[i]; + + t = t->semantic(loc, sc); + if (!t->isClassHandle()) + error("can only throw classes, not %s", t->toChars()); + } + } + + if (fbody || frequire) + { + /* Symbol table into which we place parameters and nested functions, + * solely to diagnose name collisions. + */ + localsymtab = new DsymbolTable(); + + // Establish function scope + ScopeDsymbol *ss = new ScopeDsymbol(); + ss->parent = sc->scopesym; + Scope *sc2 = sc->push(ss); + sc2->func = this; + sc2->parent = this; + sc2->callSuper = 0; + sc2->sbreak = NULL; + sc2->scontinue = NULL; + sc2->sw = NULL; + sc2->fes = fes; + sc2->linkage = LINKd; + sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref); + sc2->protection = PROTpublic; + sc2->explicitProtection = 0; + sc2->structalign = 8; + sc2->incontract = 0; +#if !IN_LLVM + sc2->tf = NULL; +#else + sc2->enclosingFinally = NULL; + sc2->enclosingScopeExit = NULL; +#endif + sc2->noctor = 0; + + // Declare 'this' + AggregateDeclaration *ad = isThis(); + if (ad) + { VarDeclaration *v; + + if (isFuncLiteralDeclaration() && isNested()) + { + error("literals cannot be class members"); + return; + } + else + { + assert(!isNested()); // can't be both member and nested + assert(ad->handle); + Type *thandle = ad->handle; +#if STRUCTTHISREF + thandle = thandle->addMod(type->mod); + thandle = thandle->addStorageClass(storage_class); + if (isPure()) + thandle = thandle->addMod(MODconst); +#else + if (storage_class & STCconst || type->isConst()) + { + assert(0); // BUG: shared not handled + if (thandle->ty == Tclass) + thandle = thandle->constOf(); + else + { assert(thandle->ty == Tpointer); + thandle = thandle->nextOf()->constOf()->pointerTo(); + } + } + else if (storage_class & STCimmutable || type->isInvariant()) + { + if (thandle->ty == Tclass) + thandle = thandle->invariantOf(); + else + { assert(thandle->ty == Tpointer); + thandle = thandle->nextOf()->invariantOf()->pointerTo(); + } + } + else if (storage_class & STCshared || type->isShared()) + { + assert(0); // not implemented + } +#endif + v = new ThisDeclaration(loc, thandle); + v->storage_class |= STCparameter; +#if STRUCTTHISREF + if (thandle->ty == Tstruct) + v->storage_class |= STCref; +#endif + v->semantic(sc2); + if (!sc2->insert(v)) + assert(0); + v->parent = this; + vthis = v; + } + } + else if (isNested()) + { + /* The 'this' for a nested function is the link to the + * enclosing function's stack frame. + * Note that nested functions and member functions are disjoint. + */ + VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo()); + v->storage_class |= STCparameter; + v->semantic(sc2); + if (!sc2->insert(v)) + assert(0); + v->parent = this; + vthis = v; + } + + // Declare hidden variable _arguments[] and _argptr + if (f->varargs == 1) + { +#if TARGET_NET + varArgs(sc2, f, argptr, _arguments); +#else + Type *t; + + if (f->linkage == LINKd) + { // Declare _arguments[] +#if BREAKABI + v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); + v_arguments->storage_class = STCparameter; + v_arguments->semantic(sc2); + sc2->insert(v_arguments); + v_arguments->parent = this; + + //t = Type::typeinfo->type->constOf()->arrayOf(); + t = Type::typeinfo->type->arrayOf(); + _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); + _arguments->semantic(sc2); + sc2->insert(_arguments); + _arguments->parent = this; +#else + t = Type::typeinfo->type->arrayOf(); + v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); + v_arguments->storage_class = STCparameter | STCin; + v_arguments->semantic(sc2); + sc2->insert(v_arguments); + v_arguments->parent = this; +#endif + } + if (f->linkage == LINKd || (parameters && parameters->dim)) + { // Declare _argptr +#if IN_GCC + t = d_gcc_builtin_va_list_d_type; +#else + t = Type::tvoid->pointerTo(); +#endif + argptr = new VarDeclaration(0, t, Id::_argptr, NULL); + argptr->semantic(sc2); + sc2->insert(argptr); + argptr->parent = this; + } +#endif + } + +#if IN_LLVM + // LDC make sure argument type is semanticed. + // Turns TypeTuple!(int, int) into two int parameters, for instance. + if (f->parameters) + { + for (size_t i = 0; i < Argument::dim(f->parameters); i++) + { Argument *arg = (Argument *)Argument::getNth(f->parameters, i); + Type* nw = arg->type->semantic(0, sc); + if (arg->type != nw) { + arg->type = nw; + // Examine this index again. + // This is important if it turned into a tuple. + // In particular, the empty tuple should be handled or the + // next parameter will be skipped. + // FIXME: Maybe we only need to do this for tuples, + // and can add tuple.length after decrement? + i--; + } + } + // update nparams to include expanded tuples + nparams = Argument::dim(f->parameters); + } +#endif + + // Propagate storage class from tuple parameters to their element-parameters. + if (f->parameters) + { + for (size_t i = 0; i < f->parameters->dim; i++) + { Argument *arg = (Argument *)f->parameters->data[i]; + + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + size_t dim = Argument::dim(t->arguments); + for (size_t j = 0; j < dim; j++) + { Argument *narg = Argument::getNth(t->arguments, j); + narg->storageClass = arg->storageClass; + } + } + } + } + + /* Declare all the function parameters as variables + * and install them in parameters[] + */ + size_t nparams = Argument::dim(f->parameters); + if (nparams) + { /* parameters[] has all the tuples removed, as the back end + * doesn't know about tuples + */ + parameters = new Dsymbols(); + parameters->reserve(nparams); + for (size_t i = 0; i < nparams; i++) + { + Argument *arg = Argument::getNth(f->parameters, i); + Identifier *id = arg->ident; + if (!id) + { + /* Generate identifier for un-named parameter, + * because we need it later on. + */ + arg->ident = id = Identifier::generateId("_param_", i); + } + Type *vtype = arg->type; + if (isPure()) + vtype = vtype->addMod(MODconst); + VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL); + //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); + v->storage_class |= STCparameter; + if (f->varargs == 2 && i + 1 == nparams) + v->storage_class |= STCvariadic; + v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); + v->semantic(sc2); + if (!sc2->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + else + parameters->push(v); + localsymtab->insert(v); + v->parent = this; + } + } + + // Declare the tuple symbols and put them in the symbol table, + // but not in parameters[]. + if (f->parameters) + { + for (size_t i = 0; i < f->parameters->dim; i++) + { Argument *arg = (Argument *)f->parameters->data[i]; + + if (!arg->ident) + continue; // never used, so ignore + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + size_t dim = Argument::dim(t->arguments); + Objects *exps = new Objects(); + exps->setDim(dim); + for (size_t j = 0; j < dim; j++) + { Argument *narg = Argument::getNth(t->arguments, j); + assert(narg->ident); + VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); + assert(v); + Expression *e = new VarExp(v->loc, v); + exps->data[j] = (void *)e; + } + assert(arg->ident); + TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); + //printf("declaring tuple %s\n", v->toChars()); + v->isexp = 1; + if (!sc2->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + localsymtab->insert(v); + v->parent = this; + } + } + } + + /* Do the semantic analysis on the [in] preconditions and + * [out] postconditions. + */ + sc2->incontract++; + + if (frequire) + { /* frequire is composed of the [in] contracts + */ + // BUG: need to error if accessing out parameters + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + // BUG: verify that all in and ref parameters are read + frequire = frequire->semantic(sc2); + labtab = NULL; // so body can't refer to labels + } + + if (fensure || addPostInvariant()) + { /* fensure is composed of the [out] contracts + */ + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc2->scopesym; + sc2 = sc2->push(sym); + + assert(type->nextOf()); + if (type->nextOf()->ty == Tvoid) + { + if (outId) + error("void functions have no result"); + } + else + { + if (!outId) + outId = Id::result; // provide a default + } + + if (outId) + { // Declare result variable + VarDeclaration *v; + Loc loc = this->loc; + + if (fensure) + loc = fensure->loc; + + v = new VarDeclaration(loc, type->nextOf(), outId, NULL); + v->noauto = 1; + sc2->incontract--; + v->semantic(sc2); + sc2->incontract++; + if (!sc2->insert(v)) + error("out result %s is already defined", v->toChars()); + v->parent = this; + vresult = v; + + // vresult gets initialized with the function return value + // in ReturnStatement::semantic() + } + + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + if (fensure) + { fensure = fensure->semantic(sc2); + labtab = NULL; // so body can't refer to labels + } + + if (!global.params.useOut) + { fensure = NULL; // discard + vresult = NULL; + } + + // Postcondition invariant + if (addPostInvariant()) + { + Expression *e = NULL; + if (isCtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + Expression *v = new ThisExp(0); + v->type = vthis->type; +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif + e = new AssertExp(0, v); + } + if (e) + { + ExpStatement *s = new ExpStatement(0, e); + if (fensure) + fensure = new CompoundStatement(0, s, fensure); + else + fensure = s; + } + } + + if (fensure) + { returnLabel = new LabelDsymbol(Id::returnLabel); + LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); + ls->isReturnLabel = 1; + returnLabel->statement = ls; + } + sc2 = sc2->pop(); + } + + sc2->incontract--; + + if (fbody) + { ClassDeclaration *cd = isClassMember(); + + /* If this is a class constructor + */ + if (isCtorDeclaration() && cd) + { + for (int i = 0; i < cd->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; + + v->ctorinit = 0; + } + } + + if (inferRetType || f->retStyle() != RETstack) + nrvo_can = 0; + + fbody = fbody->semantic(sc2); + + if (inferRetType) + { // If no return type inferred yet, then infer a void + if (!type->nextOf()) + { + ((TypeFunction *)type)->next = Type::tvoid; + type = type->semantic(loc, sc); + } + f = (TypeFunction *)type; + } + + if (isStaticCtorDeclaration()) + { /* It's a static constructor. Ensure that all + * ctor consts were initialized. + */ + + Dsymbol *p = toParent(); + ScopeDsymbol *ad = p->isScopeDsymbol(); + if (!ad) + { + error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); + } + else + { + for (int i = 0; i < ad->members->dim; i++) + { Dsymbol *s = (Dsymbol *)ad->members->data[i]; + + s->checkCtorConstInit(); + } + } + } + + if (isCtorDeclaration() && cd) + { + //printf("callSuper = x%x\n", sc2->callSuper); + + // Verify that all the ctorinit fields got initialized + if (!(sc2->callSuper & CSXthis_ctor)) + { + for (int i = 0; i < cd->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; + + if (v->ctorinit == 0 && v->isCtorinit()) + error("missing initializer for final field %s", v->toChars()); + } + } + + if (!(sc2->callSuper & CSXany_ctor) && + cd->baseClass && cd->baseClass->ctor) + { + sc2->callSuper = 0; + + // Insert implicit super() at start of fbody + Expression *e1 = new SuperExp(0); + Expression *e = new CallExp(0, e1); + + e = e->trySemantic(sc2); + if (!e) + error("no match for implicit super() call in constructor"); + else + { + Statement *s = new ExpStatement(0, e); + fbody = new CompoundStatement(0, s, fbody); + } + } + } + else if (fes) + { // For foreach(){} body, append a return 0; + Expression *e = new IntegerExp(0); + Statement *s = new ReturnStatement(0, e); + fbody = new CompoundStatement(0, fbody, s); + assert(!returnLabel); + } + else if (!hasReturnExp && type->nextOf()->ty != Tvoid) + error("expected to return a value of type %s", type->nextOf()->toChars()); + else if (!inlineAsm) + { + int blockexit = fbody ? fbody->blockExit() : 0; + if (f->isnothrow && blockexit & BEthrow) + error("'%s' is nothrow yet may throw", toChars()); + + int offend = blockexit & BEfallthru; + + if (type->nextOf()->ty == Tvoid) + { + if (offend && isMain()) + { // Add a return 0; statement + Statement *s = new ReturnStatement(0, new IntegerExp(0)); + fbody = new CompoundStatement(0, fbody, s); + } + } + else + { + if (offend) + { Expression *e; + + warning(loc, "no return at end of function"); + + if (global.params.useAssert && + !global.params.useInline) + { /* Add an assert(0, msg); where the missing return + * should be. + */ + e = new AssertExp( + endloc, + new IntegerExp(0), + new StringExp(loc, (char *)"missing return expression") + ); + } + else + e = new HaltExp(endloc); + e = new CommaExp(0, e, type->nextOf()->defaultInit()); + e = e->semantic(sc2); + Statement *s = new ExpStatement(0, e); + fbody = new CompoundStatement(0, fbody, s); + } + } + } + } + + { + Statements *a = new Statements(); + + // Merge in initialization of 'out' parameters + if (parameters) + { for (size_t i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + if (v->storage_class & STCout) + { + assert(v->init); + ExpInitializer *ie = v->init->isExpInitializer(); + assert(ie); + a->push(new ExpStatement(0, ie->exp)); + } + } + } + +// we'll handle variadics ourselves +#if !IN_LLVM + if (argptr) + { // Initialize _argptr to point past non-variadic arg +#if IN_GCC + // Handled in FuncDeclaration::toObjFile + v_argptr = argptr; + v_argptr->init = new VoidInitializer(loc); +#else + Expression *e1; + Expression *e; + Type *t = argptr->type; + VarDeclaration *p; + unsigned offset; + + e1 = new VarExp(0, argptr); + if (parameters && parameters->dim) + p = (VarDeclaration *)parameters->data[parameters->dim - 1]; + else + p = v_arguments; // last parameter is _arguments[] + offset = p->type->size(); + offset = (offset + 3) & ~3; // assume stack aligns on 4 + e = new SymOffExp(0, p, offset); + e = new AssignExp(0, e1, e); + e->type = t; + a->push(new ExpStatement(0, e)); +#endif // IN_GCC + } + + if (_arguments) + { + /* Advance to elements[] member of TypeInfo_Tuple with: + * _arguments = v_arguments.elements; + */ + Expression *e = new VarExp(0, v_arguments); + e = new DotIdExp(0, e, Id::elements); + Expression *e1 = new VarExp(0, _arguments); + e = new AssignExp(0, e1, e); + e->op = TOKconstruct; + e = e->semantic(sc2); + a->push(new ExpStatement(0, e)); + } + +#endif // !IN_LLVM + + // Merge contracts together with body into one compound statement + +#ifdef _DH + if (frequire && global.params.useIn) + { frequire->incontract = 1; + a->push(frequire); + } +#else + if (frequire && global.params.useIn) + a->push(frequire); +#endif + + // Precondition invariant + if (addPreInvariant()) + { + Expression *e = NULL; + Expression *ee = NULL; + if (isDtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + Expression *v = new ThisExp(0); + v->type = vthis->type; +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif +#if IN_LLVM + //e = new AssertExp(loc, v, NULL); + + // LDC: check for null this + //v = new ThisExp(0); + //v->type = vthis->type; + //v->var = vthis; // Error: Expression has no property var... in D1 typeof(v) == ThisExp + + //NullExp *nv = new NullExp(0); + //nv->type = v->type; + + //IdentityExp *ie = new IdentityExp(TOKnotidentity, 0, v, nv); + //ie->type = Type::tbool; +#endif + Expression *se = new StringExp(0, (char *)"null this"); + se = se->semantic(sc); + se->type = Type::tchar->arrayOf(); +//#if IN_LLVM +// ee = new AssertExp(loc, ie, se); +//#else + e = new AssertExp(loc, v, se); +//#endif + } + if (ee) + { + ExpStatement *s = new ExpStatement(0, ee); + a->push(s); + } + if (e) + { + ExpStatement *s = new ExpStatement(0, e); + a->push(s); + } + } + + if (fbody) + a->push(fbody); + + if (fensure) + { + a->push(returnLabel->statement); + + if (type->nextOf()->ty != Tvoid) + { + // Create: return vresult; + assert(vresult); + Expression *e = new VarExp(0, vresult); + if (tintro) + { e = e->implicitCastTo(sc, tintro->nextOf()); + e = e->semantic(sc); + } + ReturnStatement *s = new ReturnStatement(0, e); + a->push(s); + } + } + + fbody = new CompoundStatement(0, a); + +#if IN_LLVM + // wrap body of synchronized functions in a synchronized statement + if (isSynchronized()) + { + ClassDeclaration *cd = parent->isClassDeclaration(); + if (!cd) + error("synchronized function %s must be a member of a class", toChars()); + + Expression *sync; + if (isStatic()) + { + // static member functions synchronize on classinfo + sync = cd->type->dotExp(sc2, new TypeExp(loc, cd->type), Id::classinfo); + } + else + { + // non-static member functions synchronize on this + sync = new VarExp(loc, vthis); + } + + // we do not want to rerun semantics on the whole function, so we + // manually adjust all labels in the function that currently don't + // have an enclosingScopeExit to use the new SynchronizedStatement + SynchronizedStatement* s = new SynchronizedStatement(loc, sync, NULL); + s->semantic(sc2); + s->body = fbody; + + // LDC + LabelMap::iterator it, end = labmap.end(); + for (it = labmap.begin(); it != end; ++it) + if (it->second->enclosingScopeExit == NULL) + it->second->enclosingScopeExit = s; + + a = new Statements; + a->push(s); + fbody = new CompoundStatement(0, a); + } +#endif + + /* Append destructor calls for parameters as finally blocks. + */ + if (parameters) + { for (size_t i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + + if (v->storage_class & (STCref | STCout)) + continue; + + /* Don't do this for static arrays, since static + * arrays are called by reference. Remove this + * when we change them to call by value. + */ + if (v->type->toBasetype()->ty == Tsarray) + continue; + + Expression *e = v->callAutoDtor(sc); + if (e) + { Statement *s = new ExpStatement(0, e); + s = s->semantic(sc); + if (fbody->blockExit() == BEfallthru) + fbody = new CompoundStatement(0, fbody, s); + else + fbody = new TryFinallyStatement(0, fbody, s); + } + } + } + } + + sc2->callSuper = 0; + sc2->pop(); + } + semanticRun = 4; +} + +void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); + + StorageClassDeclaration::stcToCBuffer(buf, storage_class); + type->toCBuffer(buf, ident, hgs); + bodyToCBuffer(buf, hgs); +} + + +void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (fbody && + (!hgs->hdrgen || hgs->tpltMember || canInline(1,1)) + ) + { buf->writenl(); + + // in{} + if (frequire) + { buf->writestring("in"); + buf->writenl(); + frequire->toCBuffer(buf, hgs); + } + + // out{} + if (fensure) + { buf->writestring("out"); + if (outId) + { buf->writebyte('('); + buf->writestring(outId->toChars()); + buf->writebyte(')'); + } + buf->writenl(); + fensure->toCBuffer(buf, hgs); + } + + if (frequire || fensure) + { buf->writestring("body"); + buf->writenl(); + } + + buf->writebyte('{'); + buf->writenl(); + fbody->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); + } + else + { buf->writeByte(';'); + buf->writenl(); + } +} + +/**************************************************** + * Determine if 'this' overrides fd. + * Return !=0 if it does. + */ + +int FuncDeclaration::overrides(FuncDeclaration *fd) +{ int result = 0; + + if (fd->ident == ident) + { + int cov = type->covariant(fd->type); + if (cov) + { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); + ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); + + if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) + result = 1; + } + } + return result; +} + +/************************************************* + * Find index of function in vtbl[0..dim] that + * this function overrides. + * Returns: + * -1 didn't find one + * -2 can't determine because of forward references + */ + +int FuncDeclaration::findVtblIndex(Array *vtbl, int dim) +{ + for (int vi = 0; vi < dim; vi++) + { + FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration(); + if (fdv && fdv->ident == ident) + { + int cov = type->covariant(fdv->type); + //printf("\tbaseclass cov = %d\n", cov); + switch (cov) + { + case 0: // types are distinct + break; + + case 1: + return vi; + + case 2: + //type->print(); + //fdv->type->print(); + //printf("%s %s\n", type->deco, fdv->type->deco); + error("of type %s overrides but is not covariant with %s of type %s", + type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); + break; + + case 3: + return -2; // forward references + + default: + assert(0); + } + } + } + return -1; +} + +/**************************************************** + * Overload this FuncDeclaration with the new one f. + * Return !=0 if successful; i.e. no conflict. + */ + +int FuncDeclaration::overloadInsert(Dsymbol *s) +{ + FuncDeclaration *f; + AliasDeclaration *a; + + //printf("FuncDeclaration::overloadInsert(%s)\n", s->toChars()); + a = s->isAliasDeclaration(); + if (a) + { + if (overnext) + return overnext->overloadInsert(a); + if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) + { + //printf("\ta = '%s'\n", a->type->toChars()); + return FALSE; + } + overnext = a; + //printf("\ttrue: no conflict\n"); + return TRUE; + } + f = s->isFuncDeclaration(); + if (!f) + return FALSE; + +#if 0 + /* Disable this check because: + * const void foo(); + * semantic() isn't run yet on foo(), so the const hasn't been + * applied yet. + */ + if (type) + { printf("type = %s\n", type->toChars()); + printf("f->type = %s\n", f->type->toChars()); + } + if (type && f->type && // can be NULL for overloaded constructors + f->type->covariant(type) && + f->type->mod == type->mod && + !isFuncAliasDeclaration()) + { + //printf("\tfalse: conflict %s\n", kind()); + return FALSE; + } +#endif + + if (overnext) + return overnext->overloadInsert(f); + overnext = f; + //printf("\ttrue: no conflict\n"); + return TRUE; +} + +/******************************************** + * Find function in overload list that exactly matches t. + */ + +/*************************************************** + * Visit each overloaded function in turn, and call + * (*fp)(param, f) on it. + * Exit when no more, or (*fp)(param, f) returns 1. + * Returns: + * 0 continue + * 1 done + */ + +int overloadApply(Module* from, FuncDeclaration *fstart, + int (*fp)(void *, FuncDeclaration *), + void *param) +{ + FuncDeclaration *f; + Declaration *d; + Declaration *next; + + for (d = fstart; d; d = next) + { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); + + if (fa) + { + if (fa->getModule() == from || fa->importprot != PROTprivate) + if (overloadApply(from, fa->funcalias, fp, param)) + return 1; + next = fa->overnext; + } + else + { + AliasDeclaration *a = d->isAliasDeclaration(); + + if (a) + { + Dsymbol *s = a->toAlias(); + next = s->isDeclaration(); + if (next == a) + break; + if (next == fstart) + break; +#if IN_LLVM + if (a->importprot == PROTprivate && a->getModule() != from) + if (FuncDeclaration* fd = next->isFuncDeclaration()) + next = fd->overnext; +#endif + } + else + { + f = d->isFuncDeclaration(); + if (!f) + { d->error("is aliased to a function"); + break; // BUG: should print error message? + } + if ((*fp)(param, f)) + return 1; + + next = f->overnext; + } + } + } + return 0; +} + +/******************************************** + * If there are no overloads of function f, return that function, + * otherwise return NULL. + */ + +static int fpunique(void *param, FuncDeclaration *f) +{ FuncDeclaration **pf = (FuncDeclaration **)param; + + if (*pf) + { *pf = NULL; + return 1; // ambiguous, done + } + else + { *pf = f; + return 0; + } +} + +FuncDeclaration *FuncDeclaration::isUnique() +{ FuncDeclaration *result = NULL; + + overloadApply(getModule(), this, &fpunique, &result); + return result; +} + +/******************************************** + * Find function in overload list that exactly matches t. + */ + +struct Param1 +{ + Type *t; // type to match + FuncDeclaration *f; // return value +}; + +int fp1(void *param, FuncDeclaration *f) +{ Param1 *p = (Param1 *)param; + Type *t = p->t; + + if (t->equals(f->type)) + { p->f = f; + return 1; + } + +#if DMDV2 + /* Allow covariant matches, if it's just a const conversion + * of the return type + */ + if (t->ty == Tfunction) + { TypeFunction *tf = (TypeFunction *)f->type; + if (tf->covariant(t) == 1 && + tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) + { + p->f = f; + return 1; + } + } +#endif + return 0; +} + +FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t, Module* from) +{ + Param1 p; + p.t = t; + p.f = NULL; + overloadApply(from, this, &fp1, &p); + return p.f; +} + + +/******************************************** + * Decide which function matches the arguments best. + */ + +struct Param2 +{ + Match *m; + Expression *ethis; + Expressions *arguments; +}; + +int fp2(void *param, FuncDeclaration *f) +{ Param2 *p = (Param2 *)param; + Match *m = p->m; + Expressions *arguments = p->arguments; + MATCH match; + + if (f != m->lastf) // skip duplicates + { + m->anyf = f; + TypeFunction *tf = (TypeFunction *)f->type; + match = (MATCH) tf->callMatch(f->needThis() ? p->ethis : NULL, arguments); + //printf("match = %d\n", match); + if (match != MATCHnomatch) + { + if (match > m->last) + goto LfIsBetter; + + if (match < m->last) + goto LlastIsBetter; + + /* See if one of the matches overrides the other. + */ + if (m->lastf->overrides(f)) + goto LlastIsBetter; + else if (f->overrides(m->lastf)) + goto LfIsBetter; + + /* Try to disambiguate using template-style partial ordering rules. + * In essence, if f() and g() are ambiguous, if f() can call g(), + * but g() cannot call f(), then pick f(). + * This is because f() is "more specialized." + */ + { + MATCH c1 = f->leastAsSpecialized(m->lastf); + MATCH c2 = m->lastf->leastAsSpecialized(f); + //printf("c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) + goto LfIsBetter; + if (c1 < c2) + goto LlastIsBetter; + } + + Lambiguous: + m->nextf = f; + m->count++; + return 0; + + LfIsBetter: + m->last = match; + m->lastf = f; + m->count = 1; + return 0; + + LlastIsBetter: + return 0; + } + } + return 0; +} + +void overloadResolveX(Match *m, FuncDeclaration *fstart, + Expression *ethis, Expressions *arguments, Module* from) +{ + Param2 p; + p.m = m; + p.ethis = ethis; + p.arguments = arguments; + overloadApply(from, fstart, &fp2, &p); +} + + +FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags, Module* from) +{ + TypeFunction *tf; + Match m; + +#if 0 +printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); +if (arguments) +{ int i; + + for (i = 0; i < arguments->dim; i++) + { Expression *arg; + + arg = (Expression *)arguments->data[i]; + assert(arg->type); + printf("\t%s: ", arg->toChars()); + arg->type->print(); + } +} +#endif + + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + overloadResolveX(&m, this, ethis, arguments, from); + + if (m.count == 1) // exactly one match + { + return m.lastf; + } + else + { + OutBuffer buf; + + if (arguments) + { + HdrGenState hgs; + + argExpTypesToCBuffer(&buf, arguments, &hgs); + } + + if (m.last == MATCHnomatch) + { + if (flags & 1) // if do not print error messages + return NULL; // no match + + tf = (TypeFunction *)type; + + //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); + error(loc, "%s does not match parameter types (%s)", + Argument::argsTypesToChars(tf->parameters, tf->varargs), + buf.toChars()); + return m.anyf; // as long as it's not a FuncAliasDeclaration + } + else + { +#if 1 + TypeFunction *t1 = (TypeFunction *)m.lastf->type; + TypeFunction *t2 = (TypeFunction *)m.nextf->type; + + error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", + buf.toChars(), + m.lastf->toPrettyChars(), Argument::argsTypesToChars(t1->parameters, t1->varargs), + m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs)); +#else + error(loc, "overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); +#endif + return m.lastf; + } + } +} + +/************************************* + * Determine partial specialization order of 'this' vs g. + * This is very similar to TemplateDeclaration::leastAsSpecialized(). + * Returns: + * match 'this' is at least as specialized as g + * 0 g is more specialized than 'this' + */ + +MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) +{ +#define LOG_LEASTAS 0 + +#if LOG_LEASTAS + printf("%s.leastAsSpecialized(%s)\n", toChars(), g->toChars()); +#endif + + /* This works by calling g() with f()'s parameters, and + * if that is possible, then f() is at least as specialized + * as g() is. + */ + + TypeFunction *tf = (TypeFunction *)type; + TypeFunction *tg = (TypeFunction *)g->type; + size_t nfparams = Argument::dim(tf->parameters); + size_t ngparams = Argument::dim(tg->parameters); + MATCH match = MATCHexact; + + /* If both functions have a 'this' pointer, and the mods are not + * the same and g's is not const, then this is less specialized. + */ + if (needThis() && g->needThis()) + { + if (tf->mod != tg->mod) + { + if (tg->mod == MODconst) + match = MATCHconst; + else + return MATCHnomatch; + } + } + + /* Create a dummy array of arguments out of the parameters to f() + */ + Expressions args; + args.setDim(nfparams); + for (int u = 0; u < nfparams; u++) + { + Argument *p = Argument::getNth(tf->parameters, u); + Expression *e; + if (p->storageClass & (STCref | STCout)) + { + e = new IdentifierExp(0, p->ident); + e->type = p->type; + } + else + e = p->type->defaultInit(); + args.data[u] = e; + } + + MATCH m = (MATCH) tg->callMatch(NULL, &args); + if (m) + { + /* A variadic parameter list is less specialized than a + * non-variadic one. + */ + if (tf->varargs && !tg->varargs) + goto L1; // less specialized + +#if LOG_LEASTAS + printf(" matches %d, so is least as specialized\n", m); +#endif + return m; + } + L1: +#if LOG_LEASTAS + printf(" doesn't match, so is not as specialized\n"); +#endif + return MATCHnomatch; +} + +/******************************************* + * Given a symbol that could be either a FuncDeclaration or + * a function template, resolve it to a function symbol. + * sc instantiation scope + * loc instantiation location + * targsi initial list of template arguments + * ethis if !NULL, the 'this' pointer argument + * fargs arguments to function + * flags 1: do not issue error message on no match, just return NULL + */ + +FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, + Objects *tiargs, + Expression *ethis, + Expressions *arguments, + int flags) +{ + if (!s) + return NULL; // no match + FuncDeclaration *f = s->isFuncDeclaration(); + if (f) + f = f->overloadResolve(loc, ethis, arguments); + else + { TemplateDeclaration *td = s->isTemplateDeclaration(); + assert(td); + f = td->deduceFunctionTemplate(sc, loc, tiargs, NULL, arguments, flags); + } + return f; +} + +/******************************** + * Labels are in a separate scope, one per function. + */ + +LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident) +{ Dsymbol *s; + + if (!labtab) + labtab = new DsymbolTable(); // guess we need one + + s = labtab->lookup(ident); + if (!s) + { + s = new LabelDsymbol(ident); + labtab->insert(s); + } + return (LabelDsymbol *)s; +} + +/**************************************** + * If non-static member function that has a 'this' pointer, + * return the aggregate it is a member of. + * Otherwise, return NULL. + */ + +AggregateDeclaration *FuncDeclaration::isThis() +{ AggregateDeclaration *ad; + + //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); + ad = NULL; + if ((storage_class & STCstatic) == 0) + { + ad = isMember2(); + } + //printf("-FuncDeclaration::isThis() %p\n", ad); + return ad; +} + +AggregateDeclaration *FuncDeclaration::isMember2() +{ AggregateDeclaration *ad; + + //printf("+FuncDeclaration::isMember2() '%s'\n", toChars()); + ad = NULL; + for (Dsymbol *s = this; s; s = s->parent) + { +//printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind()); + ad = s->isMember(); + if (ad) +{ //printf("test4\n"); + break; +} + if (!s->parent || + (!s->parent->isTemplateInstance())) +{ //printf("test5\n"); + break; +} + } + //printf("-FuncDeclaration::isMember2() %p\n", ad); + return ad; +} + +/***************************************** + * Determine lexical level difference from 'this' to nested function 'fd'. + * Error if this cannot call fd. + * Returns: + * 0 same level + * -1 increase nesting by 1 (fd is nested within 'this') + * >0 decrease nesting by number + */ + +int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) +{ int level; + Dsymbol *s; + Dsymbol *fdparent; + + //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); + fdparent = fd->toParent2(); + if (fdparent == this) + return -1; + s = this; + level = 0; + while (fd != s && fdparent != s->toParent2()) + { + //printf("\ts = '%s'\n", s->toChars()); + FuncDeclaration *thisfd = s->isFuncDeclaration(); + if (thisfd) + { if (!thisfd->isNested() && !thisfd->vthis) + goto Lerr; + } + else + { + AggregateDeclaration *thiscd = s->isAggregateDeclaration(); + if (thiscd) + { if (!thiscd->isNested()) + goto Lerr; + } + else + goto Lerr; + } + + s = s->toParent2(); + assert(s); + level++; + } + return level; + +Lerr: + error(loc, "cannot access frame of function %s", fd->toChars()); + return 1; +} + +void FuncDeclaration::appendExp(Expression *e) +{ Statement *s; + + s = new ExpStatement(0, e); + appendState(s); +} + +void FuncDeclaration::appendState(Statement *s) +{ CompoundStatement *cs; + + if (!fbody) + { Statements *a; + + a = new Statements(); + fbody = new CompoundStatement(0, a); + } + cs = fbody->isCompoundStatement(); + cs->statements->push(s); +} + + +int FuncDeclaration::isMain() +{ + return ident == Id::main && + linkage != LINKc && !isMember() && !isNested(); +} + +int FuncDeclaration::isWinMain() +{ + //printf("FuncDeclaration::isWinMain() %s\n", toChars()); +#if 0 + int x = ident == Id::WinMain && + linkage != LINKc && !isMember(); + printf("%s\n", x ? "yes" : "no"); + return x; +#else + return ident == Id::WinMain && + linkage != LINKc && !isMember(); +#endif +} + +int FuncDeclaration::isDllMain() +{ + return ident == Id::DllMain && + linkage != LINKc && !isMember(); +} + +int FuncDeclaration::isExport() +{ + return protection == PROTexport; +} + +int FuncDeclaration::isImportedSymbol() +{ + //printf("isImportedSymbol()\n"); + //printf("protection = %d\n", protection); + return (protection == PROTexport) && !fbody; +} + +// Determine if function goes into virtual function pointer table + +int FuncDeclaration::isVirtual() +{ +#if 0 + printf("FuncDeclaration::isVirtual(%s)\n", toChars()); + printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); + printf("result is %d\n", + isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + toParent()->isClassDeclaration()); +#endif + return isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + toParent()->isClassDeclaration(); +} + +int FuncDeclaration::isFinal() +{ + ClassDeclaration *cd; +#if 0 + printf("FuncDeclaration::isFinal(%s)\n", toChars()); + printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); + printf("result is %d\n", + isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + (cd = toParent()->isClassDeclaration()) != NULL && + cd->storage_class & STCfinal); +#endif + return isMember() && + (Declaration::isFinal() || + ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); +} + +int FuncDeclaration::isAbstract() +{ + return storage_class & STCabstract; +} + +int FuncDeclaration::isCodeseg() +{ + return TRUE; // functions are always in the code segment +} + +int FuncDeclaration::isOverloadable() +{ + return 1; // functions can be overloaded +} + +int FuncDeclaration::isPure() +{ + //printf("FuncDeclaration::isPure() '%s'\n", toChars()); + assert(type->ty == Tfunction); + return ((TypeFunction *)this->type)->ispure; +} + +// Determine if function needs +// a static frame pointer to its lexically enclosing function + +int FuncDeclaration::isNested() +{ + //if (!toParent()) + //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); + //printf("\ttoParent2() = '%s'\n", toParent2()->toChars()); + return ((storage_class & STCstatic) == 0) && toParent2() && + (toParent2()->isFuncDeclaration() != NULL); +} + +int FuncDeclaration::needThis() +{ + //printf("FuncDeclaration::needThis() '%s'\n", toChars()); + int i = isThis() != NULL; + //printf("\t%d\n", i); + if (!i && isFuncAliasDeclaration()) + i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); + return i; +} + +int FuncDeclaration::addPreInvariant() +{ + AggregateDeclaration *ad = isThis(); + return (ad && + //ad->isClassDeclaration() && + global.params.useInvariants && + (protection == PROTpublic || protection == PROTexport) && + !naked && + ident != Id::cpctor); +} + +int FuncDeclaration::addPostInvariant() +{ + AggregateDeclaration *ad = isThis(); + return (ad && + ad->inv && + //ad->isClassDeclaration() && + global.params.useInvariants && + (protection == PROTpublic || protection == PROTexport) && + !naked && + ident != Id::cpctor); +} + +/********************************** + * Generate a FuncDeclaration for a runtime library function. + */ + +// +// LDC: Adjusted to give argument info to the runtime function decl. +// + +FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, const char *name) +{ + return genCfunc(args, treturn, Lexer::idPool(name)); +} + +FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, Identifier *id) +{ + FuncDeclaration *fd; + TypeFunction *tf; + Dsymbol *s; + static DsymbolTable *st = NULL; + + //printf("genCfunc(name = '%s')\n", id->toChars()); + //printf("treturn\n\t"); treturn->print(); + + // See if already in table + if (!st) + st = new DsymbolTable(); + s = st->lookup(id); + if (s) + { + fd = s->isFuncDeclaration(); + assert(fd); + assert(fd->type->nextOf()->equals(treturn)); + } + else + { + tf = new TypeFunction(args, treturn, 0, LINKc); + fd = new FuncDeclaration(0, 0, id, STCstatic, tf); + fd->protection = PROTpublic; + fd->linkage = LINKc; + + st->insert(fd); + } + return fd; +} + +const char *FuncDeclaration::kind() +{ + return "function"; +} + +/******************************* + * Look at all the variables in this function that are referenced + * by nested functions, and determine if a closure needs to be + * created for them. + */ + +#if DMDV2 +int FuncDeclaration::needsClosure() +{ + /* Need a closure for all the closureVars[] if any of the + * closureVars[] are accessed by a + * function that escapes the scope of this function. + * We take the conservative approach and decide that any function that: + * 1) is a virtual function + * 2) has its address taken + * 3) has a parent that escapes + * + * Note that since a non-virtual function can be called by + * a virtual one, if that non-virtual function accesses a closure + * var, the closure still has to be taken. Hence, we check for isThis() + * instead of isVirtual(). (thanks to David Friedman) + */ + + //printf("FuncDeclaration::needsClosure() %s\n", toChars()); + for (int i = 0; i < closureVars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)closureVars.data[i]; + assert(v->isVarDeclaration()); + //printf("\tv = %s\n", v->toChars()); + + for (int j = 0; j < v->nestedrefs.dim; j++) + { FuncDeclaration *f = (FuncDeclaration *)v->nestedrefs.data[j]; + assert(f != this); + + //printf("\t\tf = %s, %d, %p, %d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); + if (f->isThis() || f->tookAddressOf) + goto Lyes; // assume f escapes this function's scope + + // Look to see if any parents of f that are below this escape + for (Dsymbol *s = f->parent; s && s != this; s = s->parent) + { + f = s->isFuncDeclaration(); + if (f && (f->isThis() || f->tookAddressOf)) + goto Lyes; + } + } + } + return 0; + +Lyes: + //printf("\tneeds closure\n"); + return 1; +} +#endif + +/****************************** FuncAliasDeclaration ************************/ + +// Used as a way to import a set of functions from another scope into this one. + +FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) + : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, + (enum STC)funcalias->storage_class, funcalias->type) +{ + assert(funcalias != this); + this->funcalias = funcalias; +#if IN_LLVM + importprot = PROTundefined; +#endif +} + +const char *FuncAliasDeclaration::kind() +{ + return "function alias"; +} + + +/****************************** FuncLiteralDeclaration ************************/ + +FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, + enum TOK tok, ForeachStatement *fes) + : FuncDeclaration(loc, endloc, NULL, STCundefined, type) +{ + const char *id; + + if (fes) + id = "__foreachbody"; + else if (tok == TOKdelegate) + id = "__dgliteral"; + else + id = "__funcliteral"; + this->ident = Lexer::uniqueId(id); + this->tok = tok; + this->fes = fes; + //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); +} + +Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) +{ + FuncLiteralDeclaration *f; + + //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + f = (FuncLiteralDeclaration *)s; + else + { f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); + f->ident = ident; // keep old identifier + } + FuncDeclaration::syntaxCopy(f); + return f; +} + +int FuncLiteralDeclaration::isNested() +{ + //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); + return (tok == TOKdelegate); +} + +int FuncLiteralDeclaration::isVirtual() +{ + return FALSE; +} + +const char *FuncLiteralDeclaration::kind() +{ + // GCC requires the (char*) casts + return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; +} + +void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + static Identifier *idfunc; + static Identifier *iddel; + + if (!idfunc) + idfunc = new Identifier("function", 0); + if (!iddel) + iddel = new Identifier("delegate", 0); + + type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs); + bodyToCBuffer(buf, hgs); +} + + +/********************************* CtorDeclaration ****************************/ + +CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) + : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) +{ + this->arguments = arguments; + this->varargs = varargs; + //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); +} + +Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) +{ + CtorDeclaration *f; + + f = new CtorDeclaration(loc, endloc, NULL, varargs); + + f->outId = outId; + f->frequire = frequire ? frequire->syntaxCopy() : NULL; + f->fensure = fensure ? fensure->syntaxCopy() : NULL; + f->fbody = fbody ? fbody->syntaxCopy() : NULL; + assert(!fthrows); // deprecated + + f->arguments = Argument::arraySyntaxCopy(arguments); + return f; +} + + +void CtorDeclaration::semantic(Scope *sc) +{ + AggregateDeclaration *ad; + Type *tret; + + //printf("CtorDeclaration::semantic() %s\n", toChars()); + if (type) + return; + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static constructor + + parent = sc->parent; + Dsymbol *parent = toParent2(); + ad = parent->isAggregateDeclaration(); + if (!ad || parent->isUnionDeclaration()) + { + error("constructors are only for class or struct definitions"); + fatal(); + tret = Type::tvoid; + } + else + { tret = ad->handle; + assert(tret); + } + type = new TypeFunction(arguments, tret, varargs, LINKd); +#if STRUCTTHISREF + if (ad && ad->isStructDeclaration()) + ((TypeFunction *)type)->isref = 1; +#endif + if (!originalType) + originalType = type; + + sc->flags |= SCOPEctor; + type = type->semantic(loc, sc); + sc->flags &= ~SCOPEctor; + + // Append: + // return this; + // to the function body + if (fbody) + { + Expression *e = new ThisExp(loc); + Statement *s = new ReturnStatement(loc, e); + fbody = new CompoundStatement(loc, fbody, s); + } + + FuncDeclaration::semantic(sc); + + sc->pop(); + + // See if it's the default constructor + if (ad && varargs == 0 && Argument::dim(arguments) == 0) + { if (ad->isStructDeclaration()) + error("default constructor not allowed for structs"); + else + ad->defaultCtor = this; + } +} + +const char *CtorDeclaration::kind() +{ + return "constructor"; +} + +char *CtorDeclaration::toChars() +{ + return (char *)"this"; +} + +int CtorDeclaration::isVirtual() +{ + return FALSE; +} + +int CtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int CtorDeclaration::addPostInvariant() +{ + return (isThis() && vthis && global.params.useInvariants); +} + + +void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this"); + Argument::argsToCBuffer(buf, hgs, arguments, varargs); + bodyToCBuffer(buf, hgs); +} + +/********************************* PostBlitDeclaration ****************************/ + +PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::_postblit, STCundefined, NULL) +{ +} + +PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id) + : FuncDeclaration(loc, endloc, id, STCundefined, NULL) +{ +} + +Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, ident); + return FuncDeclaration::syntaxCopy(dd); +} + + +void PostBlitDeclaration::semantic(Scope *sc) +{ + //printf("PostBlitDeclaration::semantic() %s\n", toChars()); + //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); + parent = sc->parent; + Dsymbol *parent = toParent(); + StructDeclaration *ad = parent->isStructDeclaration(); + if (!ad) + { + error("post blits are only for struct/union definitions, not %s %s", parent->kind(), parent->toChars()); + } + else if (ident == Id::_postblit) + ad->postblits.push(this); + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not static + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int PostBlitDeclaration::overloadInsert(Dsymbol *s) +{ + return FALSE; // cannot overload postblits +} + +int PostBlitDeclaration::addPreInvariant() +{ + return FALSE; +} + +int PostBlitDeclaration::addPostInvariant() +{ + return (isThis() && vthis && global.params.useInvariants); +} + +int PostBlitDeclaration::isVirtual() +{ + return FALSE; +} + +void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("=this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* DtorDeclaration ****************************/ + +DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) +{ +} + +DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) + : FuncDeclaration(loc, endloc, id, STCundefined, NULL) +{ +} + +Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); + return FuncDeclaration::syntaxCopy(dd); +} + + +void DtorDeclaration::semantic(Scope *sc) +{ + //printf("DtorDeclaration::semantic() %s\n", toChars()); + //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); + parent = sc->parent; + Dsymbol *parent = toParent(); + AggregateDeclaration *ad = parent->isAggregateDeclaration(); + if (!ad) + { + error("destructors are only for class/struct/union definitions, not %s %s", parent->kind(), parent->toChars()); + fatal(); + } + else if (ident == Id::dtor) + ad->dtors.push(this); + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static destructor + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int DtorDeclaration::overloadInsert(Dsymbol *s) +{ + return FALSE; // cannot overload destructors +} + +int DtorDeclaration::addPreInvariant() +{ + return (isThis() && vthis && global.params.useInvariants); +} + +int DtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +const char *DtorDeclaration::kind() +{ + return "destructor"; +} + +char *DtorDeclaration::toChars() +{ + return (char *)"~this"; +} + +int DtorDeclaration::isVirtual() +{ + /* This should be FALSE so that dtor's don't get put into the vtbl[], + * but doing so will require recompiling everything. + */ +#if BREAKABI + return FALSE; +#else + return FuncDeclaration::isVirtual(); +#endif +} + +void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("~this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* StaticCtorDeclaration ****************************/ + +StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, + Identifier::generateId("_staticCtor"), STCstatic, NULL) +{ +} + +Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticCtorDeclaration *scd; + + assert(!s); + scd = new StaticCtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(scd); +} + + +void StaticCtorDeclaration::semantic(Scope *sc) +{ + //printf("StaticCtorDeclaration::semantic()\n"); + + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + /* If the static ctor appears within a template instantiation, + * it could get called multiple times by the module constructors + * for different modules. Thus, protect it with a gate. + */ + if (inTemplateInstance()) + { + /* Add this prefix to the function: + * static int gate; + * if (++gate != 1) return; + * Note that this is not thread safe; should not have threads + * during static construction. + */ + Identifier *id = Lexer::idPool("__gate"); + VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); + v->storage_class = STCstatic; + Statements *sa = new Statements(); + Statement *s = new DeclarationStatement(0, v); + sa->push(s); + Expression *e = new IdentifierExp(0, id); + e = new AddAssignExp(0, e, new IntegerExp(1)); + e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); + s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); + sa->push(s); + if (fbody) + sa->push(fbody); + fbody = new CompoundStatement(0, sa); + } + + FuncDeclaration::semantic(sc); + + // We're going to need ModuleInfo + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { m->needmoduleinfo = 1; +#ifdef IN_GCC + m->strictlyneedmoduleinfo = 1; +#endif + } +} + +AggregateDeclaration *StaticCtorDeclaration::isThis() +{ + return NULL; +} + +int StaticCtorDeclaration::isStaticConstructor() +{ + return TRUE; +} + +int StaticCtorDeclaration::isVirtual() +{ + return FALSE; +} + +int StaticCtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int StaticCtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + { buf->writestring("static this();\n"); + return; + } + buf->writestring("static this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* StaticDtorDeclaration ****************************/ + +StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, + Identifier::generateId("_staticDtor"), STCstatic, NULL) +{ + vgate = NULL; +} + +Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticDtorDeclaration *sdd; + + assert(!s); + sdd = new StaticDtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(sdd); +} + + +void StaticDtorDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + Type *tret; + + cd = sc->scopesym->isClassDeclaration(); + if (!cd) + { + } + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + /* If the static ctor appears within a template instantiation, + * it could get called multiple times by the module constructors + * for different modules. Thus, protect it with a gate. + */ + if (inTemplateInstance()) + { + /* Add this prefix to the function: + * static int gate; + * if (--gate != 0) return; + * Increment gate during constructor execution. + * Note that this is not thread safe; should not have threads + * during static destruction. + */ + Identifier *id = Lexer::idPool("__gate"); + VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); + v->storage_class = STCstatic; + Statements *sa = new Statements(); + Statement *s = new DeclarationStatement(0, v); + sa->push(s); + Expression *e = new IdentifierExp(0, id); + e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); + e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(0)); + s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); + sa->push(s); + if (fbody) + sa->push(fbody); + fbody = new CompoundStatement(0, sa); + vgate = v; + } + + FuncDeclaration::semantic(sc); + + // We're going to need ModuleInfo + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { m->needmoduleinfo = 1; +#ifdef IN_GCC + m->strictlyneedmoduleinfo = 1; +#endif + } +} + +AggregateDeclaration *StaticDtorDeclaration::isThis() +{ + return NULL; +} + +int StaticDtorDeclaration::isStaticDestructor() +{ + return TRUE; +} + +int StaticDtorDeclaration::isVirtual() +{ + return FALSE; +} + +int StaticDtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int StaticDtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("static ~this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* InvariantDeclaration ****************************/ + +InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) +{ +} + +Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) +{ + InvariantDeclaration *id; + + assert(!s); + id = new InvariantDeclaration(loc, endloc); + FuncDeclaration::syntaxCopy(id); + return id; +} + + +void InvariantDeclaration::semantic(Scope *sc) +{ + AggregateDeclaration *ad; + Type *tret; + + parent = sc->parent; + Dsymbol *parent = toParent(); + ad = parent->isAggregateDeclaration(); + if (!ad) + { + error("invariants are only for struct/union/class definitions"); + return; + } + else if (ad->inv && ad->inv != this) + { + error("more than one invariant for %s", ad->toChars()); + } + ad->inv = this; + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static invariant + sc->incontract++; + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int InvariantDeclaration::isVirtual() +{ + return FALSE; +} + +int InvariantDeclaration::addPreInvariant() +{ + return FALSE; +} + +int InvariantDeclaration::addPostInvariant() +{ + return FALSE; +} + +void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("invariant"); + bodyToCBuffer(buf, hgs); +} + + +/********************************* UnitTestDeclaration ****************************/ + +/******************************* + * Generate unique unittest function Id so we can have multiple + * instances per module. + */ + +static Identifier *unitTestId() +{ + return Lexer::uniqueId("__unittest"); +} + +UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) +{ +} + +Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) +{ + UnitTestDeclaration *utd; + + assert(!s); + utd = new UnitTestDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(utd); +} + + +void UnitTestDeclaration::semantic(Scope *sc) +{ + if (global.params.useUnitTests) + { + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + Scope *sc2 = sc->push(); + sc2->linkage = LINKd; + FuncDeclaration::semantic(sc2); + sc2->pop(); + } + + // We're going to need ModuleInfo even if the unit tests are not + // compiled in, because other modules may import this module and refer + // to this ModuleInfo. + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + m->needmoduleinfo = 1; +} + +AggregateDeclaration *UnitTestDeclaration::isThis() +{ + return NULL; +} + +int UnitTestDeclaration::isVirtual() +{ + return FALSE; +} + +int UnitTestDeclaration::addPreInvariant() +{ + return FALSE; +} + +int UnitTestDeclaration::addPostInvariant() +{ + return FALSE; +} + +void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("unittest"); + bodyToCBuffer(buf, hgs); +} + +/********************************* NewDeclaration ****************************/ + +NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) + : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) +{ + this->arguments = arguments; + this->varargs = varargs; +} + +Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) +{ + NewDeclaration *f; + + f = new NewDeclaration(loc, endloc, NULL, varargs); + + FuncDeclaration::syntaxCopy(f); + + f->arguments = Argument::arraySyntaxCopy(arguments); + + return f; +} + + +void NewDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + Type *tret; + + //printf("NewDeclaration::semantic()\n"); + + parent = sc->parent; + Dsymbol *parent = toParent(); + cd = parent->isClassDeclaration(); + if (!cd && !parent->isStructDeclaration()) + { + error("new allocators only are for class or struct definitions"); + } + tret = Type::tvoid->pointerTo(); + type = new TypeFunction(arguments, tret, varargs, LINKd); + + type = type->semantic(loc, sc); + assert(type->ty == Tfunction); + + // Check that there is at least one argument of type size_t + TypeFunction *tf = (TypeFunction *)type; + if (Argument::dim(tf->parameters) < 1) + { + error("at least one argument of type size_t expected"); + } + else + { + Argument *a = Argument::getNth(tf->parameters, 0); + if (!a->type->equals(Type::tsize_t)) + error("first argument must be type size_t, not %s", a->type->toChars()); + } + + FuncDeclaration::semantic(sc); +} + +const char *NewDeclaration::kind() +{ + return "allocator"; +} + +int NewDeclaration::isVirtual() +{ + return FALSE; +} + +int NewDeclaration::addPreInvariant() +{ + return FALSE; +} + +int NewDeclaration::addPostInvariant() +{ + return FALSE; +} + +void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("new"); + Argument::argsToCBuffer(buf, hgs, arguments, varargs); + bodyToCBuffer(buf, hgs); +} + + +/********************************* DeleteDeclaration ****************************/ + +DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments) + : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) +{ + this->arguments = arguments; +} + +Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) +{ + DeleteDeclaration *f; + + f = new DeleteDeclaration(loc, endloc, NULL); + + FuncDeclaration::syntaxCopy(f); + + f->arguments = Argument::arraySyntaxCopy(arguments); + + return f; +} + + +void DeleteDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + + //printf("DeleteDeclaration::semantic()\n"); + + parent = sc->parent; + Dsymbol *parent = toParent(); + cd = parent->isClassDeclaration(); + if (!cd && !parent->isStructDeclaration()) + { + error("new allocators only are for class or struct definitions"); + } + type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); + + type = type->semantic(loc, sc); + assert(type->ty == Tfunction); + + // Check that there is only one argument of type void* + TypeFunction *tf = (TypeFunction *)type; + if (Argument::dim(tf->parameters) != 1) + { + error("one argument of type void* expected"); + } + else + { + Argument *a = Argument::getNth(tf->parameters, 0); + if (!a->type->equals(Type::tvoid->pointerTo())) + error("one argument of type void* expected, not %s", a->type->toChars()); + } + + FuncDeclaration::semantic(sc); +} + +const char *DeleteDeclaration::kind() +{ + return "deallocator"; +} + +int DeleteDeclaration::isDelete() +{ + return TRUE; +} + +int DeleteDeclaration::isVirtual() +{ + return FALSE; +} + +int DeleteDeclaration::addPreInvariant() +{ + return FALSE; +} + +int DeleteDeclaration::addPostInvariant() +{ + return FALSE; +} + +void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("delete"); + Argument::argsToCBuffer(buf, hgs, arguments, 0); + bodyToCBuffer(buf, hgs); +} + + + + diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/hdrgen.c --- a/dmd2/hdrgen.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/hdrgen.c Sat May 30 17:23:32 2009 +0100 @@ -24,17 +24,7 @@ #include #endif -#if IN_GCC || IN_LLVM -#include "mem.h" -#else -#if _WIN32 -#include "..\root\mem.h" -#elif POSIX -#include "../root/mem.h" -#else -#error "fix this" -#endif -#endif +#include "rmem.h" #include "id.h" #include "init.h" diff -r 42bd767ec5a4 -r 638d16625da2 dmd2/html.c --- a/dmd2/html.c Thu May 28 00:07:21 2009 +0200 +++ b/dmd2/html.c Sat May 30 17:23:32 2009 +0100 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -107,10 +107,10 @@ { // Comments start with