From f9201e83526e863c5f1923e311379cd1ee4a5acf Mon Sep 17 00:00:00 2001 From: kai Date: Thu, 2 Feb 2012 03:13:27 +0100 Subject: [PATCH] Merge 1.072 --- dmd/access.c | 29 +- dmd/aggregate.h | 21 +- dmd/arrayop.c | 414 +-- dmd/arraytypes.h | 36 +- dmd/attrib.c | 186 +- dmd/attrib.h | 31 +- dmd/cast.c | 49 +- dmd/class.c | 159 +- dmd/clone.c | 14 +- dmd/cond.c | 46 +- dmd/cond.h | 9 +- dmd/constfold.c | 219 +- dmd/declaration.c | 147 +- dmd/declaration.h | 52 +- dmd/delegatize.c | 6 +- dmd/doc.c | 100 +- dmd/dsymbol.c | 287 +- dmd/dsymbol.h | 29 +- dmd/enum.c | 23 +- dmd/enum.h | 2 - dmd/expression.c | 686 +++-- dmd/expression.h | 149 +- dmd/func.c | 117 +- dmd/hdrgen.c | 8 +- dmd/identifier.h | 2 - dmd/idgen.c | 28 +- dmd/import.c | 2 +- dmd/import.h | 6 +- dmd/init.c | 190 +- dmd/init.h | 18 +- dmd/inline.c | 48 +- dmd/interpret.c | 5605 ++++++++++++++++++++++++++++++---------- dmd/json.c | 58 +- dmd/json.h | 4 +- dmd/lexer.c | 56 +- dmd/lexer.h | 2 +- dmd/macro.h | 5 +- dmd/mangle.c | 6 +- dmd/mars.c | 55 +- dmd/mars.h | 102 +- dmd/module.c | 134 +- dmd/module.h | 36 +- dmd/mtype.c | 406 ++- dmd/mtype.h | 12 +- dmd/opover.c | 2 +- dmd/optimize.c | 60 +- dmd/parse.c | 151 +- dmd/parse.h | 8 +- dmd/root/array.c | 4 +- dmd/root/async.c | 15 +- dmd/root/dchar.c | 12 +- dmd/root/dchar.h | 16 +- dmd/root/man.c | 2 +- dmd/root/port.c | 53 +- dmd/root/port.h | 5 +- dmd/root/root.c | 50 +- dmd/root/root.h | 66 +- dmd/root/stringtable.c | 4 +- dmd/root/stringtable.h | 6 +- dmd/speller.c | 8 +- dmd/statement.c | 453 ++-- dmd/statement.h | 109 +- dmd/staticassert.c | 6 +- dmd/staticassert.h | 2 - dmd/struct.c | 96 +- dmd/template.c | 454 ++-- dmd/template.h | 24 +- dmd/version.c | 4 +- gen/asmstmt.cpp | 4 - gen/cl_helpers.h | 5 - gen/main.cpp | 4 - gen/statements.cpp | 6 +- 72 files changed, 7739 insertions(+), 3484 deletions(-) diff --git a/dmd/access.c b/dmd/access.c index 0e075512..8e9282a9 100644 --- a/dmd/access.c +++ b/dmd/access.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -76,18 +76,15 @@ enum PROT ClassDeclaration::getAccess(Dsymbol *smember) } 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]; + for (size_t i = 0; i < baseclasses->dim; i++) + { BaseClass *b = (*baseclasses)[i]; - access = b->base->getAccess(smember); + enum PROT access = b->base->getAccess(smember); switch (access) { case PROTnone: @@ -153,11 +150,9 @@ static int accessCheckX( 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); + for (size_t i = 0; i < cdthis->baseclasses->dim; i++) + { BaseClass *b = (*cdthis->baseclasses)[i]; + enum PROT access = b->base->getAccess(smember); if (access >= PROTprotected || accessCheckX(smember, sfunc, b->base, cdscope) ) @@ -174,8 +169,8 @@ static int accessCheckX( ClassDeclaration *cdthis = dthis->isClassDeclaration(); if (cdthis) { - for (int i = 0; i < cdthis->baseclasses->dim; i++) - { BaseClass *b = (BaseClass *)cdthis->baseclasses->data[i]; + for (size_t i = 0; i < cdthis->baseclasses->dim; i++) + { BaseClass *b = (*cdthis->baseclasses)[i]; if (accessCheckX(smember, sfunc, b->base, cdscope)) return 1; @@ -219,12 +214,12 @@ void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) //assert(smember->parent->isBaseOf(this, NULL)); if (smemberparent == this) - { enum PROT access = smember->prot(); + { enum PROT access2 = smember->prot(); - result = access >= PROTpublic || + result = access2 >= PROTpublic || hasPrivateAccess(f) || isFriendOf(cdscope) || - (access == PROTpackage && hasPackageAccess(sc, this)); + (access2 == PROTpackage && hasPackageAccess(sc, this)); #if LOG printf("result1 = %d\n", result); #endif diff --git a/dmd/aggregate.h b/dmd/aggregate.h index e09d270c..b7dc8f2d 100644 --- a/dmd/aggregate.h +++ b/dmd/aggregate.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -61,7 +61,7 @@ struct AggregateDeclaration : ScopeDsymbol 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 + VarDeclarations fields; // VarDeclaration fields unsigned sizeok; // set when structsize contains valid data // 0: no size // 1: size is correct @@ -82,6 +82,7 @@ struct AggregateDeclaration : ScopeDsymbol Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration CtorDeclaration *defaultCtor; // default constructor Dsymbol *aliasthis; // forward unresolved lookups to aliasthis + bool noDefaultCtor; // no default construction #endif FuncDeclarations dtors; // Array of destructors @@ -99,6 +100,8 @@ struct AggregateDeclaration : ScopeDsymbol static void alignmember(unsigned salign, unsigned size, unsigned *poffset); Type *getType(); void addField(Scope *sc, VarDeclaration *v); + int firstFieldInUnion(int indx); // first field in union that includes indx + int numFieldsInUnion(int firstIndex); // #fields in union starting at index int isDeprecated(); // is aggregate deprecated? FuncDeclaration *buildDtor(Scope *sc); int isNested(); @@ -146,6 +149,7 @@ struct StructDeclaration : AggregateDeclaration #if DMDV2 int hasIdentityAssign; // !=0 if has identity opAssign FuncDeclaration *cpctor; // generated copy-constructor, if any + FuncDeclaration *eq; // bool opEquals(ref const T), if any FuncDeclarations postblits; // Array of postblit functions FuncDeclaration *postblit; // aggregate postblit @@ -202,17 +206,17 @@ struct BaseClass ClassDeclaration *base; int offset; // 'this' pointer offset - Array vtbl; // for interfaces: Array of FuncDeclaration's + FuncDeclarations vtbl; // for interfaces: Array of FuncDeclaration's // making up the vtbl[] - int baseInterfaces_dim; + size_t 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); + int fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance); void copyBaseInterfaces(BaseClasses *); }; @@ -227,6 +231,7 @@ struct ClassDeclaration : AggregateDeclaration { static ClassDeclaration *object; static ClassDeclaration *classinfo; + static ClassDeclaration *errorException; ClassDeclaration *baseClass; // NULL only if this is Object #if DMDV1 @@ -235,13 +240,13 @@ struct ClassDeclaration : AggregateDeclaration #endif FuncDeclaration *staticCtor; FuncDeclaration *staticDtor; - Array vtbl; // Array of FuncDeclaration's making up the vtbl[] - Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] + Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[] + Dsymbols 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; + size_t interfaces_dim; BaseClass **interfaces; // interfaces[interfaces_dim] for this class // (does not include baseClass) diff --git a/dmd/arrayop.c b/dmd/arrayop.c index b2433d4b..87046a64 100644 --- a/dmd/arrayop.c +++ b/dmd/arrayop.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -13,7 +13,7 @@ #include "rmem.h" -#include "stringtable.h" +#include "aav.h" #include "expression.h" #include "statement.h" @@ -31,7 +31,7 @@ extern int binary(const char *p , const char **tab, int high); * Hash table of array op functions already generated or known about. */ -StringTable arrayfuncs; +AA *arrayfuncs; #endif /********************************************** @@ -125,192 +125,195 @@ Expression *BinExp::arrayOp(Scope *sc) size_t namelen = buf.offset; buf.writeByte(0); - char *name = (char *)buf.extractData(); + char *name = buf.toChars(); + Identifier *ident = Lexer::idPool(name); /* Look up name in hash table */ +#if IN_DMD + FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident); + FuncDeclaration *fd = (FuncDeclaration *)*pfd; +#elif IN_LLVM StringValue *sv = sc->module->arrayfuncs.update(name, namelen); FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue; +#endif 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 - +#if IN_DMD + 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++) @@ -320,13 +323,13 @@ Expression *BinExp::arrayOp(Scope *sc) Parameters *fparams = new Parameters(); Expression *loopbody = buildArrayLoop(fparams); - Parameter *p = (Parameter *)fparams->data[0 /*fparams->dim - 1*/]; + Parameter *p = (*fparams)[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 ExpStatement(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)); @@ -346,32 +349,33 @@ Expression *BinExp::arrayOp(Scope *sc) */ 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 = new FuncDeclaration(loc, 0, ident, STCundefined, ftype); fd->fbody = fbody; fd->protection = PROTpublic; - fd->linkage = LINKd; - - // special attention for array ops - fd->isArrayOp = true; + fd->linkage = LINKc; + fd->isArrayOp = 1; sc->module->importedFrom->members->push(fd); sc = sc->push(); sc->parent = sc->module->importedFrom; sc->stc = 0; - sc->linkage = LINKd; + sc->linkage = LINKc; fd->semantic(sc); fd->semantic2(sc); fd->semantic3(sc); sc->pop(); -// } -// else -// { /* In library, refer to it. -// */ -// // FIXME -// fd = FuncDeclaration::genCfunc(NULL, type, name); -// } +#if IN_DMD + } + else + { /* In library, refer to it. + */ + fd = FuncDeclaration::genCfunc(type, ident); + } + *pfd = fd; // cache symbol in hash table +#elif IN_LLVM sv->ptrvalue = fd; // cache symbol in hash table +#endif } /* Call the function fd(arguments) @@ -438,6 +442,9 @@ X(Mod) X(Xor) X(And) X(Or) +#if DMDV2 +X(Pow) +#endif #undef X @@ -471,6 +478,9 @@ X(Mod) X(Xor) X(And) X(Or) +#if DMDV2 +X(Pow) +#endif #undef X @@ -526,7 +536,7 @@ Expression *AssignExp::buildArrayLoop(Parameters *fparams) ex2 = new CastExp(0, ex2, e1->type->nextOf()); #endif Expression *ex1 = e1->buildArrayLoop(fparams); - Parameter *param = (Parameter *)fparams->data[0]; + Parameter *param = (*fparams)[0]; param->storageClass = 0; Expression *e = new AssignExp(0, ex1, ex2); return e; @@ -539,7 +549,7 @@ Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \ */ \ Expression *ex2 = e2->buildArrayLoop(fparams); \ Expression *ex1 = e1->buildArrayLoop(fparams); \ - Parameter *param = (Parameter *)fparams->data[0]; \ + Parameter *param = (*fparams)[0]; \ param->storageClass = 0; \ Expression *e = new Str##AssignExp(0, ex1, ex2); \ return e; \ @@ -553,6 +563,9 @@ X(Mod) X(Xor) X(And) X(Or) +#if DMDV2 +X(Pow) +#endif #undef X @@ -589,6 +602,9 @@ X(Mod) X(Xor) X(And) X(Or) +#if DMDV2 +X(Pow) +#endif #undef X diff --git a/dmd/arraytypes.h b/dmd/arraytypes.h index ef3d6fe4..dc86bcff 100644 --- a/dmd/arraytypes.h +++ b/dmd/arraytypes.h @@ -26,26 +26,40 @@ struct FuncDeclaration; struct Identifier; struct Initializer; -struct TemplateParameters : Array { }; +typedef ArrayBase TemplateParameters; -struct Expressions : Array { }; +typedef ArrayBase Expressions; -struct Statements : Array { }; +typedef ArrayBase Statements; -struct BaseClasses : Array { }; +typedef ArrayBase BaseClasses; -struct ClassDeclarations : Array { }; +typedef ArrayBase ClassDeclarations; -struct Dsymbols : Array { }; +typedef ArrayBase Dsymbols; -struct Objects : Array { }; +typedef ArrayBase Objects; -struct FuncDeclarations : Array { }; +typedef ArrayBase FuncDeclarations; -struct Parameters : Array { }; +typedef ArrayBase Parameters; -struct Identifiers : Array { }; +typedef ArrayBase Identifiers; -struct Initializers : Array { }; +typedef ArrayBase Initializers; + +typedef ArrayBase VarDeclarations; + +typedef ArrayBase Types; + +typedef ArrayBase ScopeDsymbols; +typedef ArrayBase StaticDtorDeclarations; + +typedef ArrayBase SharedStaticDtorDeclarations; +typedef ArrayBase Modules; +typedef ArrayBase CaseStatements; +typedef ArrayBase TemplateInstances; + +typedef ArrayBase Symbols; #endif diff --git a/dmd/attrib.c b/dmd/attrib.c index 0e9b52fc..d839a671 100644 --- a/dmd/attrib.c +++ b/dmd/attrib.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -51,13 +51,13 @@ void obj_startaddress(Symbol *s); /********************************* AttribDeclaration ****************************/ -AttribDeclaration::AttribDeclaration(Array *decl) +AttribDeclaration::AttribDeclaration(Dsymbols *decl) : Dsymbol() { this->decl = decl; } -Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) +Dsymbols *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) { return decl; } @@ -65,12 +65,13 @@ Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { int m = 0; - Array *d = include(sc, sd); + Dsymbols *d = include(sc, sd); if (d) { for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; + //printf("\taddMember %s to %s\n", s->toChars(), sd->toChars()); m |= s->addMember(sc, sd, m | memnum); } } @@ -100,7 +101,7 @@ void AttribDeclaration::setScopeNewSc(Scope *sc, newsc->structalign = structalign; } for (unsigned i = 0; i < decl->dim; i++) - { Dsymbol *s = (Dsymbol *)decl->data[i]; + { Dsymbol *s = decl->tdata()[i]; s->setScope(newsc); // yes, the only difference from semanticNewSc() } @@ -135,7 +136,7 @@ void AttribDeclaration::semanticNewSc(Scope *sc, newsc->structalign = structalign; } for (unsigned i = 0; i < decl->dim; i++) - { Dsymbol *s = (Dsymbol *)decl->data[i]; + { Dsymbol *s = decl->tdata()[i]; s->semantic(newsc); } @@ -149,14 +150,14 @@ void AttribDeclaration::semanticNewSc(Scope *sc, void AttribDeclaration::semantic(Scope *sc) { - Array *d = include(sc, NULL); + Dsymbols *d = include(sc, NULL); //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); if (d) { - for (unsigned i = 0; i < d->dim; i++) + for (size_t i = 0; i < d->dim; i++) { - Dsymbol *s = (Dsymbol *)d->data[i]; + Dsymbol *s = d->tdata()[i]; s->semantic(sc); } @@ -165,12 +166,12 @@ void AttribDeclaration::semantic(Scope *sc) void AttribDeclaration::semantic2(Scope *sc) { - Array *d = include(sc, NULL); + Dsymbols *d = include(sc, NULL); if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = d->tdata()[i]; s->semantic2(sc); } } @@ -178,12 +179,12 @@ void AttribDeclaration::semantic2(Scope *sc) void AttribDeclaration::semantic3(Scope *sc) { - Array *d = include(sc, NULL); + Dsymbols *d = include(sc, NULL); if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = d->tdata()[i]; s->semantic3(sc); } } @@ -191,12 +192,12 @@ void AttribDeclaration::semantic3(Scope *sc) void AttribDeclaration::inlineScan() { - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); s->inlineScan(); } @@ -205,14 +206,15 @@ void AttribDeclaration::inlineScan() void AttribDeclaration::addComment(unsigned char *comment) { + //printf("AttribDeclaration::addComment %s\n", comment); if (comment) { - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; //printf("AttribDeclaration::addComment %s\n", s->toChars()); s->addComment(comment); } @@ -232,12 +234,12 @@ void AttribDeclaration::emitComment(Scope *sc) * Hence, Ddoc omits attributes from template members. */ - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; //printf("AttribDeclaration::emitComment %s\n", s->toChars()); s->emitComment(sc); } @@ -248,12 +250,12 @@ void AttribDeclaration::emitComment(Scope *sc) void AttribDeclaration::toObjFile(int multiobj) { - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; s->toObjFile(multiobj); } } @@ -263,12 +265,12 @@ int AttribDeclaration::cvMember(unsigned char *p) { int nwritten = 0; int n; - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; n = s->cvMember(p); if (p) p += n; @@ -281,13 +283,13 @@ int AttribDeclaration::cvMember(unsigned char *p) int AttribDeclaration::hasPointers() { - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { for (size_t i = 0; i < d->dim; i++) { - Dsymbol *s = (Dsymbol *)d->data[i]; + Dsymbol *s = d->tdata()[i]; if (s->hasPointers()) return 1; } @@ -295,6 +297,22 @@ int AttribDeclaration::hasPointers() return 0; } +bool AttribDeclaration::hasStaticCtorOrDtor() +{ + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (size_t i = 0; i < d->dim; i++) + { + Dsymbol *s = (*d)[i]; + if (s->hasStaticCtorOrDtor()) + return TRUE; + } + } + return FALSE; +} + const char *AttribDeclaration::kind() { return "attribute"; @@ -302,19 +320,19 @@ const char *AttribDeclaration::kind() int AttribDeclaration::oneMember(Dsymbol **ps) { - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); return Dsymbol::oneMembers(d, ps); } void AttribDeclaration::checkCtorConstInit() { - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; s->checkCtorConstInit(); } } @@ -325,12 +343,12 @@ void AttribDeclaration::checkCtorConstInit() void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) { - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; s->addLocalClass(aclasses); } } @@ -344,7 +362,7 @@ void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (decl->dim == 0) buf->writestring("{}"); else if (decl->dim == 1) - ((Dsymbol *)decl->data[0])->toCBuffer(buf, hgs); + (decl->tdata()[0])->toCBuffer(buf, hgs); else { buf->writenl(); @@ -352,7 +370,7 @@ void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); for (unsigned i = 0; i < decl->dim; i++) { - Dsymbol *s = (Dsymbol *)decl->data[i]; + Dsymbol *s = decl->tdata()[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -367,7 +385,7 @@ void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /************************* StorageClassDeclaration ****************************/ -StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Array *decl) +StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl) : AttribDeclaration(decl) { this->stc = stc; @@ -509,7 +527,7 @@ void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /********************************* LinkDeclaration ****************************/ -LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl) +LinkDeclaration::LinkDeclaration(enum LINK p, Dsymbols *decl) : AttribDeclaration(decl) { //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); @@ -552,7 +570,7 @@ void LinkDeclaration::semantic3(Scope *sc) sc->linkage = linkage; for (unsigned i = 0; i < decl->dim; i++) { - Dsymbol *s = (Dsymbol *)decl->data[i]; + Dsymbol *s = decl->tdata()[i]; s->semantic3(sc); } @@ -595,7 +613,7 @@ char *LinkDeclaration::toChars() /********************************* ProtDeclaration ****************************/ -ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl) +ProtDeclaration::ProtDeclaration(enum PROT p, Dsymbols *decl) : AttribDeclaration(decl) { protection = p; @@ -632,9 +650,9 @@ void ProtDeclaration::importAll(Scope *sc) newsc->explicitProtection = 1; } - for (int i = 0; i < decl->dim; i++) + for (size_t i = 0; i < decl->dim; i++) { - Dsymbol *s = (Dsymbol *)decl->data[i]; + Dsymbol *s = (*decl)[i]; s->importAll(newsc); } @@ -677,7 +695,7 @@ void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /********************************* AlignDeclaration ****************************/ -AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Array *decl) +AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl) : AttribDeclaration(decl) { this->loc = loc; @@ -721,7 +739,7 @@ void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /********************************* AnonDeclaration ****************************/ -AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl) +AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Dsymbols *decl) : AttribDeclaration(decl) { this->loc = loc; @@ -742,6 +760,12 @@ void AnonDeclaration::semantic(Scope *sc) { //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); + if (sem == 1) + { //printf("already completed\n"); + scope = NULL; + return; // semantic() already completed + } + Scope *scx = NULL; if (scope) { sc = scope; @@ -789,7 +813,7 @@ void AnonDeclaration::semantic(Scope *sc) for (unsigned i = 0; i < decl->dim; i++) { - Dsymbol *s = (Dsymbol *)decl->data[i]; + Dsymbol *s = decl->tdata()[i]; s->semantic(sc); if (isunion) @@ -882,7 +906,7 @@ void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { for (unsigned i = 0; i < decl->dim; i++) { - Dsymbol *s = (Dsymbol *)decl->data[i]; + Dsymbol *s = decl->tdata()[i]; //buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -912,7 +936,7 @@ static bool parseStringExp(Expression* e, std::string& res) return false; } -PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl) +PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl) : AttribDeclaration(decl) { this->loc = loc; @@ -942,15 +966,16 @@ void PragmaDeclaration::setScope(Scope *sc) } else { - Expression *e = (Expression *)args->data[0]; + Expression *e = args->tdata()[0]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) + args->tdata()[0] = e; + StringExp* se = e->toString(); + if (!se) { error("string expected, not '%s'", e->toChars()); } - PragmaScope* pragma = new PragmaScope(this, sc->parent, static_cast(e)); + PragmaScope* pragma = new PragmaScope(this, sc->parent, se); assert(sc); pragma->setScope(sc); @@ -980,13 +1005,13 @@ void PragmaDeclaration::semantic(Scope *sc) { for (size_t i = 0; i < args->dim; i++) { - Expression *e = (Expression *)args->data[i]; + Expression *e = args->tdata()[i]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKstring) + StringExp *se = e->toString(); + if (se) { - StringExp *se = (StringExp *)e; fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); } else @@ -1002,16 +1027,18 @@ void PragmaDeclaration::semantic(Scope *sc) error("string expected for library name"); else { - Expression *e = (Expression *)args->data[0]; + Expression *e = args->tdata()[0]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) + args->tdata()[0] = e; + if (e->op == TOKerror) + goto Lnodecl; + StringExp *se = e->toString(); + if (!se) 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; @@ -1043,10 +1070,11 @@ void PragmaDeclaration::semantic(Scope *sc) if (!d) error("first argument of GNU_asm must be a function or variable declaration"); - e = (Expression *)args->data[1]; + e = args->tdata()[1]; e = e->semantic(sc); e = e->optimize(WANTvalue); - if (e->op == TOKstring && ((StringExp *)e)->sz == 1) + e = e->toString(); + if (e && ((StringExp *)e)->sz == 1) s = ((StringExp *)e); else error("second argument of GNU_asm must be a char string"); @@ -1307,7 +1335,7 @@ void PragmaDeclaration::semantic(Scope *sc) { for (unsigned i = 0; i < decl->dim; i++) { - Dsymbol *s = (Dsymbol *)decl->data[i]; + Dsymbol *s = decl->tdata()[i]; s->semantic(sc); @@ -1492,7 +1520,7 @@ void PragmaDeclaration::toObjFile(int multiobj) * so instead append the library name to the list to be passed * to the linker. */ - global.params.libfiles->push((void *) name); + global.params.libfiles->push(name); #else error("pragma lib not supported"); #endif @@ -1533,7 +1561,7 @@ void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /********************************* ConditionalDeclaration ****************************/ -ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl) +ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl) : AttribDeclaration(decl) { //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); @@ -1558,7 +1586,7 @@ int ConditionalDeclaration::oneMember(Dsymbol **ps) //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); if (condition->inc) { - Array *d = condition->include(NULL, NULL) ? decl : elsedecl; + Dsymbols *d = condition->include(NULL, NULL) ? decl : elsedecl; return Dsymbol::oneMembers(d, ps); } *ps = NULL; @@ -1577,9 +1605,9 @@ void ConditionalDeclaration::emitComment(Scope *sc) /* If generating doc comment, be careful because if we're inside * a template, then include(NULL, NULL) will fail. */ - Array *d = decl ? decl : elsedecl; + Dsymbols *d = decl ? decl : elsedecl; for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; s->emitComment(sc); } } @@ -1587,7 +1615,7 @@ void ConditionalDeclaration::emitComment(Scope *sc) // Decide if 'then' or 'else' code should be included -Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) +Dsymbols *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) { //printf("ConditionalDeclaration::include()\n"); assert(condition); @@ -1596,14 +1624,14 @@ Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) void ConditionalDeclaration::setScope(Scope *sc) { - Array *d = include(sc, NULL); + Dsymbols *d = include(sc, NULL); //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d); if (d) { for (unsigned i = 0; i < d->dim; i++) { - Dsymbol *s = (Dsymbol *)d->data[i]; + Dsymbol *s = d->tdata()[i]; s->setScope(sc); } @@ -1612,14 +1640,14 @@ void ConditionalDeclaration::setScope(Scope *sc) void ConditionalDeclaration::importAll(Scope *sc) { - Array *d = include(sc, NULL); + Dsymbols *d = include(sc, NULL); //printf("\tConditionalDeclaration::importAll '%s', d = %p\n",toChars(), d); if (d) { for (unsigned i = 0; i < d->dim; i++) { - Dsymbol *s = (Dsymbol *)d->data[i]; + Dsymbol *s = d->tdata()[i]; s->importAll(sc); } @@ -1636,7 +1664,7 @@ void ConditionalDeclaration::addComment(unsigned char *comment) if (comment) { - Array *d = decl; + Dsymbols *d = decl; for (int j = 0; j < 2; j++) { @@ -1645,7 +1673,7 @@ void ConditionalDeclaration::addComment(unsigned char *comment) for (unsigned i = 0; i < d->dim; i++) { Dsymbol *s; - s = (Dsymbol *)d->data[i]; + s = d->tdata()[i]; //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); s->addComment(comment); } @@ -1667,7 +1695,7 @@ void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { for (unsigned i = 0; i < decl->dim; i++) { - Dsymbol *s = (Dsymbol *)decl->data[i]; + Dsymbol *s = decl->tdata()[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -1683,7 +1711,7 @@ void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); for (unsigned i = 0; i < elsedecl->dim; i++) { - Dsymbol *s = (Dsymbol *)elsedecl->data[i]; + Dsymbol *s = elsedecl->tdata()[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -1699,7 +1727,7 @@ void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /***************************** StaticIfDeclaration ****************************/ StaticIfDeclaration::StaticIfDeclaration(Condition *condition, - Array *decl, Array *elsedecl) + Dsymbols *decl, Dsymbols *elsedecl) : ConditionalDeclaration(condition, decl, elsedecl) { //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); @@ -1757,7 +1785,7 @@ void StaticIfDeclaration::setScope(Scope *sc) void StaticIfDeclaration::semantic(Scope *sc) { - Array *d = include(sc, sd); + Dsymbols *d = include(sc, sd); //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); if (d) @@ -1769,7 +1797,7 @@ void StaticIfDeclaration::semantic(Scope *sc) for (unsigned i = 0; i < d->dim; i++) { - Dsymbol *s = (Dsymbol *)d->data[i]; + Dsymbol *s = d->tdata()[i]; s->semantic(sc); } @@ -1821,12 +1849,12 @@ void CompileDeclaration::compileIt(Scope *sc) exp = exp->semantic(sc); exp = resolveProperties(sc, exp); exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring) + StringExp *se = exp->toString(); + if (!se) { 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; diff --git a/dmd/attrib.h b/dmd/attrib.h index 365a0936..a92717dc 100644 --- a/dmd/attrib.h +++ b/dmd/attrib.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -23,18 +23,16 @@ struct LabelDsymbol; struct Initializer; struct Module; struct Condition; -#ifdef _DH struct HdrGenState; -#endif /**************************************************************/ struct AttribDeclaration : Dsymbol { - Array *decl; // array of Dsymbol's + Dsymbols *decl; // array of Dsymbol's - AttribDeclaration(Array *decl); - virtual Array *include(Scope *sc, ScopeDsymbol *s); + AttribDeclaration(Dsymbols *decl); + virtual Dsymbols *include(Scope *sc, ScopeDsymbol *s); int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void setScopeNewSc(Scope *sc, StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, @@ -51,6 +49,7 @@ struct AttribDeclaration : Dsymbol const char *kind(); int oneMember(Dsymbol **ps); int hasPointers(); + bool hasStaticCtorOrDtor(); void checkCtorConstInit(); void addLocalClass(ClassDeclarations *); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -71,7 +70,7 @@ struct StorageClassDeclaration: AttribDeclaration { StorageClass stc; - StorageClassDeclaration(StorageClass stc, Array *decl); + StorageClassDeclaration(StorageClass stc, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void setScope(Scope *sc); void semantic(Scope *sc); @@ -84,7 +83,7 @@ struct LinkDeclaration : AttribDeclaration { enum LINK linkage; - LinkDeclaration(enum LINK p, Array *decl); + LinkDeclaration(enum LINK p, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void setScope(Scope *sc); void semantic(Scope *sc); @@ -97,7 +96,7 @@ struct ProtDeclaration : AttribDeclaration { enum PROT protection; - ProtDeclaration(enum PROT p, Array *decl); + ProtDeclaration(enum PROT p, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void importAll(Scope *sc); void setScope(Scope *sc); @@ -111,7 +110,7 @@ struct AlignDeclaration : AttribDeclaration { unsigned salign; - AlignDeclaration(Loc loc, unsigned sa, Array *decl); + AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void setScope(Scope *sc); void semantic(Scope *sc); @@ -123,7 +122,7 @@ struct AnonDeclaration : AttribDeclaration int isunion; int sem; // 1 if successful semantic() - AnonDeclaration(Loc loc, int isunion, Array *decl); + AnonDeclaration(Loc loc, int isunion, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -134,7 +133,7 @@ struct PragmaDeclaration : AttribDeclaration { Expressions *args; // array of Expression's - PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl); + PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void setScope(Scope *sc); @@ -154,13 +153,13 @@ struct PragmaDeclaration : AttribDeclaration struct ConditionalDeclaration : AttribDeclaration { Condition *condition; - Array *elsedecl; // array of Dsymbol's for else block + Dsymbols *elsedecl; // array of Dsymbol's for else block - ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl); + ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); Dsymbol *syntaxCopy(Dsymbol *s); int oneMember(Dsymbol **ps); void emitComment(Scope *sc); - Array *include(Scope *sc, ScopeDsymbol *s); + Dsymbols *include(Scope *sc, ScopeDsymbol *s); void addComment(unsigned char *comment); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toJsonBuffer(OutBuffer *buf); @@ -173,7 +172,7 @@ struct StaticIfDeclaration : ConditionalDeclaration ScopeDsymbol *sd; int addisdone; - StaticIfDeclaration(Condition *condition, Array *decl, Array *elsedecl); + StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); Dsymbol *syntaxCopy(Dsymbol *s); int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void semantic(Scope *sc); diff --git a/dmd/cast.c b/dmd/cast.c index 23f653c1..8a5a6622 100644 --- a/dmd/cast.c +++ b/dmd/cast.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -123,6 +123,8 @@ MATCH Expression::implicitConvTo(Type *t) toChars(), type->toChars(), t->toChars()); #endif //static int nest; if (++nest == 10) halt(); + if (t == Type::terror) + return MATCHnomatch; if (!type) { error("%s is not an expression", toChars()); type = Type::terror; @@ -377,8 +379,8 @@ MATCH StructLiteralExp::implicitConvTo(Type *t) ((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym) { m = MATCHconst; - for (int i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (*elements)[i]; Type *te = e->type; if (t->mod == 0) te = te->mutableOf(); @@ -397,8 +399,7 @@ MATCH StructLiteralExp::implicitConvTo(Type *t) #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()); @@ -466,14 +467,18 @@ MATCH ArrayLiteralExp::implicitConvTo(Type *t) result = MATCHnomatch; } - for (int i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (*elements)[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 } + + if (!result) + result = type->implicitConvTo(t); + return result; } else @@ -581,7 +586,6 @@ MATCH DelegateExp::implicitConvTo(Type *t) if (result == 0) { // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; t = t->toBasetype(); if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction && @@ -663,6 +667,12 @@ Expression *Expression::castTo(Scope *sc, Type *t) } +Expression *ErrorExp::castTo(Scope *sc, Type *t) +{ + return this; +} + + Expression *RealExp::castTo(Scope *sc, Type *t) { Expression *e = this; if (type != t) @@ -745,8 +755,6 @@ Expression *StringExp::castTo(Scope *sc, Type *t) * 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); @@ -757,7 +765,7 @@ Expression *StringExp::castTo(Scope *sc, Type *t) return new ErrorExp(); } - se = this; + StringExp *se = this; if (!committed) { se = (StringExp *)copy(); se->committed = 1; @@ -769,7 +777,7 @@ Expression *StringExp::castTo(Scope *sc, Type *t) return se; } - tb = t->toBasetype(); + Type *tb = t->toBasetype(); //printf("\ttype = %s\n", type->toChars()); if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) return Expression::castTo(sc, t); @@ -913,7 +921,11 @@ Expression *StringExp::castTo(Scope *sc, Type *t) } se->string = buffer.extractData(); se->len = newlen; - se->sz = tb->nextOf()->size(); + { + d_uns64 szx = tb->nextOf()->size(); + assert(szx <= 255); + se->sz = (unsigned char)szx; + } break; default: @@ -928,9 +940,9 @@ L2: // See if need to truncate or extend the literal if (tb->ty == Tsarray) { - int dim2 = ((TypeSArray *)tb)->dim->toInteger(); + dinteger_t dim2 = ((TypeSArray *)tb)->dim->toInteger(); - //printf("dim from = %d, to = %d\n", se->len, dim2); + //printf("dim from = %d, to = %d\n", (int)se->len, (int)dim2); // Changing dimensions if (dim2 != se->len) @@ -1038,10 +1050,10 @@ Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) e = (ArrayLiteralExp *)copy(); e->elements = (Expressions *)elements->copy(); - for (int i = 0; i < elements->dim; i++) - { Expression *ex = (Expression *)elements->data[i]; + for (size_t i = 0; i < elements->dim; i++) + { Expression *ex = (*elements)[i]; ex = ex->castTo(sc, tb->nextOf()); - e->elements->data[i] = (void *)ex; + (*e->elements)[i] = ex; } e->type = t; return e; @@ -1081,7 +1093,6 @@ Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) e->type = t; return e; } -L1: return e->Expression::castTo(sc, t); } diff --git a/dmd/class.c b/dmd/class.c index b373db2a..988dccd1 100644 --- a/dmd/class.c +++ b/dmd/class.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -31,6 +31,7 @@ ClassDeclaration *ClassDeclaration::classinfo; ClassDeclaration *ClassDeclaration::object; +ClassDeclaration *ClassDeclaration::errorException; ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) : AggregateDeclaration(loc, id) @@ -170,6 +171,12 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla Type::typeinfoshared->error("%s", msg); Type::typeinfoshared = this; } + + if (id == Id::TypeInfo_Wild) + { if (Type::typeinfowild) + Type::typeinfowild->error("%s", msg); + Type::typeinfowild = this; + } #endif } @@ -179,6 +186,12 @@ ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *basecla object = this; } + if (id == Id::Error) + { if (errorException) + errorException->error("%s", msg); + errorException = this; + } + if (id == Id::ClassInfo) { if (classinfo) classinfo->error("%s", msg); @@ -213,7 +226,7 @@ Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) cd->storage_class |= storage_class; cd->baseclasses->setDim(this->baseclasses->dim); - for (int i = 0; i < cd->baseclasses->dim; i++) + for (size_t i = 0; i < cd->baseclasses->dim; i++) { BaseClass *b = (BaseClass *)this->baseclasses->data[i]; BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); @@ -225,9 +238,7 @@ Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) } 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); @@ -278,7 +289,7 @@ void ClassDeclaration::semantic(Scope *sc) } // Expand any tuples in baseclasses[] - for (i = 0; i < baseclasses->dim; ) + for (size_t i = 0; i < baseclasses->dim; ) { BaseClass *b = (BaseClass *)baseclasses->data[i]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); @@ -368,7 +379,7 @@ void ClassDeclaration::semantic(Scope *sc) // Treat the remaining entries in baseclasses as interfaces // Check for errors, handle forward references - for (i = (baseClass ? 1 : 0); i < baseclasses->dim; ) + for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; ) { TypeClass *tc; BaseClass *b; Type *tb; @@ -490,7 +501,7 @@ void ClassDeclaration::semantic(Scope *sc) { interfaceSemantic(sc); - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->addMember(sc, this, 1); @@ -536,9 +547,9 @@ void ClassDeclaration::semantic(Scope *sc) if (ad) t = ad->handle; else if (fd) - { AggregateDeclaration *ad = fd->isMember2(); - if (ad) - t = ad->handle; + { AggregateDeclaration *ad2 = fd->isMember2(); + if (ad2) + t = ad2->handle; else { t = new TypePointer(Type::tvoid); @@ -594,13 +605,13 @@ void ClassDeclaration::semantic(Scope *sc) } structsize = sc->offset; Scope scsave = *sc; - int members_dim = members->dim; + size_t members_dim = members->dim; sizeok = 0; /* Set scope so if there are forward references, we still might be able to * resolve individual members like enums. */ - for (i = 0; i < members_dim; i++) + for (size_t i = 0; i < members_dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; /* There are problems doing this in the general case because * Scope keeps track of things like 'offset' @@ -612,7 +623,7 @@ void ClassDeclaration::semantic(Scope *sc) } } - for (i = 0; i < members_dim; i++) + for (size_t i = 0; i < members_dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->semantic(sc); } @@ -688,7 +699,7 @@ void ClassDeclaration::semantic(Scope *sc) #endif // Allocate instance of each new interface - for (i = 0; i < vtblInterfaces->dim; i++) + for (size_t i = 0; i < vtblInterfaces->dim; i++) { BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; unsigned thissize = PTRSIZE; @@ -737,7 +748,7 @@ void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (baseclasses->dim) buf->writestring(" : "); } - for (int i = 0; i < baseclasses->dim; i++) + for (size_t i = 0; i < baseclasses->dim; i++) { BaseClass *b = (BaseClass *)baseclasses->data[i]; @@ -751,7 +762,7 @@ void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); buf->writeByte('{'); buf->writenl(); - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; @@ -787,7 +798,7 @@ 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++) + for (size_t i = 0; i < cd->baseclasses->dim; i++) { BaseClass *b = (BaseClass *)cd->baseclasses->data[i]; if (b->base == this || isBaseOf2(b->base)) @@ -807,16 +818,18 @@ int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *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->semantic(NULL); + if (!cd->baseClass) cd->error("base class is forward referenced by %s", toChars()); } + if (this == cd->baseClass) + return 1; + cd = cd->baseClass; } return 0; @@ -831,7 +844,7 @@ int ClassDeclaration::isBaseInfoComplete() { if (!baseClass) return ident == Id::Object; - for (int i = 0; i < baseclasses->dim; i++) + for (size_t i = 0; i < baseclasses->dim; i++) { BaseClass *b = (BaseClass *)baseclasses->data[i]; if (!b->base || !b->base->isBaseInfoComplete()) return 0; @@ -844,14 +857,14 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) Dsymbol *s; //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); - if (scope) + if (scope && !symtab) { Scope *sc = scope; sc->mustsemantic++; semantic(sc); sc->mustsemantic--; } - if (!members || !symtab || scope) + if (!members || !symtab) { error("is forward referenced when looking for '%s'", ident->toChars()); //*(char*)0=0; @@ -863,9 +876,7 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) { // Search bases classes in depth-first, left to right order - int i; - - for (i = 0; i < baseclasses->dim; i++) + for (size_t i = 0; i < baseclasses->dim; i++) { BaseClass *b = (BaseClass *)baseclasses->data[i]; @@ -912,7 +923,10 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) } FuncDeclaration *fdstart = s->toAlias()->isFuncDeclaration(); //printf("%s fdstart = %p\n", s->kind(), fdstart); - return !overloadApply(getModule(), fdstart, &isf, fd); + if (overloadApply(fdstart, &isf, fd)) + return 0; + + return !fd->parent->isTemplateMixin(); } #endif @@ -924,24 +938,58 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) { //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); + FuncDeclaration *fdmatch = NULL; + FuncDeclaration *fdambig = NULL; ClassDeclaration *cd = this; - Array *vtbl = &cd->vtbl; + Dsymbols *vtbl = &cd->vtbl; while (1) { for (size_t i = 0; i < vtbl->dim; i++) { - FuncDeclaration *fd = ((Dsymbol*)vtbl->data[i])->isFuncDeclaration(); + FuncDeclaration *fd = (*vtbl)[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; + fd->type->covariant(tf) == 1) + { //printf("fd->parent->isClassDeclaration() = %p", fd->parent->isClassDeclaration()); + if (!fdmatch) + goto Lfd; + + { + // Function type matcing: exact > covariant + int m1 = tf->equals(fd ->type) ? MATCHexact : MATCHnomatch; + int m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch; + if (m1 > m2) + goto Lfd; + else if (m1 < m2) + goto Lfdmatch; + } + + { + // The way of definition: non-mixin > mixin + int m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; + int m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; + if (m1 > m2) + goto Lfd; + else if (m1 < m2) + goto Lfdmatch; + } + + Lambig: + fdambig = fd; + //printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars()); + continue; + + Lfd: + fdmatch = fd, fdambig = NULL; + //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars()); + continue; + + Lfdmatch: + continue; } //else printf("\t\t%d\n", fd->type->covariant(tf)); } @@ -951,7 +999,9 @@ FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) cd = cd->baseClass; } - return NULL; + if (fdambig) + error("ambiguous virtual function %s", fdambig->toChars()); + return fdmatch; } void ClassDeclaration::interfaceSemantic(Scope *sc) @@ -1001,7 +1051,7 @@ int ClassDeclaration::isAbstract() { if (isabstract) return TRUE; - for (int i = 1; i < vtbl.dim; i++) + for (size_t i = 1; i < vtbl.dim; i++) { FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration(); @@ -1078,8 +1128,7 @@ Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) } void InterfaceDeclaration::semantic(Scope *sc) -{ int i; - +{ //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); if (inuse) return; @@ -1116,7 +1165,7 @@ void InterfaceDeclaration::semantic(Scope *sc) } // Expand any tuples in baseclasses[] - for (i = 0; i < baseclasses->dim; ) + for (size_t i = 0; i < baseclasses->dim; ) { BaseClass *b = (BaseClass *)baseclasses->data[0]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); @@ -1137,7 +1186,7 @@ void InterfaceDeclaration::semantic(Scope *sc) } // Check for errors, handle forward references - for (i = 0; i < baseclasses->dim; ) + for (size_t i = 0; i < baseclasses->dim; ) { TypeClass *tc; BaseClass *b; Type *tb; @@ -1200,11 +1249,11 @@ void InterfaceDeclaration::semantic(Scope *sc) 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++) + for (size_t i = 0; i < interfaces_dim; i++) { BaseClass *b = interfaces[i]; // Skip if b has already appeared - for (int k = 0; k < i; k++) + for (size_t k = 0; k < i; k++) { if (b == interfaces[k]) goto Lcontinue; @@ -1212,12 +1261,12 @@ void InterfaceDeclaration::semantic(Scope *sc) // Copy vtbl[] from base class if (b->base->vtblOffset()) - { int d = b->base->vtbl.dim; + { size_t 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]); + for (size_t j = 1; j < d; j++) + vtbl.push((Dsymbol *)b->base->vtbl.data[j]); } } else @@ -1229,23 +1278,26 @@ void InterfaceDeclaration::semantic(Scope *sc) ; } - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = (*members)[i]; s->addMember(sc, this, 1); } sc = sc->push(this); + sc->stc &= STCsafe | STCtrusted | STCsystem; sc->parent = this; if (isCOMinterface()) sc->linkage = LINKwindows; sc->structalign = 8; + sc->protection = PROTpublic; + sc->explicitProtection = 0; structalign = sc->structalign; sc->offset = PTRSIZE * 2; inuse++; - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = (*members)[i]; s->semantic(sc); } inuse--; @@ -1338,7 +1390,7 @@ int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) int InterfaceDeclaration::isBaseInfoComplete() { assert(!baseClass); - for (int i = 0; i < baseclasses->dim; i++) + for (size_t i = 0; i < baseclasses->dim; i++) { BaseClass *b = (BaseClass *)baseclasses->data[i]; if (!b->base || !b->base->isBaseInfoComplete ()) return 0; @@ -1411,10 +1463,9 @@ BaseClass::BaseClass(Type *type, enum PROT protection) * by base classes) */ -int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance) +int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance) { ClassDeclaration *id = base; - int j; int result = 0; //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); @@ -1422,7 +1473,7 @@ int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance) vtbl->setDim(base->vtbl.dim); // first entry is ClassInfo reference - for (j = base->vtblOffset(); j < base->vtbl.dim; j++) + for (size_t j = base->vtblOffset(); j < base->vtbl.dim; j++) { FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration(); FuncDeclaration *fd; diff --git a/dmd/clone.c b/dmd/clone.c index 05aede20..320390c7 100644 --- a/dmd/clone.c +++ b/dmd/clone.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -39,7 +39,7 @@ Expression *StructDeclaration::cloneMembers() VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); Type *tv = v->type->toBasetype(); - size_t dim = 1; + dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; dim *= ((TypeSArray *)tv)->dim->toInteger(); @@ -49,10 +49,10 @@ Expression *StructDeclaration::cloneMembers() { TypeStruct *ts = (TypeStruct *)tv; StructDeclaration *sd = ts->sym; if (sd->opclone) - { Expression *ex; + { // this.v - ex = new ThisExp(0); + Expression *ex = new ThisExp(0); ex = new DotVarExp(0, ex, v, 0); if (dim == 1) @@ -96,7 +96,7 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) VarDeclaration *v = s->isVarDeclaration(); assert(v && v->storage_class & STCfield); Type *tv = v->type->toBasetype(); - size_t dim = 1; + dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; dim *= ((TypeSArray *)tv)->dim->toInteger(); @@ -139,7 +139,7 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) */ if (e) { //printf("Building __fieldDtor()\n"); - DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor")); + DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__fieldDtor")); dd->fbody = new ExpStatement(0, e); dtors.shift(dd); members->push(dd); @@ -164,7 +164,7 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) ex = new CallExp(0, ex); e = Expression::combine(ex, e); } - DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor")); + DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__aggrDtor")); dd->fbody = new ExpStatement(0, e); members->push(dd); dd->semantic(sc); diff --git a/dmd/cond.c b/dmd/cond.c index 4f0ac8da..ba6657d4 100644 --- a/dmd/cond.c +++ b/dmd/cond.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -20,18 +20,17 @@ #include "module.h" #include "template.h" #include "lexer.h" -#ifdef _DH #include "mtype.h" #include "scope.h" -#endif +#include "arraytypes.h" -int findCondition(Array *ids, Identifier *ident) +int findCondition(Strings *ids, Identifier *ident) { if (ids) { - for (int i = 0; i < ids->dim; i++) + for (size_t i = 0; i < ids->dim; i++) { - const char *id = (const char *)ids->data[i]; + const char *id = (*ids)[i]; if (strcmp(id, ident->toChars()) == 0) return TRUE; @@ -74,8 +73,8 @@ void DebugCondition::setGlobalLevel(unsigned level) void DebugCondition::addGlobalIdent(const char *ident) { if (!global.params.debugids) - global.params.debugids = new Array(); - global.params.debugids->push((void *)ident); + global.params.debugids = new Strings(); + global.params.debugids->push((char *)ident); } @@ -98,7 +97,7 @@ int DebugCondition::include(Scope *sc, ScopeDsymbol *s) inc = 1; else { if (!mod->debugidsNot) - mod->debugidsNot = new Array(); + mod->debugidsNot = new Strings(); mod->debugidsNot->push(ident->toChars()); } } @@ -135,8 +134,10 @@ void VersionCondition::checkPredefined(Loc loc, const char *ident) * redefinition breaks makefiles and older builds. */ "Posix", + "D_NET", #endif "OSX", "FreeBSD", + "OpenBSD", "Solaris", "LittleEndian", "BigEndian", "all", @@ -173,8 +174,8 @@ void VersionCondition::addGlobalIdent(const char *ident) void VersionCondition::addPredefinedGlobalIdent(const char *ident) { if (!global.params.versionids) - global.params.versionids = new Array(); - global.params.versionids->push((void *)ident); + global.params.versionids = new Strings(); + global.params.versionids->push((char *)ident); } @@ -199,7 +200,7 @@ int VersionCondition::include(Scope *sc, ScopeDsymbol *s) else { if (!mod->versionidsNot) - mod->versionidsNot = new Array(); + mod->versionidsNot = new Strings(); mod->versionidsNot->push(ident->toChars()); } } @@ -307,13 +308,14 @@ int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) 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; + Type *t = targ->trySemantic(loc, sc); + if (t) + targ = t; + else + inc = 2; // condition is false + + if (!t) + { } else if (id && tspec) { @@ -326,19 +328,19 @@ int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) TemplateParameters parameters; parameters.setDim(1); - parameters.data[0] = (void *)&tp; + parameters[0] = &tp; Objects dedtypes; dedtypes.setDim(1); - m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes); + m = targ->deduceType(sc, tspec, ¶meters, &dedtypes); if (m == MATCHnomatch || (m != MATCHexact && tok == TOKequal)) inc = 2; else { inc = 1; - Type *tded = (Type *)dedtypes.data[0]; + Type *tded = (Type *)dedtypes[0]; if (!tded) tded = targ; Dsymbol *s = new AliasDeclaration(loc, id, tded); diff --git a/dmd/cond.h b/dmd/cond.h index 12eb5068..4da14195 100644 --- a/dmd/cond.h +++ b/dmd/cond.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -17,15 +17,12 @@ struct OutBuffer; struct Module; struct Scope; struct ScopeDsymbol; -#ifdef _DH +struct DebugCondition; #include "lexer.h" // dmdhg -#endif enum TOK; -#ifdef _DH struct HdrGenState; -#endif -int findCondition(Array *ids, Identifier *ident); +int findCondition(Strings *ids, Identifier *ident); struct Condition { diff --git a/dmd/constfold.c b/dmd/constfold.c index 83075573..85ee51f9 100644 --- a/dmd/constfold.c +++ b/dmd/constfold.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -36,12 +36,10 @@ extern "C" bool real_isnan (const real_t *); static real_t zero; // work around DMC bug for now -#if __FreeBSD__ -#define fmodl fmod // hack for now, fix later -#endif - #define LOG 0 +int RealEquals(real_t x1, real_t x2); + Expression *expType(Type *type, Expression *e) { if (type != e->type) @@ -495,7 +493,7 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2) { real_t r2 = e2->toReal(); #ifdef __DMC__ - c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I; + c = Port::fmodl(e1->toReal(), r2) + Port::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__) @@ -503,14 +501,14 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2) // 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)); + c = complex_t(Port::fmodl(e1->toReal(), r2), Port::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; + c = Port::fmodl(e1->toReal(), i2) + Port::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__) @@ -518,7 +516,7 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2) // 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)); + c = complex_t(Port::fmodl(e1->toReal(), i2), Port::fmodl(e1->toImaginary(), i2)); #endif } else @@ -545,6 +543,21 @@ Expression *Mod(Type *type, Expression *e1, Expression *e2) e2 = new IntegerExp(loc, 1, e2->type); n2 = 1; } + if (n2 == -1 && !type->isunsigned()) + { // Check for int.min % -1 + if (n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64) + { + e2->error("integer overflow: int.min % -1"); + e2 = new IntegerExp(loc, 1, e2->type); + n2 = 1; + } + else if (n1 == 0x8000000000000000LL) // long.min % -1 + { + e2->error("integer overflow: long.min % -1"); + e2 = new IntegerExp(loc, 1, e2->type); + n2 = 1; + } + } if (e1->type->isunsigned() || e2->type->isunsigned()) n = ((d_uns64) n1) % ((d_uns64) n2); else @@ -567,7 +580,9 @@ Expression *Shr(Type *type, Expression *e1, Expression *e2) Loc loc = e1->loc; dinteger_t value = e1->toInteger(); - unsigned count = e2->toInteger(); + dinteger_t dcount = e2->toInteger(); + assert(dcount <= 0xFFFFFFFF); + unsigned count = (unsigned)dcount; switch (e1->type->toBasetype()->ty) { case Tint8: @@ -575,6 +590,7 @@ Expression *Shr(Type *type, Expression *e1, Expression *e2) break; case Tuns8: + case Tchar: value = (d_uns8)(value) >> count; break; @@ -583,6 +599,7 @@ Expression *Shr(Type *type, Expression *e1, Expression *e2) break; case Tuns16: + case Twchar: value = (d_uns16)(value) >> count; break; @@ -591,6 +608,7 @@ Expression *Shr(Type *type, Expression *e1, Expression *e2) break; case Tuns32: + case Tdchar: value = (d_uns32)(value) >> count; break; @@ -617,23 +635,28 @@ Expression *Ushr(Type *type, Expression *e1, Expression *e2) Loc loc = e1->loc; dinteger_t value = e1->toInteger(); - unsigned count = e2->toInteger(); + dinteger_t dcount = e2->toInteger(); + assert(dcount <= 0xFFFFFFFF); + unsigned count = (unsigned)dcount; switch (e1->type->toBasetype()->ty) { case Tint8: case Tuns8: - assert(0); // no way to trigger this + case Tchar: + // Possible only with >>>=. >>> always gets promoted to int. value = (value & 0xFF) >> count; break; case Tint16: case Tuns16: - assert(0); // no way to trigger this + case Twchar: + // Possible only with >>>=. >>> always gets promoted to int. value = (value & 0xFFFF) >> count; break; case Tint32: case Tuns32: + case Tdchar: value = (value & 0xFFFFFFFF) >> count; break; @@ -741,8 +764,8 @@ Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) 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 *ee1 = (*es1->elements)[i]; + Expression *ee2 = (*es2->elements)[i]; Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); if (v == EXP_CANT_INTERPRET) @@ -755,9 +778,9 @@ Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) } else if (e1->op == TOKarrayliteral && e2->op == TOKstring) { // Swap operands and use common code - Expression *e = e1; + Expression *etmp = e1; e1 = e2; - e2 = e; + e2 = etmp; goto Lsa; } else if (e1->op == TOKstring && e2->op == TOKarrayliteral) @@ -771,10 +794,11 @@ Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) cmp = 0; else { + cmp = 1; // if dim1 winds up being 0 for (size_t i = 0; i < dim1; i++) { uinteger_t c = es1->charAt(i); - Expression *ee2 = (Expression *)es2->elements->data[i]; + Expression *ee2 = (*es2->elements)[i]; if (ee2->isConst() != 1) return EXP_CANT_INTERPRET; cmp = (c == ee2->toInteger()); @@ -800,8 +824,8 @@ Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) { 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]; + { Expression *ee1 = (*es1->elements)[i]; + Expression *ee2 = (*es2->elements)[i]; if (ee1 == ee2) continue; @@ -885,11 +909,11 @@ Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) cmp = (es1->var == es2->var && es1->offset == es2->offset); } - else if (e1->isConst() == 1 && e2->isConst() == 1) + else + { return Equal((op == TOKidentity) ? TOKequal : TOKnotequal, type, e1, e2); - else - assert(0); + } if (op == TOKnotidentity) cmp ^= 1; return new IntegerExp(loc, cmp, type); @@ -1134,7 +1158,7 @@ Expression *Cast(Type *type, Type *to, Expression *e1) assert(sd); Expressions *elements = new Expressions; for (size_t i = 0; i < sd->fields.dim; i++) - { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + { Dsymbol *s = sd->fields.tdata()[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); @@ -1197,10 +1221,13 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) uinteger_t i = e2->toInteger(); if (i >= es1->len) + { e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len); + e = new ErrorExp(); + } else - { unsigned value = es1->charAt(i); - e = new IntegerExp(loc, value, type); + { + e = new IntegerExp(loc, es1->charAt(i), type); } } else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64) @@ -1209,30 +1236,38 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) uinteger_t i = e2->toInteger(); if (i >= length) - { e2->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length); + { + e1->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length); + e = new ErrorExp(); } - else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) + else if (e1->op == TOKarrayliteral) { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - e = (Expression *)ale->elements->data[i]; + e = ale->elements->tdata()[i]; e->type = type; + if (e->checkSideEffect(2)) + e = EXP_CANT_INTERPRET; } } else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64) { uinteger_t i = e2->toInteger(); - if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) + if (e1->op == TOKarrayliteral) { 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); + { + e1->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); + e = new ErrorExp(); } else - { e = (Expression *)ale->elements->data[i]; + { e = ale->elements->tdata()[i]; e->type = type; + if (e->checkSideEffect(2)) + e = EXP_CANT_INTERPRET; } } } - else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2)) + else if (e1->op == TOKassocarrayliteral) { AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1; /* Search the keys backwards, in case there are duplicate keys @@ -1240,13 +1275,15 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) for (size_t i = ae->keys->dim; i;) { i--; - Expression *ekey = (Expression *)ae->keys->data[i]; + Expression *ekey = ae->keys->tdata()[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 = ae->values->tdata()[i]; e->type = type; + if (e->checkSideEffect(2)) + e = EXP_CANT_INTERPRET; break; } } @@ -1274,9 +1311,12 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) uinteger_t iupr = upr->toInteger(); if (iupr > es1->len || ilwr > iupr) + { e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr); + e = new ErrorExp(); + } else - { dinteger_t value; + { void *s; size_t len = iupr - ilwr; int sz = es1->sz; @@ -1301,14 +1341,17 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) uinteger_t iupr = upr->toInteger(); if (iupr > es1->elements->dim || ilwr > iupr) + { e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr); + e = new ErrorExp(); + } else { Expressions *elements = new Expressions(); elements->setDim(iupr - ilwr); - memcpy(elements->data, - es1->elements->data + ilwr, - (iupr - ilwr) * sizeof(es1->elements->data[0])); + memcpy(elements->tdata(), + es1->elements->tdata() + ilwr, + (iupr - ilwr) * sizeof(es1->elements->tdata()[0])); e = new ArrayLiteralExp(e1->loc, elements); e->type = type; } @@ -1349,8 +1392,11 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) dinteger_t v = e->toInteger(); - size_t len = utf_codeLength(sz, v); + size_t len = (t->ty == tn->ty) ? 1 : utf_codeLength(sz, v); s = mem.malloc((len + 1) * sz); + if (t->ty == tn->ty) + memcpy((unsigned char *)s, &v, sz); + else utf_encode(sz, s, v); // Add terminating 0 @@ -1370,6 +1416,24 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) e->type = type; return e; } + else if (e1->op == TOKnull && e2->op == TOKnull) + { + if (type == e1->type) + { + // Handle null ~= null + if (t1->ty == Tarray && t2 == t1->nextOf()) + { + e = new ArrayLiteralExp(e1->loc, e2); + e->type = type; + return e; + } + else + return e1; + } + if (type == e2->type) + return e2; + return new NullExp(e1->loc, type); + } else if (e1->op == TOKstring && e2->op == TOKstring) { // Concatenate the strings @@ -1377,7 +1441,6 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) StringExp *es1 = (StringExp *)e1; StringExp *es2 = (StringExp *)e2; StringExp *es; - Type *t; size_t len = es1->len + es2->len; int sz = es1->sz; @@ -1399,10 +1462,62 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) 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 (e2->op == TOKstring && e1->op == TOKarrayliteral && + t1->nextOf()->isintegral()) + { + // Concatenate the strings + StringExp *es1 = (StringExp *)e2; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1; + size_t len = es1->len + es2->elements->dim; + int sz = es1->sz; + + void *s = mem.malloc((len + 1) * sz); + memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz); + for (size_t i = 0; i < es2->elements->dim; i++) + { Expression *es2e = es2->elements->tdata()[i]; + if (es2e->op != TOKint64) + return EXP_CANT_INTERPRET; + dinteger_t v = es2e->toInteger(); + memcpy((unsigned char *)s + i * sz, &v, sz); + } + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + StringExp *es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = 0; + es->type = type; + e = es; + } + else if (e1->op == TOKstring && e2->op == TOKarrayliteral && + t2->nextOf()->isintegral()) + { + // Concatenate the strings + StringExp *es1 = (StringExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + size_t len = es1->len + es2->elements->dim; + int sz = es1->sz; + + void *s = mem.malloc((len + 1) * sz); + memcpy(s, es1->string, es1->len * sz); + for (size_t i = 0; i < es2->elements->dim; i++) + { Expression *es2e = es2->elements->tdata()[i]; + if (es2e->op != TOKint64) + return EXP_CANT_INTERPRET; + dinteger_t v = es2e->toInteger(); + memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz); + } + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + StringExp *es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = 0; //es1->committed; es->type = type; e = es; } @@ -1412,13 +1527,20 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) void *s; StringExp *es1 = (StringExp *)e1; StringExp *es; - Type *t; int sz = es1->sz; dinteger_t v = e2->toInteger(); - size_t len = es1->len + utf_codeLength(sz, v); + // Is it a concatentation of homogenous types? + // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar) + bool homoConcat = (sz == t2->size()); + size_t len = es1->len; + len += homoConcat ? 1 : utf_codeLength(sz, v); + s = mem.malloc((len + 1) * sz); memcpy(s, es1->string, es1->len * sz); + if (homoConcat) + memcpy((unsigned char *)s + (sz * es1->len), &v, sz); + else utf_encode(sz, (unsigned char *)s + (sz * es1->len), v); // Add terminating 0 @@ -1427,7 +1549,6 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) es = new StringExp(loc, s, len); es->sz = sz; es->committed = es1->committed; - t = es1->type; es->type = type; e = es; } @@ -1437,7 +1558,6 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) 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(); @@ -1452,7 +1572,6 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) es = new StringExp(loc, s, len); es->sz = sz; es->committed = es2->committed; - t = es2->type; es->type = type; e = es; } diff --git a/dmd/declaration.c b/dmd/declaration.c index d39f1cec..313f03f3 100644 --- a/dmd/declaration.c +++ b/dmd/declaration.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -111,7 +111,7 @@ void Declaration::checkModify(Loc loc, Scope *sc, Type *t) if (fd && ((fd->isCtorDeclaration() && storage_class & STCfield) || (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) && - fd->toParent() == toParent() + fd->toParent2() == toParent() ) { VarDeclaration *v = isVarDeclaration(); @@ -194,7 +194,7 @@ Type *TupleDeclaration::getType() /* 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]; + { Object *o = (*objects)[i]; if (o->dyncast() != DYNCAST_TYPE) { @@ -221,7 +221,7 @@ Type *TupleDeclaration::getType() #else Parameter *arg = new Parameter(STCin, t, NULL, NULL); #endif - args->data[i] = (void *)arg; + (*args)[i] = arg; if (!t->deco) hasdeco = 0; } @@ -238,7 +238,7 @@ int TupleDeclaration::needThis() { //printf("TupleDeclaration::needThis(%s)\n", toChars()); for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; + { Object *o = (*objects)[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; if (e->op == TOKdsymbol) @@ -262,10 +262,8 @@ TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, 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 @@ -284,7 +282,7 @@ Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) 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 @@ -302,26 +300,43 @@ Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) } 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; + if (sem == SemanticStart) + { sem = SemanticIn; + parent = sc->parent; + int errors = global.errors; + Type *savedbasetype = basetype; basetype = basetype->semantic(loc, sc); - sem = 2; + if (errors != global.errors) + { + basetype = savedbasetype; + sem = SemanticStart; + return; + } + sem = SemanticDone; #if DMDV2 type = type->addStorageClass(storage_class); #endif + Type *savedtype = type; type = type->semantic(loc, sc); if (sc->parent->isFuncDeclaration() && init) semantic2(sc); + if (errors != global.errors) + { + basetype = savedbasetype; + type = savedtype; + sem = SemanticStart; + return; + } storage_class |= sc->stc & STCdeprecated; } - else if (sem == 1) + else if (sem == SemanticIn) { error("circular definition"); } @@ -330,11 +345,18 @@ void TypedefDeclaration::semantic(Scope *sc) void TypedefDeclaration::semantic2(Scope *sc) { //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); - if (sem == 2) - { sem = 3; + if (sem == SemanticDone) + { sem = Semantic2Done; if (init) { - init = init->semantic(sc, basetype); + Initializer *savedinit = init; + int errors = global.errors; + init = init->semantic(sc, basetype, WANTinterpret); + if (errors != global.errors) + { + init = savedinit; + return; + } ExpInitializer *ie = init->isExpInitializer(); if (ie) @@ -379,10 +401,8 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) 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; @@ -397,10 +417,8 @@ AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) 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); @@ -415,7 +433,6 @@ Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) 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 @@ -433,7 +450,6 @@ Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) } else sa->haliassym = haliassym->syntaxCopy(s); -#endif return sa; } @@ -464,6 +480,9 @@ void AliasDeclaration::semantic(Scope *sc) // type. If it is a symbol, then aliassym is set and type is NULL - // toAlias() will return aliasssym. + int errors = global.errors; + Type *savedtype = type; + Dsymbol *s; Type *t; Expression *e; @@ -476,7 +495,7 @@ void AliasDeclaration::semantic(Scope *sc) s = type->toDsymbol(sc); if (s #if DMDV2 -` && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) + && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) #endif ) goto L2; // it's a symbolic alias @@ -516,11 +535,15 @@ void AliasDeclaration::semantic(Scope *sc) } else if (t) { - type = t; + type = t->semantic(loc, sc); + //printf("\talias resolved to type %s\n", type->toChars()); } if (overnext) ScopeDsymbol::multiplyDefined(0, this, overnext); this->inSemantic = 0; + + if (errors != global.errors) + type = savedtype; return; L2: @@ -534,6 +557,7 @@ void AliasDeclaration::semantic(Scope *sc) } else { + Dsymbol *savedovernext = overnext; FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); if (f) { @@ -549,15 +573,25 @@ void AliasDeclaration::semantic(Scope *sc) } } if (overnext) - ScopeDsymbol::multiplyDefined(0, s, overnext); + ScopeDsymbol::multiplyDefined(0, this, overnext); if (s == this) { assert(global.errors); s = NULL; } + if (errors != global.errors) + { + type = savedtype; + overnext = savedovernext; + aliassym = NULL; + inSemantic = 0; + return; + } } - //printf("setting aliassym %s to %s %s\n", toChars(), s->kind(), s->toChars()); + if (!type || type->ty != Terror) + { //printf("setting aliassym %s to %s %s\n", toChars(), s->kind(), s->toChars()); aliassym = s; + } this->inSemantic = 0; } @@ -619,7 +653,7 @@ Dsymbol *AliasDeclaration::toAlias() //static int count; if (++count == 75) exit(0); //*(char*)0=0; if (inSemantic) { error("recursive alias declaration"); - aliassym = new TypedefDeclaration(loc, ident, Type::terror, NULL); + aliassym = new AliasDeclaration(loc, ident, Type::terror); type = Type::terror; } else if (!aliassym && scope) @@ -631,7 +665,7 @@ Dsymbol *AliasDeclaration::toAlias() void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("alias "); -#if 0 && _DH +#if 0 if (hgs->hdrgen) { if (haliassym) @@ -674,10 +708,8 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer assert(type || init); this->type = type; this->init = init; -#ifdef _DH this->htype = NULL; this->hinit = NULL; -#endif this->loc = loc; offset = 0; noscope = 0; @@ -691,7 +723,11 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer aliassym = NULL; onstack = 0; canassign = 0; - value = NULL; + ctfeAdrOnStack = (size_t)(-1); +#if DMDV2 + rundtor = NULL; + edtor = NULL; +#endif #if IN_LLVM aggrIndex = 0; @@ -726,7 +762,6 @@ Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) 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 @@ -744,7 +779,6 @@ Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) } else sv->hinit = hinit->syntaxCopy(); -#endif return sv; } @@ -759,6 +793,11 @@ void VarDeclaration::semantic(Scope *sc) //if (strcmp(toChars(), "mul") == 0) halt(); #endif + if (scope) + { sc = scope; + scope = NULL; + } + storage_class |= sc->stc; if (storage_class & STCextern && init) error("extern symbols cannot have initializers"); @@ -773,6 +812,7 @@ void VarDeclaration::semantic(Scope *sc) if (!type) { inuse++; type = init->inferType(sc); + type = type->semantic(loc, sc); inuse--; inferred = 1; @@ -949,10 +989,10 @@ void VarDeclaration::semantic(Scope *sc) } // If it's a member template - AggregateDeclaration *ad = ti->tempdecl->isMember(); - if (ad && storage_class != STCundefined) + AggregateDeclaration *ad2 = ti->tempdecl->isMember(); + if (ad2 && storage_class != STCundefined) { - error("cannot use template to add field to aggregate '%s'", ad->toChars()); + error("cannot use template to add field to aggregate '%s'", ad2->toChars()); } } } @@ -1061,7 +1101,7 @@ void VarDeclaration::semantic(Scope *sc) Expression *e = init->toExpression(); if (!e) { - init = init->semantic(sc, type); + init = init->semantic(sc, type, 0); // Don't need to interpret e = init->toExpression(); if (!e) { error("is not a static and cannot have static initializer"); @@ -1080,7 +1120,7 @@ void VarDeclaration::semantic(Scope *sc) ei->exp = ei->exp->semantic(sc); if (!ei->exp->implicitConvTo(type)) { - int dim = ((TypeSArray *)t)->dim->toInteger(); + dinteger_t dim = ((TypeSArray *)t)->dim->toInteger(); // If multidimensional static array, treat as one large array while (1) { @@ -1162,7 +1202,7 @@ void VarDeclaration::semantic(Scope *sc) } else { - init = init->semantic(sc, type); + init = init->semantic(sc, type, WANTinterpret); if (fd && isConst() && !isStatic()) { // Make it static storage_class |= STCstatic; @@ -1180,9 +1220,7 @@ void VarDeclaration::semantic(Scope *sc) if (!global.errors && !inferred) { - unsigned errors = global.errors; - global.gag++; - //printf("+gag\n"); + unsigned errors = global.startGagging(); Expression *e; Initializer *i2 = init; inuse++; @@ -1194,15 +1232,11 @@ void VarDeclaration::semantic(Scope *sc) } else if (si || ai) { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type); + i2 = i2->semantic(sc, type, WANTinterpret); } inuse--; - global.gag--; - //printf("-gag\n"); - if (errors != global.errors) // if errors happened + if (global.endGagging(errors)) // if errors happened { - if (global.gag == 0) - global.errors = errors; // act as if nothing happened #if DMDV2 /* Save scope for later use, to try again */ @@ -1276,7 +1310,7 @@ void VarDeclaration::semantic2(Scope *sc) printf("type = %p\n", ei->exp->type); } #endif - init = init->semantic(sc, type); + init = init->semantic(sc, type, WANTinterpret); inuse--; } } @@ -1384,8 +1418,12 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) // The current function FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - if (fdv && fdthis) + if (fdv && fdthis && fdv != fdthis && fdthis->ident != Id::ensure) { + /* __ensure is always called directly, + * so it never becomes closure. + */ + if (loc.filename) fdthis->getLevel(loc, fdv); nestedref = 1; @@ -1496,6 +1534,15 @@ Expression *VarDeclaration::callScopeDtor(Scope *sc) return e; } +/****************************************** + */ + +void ObjectNotFound(Identifier *id) +{ + Type::error(0, "%s not found. object.d may be incorrectly installed or corrupt.", id->toChars()); + fatal(); +} + /********************************* ClassInfoDeclaration ****************************/ diff --git a/dmd/declaration.h b/dmd/declaration.h index 005a1fd0..98bf0fac 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -214,10 +214,8 @@ struct TypedefDeclaration : Declaration const char *kind(); Type *getType(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH Type *htype; Type *hbasetype; -#endif void toDocBuffer(OutBuffer *buf); @@ -258,10 +256,8 @@ struct AliasDeclaration : Declaration Type *getType(); Dsymbol *toAlias(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH Type *htype; Dsymbol *haliassym; -#endif void toDocBuffer(OutBuffer *buf); @@ -286,12 +282,25 @@ struct VarDeclaration : Declaration // 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) + + // When interpreting, these point to the value (NULL if value not determinable) + // The index of this variable on the CTFE stack, -1 if not allocated + size_t ctfeAdrOnStack; + // The various functions are used only to detect compiler CTFE bugs + Expression *getValue(); + bool hasValue(); + void setValueNull(); + void setValueWithoutChecking(Expression *newval); + void createRefValue(Expression *newval); + void setRefValue(Expression *newval); + void setStackValue(Expression *newval); + void createStackValue(Expression *newval); + #if DMDV2 VarDeclaration *rundtor; // if !NULL, rundtor is tested at runtime to see // if the destructor should be run. Used to prevent // dtor calls on postblitted vars + Expression *edtor; // if !=NULL, does the destruction of the variable #endif VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); @@ -300,10 +309,8 @@ struct VarDeclaration : Declaration void semantic2(Scope *sc); const char *kind(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH Type *htype; Initializer *hinit; -#endif AggregateDeclaration *isThis(); int needThis(); int isImportedSymbol(); @@ -663,9 +670,18 @@ enum BUILTIN BUILTINtan, // std.math.tan BUILTINsqrt, // std.math.sqrt BUILTINfabs, // std.math.fabs + BUILTINatan2, // std.math.atan2 + BUILTINrndtol, // std.math.rndtol + BUILTINexpm1, // std.math.expm1 + BUILTINexp2, // std.math.exp2 + BUILTINyl2x, // std.math.yl2x + BUILTINyl2xp1, // std.math.yl2xp1 + BUILTINbsr, // core.bitop.bsr + BUILTINbsf, // core.bitop.bsf + BUILTINbswap, // core.bitop.bswap }; -Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments); +Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments); #else enum BUILTIN { }; @@ -673,7 +689,7 @@ enum BUILTIN { }; struct FuncDeclaration : Declaration { - Array *fthrows; // Array of Type's of exceptions (not used) + Types *fthrows; // Array of Type's of exceptions (not used) Statement *frequire; Statement *fensure; Statement *fbody; @@ -693,7 +709,8 @@ struct FuncDeclaration : Declaration #if IN_GCC VarDeclaration *v_argptr; // '_argptr' variable #endif - Dsymbols *parameters; // Array of VarDeclaration's for parameters + VarDeclaration *v_argsave; // save area for args passed in registers for variadic functions + VarDeclarations *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 @@ -736,9 +753,14 @@ struct FuncDeclaration : Declaration int tookAddressOf; // set if someone took the address of // this function - Dsymbols closureVars; // local variables in this function + VarDeclarations closureVars; // local variables in this function // which are referenced by nested // functions + + unsigned flags; + #define FUNCFLAGpurityInprocess 1 // working on determining purity + #define FUNCFLAGsafetyInprocess 2 // working on determining safety + #define FUNCFLAGnothrowInprocess 4 // working on determining nothrow #else int nestedFrameRef; // !=0 if nested variables referenced #endif @@ -946,6 +968,7 @@ struct StaticCtorDeclaration : FuncDeclaration int isVirtual(); int addPreInvariant(); int addPostInvariant(); + bool hasStaticCtorOrDtor(); void emitComment(Scope *sc); void toJsonBuffer(OutBuffer *buf); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -973,6 +996,7 @@ struct StaticDtorDeclaration : FuncDeclaration AggregateDeclaration *isThis(); int isStaticDestructor(); int isVirtual(); + bool hasStaticCtorOrDtor(); int addPreInvariant(); int addPostInvariant(); void emitComment(Scope *sc); @@ -1052,9 +1076,7 @@ struct DeleteDeclaration : FuncDeclaration int isVirtual(); int addPreInvariant(); int addPostInvariant(); -#ifdef _DH DeleteDeclaration *isDeleteDeclaration() { return this; } -#endif }; #endif /* DMD_DECLARATION_H */ diff --git a/dmd/delegatize.c b/dmd/delegatize.c index dde4046d..72fe66b5 100644 --- a/dmd/delegatize.c +++ b/dmd/delegatize.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -60,8 +60,8 @@ void arrayExpressionScanForNestedRef(Scope *sc, Expressions *a) //printf("arrayExpressionScanForNestedRef(%p)\n", a); if (a) { - for (int i = 0; i < a->dim; i++) - { Expression *e = (Expression *)a->data[i]; + for (size_t i = 0; i < a->dim; i++) + { Expression *e = (*a)[i]; if (e) { diff --git a/dmd/doc.c b/dmd/doc.c index 98705bc5..7b7ab95e 100644 --- a/dmd/doc.c +++ b/dmd/doc.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -65,9 +65,11 @@ struct MacroSection : Section void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); }; +typedef ArrayBase
Sections; + struct DocComment { - Array sections; // Section*[] + Sections sections; // Section*[] Section *summary; Section *copyright; @@ -133,6 +135,7 @@ LINK = $0\n\ LINK2 = $+\n\ LPAREN= (\n\ RPAREN= )\n\ +DOLLAR= $\n\ \n\ RED = $0\n\ BLUE = $0\n\ @@ -222,7 +225,7 @@ void Module::gendocfile() 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++) + for (size_t i = 0; i < global.params.ddocfiles->dim; i++) { FileName f((char *)global.params.ddocfiles->data[i], 0); File file(&f); @@ -249,12 +252,14 @@ void Module::gendocfile() Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); } - time_t t; + // Set time macros + { 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)); @@ -374,6 +379,12 @@ void escapeDdocString(OutBuffer *buf, unsigned start) unsigned char c = buf->data[u]; switch(c) { + case '$': + buf->remove(u, 1); + buf->insert(u, "$(DOLLAR)", 9); + u += 8; + break; + case '(': buf->remove(u, 1); //remove the ( buf->insert(u, "$(LPAREN)", 9); //insert this instead @@ -519,7 +530,7 @@ void ScopeDsymbol::emitMemberComments(Scope *sc) 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++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; //printf("\ts = '%s'\n", s->toChars()); @@ -691,7 +702,7 @@ void EnumDeclaration::emitComment(Scope *sc) // if (!comment) { if (isAnonymous() && members) { - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->emitComment(sc); @@ -792,29 +803,35 @@ void prefix(OutBuffer *buf, Dsymbol *s) } } -void Declaration::toDocBuffer(OutBuffer *buf) +void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclaration *td) { - //printf("Declaration::toDocbuffer() %s, originalType = %p\n", toChars(), originalType); - if (ident) + //printf("declarationToDocBuffer() %s, originalType = %s, td = %s\n", decl->toChars(), decl->originalType ? decl->originalType->toChars() : "--", td ? td->toChars() : "--"); + if (decl->ident) { - prefix(buf, this); + prefix(buf, decl); - if (type) + if (decl->type) { HdrGenState hgs; hgs.ddoc = 1; - if (originalType) - { //originalType->print(); - originalType->toCBuffer(buf, ident, &hgs); + Type *origType = decl->originalType ? decl->originalType : decl->type; + if (origType->ty == Tfunction) + { + TypeFunction *attrType = (TypeFunction*)(decl->ident == Id::ctor ? origType : decl->type); + ((TypeFunction*)origType)->toCBufferWithAttributes(buf, decl->ident, &hgs, attrType, td); } else - type->toCBuffer(buf, ident, &hgs); + origType->toCBuffer(buf, decl->ident, &hgs); } else - buf->writestring(ident->toChars()); + buf->writestring(decl->ident->toChars()); buf->writestring(";\n"); } } +void Declaration::toDocBuffer(OutBuffer *buf) +{ + declarationToDocBuffer(this, buf, NULL); +} void AliasDeclaration::toDocBuffer(OutBuffer *buf) { @@ -859,31 +876,9 @@ void FuncDeclaration::toDocBuffer(OutBuffer *buf) td->onemember == this) { /* It's a function template */ - HdrGenState hgs; unsigned o = buf->offset; - TypeFunction *tf = (TypeFunction *)type; - hgs.ddoc = 1; - prefix(buf, td); - if (tf) - { if (tf->nextOf()) - tf->nextOf()->toCBuffer(buf, NULL, &hgs); - else - buf->writestring("auto"); - } - 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(')'); - Parameter::argsToCBuffer(buf, &hgs, tf ? tf->parameters : NULL, tf ? tf->varargs : 0); - buf->writestring(";\n"); + declarationToDocBuffer(this, buf, td); highlightCode(NULL, this, buf, o); } @@ -894,6 +889,7 @@ void FuncDeclaration::toDocBuffer(OutBuffer *buf) } } +#if DMDV1 void CtorDeclaration::toDocBuffer(OutBuffer *buf) { HdrGenState hgs; @@ -902,7 +898,7 @@ void CtorDeclaration::toDocBuffer(OutBuffer *buf) Parameter::argsToCBuffer(buf, &hgs, arguments, varargs); buf->writestring(";\n"); } - +#endif void AggregateDeclaration::toDocBuffer(OutBuffer *buf) { @@ -965,7 +961,7 @@ void ClassDeclaration::toDocBuffer(OutBuffer *buf) buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); } int any = 0; - for (int i = 0; i < baseclasses->dim; i++) + for (size_t i = 0; i < baseclasses->dim; i++) { BaseClass *bc = (BaseClass *)baseclasses->data[i]; if (bc->protection == PROTprivate) @@ -1021,8 +1017,7 @@ DocComment::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; @@ -1033,16 +1028,16 @@ DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) dc->parseSections(comment); - for (int i = 0; i < dc->sections.dim; i++) - { Section *s = (Section *)dc->sections.data[i]; + for (size_t i = 0; i < dc->sections.dim; i++) + { Section *sec = dc->sections[i]; - if (icmp("copyright", s->name, s->namelen) == 0) + if (icmp("copyright", sec->name, sec->namelen) == 0) { - dc->copyright = s; + dc->copyright = sec; } - if (icmp("macros", s->name, s->namelen) == 0) + if (icmp("macros", sec->name, sec->namelen) == 0) { - dc->macros = s; + dc->macros = sec; } } @@ -1178,8 +1173,8 @@ void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) if (sections.dim) { buf->writestring("$(DDOC_SECTIONS \n"); - for (int i = 0; i < sections.dim; i++) - { Section *sec = (Section *)sections.data[i]; + for (size_t i = 0; i < sections.dim; i++) + { Section *sec = sections[i]; if (sec->nooutput) continue; @@ -1756,7 +1751,7 @@ Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) if (tf->parameters) { for (size_t k = 0; k < tf->parameters->dim; k++) - { Parameter *arg = (Parameter *)tf->parameters->data[k]; + { Parameter *arg = (*tf->parameters)[k]; if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) { @@ -2015,7 +2010,6 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) break; } } - Ldone: if (inCode) s->error("unmatched --- in DDoc comment"); ; diff --git a/dmd/dsymbol.c b/dmd/dsymbol.c index f3c83e5d..ac3ba4cc 100644 --- a/dmd/dsymbol.c +++ b/dmd/dsymbol.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -119,15 +119,15 @@ int Dsymbol::oneMember(Dsymbol **ps) * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. */ -int Dsymbol::oneMembers(Array *members, Dsymbol **ps) +int Dsymbol::oneMembers(Dsymbols *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]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *sx = (*members)[i]; int x = sx->oneMember(ps); //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); @@ -163,6 +163,12 @@ int Dsymbol::hasPointers() return 0; } +bool Dsymbol::hasStaticCtorOrDtor() +{ + //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); + return FALSE; +} + char *Dsymbol::toChars() { return ident ? ident->toChars() : (char *)"__anonymous"; @@ -212,12 +218,14 @@ const char *Dsymbol::toPrettyChars() char *Dsymbol::locToChars() { OutBuffer buf; - char *p; + if (!loc.filename) // avoid bug 5861. + { Module *m = getModule(); if (m && m->srcfile) loc.filename = m->srcfile->toChars(); + } return loc.toChars(); } @@ -541,35 +549,29 @@ int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) void Dsymbol::error(const char *format, ...) { //printf("Dsymbol::error()\n"); - if (!global.gag) + if (!loc.filename) // avoid bug 5861. { - 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()); + Module *m = getModule(); + if (m && m->srcfile) + loc.filename = m->srcfile->toChars(); + } va_list ap; va_start(ap, format); - vfprintf(stdmsg, format, ap); + verror(loc, format, ap); va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - } - global.errors++; - - //fatal(); } void Dsymbol::error(Loc loc, const char *format, ...) { + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end(ap); +} + +void Dsymbol::verror(Loc loc, const char *format, va_list ap) +{ if (!global.gag) { char *p = loc.toChars(); @@ -583,13 +585,15 @@ void Dsymbol::error(Loc loc, const char *format, ...) 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); +//halt(); + } + else + { + global.gaggedErrors++; } global.errors++; @@ -604,21 +608,24 @@ void Dsymbol::checkDeprecated(Loc loc, Scope *sc) // 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; + goto L1; } - for (; sc; sc = sc->enclosing) + for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing) { - if (sc->scopesym && sc->scopesym->isDeprecated()) - return; + if (sc2->scopesym && sc2->scopesym->isDeprecated()) + goto L1; // If inside a StorageClassDeclaration that is deprecated - if (sc->stc & STCdeprecated) - return; + if (sc2->stc & STCdeprecated) + goto L1; } error(loc, "is deprecated"); } + + L1: + ; } /********************************** @@ -631,6 +638,10 @@ Module *Dsymbol::getModule() Dsymbol *s; //printf("Dsymbol::getModule()\n"); + TemplateDeclaration *td = getFuncTemplateDecl(this); + if (td) + return td->getModule(); + s = this; while (s) { @@ -684,19 +695,19 @@ enum PROT Dsymbol::prot() */ -Array *Dsymbol::arraySyntaxCopy(Array *a) +Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) { - Array *b = NULL; + Dsymbols *b = NULL; if (a) { b = a->copy(); - for (int i = 0; i < b->dim; i++) + for (size_t i = 0; i < b->dim; i++) { - Dsymbol *s = (Dsymbol *)b->data[i]; + Dsymbol *s = (*b)[i]; s = s->syntaxCopy(NULL); - b->data[i] = (void *)s; + (*b)[i] = s; } } return b; @@ -799,8 +810,8 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) else if (imports) { // Look in imported modules - for (int i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; + for (size_t i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss = (*imports)[i]; Dsymbol *s2; // If private import, don't search it @@ -863,13 +874,11 @@ void ScopeDsymbol::importScope(ScopeDsymbol *s, enum PROT protection) if (s != this) { if (!imports) - imports = new Array(); + imports = new ScopeDsymbols(); else { - for (int i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss; - - ss = (ScopeDsymbol *) imports->data[i]; + for (size_t i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss = (*imports)[i]; if (ss == s) // if already imported { if (protection > prots[i]) @@ -953,28 +962,41 @@ Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) return symtab->insert(s); } -/*************************************** - * Determine number of Dsymbols, folding in AttribDeclaration members. +/**************************************** + * Return true if any of the members are static ctors or static dtors, or if + * any members have members that are. */ -#if DMDV2 -size_t ScopeDsymbol::dim(Array *members) +bool ScopeDsymbol::hasStaticCtorOrDtor() { - 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(); + { Dsymbol *member = (*members)[i]; - if (a) - { - n += dim(a->decl); - } - else - n++; + if (member->hasStaticCtorOrDtor()) + return TRUE; } } + return FALSE; +} + +/*************************************** + * Determine number of Dsymbols, folding in AttribDeclaration members. + */ + +#if DMDV2 +static int dimDg(void *ctx, size_t n, Dsymbol *) +{ + ++*(size_t *)ctx; + return 0; +} + +size_t ScopeDsymbol::dim(Dsymbols *members) +{ + size_t n = 0; + if (members) + foreach(members, &dimDg, &n); return n; } #endif @@ -988,31 +1010,65 @@ size_t ScopeDsymbol::dim(Array *members) */ #if DMDV2 -Dsymbol *ScopeDsymbol::getNth(Array *members, size_t nth, size_t *pn) +struct GetNthSymbolCtx { - if (!members) - return NULL; + size_t nth; + Dsymbol *sym; +}; - 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; +static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym) +{ + GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx; + if (n == p->nth) + { p->sym = sym; + return 1; } - else if (n == nth) - return s; + return 0; +} + +Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *pn) +{ + GetNthSymbolCtx ctx = { nth, NULL }; + int res = foreach(members, &getNthSymbolDg, &ctx); + return res ? ctx.sym : NULL; +} +#endif + +/*************************************** + * Expands attribute declarations in members in depth first + * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each + * member. + * If dg returns !=0, stops and returns that value else returns 0. + * Use this function to avoid the O(N + N^2/2) complexity of + * calculating dim and calling N times getNth. + */ + +#if DMDV2 +int ScopeDsymbol::foreach(Dsymbols *members, ScopeDsymbol::ForeachDg dg, void *ctx, size_t *pn) +{ + assert(members); + + size_t n = pn ? *pn : 0; // take over index + int result = 0; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + + if (AttribDeclaration *a = s->isAttribDeclaration()) + result = foreach(a->decl, dg, ctx, &n); + else if (TemplateMixin *tm = s->isTemplateMixin()) + result = foreach(tm->members, dg, ctx, &n); + else if (s->isTemplateInstance()) + ; else - n++; + result = dg(ctx, n++, s); + + if (result) + break; } if (pn) - *pn += n; - return NULL; + *pn = n; // update index + return result; } #endif @@ -1161,35 +1217,27 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) * 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. + { /* Create variable v and set it to the value of $ */ VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - - 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 |= 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 |= STCconst; - } - else if (ce->op == TOKtuple) + if (ce->op == TOKtuple) { /* It is for an expression tuple, so the - * length will be a const. + * length will be a compile-time constant. */ Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); v->init = new ExpInitializer(0, e); v->storage_class |= STCconst; } + else + { /* For arrays, $ will either be a compile-time constant + * (in which case its value in set during constant-folding), + * or a variable (in which case an expression is created in + * toir.c). + */ + VoidInitializer *e = new VoidInitializer(0); + e->type = Type::tsize_t; + v->init = e; + } *pvar = v; } return (*pvar); @@ -1202,89 +1250,46 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) DsymbolTable::DsymbolTable() { -#if STRINGTABLE - tab = new StringTable; -#else tab = NULL; -#endif } DsymbolTable::~DsymbolTable() { -#if STRINGTABLE - delete tab; -#endif } Dsymbol *DsymbolTable::lookup(Identifier *ident) { -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - StringValue *sv = tab->lookup((char*)ident->string, ident->len); - return (Dsymbol *)(sv ? sv->ptrvalue : NULL); -#else //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); return (Dsymbol *)_aaGetRvalue(tab, ident); -#endif } Dsymbol *DsymbolTable::insert(Dsymbol *s) { //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); Identifier *ident = s->ident; -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); if (*ps) return NULL; // already in table *ps = s; return s; -#endif } Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) { //printf("DsymbolTable::insert()\n"); -#if STRINGTABLE - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); if (*ps) return NULL; // already in table *ps = s; return s; -#endif } Dsymbol *DsymbolTable::update(Dsymbol *s) { Identifier *ident = s->ident; -#if STRINGTABLE - StringValue *sv = tab->update(ident->toChars(), ident->len); - sv->ptrvalue = s; - return s; -#else Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); *ps = s; return s; -#endif } diff --git a/dmd/dsymbol.h b/dmd/dsymbol.h index 8014087f..6ec7e880 100644 --- a/dmd/dsymbol.h +++ b/dmd/dsymbol.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -145,6 +145,7 @@ struct Dsymbol : Object int isAnonymous(); void error(Loc loc, const char *format, ...) IS_PRINTF(3); void error(const char *format, ...) IS_PRINTF(2); + void verror(Loc loc, const char *format, va_list ap); void checkDeprecated(Loc loc, Scope *sc); Module *getModule(); // module where declared Module *getCompilationModule(); // possibly different for templates @@ -155,7 +156,7 @@ struct Dsymbol : Object int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() - static Array *arraySyntaxCopy(Array *a); + static Dsymbols *arraySyntaxCopy(Dsymbols *a); virtual const char *toPrettyChars(); virtual const char *kind(); @@ -172,10 +173,8 @@ struct Dsymbol : Object Dsymbol *search_correct(Identifier *id); 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 void toJsonBuffer(OutBuffer *buf); @@ -198,8 +197,9 @@ struct Dsymbol : Object 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); + static int oneMembers(Dsymbols *members, Dsymbol **ps); virtual int hasPointers(); + virtual bool hasStaticCtorOrDtor(); virtual void addLocalClass(ClassDeclarations *) { } virtual void checkCtorConstInit() { } @@ -254,9 +254,8 @@ struct Dsymbol : Object virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } virtual Import *isImport() { return NULL; } virtual EnumDeclaration *isEnumDeclaration() { return NULL; } -#ifdef _DH virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } -#endif + //virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; } virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } virtual AttribDeclaration *isAttribDeclaration() { return NULL; } virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } @@ -283,10 +282,10 @@ struct Dsymbol : Object struct ScopeDsymbol : Dsymbol { - Array *members; // all Dsymbol's in this scope + Dsymbols *members; // all Dsymbol's in this scope DsymbolTable *symtab; // members[] sorted into table - Array *imports; // imported ScopeDsymbol's + ScopeDsymbols *imports; // imported ScopeDsymbol's unsigned char *prots; // array of PROT, one for each import ScopeDsymbol(); @@ -301,11 +300,15 @@ struct ScopeDsymbol : Dsymbol const char *kind(); FuncDeclaration *findGetMembers(); virtual Dsymbol *symtabInsert(Dsymbol *s); + bool hasStaticCtorOrDtor(); void emitMemberComments(Scope *sc); - static size_t dim(Array *members); - static Dsymbol *getNth(Array *members, size_t nth, size_t *pn = NULL); + static size_t dim(Dsymbols *members); + static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL); + + typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); + static int foreach(Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn=NULL); ScopeDsymbol *isScopeDsymbol() { return this; } }; @@ -357,11 +360,7 @@ struct OverloadSet : Dsymbol struct DsymbolTable : Object { -#if STRINGTABLE - StringTable *tab; -#else AA *tab; -#endif DsymbolTable(); ~DsymbolTable(); diff --git a/dmd/enum.c b/dmd/enum.c index af521dbf..c8161252 100644 --- a/dmd/enum.c +++ b/dmd/enum.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -68,7 +68,7 @@ void EnumDeclaration::semantic0(Scope *sc) return; if (!isAnonymous() || memtype) return; - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); if (em && em->value) @@ -80,7 +80,7 @@ void EnumDeclaration::semantic0(Scope *sc) } void EnumDeclaration::semantic(Scope *sc) -{ int i; +{ uinteger_t number; Type *t; Scope *sce; @@ -140,7 +140,7 @@ void EnumDeclaration::semantic(Scope *sc) if (members->dim == 0) error("enum %s must have at least one member", toChars()); int first = 1; - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); Expression *e; @@ -228,13 +228,13 @@ void EnumDeclaration::semantic(Scope *sc) if (isAnonymous()) { //sce->enclosing->insert(em); - for (Scope *scx = sce->enclosing; scx; scx = scx->enclosing) + for (Scope *sct = sce->enclosing; sct; sct = sct->enclosing) { - if (scx->scopesym) + if (sct->scopesym) { - if (!scx->scopesym->symtab) - scx->scopesym->symtab = new DsymbolTable(); - em->addMember(sce, scx->scopesym, 1); + if (!sct->scopesym->symtab) + sct->scopesym->symtab = new DsymbolTable(); + em->addMember(sce, sct->scopesym, 1); break; } } @@ -279,8 +279,7 @@ int EnumDeclaration::oneMember(Dsymbol **ps) } void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - +{ buf->writestring("enum "); if (ident) { buf->writestring(ident->toChars()); @@ -300,7 +299,7 @@ void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); buf->writeByte('{'); buf->writenl(); - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); if (!em) diff --git a/dmd/enum.h b/dmd/enum.h index c99096b9..439211d1 100644 --- a/dmd/enum.h +++ b/dmd/enum.h @@ -21,9 +21,7 @@ struct Identifier; struct Type; struct Expression; -#ifdef _DH struct HdrGenState; -#endif struct EnumDeclaration : ScopeDsymbol diff --git a/dmd/expression.c b/dmd/expression.c index b4647c12..51ea2d9c 100644 --- a/dmd/expression.c +++ b/dmd/expression.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -54,8 +54,10 @@ int isnan(double); #include "attrib.h" #include "hdrgen.h" #include "parse.h" +#include "doc.h" +Expression *createTypeInfoArray(Scope *sc, Expression *args[], unsigned dim); Expression *expandVar(int result, VarDeclaration *v); #define LOGSEMANTIC 0 @@ -181,16 +183,17 @@ FuncDeclaration *hasThis(Scope *sc) break; Dsymbol *parent = fd->parent; - while (parent) + while (1) { + if (!parent) + goto Lno; TemplateInstance *ti = parent->isTemplateInstance(); if (ti) parent = ti->parent; else break; } - - fd = fd->parent->isFuncDeclaration(); + fd = parent->isFuncDeclaration(); } if (!fd->isThis()) @@ -432,6 +435,29 @@ Expressions *arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt } /**************************************** + * Get TemplateDeclaration enclosing FuncDeclaration. + */ + +TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s) +{ + 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) + { + return ti->tempdecl; + } + } + return NULL; +} + +/**************************************** * Preprocess arguments to function. */ @@ -442,7 +468,7 @@ void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) expandTuples(exps); for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (Expression *)exps->data[i]; + { Expression *arg = (*exps)[i]; if (!arg->type) { @@ -455,7 +481,7 @@ void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) } arg = resolveProperties(sc, arg); - exps->data[i] = (void *) arg; + (*exps)[i] = arg; //arg->rvalue(); #if 0 @@ -463,7 +489,7 @@ void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) { arg = new AddrExp(arg->loc, arg); arg = arg->semantic(sc); - exps->data[i] = (void *) arg; + (*exps)[i] = arg; } #endif } @@ -498,6 +524,23 @@ Expression *callCpCtor(Loc loc, Scope *sc, Expression *e) } #endif +// Check if this function is a member of a template which has only been +// instantiated speculatively, eg from inside is(typeof()). +// Return the speculative template instance it is part of, +// or NULL if not speculative. +TemplateInstance *isSpeculativeFunction(FuncDeclaration *fd) +{ + Dsymbol * par = fd->parent; + while (par) + { + TemplateInstance *ti = par->isTemplateInstance(); + if (ti && ti->speculative) + return ti; + par = par->toParent(); + } + return NULL; +} + /**************************************** * Now that we know the exact type of the function we're calling, * the arguments[] need to be adjusted: @@ -517,6 +560,20 @@ void functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *argum if (nargs > nparams && tf->varargs == 0) error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars()); +#if DMDV2 + // If inferring return type, and semantic3() needs to be run if not already run + if (!tf->next && fd->inferRetType) + { + TemplateInstance *spec = isSpeculativeFunction(fd); + int olderrs = global.errors; + fd->semantic3(fd->scope); + // Update the template instantiation with the number + // of errors which occured. + if (spec && global.errors != olderrs) + spec->errors = global.errors - olderrs; + } +#endif + unsigned n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) int done = 0; @@ -557,7 +614,9 @@ void functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *argum //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); if (arg->implicitConvTo(p->type)) { - if (nargs != nparams) + if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf())) + goto L2; + else if (nargs != nparams) { error(loc, "expected %zu function arguments, not %zu", nparams, nargs); return; } @@ -594,7 +653,7 @@ void functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *argum c->type = v->type; for (size_t u = i; u < nargs; u++) - { Expression *a = (Expression *)arguments->data[u]; + { Expression *a = (*arguments)[u]; if (tret && !((TypeArray *)tb)->next->equals(a->type)) a = a->toDelegate(sc, tret); @@ -914,6 +973,24 @@ Expression *Expression::semantic(Scope *sc) return this; } +/********************************** + * Try to run semantic routines. + * If they fail, return NULL. + */ + +Expression *Expression::trySemantic(Scope *sc) +{ + //printf("+trySemantic(%s)\n", toChars()); + unsigned errors = global.startGagging(); + Expression *e = semantic(sc); + if (global.endGagging(errors)) + { + e = NULL; + } + //printf("-trySemantic(%s)\n", toChars()); + return e; +} + void Expression::print() { fprintf(stdmsg, "%s\n", toChars()); @@ -1014,6 +1091,11 @@ complex_t Expression::toComplex() #endif } +StringExp *Expression::toString() +{ + return NULL; +} + void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring(Token::toChars(op)); @@ -1197,11 +1279,12 @@ Expression *Expression::checkToPointer() Expression *Expression::addressOf(Scope *sc) { Expression *e; + Type *t = type; //printf("Expression::addressOf()\n"); e = toLvalue(sc, NULL); e = new AddrExp(loc, e); - e->type = type->pointerTo(); + e->type = t->pointerTo(); return e; } @@ -1263,7 +1346,7 @@ Expressions *Expression::arraySyntaxCopy(Expressions *exps) { a = new Expressions(); a->setDim(exps->dim); - for (int i = 0; i < a->dim; i++) + for (size_t i = 0; i < a->dim; i++) { Expression *e = (Expression *)exps->data[i]; e = e->syntaxCopy(); @@ -1470,13 +1553,18 @@ void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) break; } case Tchar: + { + unsigned o = buf->offset; if (v == '\'') buf->writestring("'\\''"); else if (isprint(v) && v != '\\') buf->printf("'%c'", (int)v); else buf->printf("'\\x%02x'", (int)v); + if (hgs->ddoc) + escapeDdocString(buf, o); break; + } case Tint8: buf->writestring("cast(byte)"); @@ -1655,16 +1743,11 @@ complex_t RealExp::toComplex() int RealEquals(real_t x1, real_t x2) { -#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); + return (Port::isNan(x1) && Port::isNan(x2)) || + /* In some cases, the REALPAD bytes get garbage in them, + * so be sure and ignore them. + */ + memcmp(&x1, &x2, REALSIZE - REALPAD) == 0; } int RealExp::equals(Object *o) @@ -1776,11 +1859,7 @@ void realToMangleBuffer(OutBuffer *buf, real_t value) * 0X1.9P+2 => 19P2 */ -#if __APPLE__ - if (__inline_isnan(value)) -#else - if (isnan(value)) -#endif + if (Port::isNan(value)) buf->writestring("NAN"); // no -NAN bugs else { @@ -1992,17 +2071,10 @@ Expression *IdentifierExp::semantic(Scope *sc) * 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) + if (f) + { TemplateDeclaration *tempdecl = getFuncTemplateDecl(f); + if (tempdecl) { - 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); @@ -2096,7 +2168,6 @@ Lagain: VarDeclaration *v; FuncDeclaration *f; FuncLiteralDeclaration *fld; - Declaration *d; ClassDeclaration *cd; ClassDeclaration *thiscd = NULL; Import *imp; @@ -2109,9 +2180,10 @@ Lagain: return this; if (!s->isFuncDeclaration()) // functions are checked after overloading checkDeprecated(sc, s); + Dsymbol *olds = s; s = s->toAlias(); //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); - if (!s->isFuncDeclaration()) + if (s != olds && !s->isFuncDeclaration()) checkDeprecated(sc, s); if (sc->func) @@ -2201,6 +2273,21 @@ Lagain: if (!f->originalType && f->scope) // semantic not yet run f->semantic(f->scope); + +#if DMDV2 + // if inferring return type, sematic3 needs to be run + if (f->inferRetType && f->scope && f->type && !f->type->nextOf()) + { + TemplateInstance *spec = isSpeculativeFunction(f); + int olderrs = global.errors; + f->semantic3(f->scope); + // Update the template instantiation with the number + // of errors which occured. + if (spec && global.errors != olderrs) + spec->errors = global.errors - olderrs; + } +#endif + if (f->isUnitTestDeclaration()) { error("cannot call unittest function %s", toChars()); @@ -2227,7 +2314,7 @@ Lagain: { if (!imp->pkg) { error("forward reference of import %s", imp->toChars()); - return this; + return new ErrorExp(); } ScopeExp *ie = new ScopeExp(loc, imp->pkg); return ie->semantic(sc); @@ -2252,7 +2339,8 @@ Lagain: t = s->getType(); if (t) { - return new TypeExp(loc, t); + TypeExp *te = new TypeExp(loc, t); + return te->semantic(sc); } TupleDeclaration *tup = s->isTupleDeclaration(); @@ -2283,10 +2371,8 @@ Lagain: return e; } -Lerr: error("%s '%s' is not a variable", s->kind(), s->toChars()); - type = Type::terror; - return this; + return new ErrorExp(); } char *DsymbolExp::toChars() @@ -2323,14 +2409,12 @@ Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) 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 @@ -2339,39 +2423,39 @@ Expression *ThisExp::semantic(Scope *sc) return this; } + FuncDeclaration *fd = hasThis(sc); // fd is the uplevel function with the 'this' variable + /* 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) + if (!fd && sc->intypeof) { // Find enclosing struct or class - for (Dsymbol *s = sc->parent; 1; s = s->parent) + for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent) { - ClassDeclaration *cd; - StructDeclaration *sd; - if (!s) { - error("%s is not in a struct or class scope", toChars()); + error("%s is not in a class or struct scope", toChars()); goto Lerr; } - cd = s->isClassDeclaration(); + ClassDeclaration *cd = s->isClassDeclaration(); if (cd) { type = cd->type; return this; } - sd = s->isStructDeclaration(); + 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; @@ -2380,22 +2464,13 @@ Expression *ThisExp::semantic(Scope *sc) assert(var->parent); type = var->type; var->isVarDeclaration()->checkNestedReference(sc, loc); -#if 0 - if (fd != fdthis) // if nested - { - fdthis->getLevel(loc, fd); - fd->vthis->nestedref = 1; - fd->nestedFrameRef = 1; - } -#endif 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; + return new ErrorExp(); } int ThisExp::isBool(int result) @@ -2429,8 +2504,7 @@ SuperExp::SuperExp(Loc loc) } Expression *SuperExp::semantic(Scope *sc) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; +{ ClassDeclaration *cd; Dsymbol *s; @@ -2440,22 +2514,22 @@ Expression *SuperExp::semantic(Scope *sc) if (type) return this; + FuncDeclaration *fd = hasThis(sc); + /* 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) + if (!fd && sc->intypeof) { // Find enclosing class - for (Dsymbol *s = sc->parent; 1; s = s->parent) + for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent) { - ClassDeclaration *cd; - if (!s) { error("%s is not in a class scope", toChars()); goto Lerr; } - cd = s->isClassDeclaration(); + ClassDeclaration *cd = s->isClassDeclaration(); if (cd) { cd = cd->baseClass; @@ -2468,11 +2542,9 @@ Expression *SuperExp::semantic(Scope *sc) } } } - - fdthis = sc->parent->isFuncDeclaration(); - fd = hasThis(sc); if (!fd) goto Lerr; + assert(fd->vthis); var = fd->vthis; assert(var->parent); @@ -2493,17 +2565,12 @@ Expression *SuperExp::semantic(Scope *sc) else { type = cd->baseClass->type; +#if DMDV2 + type = type->castMod(var->type->mod); +#endif } var->isVarDeclaration()->checkNestedReference(sc, loc); -#if 0 - if (fd != fdthis) - { - fdthis->getLevel(loc, fd); - fd->vthis->nestedref = 1; - fd->nestedFrameRef = 1; - } -#endif if (!sc->intypeof) sc->callSuper |= CSXsuper; @@ -2512,8 +2579,7 @@ Expression *SuperExp::semantic(Scope *sc) Lerr: error("'super' is only allowed in non-static class member functions"); - type = Type::tint32; - return this; + return new ErrorExp(); } void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -2547,6 +2613,17 @@ int NullExp::isBool(int result) return result ? FALSE : TRUE; } +StringExp *NullExp::toString() +{ + if (implicitConvTo(Type::tstring)) + { + StringExp *se = new StringExp(loc, (char*)mem.calloc(1, 1), 0); + se->type = Type::tstring; + return se; + } + return NULL; +} + void NullExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("null"); @@ -2694,6 +2771,59 @@ Expression *StringExp::semantic(Scope *sc) 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); + return 0; + } + 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); + return 0; + } + else + result++; + } + break; + + case 4: + result = len; + break; + + default: + assert(0); + } + return result; +} + +StringExp *StringExp::toString() +{ + return this; +} + /**************************************** * Convert string to char[]. */ @@ -2715,6 +2845,7 @@ StringExp *StringExp::toUTF8(Scope *sc) int StringExp::compare(Object *obj) { + //printf("StringExp::compare()\n"); // Used to sort case statement expressions so we can do an efficient lookup StringExp *se2 = (StringExp *)(obj); @@ -2728,6 +2859,7 @@ int StringExp::compare(Object *obj) int len1 = len; int len2 = se2->len; + //printf("sz = %d, len1 = %d, len2 = %d\n", sz, len1, len2); if (len1 == len2) { switch (sz) @@ -2772,6 +2904,12 @@ int StringExp::isBool(int result) return result ? TRUE : FALSE; } +#if DMDV2 +int StringExp::isLvalue() +{ + return 1; +} +#endif unsigned StringExp::charAt(size_t i) { unsigned value; @@ -2799,6 +2937,7 @@ unsigned StringExp::charAt(size_t i) void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('"'); + unsigned o = buf->offset; for (size_t i = 0; i < len; i++) { unsigned c = charAt(i); @@ -2823,6 +2962,8 @@ void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) break; } } + if (hgs->ddoc) + escapeDdocString(buf, o); buf->writeByte('"'); if (postfix) buf->writeByte(postfix); @@ -2874,10 +3015,19 @@ void StringExp::toMangleBuffer(OutBuffer *buf) default: assert(0); } + buf->reserve(1 + 11 + 2 * qlen); buf->writeByte(m); - buf->printf("%d_", qlen); - for (size_t i = 0; i < qlen; i++) - buf->printf("%02x", q[i]); + buf->printf("%d_", qlen); // nbytes <= 11 + + for (unsigned char *p = buf->data + buf->offset, *pend = p + 2 * qlen; + p < pend; p += 2, ++q) + { + unsigned char hi = *q >> 4 & 0xF; + p[0] = (hi < 10 ? hi + '0' : hi - 10 + 'a'); + unsigned char lo = *q & 0xF; + p[1] = (lo < 10 ? lo + '0' : lo - 10 + 'a'); + } + buf->offset += 2 * qlen; } /************************ ArrayLiteralExp ************************************/ @@ -2913,13 +3063,13 @@ Expression *ArrayLiteralExp::semantic(Scope *sc) return this; // Run semantic() on each element - for (int i = 0; i < elements->dim; i++) + for (size_t 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++) + for (size_t i = 0; i < elements->dim; i++) { e = (Expression *)elements->data[i]; if (!e->type) @@ -2950,8 +3100,15 @@ Expression *ArrayLiteralExp::semantic(Scope *sc) if (!t0) t0 = Type::tvoid; + type = new TypeSArray(t0, new IntegerExp(elements->dim)); type = type->semantic(loc, sc); + + /* Disallow array literals of type void being used. + */ + if (elements->dim > 0 && t0->ty == Tvoid) + error("%s of type %s has no value", toChars(), type->toChars()); + return this; } @@ -2981,6 +3138,35 @@ int ArrayLiteralExp::canThrow() } #endif +StringExp *ArrayLiteralExp::toString() +{ + TY telem = type->nextOf()->toBasetype()->ty; + + if (telem == Tchar || telem == Twchar || telem == Tdchar || + (telem == Tvoid && (!elements || elements->dim == 0))) + { + OutBuffer buf; + if (elements) + for (int i = 0; i < elements->dim; ++i) + { + Expression *ch = elements->tdata()[i]; + if (ch->op != TOKint64) + return NULL; + buf.writedchar(ch->toInteger()); + } + buf.writebyte(0); + + char prefix = 'c'; + if (telem == Twchar) prefix = 'w'; + else if (telem == Tdchar) prefix = 'd'; + + StringExp *se = new StringExp(loc, buf.extractData(), buf.size - 1, prefix); + se->type = type; + return se; + } + return NULL; +} + void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('['); @@ -3018,8 +3204,7 @@ Expression *AssocArrayLiteralExp::syntaxCopy() } Expression *AssocArrayLiteralExp::semantic(Scope *sc) -{ Expression *e; - +{ #if LOGSEMANTIC printf("AssocArrayLiteralExp::semantic('%s')\n", toChars()); #endif @@ -3107,11 +3292,12 @@ void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) // sd( e1, e2, e3, ... ) -StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements) +StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype) : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp)) { this->sd = sd; this->elements = elements; + this->stype = stype; #if IN_DMD this->sym = NULL; #endif @@ -3124,7 +3310,7 @@ StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions * Expression *StructLiteralExp::syntaxCopy() { - return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements)); + return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), stype); } Expression *StructLiteralExp::semantic(Scope *sc) @@ -3152,7 +3338,9 @@ Expression *StructLiteralExp::semantic(Scope *sc) continue; if (!e->type) - error("%s has no value", e->toChars()); + { error("%s has no value", e->toChars()); + return new ErrorExp(); + } e = resolveProperties(sc, e); if (i >= sd->fields.dim) { error("more initializers than fields of %s", sd->toChars()); @@ -3192,19 +3380,26 @@ Expression *StructLiteralExp::semantic(Scope *sc) else { if (v->init) + { if (v->init->isVoidInitializer()) + e = NULL; + else { e = v->init->toExpression(); if (!e) { error("cannot make expression out of initializer for %s", v->toChars()); - e = new ErrorExp(); + return new ErrorExp(); } else if (v->scope) - { // Do deferred semantic anaylsis + { // Do deferred semantic analysis Initializer *i2 = v->init->syntaxCopy(); - i2 = i2->semantic(v->scope, v->type); + i2 = i2->semantic(v->scope, v->type, WANTinterpret); e = i2->toExpression(); + // remove v->scope (see bug 3426) + // but not if gagged, for we might be called again. + if (!global.gag) v->scope = NULL; } } + } else e = v->type->defaultInitLiteral(loc); offset = v->offset + v->type->size(); @@ -3212,7 +3407,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) elements->push(e); } - type = sd->type; + type = stype ? stype : sd->type; return this; } @@ -3450,12 +3645,18 @@ Lagain: } //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); } + if (global.errors) + return new ErrorExp(); } else { //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); //printf("\tparent = '%s'\n", sds->parent->toChars()); sds->semantic(sc); + + AggregateDeclaration *ad = sds->isAggregateDeclaration(); + if (ad) + return (new TypeExp(loc, ad->type))->semantic(sc); } type = Type::tvoid; //printf("-2ScopeExp::semantic() %s\n", toChars()); @@ -3468,6 +3669,14 @@ void ScopeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { sds->toCBuffer(buf, hgs); } + else if (hgs != NULL && hgs->ddoc) + { // fixes bug 6491 + Module *module = sds->isModule(); + if (module) + buf->writestring(module->md->toChars()); + else + buf->writestring(sds->toChars()); + } else { buf->writestring(sds->kind()); @@ -3524,7 +3733,7 @@ Expression *NewExp::syntaxCopy() Expression *NewExp::semantic(Scope *sc) -{ int i; +{ Type *tb; ClassDeclaration *cdthis = NULL; @@ -3576,7 +3785,7 @@ Lagain: 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++) + for (size_t 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()); @@ -3792,8 +4001,7 @@ int NewExp::canThrow() #endif void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - +{ if (thisexp) { expToCBuffer(buf, hgs, thisexp, PREC_primary); buf->writeByte('.'); @@ -3866,8 +4074,7 @@ int NewAnonClassExp::canThrow() #endif void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - +{ if (thisexp) { expToCBuffer(buf, hgs, thisexp, PREC_primary); buf->writeByte('.'); @@ -3986,8 +4193,7 @@ int VarExp::equals(Object *o) } Expression *VarExp::semantic(Scope *sc) -{ FuncLiteralDeclaration *fd; - +{ #if LOGSEMANTIC printf("VarExp::semantic(%s)\n", toChars()); #endif @@ -4201,7 +4407,7 @@ TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) exps->reserve(tup->objects->dim); for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = (Object *)tup->objects->data[i]; + { Object *o = tup->objects->tdata()[i]; if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; @@ -4228,8 +4434,7 @@ TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) } int TupleExp::equals(Object *o) -{ TupleExp *ne; - +{ if (this == o) return 1; if (((Expression *)o)->op == TOKtuple) @@ -4238,8 +4443,8 @@ int TupleExp::equals(Object *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]; + { Expression *e1 = (*exps)[i]; + Expression *e2 = (*te->exps)[i]; if (!e1->equals(e2)) return 0; @@ -4264,21 +4469,17 @@ Expression *TupleExp::semantic(Scope *sc) // Run semantic() on each argument for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; + { Expression *e = (*exps)[i]; e = e->semantic(sc); if (!e->type) { error("%s has no value", e->toChars()); - e->type = Type::terror; + e = new ErrorExp(); } - exps->data[i] = (void *)e; + (*exps)[i] = e; } expandTuples(exps); - if (0 && exps->dim == 1) - { - return (Expression *)exps->data[0]; - } type = new TypeTuple(exps); type = type->semantic(loc, sc); //printf("-TupleExp::semantic(%s)\n", toChars()); @@ -4295,8 +4496,8 @@ void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) int TupleExp::checkSideEffect(int flag) { int f = 0; - for (int i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (*exps)[i]; f |= e->checkSideEffect(2); } @@ -4306,16 +4507,16 @@ int TupleExp::checkSideEffect(int flag) } #if DMDV2 -int TupleExp::canThrow() +int TupleExp::canThrow(bool mustNotThrow) { - return arrayExpressionCanThrow(exps); + return arrayExpressionCanThrow(exps, mustNotThrow); } #endif void TupleExp::checkEscape() { for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; + { Expression *e = (*exps)[i]; e->checkEscape(); } } @@ -4340,27 +4541,28 @@ Expression *FuncExp::semantic(Scope *sc) #endif if (!type) { + unsigned olderrors = global.errors; fd->semantic(sc); fd->parent = sc->parent; - if (global.errors) + if (olderrors != global.errors) { } else { fd->semantic2(sc); - if (!global.errors || + if ( (olderrors == global.errors) || // need to infer return type (fd->type && fd->type->ty == Tfunction && !fd->type->nextOf())) { fd->semantic3(sc); - if (!global.errors && global.params.useInline) + if ( (olderrors == global.errors) && global.params.useInline) fd->inlineScan(); } } // need to infer return type - if (global.errors && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()) + if ((olderrors != global.errors) && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()) ((TypeFunction *)fd->type)->next = Type::terror; // Type is a "delegate to" or "pointer to" the function literal @@ -4411,6 +4613,8 @@ Expression *DeclarationExp::semantic(Scope *sc) printf("DeclarationExp::semantic() %s\n", toChars()); #endif + unsigned olderrors = global.errors; + /* This is here to support extern(linkage) declaration, * where the extern(linkage) winds up being an AttribDeclaration * wrapper. @@ -4421,7 +4625,7 @@ Expression *DeclarationExp::semantic(Scope *sc) if (ad) { if (ad->decl && ad->decl->dim == 1) - s = (Dsymbol *)ad->decl->data[0]; + s = ad->decl->tdata()[0]; } if (s->isVarDeclaration()) @@ -4476,14 +4680,14 @@ Expression *DeclarationExp::semantic(Scope *sc) sc2->pop(); s->parent = sc->parent; } - if (!global.errors) + if (global.errors == olderrors) { declaration->semantic2(sc); - if (!global.errors) + if (global.errors == olderrors) { declaration->semantic3(sc); - if (!global.errors && global.params.useInline) + if ((global.errors == olderrors) && global.params.useInline) declaration->inlineScan(); } } @@ -4580,7 +4784,7 @@ void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(ident->toChars()); if (args) { - for (int i = 0; i < args->dim; i++) + for (size_t i = 0; i < args->dim; i++) { buf->writeByte(','); Object *oarg = (Object *)args->data[i]; @@ -4651,15 +4855,9 @@ Expression *IsExp::semantic(Scope *sc) 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 + unsigned errors_save = global.startGagging(); targ = targ->semantic(loc, sc); - global.gag--; - unsigned gerrors = global.errors; - global.errors = errors_save; - - if (gerrors) // if any errors happened + if (global.endGagging(errors_save)) // if any errors happened { // then condition is false goto Lno; } @@ -4799,7 +4997,6 @@ Expression *IsExp::semantic(Scope *sc) * If TRUE, declare id as an alias for the specialized type. */ - MATCH m; TemplateTypeParameter tp(loc, id, NULL, NULL); TemplateParameters parameters; @@ -4807,10 +5004,10 @@ Expression *IsExp::semantic(Scope *sc) parameters.data[0] = (void *)&tp; Objects dedtypes; - dedtypes.setDim(1); - dedtypes.data[0] = NULL; + dedtypes.setDim(parameters.dim); + dedtypes.zero(); - m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes); + MATCH m = targ->deduceType(sc, tspec, ¶meters, &dedtypes); if (m == MATCHnomatch || (m != MATCHexact && tok == TOKequal)) { @@ -4829,7 +5026,7 @@ Expression *IsExp::semantic(Scope *sc) /* Declare trailing parameters */ - for (int i = 1; i < parameters->dim; i++) + for (size_t i = 1; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; Declaration *s = NULL; @@ -4864,8 +5061,8 @@ Expression *IsExp::semantic(Scope *sc) * is(targ : tspec) */ tspec = tspec->semantic(loc, sc); - //printf("targ = %s\n", targ->toChars()); - //printf("tspec = %s\n", tspec->toChars()); + //printf("targ = %s, %s\n", targ->toChars(), targ->deco); + //printf("tspec = %s, %s\n", tspec->toChars(), tspec->deco); if (tok == TOKcolon) { if (targ->implicitConvTo(tspec)) goto Lyes; @@ -4914,7 +5111,7 @@ void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) #if DMDV2 if (parameters) { // First parameter is already output, so start with second - for (int i = 1; i < parameters->dim; i++) + for (size_t i = 1; i < parameters->dim; i++) { buf->writeByte(','); TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; @@ -5207,17 +5404,19 @@ Expression *CompileExp::semantic(Scope *sc) #endif UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); + if (e1->op == TOKerror) + return e1; if (!e1->type->isString()) { error("argument to mixin must be a string type, not %s\n", e1->type->toChars()); return new ErrorExp(); } e1 = e1->optimize(WANTvalue | WANTinterpret); - if (e1->op != TOKstring) + StringExp *se = e1->toString(); + if (!se) { error("argument to mixin must be a string, not (%s)", e1->toChars()); return new ErrorExp(); } - StringExp *se = (StringExp *)e1; se = se->toUTF8(sc); Parser p(sc->module, (unsigned char *)se->string, se->len, 0); p.loc = loc; @@ -5252,7 +5451,7 @@ Expression *FileExp::semantic(Scope *sc) #endif UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue); + e1 = e1->optimize(WANTvalue | WANTinterpret); if (e1->op != TOKstring) { error("file name argument must be a string, not (%s)", e1->toChars()); goto Lerror; @@ -5271,7 +5470,7 @@ Expression *FileExp::semantic(Scope *sc) * http://cwe.mitre.org/data/definitions/22.html */ - name = FileName::safeSearchPath(global.filePath, name); + name = FileName::safeSearchPath((Strings *)global.filePath, name); if (!name) { error("file %s cannot be found or not in a path specified with -J", se->toChars()); goto Lerror; @@ -5291,12 +5490,10 @@ Expression *FileExp::semantic(Scope *sc) se = new StringExp(loc, f.buffer, f.len); } } - Lret: return se->semantic(sc); Lerror: - se = new StringExp(loc, (char *)""); - goto Lret; + return new ErrorExp(); } void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -5456,6 +5653,22 @@ Expression *DotIdExp::semantic(Scope *sc) UnaExp::semantic(sc); + if (ident == Id::mangleof) + { // symbol.mangleof + Dsymbol *ds; + switch (e1->op) + { + case TOKimport: ds = ((ScopeExp *)e1)->sds; goto L1; + case TOKvar: ds = ((VarExp *)e1)->var; goto L1; + case TOKdotvar: ds = ((DotVarExp *)e1)->var; goto L1; + L1: + char* s = ds->mangle(); + e = new StringExp(loc, s, strlen(s), 'c'); + e = e->semantic(sc); + return e; + } + } + if (e1->op == TOKdotexp) { DotExp *de = (DotExp *)e1; @@ -5464,6 +5677,7 @@ Expression *DotIdExp::semantic(Scope *sc) } else { + if (e1->op != TOKtype) e1 = resolveProperties(sc, e1); eleft = NULL; eright = e1; @@ -5475,7 +5689,7 @@ Expression *DotIdExp::semantic(Scope *sc) TupleExp *te = (TupleExp *)e1; Expressions *exps = new Expressions(); exps->setDim(te->exps->dim); - for (int i = 0; i < exps->dim; i++) + for (size_t 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); @@ -5685,14 +5899,11 @@ Expression *DotIdExp::semantic(Scope *sc) * as: * .ident(e1) */ - unsigned errors = global.errors; - global.gag++; + unsigned errors = global.startGagging(); Type *t1 = e1->type; e = e1->type->dotExp(sc, e1, ident); - global.gag--; - if (errors != global.errors) // if failed to find the property + if (global.endGagging(errors)) // if failed to find the property { - global.errors = errors; e1->type = t1; // kludge to restore type e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); e = new CallExp(loc, e, e1); @@ -5859,7 +6070,7 @@ Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) if (fd && ((fd->isCtorDeclaration() && var->storage_class & STCfield) || (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) && - fd->toParent() == var->toParent() && + fd->toParent2() == var->toParent() && e1->op == TOKthis ) { @@ -5939,6 +6150,8 @@ Expression *DotTemplateInstanceExp::semantic(Scope *sc) Expression *e = new DotIdExp(loc, e1, ti->name); L1: e = e->semantic(sc); + if (e->op == TOKerror) + return e; if (e->op == TOKdottd) { if (global.errors) @@ -5947,6 +6160,14 @@ L1: TemplateDeclaration *td = dte->td; eleft = dte->e1; ti->tempdecl = td; +#if DMDV2 + if (ti->needsTypeInference(sc)) + { + e = new CallExp(loc, this); + return e->semantic(sc); + } + else +#endif ti->semantic(sc); if (!ti->inst) // if template failed to expand return new ErrorExp(); @@ -6254,7 +6475,6 @@ Expression *CallExp::semantic(Scope *sc) { TypeFunction *tf; FuncDeclaration *f; - int i; Type *t1; int istemp; Objects *targsi = NULL; // initial list of template arguments @@ -6338,15 +6558,12 @@ Expression *CallExp::semantic(Scope *sc) * If not, go with partial explicit specialization. */ ti->semanticTiargs(sc); - unsigned errors = global.errors; - global.gag++; + unsigned errors = global.startGagging(); ti->semantic(sc); - global.gag--; - if (errors != global.errors) + if (global.endGagging(errors)) { /* Didn't work, go with partial explicit specialization */ - global.errors = errors; targsi = ti->tiargs; e1 = new IdentifierExp(loc, ti->name); } @@ -6366,13 +6583,10 @@ Expression *CallExp::semantic(Scope *sc) */ ti->semanticTiargs(sc); Expression *etmp; - unsigned errors = global.errors; - global.gag++; + unsigned errors = global.startGagging(); etmp = e1->semantic(sc); - global.gag--; - if (errors != global.errors) + if (global.endGagging(errors)) { - global.errors = errors; targsi = ti->tiargs; e1 = new DotIdExp(loc, se->e1, ti->name); } @@ -6559,11 +6773,13 @@ Lagain: ) { error("cannot call public/export function %s from invariant", f->toChars()); + return new ErrorExp(); } checkDeprecated(sc, f); #if DMDV2 checkPurity(sc, f); + checkSafety(sc, f); #endif accessCheck(loc, sc, ue->e1, f); if (!f->needThis()) @@ -6575,10 +6791,15 @@ Lagain: else { if (e1->op == TOKdotvar) + { dve->var = f; + e1->type = f->type; + } else + { e1 = new DotVarExp(loc, dte->e1, f); - e1->type = f->type; + e1 = e1->semantic(sc); + } // See if we need to adjust the 'this' pointer AggregateDeclaration *ad = f->isThis(); @@ -6629,6 +6850,7 @@ Lagain: } f = f->overloadResolve(loc, NULL, arguments, sc->module); + accessCheck(loc, sc, NULL, f); checkDeprecated(sc, f); #if DMDV2 checkPurity(sc, f); @@ -6945,7 +7167,11 @@ Expression *AddrExp::semantic(Scope *sc) { m = sc->module; UnaExp::semantic(sc); + if (e1->type == Type::terror) + return new ErrorExp(); e1 = e1->toLvalue(sc, NULL); + if (e1->op == TOKerror) + return e1; if (!e1->type) { error("cannot take address of %s", e1->toChars()); @@ -6991,9 +7217,8 @@ Expression *AddrExp::semantic(Scope *sc) } if (f && f->isNested()) - { Expression *e; - - e = new DelegateExp(loc, e1, f); + { + Expression *e = new DelegateExp(loc, e1, f); e = e->semantic(sc); return e; } @@ -7043,12 +7268,14 @@ Expression *PtrExp::semantic(Scope *sc) switch (tb->ty) { case Tpointer: - type = tb->next; + type = ((TypePointer *)tb)->next; break; case Tsarray: case Tarray: - type = tb->next; + if (!global.params.useDeprecated) + error("using * on an array is deprecated; use *(%s).ptr instead", e1->toChars()); + type = ((TypeArray *)tb)->next; e1 = e1->castTo(sc, type->pointerTo()); break; @@ -7245,6 +7472,8 @@ Expression *DeleteExp::semantic(Scope *sc) UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); e1 = e1->toLvalue(sc, NULL); + if (e1->op == TOKerror) + return e1; type = Type::tvoid; tb = e1->type->toBasetype(); @@ -7292,7 +7521,7 @@ Expression *DeleteExp::semantic(Scope *sc) break; } error("cannot delete type %s", e1->type->toChars()); - break; + return new ErrorExp(); } if (e1->op == TOKindex) @@ -7316,7 +7545,7 @@ int DeleteExp::checkSideEffect(int flag) Expression *DeleteExp::checkToBoolean() { error("delete does not give a boolean result"); - return this; + return new ErrorExp(); } void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -7352,8 +7581,6 @@ Expression *CastExp::syntaxCopy() Expression *CastExp::semantic(Scope *sc) { Expression *e; - BinExp *b; - UnaExp *u; #if LOGSEMANTIC printf("CastExp::semantic('%s')\n", toChars()); @@ -7403,7 +7630,9 @@ Expression *CastExp::semantic(Scope *sc) } // Struct casts are possible only when the sizes match - if (tob->ty == Tstruct || t1b->ty == Tstruct) + // Same with static array -> static array + if (tob->ty == Tstruct || t1b->ty == Tstruct || + (tob->ty == Tsarray && t1b->ty == Tsarray)) { size_t fromsize = t1b->size(loc); size_t tosize = tob->size(loc); @@ -7565,31 +7794,34 @@ Expression *SliceExp::semantic(Scope *sc) else goto Lerror; + { + Scope *sc2 = sc; if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) { sym = new ArrayScopeSymbol(this); sym->loc = loc; sym->parent = sc->scopesym; - sc = sc->push(sym); + sc2 = sc->push(sym); } if (lwr) - { lwr = lwr->semantic(sc); - lwr = resolveProperties(sc, lwr); - lwr = lwr->implicitCastTo(sc, Type::tsize_t); + { lwr = lwr->semantic(sc2); + lwr = resolveProperties(sc2, lwr); + lwr = lwr->implicitCastTo(sc2, Type::tsize_t); if (lwr->type == Type::terror) goto Lerr; } if (upr) - { upr = upr->semantic(sc); - upr = resolveProperties(sc, upr); - upr = upr->implicitCastTo(sc, Type::tsize_t); - if (lwr->type == Type::terror) + { upr = upr->semantic(sc2); + upr = resolveProperties(sc2, upr); + upr = upr->implicitCastTo(sc2, Type::tsize_t); + if (upr->type == Type::terror) goto Lerr; } - if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) - sc->pop(); + if (sc2 != sc) + sc2->pop(); + } if (t->ty == Ttuple) { @@ -7695,6 +7927,11 @@ Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) return this; } +int SliceExp::isBool(int result) +{ + return e1->isBool(result); +} + void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { expToCBuffer(buf, hgs, e1, precedence[op]); @@ -7714,6 +7951,13 @@ void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writeByte(']'); } +int SliceExp::canThrow() +{ + return UnaExp::canThrow() + || (lwr != NULL && lwr->canThrow()) + || (upr != NULL && upr->canThrow()); +} + /********************** ArrayLength **************************************/ ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) @@ -7944,8 +8188,6 @@ IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) Expression *IndexExp::semantic(Scope *sc) { Expression *e; - BinExp *b; - UnaExp *u; Type *t1; ScopeDsymbol *sym; @@ -7979,6 +8221,8 @@ Expression *IndexExp::semantic(Scope *sc) error("%s has no value", e2->toChars()); goto Lerr; } + if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix + e2 = (*((TupleExp *)e2)->exps)[0]; e2 = resolveProperties(sc, e2); if (e2->type == Type::terror) goto Lerr; @@ -8299,7 +8543,7 @@ Expression *AssignExp::semantic(Scope *sc) { Expressions *exps = new Expressions; exps->setDim(dim); - for (int i = 0; i < dim; i++) + for (size_t 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); @@ -8401,7 +8645,7 @@ Expression *AssignExp::checkToBoolean() // if (a = b) ... // are usually mistakes. - error("'=' does not give a boolean result"); + error("assignment cannot be used as a condition, perhaps == was meant?"); return this; } @@ -8630,6 +8874,7 @@ Expression *CatAssignExp::semantic(Scope *sc) else if (tb1->ty == Tarray && (tb1next->ty == Tchar || tb1next->ty == Twchar) && + e2->type->ty != tb1next->ty && e2->implicitConvTo(Type::tdchar) ) { // Append dchar to char[] or wchar[] @@ -9091,15 +9336,15 @@ Expression *MinExp::semantic(Scope *sc) else if (t2->isintegral()) e = scaleFactor(sc); else - { error("incompatible types for minus"); - return new IntegerExp(0); + { error("can't subtract %s from pointer", t2->toChars()); + return new ErrorExp(); } } else if (t2->ty == Tpointer) { type = e2->type; error("can't subtract pointer from %s", e1->type->toChars()); - return new IntegerExp(0); + return new ErrorExp(); } else { @@ -9611,11 +9856,21 @@ Expression *OrOrExp::semantic(Scope *sc) e2 = resolveProperties(sc, e2); e2 = e2->checkToPointer(); - type = Type::tboolean; if (e2->type->ty == Tvoid) type = Type::tvoid; + else + { + e2 = e2->checkToBoolean(); + type = Type::tboolean; + } if (e2->op == TOKtype || e2->op == TOKimport) - error("%s is not an expression", e2->toChars()); + { error("%s is not an expression", e2->toChars()); + return new ErrorExp(); + } + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; return this; } @@ -9676,11 +9931,21 @@ Expression *AndAndExp::semantic(Scope *sc) e2 = resolveProperties(sc, e2); e2 = e2->checkToPointer(); - type = Type::tboolean; if (e2->type->ty == Tvoid) type = Type::tvoid; + else + { + e2 = e2->checkToBoolean(); + type = Type::tboolean; + } if (e2->op == TOKtype || e2->op == TOKimport) - error("%s is not an expression", e2->toChars()); + { error("%s is not an expression", e2->toChars()); + return new ErrorExp(); + } + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; return this; } @@ -10119,10 +10384,7 @@ Expression *CondExp::toLvalue(Scope *sc, Expression *ex) 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); diff --git a/dmd/expression.h b/dmd/expression.h index c4536907..53d4ccc3 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -44,6 +44,8 @@ struct BinExp; struct AssignExp; struct InterState; struct OverloadSet; +struct Initializer; +struct StringExp; enum TOK; @@ -82,6 +84,17 @@ void expandTuples(Expressions *exps); FuncDeclaration *hasThis(Scope *sc); Expression *fromConstInitializer(int result, Expression *e); int arrayExpressionCanThrow(Expressions *exps); +TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s); + +/* Interpreter: what form of return value expression is required? + */ +enum CtfeGoal +{ ctfeNeedRvalue, // Must return an Rvalue + ctfeNeedLvalue, // Must return an Lvalue + ctfeNeedAnyValue, // Can return either an Rvalue or an Lvalue + ctfeNeedLvalueRef,// Must return a reference to an Lvalue (for ref types) + ctfeNeedNothing // The return value is not required +}; struct IntRange { uinteger_t imin; @@ -99,6 +112,7 @@ struct Expression : Object Expression *copy(); virtual Expression *syntaxCopy(); virtual Expression *semantic(Scope *sc); + Expression *trySemantic(Scope *sc); int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() @@ -117,6 +131,7 @@ struct Expression : Object virtual real_t toReal(); virtual real_t toImaginary(); virtual complex_t toComplex(); + virtual StringExp *toString(); virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual void toMangleBuffer(OutBuffer *buf); virtual Expression *toLvalue(Scope *sc, Expression *e); @@ -143,9 +158,12 @@ struct Expression : Object virtual Expression *optimize(int result); #define WANTflags 1 #define WANTvalue 2 + // A compile-time result is required. Give an error if not possible #define WANTinterpret 4 + // Same as WANTvalue, but also expand variables as far as possible + #define WANTexpand 8 - virtual Expression *interpret(InterState *istate); + virtual Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); virtual int isConst(); virtual int isBool(int result); @@ -194,7 +212,7 @@ struct IntegerExp : Expression IntegerExp(dinteger_t value); int equals(Object *o); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); char *toChars(); void dump(int indent); dinteger_t toInteger(); @@ -221,6 +239,7 @@ struct ErrorExp : IntegerExp ErrorExp(); Expression *implicitCastTo(Scope *sc, Type *t); + Expression *castTo(Scope *sc, Type *t); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; @@ -231,7 +250,7 @@ struct RealExp : Expression RealExp(Loc loc, real_t value, Type *type); int equals(Object *o); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); char *toChars(); dinteger_t toInteger(); uinteger_t toUInteger(); @@ -259,7 +278,7 @@ struct ComplexExp : Expression ComplexExp(Loc loc, complex_t value, Type *type); int equals(Object *o); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); char *toChars(); dinteger_t toInteger(); uinteger_t toUInteger(); @@ -271,9 +290,7 @@ struct ComplexExp : Expression 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); @@ -321,7 +338,7 @@ struct ThisExp : Expression ThisExp(Loc loc); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBool(int result); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *toLvalue(Scope *sc, Expression *e); @@ -360,11 +377,12 @@ struct NullExp : Expression Expression *semantic(Scope *sc); int isBool(int result); int isConst(); + StringExp *toString(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toMangleBuffer(OutBuffer *buf); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); #if IN_DMD elem *toElem(IRState *irs); dt_t **toDt(dt_t **pdt); @@ -389,7 +407,9 @@ struct StringExp : Expression int equals(Object *o); char *toChars(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); + size_t length(); + StringExp *toString(); StringExp *toUTF8(Scope *sc); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); @@ -423,7 +443,7 @@ struct TupleExp : Expression void checkEscape(); int checkSideEffect(int flag); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *castTo(Scope *sc, Type *t); #if IN_DMD elem *toElem(IRState *irs); @@ -449,11 +469,12 @@ struct ArrayLiteralExp : Expression Expression *semantic(Scope *sc); int isBool(int result); int checkSideEffect(int flag); + StringExp *toString(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toMangleBuffer(OutBuffer *buf); void scanForNestedRef(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); @@ -488,7 +509,7 @@ struct AssocArrayLiteralExp : Expression void toMangleBuffer(OutBuffer *buf); void scanForNestedRef(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); @@ -507,6 +528,7 @@ struct StructLiteralExp : Expression StructDeclaration *sd; // which aggregate this is for Expressions *elements; // parallels sd->fields[] with // NULL entries for fields to skip + Type *stype; // final type of result (can be different from sd's type) #if IN_DMD Symbol *sym; // back end symbol to initialize with literal @@ -514,7 +536,7 @@ struct StructLiteralExp : Expression size_t soffset; // offset from start of s int fillHoles; // fill alignment 'holes' with zero - StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements); + StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL); Expression *syntaxCopy(); Expression *semantic(Scope *sc); @@ -525,7 +547,7 @@ struct StructLiteralExp : Expression void toMangleBuffer(OutBuffer *buf); void scanForNestedRef(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *toLvalue(Scope *sc, Expression *e); int inlineCost(InlineCostState *ics); @@ -609,7 +631,7 @@ struct NewExp : Expression Type *newtype, Expressions *arguments); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *optimize(int result); #if IN_DMD elem *toElem(IRState *irs); @@ -666,7 +688,7 @@ struct SymOffExp : Expression SymOffExp(Loc loc, Declaration *var, unsigned offset); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void checkEscape(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int isConst(); @@ -696,7 +718,7 @@ struct VarExp : Expression int equals(Object *o); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void dump(int indent); char *toChars(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -744,12 +766,13 @@ struct FuncExp : Expression FuncExp(Loc loc, FuncLiteralDeclaration *fd); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void scanForNestedRef(Scope *sc); char *toChars(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); #endif int inlineCost(InlineCostState *ics); @@ -771,7 +794,7 @@ struct DeclarationExp : Expression DeclarationExp(Loc loc, Dsymbol *declaration); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD @@ -857,7 +880,7 @@ struct UnaExp : Expression Expression *optimize(int result); void dump(int indent); void scanForNestedRef(Scope *sc); - Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)); + Expression *interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *)); int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); @@ -888,9 +911,12 @@ struct BinExp : Expression 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); + Expression *interpretCommon(InterState *istate, CtfeGoal goal, + Expression *(*fp)(Type *, Expression *, Expression *)); + Expression *interpretCommon2(InterState *istate, CtfeGoal goal, + Expression *(*fp)(TOK, Type *, Expression *, Expression *)); + Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, + Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); Expression *arrayOp(Scope *sc); int inlineCost(InlineCostState *ics); @@ -933,7 +959,7 @@ struct AssertExp : UnaExp AssertExp(Loc loc, Expression *e, Expression *msg = NULL); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -977,7 +1003,7 @@ struct DotVarExp : UnaExp Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void dump(int indent); #if IN_DMD @@ -1008,7 +1034,7 @@ struct DelegateExp : UnaExp DelegateExp(Loc loc, Expression *e, FuncDeclaration *func); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1052,7 +1078,7 @@ struct CallExp : UnaExp Expression *syntaxCopy(); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void dump(int indent); @@ -1086,6 +1112,7 @@ struct AddrExp : UnaExp MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); Expression *optimize(int result); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); #if IN_LLVM DValue* toElem(IRState* irs); @@ -1105,7 +1132,7 @@ struct PtrExp : UnaExp elem *toElem(IRState *irs); #endif Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); #if IN_LLVM DValue* toElem(IRState* irs); @@ -1118,7 +1145,7 @@ struct NegExp : UnaExp NegExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1148,7 +1175,7 @@ struct ComExp : UnaExp ComExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1169,7 +1196,7 @@ struct NotExp : UnaExp NotExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBit(); #if IN_DMD elem *toElem(IRState *irs); @@ -1185,7 +1212,7 @@ struct BoolExp : UnaExp BoolExp(Loc loc, Expression *e, Type *type); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBit(); #if IN_DMD elem *toElem(IRState *irs); @@ -1221,7 +1248,7 @@ struct CastExp : UnaExp Expression *syntaxCopy(); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); void checkEscape(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1254,9 +1281,10 @@ struct SliceExp : UnaExp void checkEscapeRef(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); + int isBool(int result); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void dump(int indent); #if IN_DMD elem *toElem(IRState *irs); @@ -1264,6 +1292,7 @@ struct SliceExp : UnaExp void scanForNestedRef(Scope *sc); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); + int canThrow(); int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); @@ -1280,7 +1309,7 @@ struct ArrayLengthExp : UnaExp ArrayLengthExp(Loc loc, Expression *e1); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD elem *toElem(IRState *irs); @@ -1332,7 +1361,7 @@ struct CommaExp : BinExp int isBool(int result); int checkSideEffect(int flag); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); #if IN_DMD elem *toElem(IRState *irs); #endif @@ -1354,7 +1383,7 @@ struct IndexExp : BinExp Expression *modifiableLvalue(Scope *sc, Expression *e); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *doInline(InlineDoState *ids); void scanForNestedRef(Scope *sc); @@ -1373,7 +1402,7 @@ struct PostExp : BinExp { PostExp(enum TOK op, Loc loc, Expression *e); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Identifier *opId(); // For operator overloading #if IN_DMD @@ -1391,7 +1420,7 @@ struct AssignExp : BinExp AssignExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *checkToBoolean(); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Identifier *opId(); // For operator overloading void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1424,7 +1453,7 @@ struct op##AssignExp : BinExp \ { \ op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ Expression *semantic(Scope *sc); \ - Expression *interpret(InterState *istate); \ + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); \ X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ X(Expression *buildArrayLoop(Parameters *fparams);) \ \ @@ -1460,7 +1489,7 @@ struct AddExp : BinExp AddExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1484,7 +1513,7 @@ struct MinExp : BinExp MinExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1507,7 +1536,7 @@ struct CatExp : BinExp CatExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); // For operator overloading Identifier *opId(); @@ -1527,7 +1556,7 @@ struct MulExp : BinExp MulExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1550,7 +1579,7 @@ struct DivExp : BinExp DivExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1572,7 +1601,7 @@ struct ModExp : BinExp ModExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1606,7 +1635,7 @@ struct ShlExp : BinExp ShlExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); // For operator overloading Identifier *opId(); @@ -1626,7 +1655,7 @@ struct ShrExp : BinExp ShrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); // For operator overloading Identifier *opId(); @@ -1646,7 +1675,7 @@ struct UshrExp : BinExp UshrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); // For operator overloading Identifier *opId(); @@ -1666,7 +1695,7 @@ struct AndExp : BinExp AndExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1689,7 +1718,7 @@ struct OrExp : BinExp OrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1712,7 +1741,7 @@ struct XorExp : BinExp XorExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1737,7 +1766,7 @@ struct OrOrExp : BinExp Expression *checkToBoolean(); int isBit(); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); #if IN_DMD elem *toElem(IRState *irs); @@ -1755,7 +1784,7 @@ struct AndAndExp : BinExp Expression *checkToBoolean(); int isBit(); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); #if IN_DMD elem *toElem(IRState *irs); @@ -1771,7 +1800,7 @@ 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); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBit(); // For operator overloading @@ -1791,6 +1820,7 @@ struct InExp : BinExp { InExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBit(); // For operator overloading @@ -1809,6 +1839,7 @@ struct InExp : BinExp struct RemoveExp : BinExp { RemoveExp(Loc loc, Expression *e1, Expression *e2); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD elem *toElem(IRState *irs); @@ -1826,7 +1857,7 @@ 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); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBit(); // For operator overloading @@ -1850,7 +1881,7 @@ struct IdentityExp : BinExp Expression *semantic(Scope *sc); int isBit(); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); #if IN_DMD elem *toElem(IRState *irs); #endif @@ -1870,7 +1901,7 @@ struct CondExp : BinExp Expression *syntaxCopy(); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void checkEscape(); void checkEscapeRef(); Expression *toLvalue(Scope *sc, Expression *e); diff --git a/dmd/func.c b/dmd/func.c index 62e7ee27..2a9d2386 100644 --- a/dmd/func.c +++ b/dmd/func.c @@ -218,6 +218,10 @@ void FuncDeclaration::semantic(Scope *sc) if (isAbstract() && !isVirtual()) error("non-virtual functions cannot be abstract"); + // https://github.com/donc/dmd/commit/9f7b2f8cfe5d7482f2de7f9678c176d54abe237f#commitcomment-321724 + //if (isOverride() && !isVirtual()) + //error("cannot override a non-virtual function"); + if (isAbstract() && isFinal()) error("cannot be both final and abstract"); #if 0 @@ -313,7 +317,7 @@ void FuncDeclaration::semantic(Scope *sc) // ctor = (CtorDeclaration *)this; // if (!cd->ctor) // cd->ctor = ctor; - return; + goto Ldone; } #if 0 @@ -414,12 +418,13 @@ void FuncDeclaration::semantic(Scope *sc) warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); #endif - if (fdv->toParent() == parent) + FuncDeclaration *fdc = ((Dsymbol *)cd->vtbl.data[vi])->isFuncDeclaration(); + if (fdc->toParent() == parent) { // If both are mixins, then error. // If either is not, the one that is not overrides // the other. - if (fdv->parent->isClassDeclaration()) + if (fdc->parent->isClassDeclaration()) break; if (!this->parent->isClassDeclaration() #if !BREAKABI @@ -431,7 +436,7 @@ void FuncDeclaration::semantic(Scope *sc) ) error("multiple overrides of same function"); } - cd->vtbl.data[vi] = (void *)this; + cd->vtbl[vi] = this; vtblIndex = vi; /* Remember which functions this overrides @@ -496,15 +501,12 @@ void FuncDeclaration::semantic(Scope *sc) /* Only need to have a tintro if the vptr * offsets differ */ - unsigned errors = global.errors; - global.gag++; // suppress printing of error messages + unsigned errors = global.startGagging(); // suppress printing of error messages int offset; int baseOf = fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset); - global.gag--; // suppress printing of error messages - if (errors != global.errors) + if (global.endGagging(errors)) { // any error in isBaseOf() is a forward reference error, so we bail out - global.errors = errors; cd->sizeok = 2; // can't finish due to forward reference Module::dprogress = dprogress_save; return; @@ -640,7 +642,7 @@ void FuncDeclaration::semantic(Scope *sc) FuncDeclaration *fd = new FuncDeclaration(loc, loc, Id::require, STCundefined, tf); fd->fbody = frequire; - Statement *s1 = new DeclarationStatement(loc, fd); + Statement *s1 = new ExpStatement(loc, fd); Expression *e = new CallExp(loc, new VarExp(loc, fd), (Expressions *)NULL); Statement *s2 = new ExpStatement(loc, e); frequire = new CompoundStatement(loc, s1, s2); @@ -667,7 +669,7 @@ void FuncDeclaration::semantic(Scope *sc) FuncDeclaration *fd = new FuncDeclaration(loc, loc, Id::ensure, STCundefined, tf); fd->fbody = fensure; - Statement *s1 = new DeclarationStatement(loc, fd); + Statement *s1 = new ExpStatement(loc, fd); Expression *eresult = NULL; if (outId) eresult = new IdentifierExp(loc, outId); @@ -746,6 +748,20 @@ void FuncDeclaration::semantic3(Scope *sc) } } + if (frequire) + { + for (int i = 0; i < foverrides.dim; i++) + { + FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; + + if (fdv->fbody && !fdv->frequire) + { + error("cannot have an in contract when overriden function %s does not have an in contract", fdv->toPrettyChars()); + break; + } + } + } + frequire = mergeFrequire(frequire); fensure = mergeFensure(fensure); @@ -768,7 +784,10 @@ void FuncDeclaration::semantic3(Scope *sc) sc2->sw = NULL; sc2->fes = fes; sc2->linkage = LINKd; - sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STCfinal); + sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | + STCdeprecated | STCoverride | + STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | + STCproperty | STCsafe | STCtrusted | STCsystem); sc2->protection = PROTpublic; sc2->explicitProtection = 0; sc2->structalign = 8; @@ -823,6 +842,21 @@ void FuncDeclaration::semantic3(Scope *sc) #else Type *t; + if (global.params.is64bit) + { // Declare save area for varargs registers + Type *t = new TypeIdentifier(loc, Id::va_argsave_t); + t = t->semantic(loc, sc); + if (t == Type::terror) + error("must import std.c.stdarg to use variadic functions"); + else + { + v_argsave = new VarDeclaration(loc, t, Id::va_argsave, NULL); + v_argsave->semantic(sc2); + sc2->insert(v_argsave); + v_argsave->parent = this; + } + } + if (f->linkage == LINKd) { // Declare _arguments[] #if BREAKABI @@ -846,7 +880,7 @@ void FuncDeclaration::semantic3(Scope *sc) v_arguments->parent = this; #endif } - if (f->linkage == LINKd || (parameters && parameters->dim)) + if (f->linkage == LINKd || (f->parameters && Parameter::dim(f->parameters))) { // Declare _argptr #if IN_GCC t = d_gcc_builtin_va_list_d_type; @@ -911,7 +945,7 @@ void FuncDeclaration::semantic3(Scope *sc) { /* parameters[] has all the tuples removed, as the back end * doesn't know about tuples */ - parameters = new Dsymbols(); + parameters = new VarDeclarations(); parameters->reserve(nparams); for (size_t i = 0; i < nparams; i++) { @@ -1143,7 +1177,7 @@ void FuncDeclaration::semantic3(Scope *sc) f = (TypeFunction *)type; } - int offend = fbody ? fbody->blockExit() & BEfallthru : TRUE; + int offend = fbody ? fbody->blockExit(FALSE) & BEfallthru : TRUE; if (isStaticCtorDeclaration()) { /* It's a static constructor. Ensure that all @@ -1190,17 +1224,16 @@ void FuncDeclaration::semantic3(Scope *sc) 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) + 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); @@ -1287,6 +1320,17 @@ void FuncDeclaration::semantic3(Scope *sc) v_argptr->init = new VoidInitializer(loc); #else Type *t = argptr->type; + if (global.params.is64bit) + { // Initialize _argptr to point to v_argsave + Expression *e1 = new VarExp(0, argptr); + Expression *e = new SymOffExp(0, v_argsave, 6*8 + 8*16); + e->type = argptr->type; + e = new AssignExp(0, e1, e); + e = e->semantic(sc); + a->push(new ExpStatement(0, e)); + } + else + { // Initialize _argptr to point past non-variadic arg VarDeclaration *p; unsigned offset = 0; @@ -1347,15 +1391,10 @@ void FuncDeclaration::semantic3(Scope *sc) // 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()) @@ -1483,9 +1522,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (isSynchronized()) { AggregateDeclaration *ad = isThis(); - ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL; - if (!cd) - error("synchronized function %s must be a member of a class", toChars()); + ClassDeclaration *cd = ad ? ad->isClassDeclaration() : parent->isClassDeclaration(); Expression *sync; if (isStatic()) @@ -1618,7 +1655,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf) } sf = fdv->mergeFrequire(sf); - if (fdv->fdrequire) + if (sf && fdv->fdrequire) { //printf("fdv->frequire: %s\n", fdv->frequire->toChars()); /* Make the call: @@ -1629,15 +1666,13 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf) Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire), eresult); Statement *s2 = new ExpStatement(loc, e); - if (sf) - { Catch *c = new Catch(loc, NULL, NULL, sf); + Catch *c = new Catch(loc, NULL, NULL, sf); Array *catches = new Array(); catches->push(c); sf = new TryCatchStatement(loc, s2, catches); } else - sf = s2; - } + return NULL; } return sf; } @@ -3011,7 +3046,7 @@ void StaticCtorDeclaration::semantic(Scope *sc) VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); v->storage_class = STCstatic; Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); + Statement *s = new ExpStatement(0, v); sa->push(s); Expression *e = new IdentifierExp(0, id); e = new AddAssignExp(0, e, new IntegerExp(1)); @@ -3053,6 +3088,11 @@ int StaticCtorDeclaration::isVirtual() return FALSE; } +bool StaticCtorDeclaration::hasStaticCtorOrDtor() +{ + return TRUE; +} + int StaticCtorDeclaration::addPreInvariant() { return FALSE; @@ -3117,7 +3157,7 @@ void StaticDtorDeclaration::semantic(Scope *sc) VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); v->storage_class = STCstatic; Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); + Statement *s = new ExpStatement(0, v); sa->push(s); Expression *e = new IdentifierExp(0, id); e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); @@ -3160,6 +3200,11 @@ int StaticDtorDeclaration::isVirtual() return FALSE; } +bool StaticDtorDeclaration::hasStaticCtorOrDtor() +{ + return TRUE; +} + int StaticDtorDeclaration::addPreInvariant() { return FALSE; diff --git a/dmd/hdrgen.c b/dmd/hdrgen.c index 392ab439..87c9ffee 100644 --- a/dmd/hdrgen.c +++ b/dmd/hdrgen.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // Initial header generation implementation by Dave Fladebo // http://www.digitalmars.com @@ -10,8 +10,6 @@ // Routines to emit header files -#ifdef _DH - #define PRETTY_PRINT #define TEST_EMIT_ALL 0 // For Testing @@ -85,7 +83,7 @@ void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); } - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->toHBuffer(buf, hgs); @@ -100,5 +98,3 @@ void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs) /*************************************/ - -#endif // #ifdef _DH diff --git a/dmd/identifier.h b/dmd/identifier.h index 028d3332..1abb3a41 100644 --- a/dmd/identifier.h +++ b/dmd/identifier.h @@ -35,9 +35,7 @@ struct Identifier : Object int compare(Object *o); void print(); char *toChars(); -#ifdef _DH char *toHChars(); -#endif const char *toHChars2(); int dyncast(); diff --git a/dmd/idgen.c b/dmd/idgen.c index 88d12383..1036378f 100644 --- a/dmd/idgen.c +++ b/dmd/idgen.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -60,6 +60,7 @@ Msgtable msgtable[] = { "typeinfo" }, { "outer" }, { "Exception" }, + { "Error" }, { "withSym", "__withSym" }, { "result", "__result" }, { "returnLabel", "__returnLabel" }, @@ -249,6 +250,31 @@ Msgtable msgtable[] = { "main" }, { "WinMain" }, { "DllMain" }, + + // varargs implementation + { "va_argsave_t", "__va_argsave_t" }, + { "va_argsave", "__va_argsave" }, + + // Builtin functions + { "std" }, + { "core" }, + { "math" }, + { "sin" }, + { "cos" }, + { "tan" }, + { "_sqrt", "sqrt" }, + { "_pow", "pow" }, + { "atan2" }, + { "rndtol" }, + { "expm1" }, + { "exp2" }, + { "yl2x" }, + { "yl2xp1" }, + { "fabs" }, + { "bitop" }, + { "bsf" }, + { "bsr" }, + { "bswap" }, }; diff --git a/dmd/import.c b/dmd/import.c index c85a0a01..0f78d9c1 100644 --- a/dmd/import.c +++ b/dmd/import.c @@ -25,7 +25,7 @@ /********************************* Import ****************************/ -Import::Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId, +Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId, int isstatic) : Dsymbol(id) { diff --git a/dmd/import.h b/dmd/import.h index b04fed48..65f5e6bf 100644 --- a/dmd/import.h +++ b/dmd/import.h @@ -24,13 +24,11 @@ struct OutBuffer; struct Module; struct Package; struct AliasDeclaration; -#ifdef _DH struct HdrGenState; -#endif struct Import : Dsymbol { - Array *packages; // array of Identifier's representing packages + Identifiers *packages; // array of Identifier's representing packages Identifier *id; // module Identifier Identifier *aliasId; int isstatic; // !=0 if static import @@ -45,7 +43,7 @@ struct Import : Dsymbol Module *mod; Package *pkg; // leftmost package/module - Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId, + Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId, int isstatic); void addAlias(Identifier *name, Identifier *alias); diff --git a/dmd/init.c b/dmd/init.c index 9d05d4cd..46ad5697 100644 --- a/dmd/init.c +++ b/dmd/init.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -34,7 +34,7 @@ Initializer *Initializer::syntaxCopy() return this; } -Initializer *Initializer::semantic(Scope *sc, Type *t) +Initializer *Initializer::semantic(Scope *sc, Type *t, int needInterpret) { return this; } @@ -52,7 +52,7 @@ Initializers *Initializer::arraySyntaxCopy(Initializers *ai) { a = new Initializers(); a->setDim(ai->dim); - for (int i = 0; i < a->dim; i++) + for (size_t i = 0; i < a->dim; i++) { Initializer *e = (Initializer *)ai->data[i]; e = e->syntaxCopy(); @@ -87,7 +87,7 @@ Initializer *VoidInitializer::syntaxCopy() } -Initializer *VoidInitializer::semantic(Scope *sc, Type *t) +Initializer *VoidInitializer::semantic(Scope *sc, Type *t, int needInterpret) { //printf("VoidInitializer::semantic(t = %p)\n", t); type = t; @@ -126,7 +126,7 @@ Initializer *StructInitializer::syntaxCopy() assert(field.dim == value.dim); ai->field.setDim(field.dim); ai->value.setDim(value.dim); - for (int i = 0; i < field.dim; i++) + for (size_t i = 0; i < field.dim; i++) { ai->field.data[i] = field.data[i]; @@ -144,21 +144,25 @@ void StructInitializer::addInit(Identifier *field, Initializer *value) this->value.push(value); } -Initializer *StructInitializer::semantic(Scope *sc, Type *t) +Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) { - TypeStruct *ts; int errors = 0; //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); vars.setDim(field.dim); t = t->toBasetype(); if (t->ty == Tstruct) - { unsigned i; + { unsigned fieldi = 0; - ts = (TypeStruct *)t; + TypeStruct *ts = (TypeStruct *)t; ad = ts->sym; - for (i = 0; i < field.dim; i++) + size_t nfields = ad->fields.dim; +#if DMDV2 + if (((StructDeclaration *)ad)->isnested) + nfields--; // don't count pointer to outer +#endif + for (size_t i = 0; i < field.dim; i++) { Identifier *id = (Identifier *)field.data[i]; Initializer *val = (Initializer *)value.data[i]; @@ -167,8 +171,9 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) if (id == NULL) { - if (fieldi >= ad->fields.dim) + if (fieldi >= nfields) { error(loc, "too many initializers for %s", ad->toChars()); + errors = 1; field.remove(i); i--; continue; @@ -185,15 +190,18 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) if (!s) { error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); + errors = 1; continue; } // Find out which field index it is for (fieldi = 0; 1; fieldi++) { - if (fieldi >= ad->fields.dim) + if (fieldi >= nfields) { - s->error("is not a per-instance initializable field"); + error(loc, "%s.%s is not a per-instance initializable field", + t->toChars(), s->toChars()); + errors = 1; break; } if (s == (Dsymbol *)ad->fields.data[fieldi]) @@ -202,7 +210,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) } if (s && (v = s->isVarDeclaration()) != NULL) { - val = val->semantic(sc, v->type); + val = val->semantic(sc, v->type, needInterpret); value.data[i] = (void *)val; vars.data[i] = (void *)v; } @@ -223,7 +231,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) fd->endloc = loc; Expression *e = new FuncExp(loc, fd); ExpInitializer *ie = new ExpInitializer(loc, e); - return ie->semantic(sc, t); + return ie->semantic(sc, t, needInterpret); } else { @@ -239,7 +247,6 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) return this; } - /*************************************** * This works by transforming a struct initializer into * a struct literal. In the future, the two should be the @@ -257,17 +264,96 @@ Expression *StructInitializer::toExpression() if (!sd) return NULL; Expressions *elements = new Expressions(); + size_t nfields = ad->fields.dim; +#if DMDV2 + if (sd->isnested) + nfields--; +#endif + elements->setDim(nfields); + for (size_t i = 0; i < elements->dim; i++) + { + elements->data[i] = NULL; + } + unsigned fieldi = 0; for (size_t i = 0; i < value.dim; i++) { - if (field.data[i]) + Identifier *id = (Identifier *)field.data[i]; + if (id) + { + Dsymbol * s = ad->search(loc, id, 0); + if (!s) + { + error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); + goto Lno; + } + + // Find out which field index it is + for (fieldi = 0; 1; fieldi++) + { + if (fieldi >= nfields) + { + s->error("is not a per-instance initializable field"); + goto Lno; + } + if (s == (Dsymbol *)ad->fields.data[fieldi]) + break; + } + } + else if (fieldi >= nfields) + { error(loc, "too many initializers for '%s'", ad->toChars()); goto Lno; + } Initializer *iz = (Initializer *)value.data[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); if (!ex) goto Lno; - elements->push(ex); + if (elements->data[fieldi]) + { error(loc, "duplicate initializer for field '%s'", + ((Dsymbol *)ad->fields.data[fieldi])->toChars()); + goto Lno; + } + elements->data[fieldi] = ex; + ++fieldi; + } + // Now, fill in any missing elements with default initializers. + // We also need to validate any anonymous unions + for (size_t i = 0; i < elements->dim; ) + { + VarDeclaration * vd = ((Dsymbol *)ad->fields.data[i])->isVarDeclaration(); + int unionSize = ad->numFieldsInUnion(i); + if (unionSize == 1) + { // Not a union -- default initialize if missing + if (!elements->data[i]) + elements->data[i] = vd->type->defaultInit(); + } + else + { // anonymous union -- check for errors + int found = -1; // index of the first field with an initializer + for (int j = i; j < i + unionSize; ++j) + { + if (!elements->data[j]) + continue; + if (found >= 0) + { + VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration(); + VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration(); + error(loc, "%s cannot have initializers for fields %s and %s in same union", + ad->toChars(), + v1->toChars(), v->toChars()); + goto Lno; + } + found = j; + } + if (found == -1) + { + error(loc, "no initializer for union that contains field %s", + vd->toChars()); + goto Lno; + } + } + i += unionSize; } e = new StructLiteralExp(loc, sd, elements); e->type = sd->type; @@ -275,7 +361,6 @@ Expression *StructInitializer::toExpression() Lno: delete elements; - //error(loc, "struct initializers as expressions are not allowed"); return NULL; } @@ -284,7 +369,7 @@ void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { //printf("StructInitializer::toCBuffer()\n"); buf->writebyte('{'); - for (int i = 0; i < field.dim; i++) + for (size_t i = 0; i < field.dim; i++) { if (i > 0) buf->writebyte(','); @@ -320,7 +405,7 @@ Initializer *ArrayInitializer::syntaxCopy() assert(index.dim == value.dim); ai->index.setDim(index.dim); ai->value.setDim(value.dim); - for (int i = 0; i < ai->value.dim; i++) + for (size_t i = 0; i < ai->value.dim; i++) { Expression *e = (Expression *)index.data[i]; if (e) e = e->syntaxCopy(); @@ -341,7 +426,7 @@ void ArrayInitializer::addInit(Expression *index, Initializer *value) type = NULL; } -Initializer *ArrayInitializer::semantic(Scope *sc, Type *t) +Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) { unsigned i; unsigned length; const unsigned amax = 0x80000000; @@ -367,17 +452,17 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t) length = 0; for (i = 0; i < index.dim; i++) { - Expression *idx = (Expression *)index.data[i]; + Expression *idx = index[i]; if (idx) { idx = idx->semantic(sc); idx = idx->optimize(WANTvalue | WANTinterpret); - index.data[i] = (void *)idx; + index[i] = idx; length = idx->toInteger(); } - Initializer *val = (Initializer *)value.data[i]; - val = val->semantic(sc, t->nextOf()); - value.data[i] = (void *)val; + Initializer *val = value[i]; + val = val->semantic(sc, t->nextOf(), needInterpret); + value[i] = val; length++; if (length == 0) { error(loc, "array dimension overflow"); @@ -412,7 +497,6 @@ Lerr: Expression *ArrayInitializer::toExpression() { Expressions *elements; - Expression *e; //printf("ArrayInitializer::toExpression(), dim = %d\n", dim); //static int i; if (++i == 2) halt(); @@ -445,8 +529,8 @@ Expression *ArrayInitializer::toExpression() edim = value.dim; for (size_t i = 0, j = 0; i < value.dim; i++, j++) { - if (index.data[i]) - j = ((Expression *)index.data[i])->toInteger(); + if (index[i]) + j = (index[i])->toInteger(); if (j >= edim) edim = j + 1; } @@ -456,10 +540,10 @@ Expression *ArrayInitializer::toExpression() elements->setDim(edim); for (size_t i = 0, j = 0; i < value.dim; i++, j++) { - if (index.data[i]) - j = ((Expression *)index.data[i])->toInteger(); + if (index[i]) + j = (index[i])->toInteger(); assert(j < edim); - Initializer *iz = (Initializer *)value.data[i]; + Initializer *iz = value[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); @@ -467,7 +551,7 @@ Expression *ArrayInitializer::toExpression() { goto Lno; } - elements->data[j] = ex; + (*elements)[j] = ex; } /* Fill in any missing elements with the default initializer @@ -476,13 +560,13 @@ Expression *ArrayInitializer::toExpression() Expression *init = NULL; for (size_t i = 0; i < edim; i++) { - if (!elements->data[i]) + if (!(*elements)[i]) { if (!type) goto Lno; if (!init) init = t->next->defaultInit(); - elements->data[i] = init; + (*elements)[i] = init; } } @@ -502,31 +586,30 @@ Lno: */ Initializer *ArrayInitializer::toAssocArrayInitializer() -{ Expressions *keys; - Expressions *values; +{ Expression *e; //printf("ArrayInitializer::toAssocArrayInitializer()\n"); //static int i; if (++i == 2) halt(); - keys = new Expressions(); + Expressions *keys = new Expressions(); keys->setDim(value.dim); - values = new Expressions(); + Expressions *values = new Expressions(); values->setDim(value.dim); for (size_t i = 0; i < value.dim; i++) { - e = (Expression *)index.data[i]; + e = index.tdata()[i]; if (!e) goto Lno; - keys->data[i] = (void *)e; + keys->tdata()[i] = e; - Initializer *iz = (Initializer *)value.data[i]; + Initializer *iz = value.tdata()[i]; if (!iz) goto Lno; e = iz->toExpression(); if (!e) goto Lno; - values->data[i] = (void *)e; + values->tdata()[i] = e; } e = new AssocArrayLiteralExp(loc, keys, values); return new ExpInitializer(loc, e); @@ -578,17 +661,17 @@ Laa: void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writebyte('['); - for (int i = 0; i < index.dim; i++) + for (size_t i = 0; i < index.dim; i++) { if (i > 0) buf->writebyte(','); - Expression *ex = (Expression *)index.data[i]; + Expression *ex = index.tdata()[i]; if (ex) { ex->toCBuffer(buf, hgs); buf->writebyte(':'); } - Initializer *iz = (Initializer *)value.data[i]; + Initializer *iz = value.tdata()[i]; if (iz) iz->toCBuffer(buf, hgs); } @@ -609,10 +692,19 @@ Initializer *ExpInitializer::syntaxCopy() return new ExpInitializer(loc, exp->syntaxCopy()); } -Initializer *ExpInitializer::semantic(Scope *sc, Type *t) +Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); exp = exp->semantic(sc); + int wantOptimize = needInterpret ? WANTinterpret|WANTvalue : WANTvalue; + + int olderrors = global.errors; + exp = exp->optimize(wantOptimize); + if (!global.gag && olderrors != global.errors) + return this; // Failed, suppress duplicate error messages + + if (exp->op == TOKtype) + error("initializer must be an expression, not '%s'", exp->toChars()); Type *tb = t->toBasetype(); /* Look for case of initializing a static array with a too-short @@ -645,7 +737,7 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t) exp = exp->implicitCastTo(sc, t); L1: - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->optimize(wantOptimize); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; } diff --git a/dmd/init.h b/dmd/init.h index 1b893882..b695380d 100644 --- a/dmd/init.h +++ b/dmd/init.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -26,9 +26,8 @@ struct VoidInitializer; struct StructInitializer; struct ArrayInitializer; struct ExpInitializer; -#ifdef _DH struct HdrGenState; -#endif + #if IN_LLVM namespace llvm { @@ -42,7 +41,8 @@ struct Initializer : Object Initializer(Loc loc); virtual Initializer *syntaxCopy(); - virtual Initializer *semantic(Scope *sc, Type *t); + // needInterpret is WANTinterpret if must be a manifest constant, 0 if not. + virtual Initializer *semantic(Scope *sc, Type *t, int needInterpret); virtual Type *inferType(Scope *sc); virtual Expression *toExpression() = 0; virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; @@ -66,7 +66,7 @@ struct VoidInitializer : Initializer VoidInitializer(Loc loc); Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t); + Initializer *semantic(Scope *sc, Type *t, int needInterpret); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -82,13 +82,13 @@ struct StructInitializer : Initializer Identifiers field; // of Identifier *'s Initializers value; // parallel array of Initializer *'s - Array vars; // parallel array of VarDeclaration *'s + VarDeclarations vars; // parallel array of VarDeclaration *'s AggregateDeclaration *ad; // which aggregate this is for StructInitializer(Loc loc); Initializer *syntaxCopy(); void addInit(Identifier *field, Initializer *value); - Initializer *semantic(Scope *sc, Type *t); + Initializer *semantic(Scope *sc, Type *t, int needInterpret); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -113,7 +113,7 @@ struct ArrayInitializer : Initializer ArrayInitializer(Loc loc); Initializer *syntaxCopy(); void addInit(Expression *index, Initializer *value); - Initializer *semantic(Scope *sc, Type *t); + Initializer *semantic(Scope *sc, Type *t, int needInterpret); Type *inferType(Scope *sc); Expression *toExpression(); Initializer *toAssocArrayInitializer(); @@ -133,7 +133,7 @@ struct ExpInitializer : Initializer ExpInitializer(Loc loc, Expression *exp); Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t); + Initializer *semantic(Scope *sc, Type *t, int needInterpret); Type *inferType(Scope *sc); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); diff --git a/dmd/inline.c b/dmd/inline.c index 43104f60..bd7ddc8c 100644 --- a/dmd/inline.c +++ b/dmd/inline.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -54,7 +54,7 @@ int CompoundStatement::inlineCost(InlineCostState *ics) { int cost = 0; for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s) { cost += s->inlineCost(ics); @@ -69,7 +69,7 @@ int UnrolledLoopStatement::inlineCost(InlineCostState *ics) { int cost = 0; for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s) { cost += s->inlineCost(ics); @@ -136,13 +136,13 @@ int ReturnStatement::inlineCost(InlineCostState *ics) /* -------------------------- */ -int arrayInlineCost(InlineCostState *ics, Array *arguments) +int arrayInlineCost(InlineCostState *ics, Expressions *arguments) { int cost = 0; if (arguments) { - for (int i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (*arguments)[i]; if (e) cost += e->inlineCost(ics); @@ -206,6 +206,10 @@ int AssocArrayLiteralExp::inlineCost(InlineCostState *ics) int StructLiteralExp::inlineCost(InlineCostState *ics) { +#if DMDV2 + if (sd->isnested) + return COST_MAX; +#endif return 1 + arrayInlineCost(ics, elements); } @@ -240,7 +244,7 @@ int DeclarationExp::inlineCost(InlineCostState *ics) return COST_MAX; // finish DeclarationExp::doInline #else for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = (Object *)td->objects->data[i]; + { Object *o = (*td->objects)[i]; if (o->dyncast() != DYNCAST_EXPRESSION) return COST_MAX; Expression *eo = (Expression *)o; @@ -369,7 +373,7 @@ Expression *CompoundStatement::doInline(InlineDoState *ids) //printf("CompoundStatement::doInline() %d\n", statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s) { Expression *e2 = s->doInline(ids); @@ -401,7 +405,7 @@ Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s) { Expression *e2 = s->doInline(ids); @@ -473,7 +477,7 @@ Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) newa = new Expressions(); newa->setDim(a->dim); - for (int i = 0; i < a->dim; i++) + for (size_t i = 0; i < a->dim; i++) { Expression *e = (Expression *)a->data[i]; if (e) @@ -492,10 +496,8 @@ Expression *Expression::doInline(InlineDoState *ids) Expression *SymOffExp::doInline(InlineDoState *ids) { - int i; - //printf("SymOffExp::doInline(%s)\n", toChars()); - for (i = 0; i < ids->from.dim; i++) + for (size_t i = 0; i < ids->from.dim; i++) { if (var == (Declaration *)ids->from.data[i]) { @@ -510,10 +512,8 @@ Expression *SymOffExp::doInline(InlineDoState *ids) Expression *VarExp::doInline(InlineDoState *ids) { - int i; - //printf("VarExp::doInline(%s)\n", toChars()); - for (i = 0; i < ids->from.dim; i++) + for (size_t i = 0; i < ids->from.dim; i++) { if (var == (Declaration *)ids->from.data[i]) { @@ -683,7 +683,7 @@ Expression *IndexExp::doInline(InlineDoState *ids) ids->from.push(vd); ids->to.push(vto); - if (vd->init) + if (vd->init && !vd->init->isVoidInitializer()) { ie = vd->init->isExpInitializer(); assert(ie); @@ -722,7 +722,7 @@ Expression *SliceExp::doInline(InlineDoState *ids) ids->from.push(vd); ids->to.push(vto); - if (vd->init) + if (vd->init && !vd->init->isVoidInitializer()) { ie = vd->init->isExpInitializer(); assert(ie); @@ -927,7 +927,7 @@ Statement *SwitchStatement::inlineScan(InlineScanState *iss) sdefault = (DefaultStatement *)sdefault->inlineScan(iss); if (cases) { - for (int i = 0; i < cases->dim; i++) + for (size_t i = 0; i < cases->dim; i++) { Statement *s; s = (Statement *) cases->data[i]; @@ -993,7 +993,7 @@ Statement *TryCatchStatement::inlineScan(InlineScanState *iss) body = body->inlineScan(iss); if (catches) { - for (int i = 0; i < catches->dim; i++) + for (size_t i = 0; i < catches->dim; i++) { Catch *c = (Catch *)catches->data[i]; if (c->handler) @@ -1043,7 +1043,7 @@ void arrayInlineScan(InlineScanState *iss, Array *arguments) { if (arguments) { - for (int i = 0; i < arguments->dim; i++) + for (size_t i = 0; i < arguments->dim; i++) { Expression *e = (Expression *)arguments->data[i]; if (e) @@ -1380,7 +1380,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) */ if (parameters) { - for (int i = 0; i < parameters->dim; i++) + for (size_t i = 0; i < parameters->dim; i++) { VarDeclaration *v = (VarDeclaration *)parameters->data[i]; if (/*v->isOut() || v->isRef() ||*/ v->type->toBasetype()->ty == Tsarray) @@ -1406,7 +1406,6 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) inlineScan(); #endif -Lyes: if (!hdrscan) // Don't modify inlineStatus for header content scan inlineStatus = ILSyes; #if CANINLINE_LOG @@ -1497,7 +1496,7 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, A { assert(parameters->dim == arguments->dim); - for (int i = 0; i < arguments->dim; i++) + for (size_t i = 0; i < arguments->dim; i++) { VarDeclaration *vfrom = (VarDeclaration *)parameters->data[i]; VarDeclaration *vto; @@ -1541,6 +1540,7 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, A //eb->type->print(); //eb->print(); //eb->dump(0); + e = Expression::combine(e, eb); /* There's a problem if what the function returns is used subsequently as an diff --git a/dmd/interpret.c b/dmd/interpret.c index 4e64bee7..0cd938f6 100644 --- a/dmd/interpret.c +++ b/dmd/interpret.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -24,16 +24,144 @@ #include "declaration.h" #include "aggregate.h" #include "id.h" +#include "utf.h" +#include "attrib.h" // for AttribDeclaration + +#include "template.h" +TemplateInstance *isSpeculativeFunction(FuncDeclaration *fd); + #define LOG 0 +#define LOGASSIGN 0 +#define SHOWPERFORMANCE 0 + +// Maximum allowable recursive function calls in CTFE +#define CTFE_RECURSION_LIMIT 1000 + +// The values of all CTFE variables. +struct CtfeStack +{ +private: + /* The stack. Every declaration we encounter is pushed here, + together with the VarDeclaration, and the previous + stack address of that variable, so that we can restore it + when we leave the stack frame. + Ctfe Stack addresses are just 0-based integers, but we save + them as 'void *' because ArrayBase can only do pointers. + */ + Expressions values; // values on the stack + VarDeclarations vars; // corresponding variables + ArrayBase savedId; // id of the previous state of that var + + /* Global constants get saved here after evaluation, so we never + * have to redo them. This saves a lot of time and memory. + */ + Expressions globalValues; // values of global constants + size_t framepointer; // current frame pointer + size_t maxStackPointer; // most stack we've ever used +public: + CtfeStack() : framepointer(0) + { + } + size_t stackPointer() + { + return values.dim; + } + // Largest number of stack positions we've used + size_t maxStackUsage() + { + return maxStackPointer; + } + // return the previous frame + size_t startFrame() + { + size_t oldframe = framepointer; + framepointer = stackPointer(); + return oldframe; + } + void endFrame(size_t oldframe) + { + popAll(framepointer); + framepointer = oldframe; + } + Expression *getValue(VarDeclaration *v) + { + if (v->isDataseg() && !v->isCTFE()) + { + assert(v->ctfeAdrOnStack >= 0 && + v->ctfeAdrOnStack < globalValues.dim); + return globalValues.tdata()[v->ctfeAdrOnStack]; + } + assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); + return values.tdata()[v->ctfeAdrOnStack]; + } + void setValue(VarDeclaration *v, Expression *e) + { + assert(!v->isDataseg() || v->isCTFE()); + assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); + values.tdata()[v->ctfeAdrOnStack] = e; + } + void push(VarDeclaration *v) + { + assert(!v->isDataseg() || v->isCTFE()); + if (v->ctfeAdrOnStack!= (size_t)-1 + && v->ctfeAdrOnStack >= framepointer) + { // Already exists in this frame, reuse it. + values.tdata()[v->ctfeAdrOnStack] = NULL; + return; + } + savedId.push((void *)(v->ctfeAdrOnStack)); + v->ctfeAdrOnStack = values.dim; + vars.push(v); + values.push(NULL); + } + void pop(VarDeclaration *v) + { + assert(!v->isDataseg() || v->isCTFE()); + int oldid = v->ctfeAdrOnStack; + v->ctfeAdrOnStack = (size_t)(savedId.tdata()[oldid]); + if (v->ctfeAdrOnStack == values.dim - 1) + { + values.pop(); + vars.pop(); + savedId.pop(); + } + } + void popAll(size_t stackpointer) + { + if (stackPointer() > maxStackPointer) + maxStackPointer = stackPointer(); + assert(values.dim >= stackpointer && stackpointer >= 0); + for (size_t i = stackpointer; i < values.dim; ++i) + { + VarDeclaration *v = vars.tdata()[i]; + v->ctfeAdrOnStack = (size_t)(savedId.tdata()[i]); + } + values.setDim(stackpointer); + vars.setDim(stackpointer); + savedId.setDim(stackpointer); + } + void saveGlobalConstant(VarDeclaration *v, Expression *e) + { + assert(v->isDataseg() && !v->isCTFE()); + v->ctfeAdrOnStack = globalValues.dim; + globalValues.push(e); + } +}; + +CtfeStack ctfeStack; + struct InterState { InterState *caller; // calling function's InterState FuncDeclaration *fd; // function being interpreted - Dsymbols vars; // variables used in this function + size_t framepointer; // frame pointer of previous frame Statement *start; // if !=NULL, start execution at this statement - Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result + Statement *gotoTarget; /* target of EXP_GOTO_INTERPRET result; also + * target of labelled EXP_BREAK_INTERPRET or + * EXP_CONTINUE_INTERPRET. (NULL if no label). + */ Expression *localThis; // value of 'this', or NULL if none bool awaitingLvalueReturn; // Support for ref return values: // Any return to this function should return an lvalue. @@ -45,18 +173,227 @@ InterState::InterState() memset(this, 0, sizeof(InterState)); } -Expression *interpret_aaLen(InterState *istate, Expressions *arguments); -Expression *interpret_aaKeys(InterState *istate, Expressions *arguments); -Expression *interpret_aaValues(InterState *istate, Expressions *arguments); +// Global status of the CTFE engine +struct CtfeStatus +{ + static int callDepth; // current number of recursive calls + static int stackTraceCallsToSuppress; /* When printing a stack trace, + * suppress this number of calls + */ + static int maxCallDepth; // highest number of recursive calls + static int numArrayAllocs; // Number of allocated arrays + static int numAssignments; // total number of assignments executed +}; + +int CtfeStatus::callDepth = 0; +int CtfeStatus::stackTraceCallsToSuppress = 0; +int CtfeStatus::maxCallDepth = 0; +int CtfeStatus::numArrayAllocs = 0; +int CtfeStatus::numAssignments = 0; + +// CTFE diagnostic information +void printCtfePerformanceStats() +{ +#if SHOWPERFORMANCE + printf(" ---- CTFE Performance ----\n"); + printf("max call depth = %d\tmax stack = %d\n", CtfeStatus::maxCallDepth, ctfeStack.maxStackUsage()); + printf("array allocs = %d\tassignments = %d\n\n", CtfeStatus::numArrayAllocs, CtfeStatus::numAssignments); +#endif +} -Expression *interpret_length(InterState *istate, Expression *earg); -Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration *fd); -Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclaration *fd); -ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, Expression *elem, size_t dim); Expression * resolveReferences(Expression *e, Expression *thisval, bool *isReference = NULL); -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d); +Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal); VarDeclaration *findParentVar(Expression *e, Expression *thisval); +bool needToCopyLiteral(Expression *expr); +Expression *copyLiteral(Expression *e); +Expression *paintTypeOntoLiteral(Type *type, Expression *lit); +Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2); +Expression *evaluateIfBuiltin(InterState *istate, Loc loc, + FuncDeclaration *fd, Expressions *arguments, Expression *pthis); + +// CTFE only expressions +#define TOKclassreference ((TOK)(TOKMAX+1)) +#define TOKthrownexception ((TOK)(TOKMAX+2)) + +// Reference to a class, or an interface. We need this when we +// point to a base class (we must record what the type is). +struct ClassReferenceExp : Expression +{ + StructLiteralExp *value; + ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type) : Expression(loc, TOKclassreference, sizeof(ClassReferenceExp)) + { + assert(lit && lit->sd && lit->sd->isClassDeclaration()); + this->value = lit; + this->type = type; + } + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue) + { + //printf("ClassReferenceExp::interpret() %s\n", value->toChars()); + return this; + } + char *toChars() + { + return value->toChars(); + } + ClassDeclaration *originalClass() + { + return value->sd->isClassDeclaration(); + } + // Return index of the field, or -1 if not found + int getFieldIndex(Type *fieldtype, size_t fieldoffset) + { + ClassDeclaration *cd = originalClass(); + size_t fieldsSoFar = 0; + for (size_t j = 0; j < value->elements->dim; j++) + { while (j - fieldsSoFar >= cd->fields.dim) + { fieldsSoFar += cd->fields.dim; + cd = cd->baseClass; + } + Dsymbol *s = cd->fields.tdata()[j - fieldsSoFar]; + VarDeclaration *v2 = s->isVarDeclaration(); + if (fieldoffset == v2->offset && + fieldtype->size() == v2->type->size()) + { return value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar); + } + } + return -1; + } +}; + +// Fake class which holds the thrown exception. Used for implementing exception handling. +struct ThrownExceptionExp : Expression +{ + ClassReferenceExp *thrown; // the thing being tossed + ThrownExceptionExp(Loc loc, ClassReferenceExp *victim) : Expression(loc, TOKthrownexception, sizeof(ThrownExceptionExp)) + { + this->thrown = victim; + this->type = type; + } + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue) + { + assert(0); // This should never be interpreted + return this; + } + char *toChars() + { + return "CTFE ThrownException"; + } + // Generate an error message when this exception is not caught + void generateUncaughtError() + { + thrown->error("Uncaught CTFE exception %s(%s)", thrown->type->toChars(), + thrown->value->elements->tdata()[0]->toChars()); + /* Also give the line where the throw statement was. We won't have it + * in the case where the ThrowStatement is generated internally + * (eg, in ScopeStatement) + */ + if (loc.filename && !loc.equals(thrown->loc)) + fprintf(stdmsg, "%s: thrown from here\n", loc.toChars()); + } +}; + +// True if 'e' is EXP_CANT_INTERPRET, or an exception +bool exceptionOrCantInterpret(Expression *e) +{ + if (e == EXP_CANT_INTERPRET) return true; + if (!e || e == EXP_GOTO_INTERPRET || e == EXP_VOID_INTERPRET + || e == EXP_BREAK_INTERPRET || e == EXP_CONTINUE_INTERPRET) + return false; + return e->op == TOKthrownexception; +} + + +// Used for debugging only +void showCtfeExpr(Expression *e, int level = 0) +{ + for (int i = level; i>0; --i) printf(" "); + Expressions *elements = NULL; + // We need the struct definition to detect block assignment + StructDeclaration *sd = NULL; + ClassDeclaration *cd = NULL; + if (e->op == TOKstructliteral) + { elements = ((StructLiteralExp *)e)->elements; + sd = ((StructLiteralExp *)e)->sd; + printf("STRUCT type = %s %p :\n", e->type->toChars(), e); + } + else if (e->op == TOKclassreference) + { elements = ((ClassReferenceExp *)e)->value->elements; + cd = ((ClassReferenceExp *)e)->originalClass(); + printf("CLASS type = %s %p :\n", e->type->toChars(), ((ClassReferenceExp *)e)->value->toChars()); + } + else if (e->op == TOKarrayliteral) + { + elements = ((ArrayLiteralExp *)e)->elements; + printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(), e); + } + else if (e->op == TOKassocarrayliteral) + { + printf("AA LITERAL type=%s %p:\n", e->type->toChars(), e); + } + else if (e->op == TOKstring) + { + printf("STRING %s %p\n", e->toChars(), ((StringExp *)e)->string); + } + else if (e->op == TOKslice) + { + printf("SLICE %p: %s\n", e, e->toChars()); + showCtfeExpr(((SliceExp *)e)->e1, level + 1); + } + else if (e->op == TOKvar) + { + printf("VAR %p %s\n", e, e->toChars()); + VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); + if (v && v->getValue()) + showCtfeExpr(v->getValue(), level + 1); + } + else printf("VALUE %p: %s\n", e, e->toChars()); + + if (elements) + { + size_t fieldsSoFar = 0; + for (size_t i = 0; i < elements->dim; i++) + { Expression *z = NULL; + Dsymbol *s = NULL; + if (sd) + { s = sd->fields.tdata()[i]; + z = elements->tdata()[i]; + } + else if (cd) + { while (i - fieldsSoFar >= cd->fields.dim) + { fieldsSoFar += cd->fields.dim; + cd = cd->baseClass; + for (int j = level; j>0; --j) printf(" "); + printf(" BASE CLASS: %s\n", cd->toChars()); + } + s = cd->fields.tdata()[i - fieldsSoFar]; + size_t indx = (elements->dim - fieldsSoFar)- cd->fields.dim + i; + assert(indx >= 0); + assert(indx < elements->dim); + z = elements->tdata()[indx]; + } + if (!z) { + for (int j = level; j>0; --j) printf(" "); + printf(" void\n"); + continue; + } + + if (s) + { + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + // If it is a void assignment, use the default initializer + if ((v->type->ty != z->type->ty) && v->type->ty == Tsarray) + { + for (int j = level; --j;) printf(" "); + printf(" field: block initalized static array\n"); + continue; + } + } + showCtfeExpr(z, level + 1); + } + } +} /************************************* * Attempt to interpret a function given the arguments. @@ -77,33 +414,28 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument if (global.errors) return NULL; -#if DMDV2 - if (thisarg && - (!arguments || arguments->dim == 0)) - { - if (ident == Id::length) - return interpret_length(istate, thisarg); - else if (ident == Id::keys) - return interpret_keys(istate, thisarg, this); - else if (ident == Id::values) - return interpret_values(istate, thisarg, this); - } -#endif - if (cantInterpret || semanticRun == PASSsemantic3) return NULL; - if (!fbody) - { cantInterpret = 1; - error("cannot be interpreted at compile time," - " because it has no available source code"); - return NULL; - } - if (semanticRun < PASSsemantic3 && scope) { + /* Forward reference - we need to run semantic3 on this function. + * If errors are gagged, and it's not part of a speculative + * template instance, we need to temporarily ungag errors. + */ + int olderrors = global.errors; + int oldgag = global.gag; + TemplateInstance *spec = isSpeculativeFunction(this); + if (global.gag && !spec) + global.gag = 0; semantic3(scope); - if (global.errors) // if errors compiling this function + global.gag = oldgag; // regag errors + + // If it is a speculatively-instantiated template, and errors occur, + // we need to mark the template as having errors. + if (spec && global.errors != olderrors) + spec->errors = global.errors - olderrors; + if (olderrors != global.errors) // if errors compiling this function return NULL; } if (semanticRun < PASSsemantic3done) @@ -124,12 +456,12 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument istatex.caller = istate; istatex.fd = this; istatex.localThis = thisarg; + istatex.framepointer = ctfeStack.startFrame(); Expressions vsave; // place to save previous parameter values size_t dim = 0; if (needThis() && !thisarg) - { cantInterpret = 1; - // error, no this. Prevent segfault. + { // error, no this. Prevent segfault. error("need 'this' to access member %s", toChars()); return NULL; } @@ -151,16 +483,20 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument eargs.setDim(dim); for (size_t i = 0; i < dim; i++) - { Expression *earg = (Expression *)arguments->data[i]; + { Expression *earg = arguments->tdata()[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); if (arg->storageClass & (STCout | STCref)) { - if (!istate) - { - earg->error("%s cannot be passed by reference at compile time", earg->toChars()); + if (!istate && (arg->storageClass & STCout)) + { // initializing an out parameter involves writing to it. + earg->error("global %s cannot be passed as an 'out' parameter at compile time", earg->toChars()); return NULL; } + // Convert all reference arguments into lvalue references + earg = earg->interpret(istate, ctfeNeedLvalueRef); + if (earg == EXP_CANT_INTERPRET) + return NULL; } else if (arg->storageClass & STClazy) { @@ -176,20 +512,25 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument */ earg = ((AddrExp *)earg)->e1; } - earg = earg->interpret(istate); // ? istate : &istatex); + earg = earg->interpret(istate); if (earg == EXP_CANT_INTERPRET) - { cantInterpret = 1; return NULL; } + if (earg->op == TOKthrownexception) + { + if (istate) + return earg; + ((ThrownExceptionExp *)earg)->generateUncaughtError(); + return NULL; } - eargs.data[i] = earg; + eargs.tdata()[i] = earg; } for (size_t i = 0; i < dim; i++) - { Expression *earg = (Expression *)eargs.data[i]; + { Expression *earg = eargs.tdata()[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - vsave.data[i] = v->value; + VarDeclaration *v = parameters->tdata()[i]; + ctfeStack.push(v); #if LOG printf("arg[%d] = %s\n", i, earg->toChars()); #endif @@ -198,66 +539,41 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument VarExp *ve = (VarExp *)earg; VarDeclaration *v2 = ve->var->isVarDeclaration(); if (!v2) - { cantInterpret = 1; + { + error("cannot interpret %s as a ref parameter", ve->toChars()); return NULL; } - v->value = earg; - /* Don't restore the value of v2 upon function return - */ - assert(istate); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *vx = (VarDeclaration *)istate->vars.data[i]; - if (vx == v2) - { istate->vars.data[i] = NULL; - break; - } - } + v->setValueWithoutChecking(earg); } else { // Value parameters and non-trivial references - v->value = earg; + v->setValueWithoutChecking(earg); } -#if LOG +#if LOG || LOGASSIGN printf("interpreted arg[%d] = %s\n", i, earg->toChars()); + showCtfeExpr(earg); #endif } } - // Don't restore the value of 'this' upon function return - if (needThis() && istate) - { - VarDeclaration *thisvar = findParentVar(thisarg, istate->localThis); - if (!thisvar) // it's a reference. Find which variable it refers to. - thisvar = findParentVar(thisarg->interpret(istate), istate->localThis); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v == thisvar) - { istate->vars.data[i] = NULL; - break; - } - } - } - /* Save the values of the local variables used - */ - Expressions valueSaves; - if (istate && !isNested()) - { - //printf("saving local variables...\n"); - valueSaves.setDim(istate->vars.dim); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v) - { - //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); - valueSaves.data[i] = v->value; - v->value = NULL; - } - } - } + if (vresult) + ctfeStack.push(vresult); + + // Enter the function + ++CtfeStatus::callDepth; + if (CtfeStatus::callDepth > CtfeStatus::maxCallDepth) + CtfeStatus::maxCallDepth = CtfeStatus::callDepth; Expression *e = NULL; while (1) { + if (CtfeStatus::callDepth > CTFE_RECURSION_LIMIT) + { // This is a compiler error. It must not be suppressed. + global.gag = 0; + error("CTFE recursion limit exceeded"); + e = NULL; + break; + } e = fbody->interpret(&istatex); if (e == EXP_CANT_INTERPRET) { @@ -281,28 +597,19 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument else break; } - /* Restore the parameter values - */ - for (size_t i = 0; i < dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - v->value = (Expression *)vsave.data[i]; - } + assert(e != EXP_CONTINUE_INTERPRET && e != EXP_BREAK_INTERPRET); - if (istate && !isNested()) - { - /* Restore the variable values - */ - //printf("restoring local variables...\n"); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v) - { v->value = (Expression *)valueSaves.data[i]; - //printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); - } - } - } + // Leave the function + --CtfeStatus::callDepth; + + ctfeStack.endFrame(istatex.framepointer); + + if (e == EXP_CANT_INTERPRET || !exceptionOrCantInterpret(e)) return e; + if (istate) + return e; + ((ThrownExceptionExp *)e)->generateUncaughtError(); + return NULL; } /******************************** Statement ***************************/ @@ -319,7 +626,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument * Returns: * NULL continue to next statement * EXP_CANT_INTERPRET cannot interpret statement at compile time - * !NULL expression from return statement + * !NULL expression from return statement, or thrown exception */ Expression *Statement::interpret(InterState *istate) @@ -340,12 +647,14 @@ Expression *ExpStatement::interpret(InterState *istate) START() if (exp) { - Expression *e = exp->interpret(istate); + Expression *e = exp->interpret(istate, ctfeNeedNothing); if (e == EXP_CANT_INTERPRET) { //printf("-ExpStatement::interpret(): %p\n", e); return EXP_CANT_INTERPRET; } + if (e && e!= EXP_VOID_INTERPRET && e->op == TOKthrownexception) + return e; } return NULL; } @@ -361,7 +670,7 @@ Expression *CompoundStatement::interpret(InterState *istate) if (statements) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; + { Statement *s = statements->tdata()[i]; if (s) { @@ -388,17 +697,26 @@ Expression *UnrolledLoopStatement::interpret(InterState *istate) if (statements) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; + { Statement *s = statements->tdata()[i]; e = s->interpret(istate); if (e == EXP_CANT_INTERPRET) break; if (e == EXP_CONTINUE_INTERPRET) - { e = NULL; + { + if (istate->gotoTarget && istate->gotoTarget != this) + break; // continue at higher level + istate->gotoTarget = NULL; + e = NULL; continue; } if (e == EXP_BREAK_INTERPRET) - { e = NULL; + { + if (!istate->gotoTarget || istate->gotoTarget == this) + { + istate->gotoTarget = NULL; + e = NULL; + } // else break at a higher level break; } if (e) @@ -408,6 +726,12 @@ Expression *UnrolledLoopStatement::interpret(InterState *istate) return e; } +// For CTFE only. Returns true if 'e' is TRUE or a non-null pointer. +int isTrueBool(Expression *e) +{ + return e->isBool(TRUE) || (e->type->ty == Tpointer && e->op != TOKnull); +} + Expression *IfStatement::interpret(InterState *istate) { #if LOG @@ -421,6 +745,8 @@ Expression *IfStatement::interpret(InterState *istate) Expression *e = NULL; if (ifbody) e = ifbody->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; if (istate->start && elsebody) e = elsebody->interpret(istate); return e; @@ -429,9 +755,9 @@ Expression *IfStatement::interpret(InterState *istate) Expression *e = condition->interpret(istate); assert(e); //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n"); - if (e != EXP_CANT_INTERPRET) + if (e != EXP_CANT_INTERPRET && (e && e->op != TOKthrownexception)) { - if (e->isBool(TRUE)) + if (isTrueBool(e)) e = ifbody ? ifbody->interpret(istate) : NULL; else if (e->isBool(FALSE)) e = elsebody ? elsebody->interpret(istate) : NULL; @@ -453,89 +779,103 @@ Expression *ScopeStatement::interpret(InterState *istate) return statement ? statement->interpret(istate) : NULL; } -// Helper for ReturnStatement::interpret() for returning references. -// Given an original expression, which is known to be a reference to a reference, -// turn it into a reference. -Expression * replaceReturnReference(Expression *original, InterState *istate) +Expression *resolveSlice(Expression *e) { - Expression *e = original; - if (e->op == TOKcall) - { // If it's a function call, interpret it now. - // It also needs to return an lvalue. - istate->awaitingLvalueReturn = true; - e = e->interpret(istate); - if (e == EXP_CANT_INTERPRET) - return e; + if ( ((SliceExp *)e)->e1->op == TOKnull) + return ((SliceExp *)e)->e1; + return Slice(e->type, ((SliceExp *)e)->e1, + ((SliceExp *)e)->lwr, ((SliceExp *)e)->upr); +} + +/* Determine the array length, without interpreting it. + * e must be an array literal, or a slice + * It's very wasteful to resolve the slice when we only + * need the length. + */ +uinteger_t resolveArrayLength(Expression *e) +{ + if (e->op == TOKnull) + return 0; + if (e->op == TOKslice) + { uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger(); + uinteger_t iup = ((SliceExp *)e)->upr->toInteger(); + return iup - ilo; } - // If it is a reference to a reference, convert it to a reference - if (e->op == TOKvar) - { - VarExp *ve = (VarExp *)e; - VarDeclaration *v = ve->var->isVarDeclaration(); - assert (v && v->value); - return v->value; + if (e->op == TOKstring) + { return ((StringExp *)e)->len; } - - if (e->op == TOKthis) - { - return istate->localThis; + if (e->op == TOKarrayliteral) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e; + return ale->elements ? ale->elements->dim : 0; + } + if (e->op == TOKassocarrayliteral) + { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e; + return ale->keys->dim; } + assert(0); + return 0; +} - Expression *r = e->copy(); - e = r; - Expression *next; - for (;;) - { - if (e->op == TOKindex) - next = ((IndexExp*)e)->e1; - else if (e->op == TOKdotvar) - next = ((DotVarExp *)e)->e1; - else if (e->op == TOKdotti) - next = ((DotTemplateInstanceExp *)e)->e1; - else if (e->op == TOKslice) - next = ((SliceExp*)e)->e1; - else - return EXP_CANT_INTERPRET; +// As Equal, but resolves slices before comparing +Expression *ctfeEqual(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ + if (e1->op == TOKslice) + e1 = resolveSlice(e1); + if (e2->op == TOKslice) + e2 = resolveSlice(e2); + return Equal(op, type, e1, e2); +} - Expression *old = next; - if (next->op == TOKcall) +void scrubArray(Loc loc, Expressions *elems); + +/* All results destined for use outside of CTFE need to have their CTFE-specific + * features removed. + * In particular, all slices must be resolved. + */ +Expression *scrubReturnValue(Loc loc, Expression *e) +{ + if (e->op == TOKclassreference) { - istate->awaitingLvalueReturn = true; - next = next->interpret(istate); - if (next == EXP_CANT_INTERPRET) return next; + error(loc, "%s class literals cannot be returned from CTFE", ((ClassReferenceExp*)e)->originalClass()->toChars()); + return EXP_CANT_INTERPRET; } - if (next->op == TOKvar) + if (e->op == TOKslice) { - VarDeclaration * v = ((VarExp*)next)->var->isVarDeclaration(); - if (v) - next = v->value; + e = resolveSlice(e); } - else if (next->op == TOKthis) - next = istate->localThis; - - if (old == next) - { // Haven't found the reference yet. Need to keep copying. - next = next->copy(); - old = next; + if (e->op == TOKstructliteral) + { + StructLiteralExp *se = (StructLiteralExp *)e; + scrubArray(loc, se->elements); } - if (e->op == TOKindex) - ((IndexExp*)e)->e1 = next; - else if (e->op == TOKdotvar) - ((DotVarExp *)e)->e1 = next; - else if (e->op == TOKdotti) - ((DotTemplateInstanceExp *)e)->e1 = next; - else if (e->op == TOKslice) - ((SliceExp*)e)->e1 = next; - - if (old != next) - break; - e = next; + if (e->op == TOKarrayliteral) + { + scrubArray(loc, ((ArrayLiteralExp *)e)->elements); + } + if (e->op == TOKassocarrayliteral) + { + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; + scrubArray(loc, aae->keys); + scrubArray(loc, aae->values); } + return e; +} - return r; +// Scrub all members of an array +void scrubArray(Loc loc, Expressions *elems) +{ + for (size_t i = 0; i < elems->dim; i++) + { + Expression *m = elems->tdata()[i]; + if (!m) + continue; + m = scrubReturnValue(loc, m); + elems->tdata()[i] = m; + } } + Expression *ReturnStatement::interpret(InterState *istate) { #if LOG @@ -553,8 +893,8 @@ Expression *ReturnStatement::interpret(InterState *istate) { TypeFunction *tf = (TypeFunction *)istate->fd->type; if (tf->isref && istate->caller && istate->caller->awaitingLvalueReturn) - { // We need to return an lvalue. Can't do a normal interpret. - Expression *e = replaceReturnReference(exp, istate); + { // We need to return an lvalue + Expression *e = exp->interpret(istate, ctfeNeedLvalue); if (e == EXP_CANT_INTERPRET) error("ref return %s is not yet supported in CTFE", exp->toChars()); return e; @@ -568,13 +908,27 @@ Expression *ReturnStatement::interpret(InterState *istate) } } #endif - - Expression *e = exp->interpret(istate); + // We need to treat pointers specially, because TOKsymoff can be used to + // return a value OR a pointer + Expression *e; + if ((exp->type->ty == Tpointer && exp->type->nextOf()->ty != Tfunction)) + e = exp->interpret(istate, ctfeNeedLvalue); + else + e = exp->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; + if (!istate->caller) + { + e = scrubReturnValue(loc, e); if (e == EXP_CANT_INTERPRET) return e; - // Convert lvalues into rvalues (See Bugzilla 4825 for rationale) - if (e->op == TOKvar) - e = e->interpret(istate); + } + else if (needToCopyLiteral(exp)) + e = copyLiteral(e); +#if LOGASSIGN + printf("RETURN %s\n", loc.toChars()); + showCtfeExpr(e); +#endif return e; } @@ -585,9 +939,21 @@ Expression *BreakStatement::interpret(InterState *istate) #endif START() if (ident) - return EXP_CANT_INTERPRET; - else + { LabelDsymbol *label = istate->fd->searchLabel(ident); + assert(label && label->statement); + Statement *s = label->statement; + if (s->isLabelStatement()) + s = s->isLabelStatement()->statement; + if (s->isScopeStatement()) + s = s->isScopeStatement()->statement; + istate->gotoTarget = s; return EXP_BREAK_INTERPRET; + } + else + { + istate->gotoTarget = NULL; + return EXP_BREAK_INTERPRET; + } } Expression *ContinueStatement::interpret(InterState *istate) @@ -597,7 +963,16 @@ Expression *ContinueStatement::interpret(InterState *istate) #endif START() if (ident) - return EXP_CANT_INTERPRET; + { LabelDsymbol *label = istate->fd->searchLabel(ident); + assert(label && label->statement); + Statement *s = label->statement; + if (s->isLabelStatement()) + s = s->isLabelStatement()->statement; + if (s->isScopeStatement()) + s = s->isScopeStatement()->statement; + istate->gotoTarget = s; + return EXP_CONTINUE_INTERPRET; + } else return EXP_CONTINUE_INTERPRET; } @@ -628,9 +1003,21 @@ Expression *DoStatement::interpret(InterState *istate) if (e == EXP_CANT_INTERPRET) return e; if (e == EXP_BREAK_INTERPRET) - return NULL; + { + if (!istate->gotoTarget || istate->gotoTarget == this) + { + istate->gotoTarget = NULL; + e = NULL; + } // else break at a higher level + return e; + } if (e == EXP_CONTINUE_INTERPRET) + if (!istate->gotoTarget || istate->gotoTarget == this) + { goto Lcontinue; + } + else // else continue at a higher level + return e; if (e) return e; } @@ -641,21 +1028,29 @@ Expression *DoStatement::interpret(InterState *istate) if (e == EXP_CANT_INTERPRET) break; if (e == EXP_BREAK_INTERPRET) - { e = NULL; + { + if (!istate->gotoTarget || istate->gotoTarget == this) + { + istate->gotoTarget = NULL; + e = NULL; + } // else break at a higher level break; } if (e && e != EXP_CONTINUE_INTERPRET) break; + if (istate->gotoTarget && istate->gotoTarget != this) + break; // continue at a higher level Lcontinue: + istate->gotoTarget = NULL; e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(e)) break; if (!e->isConst()) { e = EXP_CANT_INTERPRET; break; } - if (e->isBool(TRUE)) + if (isTrueBool(e)) { } else if (e->isBool(FALSE)) @@ -680,7 +1075,7 @@ Expression *ForStatement::interpret(InterState *istate) if (init) { e = init->interpret(istate); - if (e == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(e)) return e; assert(!e); } @@ -693,9 +1088,21 @@ Expression *ForStatement::interpret(InterState *istate) if (e == EXP_CANT_INTERPRET) return e; if (e == EXP_BREAK_INTERPRET) + { + if (!istate->gotoTarget || istate->gotoTarget == this) + { + istate->gotoTarget = NULL; return NULL; + } // else break at a higher level + } if (e == EXP_CONTINUE_INTERPRET) + { + if (!istate->gotoTarget || istate->gotoTarget == this) + { + istate->gotoTarget = NULL; goto Lcontinue; + } // else continue at a higher level + } if (e) return e; } @@ -705,25 +1112,33 @@ Expression *ForStatement::interpret(InterState *istate) if (!condition) goto Lhead; e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(e)) break; if (!e->isConst()) { e = EXP_CANT_INTERPRET; break; } - if (e->isBool(TRUE)) + if (isTrueBool(e)) { Lhead: e = body ? body->interpret(istate) : NULL; if (e == EXP_CANT_INTERPRET) break; if (e == EXP_BREAK_INTERPRET) - { e = NULL; + { + if (!istate->gotoTarget || istate->gotoTarget == this) + { + istate->gotoTarget = NULL; + e = NULL; + } // else break at a higher level break; } if (e && e != EXP_CONTINUE_INTERPRET) break; + if (istate->gotoTarget && istate->gotoTarget != this) + break; // continue at a higher level Lcontinue: + istate->gotoTarget = NULL; if (increment) { e = increment->interpret(istate); @@ -743,183 +1158,15 @@ Expression *ForStatement::interpret(InterState *istate) Expression *ForeachStatement::interpret(InterState *istate) { -#if 1 assert(0); // rewritten to ForStatement return NULL; -#else -#if LOG - printf("ForeachStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (istate->start) - return NULL; - - Expression *e = NULL; - Expression *eaggr; - - if (value->isOut() || value->isRef()) - return EXP_CANT_INTERPRET; - - eaggr = aggr->interpret(istate); - if (eaggr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *dim = ArrayLength(Type::tsize_t, eaggr); - if (dim == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *keysave = key ? key->value : NULL; - Expression *valuesave = value->value; - - uinteger_t d = dim->toUInteger(); - uinteger_t index; - - if (op == TOKforeach) - { - for (index = 0; index < d; index++) - { - Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); - if (key) - key->value = ekey; - e = Index(value->type, eaggr, ekey); - if (e == EXP_CANT_INTERPRET) - break; - value->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == EXP_CONTINUE_INTERPRET) - e = NULL; - else if (e) - break; - } - } - else // TOKforeach_reverse - { - for (index = d; index-- != 0;) - { - Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); - if (key) - key->value = ekey; - e = Index(value->type, eaggr, ekey); - if (e == EXP_CANT_INTERPRET) - break; - value->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == EXP_CONTINUE_INTERPRET) - e = NULL; - else if (e) - break; - } - } - value->value = valuesave; - if (key) - key->value = keysave; - return e; -#endif } #if DMDV2 Expression *ForeachRangeStatement::interpret(InterState *istate) { -#if 1 assert(0); // rewritten to ForStatement return NULL; -#else -#if LOG - printf("ForeachRangeStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (istate->start) - return NULL; - - Expression *e = NULL; - Expression *elwr = lwr->interpret(istate); - if (elwr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *eupr = upr->interpret(istate); - if (eupr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *keysave = key->value; - - if (op == TOKforeach) - { - key->value = elwr; - - while (1) - { - e = Cmp(TOKlt, key->value->type, key->value, eupr); - if (e == EXP_CANT_INTERPRET) - break; - if (e->isBool(TRUE) == FALSE) - { e = NULL; - break; - } - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == NULL || e == EXP_CONTINUE_INTERPRET) - { e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) - break; - key->value = e; - } - else - break; - } - } - else // TOKforeach_reverse - { - key->value = eupr; - - do - { - e = Cmp(TOKgt, key->value->type, key->value, elwr); - if (e == EXP_CANT_INTERPRET) - break; - if (e->isBool(TRUE) == FALSE) - { e = NULL; - break; - } - - e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) - break; - key->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - } while (e == NULL || e == EXP_CONTINUE_INTERPRET); - } - key->value = keysave; - return e; -#endif } #endif @@ -940,24 +1187,32 @@ Expression *SwitchStatement::interpret(InterState *istate) if (e == EXP_CANT_INTERPRET) return e; if (e == EXP_BREAK_INTERPRET) + { + if (!istate->gotoTarget || istate->gotoTarget == this) + { + istate->gotoTarget = NULL; return NULL; + } // else break at a higher level + } return e; } Expression *econdition = condition->interpret(istate); - if (econdition == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; + if (exceptionOrCantInterpret(econdition)) + return econdition; + if (econdition->op == TOKslice) + econdition = resolveSlice(econdition); Statement *s = NULL; if (cases) { for (size_t i = 0; i < cases->dim; i++) { - CaseStatement *cs = (CaseStatement *)cases->data[i]; - e = Equal(TOKequal, Type::tint32, econdition, cs->exp); - if (e == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; + CaseStatement *cs = cases->tdata()[i]; + e = ctfeEqual(TOKequal, Type::tint32, econdition, cs->exp); + if (exceptionOrCantInterpret(e)) + return e; if (e->isBool(TRUE)) { s = cs; break; @@ -975,7 +1230,13 @@ Expression *SwitchStatement::interpret(InterState *istate) e = body ? body->interpret(istate) : NULL; assert(!istate->start); if (e == EXP_BREAK_INTERPRET) - return NULL; + { + if (!istate->gotoTarget || istate->gotoTarget == this) + { + istate->gotoTarget = NULL; + e = NULL; + } // else break at a higher level + } return e; } @@ -1055,8 +1316,69 @@ Expression *TryCatchStatement::interpret(InterState *istate) printf("TryCatchStatement::interpret()\n"); #endif START() - error("try-catch statements are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; + Expression *e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (!exceptionOrCantInterpret(e)) + return e; + // An exception was thrown + ThrownExceptionExp *ex = (ThrownExceptionExp *)e; + Type *extype = ex->thrown->originalClass()->type; + // Search for an appropriate catch clause. + for (size_t i = 0; i < catches->dim; i++) + { +#if DMDV1 + Catch *ca = (Catch *)catches->data[i]; +#else + Catch *ca = catches->tdata()[i]; +#endif + Type *catype = ca->type; + + if (catype->equals(extype) || catype->isBaseOf(extype, NULL)) + { // Execute the handler + if (ca->var) + { + ctfeStack.push(ca->var); + ca->var->createStackValue(ex->thrown); + } + return ca->handler->interpret(istate); + } + } + return e; +} + +bool isAnErrorException(ClassDeclaration *cd) +{ + return cd == ClassDeclaration::errorException || ClassDeclaration::errorException->isBaseOf(cd, NULL); +} + +ThrownExceptionExp *chainExceptions(ThrownExceptionExp *oldest, ThrownExceptionExp *newest) +{ +#if LOG + printf("Collided exceptions %s %s\n", oldest->thrown->toChars(), newest->thrown->toChars()); +#endif +#if DMDV2 + // Little sanity check to make sure it's really a Throwable + ClassReferenceExp *boss = oldest->thrown; + assert(boss->value->elements->tdata()[4]->type->ty == Tclass); + ClassReferenceExp *collateral = newest->thrown; + if (isAnErrorException(collateral->originalClass()) + && !isAnErrorException(boss->originalClass())) + { // The new exception bypass the existing chain + assert(collateral->value->elements->tdata()[5]->type->ty == Tclass); + collateral->value->elements->tdata()[5] = boss; + return newest; + } + while (boss->value->elements->tdata()[4]->op == TOKclassreference) + { + boss = (ClassReferenceExp *)(boss->value->elements->tdata()[4]); + } + boss->value->elements->tdata()[4] = collateral; + return oldest; +#else + // for D1, the newest exception just clobbers the older one + return newest; +#endif } @@ -1066,8 +1388,20 @@ Expression *TryFinallyStatement::interpret(InterState *istate) printf("TryFinallyStatement::interpret()\n"); #endif START() - error("try-finally statements are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; + Expression *e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + return e; + Expression *second = finalbody ? finalbody->interpret(istate) : NULL; + if (second == EXP_CANT_INTERPRET) + return second; + if (exceptionOrCantInterpret(second)) + { // Check for collided exceptions + if (exceptionOrCantInterpret(e)) + e = chainExceptions((ThrownExceptionExp *)e, (ThrownExceptionExp *)second); + else + e = second; + } + return e; } Expression *ThrowStatement::interpret(InterState *istate) @@ -1076,17 +1410,16 @@ Expression *ThrowStatement::interpret(InterState *istate) printf("ThrowStatement::interpret()\n"); #endif START() - error("throw statements are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; + Expression *e = exp->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; + assert(e->op == TOKclassreference); + return new ThrownExceptionExp(loc, (ClassReferenceExp *)e); } Expression *OnScopeStatement::interpret(InterState *istate) { -#if LOG - printf("OnScopeStatement::interpret()\n"); -#endif - START() - error("scope guard statements are not yet supported in CTFE"); + assert(0); return EXP_CANT_INTERPRET; } @@ -1096,8 +1429,19 @@ Expression *WithStatement::interpret(InterState *istate) printf("WithStatement::interpret()\n"); #endif START() - error("with statements are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; + Expression *e = exp->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; + if (wthis->type->ty == Tpointer && exp->type->ty != Tpointer) + { + e = new AddrExp(loc, e); + e->type = wthis->type; + } + ctfeStack.push(wthis); + wthis->createStackValue(e); + e = body ? body->interpret(istate) : EXP_VOID_INTERPRET; + ctfeStack.pop(wthis); + return e; } Expression *AsmStatement::interpret(InterState *istate) @@ -1110,9 +1454,20 @@ Expression *AsmStatement::interpret(InterState *istate) return EXP_CANT_INTERPRET; } +#if DMDV2 +Expression *ImportStatement::interpret(InterState *istate) +{ +#if LOG + printf("ImportStatement::interpret()\n"); +#endif + START(); + return NULL; +} +#endif + /******************************** Expression ***************************/ -Expression *Expression::interpret(InterState *istate) +Expression *Expression::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("Expression::interpret() %s\n", toChars()); @@ -1123,20 +1478,24 @@ Expression *Expression::interpret(InterState *istate) return EXP_CANT_INTERPRET; } -Expression *ThisExp::interpret(InterState *istate) +Expression *ThisExp::interpret(InterState *istate, CtfeGoal goal) { + while (istate && !istate->localThis) + istate = istate->caller; + if (istate && istate->localThis && istate->localThis->op == TOKstructliteral) + return istate->localThis; if (istate && istate->localThis) - return istate->localThis->interpret(istate); + return istate->localThis->interpret(istate, goal); error("value of 'this' is not known at compile time"); return EXP_CANT_INTERPRET; } -Expression *NullExp::interpret(InterState *istate) +Expression *NullExp::interpret(InterState *istate, CtfeGoal goal) { return this; } -Expression *IntegerExp::interpret(InterState *istate) +Expression *IntegerExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("IntegerExp::interpret() %s\n", toChars()); @@ -1144,7 +1503,7 @@ Expression *IntegerExp::interpret(InterState *istate) return this; } -Expression *RealExp::interpret(InterState *istate) +Expression *RealExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("RealExp::interpret() %s\n", toChars()); @@ -1152,20 +1511,41 @@ Expression *RealExp::interpret(InterState *istate) return this; } -Expression *ComplexExp::interpret(InterState *istate) +Expression *ComplexExp::interpret(InterState *istate, CtfeGoal goal) { return this; } -Expression *StringExp::interpret(InterState *istate) +Expression *StringExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("StringExp::interpret() %s\n", toChars()); #endif + /* Since we are using StringExps as reference types for char[] arrays, + * we need to dup them if there's any chance they'll be modified. + * For efficiency, we try to only dup when necessary. + */ + // Fixed-length char arrays always get duped later anyway. + if (type->ty == Tsarray) + return this; + /* String literals are normally immutable, so we don't need to dup them + * In D2, we can detect attempts to write to read-only literals. + * For D1, we could be pessimistic, and always dup. + * But since it fails only when there has been an explicit cast, and any + * such function would give different results at runtime anyway (eg, it + * may crash), it hardly seems worth the massive performance hit. + */ +#if DMDV2 + if (!(((TypeNext *)type)->next->mod & (MODconst | MODimmutable))) + { // It seems this happens only when there has been an explicit cast + error("cannot cast a read-only string literal to mutable in CTFE"); + return EXP_CANT_INTERPRET; + } +#endif return this; } -Expression *FuncExp::interpret(InterState *istate) +Expression *FuncExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("FuncExp::interpret() %s\n", toChars()); @@ -1173,7 +1553,28 @@ Expression *FuncExp::interpret(InterState *istate) return this; } -Expression *SymOffExp::interpret(InterState *istate) +/* Is it safe to convert from srcPointee* to destPointee* ? + * srcPointee is the genuine type (never void). + * destPointee may be void. + */ +bool isSafePointerCast(Type *srcPointee, Type*destPointee) +{ // It's OK if both are the same (modulo const) +#if DMDV2 + if (srcPointee->castMod(0) == destPointee->castMod(0)) + return true; +#else + if (srcPointee == destPointee) + return true; +#endif + // it's OK to cast to void* + if (destPointee->ty == Tvoid) + return true; + // It's OK if they are the same size integers, eg int* and uint* + return srcPointee->isintegral() && destPointee->isintegral() + && srcPointee->size() == destPointee->size(); +} + +Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("SymOffExp::interpret() %s\n", toChars()); @@ -1182,20 +1583,98 @@ Expression *SymOffExp::interpret(InterState *istate) { return this; } + if (type->ty != Tpointer) + { // Probably impossible error("Cannot interpret %s at compile time", toChars()); return EXP_CANT_INTERPRET; + } + Type *pointee = ((TypePointer *)type)->next; + Expression *val = getVarExp(loc, istate, var, goal); + if (val->type->ty == Tarray || val->type->ty == Tsarray) + { + // Check for unsupported type painting operations + Type *elemtype = ((TypeArray *)(val->type))->next; + + // It's OK to cast from fixed length to dynamic array, eg &int[3] to int[]* + if (val->type->ty == Tsarray && pointee->ty == Tarray + && elemtype->size() == pointee->nextOf()->size()) + { + Expression *e = new AddrExp(loc, val); + e->type = type; + return e; + } + if ( !isSafePointerCast(elemtype, pointee) ) + { // It's also OK to cast from &string to string*. + if ( offset == 0 && isSafePointerCast(var->type, pointee) ) + { + VarExp *ve = new VarExp(loc, var); + ve->type = type; + return ve; + } + error("reinterpreting cast from %s to %s is not supported in CTFE", + val->type->toChars(), type->toChars()); + return EXP_CANT_INTERPRET; + } + + TypeArray *tar = (TypeArray *)val->type; + dinteger_t sz = pointee->size(); + dinteger_t indx = offset/sz; + assert(sz * indx == offset); + Expression *aggregate = NULL; + if (val->op == TOKarrayliteral || val->op == TOKstring) + aggregate = val; + else if (val->op == TOKslice) + { + aggregate = ((SliceExp *)val)->e1; + Expression *lwr = ((SliceExp *)val)->lwr->interpret(istate); + indx += lwr->toInteger(); + } + if (aggregate) + { + IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t); + IndexExp *ie = new IndexExp(loc, aggregate, ofs); + ie->type = type; + return ie; + } + } + else if ( offset == 0 && isSafePointerCast(var->type, pointee) ) + { + VarExp *ve = new VarExp(loc, var); + ve->type = type; + return ve; + } + + error("Cannot convert &%s to %s at compile time", var->type->toChars(), type->toChars()); + return EXP_CANT_INTERPRET; } -Expression *DelegateExp::interpret(InterState *istate) +Expression *AddrExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG - printf("DelegateExp::interpret() %s\n", toChars()); + printf("AddrExp::interpret() %s\n", toChars()); #endif - return this; + // For reference types, we need to return an lvalue ref. + TY tb = e1->type->toBasetype()->ty; + bool needRef = (tb == Tarray || tb == Taarray || tb == Tclass); + Expression *e = e1->interpret(istate, needRef ? ctfeNeedLvalueRef : ctfeNeedLvalue); + if (exceptionOrCantInterpret(e)) + return e; + // Return a simplified address expression + e = new AddrExp(loc, e); + e->type = type; + return e; } - -// ------------------------------------------------------------- +Expression *DelegateExp::interpret(InterState *istate, CtfeGoal goal) +{ +#if LOG + printf("DelegateExp::interpret() %s\n", toChars()); +#endif + return this; +} + + +// ------------------------------------------------------------- // Remove out, ref, and this // ------------------------------------------------------------- // The variable used in a dotvar, index, or slice expression, @@ -1218,26 +1697,38 @@ Expression * resolveReferences(Expression *e, Expression *thisval, bool *isRefer // Chase down rebinding of out and ref. VarExp *ve = (VarExp *)e; VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && v->value && v->value->op == TOKvar) // it's probably a reference + if (v->type->ty == Tpointer) + break; + if (v->ctfeAdrOnStack == (size_t)-1) // If not on the stack, can't possibly be a ref. + break; + if (v && v->getValue() && v->getValue()->op == TOKvar) // it's probably a reference { // Make sure it's a real reference. // It's not a reference if v is a struct initialized to // 0 using an __initZ SymbolDeclaration from // TypeStruct::defaultInit() - VarExp *ve2 = (VarExp *)v->value; + VarExp *ve2 = (VarExp *)v->getValue(); //if (!ve2->var->isSymbolDeclaration()) if (!ve2->var->isStaticStructInitDeclaration()) { if (isReference) *isReference = true; - e = v->value; + e = v->getValue(); continue; } } - else if (v && v->value && (v->value->op==TOKindex || v->value->op == TOKdotvar - || v->value->op == TOKthis || v->value->op == TOKslice )) + else if (v && v->getValue() && (v->getValue()->op == TOKslice)) + { + SliceExp *se = (SliceExp *)v->getValue(); + if (se->e1->op == TOKarrayliteral || se->e1->op == TOKassocarrayliteral || se->e1->op == TOKstring) + break; + e = v->getValue(); + continue; + } + else if (v && v->getValue() && (v->getValue()->op==TOKindex || v->getValue()->op == TOKdotvar + || v->getValue()->op == TOKthis )) { - e = v->value; + e = v->getValue(); continue; } } @@ -1246,11 +1737,15 @@ Expression * resolveReferences(Expression *e, Expression *thisval, bool *isRefer return e; } -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) +Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal) { Expression *e = EXP_CANT_INTERPRET; VarDeclaration *v = d->isVarDeclaration(); +#if IN_LLVM StaticStructInitDeclaration *s = d->isStaticStructInitDeclaration(); +#else + SymbolDeclaration *s = d->isSymbolDeclaration(); +#endif if (v) { #if DMDV2 @@ -1258,18 +1753,41 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) */ if (v->ident == Id::ctfe) return new IntegerExp(loc, 1, Type::tbool); - - if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && v->init && !v->value) + if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && v->init && !v->hasValue()) #else if (v->isConst() && v->init) #endif { e = v->init->toExpression(); + if (e && (e->op == TOKconstruct || e->op == TOKblit)) + { AssignExp *ae = (AssignExp *)e; + e = ae->e2; + v->inuse++; + e = e->interpret(istate, ctfeNeedAnyValue); + v->inuse--; + if (e == EXP_CANT_INTERPRET && !global.gag && !CtfeStatus::stackTraceCallsToSuppress) + fprintf(stdmsg, "%s: while evaluating %s.init\n", loc.toChars(), v->toChars()); + if (exceptionOrCantInterpret(e)) + return e; + e->type = v->type; + } + else + { if (e && !e->type) e->type = v->type; + if (e) + e = e->interpret(istate, ctfeNeedAnyValue); + if (e == EXP_CANT_INTERPRET && !global.gag && !CtfeStatus::stackTraceCallsToSuppress) + fprintf(stdmsg, "%s: while evaluating %s.init\n", loc.toChars(), v->toChars()); } - else if ((v->isCTFE() || (!v->isDataseg() && istate)) && !v->value) + if (e && e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) + if (v->isDataseg()) + ctfeStack.saveGlobalConstant(v, e); + else + v->setValueWithoutChecking(e); + } + else if (v->isCTFE() && !v->hasValue()) { - if (v->init) + if (v->init && v->type->size() != 0) { if (v->init->isVoidInitializer()) { @@ -1282,42 +1800,83 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) else e = v->type->defaultInitLiteral(loc); } - else if (!v->isDataseg() && !istate) { - error(loc, "variable %s cannot be read at compile time", v->toChars()); + else if (!v->isDataseg() && !v->isCTFE() && !istate) + { error(loc, "variable %s cannot be read at compile time", v->toChars()); return EXP_CANT_INTERPRET; } else - { e = v->value; - if (!v->isCTFE() && v->isDataseg()) + { e = v->hasValue() ? v->getValue() : NULL; + if (!e && !v->isCTFE() && v->isDataseg()) { error(loc, "static variable %s cannot be read at compile time", v->toChars()); e = EXP_CANT_INTERPRET; } else if (!e) error(loc, "variable %s is used before initialization", v->toChars()); - else if (e != EXP_CANT_INTERPRET) - e = e->interpret(istate); + else if (exceptionOrCantInterpret(e)) + return e; + else if ((goal == ctfeNeedLvalue) + || e->op == TOKstring || e->op == TOKstructliteral || e->op == TOKarrayliteral + || e->op == TOKassocarrayliteral || e->op == TOKslice + || e->type->toBasetype()->ty == Tpointer) + return e; // it's already an Lvalue + else + e = e->interpret(istate, goal); } if (!e) e = EXP_CANT_INTERPRET; } else if (s) { +#if !IN_LLVM + // Struct static initializers, for example + if (s->dsym->toInitializer() == s->sym) + { +#endif Expressions *exps = new Expressions(); - e = new StructLiteralExp(0, s->dsym, exps); + e = new StructLiteralExp(loc, s->dsym, exps); e = e->semantic(NULL); + if (e->op == TOKerror) + e = EXP_CANT_INTERPRET; +#if !IN_LLVM } + else + error(loc, "cannot interpret symbol %s at compile time", v->toChars()); +#endif + } + else + error(loc, "cannot interpret declaration %s at compile time", d->toChars()); return e; } -Expression *VarExp::interpret(InterState *istate) +Expression *VarExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("VarExp::interpret() %s\n", toChars()); #endif - return getVarExp(loc, istate, var); + if (goal == ctfeNeedLvalueRef) + { + // If it is a reference, return the thing it's pointing to. + VarDeclaration *v = var->isVarDeclaration(); + if (v && v->hasValue() && (v->storage_class & (STCref | STCout))) + return v->getValue(); + if (v && !v->isDataseg() && !v->isCTFE() && !istate) + { error("variable %s cannot be referenced at compile time", v->toChars()); + return EXP_CANT_INTERPRET; + } + else if (v && !v->hasValue() && !v->isCTFE() && v->isDataseg()) + { error("static variable %s cannot be referenced at compile time", v->toChars()); + return EXP_CANT_INTERPRET; + } + return this; + } + Expression *e = getVarExp(loc, istate, var, goal); + // A VarExp may include an implicit cast. It must be done explicitly. + if (e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) + e = paintTypeOntoLiteral(type, e); + return e; } -Expression *DeclarationExp::interpret(InterState *istate) +Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("DeclarationExp::interpret() %s\n", toChars()); @@ -1326,6 +1885,24 @@ Expression *DeclarationExp::interpret(InterState *istate) VarDeclaration *v = declaration->isVarDeclaration(); if (v) { + if (v->toAlias()->isTupleDeclaration()) + { // Reserve stack space for all tuple members + TupleDeclaration *td =v->toAlias()->isTupleDeclaration(); + if (!td->objects) + return NULL; + for(int i= 0; i < td->objects->dim; ++i) + { + Object * o = td->objects->tdata()[i]; + Expression *ex = isExpression(o); + DsymbolExp *s = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL; + VarDeclaration *v2 = s ? s->s->isVarDeclaration() : NULL; + assert(v2); + if (!v2->isDataseg() || v2->isCTFE()) + ctfeStack.push(v2); + } + } + if (!v->isDataseg() || v->isCTFE()) + ctfeStack.push(v); Dsymbol *s = v->toAlias(); if (s == v && !v->isStatic() && v->init) { @@ -1340,6 +1917,10 @@ Expression *DeclarationExp::interpret(InterState *istate) e = EXP_CANT_INTERPRET; } } + else if (s == v && !v->init && v->type->size()==0) + { // Zero-length arrays don't need an initializer + e = v->type->defaultInitLiteral(loc); + } #if DMDV2 else if (s == v && (v->isConst() || v->isImmutable()) && v->init) #else @@ -1353,16 +1934,24 @@ Expression *DeclarationExp::interpret(InterState *istate) } else if (s->isTupleDeclaration() && !v->init) e = NULL; + else if (v->isStatic() && !v->init) + e = NULL; // Just ignore static variables which aren't read or written yet else { - error("Declaration %s is not yet implemented in CTFE", toChars()); + error("Static variable %s cannot be modified at compile time", v->toChars()); e = EXP_CANT_INTERPRET; } } else if (declaration->isAttribDeclaration() || declaration->isTemplateMixin() || declaration->isTupleDeclaration()) - { // These can be made to work, too lazy now + { // Check for static struct declarations, which aren't executable + AttribDeclaration *ad = declaration->isAttribDeclaration(); + if (ad && ad->decl && ad->decl->dim == 1 + && ad->decl->tdata()[0]->isAggregateDeclaration()) + return NULL; // static struct declaration. Nothing to do. + + // These can be made to work, too lazy now error("Declaration %s is not yet implemented in CTFE", toChars()); e = EXP_CANT_INTERPRET; } @@ -1376,7 +1965,7 @@ Expression *DeclarationExp::interpret(InterState *istate) return e; } -Expression *TupleExp::interpret(InterState *istate) +Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("TupleExp::interpret() %s\n", toChars()); @@ -1384,28 +1973,38 @@ Expression *TupleExp::interpret(InterState *istate) Expressions *expsx = NULL; for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; + { Expression *e = exps->tdata()[i]; Expression *ex; ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(ex)) { delete expsx; return ex; } + // A tuple of assignments can contain void (Bug 5676). + if (goal == ctfeNeedNothing) + continue; + if (ex == EXP_VOID_INTERPRET) + { + error("ICE: void element %s in tuple", e->toChars()); + assert(0); + } + /* If any changes, do Copy On Write */ if (ex != e) { if (!expsx) { expsx = new Expressions(); + ++CtfeStatus::numArrayAllocs; expsx->setDim(exps->dim); for (size_t j = 0; j < i; j++) { - expsx->data[j] = exps->data[j]; + expsx->tdata()[j] = exps->tdata()[j]; } } - expsx->data[i] = (void *)ex; + expsx->tdata()[i] = ex; } } if (expsx) @@ -1417,7 +2016,7 @@ Expression *TupleExp::interpret(InterState *istate) return this; } -Expression *ArrayLiteralExp::interpret(InterState *istate) +Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) { Expressions *expsx = NULL; #if LOG @@ -1426,12 +2025,16 @@ Expression *ArrayLiteralExp::interpret(InterState *istate) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; + { Expression *e = elements->tdata()[i]; Expression *ex; + if (e->op == TOKindex) // segfault bug 6250 + assert( ((IndexExp*)e)->e1 != this); ex = e->interpret(istate); if (ex == EXP_CANT_INTERPRET) goto Lerror; + if (ex->op == TOKthrownexception) + return ex; /* If any changes, do Copy On Write */ @@ -1439,13 +2042,14 @@ Expression *ArrayLiteralExp::interpret(InterState *istate) { if (!expsx) { expsx = new Expressions(); + ++CtfeStatus::numArrayAllocs; expsx->setDim(elements->dim); for (size_t j = 0; j < elements->dim; j++) { - expsx->data[j] = elements->data[j]; + expsx->tdata()[j] = elements->tdata()[j]; } } - expsx->data[i] = (void *)ex; + expsx->tdata()[i] = ex; } } } @@ -1458,7 +2062,13 @@ Expression *ArrayLiteralExp::interpret(InterState *istate) ae->type = type; return ae; } +#if DMDV2 + if (((TypeNext *)type)->next->mod & (MODconst | MODimmutable)) + { // If it's immutable, we don't need to dup it return this; + } +#endif + return copyLiteral(this); Lerror: if (expsx) @@ -1467,7 +2077,7 @@ Lerror: return EXP_CANT_INTERPRET; } -Expression *AssocArrayLiteralExp::interpret(InterState *istate) +Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) { Expressions *keysx = keys; Expressions *valuesx = values; @@ -1475,13 +2085,16 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate) printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); #endif for (size_t i = 0; i < keys->dim; i++) - { Expression *ekey = (Expression *)keys->data[i]; - Expression *evalue = (Expression *)values->data[i]; + { Expression *ekey = keys->tdata()[i]; + Expression *evalue = values->tdata()[i]; Expression *ex; ex = ekey->interpret(istate); if (ex == EXP_CANT_INTERPRET) goto Lerr; + if (ex->op == TOKthrownexception) + return ex; + /* If any changes, do Copy On Write */ @@ -1489,12 +2102,14 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate) { if (keysx == keys) keysx = (Expressions *)keys->copy(); - keysx->data[i] = (void *)ex; + keysx->tdata()[i] = ex; } ex = evalue->interpret(istate); if (ex == EXP_CANT_INTERPRET) goto Lerr; + if (ex->op == TOKthrownexception) + return ex; /* If any changes, do Copy On Write */ @@ -1502,7 +2117,7 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate) { if (valuesx == values) valuesx = (Expressions *)values->copy(); - valuesx->data[i] = (void *)ex; + valuesx->tdata()[i] = ex; } } if (keysx != keys) @@ -1515,11 +2130,12 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate) /* Remove duplicate keys */ for (size_t i = 1; i < keysx->dim; i++) - { Expression *ekey = (Expression *)keysx->data[i - 1]; - + { Expression *ekey = keysx->tdata()[i - 1]; + if (ekey->op == TOKslice) + ekey = resolveSlice(ekey); for (size_t j = i; j < keysx->dim; j++) - { Expression *ekey2 = (Expression *)keysx->data[j]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2); + { Expression *ekey2 = keysx->tdata()[j]; + Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, ekey2); if (ex == EXP_CANT_INTERPRET) goto Lerr; if (ex->isBool(TRUE)) // if a match @@ -1554,7 +2170,7 @@ Lerr: return EXP_CANT_INTERPRET; } -Expression *StructLiteralExp::interpret(InterState *istate) +Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) { Expressions *expsx = NULL; #if LOG @@ -1570,14 +2186,14 @@ Expression *StructLiteralExp::interpret(InterState *istate) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; + { Expression *e = elements->tdata()[i]; if (!e) continue; Expression *ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(ex)) { delete expsx; - return EXP_CANT_INTERPRET; + return ex; } /* If any changes, do Copy On Write @@ -1586,13 +2202,14 @@ Expression *StructLiteralExp::interpret(InterState *istate) { if (!expsx) { expsx = new Expressions(); + ++CtfeStatus::numArrayAllocs; expsx->setDim(elements->dim); for (size_t j = 0; j < elements->dim; j++) { - expsx->data[j] = elements->data[j]; + expsx->tdata()[j] = elements->tdata()[j]; } } - expsx->data[i] = (void *)ex; + expsx->tdata()[i] = ex; } } } @@ -1607,28 +2224,171 @@ Expression *StructLiteralExp::interpret(InterState *istate) se->type = type; return se; } - return this; + return copyLiteral(this); +} + +/****************************** + * Helper for NewExp + * Create an array literal consisting of 'elem' duplicated 'dim' times. + */ +ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, + Expression *elem, size_t dim) +{ + Expressions *elements = new Expressions(); + elements->setDim(dim); + bool mustCopy = needToCopyLiteral(elem); + for (size_t i = 0; i < dim; i++) + { if (mustCopy) + elem = copyLiteral(elem); + elements->tdata()[i] = elem; + } + ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); + ae->type = type; + return ae; +} + +/****************************** + * Helper for NewExp + * Create a string literal consisting of 'value' duplicated 'dim' times. + */ +StringExp *createBlockDuplicatedStringLiteral(Type *type, + unsigned value, size_t dim, int sz) +{ + unsigned char *s; + s = (unsigned char *)mem.calloc(dim + 1, sz); + for (size_t elemi=0; elemitype = type; + se->sz = sz; + se->committed = true; + return se; +} + +// Create an array literal of type 'newtype' with dimensions given by +// 'arguments'[argnum..$] +Expression *recursivelyCreateArrayLiteral(Type *newtype, InterState *istate, + Expressions *arguments, int argnum) +{ + Expression *lenExpr = ((arguments->tdata()[argnum]))->interpret(istate); + if (exceptionOrCantInterpret(lenExpr)) + return lenExpr; + size_t len = (size_t)(lenExpr->toInteger()); + Type *elemType = ((TypeArray *)newtype)->next; + if (elemType->ty == Tarray && argnum < arguments->dim - 1) + { + Expression *elem = recursivelyCreateArrayLiteral(elemType, istate, + arguments, argnum + 1); + if (exceptionOrCantInterpret(elem)) + return elem; + + Expressions *elements = new Expressions(); + elements->setDim(len); + for (size_t i = 0; i < len; i++) + elements->tdata()[i] = copyLiteral(elem); + ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); + ae->type = newtype; + return ae; + } + assert(argnum == arguments->dim - 1); + if (elemType->ty == Tchar || elemType->ty == Twchar + || elemType->ty == Tdchar) + return createBlockDuplicatedStringLiteral(newtype, + (unsigned)(elemType->defaultInitLiteral()->toInteger()), + len, elemType->size()); + return createBlockDuplicatedArrayLiteral(newtype, + elemType->defaultInitLiteral(), + len); } -Expression *NewExp::interpret(InterState *istate) +Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("NewExp::interpret() %s\n", toChars()); #endif - if (newtype->ty == Tarray && arguments && arguments->dim == 1) + if (newtype->ty == Tarray && arguments) + return recursivelyCreateArrayLiteral(newtype, istate, arguments, 0); + + if (newtype->toBasetype()->ty == Tstruct) + { + Expression *se = newtype->defaultInitLiteral(); +#if DMDV2 + if (member) { - Expression *lenExpr = ((Expression *)(arguments->data[0]))->interpret(istate); - if (lenExpr == EXP_CANT_INTERPRET) + int olderrors = global.errors; + member->interpret(istate, arguments, se); + if (olderrors != global.errors) + { + error("cannot evaluate %s at compile time", toChars()); return EXP_CANT_INTERPRET; - return createBlockDuplicatedArrayLiteral(newtype, - ((TypeArray *)newtype)->next->defaultInitLiteral(), - lenExpr->toInteger()); + } + } +#else // The above code would fail on D1 because it doesn't use STRUCTTHISREF, + // but that's OK because D1 doesn't have struct constructors anyway. + assert(!member); +#endif + Expression *e = new AddrExp(loc, se); + e->type = type; + return e; + } + if (newtype->toBasetype()->ty == Tclass) + { + ClassDeclaration *cd = ((TypeClass *)newtype->toBasetype())->sym; + size_t totalFieldCount = 0; + for (ClassDeclaration *c = cd; c; c = c->baseClass) + totalFieldCount += c->fields.dim; + Expressions *elems = new Expressions; + elems->setDim(totalFieldCount); + size_t fieldsSoFar = totalFieldCount; + for (ClassDeclaration *c = cd; c; c = c->baseClass) + { + fieldsSoFar -= c->fields.dim; + for (size_t i = 0; i < c->fields.dim; i++) + { + Dsymbol *s = c->fields.tdata()[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(); + if (exceptionOrCantInterpret(m)) + return m; + elems->tdata()[fieldsSoFar+i] = m; + } + } + // Hack: we store a ClassDeclaration instead of a StructDeclaration. + // We probably won't get away with this. + StructLiteralExp *se = new StructLiteralExp(loc, (StructDeclaration *)cd, elems, newtype); + Expression *e = new ClassReferenceExp(loc, se, type); + if (member) + { // Call constructor + if (!member->fbody) + { + Expression *ctorfail = evaluateIfBuiltin(istate, loc, member, arguments, e); + if (ctorfail && exceptionOrCantInterpret(ctorfail)) + return ctorfail; + if (ctorfail) + return e; + member->error("%s cannot be constructed at compile time, because the constructor has no available source code", newtype->toChars()); + return EXP_CANT_INTERPRET; + } + Expression * ctorfail = member->interpret(istate, arguments, e); + if (exceptionOrCantInterpret(ctorfail)) + return ctorfail; + } + return e; } error("Cannot interpret %s at compile time", toChars()); return EXP_CANT_INTERPRET; } -Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)) +Expression *UnaExp::interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *)) { Expression *e; Expression *e1; @@ -1636,22 +2396,16 @@ Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type * printf("UnaExp::interpretCommon() %s\n", toChars()); #endif e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1) - goto Lcant; - + if (exceptionOrCantInterpret(e1)) + return e1; e = (*fp)(type, e1); return e; - -Lcant: - return EXP_CANT_INTERPRET; } #define UNA_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ +Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ { \ - return interpretCommon(istate, &op); \ + return interpretCommon(istate, goal, &op); \ } UNA_INTERPRET(Neg) @@ -1659,10 +2413,116 @@ UNA_INTERPRET(Com) UNA_INTERPRET(Not) UNA_INTERPRET(Bool) +Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs) +{ + *ofs = 0; + if (e->op == TOKaddress) + e = ((AddrExp *)e)->e1; + if (e->op == TOKindex) + { + IndexExp *ie = (IndexExp *)e; + // Note that each AA element is part of its own memory block + if ((ie->e1->type->ty == Tarray || ie->e1->type->ty == Tsarray + || ie->e1->op == TOKstring || ie->e1->op==TOKarrayliteral) && + ie->e2->op == TOKint64) + { + *ofs = ie->e2->toInteger(); + return ie->e1; + } + } + return e; +} + +// return e1 - e2 as an integer, or error if not possible +Expression *pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2) +{ + dinteger_t ofs1, ofs2; + Expression *agg1 = getAggregateFromPointer(e1, &ofs1); + Expression *agg2 = getAggregateFromPointer(e2, &ofs2); + if (agg1 == agg2) + { + Type *pointee = ((TypePointer *)agg1->type)->next; + dinteger_t sz = pointee->size(); + return new IntegerExp(loc, (ofs1-ofs2)*sz, type); + } + else if (agg1->op == TOKstring && agg2->op == TOKstring) + { + if (((StringExp *)agg1)->string == ((StringExp *)agg2)->string) + { + Type *pointee = ((TypePointer *)agg1->type)->next; + dinteger_t sz = pointee->size(); + return new IntegerExp(loc, (ofs1-ofs2)*sz, type); + } + } +#if LOGASSIGN + printf("FAILED POINTER DIFF\n"); + showCtfeExpr(agg1); + showCtfeExpr(agg2); +#endif + error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract " + "pointers to two different memory blocks", + e1->toChars(), e2->toChars()); + return EXP_CANT_INTERPRET; +} + +// Return eptr op e2, where eptr is a pointer, e2 is an integer, +// and op is TOKadd or TOKmin +Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type, + Expression *eptr, Expression *e2) +{ + if (eptr->type->nextOf()->ty == Tvoid) + { + error(loc, "cannot perform arithmetic on void* pointers at compile time"); + return EXP_CANT_INTERPRET; + } + dinteger_t ofs1, ofs2; + if (eptr->op == TOKaddress) + eptr = ((AddrExp *)eptr)->e1; + Expression *agg1 = getAggregateFromPointer(eptr, &ofs1); + if (agg1->op != TOKstring && agg1->op != TOKarrayliteral) + { + error(loc, "cannot perform pointer arithmetic on non-arrays at compile time"); + return EXP_CANT_INTERPRET; + } + ofs2 = e2->toInteger(); + Type *pointee = ((TypePointer *)agg1->type)->next; + dinteger_t sz = pointee->size(); + Expression *dollar = ArrayLength(Type::tsize_t, agg1); + assert(dollar != EXP_CANT_INTERPRET); + dinteger_t len = dollar->toInteger(); + + Expression *val = agg1; + TypeArray *tar = (TypeArray *)val->type; + dinteger_t indx = ofs1; + if (op == TOKadd || op == TOKaddass || op == TOKplusplus) + indx = indx + ofs2/sz; + else if (op == TOKmin || op == TOKminass || op == TOKminusminus) + indx -= ofs2/sz; + else + { + error(loc, "CTFE Internal compiler error: bad pointer operation"); + return EXP_CANT_INTERPRET; + } + if (val->op != TOKarrayliteral && val->op != TOKstring) + { + error(loc, "CTFE Internal compiler error: pointer arithmetic %s", val->toChars()); + return EXP_CANT_INTERPRET; + } + if (indx < 0 || indx > len) + { + error(loc, "cannot assign pointer to index %jd inside memory block [0..%jd]", indx, len); + return EXP_CANT_INTERPRET; + } + + IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t); + IndexExp *ie = new IndexExp(loc, val, ofs); + ie->type = type; + return ie; +} typedef Expression *(*fp_t)(Type *, Expression *, Expression *); -Expression *BinExp::interpretCommon(InterState *istate, fp_t fp) +Expression *BinExp::interpretCommon(InterState *istate, CtfeGoal goal, fp_t fp) { Expression *e; Expression *e1; Expression *e2; @@ -1670,19 +2530,56 @@ Expression *BinExp::interpretCommon(InterState *istate, fp_t fp) #if LOG printf("BinExp::interpretCommon() %s\n", toChars()); #endif + if (this->e1->type->ty == Tpointer && this->e2->type->ty == Tpointer && op == TOKmin) + { + e1 = this->e1->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e1)) + return e1; + e2 = this->e2->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e2)) + return e2; + return pointerDifference(loc, type, e1, e2); + } + if (this->e1->type->ty == Tpointer && this->e2->type->isintegral()) + { + e1 = this->e1->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e1)) + return e1; + e2 = this->e2->interpret(istate); + if (exceptionOrCantInterpret(e2)) + return e2; + return pointerArithmetic(loc, op, type, e1, e2); + } + if (this->e2->type->ty == Tpointer && this->e1->type->isintegral() && op==TOKadd) + { e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; + if (exceptionOrCantInterpret(e1)) + return e1; + e2 = this->e2->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e2)) + return e1; + return pointerArithmetic(loc, op, type, e2, e1); + } + if (this->e1->type->ty == Tpointer || this->e2->type->ty == Tpointer) + { + error("pointer expression %s cannot be interpreted at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + e1 = this->e1->interpret(istate); + if (exceptionOrCantInterpret(e1)) + return e1; if (e1->isConst() != 1) goto Lcant; e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; + if (exceptionOrCantInterpret(e2)) + return e2; if (e2->isConst() != 1) goto Lcant; e = (*fp)(type, e1, e2); + if (e == EXP_CANT_INTERPRET) + error("%s cannot be interpreted at compile time", toChars()); return e; Lcant: @@ -1690,9 +2587,9 @@ Lcant: } #define BIN_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ +Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ { \ - return interpretCommon(istate, &op); \ + return interpretCommon(istate, goal, &op); \ } BIN_INTERPRET(Add) @@ -1706,11 +2603,71 @@ BIN_INTERPRET(Ushr) BIN_INTERPRET(And) BIN_INTERPRET(Or) BIN_INTERPRET(Xor) +#if DMDV2 +BIN_INTERPRET(Pow) +#endif typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); -Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) +// Return EXP_CANT_INTERPRET if they point to independent memory blocks +Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) +{ + dinteger_t ofs1, ofs2; + Expression *agg1 = getAggregateFromPointer(e1, &ofs1); + Expression *agg2 = getAggregateFromPointer(e2, &ofs2); + if (agg1 == agg2 || + (agg1->op == TOKstring && agg2->op == TOKstring && + ((StringExp *)agg1)->string == ((StringExp *)agg2)->string)) + + { + dinteger_t cm = ofs1 - ofs2; + dinteger_t n; + dinteger_t zero = 0; + switch(op) + { + case TOKlt: n = (ofs1 < ofs2); break; + case TOKle: n = (ofs1 <= ofs2); break; + case TOKgt: n = (ofs1 > ofs2); break; + case TOKge: n = (ofs1 >= ofs2); break; + case TOKidentity: + case TOKequal: n = (ofs1 == ofs2); break; + case TOKnotidentity: + case TOKnotequal: n = (ofs1 != ofs2); break; + default: + assert(0); + } + return new IntegerExp(loc, n, type); + } + int cmp; + if (e1->op == TOKnull) + { + cmp = (e2->op == TOKnull); + } + else if (e2->op == TOKnull) + { + cmp = 0; + } + else + { + switch(op) + { + case TOKidentity: + case TOKequal: + case TOKnotidentity: // 'cmp' gets inverted below + case TOKnotequal: + cmp = 0; + break; + default: + return EXP_CANT_INTERPRET; + } + } + if (op == TOKnotidentity || op == TOKnotequal) + cmp ^= 1; + return new IntegerExp(loc, cmp, type); +} + +Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp) { Expression *e; Expression *e1; Expression *e2; @@ -1718,27 +2675,56 @@ Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) #if LOG printf("BinExp::interpretCommon2() %s\n", toChars()); #endif + if (this->e1->type->ty == Tpointer && this->e2->type->ty == Tpointer) + { + e1 = this->e1->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e1)) + return e1; + e2 = this->e2->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e2)) + return e2; + e = comparePointers(loc, op, type, e1, e2); + if (e == EXP_CANT_INTERPRET) + { + error("%s and %s point to independent memory blocks and " + "cannot be compared at compile time", this->e1->toChars(), + this->e2->toChars()); + } + return e; + } e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; + if (exceptionOrCantInterpret(e1)) + return e1; + if (e1->op == TOKslice) + e1 = resolveSlice(e1); + if (e1->isConst() != 1 && e1->op != TOKnull && e1->op != TOKstring && e1->op != TOKarrayliteral && e1->op != TOKstructliteral) + { + error("cannot compare %s at compile time", e1->toChars()); goto Lcant; + } e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; + if (exceptionOrCantInterpret(e2)) + return e2; + if (e2->op == TOKslice) + e2 = resolveSlice(e2); if (e2->isConst() != 1 && e2->op != TOKnull && e2->op != TOKstring && e2->op != TOKarrayliteral && e2->op != TOKstructliteral) + { + error("cannot compare %s at compile time", e2->toChars()); goto Lcant; - + } e = (*fp)(op, type, e1, e2); + if (e == EXP_CANT_INTERPRET) + error("%s cannot be interpreted at compile time", toChars()); return e; Lcant: @@ -1746,9 +2732,9 @@ Lcant: } #define BIN_INTERPRET2(op) \ -Expression *op##Exp::interpret(InterState *istate) \ +Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ { \ - return interpretCommon2(istate, &op); \ + return interpretCommon2(istate, goal, &op); \ } BIN_INTERPRET2(Equal) @@ -1761,118 +2747,23 @@ BIN_INTERPRET2(Cmp) /*************************************** * Duplicate the elements array, then set field 'indexToChange' = newelem. */ -Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, void *newelem) +Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem) { Expressions *expsx = new Expressions(); + ++CtfeStatus::numArrayAllocs; expsx->setDim(oldelems->dim); for (size_t j = 0; j < expsx->dim; j++) { if (j == indexToChange) - expsx->data[j] = newelem; + expsx->tdata()[j] = newelem; else - expsx->data[j] = oldelems->data[j]; + expsx->tdata()[j] = oldelems->tdata()[j]; } return expsx; } -/*************************************** - * Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint+newelems.length..$] - */ -Expressions *spliceElements(Expressions *oldelems, - Expressions *newelems, size_t insertpoint) -{ - Expressions *expsx = new Expressions(); - expsx->setDim(oldelems->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j >= insertpoint && j < insertpoint + newelems->dim) - expsx->data[j] = newelems->data[j - insertpoint]; - else - expsx->data[j] = oldelems->data[j]; - } - return expsx; -} - -/*************************************** - * Returns oldstr[0..insertpoint] ~ newstr ~ oldstr[insertpoint+newlen..$] - */ -StringExp *spliceStringExp(StringExp *oldstr, StringExp *newstr, size_t insertpoint) -{ - assert(oldstr->sz==newstr->sz); - unsigned char *s; - size_t oldlen = oldstr->len; - size_t newlen = newstr->len; - size_t sz = oldstr->sz; - s = (unsigned char *)mem.calloc(oldlen + 1, sz); - memcpy(s, oldstr->string, oldlen * sz); - memcpy(s + insertpoint * sz, newstr->string, newlen * sz); - StringExp *se2 = new StringExp(oldstr->loc, s, oldlen); - se2->committed = oldstr->committed; - se2->postfix = oldstr->postfix; - se2->type = oldstr->type; - return se2; -} - -/****************************** - * Create an array literal consisting of 'elem' duplicated 'dim' times. - */ -ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, - Expression *elem, size_t dim) -{ - Expressions *elements = new Expressions(); - elements->setDim(dim); - for (size_t i = 0; i < dim; i++) - elements->data[i] = elem; - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); - ae->type = type; - return ae; -} - -/****************************** - * Create a string literal consisting of 'value' duplicated 'dim' times. - */ -StringExp *createBlockDuplicatedStringLiteral(Type *type, - unsigned value, size_t dim, int sz) -{ - unsigned char *s; - s = (unsigned char *)mem.calloc(dim + 1, sz); - for (int elemi=0; elemitype = type; - return se; -} - -/******************************** - * Add v to the istate list, unless it already exists there. - */ -void addVarToInterstate(InterState *istate, VarDeclaration *v) -{ - if (!v->isParameter()) - { - for (size_t i = 0; 1; i++) - { - if (i == istate->vars.dim) - { istate->vars.push(v); - //printf("\tadding %s to istate\n", v->toChars()); - break; - } - if (v == (VarDeclaration *)istate->vars.data[i]) - break; - } - } -} - -// Create a new struct literal, which is the same as se except that se.field[offset] = elem -Expression * modifyStructField(Type *type, StructLiteralExp *se, size_t offset, Expression *newval) +// Create a new struct literal, which is the same as se except that se.field[offset] = elem +Expression * modifyStructField(Type *type, StructLiteralExp *se, size_t offset, Expression *newval) { int fieldi = se->getFieldIndex(newval->type, offset); if (fieldi == -1) @@ -1890,95 +2781,29 @@ Expression * modifyStructField(Type *type, StructLiteralExp *se, size_t offset, * set arr[index] = newval and return the new array. * */ -Expression * assignArrayElement(Loc loc, Expression *arr, Expression *index, Expression *newval) +Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae, Expression *index, Expression *newval) { - ArrayLiteralExp *ae = NULL; - AssocArrayLiteralExp *aae = NULL; - StringExp *se = NULL; - if (arr->op == TOKarrayliteral) - ae = (ArrayLiteralExp *)arr; - else if (arr->op == TOKassocarrayliteral) - aae = (AssocArrayLiteralExp *)arr; - else if (arr->op == TOKstring) - se = (StringExp *)arr; - else assert(0); - - if (ae) - { - int elemi = index->toInteger(); - if (elemi >= ae->elements->dim) - { - error(loc, "array index %d is out of bounds %s[0..%d]", elemi, - arr->toChars(), ae->elements->dim); - return EXP_CANT_INTERPRET; - } - // Create new array literal reflecting updated elem - Expressions *expsx = changeOneElement(ae->elements, elemi, newval); - Expression *ee = new ArrayLiteralExp(ae->loc, expsx); - ee->type = ae->type; - newval = ee; - } - else if (se) - { - /* Create new string literal reflecting updated elem - */ - int elemi = index->toInteger(); - if (elemi >= se->len) - { - error(loc, "array index %d is out of bounds %s[0..%d]", elemi, - arr->toChars(), se->len); - return EXP_CANT_INTERPRET; - } - unsigned char *s; - s = (unsigned char *)mem.calloc(se->len + 1, se->sz); - memcpy(s, se->string, se->len * se->sz); - unsigned value = newval->toInteger(); - switch (se->sz) - { - case 1: s[elemi] = value; break; - case 2: ((unsigned short *)s)[elemi] = value; break; - case 4: ((unsigned *)s)[elemi] = value; break; - default: - assert(0); - break; - } - StringExp *se2 = new StringExp(se->loc, s, se->len); - se2->committed = se->committed; - se2->postfix = se->postfix; - se2->type = se->type; - newval = se2; - } - else if (aae) - { /* Create new associative array literal reflecting updated key/value */ Expressions *keysx = aae->keys; - Expressions *valuesx = new Expressions(); - valuesx->setDim(aae->values->dim); + Expressions *valuesx = aae->values; int updated = 0; for (size_t j = valuesx->dim; j; ) { j--; - Expression *ekey = (Expression *)aae->keys->data[j]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, index); - if (ex == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; + Expression *ekey = aae->keys->tdata()[j]; + Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, index); + if (exceptionOrCantInterpret(ex)) + return ex; if (ex->isBool(TRUE)) - { valuesx->data[j] = (void *)newval; + { valuesx->tdata()[j] = newval; updated = 1; } - else - valuesx->data[j] = aae->values->data[j]; } if (!updated) { // Append index/newval to keysx[]/valuesx[] valuesx->push(newval); - keysx = (Expressions *)keysx->copy(); keysx->push(index); } - Expression *aae2 = new AssocArrayLiteralExp(aae->loc, keysx, valuesx); - aae2->type = aae->type; - return aae2; - } return newval; } @@ -2003,67 +2828,6 @@ UnaExp *isUnaExp(Expression *e) return NULL; } -// To resolve an assignment expression, we need to walk to the end of the -// expression to find the ultimate variable which is modified. But, in building -// up the expression, we need to walk the tree *backwards*. There isn't a -// standard way to do this, but if we know we're at depth d, iterating from -// the root up to depth d-1 will give us the parent node. Inefficient, but -// depth is almost always < 3. -struct ExpressionReverseIterator -{ - Expression *totalExpr; // The root expression - Expression *thisval; // The value to be used for TOKthis - int totalDepth; - - ExpressionReverseIterator(Expression *root, Expression *thisexpr) - { - totalExpr = root; - thisval = thisexpr; - totalDepth = findExpressionDepth(totalExpr); - } - - int findExpressionDepth(Expression *e); - Expression *getExpressionAtDepth(int depth); -}; - -// Determines the depth in unary expressions. -int ExpressionReverseIterator::findExpressionDepth(Expression *e) -{ - int depth = 0; - for (;;) - { - e = resolveReferences(e, thisval); - if (e->op == TOKvar) - return depth; - if (e->op == TOKcall) - return depth; - ++depth; - UnaExp *u = isUnaExp(e); - if (u) - e = u->e1; - else - return depth; - } -} - -Expression *ExpressionReverseIterator::getExpressionAtDepth(int depth) -{ - Expression *e = totalExpr; - int d = 0; - for (;;) - { - e = resolveReferences(e, thisval); - if (d == depth) return e; - ++d; - assert(e->op != TOKvar); - UnaExp *u = isUnaExp(e); - if (u) - e = u->e1; - else - return e; - } -} - // Returns the variable which is eventually modified, or NULL if an rvalue. // thisval is the current value of 'this'. VarDeclaration * findParentVar(Expression *e, Expression *thisval) @@ -2089,112 +2853,632 @@ VarDeclaration * findParentVar(Expression *e, Expression *thisval) return v; } -// Returns the value to be assigned to the last dotVar, given the existing value at this depth. -Expression *assignDotVar(ExpressionReverseIterator rvs, int depth, Expression *existing, Expression *newval) +// Given expr, which evaluates to an array/AA/string literal, +// return true if it needs to be copied +bool needToCopyLiteral(Expression *expr) { - if (depth == 0) - return newval; - assert(existing && existing != EXP_CANT_INTERPRET); - Expression *e = rvs.getExpressionAtDepth(depth - 1); - if (e->op == TOKdotvar) + for (;;) { - VarDeclaration *member = ((DotVarExp *)e)->var->isVarDeclaration(); - assert(member); - assert(existing); - assert(existing != EXP_CANT_INTERPRET); - assert(existing->op == TOKstructliteral); - if (existing->op != TOKstructliteral) - return EXP_CANT_INTERPRET; - - StructLiteralExp *se = (StructLiteralExp *)existing; - int fieldi = se->getFieldIndex(member->type, member->offset); - if (fieldi == -1) - return EXP_CANT_INTERPRET; - assert(fieldi>=0 && fieldi < se->elements->dim); - Expression *ex = (Expression *)(se->elements->data[fieldi]); - - newval = assignDotVar(rvs, depth - 1, ex, newval); - Expressions *expsx = changeOneElement(se->elements, fieldi, newval); - Expression * ee = new StructLiteralExp(se->loc, se->sd, expsx); - ee->type = se->type; - return ee; + switch (expr->op) + { + case TOKarrayliteral: + case TOKassocarrayliteral: + case TOKstructliteral: + return true; + case TOKstring: + case TOKthis: + case TOKvar: + return false; + case TOKassign: + return false; + case TOKindex: + case TOKdotvar: + case TOKslice: + case TOKcast: + expr = ((UnaExp *)expr)->e1; + continue; + case TOKcat: + return needToCopyLiteral(((BinExp *)expr)->e1) || + needToCopyLiteral(((BinExp *)expr)->e2); + case TOKcatass: + expr = ((BinExp *)expr)->e2; + continue; + default: + return false; } - assert(0); - return NULL; + } +} + +Expressions *copyLiteralArray(Expressions *oldelems) +{ + if (!oldelems) + return oldelems; + CtfeStatus::numArrayAllocs++; + Expressions *newelems = new Expressions(); + newelems->setDim(oldelems->dim); + for (size_t i = 0; i < oldelems->dim; i++) + newelems->tdata()[i] = copyLiteral(oldelems->tdata()[i]); + return newelems; } -Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) + +// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral. +// This value will be used for in-place modification. +Expression *copyLiteral(Expression *e) { -#if LOG - printf("BinExp::interpretAssignCommon() %s\n", toChars()); + if (e->op == TOKstring) // syntaxCopy doesn't make a copy for StringExp! + { + StringExp *se = (StringExp *)e; + unsigned char *s; + s = (unsigned char *)mem.calloc(se->len + 1, se->sz); + memcpy(s, se->string, se->len * se->sz); + StringExp *se2 = new StringExp(se->loc, s, se->len); + se2->committed = se->committed; + se2->postfix = se->postfix; + se2->type = se->type; + se2->sz = se->sz; + return se2; + } + else if (e->op == TOKarrayliteral) + { + ArrayLiteralExp *ae = (ArrayLiteralExp *)e; + ArrayLiteralExp *r = new ArrayLiteralExp(e->loc, + copyLiteralArray(ae->elements)); + r->type = e->type; + return r; + } + else if (e->op == TOKassocarrayliteral) + { + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; + AssocArrayLiteralExp *r = new AssocArrayLiteralExp(e->loc, + copyLiteralArray(aae->keys), copyLiteralArray(aae->values)); + r->type = e->type; + return r; + } + /* syntaxCopy doesn't work for struct literals, because of a nasty special + * case: block assignment is permitted inside struct literals, eg, + * an int[4] array can be initialized with a single int. + */ + else if (e->op == TOKstructliteral) + { + StructLiteralExp *se = (StructLiteralExp *)e; + Expressions *oldelems = se->elements; + Expressions * newelems = new Expressions(); + newelems->setDim(oldelems->dim); + for (size_t i = 0; i < newelems->dim; i++) + { + Expression *m = oldelems->tdata()[i]; + // We need the struct definition to detect block assignment + AggregateDeclaration *sd = se->sd; + Dsymbol *s = sd->fields.tdata()[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + // If it is a void assignment, use the default initializer + if (!m) + m = v->type->defaultInitLiteral(e->loc); + if (m->op == TOKslice) + m = resolveSlice(m); + if ((v->type->ty != m->type->ty) && v->type->ty == Tsarray) + { + // Block assignment from inside struct literals + TypeSArray *tsa = (TypeSArray *)v->type; + uinteger_t length = tsa->dim->toInteger(); + m = createBlockDuplicatedArrayLiteral(v->type, m, (size_t)length); + } + else if (v->type->ty != Tarray && v->type->ty!=Taarray) // NOTE: do not copy array references + m = copyLiteral(m); + newelems->tdata()[i] = m; + } +#if DMDV2 + StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems, se->stype); +#else + StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems); #endif - Expression *e = EXP_CANT_INTERPRET; - Expression *e1 = this->e1; - if (!istate) + r->type = e->type; + return r; + } + else if (e->op == TOKfunction || e->op == TOKdelegate + || e->op == TOKsymoff || e->op == TOKnull + || e->op == TOKvar + || e->op == TOKint64 || e->op == TOKfloat64 + || e->op == TOKchar || e->op == TOKcomplex80) + { // Simple value types + Expression *r = e->syntaxCopy(); + r->type = e->type; + return r; + } + else if (e->type->ty == Tpointer && e->type->nextOf()->ty != Tfunction) + { // For pointers, we only do a shallow copy. + Expression *r; + if (e->op == TOKaddress) + r = new AddrExp(e->loc, ((AddrExp *)e)->e1); + else if (e->op == TOKindex) + r = new IndexExp(e->loc, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2); + else if (e->op == TOKdotvar) + r = new DotVarExp(e->loc, ((DotVarExp *)e)->e1, + ((DotVarExp *)e)->var +#if DMDV2 + , ((DotVarExp *)e)->hasOverloads +#endif + ); + else + assert(0); + r->type = e->type; + return r; + } + else if (e->op == TOKslice) + { // Array slices only do a shallow copy + Expression *r = new SliceExp(e->loc, ((SliceExp *)e)->e1, + ((SliceExp *)e)->lwr, ((SliceExp *)e)->upr); + r->type = e->type; + return r; + } + else if (e->op == TOKclassreference) + return new ClassReferenceExp(e->loc, ((ClassReferenceExp *)e)->value, e->type); + else { - error("value of %s is not known at compile time", e1->toChars()); + e->error("Internal Compiler Error: CTFE literal %s", e->toChars()); + assert(0); return e; } +} - if (fp) +/* Deal with type painting. + * Type painting is a major nuisance: we can't just set + * e->type = type, because that would change the original literal. + * But, we can't simply copy the literal either, because that would change + * the values of any pointers. + */ +Expression *paintTypeOntoLiteral(Type *type, Expression *lit) +{ + if (lit->type == type) + return lit; + Expression *e; + if (lit->op == TOKslice) { - if (e1->op == TOKcast) - { CastExp *ce = (CastExp *)e1; - e1 = ce->e1; + SliceExp *se = (SliceExp *)lit; + e = new SliceExp(lit->loc, se->e1, se->lwr, se->upr); + } + else if (lit->op == TOKindex) + { + IndexExp *ie = (IndexExp *)lit; + e = new IndexExp(lit->loc, ie->e1, ie->e2); } + else if (lit->op == TOKarrayliteral) + { + ArrayLiteralExp *ae = (ArrayLiteralExp *)lit; + e = new ArrayLiteralExp(lit->loc, ae->elements); } - if (e1 == EXP_CANT_INTERPRET) - return e1; + else if (lit->op == TOKstring) + { + // For strings, we need to introduce another level of indirection + e = new SliceExp(lit->loc, lit, + new IntegerExp(0, 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit)); + } + else if (lit->op == TOKassocarrayliteral) + { + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)lit; + e = new AssocArrayLiteralExp(lit->loc, aae->keys, aae->values); + } + else + e = copyLiteral(lit); + e->type = type; + return e; +} - assert(istate); - // ---------------------------------------------------- - // Deal with read-modify-write assignments. - // Set 'newval' to the final assignment value - // Also determine the return value (except for slice - // assignments, which are more complicated) - // ---------------------------------------------------- - Expression * newval = this->e2->interpret(istate); - if (newval == EXP_CANT_INTERPRET) - return newval; - - if (fp || e1->op == TOKarraylength) +Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e) +{ + if (e->op == TOKnull) + return paintTypeOntoLiteral(to, e); + if (e->op == TOKclassreference) + { // Disallow reinterpreting class casts. Do this by ensuring that + // the original class can implicitly convert to the target class + ClassDeclaration *originalClass = ((ClassReferenceExp *)e)->originalClass(); + if (originalClass->type->implicitConvTo(to)) + return paintTypeOntoLiteral(to, e); + else { - // If it isn't a simple assignment, we need the existing value - Expression * oldval = e1->interpret(istate); - if (oldval == EXP_CANT_INTERPRET) + error(loc, "cannot reinterpret class from %s to %s at compile time", originalClass->toChars(), to->toChars()); return EXP_CANT_INTERPRET; - while (oldval->op == TOKvar) - { - oldval = resolveReferences(oldval, istate->localThis); - oldval = oldval->interpret(istate); - if (oldval == EXP_CANT_INTERPRET) - return oldval; } + } + Expression *r = Cast(type, to, e); + if (r == EXP_CANT_INTERPRET) + error(loc, "cannot cast %s to %s at compile time", r->toChars(), to->toChars()); + return r; +} - if (fp) + +/* Set a slice of char array literal 'existingAE' from a string 'newval'. + * existingAE[firstIndex..firstIndex+newval.length] = newval. + */ +void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex) +{ + size_t newlen = newval->len; + size_t sz = newval->sz; + unsigned char *s = (unsigned char *)newval->string; + Type *elemType = existingAE->type->nextOf(); + for (size_t j = 0; j < newlen; j++) { - newval = (*fp)(type, oldval, newval); - if (newval == EXP_CANT_INTERPRET) + dinteger_t val; + switch (sz) { - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; + case 1: val = s[j]; break; + case 2: val = ((unsigned short *)s)[j]; break; + case 4: val = ((unsigned *)s)[j]; break; + default: + assert(0); + break; } - // Determine the return value - e = Cast(type, type, post ? oldval : newval); - if (e == EXP_CANT_INTERPRET) - return e; + existingAE->elements->tdata()[j+firstIndex] + = new IntegerExp(newval->loc, val, elemType); } - else - e = newval; +} - if (e1->op == TOKarraylength) +/* Set a slice of string 'existingSE' from a char array literal 'newae'. + * existingSE[firstIndex..firstIndex+newae.length] = newae. + */ +void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex) +{ + unsigned char *s = (unsigned char *)existingSE->string; + for (size_t j = 0; j < newae->elements->dim; j++) + { + unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger()); + switch (existingSE->sz) + { + case 1: s[j+firstIndex] = value; break; + case 2: ((unsigned short *)s)[j+firstIndex] = value; break; + case 4: ((unsigned *)s)[j+firstIndex] = value; break; + default: + assert(0); + break; + } + } +} + +/* Set a slice of string 'existingSE' from a string 'newstr'. + * existingSE[firstIndex..firstIndex+newstr.length] = newstr. + */ +void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex) +{ + unsigned char *s = (unsigned char *)existingSE->string; + size_t sz = existingSE->sz; + assert(sz == newstr->sz); + memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len); +} + + +/* Set dest = src, where both dest and src are container value literals + * (ie, struct literals, or static arrays (can be an array literal or a string) + * Assignment is recursively in-place. + * Purpose: any reference to a member of 'dest' will remain valid after the + * assignment. + */ +void assignInPlace(Expression *dest, Expression *src) +{ + assert(dest->op == TOKstructliteral || dest->op == TOKarrayliteral || + dest->op == TOKstring); + Expressions *oldelems; + Expressions *newelems; + if (dest->op == TOKstructliteral) + { + assert(dest->op == src->op); + oldelems = ((StructLiteralExp *)dest)->elements; + newelems = ((StructLiteralExp *)src)->elements; + } + else if (dest->op == TOKarrayliteral && src->op==TOKarrayliteral) + { + oldelems = ((ArrayLiteralExp *)dest)->elements; + newelems = ((ArrayLiteralExp *)src)->elements; + } + else if (dest->op == TOKstring && src->op == TOKstring) + { + sliceAssignStringFromString((StringExp *)dest, (StringExp *)src, 0); + return; + } + else if (dest->op == TOKarrayliteral && src->op == TOKstring) + { + sliceAssignArrayLiteralFromString((ArrayLiteralExp *)dest, (StringExp *)src, 0); + return; + } + else if (src->op == TOKarrayliteral && dest->op == TOKstring) + { + sliceAssignStringFromArrayLiteral((StringExp *)dest, (ArrayLiteralExp *)src, 0); + return; + } + else assert(0); + + assert(oldelems->dim == newelems->dim); + + for (size_t i= 0; i < oldelems->dim; ++i) + { + Expression *e = newelems->tdata()[i]; + Expression *o = oldelems->tdata()[i]; + if (e->op == TOKstructliteral) + { + assert(o->op == e->op); + assignInPlace(o, e); + } + else if (e->type->ty == Tsarray && o->type->ty == Tsarray) + { + assignInPlace(o, e); + } + else + { + oldelems->tdata()[i] = newelems->tdata()[i]; + } + } +} + +void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef) +{ + assert( ae->type->ty == Tsarray || ae->type->ty == Tarray); +#if DMDV2 + Type *desttype = ((TypeArray *)ae->type)->next->castMod(0); + bool directblk = (val->type->toBasetype()->castMod(0)) == desttype; +#else + Type *desttype = ((TypeArray *)ae->type)->next; + bool directblk = (val->type->toBasetype()) == desttype; +#endif + + bool cow = !(val->op == TOKstructliteral || val->op == TOKarrayliteral + || val->op == TOKstring); + + for (size_t k = 0; k < ae->elements->dim; k++) + { + if (!directblk && ae->elements->tdata()[k]->op == TOKarrayliteral) + { + recursiveBlockAssign((ArrayLiteralExp *)ae->elements->tdata()[k], val, wantRef); + } + else + { + if (wantRef || cow) + ae->elements->tdata()[k] = val; + else + assignInPlace(ae->elements->tdata()[k], val); + } + } +} + + +Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_t fp, int post) +{ +#if LOG + printf("BinExp::interpretAssignCommon() %s\n", toChars()); +#endif + Expression *returnValue = EXP_CANT_INTERPRET; + Expression *e1 = this->e1; + if (!istate) + { + error("value of %s is not known at compile time", e1->toChars()); + return returnValue; + } + ++CtfeStatus::numAssignments; + /* Before we begin, we need to know if this is a reference assignment + * (dynamic array, AA, or class) or a value assignment. + * Determining this for slice assignments are tricky: we need to know + * if it is a block assignment (a[] = e) rather than a direct slice + * assignment (a[] = b[]). Note that initializers of multi-dimensional + * static arrays can have 2D block assignments (eg, int[7][7] x = 6;). + * So we need to recurse to determine if it is a block assignment. + */ + bool isBlockAssignment = false; + if (e1->op == TOKslice) + { + // a[] = e can have const e. So we compare the naked types. + Type *desttype = e1->type->toBasetype(); +#if DMDV2 + Type *srctype = e2->type->toBasetype()->castMod(0); +#else + Type *srctype = e2->type->toBasetype(); +#endif + while ( desttype->ty == Tsarray || desttype->ty == Tarray) + { + desttype = ((TypeArray *)desttype)->next; +#if DMDV2 + if (srctype == desttype->castMod(0)) +#else + if (srctype == desttype) +#endif + { + isBlockAssignment = true; + break; + } + } + } + bool wantRef = false; + if (!fp && this->e1->type->toBasetype() == this->e2->type->toBasetype() && + (e1->type->toBasetype()->ty == Tarray || e1->type->toBasetype()->ty == Taarray) + // e = *x is never a reference, because *x is always a value + && this->e2->op != TOKstar + ) + { +#if DMDV2 + wantRef = true; +#else + /* D1 doesn't have const in the type system. But there is still a + * vestigal const in the form of static const variables. + * Problematic code like: + * const int [] x = [1,2,3]; + * int [] y = x; + * can be dealt with by making this a non-ref assign (y = x.dup). + * Otherwise it's a big mess. + */ + VarDeclaration * targetVar = findParentVar(e2, istate->localThis); + if (!(targetVar && targetVar->isConst())) + wantRef = true; + // slice assignment of static arrays is not reference assignment + if ((e1->op==TOKslice) && ((SliceExp *)e1)->e1->type->ty == Tsarray) + wantRef = false; +#endif + // If it is assignment from a ref parameter, it's not a ref assignment + if (this->e2->op == TOKvar) + { + VarDeclaration *v = ((VarExp *)this->e2)->var->isVarDeclaration(); + if (v && (v->storage_class & (STCref | STCout))) + wantRef = false; + } + } + if (isBlockAssignment && (e2->type->toBasetype()->ty == Tarray || e2->type->toBasetype()->ty == Tsarray)) + { + wantRef = true; + } + /* This happens inside compiler-generated foreach statements. + * It's another case where we need a reference + * Note that a similar case, where e2 = 'this', occurs in + * construction of a struct with an invariant(). + */ + if (op==TOKconstruct && this->e1->op==TOKvar && this->e2->op != TOKthis + && this->e2->op != TOKcomma + && ((VarExp*)this->e1)->var->storage_class & STCref) + wantRef = true; + + if (fp) + { + while (e1->op == TOKcast) + { CastExp *ce = (CastExp *)e1; + e1 = ce->e1; + } + } + if (exceptionOrCantInterpret(e1)) + return e1; + + // First, deal with this = e; and call() = e; + if (e1->op == TOKthis) + { + e1 = istate->localThis; + } + if (e1->op == TOKcall) + { + bool oldWaiting = istate->awaitingLvalueReturn; + istate->awaitingLvalueReturn = true; + e1 = e1->interpret(istate); + istate->awaitingLvalueReturn = oldWaiting; + if (exceptionOrCantInterpret(e1)) + return e1; + if (e1->op == TOKarrayliteral || e1->op == TOKstring) + { + // f() = e2, when f returns an array, is always a slice assignment. + // Convert into arr[0..arr.length] = e2 + e1 = new SliceExp(loc, e1, + new IntegerExp(0, 0, Type::tsize_t), + ArrayLength(Type::tsize_t, e1)); + e1->type = type; + } + } + if (e1->op == TOKstar) + { + e1 = e1->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e1)) + return e1; + if (!(e1->op == TOKvar || e1->op == TOKdotvar || e1->op == TOKindex + || e1->op == TOKslice)) + { + error("cannot dereference invalid pointer %s", + this->e1->toChars()); + return EXP_CANT_INTERPRET; + } + } + + if (!(e1->op == TOKarraylength || e1->op == TOKvar || e1->op == TOKdotvar + || e1->op == TOKindex || e1->op == TOKslice)) + { + error("CTFE internal error: unsupported assignment %s", toChars()); + return EXP_CANT_INTERPRET; + } + + Expression * newval = NULL; + + if (!wantRef) + { // We need to treat pointers specially, because TOKsymoff can be used to + // return a value OR a pointer + assert(e1); + assert(e1->type); + if ((e1->type->ty == Tpointer && e1->type->nextOf()->ty != Tfunction) && (e2->op == TOKsymoff || e2->op==TOKaddress || e2->op==TOKvar)) + newval = this->e2->interpret(istate, ctfeNeedLvalue); + else + newval = this->e2->interpret(istate); + if (exceptionOrCantInterpret(newval)) + return newval; + } + // ---------------------------------------------------- + // Deal with read-modify-write assignments. + // Set 'newval' to the final assignment value + // Also determine the return value (except for slice + // assignments, which are more complicated) + // ---------------------------------------------------- + + if (fp || e1->op == TOKarraylength) + { + // If it isn't a simple assignment, we need the existing value + Expression * oldval = e1->interpret(istate); + if (exceptionOrCantInterpret(oldval)) + return oldval; + while (oldval->op == TOKvar) + { + oldval = resolveReferences(oldval, istate->localThis); + oldval = oldval->interpret(istate); + if (exceptionOrCantInterpret(oldval)) + return oldval; + } + + if (fp) + { + // ~= can create new values (see bug 6052) + if (op == TOKcatass) + { + if (needToCopyLiteral(newval)) + newval = copyLiteral(newval); + if (newval->op == TOKslice) + newval = resolveSlice(newval); + // It becomes a reference assignment + wantRef = true; + } + if (oldval->op == TOKslice) + oldval = resolveSlice(oldval); + if (this->e1->type->ty == Tpointer && this->e2->type->isintegral() + && (op==TOKaddass || op == TOKminass || + op == TOKplusplus || op == TOKminusminus)) + { + oldval = this->e1->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(oldval)) + return oldval; + newval = this->e2->interpret(istate); + if (exceptionOrCantInterpret(newval)) + return newval; + newval = pointerArithmetic(loc, op, type, oldval, newval); + } + else if (this->e1->type->ty == Tpointer) + { + error("pointer expression %s cannot be interpreted at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + else + { + newval = (*fp)(type, oldval, newval); + } + if (newval == EXP_CANT_INTERPRET) + { + error("Cannot interpret %s at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + if (exceptionOrCantInterpret(newval)) + return newval; + // Determine the return value + returnValue = ctfeCast(loc, type, type, post ? oldval : newval); + if (exceptionOrCantInterpret(returnValue)) + return returnValue; + } + else + returnValue = newval; + if (e1->op == TOKarraylength) { size_t oldlen = oldval->toInteger(); size_t newlen = newval->toInteger(); if (oldlen == newlen) // no change required -- we're done! - return e; + return returnValue; // Now change the assignment from arr.length = n into arr = newval e1 = ((ArrayLengthExp *)e1)->e1; if (oldlen != 0) @@ -2205,6 +3489,8 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) oldval = oldval->interpret(istate); } } + if (oldval->op == TOKslice) + oldval = resolveSlice(oldval); Type *t = e1->type->toBasetype(); if (t->ty == Tarray) { @@ -2216,15 +3502,35 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) Expressions *elements = new Expressions(); elements->setDim(newlen); size_t copylen = oldlen < newlen ? oldlen : newlen; + if (oldlen !=0) + assert(oldval->op == TOKarrayliteral); ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval; for (size_t i = 0; i < copylen; i++) - elements->data[i] = ae->elements->data[i]; - + elements->tdata()[i] = ae->elements->tdata()[i]; + if (elemType->ty == Tstruct || elemType->ty == Tsarray) + { /* If it is an aggregate literal representing a value type, + * we need to create a unique copy for each element + */ + for (size_t i = copylen; i < newlen; i++) + elements->tdata()[i] = copyLiteral(defaultElem); + } + else + { for (size_t i = copylen; i < newlen; i++) - elements->data[i] = defaultElem; + elements->tdata()[i] = defaultElem; + } ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements); aae->type = t; newval = aae; + // We have changed it into a reference assignment + // Note that returnValue is still the new length. + wantRef = true; + if (e1->op == TOKstar) + { // arr.length+=n becomes (t=&arr, *(t).length=*(t).length+n); + e1 = e1->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e1)) + return e1; + } } else { @@ -2234,17 +3540,24 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) } } - else if (e1->op != TOKslice) + else if (!wantRef && e1->op != TOKslice) { /* Look for special case of struct being initialized with 0. */ if (type->toBasetype()->ty == Tstruct && newval->op == TOKint64) { newval = type->defaultInitLiteral(loc); + if (newval->op != TOKstructliteral) + { + error("nested structs with constructors are not yet supported in CTFE (Bug 6419)"); + return EXP_CANT_INTERPRET; } - newval = Cast(type, type, newval); - e = newval; } - if (newval == EXP_CANT_INTERPRET) + newval = ctfeCast(loc, type, type, newval); + if (exceptionOrCantInterpret(newval)) + return newval; + returnValue = newval; + } + if (exceptionOrCantInterpret(newval)) return newval; // ------------------------------------------------- @@ -2260,88 +3573,178 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) } // This happens inside compiler-generated foreach statements. - if (op==TOKconstruct && this->e1->op==TOKvar + if (op==TOKconstruct && this->e1->op==TOKvar && + this->e2->op == TOKindex && ((VarExp*)this->e1)->var->storage_class & STCref) { - //error("assignment to ref variable %s is not yet supported in CTFE", this->toChars()); VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration(); - v->value = e2; +#if (LOGASSIGN) + printf("FOREACH ASSIGN %s=%s\n", v->toChars(), e2->toChars()); +#endif + v->setValueNull(); + v->createStackValue(e2); return e2; } + bool destinationIsReference = false; e1 = resolveReferences(e1, istate->localThis, &destinationIsReference); // Unless we have a simple var assignment, we're // only modifying part of the variable. So we need to make sure // that the parent variable exists. - if (e1->op != TOKvar && ultimateVar && !ultimateVar->value) - ultimateVar->value = ultimateVar->type->defaultInitLiteral(); + if (e1->op != TOKvar && ultimateVar && !ultimateVar->getValue()) + ultimateVar->createRefValue(copyLiteral(ultimateVar->type->defaultInitLiteral())); - // ---------------------------------------- - // Deal with dotvar expressions - // ---------------------------------------- - // Because structs are not reference types, dotvar expressions can be - // collapsed into a single assignment. - bool startedWithCall = false; - if (e1->op == TOKcall) startedWithCall = true; - while (e1->op == TOKdotvar || e1->op == TOKcall) - { - ExpressionReverseIterator rvs(e1, istate->localThis); - Expression *lastNonDotVar = e1; - // Strip of all of the leading dotvars. - if (e1->op == TOKdotvar) - { - int numDotVars = 0; - while(lastNonDotVar->op == TOKdotvar) + // --------------------------------------- + // Deal with reference assignment + // (We already have 'newval' for arraylength operations) + // --------------------------------------- + if (wantRef && !fp && this->e1->op != TOKarraylength) { - ++numDotVars; - if (lastNonDotVar->op == TOKdotvar) - lastNonDotVar = ((DotVarExp *)lastNonDotVar)->e1; - lastNonDotVar = resolveReferences(lastNonDotVar, istate->localThis); - assert(lastNonDotVar); + newval = this->e2->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(newval)) + return newval; + // If it is an assignment from a array function parameter passed by + // reference, resolve the reference. (This should NOT happen for + // non-reference types). + if (newval->op == TOKvar && (newval->type->ty == Tarray || + newval->type->ty == Tclass)) + { + newval = newval->interpret(istate); } - // We need the value of this first nonvar, since only part of it will be - // modified. - Expression * existing = lastNonDotVar->interpret(istate); - if (existing == EXP_CANT_INTERPRET) - return existing; - assert(newval !=EXP_CANT_INTERPRET); - newval = assignDotVar(rvs, numDotVars, existing, newval); - e1 = lastNonDotVar; - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - v->value = newval; - return e; - } - assert(newval !=EXP_CANT_INTERPRET); - } // end tokdotvar - else + if (newval->op == TOKassocarrayliteral || newval->op == TOKstring || + newval->op==TOKarrayliteral) { - Expression * existing = lastNonDotVar->interpret(istate); - if (existing == EXP_CANT_INTERPRET) - return existing; - // It might be a reference. Turn it into an rvalue, by interpreting again. - existing = existing->interpret(istate); - if (existing == EXP_CANT_INTERPRET) - return existing; - assert(newval !=EXP_CANT_INTERPRET); - newval = assignDotVar(rvs, 0, existing, newval); - assert(newval !=EXP_CANT_INTERPRET); + if (needToCopyLiteral(this->e2)) + newval = copyLiteral(newval); } - if (e1->op == TOKcall) + returnValue = newval; + } + + // --------------------------------------- + // Deal with AA index assignment + // --------------------------------------- + /* This needs special treatment if the AA doesn't exist yet. + * There are two special cases: + * (1) If the AA is itself an index of another AA, we may need to create + * multiple nested AA literals before we can insert the new value. + * (2) If the ultimate AA is null, no insertion happens at all. Instead, we + * create nested AA literals, and change it into a assignment. + */ + if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) { - istate->awaitingLvalueReturn = true; - e1 = e1->interpret(istate); - istate->awaitingLvalueReturn = false; + IndexExp *ie = (IndexExp *)e1; + int depth = 0; // how many nested AA indices are there? + while (ie->e1->op == TOKindex && ((IndexExp *)ie->e1)->e1->type->toBasetype()->ty == Taarray) + { + ie = (IndexExp *)ie->e1; + ++depth; + } + Expression *aggregate = resolveReferences(ie->e1, istate->localThis); + Expression *oldagg = aggregate; + // Get the AA to be modified. (We do an LvalueRef interpret, unless it + // is a simple ref parameter -- in which case, we just want the value) + aggregate = aggregate->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(aggregate)) + return aggregate; + if (aggregate->op == TOKassocarrayliteral) + { // Normal case, ultimate parent AA already exists + // We need to walk from the deepest index up, checking that an AA literal + // already exists on each level. + Expression *index = ((IndexExp *)e1)->e2->interpret(istate); + if (exceptionOrCantInterpret(index)) + return index; + if (index->op == TOKslice) // only happens with AA assignment + index = resolveSlice(index); + AssocArrayLiteralExp *existingAA = (AssocArrayLiteralExp *)aggregate; + while (depth > 0) + { // Walk the syntax tree to find the indexExp at this depth + IndexExp *xe = (IndexExp *)e1; + for (int d= 0; d < depth; ++d) + xe = (IndexExp *)xe->e1; + + Expression *indx = xe->e2->interpret(istate); + if (exceptionOrCantInterpret(indx)) + return indx; + if (indx->op == TOKslice) // only happens with AA assignment + indx = resolveSlice(indx); + + // Look up this index in it up in the existing AA, to get the next level of AA. + AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(existingAA, indx); + if (exceptionOrCantInterpret(newAA)) + return newAA; + if (!newAA) + { // Doesn't exist yet, create an empty AA... + Expressions *valuesx = new Expressions(); + Expressions *keysx = new Expressions(); + newAA = new AssocArrayLiteralExp(loc, keysx, valuesx); + newAA->type = xe->type; + //... and insert it into the existing AA. + existingAA->keys->push(indx); + existingAA->values->push(newAA); + } + existingAA = newAA; + --depth; + } + if (assignAssocArrayElement(loc, existingAA, index, newval) == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + return returnValue; + } + else + { /* The AA is currently null. 'aggregate' is actually a reference to + * whatever contains it. It could be anything: var, dotvarexp, ... + * We rewrite the assignment from: aggregate[i][j] = newval; + * into: aggregate = [i:[j: newval]]; + */ + while (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) + { + Expression *index = ((IndexExp *)e1)->e2->interpret(istate); + if (exceptionOrCantInterpret(index)) + return index; + if (index->op == TOKslice) // only happens with AA assignment + index = resolveSlice(index); + Expressions *valuesx = new Expressions(); + Expressions *keysx = new Expressions(); + valuesx->push(newval); + keysx->push(index); + newval = new AssocArrayLiteralExp(loc, keysx, valuesx); + newval->type = e1->type; + e1 = ((IndexExp *)e1)->e1; + } + // We must return to the original aggregate, in case it was a reference + wantRef = true; + e1 = oldagg; + // fall through -- let the normal assignment logic take care of it + } + } - if (e1==EXP_CANT_INTERPRET) return e1; - assert(newval); - assert(newval !=EXP_CANT_INTERPRET); + // --------------------------------------- + // Deal with dotvar expressions + // --------------------------------------- + // Because structs are not reference types, dotvar expressions can be + // collapsed into a single assignment. + if (!wantRef && e1->op == TOKdotvar) + { + // Strip of all of the leading dotvars, unless we started with a call + // (in which case, we already have the lvalue). + if (this->e1->op != TOKcall) + e1 = e1->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e1)) + return e1; + if (e1->op == TOKstructliteral && newval->op == TOKstructliteral) + { + assignInPlace(e1, newval); + return returnValue; } } +#if LOGASSIGN + if (wantRef) + printf("REF ASSIGN: %s=%s\n", e1->toChars(), newval->toChars()); + else + printf("ASSIGN: %s=%s\n", e1->toChars(), newval->toChars()); + showCtfeExpr(newval); +#endif /* Assignment to variable of the form: * v = newval @@ -2350,244 +3753,501 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) { VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); - if (!destinationIsReference) - addVarToInterstate(istate, v); - v->value = newval; + if (wantRef) + { + v->setValueNull(); + v->createRefValue(newval); } - else if (e1->op == TOKindex) + else if (e1->type->toBasetype()->ty == Tstruct) { - Expression *aggregate = resolveReferences(((IndexExp *)e1)->e1, istate->localThis); - /* Assignment to array element of the form: - * aggregate[i] = newval - */ - if (aggregate->op == TOKvar) - { IndexExp *ie = (IndexExp *)e1; - VarExp *ve = (VarExp *)aggregate; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v->value->op == TOKnull) + // In-place modification + if (newval->op != TOKstructliteral) { - if (v->type->ty == Taarray) - { // Assign to empty associative array - Expressions *valuesx = new Expressions(); - Expressions *keysx = new Expressions(); - Expression *index = ie->e2->interpret(istate); - if (index == EXP_CANT_INTERPRET) + error("CTFE internal error assigning struct"); return EXP_CANT_INTERPRET; - valuesx->push(newval); - keysx->push(index); - Expression *aae2 = new AssocArrayLiteralExp(loc, keysx, valuesx); - aae2->type = v->type; - newval = aae2; - v->value = newval; - return e; } - // This would be a runtime segfault - error("Cannot index null array %s", v->toChars()); - return EXP_CANT_INTERPRET; + newval = copyLiteral(newval); + if (v->getValue()) + assignInPlace(v->getValue(), newval); + else + v->createRefValue(newval); } - else if (v->value->op != TOKarrayliteral - && v->value->op != TOKassocarrayliteral - && v->value->op != TOKstring) + else { - error("CTFE internal compiler error"); - return EXP_CANT_INTERPRET; - } - // Set the $ variable - Expression *dollar = ArrayLength(Type::tsize_t, v->value); - if (dollar != EXP_CANT_INTERPRET && ie->lengthVar) - ie->lengthVar->value = dollar; - // Determine the index, and check that it's OK. - Expression *index = ie->e2->interpret(istate); - if (index == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - newval = assignArrayElement(loc, v->value, index, newval); - if (newval == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - v->value = newval; - return e; + TY tyE1 = e1->type->toBasetype()->ty; + if (tyE1 == Tarray || tyE1 == Taarray) + { // arr op= arr + if (!v->getValue()) + v->createRefValue(newval); + else v->setRefValue(newval); } else - error("Index assignment %s is not yet supported in CTFE ", toChars()); + { + if (!v->getValue()) // creating a new value + v->createStackValue(newval); + else + v->setStackValue(newval); + } + } + } + else if (e1->op == TOKdotvar) + { + /* Assignment to member variable of the form: + * e.v = newval + */ + Expression *exx = ((DotVarExp *)e1)->e1; + if (wantRef && exx->op != TOKstructliteral) + { + exx = exx->interpret(istate); + if (exceptionOrCantInterpret(exx)) + return exx; + } + if (exx->op != TOKstructliteral && exx->op != TOKclassreference) + { + error("CTFE internal error: Dotvar assignment"); + return EXP_CANT_INTERPRET; + } + VarDeclaration *member = ((DotVarExp *)e1)->var->isVarDeclaration(); + if (!member) + { + error("CTFE internal error: Dotvar assignment"); + return EXP_CANT_INTERPRET; + } + StructLiteralExp *se = exx->op == TOKstructliteral + ? (StructLiteralExp *)exx + : ((ClassReferenceExp *)exx)->value; + int fieldi = exx->op == TOKstructliteral + ? se->getFieldIndex(member->type, member->offset) + : ((ClassReferenceExp *)exx)->getFieldIndex(member->type, member->offset); + if (fieldi == -1) + { + error("CTFE internal error: cannot find field %s in %s", member->toChars(), exx->toChars()); + return EXP_CANT_INTERPRET; + } + assert(fieldi>=0 && fieldi < se->elements->dim); + if (newval->op == TOKstructliteral) + assignInPlace(se->elements->tdata()[fieldi], newval); + else + se->elements->tdata()[fieldi] = newval; + return returnValue; + } + else if (e1->op == TOKindex) + { + /* Assignment to array element of the form: + * aggregate[i] = newval + * aggregate is not AA (AAs were dealt with already). + */ + IndexExp *ie = (IndexExp *)e1; + assert(ie->e1->type->toBasetype()->ty != Taarray); + uinteger_t destarraylen = 0; + + // Set the $ variable, and find the array literal to modify + if (ie->e1->type->toBasetype()->ty != Tpointer) + { + Expression *oldval = ie->e1->interpret(istate); + if (oldval->op == TOKnull) + { + error("cannot index null array %s", ie->e1->toChars()); + return EXP_CANT_INTERPRET; + } + if (oldval->op != TOKarrayliteral && oldval->op != TOKstring + && oldval->op != TOKslice) + { + error("cannot determine length of %s at compile time", + ie->e1->toChars()); + return EXP_CANT_INTERPRET; + } + destarraylen = resolveArrayLength(oldval); + if (ie->lengthVar) + { + IntegerExp *dollarExp = new IntegerExp(loc, destarraylen, Type::tsize_t); + ctfeStack.push(ie->lengthVar); + ie->lengthVar->createStackValue(dollarExp); + } + } + Expression *index = ie->e2->interpret(istate); + if (ie->lengthVar) + ctfeStack.pop(ie->lengthVar); // $ is defined only inside [] + if (exceptionOrCantInterpret(index)) + return index; + + assert (index->op != TOKslice); // only happens with AA assignment + + ArrayLiteralExp *existingAE = NULL; + StringExp *existingSE = NULL; + + Expression *aggregate = resolveReferences(ie->e1, istate->localThis); + + // Set the index to modify, and check that it is in range + dinteger_t indexToModify = index->toInteger(); + if (ie->e1->type->toBasetype()->ty == Tpointer) + { + dinteger_t ofs; + aggregate = aggregate->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(aggregate)) + return aggregate; + if (aggregate->op == TOKnull) + { + error("cannot index through null pointer %s", ie->e1->toChars()); + return EXP_CANT_INTERPRET; + } + if (aggregate->op == TOKint64) + { + error("cannot index through invalid pointer %s of value %s", + ie->e1->toChars(), aggregate->toChars()); + return EXP_CANT_INTERPRET; + } + aggregate = getAggregateFromPointer(aggregate, &ofs); + indexToModify += ofs; + destarraylen = resolveArrayLength(aggregate); + } + if (indexToModify >= destarraylen) + { + error("array index %d is out of bounds [0..%d]", indexToModify, + destarraylen); + return EXP_CANT_INTERPRET; + } + + /* The only possible indexable LValue aggregates are array literals, and + * slices of array literals. + */ + if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || + aggregate->op == TOKslice || aggregate->op == TOKcall || + aggregate->op == TOKstar) + { + Expression *origagg = aggregate; + aggregate = aggregate->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(aggregate)) + return aggregate; + // The array could be an index of an AA. Resolve it if so. + if (aggregate->op == TOKindex) + { + IndexExp *ix = (IndexExp *)aggregate; + aggregate = Index(ix->type, ix->e1, ix->e2); + } + } + if (aggregate->op == TOKvar) + { + VarExp *ve = (VarExp *)aggregate; + VarDeclaration *v = ve->var->isVarDeclaration(); + aggregate = v->getValue(); + if (aggregate->op == TOKnull) + { + // This would be a runtime segfault + error("cannot index null array %s", v->toChars()); + return EXP_CANT_INTERPRET; + } + } + if (aggregate->op == TOKslice) + { + SliceExp *sexp = (SliceExp *)aggregate; + aggregate = sexp->e1; + Expression *lwr = sexp->lwr->interpret(istate); + indexToModify += lwr->toInteger(); + } + if (aggregate->op == TOKarrayliteral) + existingAE = (ArrayLiteralExp *)aggregate; + else if (aggregate->op == TOKstring) + existingSE = (StringExp *)aggregate; + else + { + error("CTFE internal compiler error %s", aggregate->toChars()); + return EXP_CANT_INTERPRET; + } + if (!wantRef && newval->op == TOKslice) + { + newval = resolveSlice(newval); + if (newval == EXP_CANT_INTERPRET) + { + error("Compiler error: CTFE index assign %s", toChars()); + assert(0); + } + } + if (wantRef && newval->op == TOKindex + && ((IndexExp *)newval)->e1 == aggregate) + { // It's a circular reference, resolve it now + newval = newval->interpret(istate); + } + if (existingAE) + { + if (newval->op == TOKstructliteral) + assignInPlace((Expression *)(existingAE->elements->tdata()[indexToModify]), newval); + else + existingAE->elements->tdata()[indexToModify] = newval; + return returnValue; + } + if (existingSE) + { + unsigned char *s = (unsigned char *)existingSE->string; + unsigned value = newval->toInteger(); + switch (existingSE->sz) + { + case 1: s[indexToModify] = value; break; + case 2: ((unsigned short *)s)[indexToModify] = value; break; + case 4: ((unsigned *)s)[indexToModify] = value; break; + default: + assert(0); + break; + } + return returnValue; + } + else + { + error("Index assignment %s is not yet supported in CTFE ", toChars()); + return EXP_CANT_INTERPRET; + } + return returnValue; } else if (e1->op == TOKslice) { - Expression *aggregate = resolveReferences(((SliceExp *)e1)->e1, istate->localThis); // ------------------------------ // aggregate[] = newval // aggregate[low..upp] = newval // ------------------------------ - /* Slice assignment, initialization of static arrays - * a[] = e - */ - if (aggregate->op==TOKvar) - { SliceExp * sexp = (SliceExp *)e1; - VarExp *ve = (VarExp *)(aggregate); - VarDeclaration *v = ve->var->isVarDeclaration(); - /* Set the $ variable - */ - Expression *ee = v->value ? ArrayLength(Type::tsize_t, v->value) - : EXP_CANT_INTERPRET; - if (ee != EXP_CANT_INTERPRET && sexp->lengthVar) - sexp->lengthVar->value = ee; + // Set the $ variable + Expression *oldval = sexp->e1; + bool assignmentToSlicedPointer = false; + if (oldval->type->toBasetype()->ty == Tpointer && oldval->type->toBasetype()->nextOf()->ty != Tfunction) + { // Slicing a pointer + oldval = oldval->interpret(istate, ctfeNeedLvalue); + dinteger_t ofs; + oldval = getAggregateFromPointer(oldval, &ofs); + assignmentToSlicedPointer = true; + } else + oldval = oldval->interpret(istate); + + if (oldval->op != TOKarrayliteral && oldval->op != TOKstring + && oldval->op != TOKslice && oldval->op != TOKnull) + { + error("CTFE ICE: cannot resolve array length"); + return EXP_CANT_INTERPRET; + } + uinteger_t dollar = resolveArrayLength(oldval); + if (sexp->lengthVar) + { + Expression *arraylen = new IntegerExp(loc, dollar, Type::tsize_t); + ctfeStack.push(sexp->lengthVar); + sexp->lengthVar->createStackValue(arraylen); + } + Expression *upper = NULL; Expression *lower = NULL; if (sexp->upr) - { upper = sexp->upr->interpret(istate); - if (upper == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; + if (exceptionOrCantInterpret(upper)) + { + if (sexp->lengthVar) + ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] + return upper; } if (sexp->lwr) - { lower = sexp->lwr->interpret(istate); - if (lower == EXP_CANT_INTERPRET) + if (sexp->lengthVar) + ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] + if (exceptionOrCantInterpret(lower)) + return lower; + + size_t dim = dollar; + size_t upperbound = upper ? upper->toInteger() : dim; + int lowerbound = lower ? lower->toInteger() : 0; + + if (!assignmentToSlicedPointer && (((int)lowerbound < 0) || (upperbound > dim))) + { + error("Array bounds [0..%d] exceeded in slice [%d..%d]", + dim, lowerbound, upperbound); return EXP_CANT_INTERPRET; } - Type *t = v->type->toBasetype(); - size_t dim; - if (t->ty == Tsarray) - dim = ((TypeSArray *)t)->dim->toInteger(); - else if (t->ty == Tarray) + if (upperbound == lowerbound) + return newval; + + Expression *aggregate = resolveReferences(((SliceExp *)e1)->e1, istate->localThis); + dinteger_t firstIndex = lowerbound; + + ArrayLiteralExp *existingAE = NULL; + StringExp *existingSE = NULL; + + /* The only possible slicable LValue aggregates are array literals, + * and slices of array literals. + */ + + if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || + aggregate->op == TOKslice || + aggregate->op == TOKstar || aggregate->op == TOKcall) { - if (!v->value || v->value->op == TOKnull) + aggregate = aggregate->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(aggregate)) + return aggregate; + // The array could be an index of an AA. Resolve it if so. + if (aggregate->op == TOKindex) + { + IndexExp *ie = (IndexExp *)aggregate; + aggregate = Index(ie->type, ie->e1, ie->e2); + } + } + if (aggregate->op == TOKvar) { - error("cannot assign to null array %s", v->toChars()); + VarExp *ve = (VarExp *)(aggregate); + VarDeclaration *v = ve->var->isVarDeclaration(); + aggregate = v->getValue(); + } + if (aggregate->op == TOKslice) + { // Slice of a slice --> change the bounds + SliceExp *sexpold = (SliceExp *)aggregate; + dinteger_t hi = upperbound + sexpold->lwr->toInteger(); + firstIndex = lowerbound + sexpold->lwr->toInteger(); + if (hi > sexpold->upr->toInteger()) + { + error("slice [%d..%d] exceeds array bounds [0..%jd]", + lowerbound, upperbound, + sexpold->upr->toInteger() - sexpold->lwr->toInteger()); return EXP_CANT_INTERPRET; } - if (v->value->op == TOKarrayliteral) - dim = ((ArrayLiteralExp *)v->value)->elements->dim; - else if (v->value->op ==TOKstring) - dim = ((StringExp *)v->value)->len; + aggregate = sexpold->e1; } - else + if (aggregate->type->toBasetype()->ty == Tpointer && aggregate->type->toBasetype()->nextOf()->ty != Tfunction) + { // Slicing a pointer --> change the bounds + aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue); + dinteger_t ofs; + aggregate = getAggregateFromPointer(aggregate, &ofs); + dinteger_t hi = upperbound + ofs; + firstIndex = lowerbound + ofs; + if (firstIndex < 0 || hi > dim) { - error("%s cannot be evaluated at compile time", toChars()); + error("slice [%d..%jd] exceeds memory block bounds [0..%jd]", + firstIndex, hi, dim); return EXP_CANT_INTERPRET; } - int upperbound = upper ? upper->toInteger() : dim; - int lowerbound = lower ? lower->toInteger() : 0; + } + if (aggregate->op==TOKarrayliteral) + existingAE = (ArrayLiteralExp *)aggregate; + else if (aggregate->op==TOKstring) + existingSE = (StringExp *)aggregate; - if (((int)lowerbound < 0) || (upperbound > dim)) + if (!wantRef && newval->op == TOKslice) { - error("Array bounds [0..%d] exceeded in slice [%d..%d]", - dim, lowerbound, upperbound); - return EXP_CANT_INTERPRET; + newval = resolveSlice(newval); + if (newval == EXP_CANT_INTERPRET) + { + error("Compiler error: CTFE slice %s", toChars()); + assert(0); } - // Could either be slice assignment (v[] = e[]), - // or block assignment (v[] = val). - // For the former, we check that the lengths match. - bool isSliceAssignment = (newval->op == TOKarrayliteral) - || (newval->op == TOKstring); + } + if (wantRef && newval->op == TOKindex + && ((IndexExp *)newval)->e1 == aggregate) + { // It's a circular reference, resolve it now + newval = newval->interpret(istate); + } + + // For slice assignment, we check that the lengths match. size_t srclen = 0; if (newval->op == TOKarrayliteral) srclen = ((ArrayLiteralExp *)newval)->elements->dim; else if (newval->op == TOKstring) srclen = ((StringExp *)newval)->len; - if (isSliceAssignment && srclen != (upperbound - lowerbound)) + if (!isBlockAssignment && srclen != (upperbound - lowerbound)) { error("Array length mismatch assigning [0..%d] to [%d..%d]", srclen, lowerbound, upperbound); - return e; + return EXP_CANT_INTERPRET; } - if (newval->op == TOKarrayliteral) + + if (!isBlockAssignment && newval->op == TOKarrayliteral && existingAE) { - // Static array assignment from literal - if (upperbound - lowerbound != dim) + Expressions *oldelems = existingAE->elements; + Expressions *newelems = ((ArrayLiteralExp *)newval)->elements; + for (size_t j = 0; j < newelems->dim; j++) { - ArrayLiteralExp *ae = (ArrayLiteralExp *)newval; - ArrayLiteralExp *existing = (ArrayLiteralExp *)v->value; - // value[] = value[0..lower] ~ ae ~ value[upper..$] - existing->elements = spliceElements(existing->elements, ae->elements, lowerbound); - newval = existing; - } - v->value = newval; - return newval; - } - else if (newval->op == TOKstring) - { - StringExp *se = (StringExp *)newval; - if (upperbound-lowerbound == dim) - v->value = newval; - else - { - if (!v->value) - v->value = createBlockDuplicatedStringLiteral(se->type, - se->type->defaultInit()->toInteger(), dim, se->sz); - if (v->value->op==TOKstring) - v->value = spliceStringExp((StringExp *)v->value, se, lowerbound); - else - error("String slice assignment is not yet supported in CTFE"); + oldelems->tdata()[j + firstIndex] = newelems->tdata()[j]; } return newval; } - else if (t->nextOf()->ty == newval->type->ty) + else if (newval->op == TOKstring && existingSE) { - // Static array block assignment - e = createBlockDuplicatedArrayLiteral(v->type, newval, upperbound-lowerbound); - - if (upperbound - lowerbound == dim) - newval = e; - else - { - ArrayLiteralExp * newarrayval; - // Only modifying part of the array. Must create a new array literal. - // If the existing array is uninitialized (this can only happen - // with static arrays), create it. - if (v->value && v->value->op == TOKarrayliteral) - newarrayval = (ArrayLiteralExp *)v->value; - else // this can only happen with static arrays - newarrayval = createBlockDuplicatedArrayLiteral(v->type, v->type->defaultInit(), dim); - // value[] = value[0..lower] ~ e ~ value[upper..$] - newarrayval->elements = spliceElements(newarrayval->elements, - ((ArrayLiteralExp *)e)->elements, lowerbound); - newval = newarrayval; + sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, firstIndex); + return newval; + } + else if (newval->op == TOKstring && existingAE + && existingAE->type->isString()) + { /* Mixed slice: it was initialized as an array literal of chars. + * Now a slice of it is being set with a string. + */ + sliceAssignArrayLiteralFromString(existingAE, (StringExp *)newval, firstIndex); + return newval; } - v->value = newval; - return e; + else if (newval->op == TOKarrayliteral && existingSE) + { /* Mixed slice: it was initialized as a string literal. + * Now a slice of it is being set with an array literal. + */ + sliceAssignStringFromArrayLiteral(existingSE, (ArrayLiteralExp *)newval, firstIndex); + return newval; } - else + else if (existingSE) + { // String literal block slice assign + unsigned value = newval->toInteger(); + unsigned char *s = (unsigned char *)existingSE->string; + for (size_t j = 0; j < upperbound-lowerbound; j++) { - error("Slice operation %s cannot be evaluated at compile time", toChars()); - return e; + switch (existingSE->sz) + { + case 1: s[j+firstIndex] = value; break; + case 2: ((unsigned short *)s)[j+firstIndex] = value; break; + case 4: ((unsigned *)s)[j+firstIndex] = value; break; + default: + assert(0); + break; } } - else - error("Slice operation %s cannot be evaluated at compile time", toChars()); + if (goal == ctfeNeedNothing) + return NULL; // avoid creating an unused literal + SliceExp *retslice = new SliceExp(loc, existingSE, + new IntegerExp(loc, firstIndex, Type::tsize_t), + new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); + retslice->type = this->type; + return retslice->interpret(istate); } - else if (e1->op == TOKstar) + else if (existingAE) { - /* Assignment to struct member of the form: - * *(symoffexp) = newval + /* Block assignment, initialization of static arrays + * x[] = e + * x may be a multidimensional static array. (Note that this + * only happens with array literals, never with strings). */ - if (((PtrExp *)e1)->e1->op == TOKsymoff) - { SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1; - VarDeclaration *v = soe->var->isVarDeclaration(); - if (v->isDataseg() && !v->isCTFE()) + Expressions * w = existingAE->elements; + assert( existingAE->type->ty == Tsarray || + existingAE->type->ty == Tarray); +#if DMDV2 + Type *desttype = ((TypeArray *)existingAE->type)->next->castMod(0); + bool directblk = (e2->type->toBasetype()->castMod(0)) == desttype; +#else + Type *desttype = ((TypeArray *)existingAE->type)->next; + bool directblk = (e2->type->toBasetype()) == desttype; +#endif + bool cow = !(newval->op == TOKstructliteral || newval->op == TOKarrayliteral + || newval->op == TOKstring); + for (size_t j = 0; j < upperbound-lowerbound; j++) { - error("%s cannot be modified at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - if (fp && !v->value) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - Expression *vie = v->value; - if (vie->op == TOKvar) + if (!directblk) + // Multidimensional array block assign + recursiveBlockAssign((ArrayLiteralExp *)w->tdata()[j+firstIndex], newval, wantRef); + else { - Declaration *d = ((VarExp *)vie)->var; - vie = getVarExp(e1->loc, istate, d); + if (wantRef || cow) + existingAE->elements->tdata()[j+firstIndex] = newval; + else + assignInPlace(existingAE->elements->tdata()[j+firstIndex], newval); } - if (vie->op != TOKstructliteral) - return EXP_CANT_INTERPRET; - - StructLiteralExp *se = (StructLiteralExp *)vie; - - newval = modifyStructField(type, se, soe->offset, newval); - - addVarToInterstate(istate, v); - v->value = newval; } + if (goal == ctfeNeedNothing) + return NULL; // avoid creating an unused literal + SliceExp *retslice = new SliceExp(loc, existingAE, + new IntegerExp(loc, firstIndex, Type::tsize_t), + new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); + retslice->type = this->type; + return retslice->interpret(istate); + } + else + error("Slice operation %s cannot be evaluated at compile time", toChars()); } else { @@ -2596,18 +4256,18 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) dump(0); #endif } - return e; + return returnValue; } -Expression *AssignExp::interpret(InterState *istate) +Expression *AssignExp::interpret(InterState *istate, CtfeGoal goal) { - return interpretAssignCommon(istate, NULL); + return interpretAssignCommon(istate, goal, NULL); } #define BIN_ASSIGN_INTERPRET(op) \ -Expression *op##AssignExp::interpret(InterState *istate) \ +Expression *op##AssignExp::interpret(InterState *istate, CtfeGoal goal) \ { \ - return interpretAssignCommon(istate, &op); \ + return interpretAssignCommon(istate, goal, &op); \ } BIN_ASSIGN_INTERPRET(Add) @@ -2622,17 +4282,20 @@ BIN_ASSIGN_INTERPRET(Ushr) BIN_ASSIGN_INTERPRET(And) BIN_ASSIGN_INTERPRET(Or) BIN_ASSIGN_INTERPRET(Xor) +#if DMDV2 +BIN_ASSIGN_INTERPRET(Pow) +#endif -Expression *PostExp::interpret(InterState *istate) +Expression *PostExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("PostExp::interpret() %s\n", toChars()); #endif Expression *e; if (op == TOKplusplus) - e = interpretAssignCommon(istate, &Add, 1); + e = interpretAssignCommon(istate, goal, &Add, 1); else - e = interpretAssignCommon(istate, &Min, 1); + e = interpretAssignCommon(istate, goal, &Min, 1); #if LOG if (e == EXP_CANT_INTERPRET) printf("PostExp::interpret() CANT\n"); @@ -2640,66 +4303,142 @@ Expression *PostExp::interpret(InterState *istate) return e; } -Expression *AndAndExp::interpret(InterState *istate) +Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("AndAndExp::interpret() %s\n", toChars()); #endif Expression *e = e1->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; + + int result; if (e != EXP_CANT_INTERPRET) { if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) + result = 0; + else if (isTrueBool(e)) { e = e2->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; if (e != EXP_CANT_INTERPRET) { if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); + result = 0; + else if (isTrueBool(e)) + result = 1; else + { + error("%s does not evaluate to a boolean", e->toChars()); e = EXP_CANT_INTERPRET; } } + } else + { + error("%s cannot be interpreted as a boolean", e->toChars()); e = EXP_CANT_INTERPRET; } + } + if (e != EXP_CANT_INTERPRET && goal != ctfeNeedNothing) + e = new IntegerExp(loc, result, type); return e; } -Expression *OrOrExp::interpret(InterState *istate) +Expression *OrOrExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("OrOrExp::interpret() %s\n", toChars()); #endif Expression *e = e1->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; + + int result; if (e != EXP_CANT_INTERPRET) { - if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); + if (isTrueBool(e)) + result = 1; else if (e->isBool(FALSE)) { e = e2->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; + if (e != EXP_CANT_INTERPRET) { if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); + result = 0; + else if (isTrueBool(e)) + result = 1; else + { + error("%s cannot be interpreted as a boolean", e->toChars()); e = EXP_CANT_INTERPRET; } } + } else + { + error("%s cannot be interpreted as a boolean", e->toChars()); e = EXP_CANT_INTERPRET; } + } + if (e != EXP_CANT_INTERPRET && goal != ctfeNeedNothing) + e = new IntegerExp(loc, result, type); return e; } +// Print a stack trace, starting from callingExp which called fd. +// To shorten the stack trace, try to detect recursion. +void showCtfeBackTrace(InterState *istate, CallExp * callingExp, FuncDeclaration *fd) +{ + if (CtfeStatus::stackTraceCallsToSuppress > 0) + { + --CtfeStatus::stackTraceCallsToSuppress; + return; + } + fprintf(stdmsg, "%s: called from here: %s\n", callingExp->loc.toChars(), callingExp->toChars()); + // Quit if it's not worth trying to compress the stack trace + if (CtfeStatus::callDepth < 6 || global.params.verbose) + return; + // Recursion happens if the current function already exists in the call stack. + int numToSuppress = 0; + int recurseCount = 0; + int depthSoFar = 0; + InterState *lastRecurse = istate; + for (InterState * cur = istate; cur; cur = cur->caller) + { + if (cur->fd == fd) + { ++recurseCount; + numToSuppress = depthSoFar; + lastRecurse = cur; + } + ++depthSoFar; + } + // We need at least three calls to the same function, to make compression worthwhile + if (recurseCount < 2) + return; + // We found a useful recursion. Print all the calls involved in the recursion + fprintf(stdmsg, "%s: %d recursive calls to function %s\n", fd->loc.toChars(), recurseCount, fd->toChars()); + for (InterState *cur = istate; cur->fd != fd; cur = cur->caller) + { + fprintf(stdmsg, "%s: recursively called from function %s\n", cur->fd->loc.toChars(), cur->fd->toChars()); + } + // We probably didn't enter the recursion in this function. + // Go deeper to find the real beginning. + InterState * cur = istate; + while (lastRecurse->caller && cur->fd == lastRecurse->caller->fd) + { + cur = cur->caller; + lastRecurse = lastRecurse->caller; + ++numToSuppress; + } + CtfeStatus::stackTraceCallsToSuppress = numToSuppress; +} -Expression *CallExp::interpret(InterState *istate) +Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e = EXP_CANT_INTERPRET; #if LOG @@ -2712,7 +4451,7 @@ Expression *CallExp::interpret(InterState *istate) if (ecall->op == TOKcall) { ecall = e1->interpret(istate); - if (ecall == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(ecall)) return ecall; } if (ecall->op == TOKstar) @@ -2720,34 +4459,36 @@ Expression *CallExp::interpret(InterState *istate) Expression * pe = ((PtrExp*)ecall)->e1; if (pe->op == TOKvar) { VarDeclaration *vd = ((VarExp *)((PtrExp*)ecall)->e1)->var->isVarDeclaration(); - if (vd && vd->value && vd->value->op == TOKsymoff) - fd = ((SymOffExp *)vd->value)->var->isFuncDeclaration(); + if (vd && vd->getValue() && vd->getValue()->op == TOKsymoff) + fd = ((SymOffExp *)vd->getValue())->var->isFuncDeclaration(); else { - ecall = getVarExp(loc, istate, vd); - if (ecall == EXP_CANT_INTERPRET) + ecall = getVarExp(loc, istate, vd, goal); + if (exceptionOrCantInterpret(ecall)) return ecall; if (ecall->op == TOKsymoff) fd = ((SymOffExp *)ecall)->var->isFuncDeclaration(); } } + else if (pe->op == TOKsymoff) + fd = ((SymOffExp *)pe)->var->isFuncDeclaration(); else ecall = ((PtrExp*)ecall)->e1->interpret(istate); } - if (ecall == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(ecall)) return ecall; if (ecall->op == TOKindex) { ecall = e1->interpret(istate); - if (ecall == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(ecall)) return ecall; } if (ecall->op == TOKdotvar && !((DotVarExp*)ecall)->var->isFuncDeclaration()) { ecall = e1->interpret(istate); - if (ecall == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(ecall)) return ecall; } @@ -2759,8 +4500,8 @@ Expression *CallExp::interpret(InterState *istate) else if (ecall->op == TOKvar) { VarDeclaration *vd = ((VarExp *)ecall)->var->isVarDeclaration(); - if (vd && vd->value) - ecall = vd->value; + if (vd && vd->getValue()) + ecall = vd->getValue(); else // Calling a function fd = ((VarExp *)e1)->var->isFuncDeclaration(); } @@ -2780,99 +4521,107 @@ Expression *CallExp::interpret(InterState *istate) TypeFunction *tf = fd ? (TypeFunction *)(fd->type) : NULL; if (!tf) - { // DAC: I'm not sure if this ever happens + { // DAC: This should never happen, it's an internal compiler error. //printf("ecall=%s %d %d\n", ecall->toChars(), ecall->op, TOKcall); + if (ecall->op == TOKidentifier) + error("cannot evaluate %s at compile time. Circular reference?", toChars()); + else + error("CTFE internal error: cannot evaluate %s at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + if (!fd) + { error("cannot evaluate %s at compile time", toChars()); return EXP_CANT_INTERPRET; } - if (pthis && fd) + if (pthis) { // Member function call if (pthis->op == TOKthis) pthis = istate ? istate->localThis : NULL; - else if (pthis->op == TOKcomma) + else + { + if (pthis->op == TOKcomma) pthis = pthis->interpret(istate); + if (exceptionOrCantInterpret(pthis)) + return pthis; + // Evaluate 'this' + Expression *oldpthis = pthis; + if (pthis->op != TOKvar) + pthis = pthis->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(pthis)) + return pthis; + if (fd->isVirtual()) + { // Make a virtual function call. + Expression *thisval = pthis; + if (pthis->op == TOKvar) + { assert(((VarExp*)thisval)->var->isVarDeclaration()); + thisval = ((VarExp*)thisval)->var->isVarDeclaration()->getValue(); + } + // Get the function from the vtable of the original class + ClassDeclaration *cd; + if (thisval && thisval->op == TOKnull) + { + error("function call through null class reference %s", pthis->toChars()); + return EXP_CANT_INTERPRET; + } + if (oldpthis->op == TOKsuper) + { assert(oldpthis->type->ty == Tclass); + cd = ((TypeClass *)oldpthis->type)->sym; + } + else + { + assert(thisval && thisval->op == TOKclassreference); + cd = ((ClassReferenceExp *)thisval)->originalClass(); + } + // We can't just use the vtable index to look it up, because + // vtables for interfaces don't get populated until the glue layer. + fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type); + + assert(fd); + } + } + } + // Check for built-in functions + Expression *eresult = evaluateIfBuiltin(istate, loc, fd, arguments, pthis); + if (eresult) + return eresult; + + // Inline .dup. Special case because it needs the return type. + if (!pthis && fd->ident == Id::adDup && arguments && arguments->dim == 2) + { + e = arguments->tdata()[1]; + e = e->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; + if (e != EXP_CANT_INTERPRET) + { + if (e->op == TOKslice) + e= resolveSlice(e); + e = expType(type, e); + e = copyLiteral(e); + } + return e; + } if (!fd->fbody) { error("%s cannot be interpreted at compile time," " because it has no available source code", fd->toChars()); return EXP_CANT_INTERPRET; } - Expression *eresult = fd->interpret(istate, arguments, pthis); + eresult = fd->interpret(istate, arguments, pthis); if (eresult) e = eresult; else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) e = EXP_VOID_INTERPRET; else - error("cannot evaluate %s at compile time", toChars()); - return e; - } - else if (fd) - { // function call -#if DMDV2 - enum BUILTIN b = fd->isBuiltin(); - if (b) - { Expressions args; - args.setDim(arguments->dim); - for (size_t i = 0; i < args.dim; i++) - { - Expression *earg = (Expression *)arguments->data[i]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return earg; - args.data[i] = (void *)earg; - } - e = eval_builtin(b, &args); - if (!e) - e = EXP_CANT_INTERPRET; - } - else -#endif - -#if DMDV1 - if (fd->ident == Id::aaLen) - return interpret_aaLen(istate, arguments); - else if (fd->ident == Id::aaKeys) - return interpret_aaKeys(istate, arguments); - else if (fd->ident == Id::aaValues) - return interpret_aaValues(istate, arguments); -#endif - - // Inline .dup - if (fd->ident == Id::adDup && arguments && arguments->dim == 2) - { - e = (Expression *)arguments->data[1]; - e = e->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - e = expType(type, e); - } - } - else - { - if (!fd->fbody) - { - error("%s cannot be interpreted at compile time," - " because it has no available source code", fd->toChars()); - return EXP_CANT_INTERPRET; - } - Expression *eresult = fd->interpret(istate, arguments); - if (eresult) - e = eresult; - else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) - e = EXP_VOID_INTERPRET; - else - error("cannot evaluate %s at compile time", toChars()); - } - } - else - { - error("cannot evaluate %s at compile time", toChars()); - return EXP_CANT_INTERPRET; + { // Print a stack trace. + if (!global.gag) + showCtfeBackTrace(istate, this, fd); } return e; } -Expression *CommaExp::interpret(InterState *istate) +Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("CommaExp::interpret() %s\n", toChars()); @@ -2886,53 +4635,94 @@ Expression *CommaExp::interpret(InterState *istate) // the variable to be created in, we need to create one now. InterState istateComma; if (!istate && firstComma->e1->op == TOKdeclaration) + { + assert(ctfeStack.stackPointer() == 0); + ctfeStack.startFrame(); istate = &istateComma; + } + + Expression *e = EXP_CANT_INTERPRET; // If the comma returns a temporary variable, it needs to be an lvalue // (this is particularly important for struct constructors) if (e1->op == TOKdeclaration && e2->op == TOKvar - && ((DeclarationExp *)e1)->declaration == ((VarExp*)e2)->var) + && ((DeclarationExp *)e1)->declaration == ((VarExp*)e2)->var + && ((VarExp*)e2)->var->storage_class & STCctfe) // same as Expression::isTemp { VarExp* ve = (VarExp *)e2; VarDeclaration *v = ve->var->isVarDeclaration(); - if (!v->init && !v->value) - v->value = v->type->defaultInitLiteral(); - if (!v->value) - v->value = v->init->toExpression(); + ctfeStack.push(v); + if (!v->init && !v->getValue()) + { + v->createRefValue(copyLiteral(v->type->defaultInitLiteral())); + } + if (!v->getValue()) { + Expression *newval = v->init->toExpression(); // Bug 4027. Copy constructors are a weird case where the // initializer is a void function (the variable is modified // through a reference parameter instead). - Expression *newval = v->value->interpret(istate); + newval = newval->interpret(istate); + if (exceptionOrCantInterpret(newval)) + { + if (istate == &istateComma) + ctfeStack.endFrame(0); + return newval; + } if (newval != EXP_VOID_INTERPRET) - v->value = newval; - return e2; + { + // v isn't necessarily null. + v->setValueWithoutChecking(copyLiteral(newval)); } - - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - e = e2->interpret(istate); + } + if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) + e = e2; + else + e = e2->interpret(istate, goal); + } + else + { + e = e1->interpret(istate, ctfeNeedNothing); + if (!exceptionOrCantInterpret(e)) + e = e2->interpret(istate, goal); + } + // If we created a temporary stack frame, end it now. + if (istate == &istateComma) + ctfeStack.endFrame(0); return e; } -Expression *CondExp::interpret(InterState *istate) +Expression *CondExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("CondExp::interpret() %s\n", toChars()); #endif - Expression *e = econd->interpret(istate); - if (e != EXP_CANT_INTERPRET) + Expression *e; + if (econd->type->ty == Tpointer && econd->type->nextOf()->ty != Tfunction) { - if (e->isBool(TRUE)) - e = e1->interpret(istate); + e = econd->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e)) + return e; + if (e->op != TOKnull) + e = new IntegerExp(loc, 1, Type::tbool); + } + else + e = econd->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; + if (isTrueBool(e)) + e = e1->interpret(istate, goal); else if (e->isBool(FALSE)) - e = e2->interpret(istate); + e = e2->interpret(istate, goal); else + { + error("%s does not evaluate to boolean result at compile time", + econd->toChars()); e = EXP_CANT_INTERPRET; } return e; } -Expression *ArrayLengthExp::interpret(InterState *istate) +Expression *ArrayLengthExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; Expression *e1; @@ -2940,62 +4730,172 @@ Expression *ArrayLengthExp::interpret(InterState *istate) printf("ArrayLengthExp::interpret() %s\n", toChars()); #endif e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) + assert(e1); + if (exceptionOrCantInterpret(e1)) + return e1; + if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKslice + || e1->op == TOKassocarrayliteral || e1->op == TOKnull) { - e = ArrayLength(type, e1); + e = new IntegerExp(loc, resolveArrayLength(e1), type); } - else if (e1->op == TOKnull) + else { - e = new IntegerExp(loc, 0, type); + error("%s cannot be evaluated at compile time", toChars()); + return EXP_CANT_INTERPRET; } - else - goto Lcant; return e; +} -Lcant: - return EXP_CANT_INTERPRET; +/* Given an AA literal 'ae', and a key 'e2': + * Return ae[e2] if present, or NULL if not found. + * Return EXP_CANT_INTERPRET on error. + */ +Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2) +{ + /* Search the keys backwards, in case there are duplicate keys + */ + for (size_t i = ae->keys->dim; i;) + { + i--; + Expression *ekey = ae->keys->tdata()[i]; + Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, e2); + if (ex == EXP_CANT_INTERPRET) + { + error("cannot evaluate %s==%s at compile time", + ekey->toChars(), e2->toChars()); + return ex; + } + if (ex->isBool(TRUE)) + { + return ae->values->tdata()[i]; + } + } + return NULL; } -Expression *IndexExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; +Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) +{ + Expression *e1 = NULL; Expression *e2; #if LOG printf("IndexExp::interpret() %s\n", toChars()); #endif + if (this->e1->type->toBasetype()->ty == Tpointer) + { + // Indexing a pointer. Note that there is no $ in this case. e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; + if (exceptionOrCantInterpret(e1)) + return e1; + e2 = this->e2->interpret(istate); + if (exceptionOrCantInterpret(e2)) + return e2; + dinteger_t indx = e2->toInteger(); + dinteger_t ofs; + Expression *agg = getAggregateFromPointer(e1, &ofs); + if (agg->op == TOKnull) + { + error("cannot index null pointer %s", this->e1->toChars()); + return EXP_CANT_INTERPRET; + } + assert(agg->op == TOKarrayliteral || agg->op == TOKstring); + dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); + Type *pointee = ((TypePointer *)agg->type)->next; + if ((indx + ofs) < 0 || (indx+ofs) > len) + { + error("pointer index [%jd] exceeds allocated memory block [0..%jd]", + indx+ofs, len); + return EXP_CANT_INTERPRET; + } + return Index(type, agg, new IntegerExp(loc, indx+ofs, Type::tsize_t)); + } + e1 = this->e1->interpret(istate); + if (exceptionOrCantInterpret(e1)) + return e1; - if (e1->op == TOKstring || e1->op == TOKarrayliteral) + if (e1->op == TOKnull) { - /* Set the $ variable + if (goal == ctfeNeedLvalue && e1->type->ty == Taarray) + return paintTypeOntoLiteral(type, e1); + error("cannot index null array %s", this->e1->toChars()); + return EXP_CANT_INTERPRET; + } + /* Set the $ variable. + * Note that foreach uses indexing but doesn't need $ */ - e = ArrayLength(Type::tsize_t, e1); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - if (lengthVar) - lengthVar->value = e; + if (lengthVar && (e1->op == TOKstring || e1->op == TOKarrayliteral + || e1->op == TOKslice)) + { + uinteger_t dollar = resolveArrayLength(e1); + Expression *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t); + ctfeStack.push(lengthVar); + lengthVar->createStackValue(dollarExp); } e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; + if (lengthVar) + ctfeStack.pop(lengthVar); // $ is defined only inside [] + if (exceptionOrCantInterpret(e2)) + return e2; + if (e1->op == TOKslice && e2->op == TOKint64) + { + // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx'] + uinteger_t indx = e2->toInteger(); + uinteger_t ilo = ((SliceExp *)e1)->lwr->toInteger(); + uinteger_t iup = ((SliceExp *)e1)->upr->toInteger(); + + if (indx > iup - ilo) + { + error("index %ju exceeds array length %ju", indx, iup - ilo); + return EXP_CANT_INTERPRET; + } + indx += ilo; + e1 = ((SliceExp *)e1)->e1; + e2 = new IntegerExp(e2->loc, indx, e2->type); + } + Expression *e = NULL; + if ((goal == ctfeNeedLvalue && type->ty != Taarray && type->ty != Tarray + && type->ty != Tsarray && type->ty != Tstruct && type->ty != Tclass) + || (goal == ctfeNeedLvalueRef && type->ty != Tsarray && type->ty != Tstruct) + ) + { // Pointer or reference of a scalar type + e = new IndexExp(loc, e1, e2); + e->type = type; + return e; + } + if (e1->op == TOKassocarrayliteral) + { + if (e2->op == TOKslice) + e2 = resolveSlice(e2); + e = findKeyInAA((AssocArrayLiteralExp *)e1, e2); + if (!e) + { + error("key %s not found in associative array %s", + e2->toChars(), this->e1->toChars()); + return EXP_CANT_INTERPRET; + } + if (exceptionOrCantInterpret(e)) + return e; + assert(!e->checkSideEffect(2)); + e = paintTypeOntoLiteral(type, e); + } + else + { e = Index(type, e1, e2); + } if (e == EXP_CANT_INTERPRET) + { error("%s cannot be interpreted at compile time", toChars()); return e; - -Lcant: - return EXP_CANT_INTERPRET; + } + if (goal == ctfeNeedRvalue && (e->op == TOKslice || e->op == TOKdotvar)) + e = e->interpret(istate); + return e; } -Expression *SliceExp::interpret(InterState *istate) -{ Expression *e; +Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) +{ Expression *e1; Expression *lwr; Expression *upr; @@ -3003,43 +4903,186 @@ Expression *SliceExp::interpret(InterState *istate) #if LOG printf("SliceExp::interpret() %s\n", toChars()); #endif + + if (this->e1->type->toBasetype()->ty == Tpointer) + { + // Slicing a pointer. Note that there is no $ in this case. e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; + if (exceptionOrCantInterpret(e1)) + return e1; + if (e1->op == TOKint64) + { + error("cannot slice invalid pointer %s of value %s", + this->e1->toChars(), e1->toChars()); + return EXP_CANT_INTERPRET; + } + + /* Evaluate lower and upper bounds of slice + */ + lwr = this->lwr->interpret(istate); + if (exceptionOrCantInterpret(lwr)) + return lwr; + upr = this->upr->interpret(istate); + if (exceptionOrCantInterpret(upr)) + return upr; + uinteger_t ilwr; + uinteger_t iupr; + ilwr = lwr->toInteger(); + iupr = upr->toInteger(); + Expression *e; + dinteger_t ofs; + Expression *agg = getAggregateFromPointer(e1, &ofs); + if (agg->op == TOKnull) + { + if (iupr == ilwr) + { + e = new NullExp(loc); + e->type = type; + return e; + } + error("cannot slice null pointer %s", this->e1->toChars()); + return EXP_CANT_INTERPRET; + } + assert(agg->op == TOKarrayliteral || agg->op == TOKstring); + dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); + Type *pointee = ((TypePointer *)agg->type)->next; + if ((ilwr + ofs) < 0 || (iupr+ofs) > (len + 1) || iupr < ilwr) + { + error("pointer slice [%jd..%jd] exceeds allocated memory block [0..%jd]", + ilwr+ofs, iupr+ofs, len); + return EXP_CANT_INTERPRET; + } + e = new SliceExp(loc, agg, lwr, upr); + e->type = type; + return e; + } + if (goal == ctfeNeedRvalue && this->e1->op == TOKstring) + e1 = this->e1; // Will get duplicated anyway + else + e1 = this->e1->interpret(istate, goal); + if (exceptionOrCantInterpret(e1)) + return e1; + if (e1->op == TOKvar) + e1 = e1->interpret(istate); + if (!this->lwr) { - e = e1->castTo(NULL, type); - return e->interpret(istate); + if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) + return e1; + return paintTypeOntoLiteral(type, e1); } /* Set the $ variable */ - e = ArrayLength(Type::tsize_t, e1); - if (e == EXP_CANT_INTERPRET) - goto Lcant; + if (e1->op != TOKarrayliteral && e1->op != TOKstring && + e1->op != TOKnull && e1->op != TOKslice) + { + error("Cannot determine length of %s at compile time\n", e1->toChars()); + return EXP_CANT_INTERPRET; + } + uinteger_t dollar = resolveArrayLength(e1); if (lengthVar) - lengthVar->value = e; + { + IntegerExp *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t); + ctfeStack.push(lengthVar); + lengthVar->createStackValue(dollarExp); + } /* Evaluate lower and upper bounds of slice */ lwr = this->lwr->interpret(istate); - if (lwr == EXP_CANT_INTERPRET) - goto Lcant; + if (exceptionOrCantInterpret(lwr)) + { + if (lengthVar) + ctfeStack.pop(lengthVar);; // $ is defined only inside [L..U] + return lwr; + } upr = this->upr->interpret(istate); - if (upr == EXP_CANT_INTERPRET) - goto Lcant; + if (lengthVar) + ctfeStack.pop(lengthVar); // $ is defined only inside [L..U] + if (exceptionOrCantInterpret(upr)) + return upr; - e = Slice(type, e1, lwr, upr); - if (e == EXP_CANT_INTERPRET) - error("%s cannot be interpreted at compile time", toChars()); + Expression *e; + uinteger_t ilwr; + uinteger_t iupr; + ilwr = lwr->toInteger(); + iupr = upr->toInteger(); + if (e1->op == TOKnull) + { + if (ilwr== 0 && iupr == 0) + return e1; + e1->error("slice [%ju..%ju] is out of bounds", ilwr, iupr); + return EXP_CANT_INTERPRET; + } + if (e1->op == TOKslice) + { + SliceExp *se = (SliceExp *)e1; + // Simplify slice of slice: + // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr'] + uinteger_t lo1 = se->lwr->toInteger(); + uinteger_t up1 = se->upr->toInteger(); + if (ilwr > iupr || iupr > up1 - lo1) + { + error("slice[%ju..%ju] exceeds array bounds[%ju..%ju]", + ilwr, iupr, lo1, up1); + return EXP_CANT_INTERPRET; + } + ilwr += lo1; + iupr += lo1; + e = new SliceExp(loc, se->e1, + new IntegerExp(loc, ilwr, lwr->type), + new IntegerExp(loc, iupr, upr->type)); + e->type = type; return e; - -Lcant: + } + if (e1->op == TOKarrayliteral + || e1->op == TOKstring) + { + if (iupr < ilwr || ilwr < 0 || iupr > dollar) + { + error("slice [%jd..%jd] exceeds array bounds [0..%jd]", + ilwr, iupr, dollar); return EXP_CANT_INTERPRET; + } + } + e = new SliceExp(loc, e1, lwr, upr); + e->type = type; + return e; } +Expression *InExp::interpret(InterState *istate, CtfeGoal goal) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("InExp::interpret() %s\n", toChars()); +#endif + Expression *e1 = this->e1->interpret(istate); + if (exceptionOrCantInterpret(e1)) + return e1; + Expression *e2 = this->e2->interpret(istate); + if (exceptionOrCantInterpret(e2)) + return e2; + if (e2->op == TOKnull) + return new NullExp(loc, type); + if (e2->op != TOKassocarrayliteral) + { + error(" %s cannot be interpreted at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + if (e1->op == TOKslice) + e1 = resolveSlice(e1); + e = findKeyInAA((AssocArrayLiteralExp *)e2, e1); + if (exceptionOrCantInterpret(e)) + return e; + if (!e) + return new NullExp(loc, type); + e = new IndexExp(loc, e2, e1); + e->type = type; + return e; +} -Expression *CatExp::interpret(InterState *istate) +Expression *CatExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; Expression *e1; Expression *e2; @@ -3048,81 +5091,245 @@ Expression *CatExp::interpret(InterState *istate) printf("CatExp::interpret() %s\n", toChars()); #endif e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) + if (exceptionOrCantInterpret(e1)) + return e1; + if (e1->op == TOKslice) { - goto Lcant; + e1 = resolveSlice(e1); } e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; + if (exceptionOrCantInterpret(e2)) + return e2; + if (e2->op == TOKslice) + e2 = resolveSlice(e2); e = Cat(type, e1, e2); if (e == EXP_CANT_INTERPRET) error("%s cannot be interpreted at compile time", toChars()); return e; +} -Lcant: -#if LOG - printf("CatExp::interpret() %s CANT\n", toChars()); -#endif - return EXP_CANT_INTERPRET; +#if DMDV2 +// Return true if t is an AA, or AssociativeArray!(key, value) +bool isAssocArray(Type *t) +{ + t = t->toBasetype(); + if (t->ty == Taarray) + return true; + if (t->ty != Tstruct) + return false; + StructDeclaration *sym = ((TypeStruct *)t)->sym; + if (sym->ident == Id::AssociativeArray) + return true; + return false; } +// Given a template AA type, extract the corresponding built-in AA type +TypeAArray *toBuiltinAAType(Type *t) +{ + t = t->toBasetype(); + if (t->ty == Taarray) + return (TypeAArray *)t; + assert(t->ty == Tstruct); + StructDeclaration *sym = ((TypeStruct *)t)->sym; + assert(sym->ident == Id::AssociativeArray); + TemplateInstance *tinst = sym->parent->isTemplateInstance(); + assert(tinst); + return new TypeAArray((Type *)(tinst->tiargs->tdata()[1]), (Type *)(tinst->tiargs->tdata()[0])); +} +#endif -Expression *CastExp::interpret(InterState *istate) +Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; Expression *e1; #if LOG printf("CastExp::interpret() %s\n", toChars()); #endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - e = Cast(type, to, e1); - if (e == EXP_CANT_INTERPRET) - error("%s cannot be interpreted at compile time", toChars()); - return e; - -Lcant: -#if LOG - printf("CastExp::interpret() %s CANT\n", toChars()); + e1 = this->e1->interpret(istate, goal); + if (exceptionOrCantInterpret(e1)) + return e1; + // If the expression has been cast to void, do nothing. + if (to->ty == Tvoid && goal == ctfeNeedNothing) + return e1; + if (to->ty == Tpointer && e1->op != TOKnull) + { + Type *pointee = ((TypePointer *)type)->next; + // Implement special cases of normally-unsafe casts +#if DMDV2 + if (pointee->ty == Taarray && e1->op == TOKaddress + && isAssocArray(((AddrExp*)e1)->e1->type)) + { // cast from template AA pointer to true AA pointer is OK. + return paintTypeOntoLiteral(to, e1); + } #endif + if (e1->op == TOKint64) + { // Happens with Windows HANDLEs, for example. + return paintTypeOntoLiteral(to, e1); + } + bool castBackFromVoid = false; + if (e1->type->ty == Tarray || e1->type->ty == Tsarray || e1->type->ty == Tpointer) + { + // Check for unsupported type painting operations + // For slices, we need the type being sliced, + // since it may have already been type painted + Type *elemtype = e1->type->nextOf(); + if (e1->op == TOKslice) + elemtype = ((SliceExp *)e1)->e1->type->nextOf(); + // Allow casts from X* to void *, and X** to void** for any X. + // But don't allow cast from X* to void**. + // So, we strip all matching * from source and target to find X. + // Allow casts to X* from void* only if the 'void' was originally an X; + // we check this later on. + Type *ultimatePointee = pointee; + Type *ultimateSrc = elemtype; + while (ultimatePointee->ty == Tpointer && ultimateSrc->ty == Tpointer) + { + ultimatePointee = ultimatePointee->nextOf(); + ultimateSrc = ultimateSrc->nextOf(); + } + if (ultimatePointee->ty != Tvoid && ultimateSrc->ty != Tvoid + && !isSafePointerCast(elemtype, pointee)) + { + error("reinterpreting cast from %s* to %s* is not supported in CTFE", + elemtype->toChars(), pointee->toChars()); return EXP_CANT_INTERPRET; -} - - -Expression *AssertExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; + } + if (ultimateSrc->ty == Tvoid) + castBackFromVoid = true; + } + + if (e1->op == TOKslice) + { + if ( ((SliceExp *)e1)->e1->op == TOKnull) + { + return paintTypeOntoLiteral(type, ((SliceExp *)e1)->e1); + } + e = new IndexExp(loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr); + e->type = type; + return e; + } + if (e1->op == TOKarrayliteral || e1->op == TOKstring) + { + e = new IndexExp(loc, e1, new IntegerExp(loc, 0, Type::tsize_t)); + e->type = type; + return e; + } + if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type != e1->type) + { // type painting operation + IndexExp *ie = (IndexExp *)e1; + e = new IndexExp(e1->loc, ie->e1, ie->e2); + if (castBackFromVoid) + { + // get the original type. For strings, it's just the type... + Type *origType = ie->e1->type->nextOf(); + // ..but for arrays of type void*, it's the type of the element + Expression *xx = NULL; + if (ie->e1->op == TOKarrayliteral && ie->e2->op == TOKint64) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)ie->e1; + uinteger_t indx = ie->e2->toInteger(); + if (indx < ale->elements->dim) + xx = ale->elements->tdata()[indx]; + } + if (xx && xx->op == TOKindex) + origType = ((IndexExp *)xx)->e1->type->nextOf(); + else if (xx && xx->op == TOKaddress) + origType= ((AddrExp *)xx)->e1->type; + else if (xx && xx->op == TOKvar) + origType = ((VarExp *)xx)->var->type; + if (!isSafePointerCast(origType, pointee)) + { + error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", + origType->toChars(), pointee->toChars()); + return EXP_CANT_INTERPRET; + } + } + e->type = type; + return e; + } + if (e1->op == TOKaddress) + { + Type *origType = ((AddrExp *)e1)->type; + if (isSafePointerCast(origType, pointee)) + { + e = new AddrExp(loc, ((AddrExp *)e1)->e1); + e->type = type; + return e; + } + } + if (e1->op == TOKvar) + { // type painting operation + Type *origType = ((VarExp *)e1)->var->type; + if (castBackFromVoid && !isSafePointerCast(origType, pointee)) + { + error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", + origType->toChars(), pointee->toChars()); + return EXP_CANT_INTERPRET; + } + e = new VarExp(loc, ((VarExp *)e1)->var); + e->type = type; + return e; + } + error("pointer cast from %s to %s is not supported at compile time", + e1->type->toChars(), to->toChars()); + return EXP_CANT_INTERPRET; + } + if (to->ty == Tarray && e1->op == TOKslice) + { + e1 = new SliceExp(e1->loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr, + ((SliceExp *)e1)->upr); + e1->type = to; + return e1; + } + // Disallow array type painting, except for conversions between built-in + // types of identical size. + if ((to->ty == Tsarray || to->ty == Tarray) && + (e1->type->ty == Tsarray || e1->type->ty == Tarray) && + !isSafePointerCast(e1->type->nextOf(), to->nextOf()) ) + { + error("array cast from %s to %s is not supported at compile time", e1->type->toChars(), to->toChars()); + return EXP_CANT_INTERPRET; + } + if (to->ty == Tsarray && e1->op == TOKslice) + e1 = resolveSlice(e1); + if (to->toBasetype()->ty == Tbool && e1->type->ty==Tpointer) + { + return new IntegerExp(loc, e1->op != TOKnull, to); + } + return ctfeCast(loc, type, to, e1); +} + +Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal) +{ Expression *e; + Expression *e1; #if LOG printf("AssertExp::interpret() %s\n", toChars()); #endif - if( this->e1->op == TOKaddress) - { // Special case: deal with compiler-inserted assert(&this, "null this") - AddrExp *ade = (AddrExp *)this->e1; - if (ade->e1->op == TOKthis && istate->localThis) - if (istate->localThis->op == TOKdotvar - && ((DotVarExp *)(istate->localThis))->e1->op == TOKthis) - return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var); - else - return istate->localThis->interpret(istate); - } if (this->e1->op == TOKthis) { if (istate->localThis) { if (istate->localThis->op == TOKdotvar && ((DotVarExp *)(istate->localThis))->e1->op == TOKthis) - return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var); + return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var, ctfeNeedRvalue); else return istate->localThis->interpret(istate); } } + // Deal with pointers (including compiler-inserted assert(&this, "null this")) + if (this->e1->type->ty == Tpointer && this->e1->type->nextOf()->ty != Tfunction) + { + e1 = this->e1->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e1)) + return e1; + if (e1->op != TOKnull) + return new IntegerExp(loc, 1, Type::tbool); + } + else e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isBool(TRUE)) + if (exceptionOrCantInterpret(e1)) + return e1; + if (isTrueBool(e1)) { } else if (e1->isBool(FALSE)) @@ -3130,8 +5337,8 @@ Expression *AssertExp::interpret(InterState *istate) if (msg) { e = msg->interpret(istate); - if (e == EXP_CANT_INTERPRET) - goto Lcant; + if (exceptionOrCantInterpret(e)) + return e; error("%s", e->toChars()); } else @@ -3139,20 +5346,22 @@ Expression *AssertExp::interpret(InterState *istate) goto Lcant; } else + { + error("%s is not a compile-time boolean expression", e1->toChars()); goto Lcant; + } return e1; Lcant: return EXP_CANT_INTERPRET; } -Expression *PtrExp::interpret(InterState *istate) +Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e = EXP_CANT_INTERPRET; #if LOG printf("PtrExp::interpret() %s\n", toChars()); #endif - // Constant fold *(&structliteral + offset) if (e1->op == TOKadd) { AddExp *ae = (AddExp *)e1; @@ -3160,33 +5369,19 @@ Expression *PtrExp::interpret(InterState *istate) { AddrExp *ade = (AddrExp *)ae->e1; Expression *ex = ade->e1; ex = ex->interpret(istate); - if (ex != EXP_CANT_INTERPRET) - { + if (exceptionOrCantInterpret(ex)) + return ex; if (ex->op == TOKstructliteral) { StructLiteralExp *se = (StructLiteralExp *)ex; - unsigned offset = ae->e2->toInteger(); + dinteger_t offset = ae->e2->toInteger(); e = se->getField(type, offset); if (!e) e = EXP_CANT_INTERPRET; return e; } } - } e = Ptr(type, e1); } - else if (e1->op == TOKsymoff) - { SymOffExp *soe = (SymOffExp *)e1; - VarDeclaration *v = soe->var->isVarDeclaration(); - if (v) - { Expression *ev = getVarExp(loc, istate, v); - if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ev; - e = se->getField(type, soe->offset); - if (!e) - e = EXP_CANT_INTERPRET; - } - } - } #if DMDV2 #else // this is required for D1, where structs return *this instead of 'this'. else if (e1->op == TOKthis) @@ -3196,7 +5391,94 @@ Expression *PtrExp::interpret(InterState *istate) } #endif else - error("Cannot interpret %s at compile time", toChars()); + { // It's possible we have an array bounds error. We need to make sure it + // errors with this line number, not the one where the pointer was set. + e = e1->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(e)) + return e; + if (!(e->op == TOKvar || e->op == TOKdotvar || e->op == TOKindex + || e->op == TOKslice || e->op == TOKaddress)) + { + error("dereference of invalid pointer '%s'", e->toChars()); + return EXP_CANT_INTERPRET; + } + if (goal != ctfeNeedLvalue) + { + if (e->op == TOKindex && e->type->ty == Tpointer) + { + IndexExp *ie = (IndexExp *)e; + // Is this a real index to an array of pointers, or just a CTFE pointer? + // If the index has the same levels of indirection, it's an index + int srcLevels = 0; + int destLevels = 0; + for(Type *xx = ie->e1->type; xx->ty == Tpointer; xx = xx->nextOf()) + ++srcLevels; + for(Type *xx = e->type->nextOf(); xx->ty == Tpointer; xx = xx->nextOf()) + ++destLevels; + bool isGenuineIndex = (srcLevels == destLevels); + + if ((ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring) + && ie->e2->op == TOKint64) + { + Expression *dollar = ArrayLength(Type::tsize_t, ie->e1); + dinteger_t len = dollar->toInteger(); + dinteger_t indx = ie->e2->toInteger(); + assert(indx >=0 && indx <= len); // invalid pointer + if (indx == len) + { + error("dereference of pointer %s one past end of memory block limits [0..%jd]", + toChars(), len); + return EXP_CANT_INTERPRET; + } + e = Index(type, ie->e1, ie->e2); + if (isGenuineIndex) + { + if (e->op == TOKindex) + e = e->interpret(istate, goal); + else if (e->op == TOKaddress) + e = paintTypeOntoLiteral(type, ((AddrExp *)e)->e1); + } + return e; + } + if (ie->e1->op == TOKassocarrayliteral) + { + e = Index(type, ie->e1, ie->e2); + if (isGenuineIndex) + { + if (e->op == TOKindex) + e = e->interpret(istate, goal); + else if (e->op == TOKaddress) + e = paintTypeOntoLiteral(type, ((AddrExp *)e)->e1); + } + return e; + } + } + if (e->op == TOKstructliteral) + return e; + e = e1->interpret(istate, goal); + if (e->op == TOKaddress) + { + e = ((AddrExp*)e)->e1; + if (e->op == TOKdotvar || e->op == TOKindex) + e = e->interpret(istate, goal); + } + else if (e->op == TOKvar) + { + e = e->interpret(istate, goal); + } + if (exceptionOrCantInterpret(e)) + return e; + } + else if (e->op == TOKaddress) + e = ((AddrExp*)e)->e1; // *(&x) ==> x + if (e->op == TOKnull) + { + error("dereference of null pointer '%s'", e1->toChars()); + return EXP_CANT_INTERPRET; + } + e->type = type; + } + #if LOG if (e == EXP_CANT_INTERPRET) printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); @@ -3204,7 +5486,7 @@ Expression *PtrExp::interpret(InterState *istate) return e; } -Expression *DotVarExp::interpret(InterState *istate) +Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e = EXP_CANT_INTERPRET; #if LOG @@ -3212,20 +5494,78 @@ Expression *DotVarExp::interpret(InterState *istate) #endif Expression *ex = e1->interpret(istate); + if (exceptionOrCantInterpret(ex)) + return ex; if (ex != EXP_CANT_INTERPRET) { - if (ex->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ex; + #if DMDV2 + // Special case for template AAs: AA.var returns the AA itself. + // ie AA.p ----> AA. This is a hack, to get around the + // corresponding hack in the AA druntime implementation. + if (isAssocArray(ex->type)) + return ex; + #endif + if (ex->op == TOKaddress) + ex = ((AddrExp *)ex)->e1; VarDeclaration *v = var->isVarDeclaration(); - if (v) - { e = se->getField(type, v->offset); + if (!v) + error("CTFE internal error: %s", toChars()); + if (ex->op == TOKnull && ex->type->toBasetype()->ty == Tclass) + { error("class '%s' is null and cannot be dereferenced", e1->toChars()); + return EXP_CANT_INTERPRET; + } + if (ex->op == TOKstructliteral || ex->op == TOKclassreference) + { + StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex; + // We can't use getField, because it makes a copy + int i = -1; + if (ex->op == TOKclassreference) + i = ((ClassReferenceExp *)ex)->getFieldIndex(type, v->offset); + else + i = se->getFieldIndex(type, v->offset); + if (i == -1) + { + error("couldn't find field %s of type %s in %s", v->toChars(), type->toChars(), se->toChars()); + return EXP_CANT_INTERPRET; + } + e = se->elements->tdata()[i]; + if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) + { + // If it is an lvalue literal, return it... + if (e->op == TOKstructliteral) + return e; + if ((type->ty == Tsarray || goal == ctfeNeedLvalue) && ( + e->op == TOKarrayliteral || + e->op == TOKassocarrayliteral || e->op == TOKstring || + e->op == TOKslice)) + return e; + /* Element is an allocated pointer, which was created in + * CastExp. + */ + if (goal == ctfeNeedLvalue && e->op == TOKindex && + e->type == type && + (type->ty == Tpointer && type->nextOf()->ty != Tfunction)) + return e; + // ...Otherwise, just return the (simplified) dotvar expression + e = new DotVarExp(loc, ex, v); + e->type = type; + return e; + } if (!e) { error("couldn't find field %s in %s", v->toChars(), type->toChars()); e = EXP_CANT_INTERPRET; } + // If it is an rvalue literal, return it... + if (e->op == TOKstructliteral || e->op == TOKarrayliteral || + e->op == TOKassocarrayliteral || e->op == TOKstring) + return e; + if (type->ty == Tpointer && type->nextOf()->ty != Tfunction) + { + assert(e->type == type); return e; } + return e->interpret(istate, goal); } else error("%s.%s is not yet implemented at compile time", e1->toChars(), var->toChars()); @@ -3238,117 +5578,698 @@ Expression *DotVarExp::interpret(InterState *istate) return e; } -/******************************* Special Functions ***************************/ +Expression *RemoveExp::interpret(InterState *istate, CtfeGoal goal) +{ +#if LOG + printf("RemoveExp::interpret() %s\n", toChars()); +#endif + Expression *agg = e1->interpret(istate); + if (exceptionOrCantInterpret(agg)) + return agg; + Expression *index = e2->interpret(istate); + if (exceptionOrCantInterpret(index)) + return index; + if (agg->op == TOKnull) + return EXP_VOID_INTERPRET; + assert(agg->op == TOKassocarrayliteral); + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)agg; + Expressions *keysx = aae->keys; + Expressions *valuesx = aae->values; + size_t removed = 0; + for (size_t j = 0; j < valuesx->dim; ++j) + { Expression *ekey = keysx->tdata()[j]; + Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, index); + if (exceptionOrCantInterpret(ex)) + return ex; + if (ex->isBool(TRUE)) + ++removed; + else if (removed != 0) + { keysx->tdata()[j - removed] = ekey; + valuesx->tdata()[j - removed] = valuesx->tdata()[j]; + } + } + valuesx->dim = valuesx->dim - removed; + keysx->dim = keysx->dim - removed; + return EXP_VOID_INTERPRET; +} -#if DMDV1 -Expression *interpret_aaLen(InterState *istate, Expressions *arguments) +/******************************* Special Functions ***************************/ + +Expression *interpret_length(InterState *istate, Expression *earg) { - if (!arguments || arguments->dim != 1) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; + //printf("interpret_length()\n"); earg = earg->interpret(istate); if (earg == EXP_CANT_INTERPRET) return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t); + if (exceptionOrCantInterpret(earg)) + return earg; + dinteger_t len = 0; + if (earg->op == TOKassocarrayliteral) + len = ((AssocArrayLiteralExp *)earg)->keys->dim; + else assert(earg->op == TOKnull); + Expression *e = new IntegerExp(earg->loc, len, Type::tsize_t); return e; } -Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) +Expression *interpret_keys(InterState *istate, Expression *earg, Type *elemType) { #if LOG - printf("interpret_aaKeys()\n"); + printf("interpret_keys()\n"); #endif - if (!arguments || arguments->dim != 2) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; earg = earg->interpret(istate); if (earg == EXP_CANT_INTERPRET) return NULL; - if (earg->op != TOKassocarrayliteral) + if (exceptionOrCantInterpret(earg)) + return earg; + if (earg->op == TOKnull) + return new NullExp(earg->loc); + if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) return NULL; + assert(earg->op == TOKassocarrayliteral); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); - Type *elemType = ((TypeAArray *)aae->type)->index; - e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); - return e; + e->type = new TypeSArray(elemType, new IntegerExp(aae->keys->dim)); + return copyLiteral(e); } -Expression *interpret_aaValues(InterState *istate, Expressions *arguments) +Expression *interpret_values(InterState *istate, Expression *earg, Type *elemType) { - //printf("interpret_aaValues()\n"); - if (!arguments || arguments->dim != 3) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; +#if LOG + printf("interpret_values()\n"); +#endif earg = earg->interpret(istate); if (earg == EXP_CANT_INTERPRET) return NULL; - if (earg->op != TOKassocarrayliteral) + if (exceptionOrCantInterpret(earg)) + return earg; + if (earg->op == TOKnull) + return new NullExp(earg->loc); + if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) return NULL; + assert(earg->op == TOKassocarrayliteral); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->values); - Type *elemType = ((TypeAArray *)aae->type)->next; - e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); + e->type = new TypeSArray(elemType, new IntegerExp(aae->values->dim)); //printf("result is %s\n", e->toChars()); - return e; + return copyLiteral(e); } -#endif +// signature is int delegate(ref Value) OR int delegate(ref Key, ref Value) +Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *deleg) +{ aa = aa->interpret(istate); + if (exceptionOrCantInterpret(aa)) + return aa; + if (aa->op != TOKassocarrayliteral) + return new IntegerExp(deleg->loc, 0, Type::tsize_t); -#if DMDV2 + FuncDeclaration *fd = NULL; + Expression *pthis = NULL; + if (deleg->op == TOKdelegate) + { + fd = ((DelegateExp *)deleg)->func; + pthis = ((DelegateExp *)deleg)->e1; + } + else if (deleg->op == TOKfunction) + fd = ((FuncExp*)deleg)->fd; -Expression *interpret_length(InterState *istate, Expression *earg) + assert(fd && fd->fbody); + assert(fd->parameters); + int numParams = fd->parameters->dim; + assert(numParams == 1 || numParams==2); + + Type *valueType = fd->parameters->tdata()[numParams-1]->type; + Type *keyType = numParams == 2 ? fd->parameters->tdata()[0]->type + : Type::tsize_t; + Expressions args; + args.setDim(numParams); + + AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)aa; + if (!ae->keys || ae->keys->dim == 0) + return new IntegerExp(deleg->loc, 0, Type::tsize_t); + Expression *eresult; + + for (size_t i = 0; i < ae->keys->dim; ++i) + { + Expression *ekey = ae->keys->tdata()[i]; + Expression *evalue = ae->values->tdata()[i]; + args.tdata()[numParams - 1] = evalue; + if (numParams == 2) args.tdata()[0] = ekey; + + eresult = fd->interpret(istate, &args, pthis); + if (exceptionOrCantInterpret(eresult)) + return eresult; + + assert(eresult->op == TOKint64); + if (((IntegerExp *)eresult)->value != 0) + return eresult; + } + return eresult; +} + +// Helper function: given a function of type A[] f(...), +// return A. +Type *returnedArrayElementType(FuncDeclaration *fd) { - //printf("interpret_length()\n"); - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t); - return e; + assert(fd->type->ty == Tfunction); + assert(fd->type->nextOf()->ty == Tarray); + return ((TypeFunction *)fd->type)->nextOf()->nextOf(); } -Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration *fd) +/* Decoding UTF strings for foreach loops. Duplicates the functionality of + * the twelve _aApplyXXn functions in aApply.d in the runtime. + */ +Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *deleg, bool rvs) { #if LOG - printf("interpret_keys()\n"); + printf("foreachApplyUtf(%s, %s)\n", str->toChars(), deleg->toChars()); #endif - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); - assert(fd->type->ty == Tfunction); - assert(fd->type->nextOf()->ty == Tarray); - Type *elemType = ((TypeFunction *)fd->type)->nextOf()->nextOf(); - e->type = new TypeSArray(elemType, new IntegerExp(aae->keys->dim)); - return e; + FuncDeclaration *fd = NULL; + Expression *pthis = NULL; + if (deleg->op == TOKdelegate) + { + fd = ((DelegateExp *)deleg)->func; + pthis = ((DelegateExp *)deleg)->e1; + } + else if (deleg->op == TOKfunction) + fd = ((FuncExp*)deleg)->fd; + + assert(fd && fd->fbody); + assert(fd->parameters); + int numParams = fd->parameters->dim; + assert(numParams == 1 || numParams==2); + Type *charType = fd->parameters->tdata()[numParams-1]->type; + Type *indexType = numParams == 2 ? fd->parameters->tdata()[0]->type + : Type::tsize_t; + uinteger_t len = resolveArrayLength(str); + if (len == 0) + return new IntegerExp(deleg->loc, 0, indexType); + + if (str->op == TOKslice) + str = resolveSlice(str); + + StringExp *se = NULL; + ArrayLiteralExp *ale = NULL; + if (str->op == TOKstring) + se = (StringExp *) str; + else if (str->op == TOKarrayliteral) + ale = (ArrayLiteralExp *)str; + else + { error("CTFE internal error: cannot foreach %s", str->toChars()); + return EXP_CANT_INTERPRET; + } + Expressions args; + args.setDim(numParams); + + Expression *eresult; + + // Buffers for encoding; also used for decoding array literals + unsigned char utf8buf[4]; + unsigned short utf16buf[2]; + + size_t start = rvs ? len : 0; + size_t end = rvs ? 0: len; + for (size_t indx = start; indx != end;) + { + // Step 1: Decode the next dchar from the string. + + const char *errmsg = NULL; // Used for reporting decoding errors + dchar_t rawvalue; // Holds the decoded dchar + size_t currentIndex = indx; // The index of the decoded character + + if (ale) + { // If it is an array literal, copy the code points into the buffer + int buflen = 1; // #code points in the buffer + size_t n = 1; // #code points in this char + size_t sz = ale->type->nextOf()->size(); + + switch(sz) + { + case 1: + if (rvs) + { // find the start of the string + --indx; + buflen = 1; + while (indx > 0 && buflen < 4) + { Expression * r = ale->elements->tdata()[indx]; + assert(r->op == TOKint64); + unsigned char x = (unsigned char)(((IntegerExp *)r)->value); + if ( (x & 0xC0) != 0x80) + break; + ++buflen; + } + } + else + buflen = (indx + 4 > len) ? len - indx : 4; + for (int i=0; i < buflen; ++i) + { + Expression * r = ale->elements->tdata()[indx + i]; + assert(r->op == TOKint64); + utf8buf[i] = (unsigned char)(((IntegerExp *)r)->value); + } + n = 0; + errmsg = utf_decodeChar(&utf8buf[0], buflen, &n, &rawvalue); + break; + case 2: + if (rvs) + { // find the start of the string + --indx; + buflen = 1; + Expression * r = ale->elements->tdata()[indx]; + assert(r->op == TOKint64); + unsigned short x = (unsigned short)(((IntegerExp *)r)->value); + if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF) + { + --indx; + ++buflen; + } + } + else + buflen = (indx + 2 > len) ? len - indx : 2; + for (int i=0; i < buflen; ++i) + { + Expression * r = ale->elements->tdata()[indx + i]; + assert(r->op == TOKint64); + utf16buf[i] = (unsigned short)(((IntegerExp *)r)->value); + } + n = 0; + errmsg = utf_decodeWchar(&utf16buf[0], buflen, &n, &rawvalue); + break; + case 4: + { + if (rvs) + --indx; + + Expression * r = ale->elements->tdata()[indx]; + assert(r->op == TOKint64); + rawvalue = ((IntegerExp *)r)->value; + n = 1; + } + break; + default: + assert(0); + } + if (!rvs) + indx += n; + } + else + { // String literals + size_t saveindx; // used for reverse iteration + + switch (se->sz) + { + case 1: + if (rvs) + { // find the start of the string + unsigned char *s = (unsigned char *)se->string; + --indx; + while (indx > 0 && ((s[indx]&0xC0)==0x80)) + --indx; + saveindx = indx; + } + errmsg = utf_decodeChar((unsigned char *)se->string, se->len, &indx, &rawvalue); + if (rvs) + indx = saveindx; + break; + case 2: + if (rvs) + { // find the start + unsigned short *s = (unsigned short *)se->string; + --indx; + if (s[indx] >= 0xDC00 && s[indx]<= 0xDFFF) + --indx; + saveindx = indx; + } + errmsg = utf_decodeWchar((unsigned short *)se->string, se->len, &indx, &rawvalue); + if (rvs) + indx = saveindx; + break; + case 4: + if (rvs) + --indx; + rawvalue = ((unsigned *)(se->string))[indx]; + if (!rvs) + ++indx; + break; + default: + assert(0); + } + } + if (errmsg) + { deleg->error("%s", errmsg); + return EXP_CANT_INTERPRET; + } + + // Step 2: encode the dchar in the target encoding + + int charlen = 1; // How many codepoints are involved? + switch(charType->size()) + { + case 1: + charlen = utf_codeLengthChar(rawvalue); + utf_encodeChar(&utf8buf[0], rawvalue); + break; + case 2: + charlen = utf_codeLengthWchar(rawvalue); + utf_encodeWchar(&utf16buf[0], rawvalue); + break; + case 4: + break; + default: + assert(0); + } + if (rvs) + currentIndex = indx; + + // Step 3: call the delegate once for each code point + + // The index only needs to be set once + if (numParams == 2) + args.tdata()[0] = new IntegerExp(deleg->loc, currentIndex, indexType); + + Expression *val = NULL; + + for (int k= 0; k < charlen; ++k) + { + dchar_t codepoint; + switch(charType->size()) + { + case 1: + codepoint = utf8buf[k]; + break; + case 2: + codepoint = utf16buf[k]; + break; + case 4: + codepoint = rawvalue; + break; + default: + assert(0); + } + val = new IntegerExp(str->loc, codepoint, charType); + + args.tdata()[numParams - 1] = val; + + eresult = fd->interpret(istate, &args, pthis); + if (exceptionOrCantInterpret(eresult)) + return eresult; + assert(eresult->op == TOKint64); + if (((IntegerExp *)eresult)->value != 0) + return eresult; + } + } + return eresult; } -Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclaration *fd) +/* If this is a built-in function, return the interpreted result, + * Otherwise, return NULL. + */ +Expression *evaluateIfBuiltin(InterState *istate, Loc loc, + FuncDeclaration *fd, Expressions *arguments, Expression *pthis) { - //printf("interpret_values()\n"); + Expression *e = NULL; + int nargs = arguments ? arguments->dim : 0; +#if DMDV2 + if (pthis && isAssocArray(pthis->type)) + { + if (fd->ident == Id::length && nargs==0) + return interpret_length(istate, pthis); + else if (fd->ident == Id::keys && nargs==0) + return interpret_keys(istate, pthis, returnedArrayElementType(fd)); + else if (fd->ident == Id::values && nargs==0) + return interpret_values(istate, pthis, returnedArrayElementType(fd)); + else if (fd->ident == Id::rehash && nargs==0) + return pthis->interpret(istate, ctfeNeedLvalue); // rehash is a no-op + } + if (!pthis) + { + enum BUILTIN b = fd->isBuiltin(); + if (b) + { Expressions args; + args.setDim(nargs); + for (size_t i = 0; i < args.dim; i++) + { + Expression *earg = arguments->tdata()[i]; earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->values); - assert(fd->type->ty == Tfunction); - assert(fd->type->nextOf()->ty == Tarray); - Type *elemType = ((TypeFunction *)fd->type)->nextOf()->nextOf(); - e->type = new TypeSArray(elemType, new IntegerExp(aae->values->dim)); - //printf("result is %s\n", e->toChars()); + if (exceptionOrCantInterpret(earg)) + return earg; + args.tdata()[i] = earg; + } + e = eval_builtin(loc, b, &args); + if (!e) + e = EXP_CANT_INTERPRET; + } + } + /* Horrid hack to retrieve the builtin AA functions after they've been + * mashed by the inliner. + */ + if (!pthis) + { + Expression *firstarg = nargs > 0 ? (Expression *)(arguments->data[0]) : NULL; + // Check for the first parameter being a templatized AA. Hack: we assume that + // template AA.var is always the AA data itself. + Expression *firstdotvar = (firstarg && firstarg->op == TOKdotvar) + ? ((DotVarExp *)firstarg)->e1 : NULL; + if (nargs==3 && isAssocArray(firstarg->type) && !strcmp(fd->ident->string, "_aaApply")) + return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); + if (nargs==3 && isAssocArray(firstarg->type) &&!strcmp(fd->ident->string, "_aaApply2")) + return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); + if (firstdotvar && isAssocArray(firstdotvar->type)) + { if (fd->ident == Id::aaLen && nargs == 1) + return interpret_length(istate, firstdotvar->interpret(istate)); + else if (fd->ident == Id::aaKeys && nargs == 2) + { + Expression *trueAA = firstdotvar->interpret(istate); + return interpret_keys(istate, trueAA, toBuiltinAAType(trueAA->type)->index); + } + else if (fd->ident == Id::aaValues && nargs == 3) + { + Expression *trueAA = firstdotvar->interpret(istate); + return interpret_values(istate, trueAA, toBuiltinAAType(trueAA->type)->nextOf()); + } + else if (fd->ident == Id::aaRehash && nargs == 2) + { + return firstdotvar->interpret(istate, ctfeNeedLvalue); + } + } + } +#endif +#if DMDV1 + if (!pthis) + { + Expression *firstarg = nargs > 0 ? (Expression *)(arguments->data[0]) : NULL; + if (firstarg && firstarg->type->toBasetype()->ty == Taarray) + { + TypeAArray *firstAAtype = (TypeAArray *)firstarg->type; + if (fd->ident == Id::aaLen && nargs == 1) + return interpret_length(istate, firstarg); + else if (fd->ident == Id::aaKeys) + return interpret_keys(istate, firstarg, firstAAtype->index); + else if (fd->ident == Id::aaValues) + return interpret_values(istate, firstarg, firstAAtype->nextOf()); + else if (nargs==2 && fd->ident == Id::aaRehash) + return firstarg->interpret(istate, ctfeNeedLvalue); //no-op + else if (nargs==3 && !strcmp(fd->ident->string, "_aaApply")) + return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); + else if (nargs==3 && !strcmp(fd->ident->string, "_aaApply2")) + return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); + } + } +#endif +#if DMDV2 + if (pthis && !fd->fbody && fd->isCtorDeclaration() && fd->parent && fd->parent->parent && fd->parent->parent->ident == Id::object) + { + if (pthis->op == TOKclassreference && fd->parent->ident == Id::Throwable) + { // At present, the constructors just copy their arguments into the struct. + // But we might need some magic if stack tracing gets added to druntime. + StructLiteralExp *se = ((ClassReferenceExp *)pthis)->value; + assert(arguments->dim <= se->elements->dim); + for (int i = 0; i < arguments->dim; ++i) + { + Expression *e = arguments->tdata()[i]->interpret(istate); + if (exceptionOrCantInterpret(e)) + return e; + se->elements->tdata()[i] = e; + } + return EXP_VOID_INTERPRET; + } + } +#endif + if (nargs == 1 && !pthis && + (fd->ident == Id::criticalenter || fd->ident == Id::criticalexit)) + { // Support synchronized{} as a no-op + return EXP_VOID_INTERPRET; + } + if (!pthis) + { + size_t idlen = strlen(fd->ident->string); + if (nargs == 2 && (idlen == 10 || idlen == 11) + && !strncmp(fd->ident->string, "_aApply", 7)) + { // Functions from aApply.d and aApplyR.d in the runtime + bool rvs = (idlen == 11); // true if foreach_reverse + char c = fd->ident->string[idlen-3]; // char width: 'c', 'w', or 'd' + char s = fd->ident->string[idlen-2]; // string width: 'c', 'w', or 'd' + char n = fd->ident->string[idlen-1]; // numParams: 1 or 2. + // There are 12 combinations + if ( (n == '1' || n == '2') && + (c == 'c' || c == 'w' || c == 'd') && + (s == 'c' || s == 'w' || s == 'd') && c != s) + { Expression *str = arguments->tdata()[0]; + str = str->interpret(istate); + if (exceptionOrCantInterpret(str)) + return str; + return foreachApplyUtf(istate, str, arguments->tdata()[1], rvs); + } + } + } return e; } -#endif +/*************************** CTFE Sanity Checks ***************************/ + +/* Setter functions for CTFE variable values. + * These functions exist to check for compiler CTFE bugs. + */ + +bool IsStackValueValid(Expression *newval) +{ + if (newval->type->ty == Tpointer && newval->type->nextOf()->ty != Tfunction) + { + if (newval->op == TOKaddress || newval->op == TOKnull || + newval->op == TOKstring) + return true; + if (newval->op == TOKindex) + { + Expression *g = ((IndexExp *)newval)->e1; + if (g->op == TOKarrayliteral || g->op == TOKstring || + g->op == TOKassocarrayliteral) + return true; + } + if (newval->op == TOKvar) + return true; + if (newval->type->nextOf()->ty == Tarray && newval->op == TOKslice) + return true; + if (newval->op == TOKint64) + return true; // Result of a cast, but cannot be dereferenced + newval->error("CTFE internal error: illegal pointer value %s\n", newval->toChars()); + return false; + } + if (newval->op == TOKclassreference || (newval->op == TOKnull && newval->type->ty == Tclass)) + return true; + if ((newval->op == TOKarrayliteral) || ( newval->op == TOKstructliteral) || + (newval->op == TOKstring) || (newval->op == TOKassocarrayliteral) || + (newval->op == TOKnull) || (newval->op == TOKslice)) + { return false; + } + if (newval->op == TOKvar) + { + VarExp *ve = (VarExp *)newval; + VarDeclaration *vv = ve->var->isVarDeclaration(); + // Must not be a reference to a reference + if (!(vv && vv->getValue() && vv->getValue()->op == TOKvar)) + return true; + } + if (newval->op == TOKdotvar) + { + if (((DotVarExp *)newval)->e1->op == TOKstructliteral) + return true; + } + if (newval->op == TOKindex) + { + IndexExp *ie = (IndexExp *)newval; + if (ie->e2->op == TOKint64) + { + if (ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring) + return true; + } + if (ie->e1->op == TOKassocarrayliteral) + return true; + // BUG: Happens ONLY in ref foreach. Should tighten this. + if (ie->e2->op == TOKvar) + return true; + } + if (newval->op == TOKfunction) return true; // function/delegate literal + if (newval->op == TOKdelegate) return true; + if (newval->op == TOKsymoff) // function pointer + { + if (((SymOffExp *)newval)->var->isFuncDeclaration()) + return true; + } + if (newval->op == TOKint64 || newval->op == TOKfloat64 || + newval->op == TOKchar || newval->op == TOKcomplex80) + return true; + newval->error("CTFE internal error: illegal stack value %s\n", newval->toChars()); + return false; +} +bool IsRefValueValid(Expression *newval) +{ + assert(newval); + if ((newval->op ==TOKarrayliteral) || ( newval->op==TOKstructliteral) || + (newval->op==TOKstring) || (newval->op == TOKassocarrayliteral) || + (newval->op == TOKnull)) + { return true; + } + // Dynamic arrays passed by ref may be null. When this happens + // they may originate from an index or dotvar expression. + if (newval->type->ty == Tarray || newval->type->ty == Taarray) + if (newval->op == TOKdotvar || newval->op == TOKindex) + return IsStackValueValid(newval); // actually must be null + if (newval->op == TOKslice) + { + SliceExp *se = (SliceExp *)newval; + assert(se->lwr && se->lwr != EXP_CANT_INTERPRET && se->lwr->op == TOKint64); + assert(se->upr && se->upr != EXP_CANT_INTERPRET && se->upr->op == TOKint64); + assert(se->e1->op == TOKarrayliteral || se->e1->op == TOKstring); + return true; + } + newval->error("CTFE internal error: illegal reference value %s\n", newval->toChars()); + return false; +} + +bool VarDeclaration::hasValue() +{ + if (ctfeAdrOnStack == (size_t)-1) + return false; + return NULL != getValue(); +} + +Expression *VarDeclaration::getValue() +{ + return ctfeStack.getValue(this); +} + +void VarDeclaration::setValueNull() +{ + ctfeStack.setValue(this, NULL); +} + +// Don't check for validity +void VarDeclaration::setValueWithoutChecking(Expression *newval) +{ + ctfeStack.setValue(this, newval); +} + +void VarDeclaration::createRefValue(Expression *newval) +{ + assert(IsRefValueValid(newval)); + ctfeStack.setValue(this, newval); +} + +void VarDeclaration::setRefValue(Expression *newval) +{ + assert(IsRefValueValid(newval)); + ctfeStack.setValue(this, newval); +} + +void VarDeclaration::setStackValue(Expression *newval) +{ + assert(IsStackValueValid(newval)); + ctfeStack.setValue(this, newval); +} + +void VarDeclaration::createStackValue(Expression *newval) +{ + assert(IsStackValueValid(newval)); + ctfeStack.setValue(this, newval); +} diff --git a/dmd/json.c b/dmd/json.c index 195a10a3..16f9f435 100644 --- a/dmd/json.c +++ b/dmd/json.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -43,15 +43,17 @@ const char Pline[] = "line"; const char Ptype[] = "type"; const char Pcomment[] = "comment"; const char Pmembers[] = "members"; +const char Pprotection[] = "protection"; +const char* Pprotectionnames[] = {NULL, "none", "private", "package", "protected", "public", "export"}; void JsonRemoveComma(OutBuffer *buf); -void json_generate(Array *modules) +void json_generate(Modules *modules) { OutBuffer buf; buf.writestring("[\n"); - for (int i = 0; i < modules->dim; i++) - { Module *m = (Module *)modules->data[i]; + for (size_t i = 0; i < modules->dim; i++) + { Module *m = modules->tdata()[i]; if (global.params.verbose) printf("json gen %s\n", m->toChars()); m->toJsonBuffer(&buf); @@ -64,7 +66,7 @@ void json_generate(Array *modules) char *arg = global.params.xfilename; if (!arg || !*arg) { // Generate lib file name from first obj name - char *n = (char *)global.params.objfiles->data[0]; + char *n = global.params.objfiles->tdata()[0]; n = FileName::name(n); FileName *fn = FileName::forceExt(n, global.json_ext); @@ -192,8 +194,8 @@ void Module::toJsonBuffer(OutBuffer *buf) buf->writestring(" : [\n"); size_t offset = buf->offset; - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = members->tdata()[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -211,13 +213,13 @@ void AttribDeclaration::toJsonBuffer(OutBuffer *buf) { //printf("AttribDeclaration::toJsonBuffer()\n"); - Array *d = include(NULL, NULL); + Dsymbols *d = include(NULL, NULL); if (d) { size_t offset = buf->offset; for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; + { Dsymbol *s = d->tdata()[i]; //printf("AttribDeclaration::toJsonBuffer %s\n", s->toChars()); if (offset != buf->offset) { buf->writestring(",\n"); @@ -259,6 +261,10 @@ void Declaration::toJsonBuffer(OutBuffer *buf) JsonProperty(buf, Pname, toChars()); JsonProperty(buf, Pkind, kind()); + + if (prot()) + JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); + if (type) JsonProperty(buf, Ptype, type->toChars()); @@ -285,8 +291,13 @@ void AggregateDeclaration::toJsonBuffer(OutBuffer *buf) JsonProperty(buf, Pname, toChars()); JsonProperty(buf, Pkind, kind()); + + if (prot()) + JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); + if (comment) JsonProperty(buf, Pcomment, (const char *)comment); + if (loc.linnum) JsonProperty(buf, Pline, loc.linnum); @@ -302,7 +313,7 @@ void AggregateDeclaration::toJsonBuffer(OutBuffer *buf) JsonString(buf, "interfaces"); buf->writestring(" : [\n"); size_t offset = buf->offset; - for (int i = 0; i < cd->interfaces_dim; i++) + for (size_t i = 0; i < cd->interfaces_dim; i++) { BaseClass *b = cd->interfaces[i]; if (offset != buf->offset) { buf->writestring(",\n"); @@ -320,8 +331,8 @@ void AggregateDeclaration::toJsonBuffer(OutBuffer *buf) JsonString(buf, Pmembers); buf->writestring(" : [\n"); size_t offset = buf->offset; - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = members->tdata()[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -344,6 +355,10 @@ void TemplateDeclaration::toJsonBuffer(OutBuffer *buf) JsonProperty(buf, Pname, toChars()); JsonProperty(buf, Pkind, kind()); + + if (prot()) + JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); + if (comment) JsonProperty(buf, Pcomment, (const char *)comment); @@ -353,8 +368,8 @@ void TemplateDeclaration::toJsonBuffer(OutBuffer *buf) JsonString(buf, Pmembers); buf->writestring(" : [\n"); size_t offset = buf->offset; - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = members->tdata()[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -374,9 +389,9 @@ void EnumDeclaration::toJsonBuffer(OutBuffer *buf) { if (members) { - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; s->toJsonBuffer(buf); buf->writestring(",\n"); } @@ -389,6 +404,10 @@ void EnumDeclaration::toJsonBuffer(OutBuffer *buf) JsonProperty(buf, Pname, toChars()); JsonProperty(buf, Pkind, kind()); + + if (prot()) + JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); + if (comment) JsonProperty(buf, Pcomment, (const char *)comment); @@ -403,8 +422,8 @@ void EnumDeclaration::toJsonBuffer(OutBuffer *buf) JsonString(buf, Pmembers); buf->writestring(" : [\n"); size_t offset = buf->offset; - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = members->tdata()[i]; if (offset != buf->offset) { buf->writestring(",\n"); offset = buf->offset; @@ -427,6 +446,9 @@ void EnumMember::toJsonBuffer(OutBuffer *buf) JsonProperty(buf, Pname, toChars()); JsonProperty(buf, Pkind, kind()); + if (prot()) + JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); + if (comment) JsonProperty(buf, Pcomment, (const char *)comment); diff --git a/dmd/json.h b/dmd/json.h index 8c271e61..1cf8bfab 100644 --- a/dmd/json.h +++ b/dmd/json.h @@ -16,9 +16,9 @@ #pragma once #endif /* __DMC__ */ -struct Array; +#include "arraytypes.h" -void json_generate(Array *); +void json_generate(Modules *); #endif /* DMD_JSON_H */ diff --git a/dmd/lexer.c b/dmd/lexer.c index 963384f3..acfa45a1 100644 --- a/dmd/lexer.c +++ b/dmd/lexer.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -106,7 +106,7 @@ void Token::print() const char *Token::toChars() { const char *p; - static char buffer[3 + 3 * sizeof(value) + 1]; + static char buffer[3 + 3 * sizeof(float80value) + 1]; p = buffer; switch (value) @@ -302,29 +302,22 @@ Lexer::Lexer(Module *mod, void Lexer::error(const char *format, ...) { - if (mod && !global.gag) - { - char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - va_list ap; va_start(ap, format); - vfprintf(stdmsg, format, ap); + verror(loc, format, ap); va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); - } - global.errors++; } void Lexer::error(Loc loc, const char *format, ...) { + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end(ap); +} + +void Lexer::verror(Loc loc, const char *format, va_list ap) +{ if (mod && !global.gag) { char *p = loc.toChars(); @@ -332,10 +325,7 @@ void Lexer::error(Loc loc, const char *format, ...) fprintf(stdmsg, "%s: ", p); mem.free(p); - va_list ap; - va_start(ap, format); vfprintf(stdmsg, format, ap); - va_end(ap); fprintf(stdmsg, "\n"); fflush(stdmsg); @@ -343,6 +333,10 @@ void Lexer::error(Loc loc, const char *format, ...) if (global.errors >= 20) // moderate blizzard of cascading messages fatal(); } + else + { + global.gaggedErrors++; + } global.errors++; } @@ -732,7 +726,6 @@ void Lexer::scan(Token *t) t->ustring = (unsigned char *)timestamp; Lstr: t->value = TOKstring; - Llen: t->postfix = 0; t->len = strlen((char *)t->ustring); } @@ -743,7 +736,7 @@ void Lexer::scan(Token *t) for (const char *p = global.version + 1; 1; p++) { char c = *p; - if (isdigit(c)) + if (isdigit((unsigned char)c)) minor = minor * 10 + c - '0'; else if (c == '.') { major = minor; @@ -1985,7 +1978,6 @@ TOK Lexer::number(Token *t) }; enum FLAGS flags = FLAGS_decimal; - int i; int base; unsigned c; unsigned char *start; @@ -2230,7 +2222,7 @@ done: p += 2, r = 16; else if (p[1] == 'b' || p[1] == 'B') p += 2, r = 2; - else if (isdigit(p[1])) + else if (isdigit((unsigned char)p[1])) p += 1, r = 8; } @@ -2265,6 +2257,7 @@ done: } // Parse trailing 'u', 'U', 'l' or 'L' in any combination + const unsigned char *psuffix = p; while (1) { unsigned char f; @@ -2291,6 +2284,12 @@ done: break; } +#if DMDV2 + if (state == STATE_octal && n >= 8 && !global.params.useDeprecated) + error("octal literals 0%llo%.*s are deprecated, use std.conv.octal!%llo%.*s instead", + n, p - psuffix, psuffix, n, p - psuffix, psuffix); +#endif + switch (flags) { case 0: @@ -2571,7 +2570,10 @@ void Lexer::pragma() scan(&tok); if (tok.value == TOKint32v || tok.value == TOKint64v) - linnum = tok.uns64value - 1; + { linnum = tok.uns64value - 1; + if (linnum != tok.uns64value - 1) + error("line number out of range"); + } else goto Lerr; @@ -3038,6 +3040,8 @@ void Lexer::initKeywords() enum TOK v; unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]); + stringtable.init(); + if (global.params.Dversion == 1) nkeywords -= 2; diff --git a/dmd/lexer.h b/dmd/lexer.h index a598b69a..ccb3a799 100644 --- a/dmd/lexer.h +++ b/dmd/lexer.h @@ -210,7 +210,6 @@ enum TOK case TOKcomplex32: t = Type::tcomplex32; goto LabelX; \ case TOKcomplex64: t = Type::tcomplex64; goto LabelX; \ case TOKcomplex80: t = Type::tcomplex80; goto LabelX; \ - case TOKbit: t = Type::tbit; goto LabelX; \ case TOKbool: t = Type::tbool; goto LabelX; \ case TOKchar: t = Type::tchar; goto LabelX; \ case TOKwchar: t = Type::twchar; goto LabelX; \ @@ -305,6 +304,7 @@ struct Lexer TOK inreal(Token *t); void error(const char *format, ...) IS_PRINTF(2); void error(Loc loc, const char *format, ...) IS_PRINTF(3); + void verror(Loc loc, const char *format, va_list ap); void pragma(); unsigned decodeUTF(); void getDocComment(Token *t, unsigned lineComment); diff --git a/dmd/macro.h b/dmd/macro.h index cf99ab81..7c6d4928 100644 --- a/dmd/macro.h +++ b/dmd/macro.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -19,8 +19,9 @@ #include "root.h" -class Macro +struct Macro { + private: Macro *next; // next in list unsigned char *name; // macro name diff --git a/dmd/mangle.c b/dmd/mangle.c index ca26961c..39549179 100644 --- a/dmd/mangle.c +++ b/dmd/mangle.c @@ -24,7 +24,7 @@ #include "id.h" #include "module.h" -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS char *cpp_mangle(Dsymbol *s); #endif @@ -34,7 +34,7 @@ char *mangle(Declaration *sthis) char *id; Dsymbol *s; - //printf("::mangle(%s)\n", sthis->toChars()); + //printf("::mangle(%s), type %s\n", sthis->toChars(), sthis->type->toChars()); s = sthis; do { @@ -122,7 +122,7 @@ char *Declaration::mangle() return ident->toChars(); case LINKcpp: -#if DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS) +#if DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) return cpp_mangle(this); #else // Windows C++ mangling is done by C++ back end diff --git a/dmd/mars.c b/dmd/mars.c index c7e8db93..564dc331 100644 --- a/dmd/mars.c +++ b/dmd/mars.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -36,6 +36,21 @@ #include "lexer.h" #include "json.h" +#if WINDOWS_SEH +#include +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); +#endif + + +int response_expand(int *pargc, char ***pargv); +void browse(const char *url); +void getenv_setargv(const char *envvar, int *pargc, char** *pargv); + +void obj_start(char *srcfile); +void obj_end(Library *library, File *objfile); + +void printCtfePerformanceStats(); + Global global; Global::Global() @@ -57,9 +72,9 @@ Global::Global() obj_ext_alt = "obj"; #endif - copyright = "Copyright (c) 1999-2010 by Digital Mars and Tomas Lindquist Olsen"; + copyright = "Copyright (c) 1999-2011 by Digital Mars and Tomas Lindquist Olsen"; written = "written by Walter Bright and Tomas Lindquist Olsen"; - version = "v1.067"; + version = "v1.072"; ldc_version = "LDC trunk"; llvm_version = "LLVM 3.0"; global.structalign = 8; @@ -72,6 +87,24 @@ Global::Global() // may run before this one. } +unsigned Global::startGagging() +{ + ++gag; + return gaggedErrors; +} + +bool Global::endGagging(unsigned oldGagged) +{ + bool anyErrs = (gaggedErrors != oldGagged); + --gag; + // Restore the original state of gagged errors; set total errors + // to be original errors + new ungagged errors. + errors -= (gaggedErrors - oldGagged); + gaggedErrors = oldGagged; + return anyErrs; +} + + char *Loc::toChars() const { OutBuffer buf; @@ -132,6 +165,11 @@ void verror(Loc loc, const char *format, va_list ap) vfprintf(stdmsg, format, ap); fprintf(stdmsg, "\n"); fflush(stdmsg); +//halt(); + } + else + { + global.gaggedErrors++; } global.errors++; } @@ -187,7 +225,6 @@ void halt() #endif } - /*********************************** * Parse and append contents of environment variable envvar * to argc and argv[]. @@ -209,11 +246,11 @@ void getenv_setargv(const char *envvar, int *pargc, char** *pargv) env = mem.strdup(env); // create our own writable copy int argc = *pargc; - Array *argv = new Array(); + Strings *argv = new Strings(); argv->setDim(argc); - int argc_left = 0; - for (int i = 0; i < argc; i++) { + size_t argc_left = 0; + for (size_t i = 0; i < argc; i++) { if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) { // HACK: set flag to indicate we saw '-run' here global.params.run = true; @@ -231,7 +268,7 @@ void getenv_setargv(const char *envvar, int *pargc, char** *pargv) argv->push((char*)""); argc++; - int j = 1; // leave argv[0] alone + size_t j = 1; // leave argv[0] alone while (1) { int wildcard = 1; // do wildcard expansion @@ -310,5 +347,5 @@ Ldone: argv->data[argc++] = (void *)(*pargv)[i]; *pargc = argc; - *pargv = (char **)argv->data; + *pargv = argv->tdata(); } diff --git a/dmd/mars.h b/dmd/mars.h index 9ae013f1..f02a821a 100644 --- a/dmd/mars.h +++ b/dmd/mars.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -29,6 +29,7 @@ Macros defined by the compiler, not the code: __DMC__ Digital Mars compiler _MSC_VER Microsoft compiler __GNUC__ Gnu compiler + __clang__ Clang compiler Host operating system: _WIN32 Microsoft NT, Windows 95, Windows 98, Win32s, @@ -37,6 +38,7 @@ Macros defined by the compiler, not the code: linux Linux __APPLE__ Mac OSX __FreeBSD__ FreeBSD + __OpenBSD__ OpenBSD __sun&&__SVR4 Solaris, OpenSolaris (yes, both macros are necessary) For the target systems, there are the target operating system and @@ -47,6 +49,7 @@ the target object file format: TARGET_LINUX Covers 32 and 64 bit linux TARGET_OSX Covers 32 and 64 bit Mac OSX TARGET_FREEBSD Covers 32 and 64 bit FreeBSD + TARGET_OPENBSD Covers 32 and 64 bit OpenBSD TARGET_SOLARIS Covers 32 and 64 bit Solaris TARGET_NET Covers .Net @@ -55,7 +58,7 @@ the target object file format: Target object module format: OMFOBJ Intel Object Module Format, used on Windows - ELFOBJ Elf Object Module Format, used on linux, FreeBSD and Solaris + ELFOBJ Elf Object Module Format, used on linux, FreeBSD, OpenBSD and Solaris MACHOBJ Mach-O Object Module Format, used on Mac OSX There are currently no macros for byte endianness order. @@ -81,12 +84,20 @@ the target object file format: #ifndef IS_PRINTF # ifdef __GNUC__ -# define IS_PRINTF(FMTARG) __attribute((__format__ (__printf__, (FMTARG), (FMTARG)+1) )) +# define IS_PRINTF(FMTARG) __attribute__((__format__ (__printf__, (FMTARG), (FMTARG)+1) )) # else # define IS_PRINTF(FMTARG) # endif #endif +#ifndef IS_VPRINTF +# ifdef __GNUC__ +# define IS_VPRINTF(FMTARG) __attribute__((__format__ (__printf__, (FMTARG), 0) )) +# else +# define IS_VPRINTF(FMTARG) +# endif +#endif + #ifdef IN_GCC /* Changes for the GDC compiler by David Friedman */ #endif @@ -99,19 +110,23 @@ the target object file format: #define MODULEINFO_IS_STRUCT DMDV2 // if ModuleInfo is a struct rather than a class // Set if C++ mangling is done by the front end -#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS)) +#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)) -/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD and +/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD, TARGET_OPENBSD and * TARGET_SOLARIS, which are * set on the command line via the compiler makefile. */ #if _WIN32 +#ifndef TARGET_WINDOS #define TARGET_WINDOS 1 // Windows dmd generates Windows targets -#define OMFOBJ 1 +#endif +#ifndef OMFOBJ +#define OMFOBJ TARGET_WINDOS +#endif #endif -#if TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS +#if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS #ifndef ELFOBJ #define ELFOBJ 1 #endif @@ -124,7 +139,6 @@ the target object file format: #endif -struct Array; struct OutBuffer; // LDC @@ -158,6 +172,11 @@ enum OS typedef unsigned char ubyte; +// Can't include arraytypes.h here, need to declare these directly. +template struct ArrayBase; +//typedef ArrayBase Identifiers; +typedef ArrayBase Strings; + // Put command line switches in here struct Param { @@ -171,6 +190,7 @@ struct Param char optimizeLevel; // optimization level #endif char vtls; // identify thread local variables +// KN Start merge conflict ARCH cpu; // target CPU OS os; // target OS bool is64bit; // generate 64 bit code @@ -186,20 +206,51 @@ struct Param bool useInline; // inline expand functions ubyte warnings; // enable warnings ubyte Dversion; // D version number +// KN End merge conflict +#if 0 + char symdebug; // insert debug symbolic information + char alwaysframe; // always emit standard stack frame + char optimize; // run optimizer + char map; // generate linker .map file + char cpu; // target CPU + char is64bit; // generate 64 bit code + char isLinux; // generate code for linux + char isOSX; // generate code for Mac OSX + char isWindows; // generate code for Windows + char isFreeBSD; // generate code for FreeBSD + char isOPenBSD; // generate code for OpenBSD + char isSolaris; // generate code for Solaris + char scheduler; // which scheduler to use + char useDeprecated; // allow use of deprecated features + char useAssert; // generate runtime code for assert()'s + char useInvariants; // generate class invariant checks + char useIn; // generate precondition checks + char useOut; // generate postcondition checks + char useArrayBounds; // 0: no array bounds checks + // 1: array bounds checks for safe functions only + // 2: array bounds checks for all functions + char noboundscheck; // no array bounds checking at all + char useSwitchError; // check for switches without a default + char useUnitTests; // generate unittest code + char useInline; // inline expand functions + char release; // build release version + char preservePaths; // !=0 means don't strip path from source file + char warnings; // 0: enable warnings +#endif // 1: warnings as errors // 2: informational warnings (no errors) char safe; // enforce safe memory model char *argv0; // program name - Array *imppath; // array of char*'s of where to look for import modules - Array *fileImppath; // array of char*'s of where to look for file import modules - char *objdir; // .obj file output directory + Strings *imppath; // array of char*'s of where to look for import modules + Strings *fileImppath; // array of char*'s of where to look for file import modules + char *objdir; // .obj/.lib file output directory char *objname; // .obj file output name bool doDocComments; // process embedded documentation comments char *docdir; // write documentation file to docdir directory char *docname; // write documentation file to docname - Array *ddocfiles; // macro include files for Ddoc + Strings *ddocfiles; // macro include files for Ddoc bool doHdrGeneration; // process embedded documentation comments char *hdrdir; // write 'header' file to docdir directory @@ -209,15 +260,15 @@ struct Param char *xfilename; // write JSON file to xfilename unsigned debuglevel; // debug level - Array *debugids; // debug identifiers + Strings *debugids; // debug identifiers unsigned versionlevel; // version level - Array *versionids; // version identifiers + Strings *versionids; // version identifiers bool dump_source; - Array *defaultlibnames; // default libraries for non-debug builds - Array *debuglibnames; // default libraries for debug builds + Strings *defaultlibnames; // default libraries for non-debug builds + Strings *debuglibnames; // default libraries for debug builds char *moduleDepsFile; // filename for deps output OutBuffer *moduleDeps; // contents to be written to deps file @@ -235,9 +286,9 @@ struct Param bool run; // run resulting executable // Linker stuff - Array *objfiles; - Array *linkswitches; - Array *libfiles; + Strings *objfiles; + Strings *linkswitches; + Strings *libfiles; char *deffile; char *resfile; char *exefile; @@ -281,8 +332,8 @@ struct Global const char *map_ext; // for .map files const char *copyright; const char *written; - Array *path; // Array of char*'s which form the import lookup path - Array *filePath; // Array of char*'s which form the file import lookup path + Strings *path; // Array of char*'s which form the import lookup path + Strings *filePath; // Array of char*'s which form the file import lookup path int structalign; const char *version; char *ldc_version; @@ -292,6 +343,15 @@ struct Global unsigned errors; // number of errors reported so far unsigned warnings; // number of warnings reported so far unsigned gag; // !=0 means gag reporting of errors & warnings + unsigned gaggedErrors; // number of errors reported while gagged + + // Start gagging. Return the current number of gagged errors + unsigned startGagging(); + + /* End gagging, restoring the old gagged state. + * Return true if errors occured while gagged. + */ + bool endGagging(unsigned oldGagged); Global(); }; diff --git a/dmd/module.c b/dmd/module.c index deb89b6f..9c7e89b7 100644 --- a/dmd/module.c +++ b/dmd/module.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -64,9 +64,9 @@ ClassDeclaration *Module::moduleinfo; Module *Module::rootModule; DsymbolTable *Module::modules; -Array Module::amodules; +Modules Module::amodules; -Array Module::deferred; // deferred Dsymbol's needing semantic() run on them +Dsymbols Module::deferred; // deferred Dsymbol's needing semantic() run on them unsigned Module::dprogress; void Module::init() @@ -78,6 +78,8 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen : Package(ident) { FileName *srcfilename; + FileName *objfilename; + FileName *symfilename; // printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars()); this->arg = filename; @@ -301,7 +303,7 @@ const char *Module::kind() return "module"; } -Module *Module::load(Loc loc, Array *packages, Identifier *ident) +Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) { Module *m; char *filename; @@ -315,10 +317,9 @@ Module *Module::load(Loc loc, Array *packages, Identifier *ident) if (packages && packages->dim) { OutBuffer buf; - int i; - for (i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; + for (size_t i = 0; i < packages->dim; i++) + { Identifier *pid = packages->tdata()[i]; buf.writestring(pid->toChars()); #if _WIN32 @@ -355,7 +356,7 @@ Module *Module::load(Loc loc, Array *packages, Identifier *ident) { for (size_t i = 0; i < global.path->dim; i++) { - char *p = (char *)global.path->data[i]; + char *p = (*global.path)[i]; char *n = FileName::combine(p, sdi); if (FileName::exists(n)) { result = n; @@ -379,7 +380,7 @@ Module *Module::load(Loc loc, Array *packages, Identifier *ident) if (packages) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; + { Identifier *pid = packages->tdata()[i]; printf("%s.", pid->toChars()); } } @@ -406,10 +407,10 @@ void Module::read(Loc loc) */ if (global.path) { - for (int i = 0; i < global.path->dim; i++) + for (size_t i = 0; i < global.path->dim; i++) { - char *p = (char *)global.path->data[i]; - fprintf(stdmsg, "import path[%d] = %s\n", i, p); + char *p = global.path->tdata()[i]; + fprintf(stdmsg, "import path[%zd] = %s\n", i, p); } } else @@ -421,7 +422,7 @@ void Module::read(Loc loc) inline unsigned readwordLE(unsigned short *p) { -#if __I86__ +#if LITTLE_ENDIAN return *p; #else return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0]; @@ -435,7 +436,7 @@ inline unsigned readwordBE(unsigned short *p) inline unsigned readlongLE(unsigned *p) { -#if __I86__ +#if LITTLE_ENDIAN return *p; #else return ((unsigned char *)p)[0] | @@ -671,6 +672,11 @@ void Module::parse() #endif p.nextToken(); members = p.parseModule(); + + ::free(srcfile->buffer); + srcfile->buffer = NULL; + srcfile->len = 0; + md = p.md; numlines = p.loc.linnum; @@ -730,7 +736,7 @@ void Module::importAll(Scope *prevsc) // Add import of "object" if this module isn't "object" if (ident != Id::object) { - if (members->dim == 0 || ((Dsymbol *)members->data[0])->ident != Id::object) + if (members->dim == 0 || ((*members)[0])->ident != Id::object) { Import *im = new Import(0, NULL, Id::object, NULL, 0); members->shift(im); @@ -741,9 +747,9 @@ void Module::importAll(Scope *prevsc) { // Add all symbols into module's symbol table symtab = new DsymbolTable(); - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; s->addMember(NULL, sc->scopesym, 1); } } @@ -755,14 +761,14 @@ void Module::importAll(Scope *prevsc) * before any semantic() on any of them. */ setScope(sc); // remember module scope for semantic - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = members->tdata()[i]; s->setScope(sc); } - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; s->importAll(sc); } @@ -770,7 +776,7 @@ void Module::importAll(Scope *prevsc) sc->pop(); // 2 pops because Scope::createGlobal() created 2 } -void Module::semantic(Scope *unused_sc) +void Module::semantic() { if (semanticstarted) return; @@ -799,7 +805,7 @@ void Module::semantic(Scope *unused_sc) // Add all symbols into module's symbol table symtab = new DsymbolTable(); - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->addMember(NULL, sc->scopesym, 1); } @@ -809,23 +815,23 @@ void Module::semantic(Scope *unused_sc) * If this works out well, it can be extended to all modules * before any semantic() on any of them. */ - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->setScope(sc); } #endif // Do semantic() on members that don't depend on others - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = members->tdata()[i]; //printf("\tModule('%s'): '%s'.semantic0()\n", toChars(), s->toChars()); s->semantic0(sc); } // Pass 1 semantic routines: do public side of the definition - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = members->tdata()[i]; //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); s->semantic(sc); @@ -840,14 +846,13 @@ void Module::semantic(Scope *unused_sc) //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); } -void Module::semantic2(Scope* unused_sc) -{ int i; - +void Module::semantic2() +{ if (deferred.dim) { - for (int i = 0; i < deferred.dim; i++) + for (size_t i = 0; i < deferred.dim; i++) { - Dsymbol *sd = (Dsymbol *)deferred.data[i]; + Dsymbol *sd = deferred.tdata()[i]; sd->error("unable to resolve forward reference in definition"); } @@ -866,10 +871,10 @@ void Module::semantic2(Scope* unused_sc) //printf("Module = %p\n", sc.scopesym); // Pass 2 semantic routines: do initializers and function bodies - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s; - s = (Dsymbol *)members->data[i]; + s = members->tdata()[i]; s->semantic2(sc); } @@ -879,9 +884,8 @@ void Module::semantic2(Scope* unused_sc) //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); } -void Module::semantic3(Scope* unused_sc) -{ int i; - +void Module::semantic3() +{ //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent); if (semanticstarted >= 3) return; @@ -895,10 +899,10 @@ void Module::semantic3(Scope* unused_sc) //printf("Module = %p\n", sc.scopesym); // Pass 3 semantic routines: do initializers and function bodies - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s; - s = (Dsymbol *)members->data[i]; + s = members->tdata()[i]; //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars()); s->semantic3(sc); } @@ -920,8 +924,8 @@ void Module::inlineScan() // gets imported, it is unaffected by context. //printf("Module = %p\n", sc.scopesym); - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = members->tdata()[i]; //if (global.params.verbose) //printf("inline scan symbol %s\n", s->toChars()); @@ -945,8 +949,8 @@ void Module::gensymfile() buf.printf("// Sym file generated from '%s'", srcfile->toChars()); buf.writenl(); - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = members->tdata()[i]; s->toCBuffer(&buf, &hgs); } @@ -1006,8 +1010,8 @@ Dsymbol *Module::symtabInsert(Dsymbol *s) void Module::clearCache() { - for (int i = 0; i < amodules.dim; i++) - { Module *m = (Module *)amodules.data[i]; + for (size_t i = 0; i < amodules.dim; i++) + { Module *m = amodules.tdata()[i]; m->searchCacheIdent = NULL; } } @@ -1019,9 +1023,9 @@ void Module::clearCache() void Module::addDeferredSemantic(Dsymbol *s) { // Don't add it if it is already there - for (int i = 0; i < deferred.dim; i++) + for (size_t i = 0; i < deferred.dim; i++) { - Dsymbol *sd = (Dsymbol *)deferred.data[i]; + Dsymbol *sd = deferred.tdata()[i]; if (sd == s) return; @@ -1066,10 +1070,10 @@ void Module::runDeferredSemantic() todo = (Dsymbol **)alloca(len * sizeof(Dsymbol *)); assert(todo); } - memcpy(todo, deferred.data, len * sizeof(Dsymbol *)); + memcpy(todo, deferred.tdata(), len * sizeof(Dsymbol *)); deferred.setDim(0); - for (int i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) { Dsymbol *s = todo[i]; @@ -1093,13 +1097,13 @@ int Module::imports(Module *m) //printf("%s Module::imports(%s)\n", toChars(), m->toChars()); int aimports_dim = aimports.dim; #if 0 - for (int i = 0; i < aimports.dim; i++) + for (size_t i = 0; i < aimports.dim; i++) { Module *mi = (Module *)aimports.data[i]; printf("\t[%d] %s\n", i, mi->toChars()); } #endif - for (int i = 0; i < aimports.dim; i++) - { Module *mi = (Module *)aimports.data[i]; + for (size_t i = 0; i < aimports.dim; i++) + { Module *mi = aimports.tdata()[i]; if (mi == m) return TRUE; if (!mi->insearch) @@ -1122,16 +1126,16 @@ int Module::selfImports() //printf("Module::selfImports() %s\n", toChars()); if (!selfimports) { - for (int i = 0; i < amodules.dim; i++) - { Module *mi = (Module *)amodules.data[i]; + for (size_t i = 0; i < amodules.dim; i++) + { Module *mi = amodules.tdata()[i]; //printf("\t[%d] %s\n", i, mi->toChars()); mi->insearch = 0; } selfimports = imports(this) + 1; - for (int i = 0; i < amodules.dim; i++) - { Module *mi = (Module *)amodules.data[i]; + for (size_t i = 0; i < amodules.dim; i++) + { Module *mi = amodules.tdata()[i]; //printf("\t[%d] %s\n", i, mi->toChars()); mi->insearch = 0; } @@ -1142,7 +1146,7 @@ int Module::selfImports() /* =========================== ModuleDeclaration ===================== */ -ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id) +ModuleDeclaration::ModuleDeclaration(Identifiers *packages, Identifier *id) { this->packages = packages; this->id = id; @@ -1151,12 +1155,11 @@ ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id) char *ModuleDeclaration::toChars() { OutBuffer buf; - int i; if (packages && packages->dim) { - for (i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; + for (size_t i = 0; i < packages->dim; i++) + { Identifier *pid = packages->tdata()[i]; buf.writestring(pid->toChars()); buf.writeByte('.'); @@ -1181,7 +1184,7 @@ const char *Package::kind() } -DsymbolTable *Package::resolve(Array *packages, Dsymbol **pparent, Package **ppkg) +DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg) { DsymbolTable *dst = Module::modules; Dsymbol *parent = NULL; @@ -1191,10 +1194,9 @@ DsymbolTable *Package::resolve(Array *packages, Dsymbol **pparent, Package **ppk *ppkg = NULL; if (packages) - { int i; - - for (i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; + { + for (size_t i = 0; i < packages->dim; i++) + { Identifier *pid = packages->tdata()[i]; Dsymbol *p; p = dst->lookup(pid); diff --git a/dmd/module.h b/dmd/module.h index 5ed79b72..4384d4eb 100644 --- a/dmd/module.h +++ b/dmd/module.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -51,7 +51,7 @@ struct Package : ScopeDsymbol Package(Identifier *ident); const char *kind(); - static DsymbolTable *resolve(Array *packages, Dsymbol **pparent, Package **ppkg); + static DsymbolTable *resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg); Package *isPackage() { return this; } @@ -62,8 +62,8 @@ struct Module : Package { static Module *rootModule; static DsymbolTable *modules; // symbol table of all modules - static Array amodules; // array of all modules - static Array deferred; // deferred Dsymbol's needing semantic() run on them + static Modules amodules; // array of all modules + static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them static unsigned dprogress; // progress resolving the deferred list static void init(); @@ -104,19 +104,19 @@ struct Module : Package // i.e. a module that will be taken all the // way to an object file - Array *decldefs; // top level declarations for this Module + Dsymbols *decldefs; // top level declarations for this Module - Array aimports; // all imported modules + Modules aimports; // all imported modules ModuleInfoDeclaration *vmoduleinfo; unsigned debuglevel; // debug level - Array *debugids; // debug identifiers - Array *debugidsNot; // forward referenced debug identifiers + Strings *debugids; // debug identifiers + Strings *debugidsNot; // forward referenced debug identifiers unsigned versionlevel; // version level - Array *versionids; // version identifiers - Array *versionidsNot; // forward referenced version identifiers + Strings *versionids; // version identifiers + Strings *versionidsNot; // forward referenced version identifiers Macro *macrotable; // document comment macros struct Escape *escapetable; // document comment escapes @@ -129,7 +129,7 @@ struct Module : Package Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen); ~Module(); - static Module *load(Loc loc, Array *packages, Identifier *ident); + static Module *load(Loc loc, Identifiers *packages, Identifier *ident); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toJsonBuffer(OutBuffer *buf); @@ -143,13 +143,13 @@ struct Module : Package void parse(); // syntactic parse #endif void importAll(Scope *sc); - void semantic(Scope* unused_sc = NULL); // semantic analysis - void semantic2(Scope* unused_sc = NULL); // pass 2 semantic analysis - void semantic3(Scope* unused_sc = NULL); // pass 3 semantic analysis + void semantic(); // semantic analysis + void semantic2(); // pass 2 semantic analysis + void semantic3(); // pass 3 semantic analysis void inlineScan(); // scan for functions to inline -#ifdef _DH + void setHdrfile(); // set hdrfile member void genhdrfile(); // generate D import file -#endif + void genobjfile(int multiobj); // void gensymfile(); void gendocfile(); int needModuleInfo(); @@ -215,10 +215,10 @@ struct Module : Package struct ModuleDeclaration { Identifier *id; - Array *packages; // array of Identifier's representing packages + Identifiers *packages; // array of Identifier's representing packages bool safe; - ModuleDeclaration(Array *packages, Identifier *id); + ModuleDeclaration(Identifiers *packages, Identifier *id); char *toChars(); }; diff --git a/dmd/mtype.c b/dmd/mtype.c index 751831bc..40810cd9 100644 --- a/dmd/mtype.c +++ b/dmd/mtype.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -52,7 +52,6 @@ #include "import.h" #include "aggregate.h" #include "hdrgen.h" -#include "doc.h" #if IN_LLVM //#include "gen/tollvm.h" @@ -83,7 +82,7 @@ int PTRSIZE = 4; int REALSIZE = 16; int REALPAD = 6; int REALALIGNSIZE = 16; -#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS +#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS int REALSIZE = 12; int REALPAD = 2; int REALALIGNSIZE = 4; @@ -119,6 +118,7 @@ ClassDeclaration *Type::typeinfodelegate; ClassDeclaration *Type::typeinfotypelist; Type *Type::tvoidptr; +Type *Type::tstring; Type *Type::basic[TMAX]; unsigned char Type::mangleChar[TMAX]; StringTable Type::stringtable; @@ -189,9 +189,8 @@ void Type::init(Ir* _sir) #else void Type::init() #endif -{ int i; - int j; - +{ + stringtable.init(); Lexer::initKeywords(); mangleChar[Tarray] = 'A'; @@ -242,9 +241,9 @@ void Type::init() mangleChar[Tslice] = '@'; mangleChar[Treturn] = '@'; - for (i = 0; i < TMAX; i++) + for (size_t i = 0; i < TMAX; i++) { if (!mangleChar[i]) - fprintf(stdmsg, "ty = %d\n", i); + fprintf(stdmsg, "ty = %zd\n", i); assert(mangleChar[i]); } @@ -257,11 +256,12 @@ void Type::init() Tbool, Tascii, Twchar, Tdchar }; - for (i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++) + for (size_t i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++) basic[basetab[i]] = new TypeBasic(basetab[i]); basic[Terror] = new TypeError(); tvoidptr = tvoid->pointerTo(); + tstring = tchar->arrayOf(); // LDC sir = _sir; @@ -321,8 +321,22 @@ Type *Type::semantic(Loc loc, Scope *sc) return merge(); } +Type *Type::trySemantic(Loc loc, Scope *sc) +{ + //printf("+trySemantic(%s) %d\n", toChars(), global.errors); + unsigned errors = global.startGagging(); + Type *t = semantic(loc, sc); + if (global.endGagging(errors)) // if any errors happened + { + t = NULL; + } + //printf("-trySemantic(%s) %d\n", toChars(), global.errors); + return t; +} Type *Type::pointerTo() { + if (ty == Terror) + return this; if (!pto) { Type *t; @@ -334,6 +348,8 @@ Type *Type::pointerTo() Type *Type::referenceTo() { + if (ty == Terror) + return this; if (!rto) { Type *t; @@ -345,6 +361,8 @@ Type *Type::referenceTo() Type *Type::arrayOf() { + if (ty == Terror) + return this; if (!arrayof) { Type *t; @@ -446,6 +464,7 @@ void Type::toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod) Type *Type::merge() { + if (ty == Terror) return this; //printf("merge(%s)\n", toChars()); Type *t = this; assert(t); @@ -664,6 +683,8 @@ Expression *Type::getProperty(Loc loc, Identifier *ident) { if (ty == Tvoid) error(loc, "void does not have an initializer"); + if (ty == Tfunction) + error(loc, "function does not have an initializer"); e = defaultInit(loc); } else if (ident == Id::mangleof) @@ -1013,12 +1034,6 @@ TypeBasic::TypeBasic(TY ty) break; - case Tbit: d = Token::toChars(TOKbit); - c = "bit"; - flags |= TFLAGSintegral | TFLAGSunsigned; -assert(0); - break; - case Tbool: d = "bool"; c = d; flags |= TFLAGSintegral | TFLAGSunsigned; @@ -1104,7 +1119,6 @@ d_uns64 TypeBasic::size(Loc loc) size = 1; break; - case Tbit: size = 1; break; case Tbool: size = 1; break; case Tascii: size = 1; break; case Twchar: size = 2; break; @@ -1120,20 +1134,47 @@ d_uns64 TypeBasic::size(Loc loc) unsigned TypeBasic::alignsize() { +#if IN_LLVM if (ty == Tvoid) return 1; return GetTypeAlignment(sir, this); -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +#else + unsigned sz; + + switch (ty) + { + case Tfloat80: + case Timaginary80: + case Tcomplex80: + sz = REALALIGNSIZE; + break; + +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS case Tint64: case Tuns64: + sz = global.params.is64bit ? 8 : 4; + break; + case Tfloat64: case Timaginary64: + sz = global.params.is64bit ? 8 : 4; + break; + case Tcomplex32: - case Tcomplex64: sz = 4; break; + + case Tcomplex64: + sz = global.params.is64bit ? 8 : 4; + break; #endif + default: + sz = size(0); + break; + } + return sz; +#endif } #if IN_LLVM @@ -1168,7 +1209,6 @@ Expression *TypeBasic::getProperty(Loc loc, Identifier *ident) case Tuns32: ivalue = 0xFFFFFFFFUL; goto Livalue; case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFLL; goto Livalue; case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFULL; goto Livalue; - case Tbit: ivalue = 1; goto Livalue; case Tbool: ivalue = 1; goto Livalue; case Tchar: ivalue = 0xFF; goto Livalue; case Twchar: ivalue = 0xFFFFUL; goto Livalue; @@ -1197,7 +1237,6 @@ Expression *TypeBasic::getProperty(Loc loc, Identifier *ident) case Tuns32: ivalue = 0; goto Livalue; case Tint64: ivalue = (-9223372036854775807LL-1LL); goto Livalue; case Tuns64: ivalue = 0; goto Livalue; - case Tbit: ivalue = 0; goto Livalue; case Tbool: ivalue = 0; goto Livalue; case Tchar: ivalue = 0; goto Livalue; case Twchar: ivalue = 0; goto Livalue; @@ -1378,7 +1417,7 @@ Lfvalue: cvalue.re = fvalue; cvalue.im = fvalue; #endif - //for (int i = 0; i < 20; i++) + //for (size_t i = 0; i < 20; i++) // printf("%02x ", ((unsigned char *)&cvalue)[i]); //printf("\n"); e = new ComplexExp(loc, cvalue, this); @@ -1519,7 +1558,7 @@ int TypeBasic::isZeroInit(Loc loc) int TypeBasic::isbit() { - return (ty == Tbit); + return 0; } int TypeBasic::isintegral() @@ -1816,13 +1855,6 @@ d_uns64 TypeSArray::size(Loc loc) if (!dim) return Type::size(loc); sz = dim->toInteger(); - if (next->toBasetype()->ty == Tbit) // if array of bits - { - if (sz + 31 < sz) - goto Loverflow; - sz = ((sz + 31) & ~31) / 8; // size in bytes, rounded up to 32 bit dwords - } - else { dinteger_t n, n2; n = next->size(); @@ -1902,7 +1934,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol sc = sc->pop(); if (d >= td->objects->dim) - { error(loc, "tuple index %ju exceeds %u", d, td->objects->dim); + { error(loc, "tuple index %ju exceeds length %u", d, td->objects->dim); goto Ldefault; } Object *o = (Object *)td->objects->data[(size_t)d]; @@ -1974,7 +2006,10 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) if (dim) { dinteger_t n, n2; + int errors = global.errors; dim = semanticLength(sc, tbn, dim); + if (errors != global.errors) + goto Lerror; dim = dim->optimize(WANTvalue | WANTinterpret); if (sc && sc->parameterSpecialization && dim->op == TOKvar && @@ -1990,6 +2025,9 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) dim = dim->optimize(WANTvalue); dinteger_t d2 = dim->toInteger(); + if (dim->op == TOKerror) + goto Lerror; + if (d1 != d2) goto Loverflow; @@ -2014,7 +2052,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) { Loverflow: error(loc, "index %jd overflow for static array", d1); - dim = new IntegerExp(0, 1, tsize_t); + goto Lerror; } } } @@ -2028,20 +2066,24 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) if (d >= tt->arguments->dim) { error(loc, "tuple index %ju exceeds %u", d, tt->arguments->dim); - return Type::terror; + goto Lerror; } - Parameter *arg = (Parameter *)tt->arguments->data[(size_t)d]; + Parameter *arg = tt->arguments->tdata()[(size_t)d]; return arg->type; } case Tfunction: case Tnone: error(loc, "can't have array of %s", tbn->toChars()); - tbn = next = tint32; - break; + goto Lerror; } if (tbn->isscope()) - error(loc, "cannot have array of scope %s", tbn->toChars()); + { error(loc, "cannot have array of auto %s", tbn->toChars()); + goto Lerror; + } return merge(); + +Lerror: + return Type::terror; } void TypeSArray::toDecoBuffer(OutBuffer *buf, bool mangle) @@ -2169,6 +2211,17 @@ Expression *TypeSArray::toExpression() int TypeSArray::hasPointers() { + /* Don't want to do this, because: + * struct S { T* array[0]; } + * may be a variable length struct. + */ + //if (dim->toInteger() == 0) + //return FALSE; + + if (next->ty == Tvoid) + // Arrays of void contain arbitrary data, which may include pointers + return TRUE; + else return next->hasPointers(); } @@ -2254,6 +2307,8 @@ Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident) return new IntegerExp(se->loc, se->len, Type::tindex); } + if (e->op == TOKnull) + return new IntegerExp(e->loc, 0, Type::tindex); e = new ArrayLengthExp(e->loc, e); e->type = Type::tsize_t; return e; @@ -2397,7 +2452,6 @@ Type *TypeAArray::semantic(Loc loc, Scope *sc) key = key->next->arrayOf(); #endif break; - case Tbit: case Tbool: case Tfunction: case Tvoid: @@ -2516,6 +2570,9 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) arguments = new Expressions(); arguments->push(e); size_t keysize = key->size(e->loc); + if (global.params.is64bit) + keysize = (keysize + 15) & ~15; + else keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1); arguments->push(new IntegerExp(0, keysize, Type::tsize_t)); arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t)); @@ -2706,8 +2763,6 @@ int TypePointer::hasPointers() TypeReference::TypeReference(Type *t) : Type(Treference, t) { - if (t->ty == Tbit) - error(0,"cannot make reference to a bit"); // BUG: what about references to static arrays? } @@ -2833,7 +2888,12 @@ int Type::covariant(Type *t) } } else if (t1->parameters != t2->parameters) + { + size_t dim1 = !t1->parameters ? 0 : t1->parameters->dim; + size_t dim2 = !t2->parameters ? 0 : t2->parameters->dim; + if (dim1 || dim2) goto Ldistinct; + } // The argument lists match if (inoutmismatch) @@ -2841,6 +2901,7 @@ int Type::covariant(Type *t) if (t1->linkage != t2->linkage) goto Lnotcovariant; + // Return types Type *t1n = t1->next; Type *t2n = t2->next; @@ -2863,7 +2924,7 @@ int Type::covariant(Type *t) if (!cd->isBaseInfoComplete()) #endif { - return 3; + return 3; // forward references } } if (t1n->implicitConvTo(t2n)) @@ -2946,6 +3007,11 @@ void TypeFunction::toDecoBuffer(OutBuffer *buf, bool mangle) void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) { + toCBufferWithAttributes(buf, ident, hgs, this, NULL); +} + +void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td) +{ const char *p = NULL; if (inuse) @@ -2979,6 +3045,17 @@ void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs { buf->writeByte(' '); buf->writestring(ident->toHChars2()); } + if (td) + { buf->writeByte('('); + for (size_t i = 0; i < td->origParameters->dim; i++) + { + TemplateParameter *tp = td->origParameters->tdata()[i]; + if (i) + buf->writestring(", "); + tp->toCBuffer(buf, hgs); + } + buf->writeByte(')'); + } Parameter::argsToCBuffer(buf, hgs, parameters, varargs); inuse--; } @@ -3038,10 +3115,10 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) if (parameters) { tf->parameters = (Parameters *)parameters->copy(); for (size_t i = 0; i < parameters->dim; i++) - { Parameter *arg = (Parameter *)parameters->data[i]; + { Parameter *arg = parameters->tdata()[i]; Parameter *cpy = (Parameter *)mem.malloc(sizeof(Parameter)); memcpy(cpy, arg, sizeof(Parameter)); - tf->parameters->data[i] = (void *)cpy; + tf->parameters->tdata()[i] = cpy; } } @@ -3195,12 +3272,18 @@ int TypeFunction::callMatch(Expressions *args) goto L1; goto Nomatch; // not enough arguments } - arg = (Expression *)args->data[u]; + arg = (*args)[u]; assert(arg); if (p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid) m = MATCHconvert; else m = arg->implicitConvTo(p->type); + /* prefer matching the element type rather than the array + * type when more arguments are present with T[]... + */ + if (varargs == 2 && u + 1 == nparams && nargs > nparams) + goto L1; + //printf("\tm = %d\n", m); if (m == MATCHnomatch) // if no match { @@ -3220,7 +3303,7 @@ int TypeFunction::callMatch(Expressions *args) case Tarray: for (; u < nargs; u++) { - arg = (Expression *)args->data[u]; + arg = (*args)[u]; assert(arg); #if 1 /* If lazy array of delegates, @@ -3292,6 +3375,12 @@ Type *TypeFunction::reliesOnTident() return next->reliesOnTident(); } +Expression *TypeFunction::defaultInit(Loc loc) +{ + error(loc, "function does not have a default initializer"); + return new ErrorExp(); +} + /***************************** TypeDelegate *****************************/ TypeDelegate::TypeDelegate(Type *t) @@ -3331,6 +3420,11 @@ unsigned TypeDelegate::alignsize() { // A Delegate consists of two ptr values, so align it on pointer size // boundary +#if DMDV1 + // See Bugzilla 942 for discussion + if (!global.params.is64bit) + return PTRSIZE * 2; +#endif return PTRSIZE; } @@ -3408,7 +3502,7 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) { //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars()); idents.setDim(t->idents.dim); - for (int i = 0; i < idents.dim; i++) + for (size_t i = 0; i < idents.dim; i++) { Identifier *id = (Identifier *)t->idents.data[i]; if (id->dyncast() == DYNCAST_DSYMBOL) @@ -3430,9 +3524,7 @@ void TypeQualified::addIdent(Identifier *ident) void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs) { - int i; - - for (i = 0; i < idents.dim; i++) + for (size_t i = 0; i < idents.dim; i++) { Identifier *id = (Identifier *)idents.data[i]; buf->writeByte('.'); @@ -3465,8 +3557,6 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym, Expression **pe, Type **pt, Dsymbol **ps) { - Identifier *id = NULL; - int i; VarDeclaration *v; EnumMember *em; TupleDeclaration *td; @@ -3487,11 +3577,10 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, s->checkDeprecated(loc, sc); // check for deprecated aliases s = s->toAlias(); //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - for (i = 0; i < idents.dim; i++) - { Dsymbol *sm; - - id = (Identifier *)idents.data[i]; - sm = s->searchX(loc, sc, id); + for (size_t i = 0; i < idents.dim; i++) + { + Identifier *id = idents[i]; + Dsymbol *sm = s->searchX(loc, sc, id); //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); //printf("getType = '%s'\n", s->getType()->toChars()); if (!sm) @@ -3509,12 +3598,12 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, goto Lerror; goto L3; } - else if (v && id == Id::stringof) + else if (v && (id == Id::stringof || id == Id::offsetof)) { e = new DsymbolExp(loc, s); do { - id = (Identifier *)idents.data[i]; + id = idents.tdata()[i]; e = new DotIdExp(loc, e, id); } while (++i < idents.dim); e = e->semantic(sc); @@ -3524,7 +3613,14 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, t = s->getType(); if (!t && s->isDeclaration()) - t = s->isDeclaration()->type; + { t = s->isDeclaration()->type; + if (!t && s->isTupleDeclaration()) + { + e = new TupleExp(loc, s->isTupleDeclaration()); + e = e->semantic(sc); + t = e->type; + } + } if (t) { sm = t->toDsymbol(sc); @@ -3540,15 +3636,21 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, L3: for (; i < idents.dim; i++) { - id = (Identifier *)idents.data[i]; + id = idents.tdata()[i]; //printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type); e = e->type->dotExp(sc, e, id); } + if (e->op == TOKtype) + *pt = e->type; + else *pe = e; } else + { Lerror: error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); + *pe = new ErrorExp(); + } return; } L2: @@ -3664,6 +3766,7 @@ L1: else error(loc, "undefined identifier %s", p); } + *pt = Type::terror; } } @@ -3738,7 +3841,7 @@ Dsymbol *TypeIdentifier::toDsymbol(Scope *sc) Dsymbol *s = sc->search(loc, ident, &scopesym); if (s) { - for (int i = 0; i < idents.dim; i++) + for (size_t i = 0; i < idents.dim; i++) { Identifier *id = (Identifier *)idents.data[i]; s = s->searchX(loc, sc, id); @@ -3796,7 +3899,7 @@ Type *TypeIdentifier::reliesOnTident() Expression *TypeIdentifier::toExpression() { Expression *e = new IdentifierExp(loc, ident); - for (int i = 0; i < idents.dim; i++) + for (size_t i = 0; i < idents.dim; i++) { Identifier *id = (Identifier *)idents.data[i]; e = new DotIdExp(loc, e, id); @@ -3870,15 +3973,12 @@ Type *TypeInstance::semantic(Loc loc, Scope *sc) if (sc->parameterSpecialization) { - unsigned errors = global.errors; - global.gag++; + unsigned errors = global.startGagging(); resolve(loc, sc, &e, &t, &s); - global.gag--; - if (errors != global.errors) - { if (global.gag == 0) - global.errors = errors; + if (global.endGagging(errors)) + { return this; } } @@ -3892,7 +3992,7 @@ Type *TypeInstance::semantic(Loc loc, Scope *sc) printf("2: e:%p s:%p ", e, s); #endif error(loc, "%s is used as a type", toChars()); - t = tvoid; + t = terror; } return t; } @@ -3907,18 +4007,13 @@ Dsymbol *TypeInstance::toDsymbol(Scope *sc) if (sc->parameterSpecialization) { - unsigned errors = global.errors; - global.gag++; + unsigned errors = global.startGagging(); resolve(loc, sc, &e, &t, &s); - global.gag--; - if (errors != global.errors) - { if (global.gag == 0) - global.errors = errors; + if (global.endGagging(errors)) return NULL; } - } else resolve(loc, sc, &e, &t, &s); @@ -4361,7 +4456,10 @@ char *TypeTypedef::toChars() Type *TypeTypedef::semantic(Loc loc, Scope *sc) { //printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem); + int errors = global.errors; sym->semantic(sc); + if (errors != global.errors) + return terror; return merge(); } @@ -4632,8 +4730,7 @@ void TypeStruct::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) } Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ unsigned offset; - +{ Expression *b; VarDeclaration *v; Dsymbol *s; @@ -4771,7 +4868,8 @@ L1: if (e->op == TOKtype) { FuncDeclaration *fd = sc->func; - if (d->needThis() && fd && fd->vthis) + if (d->needThis() && fd && fd->vthis && + fd->toParent2()->isStructDeclaration() == sym) { e = new DotVarExp(e->loc, new ThisExp(e->loc), d); e = e->semantic(sc); @@ -4794,7 +4892,7 @@ L1: accessCheck(e->loc, sc, e, d); ve = new VarExp(e->loc, d); e = new CommaExp(e->loc, e, ve); - e->type = d->type; + e = e->semantic(sc); return e; } @@ -4853,7 +4951,11 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) VarDeclaration *vd = (VarDeclaration *)(sym->fields.data[j]); Expression *e; if (vd->init) + { if (vd->init->isVoidInitializer()) + e = NULL; + else e = vd->init->toExpression(); + } else e = vd->type->defaultInitLiteral(); structelems->data[j] = e; @@ -4953,9 +5055,7 @@ void TypeClass::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) } Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ unsigned offset; - - Expression *b; +{ VarDeclaration *v; Dsymbol *s; DotVarExp *de; @@ -5263,7 +5363,7 @@ L1: accessCheck(e->loc, sc, e, d); ve = new VarExp(e->loc, d); e = new CommaExp(e->loc, e, ve); - e->type = d->type; + e = e->semantic(sc); return e; } @@ -5660,23 +5760,20 @@ char *Parameter::argsTypesToChars(Parameters *args, int varargs) buf->writeByte('('); if (args) - { int i; - OutBuffer argbuf; + { OutBuffer argbuf; HdrGenState hgs; - for (i = 0; i < args->dim; i++) - { Parameter *arg; - - if (i) + for (size_t i = 0; i < args->dim; i++) + { if (i) buf->writeByte(','); - arg = (Parameter *)args->data[i]; + Parameter *arg = (Parameter *)args->data[i]; argbuf.reset(); arg->type->toCBuffer2(&argbuf, &hgs, 0); buf->write(&argbuf); } if (varargs) { - if (i && varargs == 1) + if (args->dim && varargs == 1) buf->writeByte(','); buf->writestring("..."); } @@ -5690,15 +5787,14 @@ void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *argu { buf->writeByte('('); if (arguments) - { int i; + { OutBuffer argbuf; - for (i = 0; i < arguments->dim; i++) - { Parameter *arg; - + for (size_t i = 0; i < arguments->dim; i++) + { if (i) buf->writestring(", "); - arg = (Parameter *)arguments->data[i]; + Parameter *arg = (Parameter *)arguments->data[i]; if (arg->storageClass & STCout) buf->writestring("out "); else if (arg->storageClass & STCref) @@ -5711,18 +5807,13 @@ void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *argu if (arg->defaultArg) { argbuf.writestring(" = "); - unsigned o = argbuf.offset; arg->defaultArg->toCBuffer(&argbuf, hgs); - if(hgs->ddoc) - { - escapeDdocString(&argbuf, o); - } } buf->write(&argbuf); } if (varargs) { - if (i && varargs == 1) + if (arguments->dim && varargs == 1) buf->writeByte(','); buf->writestring("..."); } @@ -5730,21 +5821,40 @@ void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *argu buf->writeByte(')'); } +static const int mangleFlag = 0x01; + +static int argsToDecoBufferDg(void *ctx, size_t n, Parameter *arg, int flags) +{ + arg->toDecoBuffer((OutBuffer *)ctx, flags & mangleFlag); + return 0; +} void Parameter::argsToDecoBuffer(OutBuffer *buf, Parameters *arguments, bool mangle) { //printf("Parameter::argsToDecoBuffer()\n"); - // Write argument types if (arguments) - { - size_t dim = Parameter::dim(arguments); - for (size_t i = 0; i < dim; i++) - { - Parameter *arg = Parameter::getNth(arguments, i); - arg->toDecoBuffer(buf, mangle); - } - } + foreach(arguments, &argsToDecoBufferDg, buf, 0, mangle ? mangleFlag : 0); +} + +/**************************************** + * Determine if parameter list is really a template parameter list + * (i.e. it has auto or alias parameters) + */ + +static int isTPLDg(void *ctx, size_t n, Parameter *arg, int) +{ + if (arg->storageClass & (STCalias | STCauto | STCstatic)) + return 1; + return 0; +} + +int Parameter::isTPL(Parameters *arguments) +{ + //printf("Parameter::isTPL()\n"); + if (arguments) + return foreach(arguments, &isTPLDg, NULL); + return 0; } /**************************************************** @@ -5804,23 +5914,17 @@ void Parameter::toDecoBuffer(OutBuffer *buf, bool mangle) * Determine number of arguments, folding in tuples. */ +static int dimDg(void *ctx, size_t n, Parameter *, int) +{ + ++*(size_t *)ctx; + return 0; +} + size_t Parameter::dim(Parameters *args) { size_t n = 0; if (args) - { - for (size_t i = 0; i < args->dim; i++) - { Parameter *arg = (Parameter *)args->data[i]; - Type *t = arg->type->toBasetype(); - - if (t->ty == Ttuple) - { TypeTuple *tu = (TypeTuple *)t; - n += dim(tu->arguments); - } - else - n++; - } - } + foreach(args, &dimDg, &n); return n; } @@ -5832,29 +5936,59 @@ size_t Parameter::dim(Parameters *args) * of Parameters */ +struct GetNthParamCtx +{ + size_t nth; + Parameter *arg; +}; + +static int getNthParamDg(void *ctx, size_t n, Parameter *arg, int) +{ + GetNthParamCtx *p = (GetNthParamCtx *)ctx; + if (n == p->nth) + { p->arg = arg; + return 1; + } + return 0; +} + Parameter *Parameter::getNth(Parameters *args, size_t nth, size_t *pn) { - if (!args) - return NULL; + GetNthParamCtx ctx = { nth, NULL }; + int res = foreach(args, &getNthParamDg, &ctx); + return res ? ctx.arg : NULL; +} - size_t n = 0; +/*************************************** + * Expands tuples in args in depth first order. Calls + * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter. + * If dg returns !=0, stops and returns that value else returns 0. + * Use this function to avoid the O(N + N^2/2) complexity of + * calculating dim and calling N times getNth. + */ + +int Parameter::foreach(Parameters *args, Parameter::ForeachDg dg, void *ctx, size_t *pn, int flags) +{ + assert(args && dg); + + size_t n = pn ? *pn : 0; // take over index + int result = 0; for (size_t i = 0; i < args->dim; i++) - { Parameter *arg = (Parameter *)args->data[i]; + { Parameter *arg = args->tdata()[i]; Type *t = arg->type->toBasetype(); if (t->ty == Ttuple) { TypeTuple *tu = (TypeTuple *)t; - arg = getNth(tu->arguments, nth - n, &n); - if (arg) - return arg; + result = foreach(tu->arguments, dg, ctx, &n, flags); } - else if (n == nth) - return arg; else - n++; + result = dg(ctx, n++, arg, flags); + + if (result) + break; } if (pn) - *pn += n; - return NULL; + *pn = n; // update index + return result; } diff --git a/dmd/mtype.h b/dmd/mtype.h index 88844bdc..818fc15e 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -170,6 +170,7 @@ struct Type : Object #define tboolean tbool // result of boolean expression #define tindex tsize_t // array/ptr index static Type *tvoidptr; // void* + static Type *tstring; // immutable(char)[] #define terror basic[Terror] // for error recovery #define tsize_t basic[Tsize_t] // matches size_t alias @@ -222,6 +223,7 @@ struct Type : Object virtual d_uns64 size(Loc loc); virtual unsigned alignsize(); virtual Type *semantic(Loc loc, Scope *sc); + Type *trySemantic(Loc loc, Scope *sc); // append the mangleof or a string uniquely identifying this type to buf virtual void toDecoBuffer(OutBuffer *buf, bool mangle); Type *merge(); @@ -508,6 +510,7 @@ struct TypeFunction : Type Type *semantic(Loc loc, Scope *sc); void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); + void toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); TypeInfoDeclaration *getTypeInfoDeclaration(); @@ -528,6 +531,8 @@ struct TypeFunction : Type FuncDeclaration* funcdecl; #endif + + Expression *defaultInit(Loc loc); }; struct TypeDelegate : Type @@ -553,7 +558,7 @@ struct TypeDelegate : Type struct TypeQualified : Type { Loc loc; - Array idents; // array of Identifier's representing ident.ident.ident etc. + Identifiers idents; // array of Identifier's representing ident.ident.ident etc. TypeQualified(TY ty, Loc loc); void syntaxCopyHelper(TypeQualified *t); @@ -815,6 +820,9 @@ struct Parameter : Object static int isTPL(Parameters *arguments); static size_t dim(Parameters *arguments); static Parameter *getNth(Parameters *arguments, size_t nth, size_t *pn = NULL); + + typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param, int flags); + static int foreach(Parameters *args, ForeachDg dg, void *ctx, size_t *pn=NULL, int flags = 0); }; extern int PTRSIZE; diff --git a/dmd/opover.c b/dmd/opover.c index 54f4de33..cad40d3a 100644 --- a/dmd/opover.c +++ b/dmd/opover.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com diff --git a/dmd/optimize.c b/dmd/optimize.c index 3539ad8a..1d179674 100644 --- a/dmd/optimize.c +++ b/dmd/optimize.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -40,7 +40,7 @@ static real_t zero; // work around DMC bug for now * return that initializer. */ -Expression *fromConstInitializer(Expression *e1) +Expression *fromConstInitializer(int result, Expression *e1) { //printf("fromConstInitializer(%s)\n", e1->toChars()); if (e1->op == TOKvar) @@ -48,7 +48,13 @@ Expression *fromConstInitializer(Expression *e1) VarDeclaration *v = ve->var->isVarDeclaration(); if (v && !v->originalType && v->scope) // semantic() not yet run v->semantic (v->scope); - if (v && v->isConst() && v->init) + if (!v || !v->type) + return e1; + Type * tb = v->type->toBasetype(); + if (v->isConst() && v->init + && (result & WANTinterpret || (tb->isscalar() || + ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct)))) + ) { Expression *ei = v->init->toExpression(); if (ei && ei->type) e1 = ei; @@ -66,10 +72,7 @@ Expression *Expression::optimize(int result) Expression *VarExp::optimize(int result) { - if (result & WANTinterpret) - { - return fromConstInitializer(this); - } + return fromConstInitializer(result, this); return this; } @@ -388,7 +391,7 @@ Expression *CastExp::optimize(int result) e1 = e1->optimize(result); if (result & WANTinterpret) - e1 = fromConstInitializer(e1); + e1 = fromConstInitializer(result, e1); if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && (type->ty == Tpointer || type->ty == Tarray) && @@ -660,7 +663,7 @@ Expression *ArrayLengthExp::optimize(int result) { Expression *e; //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e1 = e1->optimize(WANTvalue | WANTexpand | (result & WANTinterpret)); e = this; if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) { @@ -677,8 +680,8 @@ Expression *EqualExp::optimize(int result) e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); e = this; - Expression *e1 = fromConstInitializer(this->e1); - Expression *e2 = fromConstInitializer(this->e2); + Expression *e1 = fromConstInitializer(result, this->e1); + Expression *e2 = fromConstInitializer(result, this->e2); e = Equal(op, type, e1, e2); if (e == EXP_CANT_INTERPRET) @@ -703,13 +706,40 @@ Expression *IdentityExp::optimize(int result) return e; } + +/* It is possible for constant folding to change an array expression of + * unknown length, into one where the length is known. + * If the expression 'arr' is a literal, set lengthVar to be its length. + */ +void setLengthVarIfKnown(VarDeclaration *lengthVar, Expression *arr) +{ + if (!lengthVar) + return; + if (lengthVar->init && !lengthVar->init->isVoidInitializer()) + return; // we have previously calculated the length + size_t len; + if (arr->op == TOKstring) + len = ((StringExp *)arr)->len; + else if (arr->op == TOKarrayliteral) + len = ((ArrayLiteralExp *)arr)->elements->dim; + else + return; // we don't know the length yet + + Expression *dollar = new IntegerExp(0, len, Type::tsize_t); + lengthVar->init = new ExpInitializer(0, dollar); + lengthVar->storage_class |= STCstatic | STCconst; +} + + Expression *IndexExp::optimize(int result) { Expression *e; //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret)); if (result & WANTinterpret) - e1 = fromConstInitializer(e1); + e1 = fromConstInitializer(result, e1); + // We might know $ now + setLengthVarIfKnown(lengthVar, e1); e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); e = Index(type, e1, e2); if (e == EXP_CANT_INTERPRET) @@ -717,6 +747,7 @@ Expression *IndexExp::optimize(int result) return e; } + Expression *SliceExp::optimize(int result) { Expression *e; @@ -733,12 +764,15 @@ Expression *SliceExp::optimize(int result) return e; } if (result & WANTinterpret) - e1 = fromConstInitializer(e1); + e1 = fromConstInitializer(result, e1); + // We might know $ now + setLengthVarIfKnown(lengthVar, e1); lwr = lwr->optimize(WANTvalue | (result & WANTinterpret)); upr = upr->optimize(WANTvalue | (result & WANTinterpret)); e = Slice(type, e1, lwr, upr); if (e == EXP_CANT_INTERPRET) e = this; + //printf("-SliceExp::optimize() %s\n", e->toChars()); return e; } diff --git a/dmd/parse.c b/dmd/parse.c index 80cfe258..f0646205 100644 --- a/dmd/parse.c +++ b/dmd/parse.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -68,9 +68,9 @@ Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocCo //nextToken(); // start up the scanner } -Array *Parser::parseModule() +Dsymbols *Parser::parseModule() { - Array *decldefs; + Dsymbols *decldefs; // ModuleDeclation leads off if (token.value == TOKmodule) @@ -103,14 +103,14 @@ Array *Parser::parseModule() } else { - Array *a = NULL; + Identifiers *a = NULL; Identifier *id; id = token.ident; while (nextToken() == TOKdot) { if (!a) - a = new Array(); + a = new Identifiers(); a->push(id); nextToken(); if (token.value != TOKidentifier) @@ -138,21 +138,21 @@ Lerr: while (token.value != TOKsemicolon && token.value != TOKeof) nextToken(); nextToken(); - return new Array(); + return new Dsymbols(); } -Array *Parser::parseDeclDefs(int once) +Dsymbols *Parser::parseDeclDefs(int once) { Dsymbol *s; - Array *decldefs; - Array *a; - Array *aelse; + Dsymbols *decldefs; + Dsymbols *a; + Dsymbols *aelse; enum PROT prot; StorageClass stc; Condition *condition; unsigned char *comment; //printf("Parser::parseDeclDefs()\n"); - decldefs = new Array(); + decldefs = new Dsymbols(); do { comment = token.blockComment; @@ -396,10 +396,10 @@ Array *Parser::parseDeclDefs(int once) if (token.value == TOKlparen) { nextToken(); - if (token.value == TOKint32v) + if (token.value == TOKint32v && token.uns64value > 0) n = (unsigned)token.uns64value; else - { error("integer expected, not %s", token.toChars()); + { error("positive integer expected, not %s", token.toChars()); n = 1; } nextToken(); @@ -445,7 +445,7 @@ Array *Parser::parseDeclDefs(int once) nextToken(); if (token.value == TOKidentifier) s = new DebugSymbol(loc, token.ident); - else if (token.value == TOKint32v) + else if (token.value == TOKint32v || token.value == TOKint64v) s = new DebugSymbol(loc, (unsigned)token.uns64value); else { error("identifier or integer expected, not %s", token.toChars()); @@ -466,7 +466,7 @@ Array *Parser::parseDeclDefs(int once) nextToken(); if (token.value == TOKidentifier) s = new VersionSymbol(loc, token.ident); - else if (token.value == TOKint32v) + else if (token.value == TOKint32v || token.value == TOKint64v) s = new VersionSymbol(loc, (unsigned)token.uns64value); else { error("identifier or integer expected, not %s", token.toChars()); @@ -528,14 +528,43 @@ void Parser::composeStorageClass(StorageClass stc) } #endif +/*********************************************** + * Parse storage class, lexer is on '@' + */ + +#if DMDV2 +StorageClass Parser::parseAttribute() +{ + nextToken(); + StorageClass stc = 0; + if (token.value != TOKidentifier) + { + error("identifier expected after @, not %s", token.toChars()); + } + else if (token.ident == Id::property) + stc = STCproperty; + else if (token.ident == Id::safe) + stc = STCsafe; + else if (token.ident == Id::trusted) + stc = STCtrusted; + else if (token.ident == Id::system) + stc = STCsystem; + else if (token.ident == Id::disable) + stc = STCdisable; + else + error("valid attribute identifiers are @property, @safe, @trusted, @system, @disable not @%s", token.toChars()); + return stc; +} +#endif + + /******************************************** * Parse declarations after an align, protection, or extern decl. */ -Array *Parser::parseBlock() +Dsymbols *Parser::parseBlock() { - Array *a = NULL; - Dsymbol *s; + Dsymbols *a = NULL; //printf("parseBlock()\n"); switch (token.value) @@ -692,7 +721,7 @@ Condition *Parser::parseDebugCondition() if (token.value == TOKidentifier) id = token.ident; - else if (token.value == TOKint32v) + else if (token.value == TOKint32v || token.value == TOKint64v) level = (unsigned)token.uns64value; else error("identifier or integer expected, not %s", token.toChars()); @@ -721,7 +750,7 @@ Condition *Parser::parseVersionCondition() nextToken(); if (token.value == TOKidentifier) id = token.ident; - else if (token.value == TOKint32v) + else if (token.value == TOKint32v || token.value == TOKint64v) level = (unsigned)token.uns64value; #if DMDV2 /* Allow: @@ -754,8 +783,6 @@ Condition *Parser::parseVersionCondition() Condition *Parser::parseStaticIfCondition() { Expression *exp; Condition *condition; - Array *aif; - Array *aelse; Loc loc = this->loc; nextToken(); @@ -1110,7 +1137,7 @@ EnumDeclaration *Parser::parseEnum() else if (token.value == TOKlcurly) { //printf("enum definition\n"); - e->members = new Array(); + e->members = new Dsymbols(); nextToken(); unsigned char *comment = token.blockComment; while (token.value != TOKrcurly) @@ -1237,7 +1264,7 @@ Dsymbol *Parser::parseAggregate() { //printf("aggregate definition\n"); nextToken(); - Array *decl = parseDeclDefs(0); + Dsymbols *decl = parseDeclDefs(0); if (token.value != TOKrcurly) error("} expected following member declarations in aggregate"); nextToken(); @@ -1259,7 +1286,7 @@ Dsymbol *Parser::parseAggregate() if (tpl) { // Wrap a template around the aggregate declaration - Array *decldefs = new Array(); + Dsymbols *decldefs = new Dsymbols(); decldefs->push(a); TemplateDeclaration *tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs); @@ -1338,7 +1365,7 @@ TemplateDeclaration *Parser::parseTemplateDeclaration() TemplateDeclaration *tempdecl; Identifier *id; TemplateParameters *tpl; - Array *decldefs; + Dsymbols *decldefs; Loc loc = this->loc; nextToken(); @@ -1535,7 +1562,7 @@ Dsymbol *Parser::parseMixin() Identifier *id; Type *tqual; Objects *tiargs; - Array *idents; + Identifiers *idents; //printf("parseMixin()\n"); nextToken(); @@ -1566,7 +1593,7 @@ Dsymbol *Parser::parseMixin() nextToken(); } - idents = new Array(); + idents = new Identifiers(); while (1) { tiargs = NULL; @@ -1659,7 +1686,7 @@ Import *Parser::parseImport(Array *decldefs, int isstatic) { Import *s; Identifier *id; Identifier *aliasid = NULL; - Array *a; + Identifiers *a; Loc loc; //printf("Parser::parseImport()\n"); @@ -1684,7 +1711,7 @@ Import *Parser::parseImport(Array *decldefs, int isstatic) while (token.value == TOKdot) { if (!a) - a = new Array(); + a = new Identifiers(); a->push(id); nextToken(); if (token.value != TOKidentifier) @@ -2143,7 +2170,7 @@ Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters * * Return array of Declaration *'s. */ -Array *Parser::parseDeclarations() +Dsymbols *Parser::parseDeclarations() { StorageClass storage_class; StorageClass stc; @@ -2151,7 +2178,7 @@ Array *Parser::parseDeclarations() Type *t; Type *tfirst; Identifier *ident; - Array *a; + Dsymbols *a; enum TOK tok = TOKreserved; unsigned char *comment = token.blockComment; enum LINK link = linkage; @@ -2213,7 +2240,7 @@ Array *Parser::parseDeclarations() break; } - a = new Array(); + a = new Dsymbols(); /* Look for auto initializers: * storage_class identifier = initializer; @@ -2300,7 +2327,7 @@ Array *Parser::parseDeclarations() a->push(v); else { - Array *ax = new Array(); + Dsymbols *ax = new Dsymbols(); ax->push(v); Dsymbol *s = new LinkDeclaration(link, ax); a->push(s); @@ -2334,14 +2361,14 @@ Array *Parser::parseDeclarations() } else { - Array *ax = new Array(); + Dsymbols *ax = new Dsymbols(); ax->push(f); s = new LinkDeclaration(link, ax); } if (tpl) // it's a function template { // Wrap a template around the aggregate declaration - Array *decldefs = new Array(); + Dsymbols *decldefs = new Dsymbols(); decldefs->push(s); TemplateDeclaration *tempdecl = new TemplateDeclaration(loc, s->ident, tpl, NULL, decldefs); @@ -2365,7 +2392,7 @@ Array *Parser::parseDeclarations() a->push(v); else { - Array *ax = new Array(); + Dsymbols *ax = new Dsymbols(); ax->push(v); Dsymbol *s = new LinkDeclaration(link, ax); a->push(s); @@ -2585,7 +2612,7 @@ Initializer *Parser::parseInitializer() is = new StructInitializer(loc); nextToken(); - comma = 0; + comma = 2; while (1) { switch (token.value) @@ -2609,6 +2636,8 @@ Initializer *Parser::parseInitializer() continue; case TOKcomma: + if (comma == 2) + error("expression expected, not ','"); nextToken(); comma = 2; continue; @@ -2622,6 +2651,8 @@ Initializer *Parser::parseInitializer() break; default: + if (comma == 1) + error("comma expected separating field initializers"); value = parseInitializer(); is->addInit(NULL, value); comma = 1; @@ -2670,7 +2701,7 @@ Initializer *Parser::parseInitializer() ia = new ArrayInitializer(loc); nextToken(); - comma = 0; + comma = 2; while (1) { switch (token.value) @@ -2707,6 +2738,8 @@ Initializer *Parser::parseInitializer() continue; case TOKcomma: + if (comma == 2) + error("expression expected, not ','"); nextToken(); comma = 2; continue; @@ -2909,10 +2942,10 @@ Statement *Parser::parseStatement(int flags) { Statements *as = new Statements(); as->reserve(a->dim); - for (int i = 0; i < a->dim; i++) + for (size_t i = 0; i < a->dim; i++) { Dsymbol *d = (Dsymbol *)a->data[i]; - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); as->push(s); } s = new CompoundDeclarationStatement(loc, as); @@ -2920,7 +2953,7 @@ Statement *Parser::parseStatement(int flags) else if (a->dim == 1) { Dsymbol *d = (Dsymbol *)a->data[0]; - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); } else assert(0); @@ -2936,7 +2969,7 @@ Statement *Parser::parseStatement(int flags) { Dsymbol *d; d = parseAggregate(); - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); break; } @@ -2944,7 +2977,7 @@ Statement *Parser::parseStatement(int flags) { Dsymbol *d; d = parseEnum(); - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); break; } @@ -2952,16 +2985,21 @@ Statement *Parser::parseStatement(int flags) { t = peek(&token); if (t->value == TOKlparen) { // mixin(string) - nextToken(); - check(TOKlparen, "mixin"); Expression *e = parseAssignExp(); - check(TOKrparen); - check(TOKsemicolon, "mixin (string)"); - s = new CompileStatement(loc, e); + check(TOKsemicolon); + if (e->op == TOKmixin) + { + CompileExp *cpe = (CompileExp *)e; + s = new CompileStatement(loc, cpe->e1); + } + else + { + s = new ExpStatement(loc, e); + } break; } Dsymbol *d = parseMixin(); - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); break; } @@ -2998,7 +3036,7 @@ Statement *Parser::parseStatement(int flags) if (!(flags & PSsemi)) error("use '{ }' for an empty statement, not a ';'"); nextToken(); - s = new ExpStatement(loc, NULL); + s = new ExpStatement(loc, (Expression *)NULL); break; case TOKdo: @@ -3316,7 +3354,7 @@ Statement *Parser::parseStatement(int flags) s = new ScopeStatement(loc, s); // Keep cases in order by building the case statements backwards - for (int i = cases.dim; i; i--) + for (size_t i = cases.dim; i; i--) { exp = (Expression *)cases.data[i - 1]; s = new CaseStatement(loc, exp, s); @@ -3707,8 +3745,6 @@ int Parser::isBasicType(Token **pt) { // This code parallels parseBasicType() Token *t = *pt; - Token *t2; - int parens; switch (t->value) { @@ -4157,7 +4193,6 @@ int Parser::skipParens(Token *t, Token **pt) break; case TOKeof: - case TOKsemicolon: goto Lfalse; default: @@ -4359,7 +4394,6 @@ Expression *Parser::parsePrimaryExp() case BASIC_TYPES_X(t): nextToken(); - L1: check(TOKdot, t->toChars()); if (token.value != TOKidentifier) { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars()); @@ -4676,6 +4710,7 @@ Expression *Parser::parsePostExp(Expression *e) nextToken(); if (token.value == TOKrbracket) { // array[] + inBrackets--; e = new SliceExp(loc, e, NULL, NULL); nextToken(); } @@ -5386,7 +5421,7 @@ Expression *Parser::parseNewExp(Expression *thisexp) else { nextToken(); - Array *decl = parseDeclDefs(0); + Dsymbols *decl = parseDeclDefs(0); if (token.value != TOKrcurly) error("class member expected"); nextToken(); @@ -5472,7 +5507,7 @@ enum PREC precedence[TOKMAX]; void initPrecedence() { - for (int i = 0; i < TOKMAX; i++) + for (size_t i = 0; i < TOKMAX; i++) precedence[i] = PREC_zero; precedence[TOKtype] = PREC_expr; diff --git a/dmd/parse.h b/dmd/parse.h index 48a3cfd6..8f179b9c 100644 --- a/dmd/parse.h +++ b/dmd/parse.h @@ -66,10 +66,10 @@ struct Parser : Lexer Parser(Module *module, unsigned char *base, unsigned length, int doDocComment); - Array *parseModule(); - Array *parseDeclDefs(int once); + Dsymbols *parseModule(); + Dsymbols *parseDeclDefs(int once); Array *parseAutoDeclarations(StorageClass storageClass, unsigned char *comment); - Array *parseBlock(); + Dsymbols *parseBlock(); void composeStorageClass(StorageClass stc); Expression *parseConstraint(); TemplateDeclaration *parseTemplateDeclaration(); @@ -102,7 +102,7 @@ struct Parser : Lexer Type *parseBasicType(); Type *parseBasicType2(Type *t); Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL); - Array *parseDeclarations(); + Dsymbols *parseDeclarations(); void parseContracts(FuncDeclaration *f); Statement *parseStatement(int flags); Initializer *parseInitializer(); diff --git a/dmd/root/array.c b/dmd/root/array.c index f0e63c9f..3630654a 100644 --- a/dmd/root/array.c +++ b/dmd/root/array.c @@ -190,7 +190,8 @@ char *Array::toChars() char *str; char *p; - buf = (char **)alloca(dim * sizeof(char *)); + buf = (char **)malloc(dim * sizeof(char *)); + assert(buf); len = 2; for (u = 0; u < dim; u++) { @@ -211,6 +212,7 @@ char *Array::toChars() } *p++ = ']'; *p = 0; + free(buf); return str; } diff --git a/dmd/root/async.c b/dmd/root/async.c index 01893cbc..8699e961 100644 --- a/dmd/root/async.c +++ b/dmd/root/async.c @@ -12,7 +12,6 @@ #include #include "root.h" -#include "rmem.h" static unsigned __stdcall startthread(void *p); @@ -41,7 +40,7 @@ struct AsyncRead AsyncRead *AsyncRead::create(size_t nfiles) { - AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + + AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) + (nfiles - 1) * sizeof(FileData)); aw->filesmax = nfiles; return aw; @@ -92,7 +91,7 @@ int AsyncRead::read(size_t i) void AsyncRead::dispose(AsyncRead *aw) { - delete aw; + free(aw); } @@ -119,7 +118,6 @@ unsigned __stdcall startthread(void *p) #include #include "root.h" -#include "rmem.h" void *startthread(void *arg); @@ -155,7 +153,7 @@ struct AsyncRead AsyncRead *AsyncRead::create(size_t nfiles) { - AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + + AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) + (nfiles - 1) * sizeof(FileData)); aw->filesmax = nfiles; return aw; @@ -228,7 +226,7 @@ void AsyncRead::dispose(AsyncRead *aw) if (status != 0) err_abort(status, "mutex destroy"); } - delete aw; + free(aw); } @@ -265,7 +263,6 @@ void *startthread(void *p) #include #include "root.h" -#include "rmem.h" struct FileData { @@ -292,7 +289,7 @@ struct AsyncRead AsyncRead *AsyncRead::create(size_t nfiles) { - AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + + AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) + (nfiles - 1) * sizeof(FileData)); aw->filesmax = nfiles; return aw; @@ -322,7 +319,7 @@ int AsyncRead::read(size_t i) void AsyncRead::dispose(AsyncRead *aw) { - delete aw; + free(aw); } #endif diff --git a/dmd/root/dchar.c b/dmd/root/dchar.c index 741e7d7a..db90916f 100644 --- a/dmd/root/dchar.c +++ b/dmd/root/dchar.c @@ -327,7 +327,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len) case 2: hash *= 37; -#if __I86__ +#if LITTLE_ENDIAN hash += *(const uint16_t *)str; #else hash += str[0] * 256 + str[1]; @@ -336,7 +336,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len) case 3: hash *= 37; -#if __I86__ +#if LITTLE_ENDIAN hash += (*(const uint16_t *)str << 8) + ((const uint8_t *)str)[2]; #else @@ -346,7 +346,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len) default: hash *= 37; -#if __I86__ +#if LITTLE_ENDIAN hash += *(const uint32_t *)str; #else hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; @@ -379,7 +379,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len) case 2: hash *= 37; -#if __I86__ +#if LITTLE_ENDIAN hash += *(const uint16_t *)str; #else hash += str[0] * 256 + str[1]; @@ -388,7 +388,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len) case 3: hash *= 37; -#if __I86__ +#if LITTLE_ENDIAN hash += (*(const uint16_t *)str << 8) + ((const uint8_t *)str)[2]; #else @@ -398,7 +398,7 @@ hash_t Dchar::calcHash(const dchar *str, size_t len) default: hash *= 37; -#if __I86__ +#if LITTLE_ENDIAN hash += *(const uint32_t *)str; #else hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; diff --git a/dmd/root/dchar.h b/dmd/root/dchar.h index c22b48db..631c2a35 100644 --- a/dmd/root/dchar.h +++ b/dmd/root/dchar.h @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // www.digitalmars.com @@ -161,14 +161,14 @@ struct Dchar static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } static int isDigit(dchar c) { return '0' <= c && c <= '9'; } #ifndef GCC_SAFE_DMD - static int isAlpha(dchar c) { return isalpha(c); } - static int isUpper(dchar c) { return isupper(c); } - static int isLower(dchar c) { return islower(c); } - static int isLocaleUpper(dchar c) { return isupper(c); } - static int isLocaleLower(dchar c) { return islower(c); } - static int toLower(dchar c) { return isupper(c) ? tolower(c) : c; } + static int isAlpha(dchar c) { return isalpha((unsigned char)c); } + static int isUpper(dchar c) { return isupper((unsigned char)c); } + static int isLower(dchar c) { return islower((unsigned char)c); } + static int isLocaleUpper(dchar c) { return isupper((unsigned char)c); } + static int isLocaleLower(dchar c) { return islower((unsigned char)c); } + static int toLower(dchar c) { return isupper((unsigned char)c) ? tolower(c) : c; } static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return islower(c) ? toupper(c) : c; } + static int toUpper(dchar c) { return islower((unsigned char)c) ? toupper(c) : c; } static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? #endif static dchar *chr(dchar *p, int c) { return strchr(p, c); } diff --git a/dmd/root/man.c b/dmd/root/man.c index 2c3bbc40..8b2787c4 100644 --- a/dmd/root/man.c +++ b/dmd/root/man.c @@ -26,7 +26,7 @@ void browse(const char *url) #endif -#if linux || __FreeBSD__ || __sun&&__SVR4 +#if linux || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 #include #include diff --git a/dmd/root/port.c b/dmd/root/port.c index 97219024..1ca30c8d 100644 --- a/dmd/root/port.c +++ b/dmd/root/port.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -70,6 +70,11 @@ double Port::pow(double x, double y) return ::pow(x, y); } +long double Port::fmodl(long double x, long double y) +{ + return ::fmodl(x, y); +} + unsigned long long Port::strtoull(const char *p, char **pend, int base) { return ::strtoull(p, pend, base); @@ -201,14 +206,21 @@ double Port::pow(double x, double y) return ::pow(x, y); } +long double Port::fmodl(long double x, long double y) +{ + return ::fmodl(x, y); +} + unsigned _int64 Port::strtoull(const char *p, char **pend, int base) { unsigned _int64 number = 0; int c; int error; +#ifndef ULLONG_MAX #define ULLONG_MAX ((unsigned _int64)~0I64) +#endif - while (isspace(*p)) /* skip leading white space */ + while (isspace((unsigned char)*p)) /* skip leading white space */ p++; if (*p == '+') p++; @@ -315,7 +327,7 @@ char *Port::strupr(char *s) #endif -#if linux || __APPLE__ || __FreeBSD__ || __MINGW32__ || __HAIKU__ +#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __MINGW32__ || __HAIKU__ #include #if linux @@ -332,6 +344,7 @@ char *Port::strupr(char *s) #include #include #include +#include static double zero = 0; double Port::nan = NAN; @@ -368,18 +381,14 @@ PortInitializer::PortInitializer() #endif } -#if !defined __MINGW32__ && !defined __HAIKU__ -#undef isnan -#endif int Port::isNan(double r) { #if __APPLE__ return __inline_isnan(r); -#elif defined __MINGW32__ - return isnan(r); -#elif defined __HAIKU__ +#elif __OpenBSD__ || __MINGW32__ || __HAIKU__ return isnan(r); #else + #undef isnan return ::isnan(r); #endif } @@ -388,11 +397,10 @@ int Port::isNan(long double r) { #if __APPLE__ return __inline_isnan(r); -#elif defined __MINGW32__ - return isnan(r); -#elif defined __HAIKU__ +#elif __OpenBSD__ || __MINGW32__ || __HAIKU__ return isnan(r); #else + #undef isnan return ::isnan(r); #endif } @@ -419,18 +427,14 @@ int Port::isFinite(double r) return ::finite(r); } -#if !defined __MINGW32__ && !defined __HAIKU__ -#undef isinf -#endif int Port::isInfinity(double r) { #if __APPLE__ return fpclassify(r) == FP_INFINITE; -#elif defined __MINGW32__ - return isinf(r); -#elif defined __HAIKU__ +#elif __OpenBSD__ || __MINGW32__ || __HAIKU__ return isinf(r); #else + #undef isinf return ::isinf(r); #endif } @@ -453,6 +457,15 @@ double Port::pow(double x, double y) return ::pow(x, y); } +long double Port::fmodl(long double x, long double y) +{ +#if __FreeBSD__ || __OpenBSD__ + return ::fmod(x, y); // hack for now, fix later +#else + return ::fmodl(x, y); +#endif +} + unsigned long long Port::strtoull(const char *p, char **pend, int base) { return ::strtoull(p, pend, base); @@ -466,10 +479,14 @@ char *Port::ull_to_string(char *buffer, ulonglong ull) wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) { +#if __OpenBSD__ + assert(0); +#else #ifndef __MINGW32__ swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); #else _snwprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); +#endif #endif return buffer; } diff --git a/dmd/root/port.h b/dmd/root/port.h index e00ec465..0c7e24a4 100644 --- a/dmd/root/port.h +++ b/dmd/root/port.h @@ -40,7 +40,8 @@ struct Port static double dbl_min; static long double ldbl_max; -#if __GNUC__ && !defined __HAIKU__ +#if __OpenBSD__ +#elif __GNUC__ && !defined __HAIKU__ // These conflict with macros in math.h, should rename them #undef isnan #undef isfinite @@ -60,6 +61,8 @@ struct Port static double floor(double); static double pow(double x, double y); + static long double fmodl(long double x, long double y); + static ulonglong strtoull(const char *p, char **pend, int base); static char *ull_to_string(char *buffer, ulonglong ull); diff --git a/dmd/root/root.c b/dmd/root/root.c index 96cfd115..b0ed53ec 100644 --- a/dmd/root/root.c +++ b/dmd/root/root.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -8,7 +8,7 @@ // See the included readme.txt for details. #ifndef POSIX -#define POSIX (linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4) +#define POSIX (linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4) #endif #include @@ -364,21 +364,21 @@ FileName::FileName(char *path, char *name) } // Split a path into an Array of paths -Array *FileName::splitPath(const char *path) +Strings *FileName::splitPath(const char *path) { char c = 0; // unnecessary initializer is for VC /W4 const char *p; OutBuffer buf; - Array *array; + Strings *array; - array = new Array(); + array = new Strings(); if (path) { p = path; do { char instring = 0; - while (isspace(*p)) // skip leading whitespace + while (isspace((unsigned char)*p)) // skip leading whitespace p++; buf.reserve(strlen(p) + 1); // guess size of path // LDC remember first character @@ -799,7 +799,7 @@ void FileName::CopyTo(FileName *to) * cwd if !=0, search current directory before searching path */ -char *FileName::searchPath(Array *path, const char *name, int cwd) +char *FileName::searchPath(Strings *path, const char *name, int cwd) { if (absolute(name)) { @@ -815,7 +815,7 @@ char *FileName::searchPath(Array *path, const char *name, int cwd) for (i = 0; i < path->dim; i++) { - char *p = (char *)path->data[i]; + char *p = path->tdata()[i]; char *n = combine(p, name); if (exists(n)) @@ -839,7 +839,7 @@ char *FileName::searchPath(Array *path, const char *name, int cwd) * !=NULL mem.malloc'd file name */ -char *FileName::safeSearchPath(Array *path, const char *name) +char *FileName::safeSearchPath(Strings *path, const char *name) { #if _WIN32 /* Disallow % / \ : and .. in name characters @@ -876,7 +876,7 @@ char *FileName::safeSearchPath(Array *path, const char *name) for (i = 0; i < path->dim; i++) { char *cname = NULL; - char *cpath = canonicalName((char *)path->data[i]); + char *cpath = canonicalName(path->tdata()[i]); //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n", // name, (char *)path->data[i], cpath); if (cpath == NULL) @@ -966,7 +966,7 @@ void FileName::ensurePathExists(const char *path) { //printf("mkdir(%s)\n", path); #if _WIN32 - if (mkdir(path)) + if (_mkdir(path)) #endif #if POSIX if (mkdir(path, 0777)) @@ -1088,13 +1088,13 @@ int File::read() //printf("File::read('%s')\n",name); fd = open(name, O_RDONLY); if (fd == -1) - { result = errno; + { //printf("\topen error, errno = %d\n",errno); goto err1; } if (!ref) - mem.free(buffer); + ::free(buffer); ref = 0; // we own the buffer now //printf("\tfile opened\n"); @@ -1104,7 +1104,7 @@ int File::read() goto err2; } size = buf.st_size; - buffer = (unsigned char *) mem.malloc(size + 2); + buffer = (unsigned char *) ::malloc(size + 2); if (!buffer) { printf("\tmalloc error, errno = %d\n",errno); @@ -1137,7 +1137,7 @@ int File::read() err2: close(fd); err: - mem.free(buffer); + ::free(buffer); buffer = NULL; len = 0; @@ -1158,11 +1158,11 @@ err1: goto err1; if (!ref) - mem.free(buffer); + ::free(buffer); ref = 0; size = GetFileSize(h,NULL); - buffer = (unsigned char *) mem.malloc(size + 2); + buffer = (unsigned char *) ::malloc(size + 2); if (!buffer) goto err2; @@ -1191,7 +1191,7 @@ err1: err2: CloseHandle(h); err: - mem.free(buffer); + ::free(buffer); buffer = NULL; len = 0; @@ -1454,23 +1454,23 @@ void File::remove() #endif } -Array *File::match(char *n) +Files *File::match(char *n) { return match(new FileName(n, 0)); } -Array *File::match(FileName *n) +Files *File::match(FileName *n) { #if POSIX return NULL; #elif _WIN32 HANDLE h; WIN32_FIND_DATAA fileinfo; - Array *a; + Files *a; char *c; char *name; - a = new Array(); + a = new Files(); c = n->toChars(); name = n->name(); h = FindFirstFileA(c,&fileinfo); @@ -1563,11 +1563,11 @@ OutBuffer::~OutBuffer() mem.free(data); } -void *OutBuffer::extractData() +char *OutBuffer::extractData() { - void *p; + char *p; - p = (void *)data; + p = (char *)data; data = NULL; offset = 0; size = 0; diff --git a/dmd/root/root.h b/dmd/root/root.h index 1d19048f..8c2557f0 100644 --- a/dmd/root/root.h +++ b/dmd/root/root.h @@ -1,6 +1,6 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -13,6 +13,9 @@ #include #include +#ifdef DEBUG +#include +#endif #if __DMC__ #pragma once @@ -68,7 +71,12 @@ longlong randomx(); */ struct OutBuffer; -struct Array; + +// Can't include arraytypes.h here, need to declare these directly. +template struct ArrayBase; +typedef ArrayBase Files; +typedef ArrayBase Strings; + struct Object { @@ -149,14 +157,14 @@ struct FileName : String static const char *replaceName(const char *path, const char *name); static char *combine(const char *path, const char *name); - static Array *splitPath(const char *path); + static Strings *splitPath(const char *path); static FileName *defaultExt(const char *name, const char *ext); static FileName *forceExt(const char *name, const char *ext); int equalsExt(const char *ext); void CopyTo(FileName *to); - static char *searchPath(Array *path, const char *name, int cwd); - static char *safeSearchPath(Array *path, const char *name); + static char *searchPath(Strings *path, const char *name, int cwd); + static char *safeSearchPath(Strings *path, const char *name); static int exists(const char *name); static void ensurePathExists(const char *path); static char *canonicalName(const char *name); @@ -241,8 +249,8 @@ struct File : Object * matching File's. */ - static Array *match(char *); - static Array *match(FileName *); + static Files *match(char *); + static Files *match(FileName *); // Compare file times. // Return <0 this < f @@ -275,7 +283,7 @@ struct OutBuffer : Object OutBuffer(); ~OutBuffer(); - void *extractData(); + char *extractData(); void mark(); void reserve(unsigned nbytes); @@ -348,6 +356,48 @@ struct Array : Object Array *copy(); }; +template +struct ArrayBase : Array +{ + TYPE **tdata() + { + return (TYPE **)data; + } + + TYPE*& operator[] (size_t index) + { +#ifdef DEBUG + assert(index < dim); +#endif + return ((TYPE **)data)[index]; + } + + void insert(size_t index, TYPE *v) + { + Array::insert(index, (void *)v); + } + + void insert(size_t index, ArrayBase *a) + { + Array::insert(index, (Array *)a); + } + + void append(ArrayBase *a) + { + Array::append((Array *)a); + } + + void push(TYPE *a) + { + Array::push((void *)a); + } + + ArrayBase *copy() + { + return (ArrayBase *)Array::copy(); + } +}; + struct Bits : Object { unsigned bitdim; diff --git a/dmd/root/stringtable.c b/dmd/root/stringtable.c index 2f54852a..a50f737d 100644 --- a/dmd/root/stringtable.c +++ b/dmd/root/stringtable.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -18,7 +18,7 @@ #include "lstring.h" #include "stringtable.h" -StringTable::StringTable(unsigned size) +void StringTable::init(unsigned size) { table = (void **)mem.calloc(size, sizeof(void *)); tabledim = size; diff --git a/dmd/root/stringtable.h b/dmd/root/stringtable.h index c56d9b4f..c9ba26c5 100644 --- a/dmd/root/stringtable.h +++ b/dmd/root/stringtable.h @@ -1,4 +1,4 @@ -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -28,13 +28,13 @@ struct StringValue Lstring lstring; }; -struct StringTable : Object +struct StringTable { void **table; unsigned count; unsigned tabledim; - StringTable(unsigned size = 37); + void init(unsigned size = 37); ~StringTable(); StringValue *lookup(const dchar *s, unsigned len); diff --git a/dmd/speller.c b/dmd/speller.c index 845f5756..4cfd5273 100644 --- a/dmd/speller.c +++ b/dmd/speller.c @@ -111,7 +111,7 @@ void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, /* Deletions */ memcpy(buf, seed + 1, seedlen); - for (int i = 0; i < seedlen; i++) + for (size_t i = 0; i < seedlen; i++) { //printf("del buf = '%s'\n", buf); void *p; @@ -129,7 +129,7 @@ void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, if (!flag) { memcpy(buf, seed, seedlen + 1); - for (int i = 0; i + 1 < seedlen; i++) + for (size_t i = 0; i + 1 < seedlen; i++) { // swap [i] and [i + 1] buf[i] = seed[i + 1]; @@ -148,7 +148,7 @@ void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, { /* Substitutions */ memcpy(buf, seed, seedlen + 1); - for (int i = 0; i < seedlen; i++) + for (size_t i = 0; i < seedlen; i++) { for (const char *s = charset; *s; s++) { @@ -168,7 +168,7 @@ void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, /* Insertions */ memcpy(buf + 1, seed, seedlen + 1); - for (int i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations + for (size_t i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations { for (const char *s = charset; *s; s++) { diff --git a/dmd/statement.c b/dmd/statement.c index bb64b66f..d6ae39bd 100644 --- a/dmd/statement.c +++ b/dmd/statement.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -38,18 +38,27 @@ /*********************************** * Return size of OS critical section. */ -#if _WIN32 -int os_critsecsize() -{ - return sizeof(CRITICAL_SECTION); -} -#endif - -#if linux || __APPLE__ || __FreeBSD__ || __HAIKU__ || __sun&&__SVR4 +#if IN_LLVM +// sizes based on those from tollvm.cpp:DtoMutexType() int os_critsecsize() { +#if defined(_MSC_VER) + // TODO Check size + return 68; +#else + if (global.params.os == OSWindows) + return 68; + else if (global.params.os == OSFreeBSD) + return sizeof(size_t); + else return sizeof(pthread_mutex_t); +#endif } +#elif IN_DMD + +extern int os_critsecsize32(); +extern int os_critsecsize64(); + #endif /******************************** Statement ***************************/ @@ -57,11 +66,9 @@ int os_critsecsize() Statement::Statement(Loc loc) : loc(loc) { -#ifdef _DH // If this is an in{} contract scope statement (skip for determining // inlineStatus of a function body for header content) incontract = 0; -#endif } Statement *Statement::syntaxCopy() @@ -158,7 +165,7 @@ int Statement::usesEH() /* Only valid after semantic analysis */ -int Statement::blockExit() +int Statement::blockExit(bool mustNotThrow) { printf("Statement::blockExit(%p)\n", this); printf("%s\n", toChars()); @@ -236,6 +243,12 @@ ExpStatement::ExpStatement(Loc loc, Expression *exp) this->exp = exp; } +ExpStatement::ExpStatement(Loc loc, Dsymbol *declaration) + : Statement(loc) +{ + this->exp = new DeclarationExp(loc, declaration); +} + Statement *ExpStatement::syntaxCopy() { Expression *e = exp ? exp->syntaxCopy() : NULL; @@ -246,10 +259,19 @@ Statement *ExpStatement::syntaxCopy() void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (exp) - exp->toCBuffer(buf, hgs); + { exp->toCBuffer(buf, hgs); + if (exp->op != TOKdeclaration) + { buf->writeByte(';'); + if (!hgs->FLinit.init) + buf->writenl(); + } + } + else + { buf->writeByte(';'); if (!hgs->FLinit.init) buf->writenl(); + } } Statement *ExpStatement::semantic(Scope *sc) @@ -261,16 +283,11 @@ Statement *ExpStatement::semantic(Scope *sc) exp = resolveProperties(sc, exp); exp->checkSideEffect(0); exp = exp->optimize(0); - if (exp->op == TOKdeclaration && !isDeclarationStatement()) - { Statement *s = new DeclarationStatement(loc, exp); - return s; - } - //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0); } return this; } -int ExpStatement::blockExit() +int ExpStatement::blockExit(bool mustNotThrow) { int result = BEfallthru; if (exp) @@ -294,6 +311,53 @@ int ExpStatement::isEmpty() return exp == NULL; } +void ExpStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("ExpStatement::scopeCode()\n"); + //print(); + + *sentry = NULL; + *sexception = NULL; + *sfinally = NULL; + + if (exp) + { + if (exp->op == TOKdeclaration) + { + DeclarationExp *de = (DeclarationExp *)(exp); + VarDeclaration *v = de->declaration->isVarDeclaration(); + if (v) + { Expression *e; + + e = v->callScopeDtor(sc); + if (e) + { + //printf("dtor is: "); e->print(); +#if 0 + if (v->type->toBasetype()->ty == Tstruct) + { /* Need a 'gate' to turn on/off destruction, + * in case v gets moved elsewhere. + */ + Identifier *id = Lexer::uniqueId("__runDtor"); + ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1)); + VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie); + *sentry = new ExpStatement(loc, rd); + v->rundtor = rd; + + /* Rewrite e as: + * rundtor && e + */ + Expression *ve = new VarExp(loc, v->rundtor); + e = new AndAndExp(loc, ve, e); + e->type = Type::tbool; + } +#endif + *sfinally = new ExpStatement(loc, e); + } + } + } + } +} /******************************** CompileStatement ***************************/ @@ -325,11 +389,13 @@ Statements *CompileStatement::flatten(Scope *sc) exp = exp->semantic(sc); exp = resolveProperties(sc, exp); exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring) + if (exp->op == TOKerror) + return NULL; + StringExp *se = exp->toString(); + if (!se) { error("argument to mixin must be a string, not (%s)", exp->toChars()); return NULL; } - StringExp *se = (StringExp *)exp; se = se->toUTF8(sc); Parser p(sc->module, (unsigned char *)se->string, se->len, 0); p.loc = loc; @@ -356,59 +422,6 @@ Statement *CompileStatement::semantic(Scope *sc) } -/******************************** DeclarationStatement ***************************/ - -DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration) - : ExpStatement(loc, new DeclarationExp(loc, declaration)) -{ -} - -DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp) - : ExpStatement(loc, exp) -{ -} - -Statement *DeclarationStatement::syntaxCopy() -{ - DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy()); - return ds; -} - -void DeclarationStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("DeclarationStatement::scopeCode()\n"); - //print(); - - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - - if (exp) - { - if (exp->op == TOKdeclaration) - { - DeclarationExp *de = (DeclarationExp *)(exp); - VarDeclaration *v = de->declaration->isVarDeclaration(); - if (v) - { Expression *e; - - e = v->callScopeDtor(sc); - if (e) - { - //printf("dtor is: "); e->print(); - *sfinally = new ExpStatement(loc, e); - } - } - } - } -} - -void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - exp->toCBuffer(buf, hgs); -} - - /******************************** CompoundStatement ***************************/ CompoundStatement::CompoundStatement(Loc loc, Statements *s) @@ -505,9 +518,9 @@ Statement *CompoundStatement::semantic(Scope *sc) Statement *body; Statements *a = new Statements(); - for (int j = i + 1; j < statements->dim; j++) + for (size_t j = i + 1; j < statements->dim; j++) { - a->push(statements->data[j]); + a->push((*statements)[j]); } body = new CompoundStatement(0, a); body = new ScopeStatement(0, body); @@ -546,9 +559,9 @@ Statement *CompoundStatement::semantic(Scope *sc) Statement *body; Statements *a = new Statements(); - for (int j = i + 1; j < statements->dim; j++) + for (size_t j = i + 1; j < statements->dim; j++) { - a->push(statements->data[j]); + a->push((*statements)[j]); } body = new CompoundStatement(0, a); s = new TryFinallyStatement(0, body, sfinally); @@ -564,7 +577,7 @@ Statement *CompoundStatement::semantic(Scope *sc) } if (statements->dim == 1 && !isAsmBlockStatement()) { - return (Statement *)statements->data[0]; + return (*statements)[0]; } return this; } @@ -578,8 +591,8 @@ ReturnStatement *CompoundStatement::isReturnStatement() { ReturnStatement *rs = NULL; - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (*statements)[i]; if (s) { rs = s->isReturnStatement(); @@ -592,7 +605,7 @@ ReturnStatement *CompoundStatement::isReturnStatement() void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { - for (int i = 0; i < statements->dim; i++) + for (size_t i = 0; i < statements->dim; i++) { Statement *s = (Statement *) statements->data[i]; if (s) s->toCBuffer(buf, hgs); @@ -601,7 +614,7 @@ void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) int CompoundStatement::usesEH() { - for (int i = 0; i < statements->dim; i++) + for (size_t i = 0; i < statements->dim; i++) { Statement *s = (Statement *) statements->data[i]; if (s && s->usesEH()) return TRUE; @@ -609,7 +622,7 @@ int CompoundStatement::usesEH() return FALSE; } -int CompoundStatement::blockExit() +int CompoundStatement::blockExit(bool mustNotThrow) { //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); int result = BEfallthru; @@ -621,13 +634,13 @@ int CompoundStatement::blockExit() //printf("%s\n", s->toChars()); if (!(result & BEfallthru) && !s->comeFrom()) { - if (s->blockExit() != BEhalt && !s->isEmpty()) + if (s->blockExit(mustNotThrow) != BEhalt && !s->isEmpty()) s->warning("statement is not reachable"); } else { result &= ~BEfallthru; - result |= s->blockExit(); + result |= s->blockExit(mustNotThrow); } } } @@ -638,7 +651,7 @@ int CompoundStatement::comeFrom() { int comefrom = FALSE; //printf("CompoundStatement::comeFrom()\n"); - for (int i = 0; i < statements->dim; i++) + for (size_t i = 0; i < statements->dim; i++) { Statement *s = (Statement *)statements->data[i]; if (!s) @@ -651,7 +664,7 @@ int CompoundStatement::comeFrom() int CompoundStatement::isEmpty() { - for (int i = 0; i < statements->dim; i++) + for (size_t i = 0; i < statements->dim; i++) { Statement *s = (Statement *) statements->data[i]; if (s && !s->isEmpty()) return FALSE; @@ -685,11 +698,13 @@ Statement *CompoundDeclarationStatement::syntaxCopy() void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { int nwritten = 0; - for (int i = 0; i < statements->dim; i++) + for (size_t i = 0; i < statements->dim; i++) { Statement *s = (Statement *) statements->data[i]; - if (s) - { DeclarationStatement *ds = s->isDeclarationStatement(); - assert(ds); + ExpStatement *ds; + if (s && + (ds = s->isExpStatement()) != NULL && + ds->exp->op == TOKdeclaration) + { DeclarationExp *de = (DeclarationExp *)ds->exp; assert(de->op == TOKdeclaration); Declaration *d = de->declaration->isDeclaration(); @@ -821,14 +836,14 @@ int UnrolledLoopStatement::usesEH() return FALSE; } -int UnrolledLoopStatement::blockExit() +int UnrolledLoopStatement::blockExit(bool mustNotThrow) { int result = BEfallthru; for (size_t i = 0; i < statements->dim; i++) { Statement *s = (Statement *) statements->data[i]; if (s) { - int r = s->blockExit(); + int r = s->blockExit(mustNotThrow); result |= r & ~(BEbreak | BEcontinue); } } @@ -924,10 +939,10 @@ int ScopeStatement::usesEH() return statement ? statement->usesEH() : FALSE; } -int ScopeStatement::blockExit() +int ScopeStatement::blockExit(bool mustNotThrow) { //printf("ScopeStatement::blockExit(%p)\n", statement); - return statement ? statement->blockExit() : BEfallthru; + return statement ? statement->blockExit(mustNotThrow) : BEfallthru; } @@ -997,7 +1012,7 @@ int WhileStatement::usesEH() return body ? body->usesEH() : 0; } -int WhileStatement::blockExit() +int WhileStatement::blockExit(bool mustNotThrow) { assert(0); //printf("WhileStatement::blockExit(%p)\n", this); @@ -1008,7 +1023,7 @@ int WhileStatement::blockExit() if (condition->isBool(TRUE)) { if (body) - { result |= body->blockExit(); + { result |= body->blockExit(mustNotThrow); if (result & BEbreak) result |= BEfallthru; } @@ -1020,7 +1035,7 @@ int WhileStatement::blockExit() else { if (body) - result |= body->blockExit(); + result |= body->blockExit(mustNotThrow); result |= BEfallthru; } result &= ~(BEbreak | BEcontinue); @@ -1092,11 +1107,11 @@ int DoStatement::usesEH() return body ? body->usesEH() : 0; } -int DoStatement::blockExit() +int DoStatement::blockExit(bool mustNotThrow) { int result; if (body) - { result = body->blockExit(); + { result = body->blockExit(mustNotThrow); if (result == BEbreak) return BEfallthru; if (result & BEcontinue) @@ -1222,11 +1237,11 @@ int ForStatement::usesEH() return (init && init->usesEH()) || body->usesEH(); } -int ForStatement::blockExit() +int ForStatement::blockExit(bool mustNotThrow) { int result = BEfallthru; if (init) - { result = init->blockExit(); + { result = init->blockExit(mustNotThrow); if (!(result & BEfallthru)) return result; } @@ -1241,7 +1256,7 @@ int ForStatement::blockExit() else result &= ~BEfallthru; // the body must do the exiting if (body) - { int r = body->blockExit(); + { int r = body->blockExit(mustNotThrow); if (r & (BEbreak | BEgoto)) result |= BEfallthru; result |= r & ~(BEfallthru | BEbreak | BEcontinue); @@ -1387,16 +1402,17 @@ Statement *ForeachStatement::semantic(Scope *sc) Expression *e; Type *t; if (te) - e = (Expression *)te->exps->data[k]; + e = te->exps->tdata()[k]; else t = Parameter::getNth(tuple->arguments, k)->type; - Parameter *arg = (Parameter *)arguments->data[0]; + Parameter *arg = arguments->tdata()[0]; Statements *st = new Statements(); if (dim == 2) { // Declare key if (arg->storageClass & (STCout | STCref | STClazy)) error("no storage class for key %s", arg->ident->toChars()); + arg->type = arg->type->semantic(loc, sc); TY keyty = arg->type->ty; if (keyty != Tint32 && keyty != Tuns32) { @@ -1413,7 +1429,7 @@ Statement *ForeachStatement::semantic(Scope *sc) var->storage_class |= STCconst; DeclarationExp *de = new DeclarationExp(loc, var); st->push(new ExpStatement(loc, de)); - arg = (Parameter *)arguments->data[1]; // value + arg = (*arguments)[1]; // value } // Declare value if (arg->storageClass & (STCout | STCref | STClazy)) @@ -1421,16 +1437,22 @@ Statement *ForeachStatement::semantic(Scope *sc) Dsymbol *var; if (te) { Type *tb = e->type->toBasetype(); + Dsymbol *s = NULL; if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar) - { VarExp *ve = (VarExp *)e; - var = new AliasDeclaration(loc, arg->ident, ve->var); - } + s = ((VarExp *)e)->var; + else if (e->op == TOKtemplate) + s =((TemplateExp *)e)->td; + else if (e->op == TOKimport) + s =((ScopeExp *)e)->sds; + + if (s) + var = new AliasDeclaration(loc, arg->ident, s); else { arg->type = e->type; Initializer *ie = new ExpInitializer(0, e); VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); - if (e->isConst()) + if (e->isConst() || e->op == TOKstring) v->storage_class |= STCconst; var = v; } @@ -1542,8 +1564,8 @@ Statement *ForeachStatement::semantic(Scope *sc) if (!key) { - Identifier *id = Lexer::uniqueId("__key"); - key = new VarDeclaration(loc, Type::tsize_t, id, NULL); + Identifier *idkey = Lexer::uniqueId("__key"); + key = new VarDeclaration(loc, Type::tsize_t, idkey, NULL); } if (op == TOKforeach_reverse) key->init = new ExpInitializer(loc, tmp_length); @@ -1551,8 +1573,8 @@ Statement *ForeachStatement::semantic(Scope *sc) key->init = new ExpInitializer(loc, new IntegerExp(0)); Statements *cs = new Statements(); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); + cs->push(new ExpStatement(loc, tmp)); + cs->push(new ExpStatement(loc, key)); Statement *forinit = new CompoundDeclarationStatement(loc, cs); Expression *cond; @@ -1570,7 +1592,7 @@ Statement *ForeachStatement::semantic(Scope *sc) // T value = tmp[key]; value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); - Statement *ds = new DeclarationStatement(loc, new DeclarationExp(loc, value)); + Statement *ds = new ExpStatement(loc, value); body = new CompoundStatement(loc, ds, body); @@ -1665,7 +1687,7 @@ Statement *ForeachStatement::semantic(Scope *sc) VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, rinit)); // r->semantic(sc); //printf("r: %s, init: %s\n", r->toChars(), r->init->toChars()); - Statement *init = new DeclarationStatement(loc, r); + Statement *init = new ExpStatement(loc, r); //printf("init: %s\n", init->toChars()); // !__r.empty @@ -1691,7 +1713,7 @@ Statement *ForeachStatement::semantic(Scope *sc) DeclarationExp *de = new DeclarationExp(loc, ve); Statement *body = new CompoundStatement(loc, - new DeclarationStatement(loc, de), this->body); + new ExpStatement(loc, de), this->body); s = new ForStatement(loc, init, condition, increment, body); #if 0 @@ -1746,14 +1768,14 @@ Statement *ForeachStatement::semantic(Scope *sc) id = Lexer::uniqueId("__applyArg", i); Initializer *ie = new ExpInitializer(0, new IdentifierExp(0, id)); VarDeclaration *v = new VarDeclaration(0, arg->type, arg->ident, ie); - s = new DeclarationStatement(0, v); + s = new ExpStatement(0, v); body = new CompoundStatement(loc, s, body); } a = new Parameter(STCref, arg->type, id, NULL); args->push(a); } Type *t = new TypeFunction(args, Type::tint32, 0, LINKd); - cases = new Array(); + cases = new Statements(); gotos = new Array(); FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); fld->fbody = body; @@ -1773,7 +1795,7 @@ Statement *ForeachStatement::semantic(Scope *sc) } } - if (tab->ty == Taarray) + if (taa) { // Check types Parameter *arg = (Parameter *)arguments->data[0]; @@ -1829,7 +1851,10 @@ Statement *ForeachStatement::semantic(Scope *sc) Expressions *exps = new Expressions(); exps->push(aggr); size_t keysize = taa->key->size(); - keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1); + if (global.params.is64bit) + keysize = (keysize + 15) & ~15; + else + keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1); exps->push(new IntegerExp(0, keysize, Type::tsize_t)); // LDC paint delegate argument to the type runtime expects @@ -1958,7 +1983,7 @@ Statement *ForeachStatement::semantic(Scope *sc) a->push(s); // cases 2... - for (int i = 0; i < cases->dim; i++) + for (size_t i = 0; i < cases->dim; i++) { s = (Statement *)cases->data[i]; s = new CaseStatement(0, new IntegerExp(i + 2), s); @@ -1971,6 +1996,9 @@ Statement *ForeachStatement::semantic(Scope *sc) } break; } + case Terror: + s = NULL; + break; default: error("foreach: %s is not an aggregate type", aggr->type->toChars()); @@ -1997,7 +2025,7 @@ int ForeachStatement::usesEH() return body->usesEH(); } -int ForeachStatement::blockExit() +int ForeachStatement::blockExit(bool mustNotThrow) { int result = BEfallthru; if (aggr->canThrow()) @@ -2005,7 +2033,7 @@ int ForeachStatement::blockExit() if (body) { - result |= body->blockExit() & ~(BEbreak | BEcontinue); + result |= body->blockExit(mustNotThrow) & ~(BEbreak | BEcontinue); } return result; } @@ -2022,7 +2050,7 @@ void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring(Token::toChars(op)); buf->writestring(" ("); - for (int i = 0; i < arguments->dim; i++) + for (size_t i = 0; i < arguments->dim; i++) { Parameter *a = (Parameter *)arguments->data[i]; if (i) @@ -2077,7 +2105,6 @@ Statement *ForeachRangeStatement::syntaxCopy() Statement *ForeachRangeStatement::semantic(Scope *sc) { //printf("ForeachRangeStatement::semantic() %p\n", this); - ScopeDsymbol *sym; Statement *s = this; lwr = lwr->semantic(sc); @@ -2136,13 +2163,13 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) // Keep order of evaluation as lwr, then upr if (op == TOKforeach) { - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs->push(new ExpStatement(loc, key)); + cs->push(new ExpStatement(loc, tmp)); } else { - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); + cs->push(new ExpStatement(loc, tmp)); + cs->push(new ExpStatement(loc, key)); } Statement *forinit = new CompoundDeclarationStatement(loc, cs); @@ -2207,7 +2234,7 @@ int ForeachRangeStatement::usesEH() return body->usesEH(); } -int ForeachRangeStatement::blockExit() +int ForeachRangeStatement::blockExit(bool mustNotThrow) { assert(0); int result = BEfallthru; @@ -2219,7 +2246,7 @@ int ForeachRangeStatement::blockExit() if (body) { - result |= body->blockExit() & ~(BEbreak | BEcontinue); + result |= body->blockExit(mustNotThrow) & ~(BEbreak | BEcontinue); } return result; } @@ -2344,7 +2371,7 @@ int IfStatement::usesEH() return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); } -int IfStatement::blockExit() +int IfStatement::blockExit(bool mustNotThrow) { //printf("IfStatement::blockExit(%p)\n", this); @@ -2354,25 +2381,25 @@ int IfStatement::blockExit() if (condition->isBool(TRUE)) { if (ifbody) - result |= ifbody->blockExit(); + result |= ifbody->blockExit(mustNotThrow); else result |= BEfallthru; } else if (condition->isBool(FALSE)) { if (elsebody) - result |= elsebody->blockExit(); + result |= elsebody->blockExit(mustNotThrow); else result |= BEfallthru; } else { if (ifbody) - result |= ifbody->blockExit(); + result |= ifbody->blockExit(mustNotThrow); else result |= BEfallthru; if (elsebody) - result |= elsebody->blockExit(); + result |= elsebody->blockExit(mustNotThrow); else result |= BEfallthru; } @@ -2464,11 +2491,11 @@ int ConditionalStatement::usesEH() return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); } -int ConditionalStatement::blockExit() +int ConditionalStatement::blockExit(bool mustNotThrow) { - int result = ifbody->blockExit(); + int result = ifbody->blockExit(mustNotThrow); if (elsebody) - result |= elsebody->blockExit(); + result |= elsebody->blockExit(mustNotThrow); return result; } @@ -2526,13 +2553,13 @@ Statement *PragmaStatement::semantic(Scope *sc) { for (size_t i = 0; i < args->dim; i++) { - Expression *e = (Expression *)args->data[i]; + Expression *e = args->tdata()[i]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKstring) + StringExp *se = e->toString(); + if (se) { - StringExp *se = (StringExp *)e; fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); } else @@ -2552,16 +2579,16 @@ Statement *PragmaStatement::semantic(Scope *sc) error("string expected for library name"); else { - Expression *e = (Expression *)args->data[0]; + Expression *e = args->tdata()[0]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) + args->tdata()[0] = e; + StringExp *se = e->toString(); + if (!se) 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; @@ -2614,14 +2641,14 @@ int PragmaStatement::usesEH() return body && body->usesEH(); } -int PragmaStatement::blockExit() +int PragmaStatement::blockExit(bool mustNotThrow) { int result = BEfallthru; #if 0 // currently, no code is generated for Pragma's, so it's just fallthru if (arrayExpressionCanThrow(args)) result |= BEthrow; if (body) - result |= body->blockExit(); + result |= body->blockExit(mustNotThrow); #endif return result; } @@ -2676,7 +2703,7 @@ Statement *StaticAssertStatement::semantic(Scope *sc) return NULL; } -int StaticAssertStatement::blockExit() +int StaticAssertStatement::blockExit(bool mustNotThrow) { return BEfallthru; } @@ -2736,13 +2763,13 @@ Statement *SwitchStatement::semantic(Scope *sc) sc->sbreak = this; sc->sw = this; - cases = new Array(); + cases = new CaseStatements(); sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead body = body->semantic(sc); sc->noctor--; // Resolve any goto case's with exp - for (int i = 0; i < gotoCases.dim; i++) + for (size_t i = 0; i < gotoCases.dim; i++) { GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i]; @@ -2756,7 +2783,7 @@ Statement *SwitchStatement::semantic(Scope *sc) { if (!scx->sw) continue; - for (int j = 0; j < scx->sw->cases->dim; j++) + for (size_t j = 0; j < scx->sw->cases->dim; j++) { CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j]; @@ -2849,13 +2876,13 @@ int SwitchStatement::usesEH() return body ? body->usesEH() : 0; } -int SwitchStatement::blockExit() +int SwitchStatement::blockExit(bool mustNotThrow) { int result = BEnone; if (condition->canThrow()) result |= BEthrow; if (body) - { result |= body->blockExit(); + { result |= body->blockExit(mustNotThrow); if (result & BEbreak) { result |= BEfallthru; result &= ~BEbreak; @@ -2927,13 +2954,13 @@ Statement *CaseStatement::semantic(Scope *sc) exp = exp->implicitCastTo(sc, sw->condition->type); exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring && exp->op != TOKint64) + if (exp->op != TOKstring && exp->op != TOKint64 && exp->op != TOKerror) { error("case must be a string or an integral constant, not %s", exp->toChars()); exp = new IntegerExp(0); } - for (int i = 0; i < sw->cases->dim; i++) + for (size_t i = 0; i < sw->cases->dim; i++) { CaseStatement *cs = (CaseStatement *)sw->cases->data[i]; @@ -2977,9 +3004,9 @@ int CaseStatement::usesEH() return statement->usesEH(); } -int CaseStatement::blockExit() +int CaseStatement::blockExit(bool mustNotThrow) { - return statement->blockExit(); + return statement->blockExit(mustNotThrow); } @@ -3027,11 +3054,15 @@ Statement *CaseRangeStatement::semantic(Scope *sc) first = first->semantic(sc); first = first->implicitCastTo(sc, sw->condition->type); first = first->optimize(WANTvalue | WANTinterpret); - dinteger_t fval = first->toInteger(); last = last->semantic(sc); last = last->implicitCastTo(sc, sw->condition->type); last = last->optimize(WANTvalue | WANTinterpret); + + if (first->op == TOKerror || last->op == TOKerror) + return statement ? statement->semantic(sc) : NULL; + + dinteger_t fval = first->toInteger(); dinteger_t lval = last->toInteger(); if (lval - fval > 256) @@ -3126,9 +3157,9 @@ int DefaultStatement::usesEH() return statement->usesEH(); } -int DefaultStatement::blockExit() +int DefaultStatement::blockExit(bool mustNotThrow) { - return statement->blockExit(); + return statement->blockExit(mustNotThrow); } @@ -3165,7 +3196,7 @@ Statement *GotoDefaultStatement::semantic(Scope *sc) return this; } -int GotoDefaultStatement::blockExit() +int GotoDefaultStatement::blockExit(bool mustNotThrow) { return BEgoto; } @@ -3213,7 +3244,7 @@ Statement *GotoCaseStatement::semantic(Scope *sc) return this; } -int GotoCaseStatement::blockExit() +int GotoCaseStatement::blockExit(bool mustNotThrow) { return BEgoto; } @@ -3237,7 +3268,7 @@ SwitchErrorStatement::SwitchErrorStatement(Loc loc) { } -int SwitchErrorStatement::blockExit() +int SwitchErrorStatement::blockExit(bool mustNotThrow) { return BEthrow; } @@ -3353,11 +3384,12 @@ Statement *ReturnStatement::semantic(Scope *sc) } else if (fd->inferRetType) { - if (fd->type->nextOf()) + Type *tfret = fd->type->nextOf(); + if (tfret) { - if (!exp->type->equals(fd->type->nextOf())) + if (tfret != Type::terror && !exp->type->equals(tfret)) error("mismatched function return type inference of %s and %s", - exp->type->toChars(), fd->type->nextOf()->toChars()); + exp->type->toChars(), tfret->toChars()); } else { @@ -3371,6 +3403,8 @@ Statement *ReturnStatement::semantic(Scope *sc) } else if (tbret->ty != Tvoid) { + if (fd->tintro) + exp = exp->implicitCastTo(sc, fd->type->nextOf()); exp = exp->implicitCastTo(sc, tret); } } @@ -3510,7 +3544,7 @@ Statement *ReturnStatement::semantic(Scope *sc) return this; } -int ReturnStatement::blockExit() +int ReturnStatement::blockExit(bool mustNotThrow) { int result = BEreturn; if (exp && exp->canThrow()) @@ -3605,7 +3639,7 @@ Statement *BreakStatement::semantic(Scope *sc) return this; } -int BreakStatement::blockExit() +int BreakStatement::blockExit(bool mustNotThrow) { //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); return ident ? BEgoto : BEbreak; @@ -3708,7 +3742,7 @@ Statement *ContinueStatement::semantic(Scope *sc) return this; } -int ContinueStatement::blockExit() +int ContinueStatement::blockExit(bool mustNotThrow) { return ident ? BEgoto : BEcontinue; } @@ -3784,7 +3818,7 @@ Statement *SynchronizedStatement::semantic(Scope *sc) VarDeclaration *tmp = new VarDeclaration(loc, exp->type, id, ie); Statements *cs = new Statements(); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs->push(new ExpStatement(loc, tmp)); Parameters* enterargs = new Parameters; enterargs->push(new Parameter(STCin, ClassDeclaration::object->type, NULL, NULL)); @@ -3812,12 +3846,16 @@ Statement *SynchronizedStatement::semantic(Scope *sc) * try { body } finally { _d_criticalexit(critsec.ptr); } */ Identifier *id = Lexer::uniqueId("__critsec"); +#if IN_DMD + Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + (global.params.is64bit ? os_critsecsize64() : os_critsecsize32()))); +#elif IN_LLVM Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + os_critsecsize())); +#endif VarDeclaration *tmp = new VarDeclaration(loc, t, id, NULL); tmp->storage_class |= STCgshared | STCstatic; Statements *cs = new Statements(); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs->push(new ExpStatement(loc, tmp)); Parameters* enterargs = new Parameters; enterargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); @@ -3859,9 +3897,9 @@ int SynchronizedStatement::usesEH() return TRUE; } -int SynchronizedStatement::blockExit() +int SynchronizedStatement::blockExit(bool mustNotThrow) { - return body ? body->blockExit() : BEfallthru; + return body ? body->blockExit(mustNotThrow) : BEfallthru; } @@ -3903,6 +3941,8 @@ Statement *WithStatement::semantic(Scope *sc) //printf("WithStatement::semantic()\n"); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + if (exp->op == TOKerror) + return NULL; if (exp->op == TOKimport) { ScopeExp *es = (ScopeExp *)exp; @@ -3972,13 +4012,13 @@ int WithStatement::usesEH() return body ? body->usesEH() : 0; } -int WithStatement::blockExit() +int WithStatement::blockExit(bool mustNotThrow) { int result = BEnone; if (exp->canThrow()) result = BEthrow; if (body) - result |= body->blockExit(); + result |= body->blockExit(mustNotThrow); else result |= BEfallthru; return result; @@ -3998,7 +4038,7 @@ Statement *TryCatchStatement::syntaxCopy() { Array *a = new Array(); a->setDim(catches->dim); - for (int i = 0; i < a->dim; i++) + for (size_t i = 0; i < a->dim; i++) { Catch *c; c = (Catch *)catches->data[i]; @@ -4047,19 +4087,36 @@ int TryCatchStatement::usesEH() return TRUE; } -int TryCatchStatement::blockExit() +int TryCatchStatement::blockExit(bool mustNotThrow) { assert(body); - int result = body->blockExit(); + int result = body->blockExit(false); + int catchresult = 0; for (size_t i = 0; i < catches->dim; i++) { Catch *c = (Catch *)catches->data[i]; - result |= c->blockExit(); + if (c->type == Type::terror) + continue; + + catchresult |= c->blockExit(mustNotThrow); + + /* If we're catching Object, then there is no throwing + */ + Identifier *id = c->type->toBasetype()->isClassHandle()->ident; + if (id == Id::Object) + { + result &= ~BEthrow; } - return result; + } + if (mustNotThrow && (result & BEthrow)) + { + body->blockExit(mustNotThrow); // now explain why this is nothrow + } + return result | catchresult; } + void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("try"); @@ -4137,9 +4194,9 @@ void Catch::semantic(Scope *sc) sc->pop(); } -int Catch::blockExit() +int Catch::blockExit(bool mustNotThrow) { - return handler ? handler->blockExit() : BEfallthru; + return handler ? handler->blockExit(mustNotThrow) : BEfallthru; } void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -4218,10 +4275,10 @@ int TryFinallyStatement::usesEH() return TRUE; } -int TryFinallyStatement::blockExit() +int TryFinallyStatement::blockExit(bool mustNotThrow) { if (body) - return body->blockExit(); + return body->blockExit(mustNotThrow); return BEfallthru; } @@ -4248,7 +4305,7 @@ Statement *OnScopeStatement::semantic(Scope *sc) return this; } -int OnScopeStatement::blockExit() +int OnScopeStatement::blockExit(bool mustNotThrow) { // At this point, this statement is just an empty placeholder return BEfallthru; } @@ -4293,7 +4350,7 @@ void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexc ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new DeclarationStatement(loc, v); + *sentry = new ExpStatement(loc, v); Expression *e = new IntegerExp(1); e = new AssignExp(0, new VarExp(0, v), e); @@ -4336,12 +4393,14 @@ Statement *ThrowStatement::semantic(Scope *sc) error("Throw statements cannot be in contracts"); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + if (exp->op == TOKerror) + return this; if (!exp->type->toBasetype()->isClassHandle()) error("can only throw class objects, not type %s", exp->type->toChars()); return this; } -int ThrowStatement::blockExit() +int ThrowStatement::blockExit(bool mustNotThrow) { return BEthrow; // obviously } @@ -4388,7 +4447,7 @@ Statements *VolatileStatement::flatten(Scope *sc) a = statement ? statement->flatten(sc) : NULL; if (a) - { for (int i = 0; i < a->dim; i++) + { for (size_t i = 0; i < a->dim; i++) { Statement *s = (Statement *)a->data[i]; s = new VolatileStatement(loc, s); @@ -4399,9 +4458,9 @@ Statements *VolatileStatement::flatten(Scope *sc) return a; } -int VolatileStatement::blockExit() +int VolatileStatement::blockExit(bool mustNotThrow) { - return statement ? statement->blockExit() : BEfallthru; + return statement ? statement->blockExit(mustNotThrow) : BEfallthru; } @@ -4464,7 +4523,7 @@ Statement *GotoStatement::semantic(Scope *sc) return this; } -int GotoStatement::blockExit() +int GotoStatement::blockExit(bool mustNotThrow) { //printf("GotoStatement::blockExit(%p)\n", this); return BEgoto; @@ -4538,7 +4597,7 @@ Statements *LabelStatement::flatten(Scope *sc) { if (!a->dim) { - a->push(new ExpStatement(loc, NULL)); + a->push(new ExpStatement(loc, (Expression *)NULL)); } Statement *s = (Statement *)a->data[0]; @@ -4556,10 +4615,10 @@ int LabelStatement::usesEH() return statement ? statement->usesEH() : FALSE; } -int LabelStatement::blockExit() +int LabelStatement::blockExit(bool mustNotThrow) { //printf("LabelStatement::blockExit(%p)\n", this); - return statement ? statement->blockExit() : BEfallthru; + return statement ? statement->blockExit(mustNotThrow) : BEfallthru; } diff --git a/dmd/statement.h b/dmd/statement.h index 150fa71d..d8327d4b 100644 --- a/dmd/statement.h +++ b/dmd/statement.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -27,7 +27,7 @@ struct Expression; struct LabelDsymbol; struct Identifier; struct IfStatement; -struct DeclarationStatement; +struct ExpStatement; struct DefaultStatement; struct VarDeclaration; struct Condition; @@ -46,6 +46,9 @@ struct GotoStatement; struct ScopeStatement; struct TryCatchStatement; struct TryFinallyStatement; +struct CaseStatement; +struct DefaultStatement; +struct LabelStatement; struct HdrGenState; struct InterState; struct CaseStatement; @@ -112,9 +115,7 @@ struct Statement : Object virtual GotoStatement *isGotoStatement() { return NULL; } virtual AsmStatement *isAsmStatement() { return NULL; } virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; } -#ifdef _DH int incontract; -#endif virtual ScopeStatement *isScopeStatement() { return NULL; } virtual Statement *semantic(Scope *sc); Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue); @@ -122,7 +123,7 @@ struct Statement : Object virtual int hasBreak(); virtual int hasContinue(); virtual int usesEH(); - virtual int blockExit(); + virtual int blockExit(bool mustNotThrow); virtual int comeFrom(); virtual int isEmpty(); virtual void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); @@ -137,11 +138,12 @@ struct Statement : Object virtual void toIR(IRState *irs); // Avoid dynamic_cast - virtual DeclarationStatement *isDeclarationStatement() { return NULL; } + virtual ExpStatement *isExpStatement() { return NULL; } virtual CompoundStatement *isCompoundStatement() { return NULL; } virtual ReturnStatement *isReturnStatement() { return NULL; } virtual IfStatement *isIfStatement() { return NULL; } virtual CaseStatement* isCaseStatement() { return NULL; } + virtual DefaultStatement *isDefaultStatement() { return NULL; } virtual LabelStatement* isLabelStatement() { return NULL; } #if IN_LLVM @@ -163,12 +165,14 @@ struct ExpStatement : Statement Expression *exp; ExpStatement(Loc loc, Expression *exp); + ExpStatement(Loc loc, Dsymbol *s); Statement *syntaxCopy(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); - int blockExit(); + int blockExit(bool mustNotThrow); int isEmpty(); + void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); @@ -179,6 +183,8 @@ struct ExpStatement : Statement #if IN_LLVM void toNakedIR(IRState *irs); #endif + + ExpStatement *isExpStatement() { return this; } }; struct CompileStatement : Statement @@ -192,20 +198,6 @@ struct CompileStatement : Statement Statement *semantic(Scope *sc); }; -struct DeclarationStatement : ExpStatement -{ - // Doing declarations as an expression, rather than a statement, - // makes inlining functions much easier. - - DeclarationStatement(Loc loc, Dsymbol *s); - DeclarationStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - - DeclarationStatement *isDeclarationStatement() { return this; } -}; - struct CompoundStatement : Statement { Statements *statements; @@ -217,7 +209,7 @@ struct CompoundStatement : Statement void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual Statement *semantic(Scope *sc); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); int isEmpty(); virtual Statements *flatten(Scope *sc); @@ -257,7 +249,7 @@ struct UnrolledLoopStatement : Statement int hasBreak(); int hasContinue(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -281,7 +273,7 @@ struct ScopeStatement : Statement int hasBreak(); int hasContinue(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); int isEmpty(); Expression *interpret(InterState *istate); @@ -302,7 +294,7 @@ struct WhileStatement : Statement int hasBreak(); int hasContinue(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -323,7 +315,7 @@ struct DoStatement : Statement int hasBreak(); int hasContinue(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -347,7 +339,7 @@ struct ForStatement : Statement int hasBreak(); int hasContinue(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -369,7 +361,7 @@ struct ForeachStatement : Statement FuncDeclaration *func; // function we're lexically in - Array *cases; // put breaks, continues, gotos and returns here + Statements *cases; // put breaks, continues, gotos and returns here Array *gotos; // forward referenced goto's go here ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, Expression *aggr, Statement *body); @@ -379,7 +371,7 @@ struct ForeachStatement : Statement int hasBreak(); int hasContinue(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -407,7 +399,7 @@ struct ForeachRangeStatement : Statement int hasBreak(); int hasContinue(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -433,7 +425,7 @@ struct IfStatement : Statement Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); IfStatement *isIfStatement() { return this; } int inlineCost(InlineCostState *ics); @@ -454,7 +446,7 @@ struct ConditionalStatement : Statement Statement *semantic(Scope *sc); Statements *flatten(Scope *sc); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; @@ -469,7 +461,7 @@ struct PragmaStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; @@ -481,7 +473,7 @@ struct StaticAssertStatement : Statement StaticAssertStatement(StaticAssert *sa); Statement *syntaxCopy(); Statement *semantic(Scope *sc); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; @@ -494,7 +486,7 @@ struct SwitchStatement : Statement DefaultStatement *sdefault; Array gotoCases; // array of unresolved GotoCaseStatement's - Array *cases; // array of CaseStatement's + CaseStatements *cases; // array of CaseStatement's int hasNoDefault; // !=0 if no default statement // LDC @@ -505,7 +497,7 @@ struct SwitchStatement : Statement Statement *semantic(Scope *sc); int hasBreak(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -530,17 +522,16 @@ struct CaseStatement : Statement Statement *semantic(Scope *sc); int compare(Object *obj); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + CaseStatement *isCaseStatement() { return this; } Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); - CaseStatement* isCaseStatement() { return this; } - #if IN_LLVM llvm::BasicBlock* bodyBB; llvm::Value* llvmIdx; @@ -577,10 +568,11 @@ struct DefaultStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + DefaultStatement *isDefaultStatement() { return this; } Statement *inlineScan(InlineScanState *iss); @@ -598,7 +590,7 @@ struct GotoDefaultStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -614,7 +606,7 @@ struct GotoCaseStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -623,7 +615,7 @@ struct GotoCaseStatement : Statement struct SwitchErrorStatement : Statement { SwitchErrorStatement(Loc loc); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -637,7 +629,7 @@ struct ReturnStatement : Statement Statement *syntaxCopy(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *semantic(Scope *sc); - int blockExit(); + int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); int inlineCost(InlineCostState *ics); @@ -657,7 +649,7 @@ struct BreakStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -674,7 +666,7 @@ struct ContinueStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -694,7 +686,7 @@ struct SynchronizedStatement : Statement int hasBreak(); int hasContinue(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -717,7 +709,7 @@ struct WithStatement : Statement Statement *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); Statement *inlineScan(InlineScanState *iss); @@ -735,7 +727,7 @@ struct TryCatchStatement : Statement Statement *semantic(Scope *sc); int hasBreak(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); Statement *inlineScan(InlineScanState *iss); @@ -756,7 +748,7 @@ struct Catch : Object Catch(Loc loc, Type *t, Identifier *id, Statement *handler); Catch *syntaxCopy(); void semantic(Scope *sc); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; @@ -772,7 +764,7 @@ struct TryFinallyStatement : Statement int hasBreak(); int hasContinue(); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); Statement *inlineScan(InlineScanState *iss); @@ -787,7 +779,7 @@ struct OnScopeStatement : Statement OnScopeStatement(Loc loc, TOK tok, Statement *statement); Statement *syntaxCopy(); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *semantic(Scope *sc); int usesEH(); @@ -805,7 +797,7 @@ struct ThrowStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int blockExit(); + int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); Statement *inlineScan(InlineScanState *iss); @@ -821,7 +813,7 @@ struct VolatileStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); Statements *flatten(Scope *sc); - int blockExit(); + int blockExit(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -839,7 +831,7 @@ struct GotoStatement : Statement GotoStatement(Loc loc, Identifier *ident); Statement *syntaxCopy(); Statement *semantic(Scope *sc); - int blockExit(); + int blockExit(bool mustNotThrow); Expression *interpret(InterState *istate); void toIR(IRState *irs); @@ -862,20 +854,19 @@ struct LabelStatement : Statement Statement *semantic(Scope *sc); Statements *flatten(Scope *sc); int usesEH(); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); + LabelStatement *isLabelStatement() { return this; } void toIR(IRState *irs); // LDC bool asmLabel; // for labels inside inline assembler void toNakedIR(IRState *irs); - - LabelStatement* isLabelStatement() { return this; } }; struct LabelDsymbol : Dsymbol @@ -897,7 +888,7 @@ struct AsmStatement : Statement AsmStatement(Loc loc, Token *tokens); Statement *syntaxCopy(); Statement *semantic(Scope *sc); - int blockExit(); + int blockExit(bool mustNotThrow); int comeFrom(); Expression *interpret(InterState *istate); diff --git a/dmd/staticassert.c b/dmd/staticassert.c index 83e99019..33db1aa4 100644 --- a/dmd/staticassert.c +++ b/dmd/staticassert.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -52,10 +52,8 @@ void StaticAssert::semantic(Scope *sc) void StaticAssert::semantic2(Scope *sc) { - Expression *e; - //printf("StaticAssert::semantic2() %s\n", toChars()); - e = exp->semantic(sc); + Expression *e = exp->semantic(sc); if (e->op == TOKerror) return; e = e->optimize(WANTvalue | WANTinterpret); diff --git a/dmd/staticassert.h b/dmd/staticassert.h index 22bf0c57..91c37f04 100644 --- a/dmd/staticassert.h +++ b/dmd/staticassert.h @@ -18,9 +18,7 @@ #include "dsymbol.h" struct Expression; -#ifdef _DH struct HdrGenState; -#endif struct StaticAssert : Dsymbol { diff --git a/dmd/struct.c b/dmd/struct.c index 7af158d0..20c18f60 100644 --- a/dmd/struct.c +++ b/dmd/struct.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -51,6 +51,8 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) ctor = NULL; defaultCtor = NULL; + aliasthis = NULL; + noDefaultCtor = FALSE; #endif #if IN_LLVM @@ -83,8 +85,7 @@ void AggregateDeclaration::semantic2(Scope *sc) } void AggregateDeclaration::semantic3(Scope *sc) -{ int i; - +{ // LDC if (!global.params.useAvailableExternally) availableExternally = false; @@ -93,7 +94,7 @@ void AggregateDeclaration::semantic3(Scope *sc) if (members) { sc = sc->push(this); - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->semantic3(sc); @@ -103,12 +104,11 @@ void AggregateDeclaration::semantic3(Scope *sc) } void AggregateDeclaration::inlineScan() -{ int i; - +{ //printf("AggregateDeclaration::inlineScan(%s)\n", toChars()); if (members) { - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; //printf("inline scan aggregate symbol '%s'\n", s->toChars()); @@ -155,7 +155,7 @@ void AggregateDeclaration::alignmember( if (salign > 1) { assert(size != 3); - int sa = size; + unsigned sa = size; if (sa == 0 || salign < sa) sa = salign; *poffset = (*poffset + sa - 1) & ~(sa - 1); @@ -216,7 +216,10 @@ void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) if (!isUnionDeclaration()) sc->offset = ofs; #endif - if (sc->structalign < memalignsize) + if (global.params.is64bit && sc->structalign == 8 && memalignsize == 16) + /* Not sure how to handle this */ + ; + else if (sc->structalign < memalignsize) memalignsize = sc->structalign; if (alignsize < memalignsize) alignsize = memalignsize; @@ -227,6 +230,57 @@ void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) fields.push(v); } +/**************************************** + * If field[indx] is not part of a union, return indx. + * Otherwise, return the lowest field index of the union. + */ +int AggregateDeclaration::firstFieldInUnion(int indx) +{ + if (isUnionDeclaration()) + return 0; + VarDeclaration * vd = (VarDeclaration *)fields.data[indx]; + int firstNonZero = indx; // first index in the union with non-zero size + for (; ;) + { + if (indx == 0) + return firstNonZero; + VarDeclaration * v = (VarDeclaration *)fields.data[indx - 1]; + if (v->offset != vd->offset) + return firstNonZero; + --indx; + /* If it is a zero-length field, it's ambiguous: we don't know if it is + * in the union unless we find an earlier non-zero sized field with the + * same offset. + */ + if (v->size(loc) != 0) + firstNonZero = indx; + } +} + +/**************************************** + * Count the number of fields starting at firstIndex which are part of the + * same union as field[firstIndex]. If not a union, return 1. + */ +int AggregateDeclaration::numFieldsInUnion(int firstIndex) +{ + VarDeclaration * vd = (VarDeclaration *)fields.data[firstIndex]; + /* If it is a zero-length field, AND we can't find an earlier non-zero + * sized field with the same offset, we assume it's not part of a union. + */ + if (vd->size(loc) == 0 && !isUnionDeclaration() && + firstFieldInUnion(firstIndex) == firstIndex) + return 1; + int count = 1; + for (size_t i = firstIndex+1; i < fields.dim; ++i) + { + VarDeclaration * v = (VarDeclaration *)fields.data[i]; + // If offsets are different, they are not in the same union + if (v->offset != vd->offset) + break; + ++count; + } + return count; +} /********************************* StructDeclaration ****************************/ @@ -257,7 +311,7 @@ Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) } void StructDeclaration::semantic(Scope *sc) -{ int i; +{ Scope *sc2; //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); @@ -310,7 +364,7 @@ void StructDeclaration::semantic(Scope *sc) if (sizeok == 0) // if not already done the addMember step { - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); @@ -327,12 +381,12 @@ void StructDeclaration::semantic(Scope *sc) sc2->protection = PROTpublic; sc2->explicitProtection = 0; - int members_dim = members->dim; + size_t members_dim = members->dim; /* Set scope so if there are forward references, we still might be able to * resolve individual members like enums. */ - for (int i = 0; i < members_dim; i++) + for (size_t i = 0; i < members_dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; /* There are problems doing this in the general case because * Scope keeps track of things like 'offset' @@ -344,7 +398,7 @@ void StructDeclaration::semantic(Scope *sc) } } - for (i = 0; i < members_dim; i++) + for (size_t i = 0; i < members_dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->semantic(sc2); @@ -356,6 +410,10 @@ void StructDeclaration::semantic(Scope *sc) #endif } +#if DMDV1 + /* This doesn't work for DMDV2 because (ref S) and (S) parameter + * lists will overload the same. + */ /* The TypeInfo_Struct is expecting an opEquals and opCmp with * a parameter that is a pointer to the struct. But if there * isn't one, but is an opEquals or opCmp with a value, write @@ -413,6 +471,7 @@ void StructDeclaration::semantic(Scope *sc) id = Id::cmp; } +#endif #if DMDV2 dtor = buildDtor(sc2); postblit = buildPostBlit(sc2); @@ -458,7 +517,7 @@ void StructDeclaration::semantic(Scope *sc) // Determine if struct is all zeros or not zeroInit = 1; - for (i = 0; i < fields.dim; i++) + for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = (Dsymbol *)fields.data[i]; VarDeclaration *vd = s->isVarDeclaration(); @@ -501,7 +560,7 @@ Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) { //printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars()); - if (scope) + if (scope && !symtab) semantic(scope); if (!members || !symtab) @@ -514,8 +573,7 @@ Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) } void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - +{ buf->printf("%s ", kind()); if (!isAnonymous()) buf->writestring(toChars()); @@ -528,7 +586,7 @@ void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); buf->writeByte('{'); buf->writenl(); - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; diff --git a/dmd/template.c b/dmd/template.c index e1b9827a..67180be5 100644 --- a/dmd/template.c +++ b/dmd/template.c @@ -158,16 +158,35 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) Expression *e2 = isExpression(o2); Dsymbol *s1 = isDsymbol(o1); Dsymbol *s2 = isDsymbol(o2); - Tuple *v1 = isTuple(o1); - Tuple *v2 = isTuple(o2); + Tuple *u1 = isTuple(o1); + Tuple *u2 = isTuple(o2); - //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2); + //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, u1 %p u2 %p\n", t1,t2,e1,e2,s1,s2,u1,u2); /* A proper implementation of the various equals() overrides * should make it possible to just do o1->equals(o2), but * we'll do that another day. */ + if (s1) + { + VarDeclaration *v1 = s1->isVarDeclaration(); + if (v1 && v1->storage_class & STCmanifest) + { ExpInitializer *ei1 = v1->init->isExpInitializer(); + if (ei1) + e1 = ei1->exp, s1 = NULL; + } + } + if (s2) + { + VarDeclaration *v2 = s2->isVarDeclaration(); + if (v2 && v2->storage_class & STCmanifest) + { ExpInitializer *ei2 = v2->init->isExpInitializer(); + if (ei2) + e2 = ei2->exp, s2 = NULL; + } + } + if (t1) { /* if t1 is an instance of ti, then give error @@ -213,49 +232,26 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) } else if (s1) { - //printf("%p %s %s, %p %s %s\n", s1, s1->kind(), s1->toChars(), s2, s2->kind(), s2->toChars()); - if (!s2) - { + if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) goto Lnomatch; } - if (!s1->equals(s2)) - { -#if DMDV2 - VarDeclaration *v1 = s1->isVarDeclaration(); - VarDeclaration *v2 = s2->isVarDeclaration(); - if (v1 && v2 && v1->storage_class & v2->storage_class & STCmanifest) - { ExpInitializer *ei1 = v1->init->isExpInitializer(); - ExpInitializer *ei2 = v2->init->isExpInitializer(); - if (ei1 && ei2 && !ei1->exp->equals(ei2->exp)) - goto Lnomatch; - goto Lmatch; - } - else -#endif - goto Lnomatch; - } - if (s1->parent != s2->parent) - { - goto Lnomatch; - } - } - else if (v1) + else if (u1) { - if (!v2) + if (!u2) goto Lnomatch; - if (v1->objects.dim != v2->objects.dim) + if (u1->objects.dim != u2->objects.dim) goto Lnomatch; - for (size_t i = 0; i < v1->objects.dim; i++) + for (size_t i = 0; i < u1->objects.dim; i++) { - if (!match((Object *)v1->objects.data[i], - (Object *)v2->objects.data[i], + if (!match(u1->objects.tdata()[i], + u2->objects.tdata()[i], tempdecl, sc)) goto Lnomatch; } } -Lmatch: //printf("match\n"); return 1; // match + Lnomatch: //printf("nomatch\n"); return 0; // nomatch; @@ -347,7 +343,7 @@ Object *objectSyntaxCopy(Object *o) /* ======================== TemplateDeclaration ============================= */ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, - TemplateParameters *parameters, Expression *constraint, Array *decldefs) + TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs) : ScopeDsymbol(id) { #if LOG @@ -355,7 +351,7 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, #endif #if 0 if (parameters) - for (int i = 0; i < parameters->dim; i++) + for (size_t i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; //printf("\tparameter[%d] = %p\n", i, tp); TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); @@ -375,6 +371,20 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, this->overroot = NULL; this->semanticRun = 0; this->onemember = NULL; + + // Compute in advance for Ddoc's use + if (members) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s)) + { + if (s && s->ident && s->ident->equals(ident)) + { + onemember = s; + s->parent = this; + } + } + } } Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) @@ -388,7 +398,7 @@ Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) { p = new TemplateParameters(); p->setDim(parameters->dim); - for (int i = 0; i < p->dim; i++) + for (size_t i = 0; i < p->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; p->data[i] = (void *)tp->syntaxCopy(); } @@ -396,7 +406,7 @@ Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) Expression *e = NULL; if (constraint) e = constraint->syntaxCopy(); - Array *d = Dsymbol::arraySyntaxCopy(members); + Dsymbols *d = Dsymbol::arraySyntaxCopy(members); td = new TemplateDeclaration(loc, ident, p, e, d); #if IN_LLVM @@ -469,21 +479,21 @@ void TemplateDeclaration::semantic(Scope *sc) { origParameters = new TemplateParameters(); origParameters->setDim(parameters->dim); - for (int i = 0; i < parameters->dim; i++) + for (size_t i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; origParameters->data[i] = (void *)tp->syntaxCopy(); } } - for (int i = 0; i < parameters->dim; i++) + for (size_t i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; tp->declareParameter(paramscope); } - for (int i = 0; i < parameters->dim; i++) + for (size_t i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; @@ -494,6 +504,8 @@ void TemplateDeclaration::semantic(Scope *sc) paramscope->pop(); + // Compute again + onemember = NULL; if (members) { Dsymbol *s; @@ -547,7 +559,7 @@ int TemplateDeclaration::overloadInsert(Dsymbol *s) if (f->parameters->dim != f2->parameters->dim) goto Lcontinue; - for (int i = 0; i < f->parameters->dim; i++) + for (size_t i = 0; i < f->parameters->dim; i++) { TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i]; TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i]; @@ -588,7 +600,7 @@ int TemplateDeclaration::overloadInsert(Dsymbol *s) MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, Objects *dedtypes, int flag) { MATCH m; - int dedtypes_dim = dedtypes->dim; + size_t dedtypes_dim = dedtypes->dim; #define LOGM 0 #if LOGM @@ -604,7 +616,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, #endif dedtypes->zero(); - int parameters_dim = parameters->dim; + size_t parameters_dim = parameters->dim; int variadic = isVariadic() != NULL; // If more arguments than parameters, no match @@ -628,7 +640,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, // Attempt type deduction m = MATCHexact; - for (int i = 0; i < dedtypes_dim; i++) + for (size_t i = 0; i < dedtypes_dim; i++) { MATCH m2; TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; Declaration *sparam; @@ -671,7 +683,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, /* Any parameter left without a type gets the type of * its corresponding arg */ - for (int i = 0; i < dedtypes_dim; i++) + for (size_t i = 0; i < dedtypes_dim; i++) { if (!dedtypes->data[i]) { assert(i < ti->tiargs->dim); @@ -706,7 +718,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, printf("instance %s\n", ti->toChars()); if (m) { - for (int i = 0; i < dedtypes_dim; i++) + for (size_t i = 0; i < dedtypes_dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; Object *oarg; @@ -772,7 +784,7 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) // generated from the parameters to this template declaration ti.tiargs = new Objects(); ti.tiargs->setDim(parameters->dim); - for (int i = 0; i < ti.tiargs->dim; i++) + for (size_t i = 0; i < ti.tiargs->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; @@ -827,7 +839,6 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, Objects *dedargs) { - size_t i; size_t nfparams; size_t nfargs; size_t nargsi; // array size of targsi @@ -841,7 +852,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, #if 0 printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); - for (i = 0; i < fargs->dim; i++) + for (size_t i = 0; i < fargs->dim; i++) { Expression *e = (Expression *)fargs->data[i]; printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); } @@ -866,7 +877,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, TemplateTupleParameter *tp = isVariadic(); #if 0 - for (i = 0; i < dedargs->dim; i++) + for (size_t i = 0; i < dedargs->dim; i++) { printf("\tdedarg[%d] = ", i); Object *oarg = (Object *)dedargs->data[i]; @@ -917,7 +928,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, } } #if 0 - for (i = 0; i < dedargs->dim; i++) + for (size_t i = 0; i < dedargs->dim; i++) { printf("\tdedarg[%d] = ", i); Object *oarg = (Object *)dedargs->data[i]; @@ -975,7 +986,7 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, tuple_dim = nfargs - (nfparams - 1); t->objects.setDim(tuple_dim); - for (i = 0; i < tuple_dim; i++) + for (size_t i = 0; i < tuple_dim; i++) { Expression *farg = (Expression *)fargs->data[fptupindex + i]; t->objects.data[i] = (void *)farg->type; } @@ -1062,7 +1073,7 @@ L2: * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex] * arg[fputupindex+dim.. ] == param[fptupindex+1.. ] */ - i = parami; + size_t i = parami; if (fptupindex >= 0 && parami > fptupindex) i += tuple_dim - 1; @@ -1196,7 +1207,7 @@ Lmatch: /* Fill in any missing arguments with their defaults. */ - for (i = nargsi; i < dedargs->dim; i++) + for (size_t i = nargsi; i < dedargs->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; //printf("tp[%d] = %s\n", i, tp->ident->toChars()); @@ -1259,7 +1270,7 @@ Lmatch: #endif #if 0 - for (i = 0; i < dedargs->dim; i++) + for (size_t i = 0; i < dedargs->dim; i++) { Type *t = (Type *)dedargs->data[i]; printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); } @@ -1398,13 +1409,13 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); printf(" targsi:\n"); if (targsi) - { for (int i = 0; i < targsi->dim; i++) + { for (size_t i = 0; i < targsi->dim; i++) { Object *arg = (Object *)targsi->data[i]; printf("\t%s\n", arg->toChars()); } } printf(" fargs:\n"); - for (int i = 0; i < fargs->dim; i++) + for (size_t i = 0; i < fargs->dim; i++) { Expression *arg = (Expression *)fargs->data[i]; printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); //printf("\tty = %d\n", arg->type->ty); @@ -1503,7 +1514,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, OutBuffer bufa; Objects *args = targsi; if (args) - { for (int i = 0; i < args->dim; i++) + { for (size_t i = 0; i < args->dim; i++) { if (i) bufa.writeByte(','); @@ -1520,17 +1531,25 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, return NULL; } +bool TemplateDeclaration::hasStaticCtorOrDtor() +{ + return FALSE; // don't scan uninstantiated templates +} + void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { -#if 0 // Should handle template functions +#if 0 // Should handle template functions for doc generation if (onemember && onemember->isFuncDeclaration()) buf->writestring("foo "); #endif + if (hgs->ddoc) buf->writestring(kind()); + else + buf->writestring("template"); buf->writeByte(' '); buf->writestring(ident->toChars()); buf->writeByte('('); - for (int i = 0; i < parameters->dim; i++) + for (size_t i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; if (hgs->ddoc) @@ -1554,7 +1573,7 @@ void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); buf->writebyte('{'); buf->writenl(); - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->toCBuffer(buf, hgs); @@ -1573,7 +1592,7 @@ char *TemplateDeclaration::toChars() memset(&hgs, 0, sizeof(hgs)); buf.writestring(ident->toChars()); buf.writeByte('('); - for (int i = 0; i < parameters->dim; i++) + for (size_t i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; if (i) @@ -1738,9 +1757,6 @@ MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame printf("\ttparam = %d, ", tparam->ty); tparam->print(); #endif return Type::deduceType(sc, tparam, parameters, dedtypes); - - Lnomatch: - return MATCHnomatch; } #endif @@ -1756,33 +1772,23 @@ MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame // Extra check that array dimensions must match if (tparam) { + if (tparam->ty == Tarray) + { MATCH m; + + m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); + if (m == MATCHexact) + m = MATCHconvert; + return m; + } + + Identifier *id = NULL; if (tparam->ty == Tsarray) { TypeSArray *tp = (TypeSArray *)tparam; - if (tp->dim->op == TOKvar && ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) - { int i = templateIdentifierLookup(((VarExp *)tp->dim)->var->ident, parameters); - // This code matches code in TypeInstance::deduceType() - if (i == -1) - goto Lnomatch; - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (!tvp) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->data[i]; - if (e) { - if (!dim->equals(e)) - goto Lnomatch; - } - else - { Type *vt = tvp->valType->semantic(0, sc); - MATCH m = (MATCH)dim->implicitConvTo(vt); - if (!m) - goto Lnomatch; - dedtypes->data[i] = dim; - } + id = ((VarExp *)tp->dim)->var->ident; } else if (dim->toInteger() != tp->dim->toInteger()) return MATCHnomatch; @@ -1790,45 +1796,39 @@ MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame else if (tparam->ty == Taarray) { TypeAArray *tp = (TypeAArray *)tparam; - if (tp->index->ty == Tident) - { TypeIdentifier *tident = (TypeIdentifier *)tp->index; - - if (tident->idents.dim == 0) - { Identifier *id = tident->ident; - - for (size_t i = 0; i < parameters->dim; i++) + if (tp->index->ty == Tident && + ((TypeIdentifier *)tp->index)->idents.dim == 0) { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - - if (tp->ident->equals(id)) - { // Found the corresponding template parameter - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (!tvp || !tvp->valType->isintegral()) + id = ((TypeIdentifier *)tp->index)->ident; + } + } + if (id) + { + // This code matches code in TypeInstance::deduceType() + int i = templateIdentifierLookup(id, parameters); + if (i == -1) goto Lnomatch; - - if (dedtypes->data[i]) + TemplateParameter *tprm = parameters->tdata()[i]; + TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); + if (!tvp) + goto Lnomatch; + Expression *e = (Expression *)dedtypes->tdata()[i]; + if (e) { - if (!dim->equals((Object *)dedtypes->data[i])) + if (!dim->equals(e)) goto Lnomatch; } else - { dedtypes->data[i] = (void *)dim; + { + Type *vt = tvp->valType->semantic(0, sc); + MATCH m = (MATCH)dim->implicitConvTo(vt); + if (!m) + goto Lnomatch; + dedtypes->tdata()[i] = dim; } return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); } } - } - } - } - else if (tparam->ty == Tarray) - { MATCH m; - - m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); - if (m == MATCHexact) - m = MATCHconvert; - return m; - } - } return Type::deduceType(sc, tparam, parameters, dedtypes); Lnomatch: @@ -1903,7 +1903,7 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para /* The types of the function arguments [nfparams - 1 .. nfargs] * now form the tuple argument. */ - int tuple_dim = nfargs - (nfparams - 1); + size_t tuple_dim = nfargs - (nfparams - 1); /* See if existing tuple, and whether it matches or not */ @@ -1956,7 +1956,7 @@ MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *pa { TypeIdentifier *tp = (TypeIdentifier *)tparam; - for (int i = 0; i < idents.dim; i++) + for (size_t i = 0; i < idents.dim; i++) { Identifier *id1 = (Identifier *)idents.data[i]; Identifier *id2 = (Identifier *)tp->idents.data[i]; @@ -2032,7 +2032,7 @@ MATCH TypeInstance::deduceType(Scope *sc, L2: - for (int i = 0; 1; i++) + for (size_t i = 0; 1; i++) { //printf("\ttest: tempinst->tiargs[%d]\n", i); Object *o1; @@ -2093,7 +2093,7 @@ MATCH TypeInstance::deduceType(Scope *sc, /* Create tuple from remaining args */ Tuple *vt = new Tuple(); - int vtdim = tempinst->tiargs->dim - i; + size_t vtdim = tempinst->tiargs->dim - i; vt->objects.setDim(vtdim); for (size_t k = 0; k < vtdim; k++) vt->objects.data[k] = (void *)tempinst->tiargs->data[i + k]; @@ -2550,7 +2550,7 @@ Lnomatch: */ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, - int i, TemplateParameters *parameters, Objects *dedtypes, + size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags) { //printf("TemplateTypeParameter::matchArg()\n"); @@ -2794,7 +2794,8 @@ Lnomatch: } MATCH TemplateAliasParameter::matchArg(Scope *sc, - Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, + Objects *tiargs, size_t i, TemplateParameters *parameters, + Objects *dedtypes, Declaration **psparam, int flags) { Dsymbol *sa; @@ -3009,7 +3010,7 @@ Lnomatch: MATCH TemplateValueParameter::matchArg(Scope *sc, - Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, + Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags) { //printf("TemplateValueParameter::matchArg()\n"); @@ -3149,10 +3150,7 @@ Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) e = e->syntaxCopy(); e = e->semantic(sc); #if DMDV2 - if (e->op == TOKdefault) - { DefaultInitExp *de = (DefaultInitExp *)e; - e = de->resolve(loc, sc); - } + e = e->resolveLoc(loc, sc); #endif } return e; @@ -3200,12 +3198,11 @@ int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) return 1; // match } -Lnomatch: return 0; } MATCH TemplateTupleParameter::matchArg(Scope *sc, - Objects *tiargs, int i, TemplateParameters *parameters, + Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags) { @@ -3246,7 +3243,7 @@ void TemplateTupleParameter::print(Object *oarg, Object *oded) assert(v); //printf("|%d| ", v->objects.dim); - for (int i = 0; i < v->objects.dim; i++) + for (size_t i = 0; i < v->objects.dim; i++) { if (i) printf(", "); @@ -3318,6 +3315,7 @@ TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) this->havetempdecl = 0; this->isnested = NULL; this->errors = 0; + this->speculative = 0; #if IN_LLVM // LDC @@ -3352,6 +3350,7 @@ TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *ti this->havetempdecl = 1; this->isnested = NULL; this->errors = 0; + this->speculative = 0; #if IN_LLVM // LDC @@ -3517,6 +3516,27 @@ void TemplateInstance::semantic(Scope *sc) // It's a match inst = ti; parent = ti->parent; + + // If both this and the previous instantiation were speculative, + // use the number of errors that happened last time. + if (inst->speculative && global.gag) + { + global.errors += inst->errors; + global.gaggedErrors += inst->errors; + } + + // If the first instantiation was speculative, but this is not: + if (inst->speculative && !global.gag) + { + // If the first instantiation had failed, re-run semantic, + // so that error messages are shown. + if (inst->errors) + goto L1; + // It had succeeded, mark it is a non-speculative instantiation, + // and reuse it. + inst->speculative = 0; + } + #if LOG printf("\tit's a match with instance %p\n", inst); #endif @@ -3529,10 +3549,15 @@ void TemplateInstance::semantic(Scope *sc) /* So, we need to implement 'this' instance. */ #if LOG - printf("\timplement template instance '%s'\n", toChars()); + printf("\timplement template instance %s '%s'\n", tempdecl->parent->toChars(), toChars()); + printf("\ttempdecl %s\n", tempdecl->toChars()); #endif unsigned errorsave = global.errors; inst = this; + // Mark as speculative if we are instantiated from inside is(typeof()) + if (global.gag && sc->intypeof) + speculative = 1; + int tempdecl_instance_idx = tempdecl->instances.dim; tempdecl->instances.push(this); parent = tempdecl->parent; @@ -3547,10 +3572,16 @@ void TemplateInstance::semantic(Scope *sc) //printf("parent = '%s'\n", parent->kind()); // Add 'this' to the enclosing scope's members[] so the semantic routines - // will get called on the instance members + // will get called on the instance members. Store the place we added it to + // in target_symbol_list(_idx) so we can remove it later if we encounter + // an error. #if 1 int dosemantic3 = 0; - { Array *a; + Dsymbols *target_symbol_list = NULL; + int target_symbol_list_idx; + + if (!sc->parameterSpecialization) + { Dsymbols *a; Scope *scx = sc; #if 0 @@ -3581,16 +3612,20 @@ void TemplateInstance::semantic(Scope *sc) //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); a = m->members; if (m->semanticRun >= 3) + { dosemantic3 = 1; } - for (int i = 0; 1; i++) + } + for (size_t i = 0; 1; i++) { if (i == a->dim) { + target_symbol_list = a; + target_symbol_list_idx = i; a->push(this); break; } - if (this == (Dsymbol *)a->data[i]) // if already in Array + if (this == a->tdata()[i]) // if already in Array break; } } @@ -3624,9 +3659,9 @@ void TemplateInstance::semantic(Scope *sc) // parent = scope->scopesym; symtab = new DsymbolTable(); int memnum = 0; - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; #if LOG printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); #endif @@ -3689,9 +3724,9 @@ void TemplateInstance::semantic(Scope *sc) error("recursive expansion"); fatal(); } - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); // if (isnested) @@ -3717,7 +3752,7 @@ void TemplateInstance::semantic(Scope *sc) * or semantic3() yet. */ for (size_t i = 0; i < Module::deferred.dim; i++) - { Dsymbol *sd = (Dsymbol *)Module::deferred.data[i]; + { Dsymbol *sd = Module::deferred.tdata()[i]; if (sd->parent == this) goto Laftersemantic; @@ -3777,15 +3812,23 @@ void TemplateInstance::semantic(Scope *sc) } errors = 1; if (global.gag) - { // Try to reset things so we can try again later to instantiate it + { + // Errors are gagged, so remove the template instance from the + // instance/symbol lists we added it to and reset our state to + // finish clean and so we can try to instantiate it again later + // (see bugzilla 4302 and 6602). tempdecl->instances.remove(tempdecl_instance_idx); - if (!(sc->flags & SCOPEstaticif)) - { // Bugzilla 4302 for discussion + if (target_symbol_list) + { + // Because we added 'this' in the last position above, we + // should be able to remove it without messing other indices up. + assert(target_symbol_list->tdata()[target_symbol_list_idx] == this); + target_symbol_list->remove(target_symbol_list_idx); + } semanticRun = 0; inst = NULL; } } - } #if LOG printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); @@ -3833,7 +3876,9 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f tiargs->data[j] = ea; } else if (sa) - { tiargs->data[j] = sa; + { + Ldsym: + tiargs->tdata()[j] = sa; TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); if (d) { @@ -3854,14 +3899,14 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f if (dim) { tiargs->reserve(dim); for (size_t i = 0; i < dim; i++) - { Parameter *arg = (Parameter *)tt->arguments->data[i]; + { Parameter *arg = tt->arguments->tdata()[i]; tiargs->insert(j + i, arg->type); } } j--; } else - tiargs->data[j] = ta; + tiargs->tdata()[j] = ta; } else { @@ -3873,7 +3918,7 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f { if (!ea) { assert(global.errors); - ea = new IntegerExp(0); + ea = new ErrorExp(); } assert(ea); ea = ea->semantic(sc); @@ -3883,6 +3928,10 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f { ta = ea->type; goto Ltype; } + if (ea->op == TOKimport) + { sa = ((ScopeExp *)ea)->sds; + goto Ldsym; + } if (ea->op == TOKtuple) { // Expand tuple TupleExp *te = (TupleExp *)ea; @@ -3891,7 +3940,7 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f if (dim) { tiargs->reserve(dim); for (size_t i = 0; i < dim; i++) - tiargs->insert(j + i, te->exps->data[i]); + tiargs->insert(j + i, (*te->exps)[i]); } j--; } @@ -3936,7 +3985,6 @@ TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) Dsymbol *s; Dsymbol *scopesym; Identifier *id; - int i; id = name; s = sc->search(loc, id, &scopesym); @@ -4173,10 +4221,12 @@ int TemplateInstance::hasNestedArgs(Objects *args) * symbol that is on the stack. */ for (size_t i = 0; i < args->dim; i++) - { Object *o = (Object *)args->data[i]; + { Object *o = (*args)[i]; Expression *ea = isExpression(o); + Type *ta = isType(o); Dsymbol *sa = isDsymbol(o); Tuple *va = isTuple(o); + //printf("o %p ea %p ta %p sa %p va %p\n", o, ea, ta, sa, va); if (ea) { if (ea->op == TOKvar) @@ -4190,20 +4240,36 @@ int TemplateInstance::hasNestedArgs(Objects *args) goto Lsa; } } + else if (ta) + { + if (ta->ty == Tstruct || ta->ty == Tclass) + { sa = ta->toDsymbol(NULL); + TemplateInstance *ti = sa->parent->isTemplateInstance(); + if (ti && ti->isnested) + { sa = ti; + goto Lsa; + } + } + } else if (sa) { Lsa: + //printf("sa = %s %s\n", sa->kind(), sa->toChars()); Declaration *d = sa->isDeclaration(); - if (d && !d->isDataseg() && + TemplateInstance *ad = sa->isTemplateInstance(); + if ( + (ad && ad->isnested) || + (d && !d->isDataseg() && #if DMDV2 !(d->storage_class & STCmanifest) && #endif (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && - !isTemplateMixin()) + !isTemplateMixin() + )) { // if module level template if (tempdecl->toParent()->isModule()) - { Dsymbol *dparent = d->toParent(); + { Dsymbol *dparent = sa->toParent(); if (!isnested) isnested = dparent; else if (isnested != dparent) @@ -4224,14 +4290,14 @@ int TemplateInstance::hasNestedArgs(Objects *args) } } error("%s is nested in both %s and %s", - toChars(), isnested->toChars(), dparent->toChars()); + toChars(), isnested->toPrettyChars(), dparent->toPrettyChars()); } L1: //printf("\tnested inside %s\n", isnested->toChars()); nested |= 1; } else - error("cannot use local '%s' as parameter to non-global template %s", d->toChars(), tempdecl->toChars()); + error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars()); } } else if (va) @@ -4255,7 +4321,7 @@ Identifier *TemplateInstance::genIdent() char *id = tempdecl->ident->toChars(); buf.printf("__T%zu%s", strlen(id), id); Objects *args = tiargs; - for (int i = 0; i < args->dim; i++) + for (size_t i = 0; i < args->dim; i++) { Object *o = (Object *)args->data[i]; Type *ta = isType(o); Expression *ea = isExpression(o); @@ -4276,9 +4342,7 @@ Identifier *TemplateInstance::genIdent() } } else if (ea) - { sinteger_t v; - real_t r; - + { ea = ea->optimize(WANTvalue | WANTinterpret); if (ea->op == TOKvar) { @@ -4286,6 +4350,12 @@ Identifier *TemplateInstance::genIdent() ea = NULL; goto Lsa; } + if (ea->op == TOKthis) + { + sa = ((ThisExp *)ea)->var; + ea = NULL; + goto Lsa; + } if (ea->op == TOKfunction) { sa = ((FuncExp *)ea)->fd; @@ -4357,7 +4427,7 @@ Identifier *TemplateInstance::genIdent() void TemplateInstance::declareParameters(Scope *sc) { //printf("TemplateInstance::declareParameters()\n"); - for (int i = 0; i < tdtypes.dim; i++) + for (size_t i = 0; i < tdtypes.dim; i++) { TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; //Object *o = (Object *)tiargs->data[i]; @@ -4396,6 +4466,12 @@ int TemplateInstance::needsTypeInference(Scope *sc) return FALSE; } +#if DMDV2 + for (size_t i = 0; i < td->parameters->dim; i++) + if (td->parameters->tdata()[i]->isTemplateThisParameter()) + return TRUE; +#endif + /* Determine if the instance arguments, tiargs, are all that is necessary * to instantiate the template. */ @@ -4403,7 +4479,7 @@ int TemplateInstance::needsTypeInference(Scope *sc) //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); TypeFunction *fdtype = (TypeFunction *)fd->type; if (Parameter::dim(fdtype->parameters) && - (tp || tiargs->dim < td->parameters->dim)) + ((tp && td->parameters->dim > 1) || tiargs->dim < td->parameters->dim)) return TRUE; } //printf("false\n"); @@ -4457,10 +4533,26 @@ void TemplateInstance::semantic3(Scope *sc) sc = sc->push(argsym); sc = sc->push(this); sc->tinst = this; - for (int i = 0; i < members->dim; i++) + int oldgag = global.gag; + int olderrors = global.errors; + /* If this is a speculative instantiation, gag errors. + * Future optimisation: If the results are actually needed, errors + * would already be gagged, so we don't really need to run semantic + * on the members. + */ + if (speculative && !oldgag) + olderrors = global.startGagging(); + for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = (*members)[i]; s->semantic3(sc); + if (speculative && global.errors != olderrors) + break; + } + if (speculative && !oldgag) + { // If errors occurred, this instantiation failed + errors += global.errors - olderrors; + global.endGagging(olderrors); } sc = sc->pop(); sc->pop(); @@ -4479,7 +4571,7 @@ void TemplateInstance::printInstantiationTrace() if (global.gag) return; - const int max_shown = 6; + const unsigned max_shown = 6; const char format[] = "%s: instantiated from here: %s\n"; // determine instantiation depth and number of recursive instantiations @@ -4532,7 +4624,7 @@ void TemplateInstance::printInstantiationTrace() { // Even after collapsing the recursions, the depth is too deep. // Just display the first few and last few instantiations. - size_t i = 0; + unsigned i = 0; for (TemplateInstance *cur = this; cur; cur = cur->tinst) { if (i == max_shown / 2) @@ -4559,7 +4651,7 @@ void TemplateInstance::toObjFile(int multiobj) assert(0 && "multiobj"); else { - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->toObjFile(multiobj); @@ -4577,7 +4669,7 @@ void TemplateInstance::inlineScan() #endif if (!errors && members) { - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->inlineScan(); @@ -4705,7 +4797,7 @@ void TemplateInstance::printInstantiationTrace() /* ======================== TemplateMixin ================================ */ TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, - Array *idents, Objects *tiargs) + Identifiers *idents, Objects *tiargs) : TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1]) { //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); @@ -4718,9 +4810,9 @@ TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) { TemplateMixin *tm; - Array *ids = new Array(); + Identifiers *ids = new Identifiers(); ids->setDim(idents->dim); - for (int i = 0; i < idents->dim; i++) + for (size_t i = 0; i < idents->dim; i++) { // Matches TypeQualified::syntaxCopyHelper() Identifier *id = (Identifier *)idents->data[i]; if (id->dyncast() == DYNCAST_DSYMBOL) @@ -4781,7 +4873,7 @@ void TemplateMixin::semantic(Scope *sc) // Follow qualifications to find the TemplateDeclaration if (!tempdecl) { Dsymbol *s; - int i; + size_t i; Identifier *id; if (tqual) @@ -4891,7 +4983,7 @@ void TemplateMixin::semantic(Scope *sc) if (tiargs->dim != tm->tiargs->dim) continue; - for (int i = 0; i < tiargs->dim; i++) + for (size_t i = 0; i < tiargs->dim; i++) { Object *o = (Object *)tiargs->data[i]; Type *ta = isType(o); Expression *ea = isExpression(o); @@ -4987,7 +5079,7 @@ void TemplateMixin::semantic(Scope *sc) fatal(); } - for (int i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->semantic(sc2); @@ -5030,8 +5122,7 @@ void TemplateMixin::semantic(Scope *sc) } void TemplateMixin::semantic2(Scope *sc) -{ int i; - +{ if (semanticRun >= 2) return; semanticRun = 2; @@ -5043,7 +5134,7 @@ void TemplateMixin::semantic2(Scope *sc) assert(sc); sc = sc->push(argsym); sc = sc->push(this); - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; #if LOG @@ -5060,8 +5151,7 @@ void TemplateMixin::semantic2(Scope *sc) } void TemplateMixin::semantic3(Scope *sc) -{ int i; - +{ if (semanticRun >= 3) return; semanticRun = 3; @@ -5072,7 +5162,7 @@ void TemplateMixin::semantic3(Scope *sc) { sc = sc->push(argsym); sc = sc->push(this); - for (i = 0; i < members->dim; i++) + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; s->semantic3(sc); @@ -5128,7 +5218,7 @@ void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("mixin "); - for (int i = 0; i < idents->dim; i++) + for (size_t i = 0; i < idents->dim; i++) { Identifier *id = (Identifier *)idents->data[i]; if (i) @@ -5138,7 +5228,7 @@ void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring("!("); if (tiargs) { - for (int i = 0; i < tiargs->dim; i++) + for (size_t i = 0; i < tiargs->dim; i++) { if (i) buf->writebyte(','); Object *oarg = (Object *)tiargs->data[i]; diff --git a/dmd/template.h b/dmd/template.h index e43d51dd..2ef2646d 100644 --- a/dmd/template.h +++ b/dmd/template.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -55,7 +55,7 @@ struct TemplateDeclaration : ScopeDsymbol TemplateParameters *origParameters; // originals for Ddoc Expression *constraint; - Array instances; // array of TemplateInstance's + TemplateInstances instances; // array of TemplateInstance's TemplateDeclaration *overnext; // next overloaded TemplateDeclaration TemplateDeclaration *overroot; // first in overnext list @@ -65,11 +65,12 @@ struct TemplateDeclaration : ScopeDsymbol Dsymbol *onemember; // if !=NULL then one member of this template TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, - Expression *constraint, Array *decldefs); + Expression *constraint, Dsymbols *decldefs); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); int overloadInsert(Dsymbol *s); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + bool hasStaticCtorOrDtor(); const char *kind(); char *toChars(); @@ -140,7 +141,7 @@ struct TemplateParameter /* Match actual argument against parameter. */ - virtual MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags = 0) = 0; + virtual MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags = 0) = 0; /* Create dummy argument based on parameter. */ @@ -166,7 +167,7 @@ struct TemplateTypeParameter : TemplateParameter Object *specialization(); Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); void *dummyArg(); }; @@ -210,7 +211,7 @@ struct TemplateValueParameter : TemplateParameter Object *specialization(); Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); void *dummyArg(); }; @@ -238,7 +239,7 @@ struct TemplateAliasParameter : TemplateParameter Object *specialization(); Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); void *dummyArg(); }; @@ -259,7 +260,7 @@ struct TemplateTupleParameter : TemplateParameter Object *specialization(); Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); void *dummyArg(); }; @@ -271,7 +272,7 @@ struct TemplateInstance : ScopeDsymbol * tiargs = args */ Identifier *name; - //Array idents; + //Identifiers idents; Objects *tiargs; // Array of Types/Expressions of template // instance arguments [int*, char, 10*10] @@ -292,6 +293,7 @@ struct TemplateInstance : ScopeDsymbol int havetempdecl; // 1 if used second constructor Dsymbol *isnested; // if referencing local symbols, this is the context int errors; // 1 if compiled with errors + int speculative; // 1 if only instantiated with errors gagged #ifdef IN_GCC /* On some targets, it is necessary to know whether a symbol will be emitted in the output or not before the symbol @@ -343,10 +345,10 @@ struct TemplateInstance : ScopeDsymbol struct TemplateMixin : TemplateInstance { - Array *idents; + Identifiers *idents; Type *tqual; - TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Array *idents, Objects *tiargs); + TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Identifiers *idents, Objects *tiargs); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void semantic2(Scope *sc); diff --git a/dmd/version.c b/dmd/version.c index 37bc8775..22d415a2 100644 --- a/dmd/version.c +++ b/dmd/version.c @@ -63,7 +63,7 @@ int DebugSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) if (findCondition(m->debugidsNot, ident)) error("defined after use"); if (!m->debugids) - m->debugids = new Array(); + m->debugids = new Strings(); m->debugids->push(ident->toChars()); } } @@ -144,7 +144,7 @@ int VersionSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) if (findCondition(m->versionidsNot, ident)) error("defined after use"); if (!m->versionids) - m->versionids = new Array(); + m->versionids = new Strings(); m->versionids->push(ident->toChars()); } } diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index d0615348..601dd54a 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -183,11 +183,7 @@ Statement *AsmStatement::semantic(Scope *sc) return this; } -#if DMDV2 int AsmStatement::blockExit(bool mustNotThrow) -#else -int AsmStatement::blockExit() -#endif { //printf("AsmStatement::blockExit(%p)\n", this); #if DMDV2 diff --git a/gen/cl_helpers.h b/gen/cl_helpers.h index ec19e5c0..03205661 100644 --- a/gen/cl_helpers.h +++ b/gen/cl_helpers.h @@ -6,13 +6,8 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" -#if DMDV1 -struct Array; -typedef Array Strings; -#else template struct ArrayBase; typedef ArrayBase Strings; -#endif namespace opts { namespace cl = llvm::cl; diff --git a/gen/main.cpp b/gen/main.cpp index 4945b197..4ed26537 100644 --- a/gen/main.cpp +++ b/gen/main.cpp @@ -49,10 +49,6 @@ using namespace opts; #include #endif -#if DMDV1 -typedef Array Modules; -#endif - extern void getenv_setargv(const char *envvar, int *pargc, char** *pargv); extern void backend_init(); extern void backend_term(); diff --git a/gen/statements.cpp b/gen/statements.cpp index 47efee98..2d487c8d 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -837,7 +837,7 @@ static LLValue* call_string_switch_runtime(llvm::Value* table, Expression* e) fname = "_d_switch_dstring"; } else { - assert(0 && "not char/wchar/dchar"); + llvm_unreachable("not char/wchar/dchar"); } llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, fname); @@ -1587,11 +1587,7 @@ void VolatileStatement::toIR(IRState* p) p->func()->gen->targetScopes.pop_back(); // no point in a unreachable barrier, terminating statements must insert this themselves. -#if DMDV2 if (statement->blockExit(false) & BEfallthru) -#else - if (statement->blockExit() & BEfallthru) -#endif { // store-load DtoMemoryBarrier(false, false, true, false);