Mercurial > projects > ldc
changeset 1587:def7a1d494fd
Merge DMD 1.051
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Fri, 06 Nov 2009 23:58:01 +0100 |
parents | 7f728c52e63c |
children | 71ad691baeb2 |
files | dmd/aggregate.h dmd/arrayop.c dmd/attrib.c dmd/attrib.h dmd/cast.c dmd/class.c dmd/constfold.c dmd/declaration.c dmd/declaration.h dmd/doc.c dmd/dsymbol.c dmd/dsymbol.h dmd/enum.h dmd/expression.c dmd/expression.h dmd/func.c dmd/idgen.c dmd/import.c dmd/import.h dmd/init.c dmd/inline.c dmd/interpret.c dmd/lexer.c dmd/lexer.h dmd/mangle.c dmd/mars.c dmd/mars.h dmd/module.c dmd/module.h dmd/mtype.c dmd/mtype.h dmd/opover.c dmd/optimize.c dmd/parse.c dmd/root/async.c dmd/root/man.c dmd/root/root.c dmd/scope.c dmd/scope.h dmd/statement.c dmd/statement.h dmd/struct.c dmd/template.c dmd/template.h gen/classes.cpp gen/main.cpp |
diffstat | 46 files changed, 19573 insertions(+), 16605 deletions(-) [+] |
line wrap: on
line diff
--- a/dmd/aggregate.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/aggregate.h Fri Nov 06 23:58:01 2009 +0100 @@ -62,13 +62,19 @@ // 1: size is correct // 2: cannot determine size; fwd referenced int isdeprecated; // !=0 if deprecated - Scope *scope; // !=NULL means context to use // Special member functions InvariantDeclaration *inv; // invariant NewDeclaration *aggNew; // allocator DeleteDeclaration *aggDelete; // deallocator +#if DMDV2 + //CtorDeclaration *ctor; + Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration + CtorDeclaration *defaultCtor; // default constructor + Dsymbol *aliasthis; // forward unresolved lookups to aliasthis +#endif + FuncDeclarations dtors; // Array of destructors FuncDeclaration *dtor; // aggregate destructor @@ -88,6 +94,7 @@ FuncDeclaration *buildDtor(Scope *sc); void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); void toDocBuffer(OutBuffer *buf); // For access checking
--- a/dmd/arrayop.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/arrayop.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -31,6 +31,14 @@ Expression *BinExp::arrayOp(Scope *sc) { + //printf("BinExp::arrayOp() %s\n", toChars()); + + if (type->toBasetype()->nextOf()->toBasetype()->ty == Tvoid) + { + error("Cannot perform array operations on void[] arrays"); + return new ErrorExp(); + } + Expressions *arguments = new Expressions(); /* The expression to generate an array operation for is mangled @@ -288,6 +296,8 @@ sc->stc = 0; sc->linkage = LINKd; fd->semantic(sc); + fd->semantic2(sc); + fd->semantic3(sc); sc->pop(); // } // else @@ -318,6 +328,17 @@ arguments->shift(this); } +void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + Type *tb = type->toBasetype(); + if (tb->ty == Tarray || tb->ty == Tsarray) + { + e1->buildArrayIdent(buf, arguments); + } + else + Expression::buildArrayIdent(buf, arguments); +} + void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) { buf->writestring("Slice"); @@ -402,6 +423,17 @@ return e; } +Expression *CastExp::buildArrayLoop(Arguments *fparams) +{ + Type *tb = type->toBasetype(); + if (tb->ty == Tarray || tb->ty == Tsarray) + { + return e1->buildArrayLoop(fparams); + } + else + return Expression::buildArrayLoop(fparams); +} + Expression *SliceExp::buildArrayLoop(Arguments *fparams) { Identifier *id = Identifier::generateId("p", fparams->dim); @@ -420,6 +452,14 @@ /* Evaluate assign expressions right to left */ Expression *ex2 = e2->buildArrayLoop(fparams); +#if DMDV2 + /* Need the cast because: + * b = c + p[i]; + * where b is a byte fails because (c + p[i]) is an int + * which cannot be implicitly cast to byte. + */ + ex2 = new CastExp(0, ex2, e1->type->nextOf()); +#endif Expression *ex1 = e1->buildArrayLoop(fparams); Argument *param = (Argument *)fparams->data[0]; param->storageClass = 0; @@ -488,3 +528,34 @@ #undef X +/*********************************************** + * Test if operand is a valid array op operand. + */ + +int Expression::isArrayOperand() +{ + //printf("Expression::isArrayOperand() %s\n", toChars()); + if (op == TOKslice) + return 1; + if (type->toBasetype()->ty == Tarray) + { + switch (op) + { + case TOKadd: + case TOKmin: + case TOKmul: + case TOKdiv: + case TOKmod: + case TOKxor: + case TOKand: + case TOKor: + case TOKneg: + case TOKtilde: + return 1; + + default: + break; + } + } + return 0; +}
--- a/dmd/attrib.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/attrib.c Fri Nov 06 23:58:01 2009 +0100 @@ -26,6 +26,9 @@ #include "module.h" #include "parse.h" #include "template.h" +#if TARGET_NET + #include "frontend.net/pragma.h" +#endif #if IN_LLVM #include "../gen/enums.h" @@ -74,6 +77,76 @@ return m; } +void AttribDeclaration::setScopeNewSc(Scope *sc, + unsigned stc, enum LINK linkage, enum PROT protection, int explicitProtection, + unsigned structalign) +{ + if (decl) + { + Scope *newsc = sc; + if (stc != sc->stc || + linkage != sc->linkage || + protection != sc->protection || + explicitProtection != sc->explicitProtection || + structalign != sc->structalign) + { + // create new one for changes + newsc = new Scope(*sc); + newsc->flags &= ~SCOPEfree; + newsc->stc = stc; + newsc->linkage = linkage; + newsc->protection = protection; + newsc->explicitProtection = explicitProtection; + newsc->structalign = structalign; + } + for (unsigned i = 0; i < decl->dim; i++) + { Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->setScope(newsc); // yes, the only difference from semanticNewSc() + } + if (newsc != sc) + { + sc->offset = newsc->offset; + newsc->pop(); + } + } +} + +void AttribDeclaration::semanticNewSc(Scope *sc, + unsigned stc, enum LINK linkage, enum PROT protection, int explicitProtection, + unsigned structalign) +{ + if (decl) + { + Scope *newsc = sc; + if (stc != sc->stc || + linkage != sc->linkage || + protection != sc->protection || + explicitProtection != sc->explicitProtection || + structalign != sc->structalign) + { + // create new one for changes + newsc = new Scope(*sc); + newsc->flags &= ~SCOPEfree; + newsc->stc = stc; + newsc->linkage = linkage; + newsc->protection = protection; + newsc->explicitProtection = explicitProtection; + newsc->structalign = structalign; + } + for (unsigned i = 0; i < decl->dim; i++) + { Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(newsc); + } + if (newsc != sc) + { + sc->offset = newsc->offset; + newsc->pop(); + } + } +} + void AttribDeclaration::semantic(Scope *sc) { Array *d = include(sc, NULL); @@ -302,24 +375,50 @@ return scd; } +void StorageClassDeclaration::setScope(Scope *sc) +{ + if (decl) + { + unsigned scstc = sc->stc; + + /* These sets of storage classes are mutually exclusive, + * so choose the innermost or most recent one. + */ + if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) + scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); + if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) + scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); + if (stc & (STCconst | STCimmutable | STCmanifest)) + scstc &= ~(STCconst | STCimmutable | STCmanifest); + if (stc & (STCgshared | STCshared | STCtls)) + scstc &= ~(STCgshared | STCshared | STCtls); + scstc |= stc; + + setScopeNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); + } +} + void StorageClassDeclaration::semantic(Scope *sc) { if (decl) - { unsigned stc_save = sc->stc; + { + unsigned scstc = sc->stc; - if (stc & (STCauto | STCscope | STCstatic | STCextern)) - sc->stc &= ~(STCauto | STCscope | STCstatic | STCextern); - sc->stc |= stc; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; + /* These sets of storage classes are mutually exclusive, + * so choose the innermost or most recent one. + */ + if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) + scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); + if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) + scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); + if (stc & (STCconst | STCimmutable | STCmanifest)) + scstc &= ~(STCconst | STCimmutable | STCmanifest); + if (stc & (STCgshared | STCshared | STCtls)) + scstc &= ~(STCgshared | STCshared | STCtls); + scstc |= stc; - s->semantic(sc); - } - sc->stc = stc_save; + semanticNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); } - else - sc->stc = stc; } void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, int stc) @@ -337,17 +436,11 @@ { STCstatic, TOKstatic }, { STCextern, TOKextern }, { STCconst, TOKconst }, -// { STCinvariant, TOKimmutable }, -// { STCshared, TOKshared }, { STCfinal, TOKfinal }, { STCabstract, TOKabstract }, { STCsynchronized, TOKsynchronized }, { STCdeprecated, TOKdeprecated }, { STCoverride, TOKoverride }, -// { STCnothrow, TOKnothrow }, -// { STCpure, TOKpure }, -// { STCref, TOKref }, -// { STCtls, TOKtls }, }; for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) @@ -384,24 +477,21 @@ return ld; } +void LinkDeclaration::setScope(Scope *sc) +{ + //printf("LinkDeclaration::setScope(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { + setScopeNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); + } +} + void LinkDeclaration::semantic(Scope *sc) { //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->linkage = linkage_save; - } - else { - sc->linkage = linkage; + semanticNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); } } @@ -473,31 +563,48 @@ return pd; } +void ProtDeclaration::setScope(Scope *sc) +{ + if (decl) + { + setScopeNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); + } +} + +void ProtDeclaration::importAll(Scope *sc) +{ + Scope *newsc = sc; + if (sc->protection != protection || + sc->explicitProtection != 1) + { + // create new one for changes + newsc = new Scope(*sc); + newsc->flags &= ~SCOPEfree; + newsc->protection = protection; + newsc->explicitProtection = 1; + } + + for (int i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + s->importAll(newsc); + } + + if (newsc != sc) + newsc->pop(); +} + void ProtDeclaration::semantic(Scope *sc) { if (decl) - { enum PROT protection_save = sc->protection; - int explicitProtection_save = sc->explicitProtection; - - sc->protection = protection; - sc->explicitProtection = 1; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - } - sc->protection = protection_save; - sc->explicitProtection = explicitProtection_save; - } - else - { sc->protection = protection; - sc->explicitProtection = 1; + { + semanticNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); } } -void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ const char *p; +void ProtDeclaration::protectionToCBuffer(OutBuffer *buf, enum PROT protection) +{ + const char *p; switch (protection) { @@ -511,6 +618,12 @@ break; } buf->writestring(p); + buf->writeByte(' '); +} + +void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + protectionToCBuffer(buf, protection); AttribDeclaration::toCBuffer(buf, hgs); } @@ -532,35 +645,23 @@ return ad; } +void AlignDeclaration::setScope(Scope *sc) +{ + //printf("\tAlignDeclaration::setScope '%s'\n",toChars()); + if (decl) + { + setScopeNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); + } +} + void AlignDeclaration::semantic(Scope *sc) { // LDC // we only support packed structs, as from the spec: align(1) struct Packed { ... } // other alignments are simply ignored. my tests show this is what llvm-gcc does too ... - - //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); - if (decl) - { unsigned salign_save = sc->structalign; - - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - if (s->isStructDeclaration() && salign == 1) - { - sc->structalign = salign; - s->semantic(sc); - sc->structalign = salign_save; - } - else - { - s->semantic(sc); - } - } - sc->structalign = salign_save; + { + semanticNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); } - else - assert(0 && "what kind of align use triggers this?"); } @@ -577,7 +678,6 @@ { this->loc = loc; this->isunion = isunion; - this->scope = NULL; this->sem = 0; } @@ -780,6 +880,39 @@ return pd; } +void PragmaDeclaration::setScope(Scope *sc) +{ +#if TARGET_NET + if (ident == Lexer::idPool("assembly")) + { + if (!args || args->dim != 1) + { + error("pragma has invalid number of arguments"); + } + else + { + Expression *e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + { + error("string expected, not '%s'", e->toChars()); + } + PragmaScope* pragma = new PragmaScope(this, sc->parent, static_cast<StringExp*>(e)); + + assert(sc); + pragma->setScope(sc); + + //add to module members + assert(sc->module); + assert(sc->module->members); + sc->module->members->push(pragma); + } + } +#endif // TARGET_NET +} + void PragmaDeclaration::semantic(Scope *sc) { // Should be merged with PragmaStatement @@ -803,10 +936,10 @@ if (e->op == TOKstring) { StringExp *se = (StringExp *)e; - fprintf(stdmsg, "%.*s", (int)se->len, (char*)se->string); + fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); } else - error("string expected for message, not '%s'", e->toChars()); + fprintf(stdmsg, e->toChars()); } fprintf(stdmsg, "\n"); } @@ -873,6 +1006,27 @@ goto Lnodecl; } #endif +#if TARGET_NET + else if (ident == Lexer::idPool("assembly")) + { + if (!args || args->dim != 1) + error("pragma has invalid number of arguments"); + else + { + Expression *e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + { + error("string expected, not '%s'", e->toChars()); + } + PragmaScope* pragma = new PragmaScope(this, sc->parent, static_cast<StringExp*>(e)); + decl = new Array; + decl->push(pragma); + } + } +#endif // TARGET_NET // LDC #if IN_LLVM @@ -1001,6 +1155,7 @@ #endif // LDC + else if (ignoreUnsupportedPragmas) { if (global.params.verbose) @@ -1298,6 +1453,37 @@ return condition->include(sc, sd) ? decl : elsedecl; } +void ConditionalDeclaration::setScope(Scope *sc) +{ + Array *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]; + + s->setScope(sc); + } + } +} + +void ConditionalDeclaration::importAll(Scope *sc) +{ + Array *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]; + + s->importAll(sc); + } + } +} void ConditionalDeclaration::addComment(unsigned char *comment) { @@ -1418,6 +1604,16 @@ } +void StaticIfDeclaration::importAll(Scope *sc) +{ + // do not evaluate condition before semantic pass +} + +void StaticIfDeclaration::setScope(Scope *sc) +{ + // do not evaluate condition before semantic pass +} + void StaticIfDeclaration::semantic(Scope *sc) { Array *d = include(sc, sd);
--- a/dmd/attrib.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/attrib.h Fri Nov 06 23:58:01 2009 +0100 @@ -1,183 +1,202 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_ATTRIB_H -#define DMD_ATTRIB_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -struct Initializer; -struct Module; -struct Condition; -#ifdef _DH -struct HdrGenState; -#endif - -/**************************************************************/ - -struct AttribDeclaration : Dsymbol -{ - Array *decl; // array of Dsymbol's - - AttribDeclaration(Array *decl); - virtual Array *include(Scope *sc, ScopeDsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - void addComment(unsigned char *comment); - void emitComment(Scope *sc); - const char *kind(); - int oneMember(Dsymbol **ps); - int hasPointers(); - void checkCtorConstInit(); - void addLocalClass(ClassDeclarations *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - AttribDeclaration *isAttribDeclaration() { return this; } - -#if IN_DMD - virtual void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); -#endif - -#if IN_LLVM - virtual void codegen(Ir*); -#endif -}; - -struct StorageClassDeclaration: AttribDeclaration -{ - unsigned stc; - - StorageClassDeclaration(unsigned stc, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - static void stcToCBuffer(OutBuffer *buf, int stc); -}; - -struct LinkDeclaration : AttribDeclaration -{ - enum LINK linkage; - - LinkDeclaration(enum LINK p, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void semantic3(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *toChars(); -}; - -struct ProtDeclaration : AttribDeclaration -{ - enum PROT protection; - - ProtDeclaration(enum PROT p, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AlignDeclaration : AttribDeclaration -{ - unsigned salign; - - AlignDeclaration(Loc loc, unsigned sa, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AnonDeclaration : AttribDeclaration -{ - int isunion; - Scope *scope; // !=NULL means context to use - int sem; // 1 if successful semantic() - - AnonDeclaration(Loc loc, int isunion, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -struct PragmaDeclaration : AttribDeclaration -{ - Expressions *args; // array of Expression's - - PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - int oneMember(Dsymbol **ps); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -struct ConditionalDeclaration : AttribDeclaration -{ - Condition *condition; - Array *elsedecl; // array of Dsymbol's for else block - - ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int oneMember(Dsymbol **ps); - void emitComment(Scope *sc); - Array *include(Scope *sc, ScopeDsymbol *s); - void addComment(unsigned char *comment); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct StaticIfDeclaration : ConditionalDeclaration -{ - ScopeDsymbol *sd; - int addisdone; - - StaticIfDeclaration(Condition *condition, Array *decl, Array *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - const char *kind(); -}; - -// Mixin declarations - -struct CompileDeclaration : AttribDeclaration -{ - Expression *exp; - - ScopeDsymbol *sd; - int compiled; - - CompileDeclaration(Loc loc, Expression *exp); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); - void compileIt(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif /* DMD_ATTRIB_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_ATTRIB_H +#define DMD_ATTRIB_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "dsymbol.h" + +struct Expression; +struct Statement; +struct LabelDsymbol; +struct Initializer; +struct Module; +struct Condition; +#ifdef _DH +struct HdrGenState; +#endif + +/**************************************************************/ + +struct AttribDeclaration : Dsymbol +{ + Array *decl; // array of Dsymbol's + + AttribDeclaration(Array *decl); + virtual Array *include(Scope *sc, ScopeDsymbol *s); + int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + void setScopeNewSc(Scope *sc, + unsigned newstc, enum LINK linkage, enum PROT protection, int explictProtection, + unsigned structalign); + void semanticNewSc(Scope *sc, + unsigned newstc, enum LINK linkage, enum PROT protection, int explictProtection, + unsigned structalign); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void inlineScan(); + void addComment(unsigned char *comment); + void emitComment(Scope *sc); + const char *kind(); + int oneMember(Dsymbol **ps); + int hasPointers(); + void checkCtorConstInit(); + void addLocalClass(ClassDeclarations *); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJsonBuffer(OutBuffer *buf); + AttribDeclaration *isAttribDeclaration() { return this; } + +#if IN_DMD + virtual void toObjFile(int multiobj); // compile to .obj file + int cvMember(unsigned char *p); +#endif + +#if IN_LLVM + virtual void codegen(Ir*); +#endif +}; + +struct StorageClassDeclaration: AttribDeclaration +{ + unsigned stc; + + StorageClassDeclaration(unsigned stc, Array *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void setScope(Scope *sc); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + static void stcToCBuffer(OutBuffer *buf, int stc); +}; + +struct LinkDeclaration : AttribDeclaration +{ + enum LINK linkage; + + LinkDeclaration(enum LINK p, Array *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void setScope(Scope *sc); + void semantic(Scope *sc); + void semantic3(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *toChars(); +}; + +struct ProtDeclaration : AttribDeclaration +{ + enum PROT protection; + + ProtDeclaration(enum PROT p, Array *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void importAll(Scope *sc); + void setScope(Scope *sc); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + static void protectionToCBuffer(OutBuffer *buf, enum PROT protection); +}; + +struct AlignDeclaration : AttribDeclaration +{ + unsigned salign; + + AlignDeclaration(Loc loc, unsigned sa, Array *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void setScope(Scope *sc); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct AnonDeclaration : AttribDeclaration +{ + int isunion; + int sem; // 1 if successful semantic() + + AnonDeclaration(Loc loc, int isunion, Array *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); +}; + +struct PragmaDeclaration : AttribDeclaration +{ + Expressions *args; // array of Expression's + + PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void setScope(Scope *sc); + int oneMember(Dsymbol **ps); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file +#endif + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + +struct ConditionalDeclaration : AttribDeclaration +{ + Condition *condition; + Array *elsedecl; // array of Dsymbol's for else block + + ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl); + Dsymbol *syntaxCopy(Dsymbol *s); + int oneMember(Dsymbol **ps); + void emitComment(Scope *sc); + Array *include(Scope *sc, ScopeDsymbol *s); + void addComment(unsigned char *comment); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJsonBuffer(OutBuffer *buf); + void importAll(Scope *sc); + void setScope(Scope *sc); +}; + +struct StaticIfDeclaration : ConditionalDeclaration +{ + ScopeDsymbol *sd; + int addisdone; + + StaticIfDeclaration(Condition *condition, Array *decl, Array *elsedecl); + Dsymbol *syntaxCopy(Dsymbol *s); + int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + void semantic(Scope *sc); + void importAll(Scope *sc); + void setScope(Scope *sc); + const char *kind(); +}; + +// Mixin declarations + +struct CompileDeclaration : AttribDeclaration +{ + Expression *exp; + + ScopeDsymbol *sd; + int compiled; + + CompileDeclaration(Loc loc, Expression *exp); + Dsymbol *syntaxCopy(Dsymbol *s); + int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); + void compileIt(Scope *sc); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +#endif /* DMD_ATTRIB_H */
--- a/dmd/cast.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/cast.c Fri Nov 06 23:58:01 2009 +0100 @@ -1078,22 +1078,20 @@ Expression *SymOffExp::castTo(Scope *sc, Type *t) { - Type *tb; - #if 0 printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", toChars(), type->toChars(), t->toChars()); #endif Expression *e = this; - tb = t->toBasetype(); - type = type->toBasetype(); - if (tb != type) + Type *tb = t->toBasetype(); + Type *typeb = type->toBasetype(); + if (tb != typeb) { // Look for pointers to functions where the functions are overloaded. FuncDeclaration *f; - if (type->ty == Tpointer && type->next->ty == Tfunction && + if (typeb->ty == Tpointer && typeb->next->ty == Tfunction && tb->ty == Tpointer && tb->next->ty == Tfunction) { f = var->isFuncDeclaration(); @@ -1102,15 +1100,47 @@ f = f->overloadExactMatch(tb->next, m); if (f) { - e = new SymOffExp(loc, f, 0); - e->type = t; +#if DMDV2 + if (tb->ty == Tdelegate) + { + if (f->needThis() && hasThis(sc)) + { + e = new DelegateExp(loc, new ThisExp(loc), f); + e = e->semantic(sc); + } + else if (f->isNested()) + { + e = new DelegateExp(loc, new IntegerExp(0), f); + e = e->semantic(sc); + } + else if (f->needThis()) + { error("no 'this' to create delegate for %s", f->toChars()); + e = new ErrorExp(); + } + else + { error("cannot cast from function pointer to delegate"); + e = new ErrorExp(); + } + } + else +#endif + { + e = new SymOffExp(loc, f, 0); + e->type = t; + } +#if DMDV2 + f->tookAddressOf++; +#endif return e; } } } e = Expression::castTo(sc, t); } - e->type = t; + else + { + e->type = t; + } return e; } @@ -1484,13 +1514,13 @@ { assert(0); } - else if (e1->op == TOKslice && t1->ty == Tarray && + else if (e1->isArrayOperand() && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf())) { // T[] op T e2 = e2->castTo(sc, t1->nextOf()); t = t1->nextOf()->arrayOf(); } - else if (e2->op == TOKslice && t2->ty == Tarray && + else if (e2->isArrayOperand() && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) { // T op T[] e1 = e1->castTo(sc, t2->nextOf());
--- a/dmd/class.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/class.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -161,6 +161,12 @@ Type::typeinfoinvariant->error("%s", msg); Type::typeinfoinvariant = this; } + + if (id == Id::TypeInfo_Shared) + { if (Type::typeinfoshared) + Type::typeinfoshared->error("%s", msg); + Type::typeinfoshared = this; + } #endif } @@ -226,19 +232,19 @@ //{ static int n; if (++n == 20) *(char*)0=0; } if (!ident) // if anonymous class - { char *id = "__anonclass"; + { const char *id = "__anonclass"; ident = Identifier::generateId(id); } - if (!scope) - { - if (!parent && sc->parent && !sc->parent->isModule()) - parent = sc->parent; + if (!sc) + sc = scope; + if (!parent && sc->parent && !sc->parent->isModule()) + parent = sc->parent; - type = type->semantic(loc, sc); - handle = handle->semantic(loc, sc); - } + type = type->semantic(loc, sc); + handle = type; + if (!members) // if forward reference { //printf("\tclass '%s' is forward referenced\n", toChars()); return; @@ -329,13 +335,21 @@ goto L7; } } + if (!tc->sym->symtab || tc->sym->sizeok == 0) + { // Try to resolve forward reference + if (sc->mustsemantic && tc->sym->scope) + tc->sym->semantic(NULL); + } if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) { + //printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars()); //error("forward reference of base class %s", baseClass->toChars()); // Forward reference of base class, try again later //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); scope = scx ? scx : new Scope(*sc); scope->setNoFree(); + if (tc->sym->scope) + tc->sym->scope->module->addDeferredSemantic(tc->sym); scope->module->addDeferredSemantic(this); return; } @@ -389,6 +403,12 @@ error("inherits from duplicate interface %s", b2->base->toChars()); } + if (!tc->sym->symtab) + { // Try to resolve forward reference + if (sc->mustsemantic && tc->sym->scope) + tc->sym->semantic(NULL); + } + b->base = tc->sym; if (!b->base->symtab || b->base->scope) { @@ -397,6 +417,8 @@ //printf("\ttry later, forward reference of base %s\n", baseClass->toChars()); scope = scx ? scx : new Scope(*sc); scope->setNoFree(); + if (tc->sym->scope) + tc->sym->scope->module->addDeferredSemantic(tc->sym); scope->module->addDeferredSemantic(this); return; } @@ -500,15 +522,15 @@ { Dsymbol *s = toParent2(); if (s) { - ClassDeclaration *cd = s->isClassDeclaration(); + AggregateDeclaration *ad = s->isClassDeclaration(); FuncDeclaration *fd = s->isFuncDeclaration(); - if (cd || fd) + if (ad || fd) { isnested = 1; Type *t; - if (cd) - t = cd->type; + if (ad) + t = ad->handle; else if (fd) { AggregateDeclaration *ad = fd->isMember2(); if (ad) @@ -564,7 +586,7 @@ // sc->offset += PTRSIZE; // room for uplevel context pointer } else - { sc->offset = PTRSIZE * 2; // allow room for vptr[] and monitor + { sc->offset = PTRSIZE * 2; // allow room for __vptr and __monitor alignsize = PTRSIZE; } structsize = sc->offset; @@ -703,17 +725,22 @@ //buf->writestring(b->base->ident->toChars()); b->type->toCBuffer(buf, NULL, hgs); } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (int i = 0; i < members->dim; i++) + if (members) { - Dsymbol *s = (Dsymbol *)members->data[i]; + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; - buf->writestring(" "); - s->toCBuffer(buf, hgs); + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writestring("}"); } - buf->writestring("}"); + else + buf->writeByte(';'); buf->writenl(); } @@ -777,13 +804,18 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) { Dsymbol *s; + //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); - //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); if (scope) - semantic(scope); + { Scope *sc = scope; + sc->mustsemantic++; + semantic(sc); + sc->mustsemantic--; + } if (!members || !symtab || scope) - { error("is forward referenced when looking for '%s'", ident->toChars()); + { + error("is forward referenced when looking for '%s'", ident->toChars()); //*(char*)0=0; return NULL; } @@ -831,7 +863,7 @@ int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) { - //printf("ClassDeclaration::isFuncHidden(%s)\n", fd->toChars()); + //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); Dsymbol *s = search(0, fd->ident, 4|2); if (!s) { //printf("not found\n"); @@ -916,6 +948,13 @@ return 0; } +#if DMDV2 +int ClassDeclaration::isCPPinterface() +{ + return 0; +} +#endif + /**************************************** */ @@ -1006,10 +1045,15 @@ //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); if (inuse) return; - if (!scope) - { type = type->semantic(loc, sc); - handle = handle->semantic(loc, sc); - } + + if (!sc) + sc = scope; + if (!parent && sc->parent && !sc->parent->isModule()) + parent = sc->parent; + + type = type->semantic(loc, sc); + handle = type; + if (!members) // if forward reference { //printf("\tinterface '%s' is forward referenced\n", toChars()); return; @@ -1090,6 +1134,11 @@ baseclasses.remove(i); continue; } + if (!b->base->symtab) + { // Try to resolve forward reference + if (sc->mustsemantic && b->base->scope) + b->base->semantic(NULL); + } if (!b->base->symtab || b->base->scope || b->base->inuse) { //error("forward reference of base class %s", baseClass->toChars()); @@ -1262,6 +1311,13 @@ return com; } +#if DMDV2 +int InterfaceDeclaration::isCPPinterface() +{ + return cpp; +} +#endif + /******************************************* */
--- a/dmd/constfold.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/constfold.c Fri Nov 06 23:58:01 2009 +0100 @@ -74,6 +74,11 @@ return 1; } +int NullExp::isConst() +{ + return 1; +} + int SymOffExp::isConst() { return 2; @@ -845,7 +850,7 @@ { cmp = e1->toComplex() == e2->toComplex(); } - else if (e1->type->isintegral()) + else if (e1->type->isintegral() || e1->type->toBasetype()->ty == Tpointer) { cmp = (e1->toInteger() == e2->toInteger()); } @@ -862,9 +867,13 @@ Loc loc = e1->loc; int cmp; - if (e1->op == TOKnull && e2->op == TOKnull) + if (e1->op == TOKnull) { - cmp = 1; + cmp = (e2->op == TOKnull); + } + else if (e2->op == TOKnull) + { + cmp = 0; } else if (e1->op == TOKsymoff && e2->op == TOKsymoff) { @@ -1046,11 +1055,12 @@ return e1; Type *tb = to->toBasetype(); - Type *typeb = type->toBasetype(); - // LDC: ported from D2 to allow char[] ~ char[n] arguments in CTFE + /* Allow casting from one string type to another + */ if (e1->op == TOKstring) { + Type *typeb = type->toBasetype(); if (tb->ty == Tarray && typeb->ty == Tarray && tb->nextOf()->size() == typeb->nextOf()->size()) { @@ -1069,7 +1079,7 @@ { dinteger_t result; real_t r = e1->toReal(); - switch (typeb->ty) + switch (type->toBasetype()->ty) { case Tint8: result = (d_int8)r; break; case Tchar:
--- a/dmd/declaration.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/declaration.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,1453 +1,1616 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <assert.h> - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "mtype.h" -#include "template.h" -#include "scope.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "hdrgen.h" - -/********************************* Declaration ****************************/ - -Declaration::Declaration(Identifier *id) - : Dsymbol(id) -{ - type = NULL; - originalType = NULL; - storage_class = STCundefined; - protection = PROTundefined; - linkage = LINKdefault; - inuse = 0; -} - -void Declaration::semantic(Scope *sc) -{ -} - -const char *Declaration::kind() -{ - return "declaration"; -} - -unsigned Declaration::size(Loc loc) -{ - assert(type); - return type->size(); -} - -int Declaration::isStaticConstructor() -{ - return FALSE; -} - -int Declaration::isStaticDestructor() -{ - return FALSE; -} - -int Declaration::isDelete() -{ - return FALSE; -} - -int Declaration::isDataseg() -{ - return FALSE; -} - -int Declaration::isCodeseg() -{ - return FALSE; -} - -enum PROT Declaration::prot() -{ - return protection; -} - -/************************************* - * Check to see if declaration can be modified in this context (sc). - * Issue error if not. - */ - -#if DMDV2 -void Declaration::checkModify(Loc loc, Scope *sc, Type *t) -{ - if (sc->incontract && isParameter()) - error(loc, "cannot modify parameter '%s' in contract", toChars()); - - if (isCtorinit()) - { // It's only modifiable if inside the right constructor - Dsymbol *s = sc->func; - while (1) - { - FuncDeclaration *fd = NULL; - if (s) - fd = s->isFuncDeclaration(); - if (fd && - ((fd->isCtorDeclaration() && storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) && - fd->toParent() == toParent() - ) - { - VarDeclaration *v = isVarDeclaration(); - assert(v); - v->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else - { - const char *p = isStatic() ? "static " : ""; - error(loc, "can only initialize %sconst %s inside %sconstructor", - p, toChars(), p); - } - } - break; - } - } - else - { - VarDeclaration *v = isVarDeclaration(); - if (v && v->canassign == 0) - { - char *p = NULL; - if (isConst()) - p = "const"; - else if (isInvariant()) - p = "invariant"; - else if (storage_class & STCmanifest) - p = "manifest constant"; - else if (!t->isAssignable()) - p = "struct with immutable members"; - if (p) - { error(loc, "cannot modify %s", p); - halt(); - } - } - } -} -#endif - - -/********************************* TupleDeclaration ****************************/ - -TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) - : Declaration(id) -{ - this->type = NULL; - this->objects = objects; - this->isexp = 0; - this->tupletype = NULL; -} - -Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); - return NULL; -} - -const char *TupleDeclaration::kind() -{ - return "tuple"; -} - -Type *TupleDeclaration::getType() -{ - /* If this tuple represents a type, return that type - */ - - //printf("TupleDeclaration::getType() %s\n", toChars()); - if (isexp) - return NULL; - if (!tupletype) - { - /* It's only a type tuple if all the Object's are types - */ - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; - - if (o->dyncast() != DYNCAST_TYPE) - { - //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); - return NULL; - } - } - - /* We know it's a type tuple, so build the TypeTuple - */ - Arguments *args = new Arguments(); - args->setDim(objects->dim); - OutBuffer buf; - for (size_t i = 0; i < objects->dim; i++) - { Type *t = (Type *)objects->data[i]; - - //printf("type = %s\n", t->toChars()); -#if 0 - buf.printf("_%s_%d", ident->toChars(), i); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - Argument *arg = new Argument(STCin, t, id, NULL); -#else - Argument *arg = new Argument(STCin, t, NULL, NULL); -#endif - args->data[i] = (void *)arg; - } - - tupletype = new TypeTuple(args); - } - - return tupletype; -} - -int TupleDeclaration::needThis() -{ - //printf("TupleDeclaration::needThis(%s)\n", toChars()); - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - if (e->op == TOKdsymbol) - { DsymbolExp *ve = (DsymbolExp *)e; - Declaration *d = ve->s->isDeclaration(); - if (d && d->needThis()) - { - return 1; - } - } - } - } - return 0; -} - -/********************************* TypedefDeclaration ****************************/ - -TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) - : Declaration(id) -{ - this->type = new TypeTypedef(this); - this->basetype = basetype->toBasetype(); - this->init = init; -#ifdef _DH - this->htype = NULL; - this->hbasetype = NULL; -#endif - this->sem = 0; - this->loc = loc; -#if IN_DMD - this->sinit = NULL; -#endif -} - -Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *basetype = this->basetype->syntaxCopy(); - - Initializer *init = NULL; - if (this->init) - init = this->init->syntaxCopy(); - - assert(!s); - TypedefDeclaration *st; - st = new TypedefDeclaration(loc, ident, basetype, init); -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - st->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - st->htype = htype->syntaxCopy(); - if (!hbasetype) - { if (basetype) - { hbasetype = basetype->syntaxCopy(); - st->hbasetype = basetype->syntaxCopy(); - } - } - else - st->hbasetype = hbasetype->syntaxCopy(); -#endif - return st; -} - -void TypedefDeclaration::semantic(Scope *sc) -{ - //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); - if (sem == 0) - { sem = 1; - basetype = basetype->semantic(loc, sc); - sem = 2; - type = type->semantic(loc, sc); - if (sc->parent->isFuncDeclaration() && init) - semantic2(sc); - storage_class |= sc->stc & STCdeprecated; - } - else if (sem == 1) - { - error("circular definition"); - } -} - -void TypedefDeclaration::semantic2(Scope *sc) -{ - //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); - if (sem == 2) - { sem = 3; - if (init) - { - init = init->semantic(sc, basetype); - - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - { - if (ie->exp->type == basetype) - ie->exp->type = type; - } - } - } -} - -const char *TypedefDeclaration::kind() -{ - return "typedef"; -} - -Type *TypedefDeclaration::getType() -{ - return type; -} - -void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typedef "); - basetype->toCBuffer(buf, ident, hgs); - if (init) - { - buf->writestring(" = "); - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* AliasDeclaration ****************************/ - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("type = '%s'\n", type->toChars()); - this->loc = loc; - this->type = type; - this->aliassym = NULL; -#ifdef _DH - this->htype = NULL; - this->haliassym = NULL; -#endif - this->overnext = NULL; - this->inSemantic = 0; - this->importprot = PROTundefined; - assert(type); -} - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); - assert(s != this); - this->loc = loc; - this->type = NULL; - this->aliassym = s; -#ifdef _DH - this->htype = NULL; - this->haliassym = NULL; -#endif - this->overnext = NULL; - this->inSemantic = 0; - assert(s); -} - -Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("AliasDeclaration::syntaxCopy()\n"); - assert(!s); - AliasDeclaration *sa; - if (type) - sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); - else - sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sa->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sa->htype = htype->syntaxCopy(); - if (!haliassym) - { if (aliassym) - { haliassym = aliassym->syntaxCopy(s); - sa->haliassym = aliassym->syntaxCopy(s); - } - } - else - sa->haliassym = haliassym->syntaxCopy(s); -#endif - return sa; -} - -void AliasDeclaration::semantic(Scope *sc) -{ - //printf("AliasDeclaration::semantic() %s\n", toChars()); - if (aliassym) - { - if (aliassym->isTemplateInstance()) - aliassym->semantic(sc); - return; - } - this->inSemantic = 1; - - if (storage_class & STCconst) - error("cannot be const"); - - storage_class |= sc->stc & STCdeprecated; - - // Given: - // alias foo.bar.abc def; - // it is not knowable from the syntax whether this is an alias - // for a type or an alias for a symbol. It is up to the semantic() - // pass to distinguish. - // If it is a type, then type is set and getType() will return that - // type. If it is a symbol, then aliassym is set and type is NULL - - // toAlias() will return aliasssym. - - Dsymbol *s; - Type *t; - Expression *e; - - /* This section is needed because resolve() will: - * const x = 3; - * alias x y; - * try to alias y to 3. - */ - s = type->toDsymbol(sc); - if (s) - goto L2; // it's a symbolic alias - - //printf("alias type is %s\n", type->toChars()); - type->resolve(loc, sc, &e, &t, &s); - if (s) - { - goto L2; - } - else if (e) - { - // Try to convert Expression to Dsymbol - if (e->op == TOKvar) - { s = ((VarExp *)e)->var; - goto L2; - } - else if (e->op == TOKfunction) - { s = ((FuncExp *)e)->fd; - goto L2; - } - else - { error("cannot alias an expression %s", e->toChars()); - t = e->type; - } - } - else if (t) - { - type = t; - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, this, overnext); - this->inSemantic = 0; - return; - - L2: - //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); - type = NULL; - VarDeclaration *v = s->isVarDeclaration(); - if (v && v->linkage == LINKdefault) - { - error("forward reference of %s", v->toChars()); - s = NULL; - } - else - { - FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); - if (f) - { - if (overnext) - { - FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); - fa->importprot = importprot; - if (!fa->overloadInsert(overnext)) - ScopeDsymbol::multiplyDefined(0, f, overnext); - overnext = NULL; - s = fa; - s->parent = sc->parent; - } - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, s, overnext); - if (s == this) - { - assert(global.errors); - s = NULL; - } - } - aliassym = s; - this->inSemantic = 0; -} - -int AliasDeclaration::overloadInsert(Dsymbol *s) -{ - /* Don't know yet what the aliased symbol is, so assume it can - * be overloaded and check later for correctness. - */ - - //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); - if (overnext == NULL) - { overnext = s; - return TRUE; - } - else - { - return overnext->overloadInsert(s); - } -} - -const char *AliasDeclaration::kind() -{ - return "alias"; -} - -Type *AliasDeclaration::getType() -{ - return type; -} - -Dsymbol *AliasDeclaration::toAlias() -{ - //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); - assert(this != aliassym); - //static int count; if (++count == 10) *(char*)0=0; - if (inSemantic) - { error("recursive alias declaration"); - aliassym = new TypedefDeclaration(loc, ident, Type::terror, NULL); - } - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); -#if 0 && _DH - if (hgs->hdrgen) - { - if (haliassym) - { - buf->writestring(haliassym->toChars()); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - htype->toCBuffer(buf, ident, hgs); - } - else -#endif - { - if (aliassym) - { - buf->writestring(aliassym->toChars()); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - type->toCBuffer(buf, ident, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* VarDeclaration ****************************/ - -VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) - : Declaration(id) -{ - //printf("VarDeclaration('%s')\n", id->toChars()); -#ifdef DEBUG - if (!type && !init) - { printf("VarDeclaration('%s')\n", id->toChars()); - //*(char*)0=0; - } -#endif - assert(type || init); - this->type = type; - this->init = init; -#ifdef _DH - this->htype = NULL; - this->hinit = NULL; -#endif - this->loc = loc; - offset = 0; - noscope = 0; - nestedref = 0; - ctorinit = 0; - aliassym = NULL; - onstack = 0; - canassign = 0; - value = NULL; - -#if IN_LLVM - aggrIndex = 0; - - // LDC - anonDecl = NULL; - offset2 = 0; - - nakedUse = false; - - availableExternally = true; // assume this unless proven otherwise -#endif -} - -Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); - - VarDeclaration *sv; - if (s) - { sv = (VarDeclaration *)s; - } - else - { - Initializer *init = NULL; - if (this->init) - { init = this->init->syntaxCopy(); - //init->isExpInitializer()->exp->print(); - //init->isExpInitializer()->exp->dump(0); - } - - sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); - sv->storage_class = storage_class; - } -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sv->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sv->htype = htype->syntaxCopy(); - if (!hinit) - { if (init) - { hinit = init->syntaxCopy(); - sv->hinit = init->syntaxCopy(); - } - } - else - sv->hinit = hinit->syntaxCopy(); -#endif - return sv; -} - -void VarDeclaration::semantic(Scope *sc) -{ - //printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); - //printf(" type = %s\n", type ? type->toChars() : "null"); - //printf(" stc = x%x\n", sc->stc); - //printf(" storage_class = x%x\n", storage_class); - //printf("linkage = %d\n", sc->linkage); - //if (strcmp(toChars(), "mul") == 0) halt(); - - storage_class |= sc->stc; - if (storage_class & STCextern && init) - error("extern symbols cannot have initializers"); - - /* If auto type inference, do the inference - */ - int inferred = 0; - if (!type) - { inuse++; - type = init->inferType(sc); - inuse--; - inferred = 1; - - /* This is a kludge to support the existing syntax for RAII - * declarations. - */ - storage_class &= ~STCauto; - originalType = type; - } - else - { if (!originalType) - originalType = type; - type = type->semantic(loc, sc); - } - //printf(" semantic type = %s\n", type ? type->toChars() : "null"); - - type->checkDeprecated(loc, sc); - linkage = sc->linkage; - this->parent = sc->parent; - //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); - protection = sc->protection; - //printf("sc->stc = %x\n", sc->stc); - //printf("storage_class = x%x\n", storage_class); - - Dsymbol *parent = toParent(); - FuncDeclaration *fd = parent->isFuncDeclaration(); - - Type *tb = type->toBasetype(); - if (tb->ty == Tvoid && !(storage_class & STClazy)) - { error("voids have no value"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tfunction) - { error("cannot be declared to be a function"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tb; - - if (!ts->sym->members) - { - error("no definition of struct %s", ts->toChars()); - } - } - if ((storage_class & STCauto) && !inferred) - error("both auto and explicit type given"); - - if (tb->ty == Ttuple) - { /* Instead, declare variables for each of the tuple elements - * and add those. - */ - TypeTuple *tt = (TypeTuple *)tb; - size_t nelems = Argument::dim(tt->arguments); - Objects *exps = new Objects(); - exps->setDim(nelems); - Expression *ie = init ? init->toExpression() : NULL; - - for (size_t i = 0; i < nelems; i++) - { Argument *arg = Argument::getNth(tt->arguments, i); - - OutBuffer buf; - buf.printf("_%s_field_%zu", ident->toChars(), i); - buf.writeByte(0); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - - Expression *einit = ie; - if (ie && ie->op == TOKtuple) - { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; - } - Initializer *ti = init; - if (einit) - { ti = new ExpInitializer(einit->loc, einit); - } - - VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); - //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); - v->semantic(sc); - -/* -// removed for LDC since TupleDeclaration::toObj already creates the fields; -// adding them to the scope again leads to duplicates - if (sc->scopesym) - { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); - if (sc->scopesym->members) - sc->scopesym->members->push(v); - } -*/ - Expression *e = new DsymbolExp(loc, v); - exps->data[i] = e; - } - TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); - v2->isexp = 1; - aliassym = v2; - return; - } - - if (storage_class & STCconst && !init && !fd) - // Initialize by constructor only - storage_class = (storage_class & ~STCconst) | STCctorinit; - - if (isConst()) - { - } - else if (isStatic()) - { - } - else if (isSynchronized()) - { - error("variable %s cannot be synchronized", toChars()); - } - else if (isOverride()) - { - error("override cannot be applied to variable"); - } - else if (isAbstract()) - { - error("abstract cannot be applied to variable"); - } - else if (storage_class & STCtemplateparameter) - { - } - else - { - AggregateDeclaration *aad = sc->anonAgg; - if (!aad) - aad = parent->isAggregateDeclaration(); - if (aad) - { - aad->addField(sc, this); - } - - InterfaceDeclaration *id = parent->isInterfaceDeclaration(); - if (id) - { - error("field not allowed in interface"); - } - - /* Templates cannot add fields to aggregates - */ - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - AggregateDeclaration *ad = ti->tempdecl->isMember(); - if (ad && storage_class != STCundefined) - { - error("cannot use template to add field to aggregate '%s'", ad->toChars()); - } - } - } - - if (type->isscope() && !noscope) - { - if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) - { - error("globals, statics, fields, ref and out parameters cannot be scope"); - } - - if (!(storage_class & STCscope)) - { - if (!(storage_class & STCparameter) && ident != Id::withSym) - error("reference to scope class must be scope"); - } - } - - if (!init && !sc->inunion && !isStatic() && !isConst() && fd && - !(storage_class & (STCfield | STCin | STCforeach)) && - type->size() != 0) - { - // Provide a default initializer - //printf("Providing default initializer for '%s'\n", toChars()); - if (type->ty == Tstruct && - ((TypeStruct *)type)->sym->zeroInit == 1) - { /* If a struct is all zeros, as a special case - * set it's initializer to the integer 0. - * In AssignExp::toElem(), we check for this and issue - * a memset() to initialize the struct. - * Must do same check in interpreter. - */ - Expression *e = new IntegerExp(loc, 0, Type::tint32); - Expression *e1; - e1 = new VarExp(loc, this); - e = new AssignExp(loc, e1, e); - e->type = e1->type; - init = new ExpInitializer(loc, e/*->type->defaultInit()*/); - return; - } - else if (type->ty == Ttypedef) - { TypeTypedef *td = (TypeTypedef *)type; - if (td->sym->init) - { init = td->sym->init; - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - // Make copy so we can modify it - init = new ExpInitializer(ie->loc, ie->exp); - } - else - init = getExpInitializer(); - } - else - { - init = getExpInitializer(); - } - } - - if (init) - { - sc = sc->push(); - sc->stc &= ~(STCconst | STCinvariant | STCpure); - - ArrayInitializer *ai = init->isArrayInitializer(); - if (ai && tb->ty == Taarray) - { - init = ai->toAssocArrayInitializer(); - } - - StructInitializer *si = init->isStructInitializer(); - ExpInitializer *ei = init->isExpInitializer(); - - // See if we can allocate on the stack - if (ei && isScope() && ei->exp->op == TOKnew) - { NewExp *ne = (NewExp *)ei->exp; - if (!(ne->newargs && ne->newargs->dim)) - { ne->onstack = 1; - onstack = 1; - if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) - onstack = 2; - } - } - - // If inside function, there is no semantic3() call - if (sc->func) - { - // If local variable, use AssignExp to handle all the various - // possibilities. - if (fd && !isStatic() && !isConst() && !init->isVoidInitializer()) - { - //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); - if (!ei) - { - Expression *e = init->toExpression(); - if (!e) - { - init = init->semantic(sc, type); - e = init->toExpression(); - if (!e) - { error("is not a static and cannot have static initializer"); - return; - } - } - ei = new ExpInitializer(init->loc, e); - init = ei; - } - - Expression *e1 = new VarExp(loc, this); - - Type *t = type->toBasetype(); - if (t->ty == Tsarray) - { - ei->exp = ei->exp->semantic(sc); - if (!ei->exp->implicitConvTo(type)) - { - int dim = ((TypeSArray *)t)->dim->toInteger(); - // If multidimensional static array, treat as one large array - while (1) - { - t = t->nextOf()->toBasetype(); - if (t->ty != Tsarray) - break; - dim *= ((TypeSArray *)t)->dim->toInteger(); - e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); - } - } - e1 = new SliceExp(loc, e1, NULL, NULL); - } - else if (t->ty == Tstruct) - { - ei->exp = ei->exp->semantic(sc); - if (!ei->exp->implicitConvTo(type)) - ei->exp = new CastExp(loc, ei->exp, type); - } - ei->exp = new AssignExp(loc, e1, ei->exp); - ei->exp->op = TOKconstruct; - canassign++; - ei->exp = ei->exp->semantic(sc); - canassign--; - ei->exp->optimize(WANTvalue); - } - else - { - init = init->semantic(sc, type); - if (fd && isConst() && !isStatic()) - { // Make it static - storage_class |= STCstatic; - } - } - } - else if (isConst() || isFinal()) - { - /* Because we may need the results of a const declaration in a - * subsequent type, such as an array dimension, before semantic2() - * gets ordinarily run, try to run semantic2() now. - * Ignore failure. - */ - - if (!global.errors && !inferred) - { - unsigned errors = global.errors; - global.gag++; - //printf("+gag\n"); - Expression *e; - Initializer *i2 = init; - inuse++; - if (ei) - { - e = ei->exp->syntaxCopy(); - e = e->semantic(sc); - e = e->implicitCastTo(sc, type); - } - else if (si || ai) - { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type); - } - inuse--; - global.gag--; - //printf("-gag\n"); - if (errors != global.errors) // if errors happened - { - if (global.gag == 0) - global.errors = errors; // act as if nothing happened - } - else if (ei) - { - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKint64 || e->op == TOKstring) - { - ei->exp = e; // no errors, keep result - } - } - else - init = i2; // no errors, keep result - } - } - sc = sc->pop(); - } -} - -ExpInitializer *VarDeclaration::getExpInitializer() -{ - ExpInitializer *ei; - - if (init) - ei = init->isExpInitializer(); - else - { - Expression *e = type->defaultInit(loc); - if (e) - ei = new ExpInitializer(loc, e); - else - ei = NULL; - } - return ei; -} - -void VarDeclaration::semantic2(Scope *sc) -{ - //printf("VarDeclaration::semantic2('%s')\n", toChars()); - if (init && !toParent()->isFuncDeclaration()) - { inuse++; -#if 0 - ExpInitializer *ei = init->isExpInitializer(); - if (ei) - { - ei->exp->dump(0); - printf("type = %p\n", ei->exp->type); - } -#endif - init = init->semantic(sc, type); - inuse--; - } -} - -void VarDeclaration::semantic3(Scope *sc) -{ - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - // Preserve call chain - Declaration::semantic3(sc); -} - -const char *VarDeclaration::kind() -{ - return "variable"; -} - -Dsymbol *VarDeclaration::toAlias() -{ - //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); - assert(this != aliassym); - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - StorageClassDeclaration::stcToCBuffer(buf, storage_class); - - /* If changing, be sure and fix CompoundDeclarationStatement::toCBuffer() - * too. - */ - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (init) - { buf->writestring(" = "); - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -int VarDeclaration::needThis() -{ - //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); - return storage_class & STCfield; -} - -int VarDeclaration::isImportedSymbol() -{ - if (protection == PROTexport && !init && (isStatic() || isConst() || parent->isModule())) - return TRUE; - return FALSE; -} - -void VarDeclaration::checkCtorConstInit() -{ - if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) - error("missing initializer in static constructor for const variable"); -} - -/************************************ - * Check to see if this variable is actually in an enclosing function - * rather than the current one. - */ - -void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) -{ - //printf("VarDeclaration::checkNestedReference() %s\n", toChars()); - if (parent && !isDataseg() && parent != sc->parent) - { - // The function that this variable is in - FuncDeclaration *fdv = toParent()->isFuncDeclaration(); - // The current function - FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - - if (fdv && fdthis) - { - if (loc.filename) - fdthis->getLevel(loc, fdv); - nestedref = 1; - fdv->nestedFrameRef = 1; -#if IN_LLVM -#if DMDV1 - fdv->nestedVars.insert(this); -#endif -#endif - //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); - } - } -} - -/******************************* - * Does symbol go into data segment? - * Includes extern variables. - */ - -int VarDeclaration::isDataseg() -{ -#if 0 - printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); - printf("%x, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); - printf("parent = '%s'\n", parent->toChars()); -#endif - Dsymbol *parent = this->toParent(); - if (!parent && !(storage_class & (STCstatic | STCconst))) - { error("forward referenced"); - type = Type::terror; - return 0; - } - return (storage_class & (STCstatic | STCconst) || - parent->isModule() || - parent->isTemplateInstance()); -} - -int VarDeclaration::hasPointers() -{ - return (!isDataseg() && type->hasPointers()); -} - -int VarDeclaration::isSameAsInitializer() -{ - if (init && init->isExpInitializer() && - init->isExpInitializer()->exp->op == TOKstructliteral) - return 0; - return isConst(); -} - -/****************************************** - * If a variable has an scope destructor call, return call for it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::callScopeDtor() -{ Expression *e = NULL; - - //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); - if (storage_class & STCscope && !noscope) - { - for (ClassDeclaration *cd = type->isClassHandle(); - cd; - cd = cd->baseClass) - { - /* We can do better if there's a way with onstack - * classes to determine if there's no way the monitor - * could be set. - */ - //if (cd->isInterfaceDeclaration()) - //error("interface %s cannot be scope", cd->toChars()); - if (1 || onstack || cd->dtors.dim) // if any destructors - { - // delete this; - Expression *ec; - - ec = new VarExp(loc, this); - e = new DeleteExp(loc, ec); - e->type = Type::tvoid; - break; - } - } - } - return e; -} - - -/********************************* ClassInfoDeclaration ****************************/ - -ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) - : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) -{ - this->cd = cd; - storage_class = STCstatic; -} - -Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ClassInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* ModuleInfoDeclaration ****************************/ - -ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) - : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL) -{ - this->mod = mod; - storage_class = STCstatic; -} - -Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ModuleInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* TypeInfoDeclaration ****************************/ - -TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) - : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) -{ - this->tinfo = tinfo; - storage_class = STCstatic; - protection = PROTpublic; - linkage = LINKc; -} - -Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void TypeInfoDeclaration::semantic(Scope *sc) -{ - assert(linkage == LINKc); - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; -} - -/***************************** TypeInfoConstDeclaration **********************/ - -#if DMDV2 -TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoInvariantDeclaration **********************/ - -#if DMDV2 -TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoStructDeclaration **********************/ - -TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoClassDeclaration ***********************/ - -TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoInterfaceDeclaration *******************/ - -TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTypedefDeclaration *********************/ - -TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoPointerDeclaration *********************/ - -TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoArrayDeclaration ***********************/ - -TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoStaticArrayDeclaration *****************/ - -TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoAssociativeArrayDeclaration ************/ - -TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoEnumDeclaration ***********************/ - -TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoFunctionDeclaration ********************/ - -TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoDelegateDeclaration ********************/ - -TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTupleDeclaration **********************/ - -TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/********************************* ThisDeclaration ****************************/ - -// For the "this" parameter to member functions - -ThisDeclaration::ThisDeclaration(Loc loc, Type *t) - : VarDeclaration(loc, t, Id::This, NULL) -{ - noscope = 1; -} - -Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -/********************** StaticStructInitDeclaration ***************************/ - -StaticStructInitDeclaration::StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym) - : Declaration(new Identifier("", TOKidentifier)) -{ - this->loc = loc; - this->dsym = dsym; - storage_class |= STCconst; -} - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <assert.h> + +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "mtype.h" +#include "template.h" +#include "scope.h" +#include "aggregate.h" +#include "module.h" +#include "id.h" +#include "expression.h" +#include "hdrgen.h" + +/********************************* Declaration ****************************/ + +Declaration::Declaration(Identifier *id) + : Dsymbol(id) +{ + type = NULL; + originalType = NULL; + storage_class = STCundefined; + protection = PROTundefined; + linkage = LINKdefault; + inuse = 0; +} + +void Declaration::semantic(Scope *sc) +{ +} + +const char *Declaration::kind() +{ + return "declaration"; +} + +unsigned Declaration::size(Loc loc) +{ + assert(type); + return type->size(); +} + +int Declaration::isStaticConstructor() +{ + return FALSE; +} + +int Declaration::isStaticDestructor() +{ + return FALSE; +} + +int Declaration::isDelete() +{ + return FALSE; +} + +int Declaration::isDataseg() +{ + return FALSE; +} + +int Declaration::isThreadlocal() +{ + return FALSE; +} + +int Declaration::isCodeseg() +{ + return FALSE; +} + +enum PROT Declaration::prot() +{ + return protection; +} + +/************************************* + * Check to see if declaration can be modified in this context (sc). + * Issue error if not. + */ + +#if DMDV2 +void Declaration::checkModify(Loc loc, Scope *sc, Type *t) +{ + if (sc->incontract && isParameter()) + error(loc, "cannot modify parameter '%s' in contract", toChars()); + + if (isCtorinit()) + { // It's only modifiable if inside the right constructor + Dsymbol *s = sc->func; + while (1) + { + FuncDeclaration *fd = NULL; + if (s) + fd = s->isFuncDeclaration(); + if (fd && + ((fd->isCtorDeclaration() && storage_class & STCfield) || + (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) && + fd->toParent() == toParent() + ) + { + VarDeclaration *v = isVarDeclaration(); + assert(v); + v->ctorinit = 1; + //printf("setting ctorinit\n"); + } + else + { + if (s) + { s = s->toParent2(); + continue; + } + else + { + const char *p = isStatic() ? "static " : ""; + error(loc, "can only initialize %sconst %s inside %sconstructor", + p, toChars(), p); + } + } + break; + } + } + else + { + VarDeclaration *v = isVarDeclaration(); + if (v && v->canassign == 0) + { + const char *p = NULL; + if (isConst()) + p = "const"; + else if (isInvariant()) + p = "immutable"; + else if (storage_class & STCmanifest) + p = "enum"; + else if (!t->isAssignable()) + p = "struct with immutable members"; + if (p) + { error(loc, "cannot modify %s", p); + } + } + } +} +#endif + + +/********************************* TupleDeclaration ****************************/ + +TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) + : Declaration(id) +{ + this->type = NULL; + this->objects = objects; + this->isexp = 0; + this->tupletype = NULL; +} + +Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); + return NULL; +} + +const char *TupleDeclaration::kind() +{ + return "tuple"; +} + +Type *TupleDeclaration::getType() +{ + /* If this tuple represents a type, return that type + */ + + //printf("TupleDeclaration::getType() %s\n", toChars()); + if (isexp) + return NULL; + if (!tupletype) + { + /* It's only a type tuple if all the Object's are types + */ + for (size_t i = 0; i < objects->dim; i++) + { Object *o = (Object *)objects->data[i]; + + if (o->dyncast() != DYNCAST_TYPE) + { + //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); + return NULL; + } + } + + /* We know it's a type tuple, so build the TypeTuple + */ + Arguments *args = new Arguments(); + args->setDim(objects->dim); + OutBuffer buf; + int hasdeco = 1; + for (size_t i = 0; i < objects->dim; i++) + { Type *t = (Type *)objects->data[i]; + + //printf("type = %s\n", t->toChars()); +#if 0 + buf.printf("_%s_%d", ident->toChars(), i); + char *name = (char *)buf.extractData(); + Identifier *id = new Identifier(name, TOKidentifier); + Argument *arg = new Argument(STCin, t, id, NULL); +#else + Argument *arg = new Argument(STCin, t, NULL, NULL); +#endif + args->data[i] = (void *)arg; + if (!t->deco) + hasdeco = 0; + } + + tupletype = new TypeTuple(args); + if (hasdeco) + return tupletype->semantic(0, NULL); + } + + return tupletype; +} + +int TupleDeclaration::needThis() +{ + //printf("TupleDeclaration::needThis(%s)\n", toChars()); + for (size_t i = 0; i < objects->dim; i++) + { Object *o = (Object *)objects->data[i]; + if (o->dyncast() == DYNCAST_EXPRESSION) + { Expression *e = (Expression *)o; + if (e->op == TOKdsymbol) + { DsymbolExp *ve = (DsymbolExp *)e; + Declaration *d = ve->s->isDeclaration(); + if (d && d->needThis()) + { + return 1; + } + } + } + } + return 0; +} + +/********************************* TypedefDeclaration ****************************/ + +TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) + : Declaration(id) +{ + this->type = new TypeTypedef(this); + this->basetype = basetype->toBasetype(); + this->init = init; +#ifdef _DH + this->htype = NULL; + this->hbasetype = NULL; +#endif + this->sem = 0; + this->loc = loc; +#if IN_DMD + this->sinit = NULL; +#endif +} + +Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) +{ + Type *basetype = this->basetype->syntaxCopy(); + + Initializer *init = NULL; + if (this->init) + init = this->init->syntaxCopy(); + + assert(!s); + TypedefDeclaration *st; + st = new TypedefDeclaration(loc, ident, basetype, init); +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + st->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + st->htype = htype->syntaxCopy(); + if (!hbasetype) + { if (basetype) + { hbasetype = basetype->syntaxCopy(); + st->hbasetype = basetype->syntaxCopy(); + } + } + else + st->hbasetype = hbasetype->syntaxCopy(); +#endif + return st; +} + +void TypedefDeclaration::semantic(Scope *sc) +{ + //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); + if (sem == 0) + { sem = 1; + basetype = basetype->semantic(loc, sc); + sem = 2; + type = type->semantic(loc, sc); + if (sc->parent->isFuncDeclaration() && init) + semantic2(sc); + storage_class |= sc->stc & STCdeprecated; + } + else if (sem == 1) + { + error("circular definition"); + } +} + +void TypedefDeclaration::semantic2(Scope *sc) +{ + //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); + if (sem == 2) + { sem = 3; + if (init) + { + init = init->semantic(sc, basetype); + + ExpInitializer *ie = init->isExpInitializer(); + if (ie) + { + if (ie->exp->type == basetype) + ie->exp->type = type; + } + } + } +} + +const char *TypedefDeclaration::kind() +{ + return "typedef"; +} + +Type *TypedefDeclaration::getType() +{ + return type; +} + +void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("typedef "); + basetype->toCBuffer(buf, ident, hgs); + if (init) + { + buf->writestring(" = "); + init->toCBuffer(buf, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +/********************************* AliasDeclaration ****************************/ + +AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) + : Declaration(id) +{ + //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); + //printf("type = '%s'\n", type->toChars()); + this->loc = loc; + this->type = type; + this->aliassym = NULL; +#ifdef _DH + this->htype = NULL; + this->haliassym = NULL; +#endif + this->overnext = NULL; + this->inSemantic = 0; + this->importprot = PROTundefined; + assert(type); +} + +AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) + : Declaration(id) +{ + //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); + assert(s != this); + this->loc = loc; + this->type = NULL; + this->aliassym = s; +#ifdef _DH + this->htype = NULL; + this->haliassym = NULL; +#endif + this->overnext = NULL; + this->inSemantic = 0; + assert(s); +} + +Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("AliasDeclaration::syntaxCopy()\n"); + assert(!s); + AliasDeclaration *sa; + if (type) + sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); + else + sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + sa->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + sa->htype = htype->syntaxCopy(); + if (!haliassym) + { if (aliassym) + { haliassym = aliassym->syntaxCopy(s); + sa->haliassym = aliassym->syntaxCopy(s); + } + } + else + sa->haliassym = haliassym->syntaxCopy(s); +#endif + return sa; +} + +void AliasDeclaration::semantic(Scope *sc) +{ + //printf("AliasDeclaration::semantic() %s\n", toChars()); + if (aliassym) + { + if (aliassym->isTemplateInstance()) + aliassym->semantic(sc); + return; + } + this->inSemantic = 1; + + if (storage_class & STCconst) + error("cannot be const"); + + storage_class |= sc->stc & STCdeprecated; + + // Given: + // alias foo.bar.abc def; + // it is not knowable from the syntax whether this is an alias + // for a type or an alias for a symbol. It is up to the semantic() + // pass to distinguish. + // If it is a type, then type is set and getType() will return that + // type. If it is a symbol, then aliassym is set and type is NULL - + // toAlias() will return aliasssym. + + Dsymbol *s; + Type *t; + Expression *e; + + /* This section is needed because resolve() will: + * const x = 3; + * alias x y; + * try to alias y to 3. + */ + s = type->toDsymbol(sc); + if (s +#if DMDV2 +` && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) +#endif + ) + goto L2; // it's a symbolic alias + +#if DMDV2 + if (storage_class & (STCref | STCnothrow | STCpure)) + { // For 'ref' to be attached to function types, and picked + // up by Type::resolve(), it has to go into sc. + sc = sc->push(); + sc->stc |= storage_class & (STCref | STCnothrow | STCpure); + type->resolve(loc, sc, &e, &t, &s); + sc = sc->pop(); + } + else +#endif + type->resolve(loc, sc, &e, &t, &s); + if (s) + { + goto L2; + } + else if (e) + { + // Try to convert Expression to Dsymbol + if (e->op == TOKvar) + { s = ((VarExp *)e)->var; + goto L2; + } + else if (e->op == TOKfunction) + { s = ((FuncExp *)e)->fd; + goto L2; + } + else + { error("cannot alias an expression %s", e->toChars()); + t = e->type; + } + } + else if (t) + { + type = t; + } + if (overnext) + ScopeDsymbol::multiplyDefined(0, this, overnext); + this->inSemantic = 0; + return; + + L2: + //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); + type = NULL; + VarDeclaration *v = s->isVarDeclaration(); + if (v && v->linkage == LINKdefault) + { + error("forward reference of %s", v->toChars()); + s = NULL; + } + else + { + FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); + if (f) + { + if (overnext) + { + FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); + fa->importprot = importprot; + if (!fa->overloadInsert(overnext)) + ScopeDsymbol::multiplyDefined(0, f, overnext); + overnext = NULL; + s = fa; + s->parent = sc->parent; + } + } + if (overnext) + ScopeDsymbol::multiplyDefined(0, s, overnext); + if (s == this) + { + assert(global.errors); + s = NULL; + } + } + if (!aliassym) + aliassym = s; + this->inSemantic = 0; +} + +int AliasDeclaration::overloadInsert(Dsymbol *s) +{ + /* Don't know yet what the aliased symbol is, so assume it can + * be overloaded and check later for correctness. + */ + + //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); + if (overnext == NULL) + { + if (s == this) + { + return TRUE; + } + overnext = s; + return TRUE; + } + else + { + return overnext->overloadInsert(s); + } +} + +const char *AliasDeclaration::kind() +{ + return "alias"; +} + +Type *AliasDeclaration::getType() +{ + //printf("AliasDeclaration::getType() %s\n", type->toChars()); +#if 0 + if (!type->deco && scope) + semantic(scope); + if (type && !type->deco) + error("forward reference to alias %s\n", toChars()); +#endif + return type; +} + +Dsymbol *AliasDeclaration::toAlias() +{ + //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); + assert(this != aliassym); + //static int count; if (++count == 75) exit(0); //*(char*)0=0; + if (inSemantic) + { error("recursive alias declaration"); + aliassym = new TypedefDeclaration(loc, ident, Type::terror, NULL); + } + Dsymbol *s = aliassym ? aliassym->toAlias() : this; + return s; +} + +void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("alias "); +#if 0 && _DH + if (hgs->hdrgen) + { + if (haliassym) + { + buf->writestring(haliassym->toChars()); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + } + else + htype->toCBuffer(buf, ident, hgs); + } + else +#endif + { + if (aliassym) + { + buf->writestring(aliassym->toChars()); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + } + else + type->toCBuffer(buf, ident, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +/********************************* VarDeclaration ****************************/ + +VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) + : Declaration(id) +{ + //printf("VarDeclaration('%s')\n", id->toChars()); +#ifdef DEBUG + if (!type && !init) + { printf("VarDeclaration('%s')\n", id->toChars()); + //*(char*)0=0; + } +#endif + assert(type || init); + this->type = type; + this->init = init; +#ifdef _DH + this->htype = NULL; + this->hinit = NULL; +#endif + this->loc = loc; + offset = 0; + noscope = 0; +#if DMDV1 + nestedref = 0; +#endif + ctorinit = 0; + aliassym = NULL; + onstack = 0; + canassign = 0; + value = NULL; + +#if IN_LLVM + aggrIndex = 0; + + // LDC + anonDecl = NULL; + offset2 = 0; + + nakedUse = false; + + availableExternally = true; // assume this unless proven otherwise +#endif +} + +Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); + + VarDeclaration *sv; + if (s) + { sv = (VarDeclaration *)s; + } + else + { + Initializer *init = NULL; + if (this->init) + { init = this->init->syntaxCopy(); + //init->isExpInitializer()->exp->print(); + //init->isExpInitializer()->exp->dump(0); + } + + sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); + sv->storage_class = storage_class; + } +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + sv->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + sv->htype = htype->syntaxCopy(); + if (!hinit) + { if (init) + { hinit = init->syntaxCopy(); + sv->hinit = init->syntaxCopy(); + } + } + else + sv->hinit = hinit->syntaxCopy(); +#endif + return sv; +} + +void VarDeclaration::semantic(Scope *sc) +{ +#if 0 + printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); + printf(" type = %s\n", type ? type->toChars() : "null"); + printf(" stc = x%x\n", sc->stc); + printf(" storage_class = x%x\n", storage_class); + printf("linkage = %d\n", sc->linkage); + //if (strcmp(toChars(), "mul") == 0) halt(); +#endif + + storage_class |= sc->stc; + if (storage_class & STCextern && init) + error("extern symbols cannot have initializers"); + + /* If auto type inference, do the inference + */ + int inferred = 0; + if (!type) + { inuse++; + type = init->inferType(sc); + inuse--; + inferred = 1; + + /* This is a kludge to support the existing syntax for RAII + * declarations. + */ + storage_class &= ~STCauto; + originalType = type; + } + else + { if (!originalType) + originalType = type; + type = type->semantic(loc, sc); + } + //printf(" semantic type = %s\n", type ? type->toChars() : "null"); + + type->checkDeprecated(loc, sc); + linkage = sc->linkage; + this->parent = sc->parent; + //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); + protection = sc->protection; + //printf("sc->stc = %x\n", sc->stc); + //printf("storage_class = x%x\n", storage_class); + +#if DMDV2 + if (storage_class & STCgshared && global.params.safe && !sc->module->safe) + { + error("__gshared not allowed in safe mode; use shared"); + } +#endif + + Dsymbol *parent = toParent(); + FuncDeclaration *fd = parent->isFuncDeclaration(); + + Type *tb = type->toBasetype(); + if (tb->ty == Tvoid && !(storage_class & STClazy)) + { error("voids have no value"); + type = Type::terror; + tb = type; + } + if (tb->ty == Tfunction) + { error("cannot be declared to be a function"); + type = Type::terror; + tb = type; + } + if (tb->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tb; + + if (!ts->sym->members) + { + error("no definition of struct %s", ts->toChars()); + } + } + if ((storage_class & STCauto) && !inferred) + error("both auto and explicit type given"); + + if (tb->ty == Ttuple) + { /* Instead, declare variables for each of the tuple elements + * and add those. + */ + TypeTuple *tt = (TypeTuple *)tb; + size_t nelems = Argument::dim(tt->arguments); + Objects *exps = new Objects(); + exps->setDim(nelems); + Expression *ie = init ? init->toExpression() : NULL; + + for (size_t i = 0; i < nelems; i++) + { Argument *arg = Argument::getNth(tt->arguments, i); + + OutBuffer buf; + buf.printf("_%s_field_%zu", ident->toChars(), i); + buf.writeByte(0); + char *name = (char *)buf.extractData(); + Identifier *id = new Identifier(name, TOKidentifier); + + Expression *einit = ie; + if (ie && ie->op == TOKtuple) + { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; + } + Initializer *ti = init; + if (einit) + { ti = new ExpInitializer(einit->loc, einit); + } + + VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); + //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); + v->semantic(sc); + +/* +// removed for LDC since TupleDeclaration::toObj already creates the fields; +// adding them to the scope again leads to duplicates + if (sc->scopesym) + { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); + if (sc->scopesym->members) + sc->scopesym->members->push(v); + } +*/ + Expression *e = new DsymbolExp(loc, v); + exps->data[i] = e; + } + TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); + v2->isexp = 1; + aliassym = v2; + return; + } + + if (storage_class & STCconst && !init && !fd) + // Initialize by constructor only + storage_class = (storage_class & ~STCconst) | STCctorinit; + + if (isConst()) + { + } + else if (isStatic()) + { + } + else if (isSynchronized()) + { + error("variable %s cannot be synchronized", toChars()); + } + else if (isOverride()) + { + error("override cannot be applied to variable"); + } + else if (isAbstract()) + { + error("abstract cannot be applied to variable"); + } + else if (storage_class & STCtemplateparameter) + { + } + else + { + AggregateDeclaration *aad = sc->anonAgg; + if (!aad) + aad = parent->isAggregateDeclaration(); + if (aad) + { +#if DMDV2 + assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); + + if (storage_class & (STCconst | STCimmutable) && init) + { + if (!type->toBasetype()->isTypeBasic()) + storage_class |= STCstatic; + } + else +#endif + aad->addField(sc, this); + } + + InterfaceDeclaration *id = parent->isInterfaceDeclaration(); + if (id) + { + error("field not allowed in interface"); + } + + /* Templates cannot add fields to aggregates + */ + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + AggregateDeclaration *ad = ti->tempdecl->isMember(); + if (ad && storage_class != STCundefined) + { + error("cannot use template to add field to aggregate '%s'", ad->toChars()); + } + } + } + +#if DMDV2 + if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref && + ident != Id::This) + { + error("only parameters or foreach declarations can be ref"); + } +#endif + + if (type->isscope() && !noscope) + { + if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd) + { + error("globals, statics, fields, ref and out parameters cannot be scope"); + } + + if (!(storage_class & STCscope)) + { + if (!(storage_class & STCparameter) && ident != Id::withSym) + error("reference to scope class must be scope"); + } + } + + enum TOK op = TOKconstruct; + if (!init && !sc->inunion && !isStatic() && !isConst() && fd && + !(storage_class & (STCfield | STCin | STCforeach)) && + type->size() != 0) + { + // Provide a default initializer + //printf("Providing default initializer for '%s'\n", toChars()); + if (type->ty == Tstruct && + ((TypeStruct *)type)->sym->zeroInit == 1) + { /* If a struct is all zeros, as a special case + * set it's initializer to the integer 0. + * In AssignExp::toElem(), we check for this and issue + * a memset() to initialize the struct. + * Must do same check in interpreter. + */ + Expression *e = new IntegerExp(loc, 0, Type::tint32); + Expression *e1; + e1 = new VarExp(loc, this); + e = new AssignExp(loc, e1, e); + e->op = TOKconstruct; + e->type = e1->type; // don't type check this, it would fail + init = new ExpInitializer(loc, e); + return; + } + else if (type->ty == Ttypedef) + { TypeTypedef *td = (TypeTypedef *)type; + if (td->sym->init) + { init = td->sym->init; + ExpInitializer *ie = init->isExpInitializer(); + if (ie) + // Make copy so we can modify it + init = new ExpInitializer(ie->loc, ie->exp); + } + else + init = getExpInitializer(); + } + else + { + init = getExpInitializer(); + } + // Default initializer is always a blit + op = TOKblit; + } + + if (init) + { + sc = sc->push(); + sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref); + + ArrayInitializer *ai = init->isArrayInitializer(); + if (ai && tb->ty == Taarray) + { + init = ai->toAssocArrayInitializer(); + } + + StructInitializer *si = init->isStructInitializer(); + ExpInitializer *ei = init->isExpInitializer(); + + // See if initializer is a NewExp that can be allocated on the stack + if (ei && isScope() && ei->exp->op == TOKnew) + { NewExp *ne = (NewExp *)ei->exp; + if (!(ne->newargs && ne->newargs->dim)) + { ne->onstack = 1; + onstack = 1; + if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) + onstack = 2; + } + } + + // If inside function, there is no semantic3() call + if (sc->func) + { + // If local variable, use AssignExp to handle all the various + // possibilities. + if (fd && !isStatic() && !isConst() && !init->isVoidInitializer()) + { + //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); + if (!ei) + { + Expression *e = init->toExpression(); + if (!e) + { + init = init->semantic(sc, type); + e = init->toExpression(); + if (!e) + { error("is not a static and cannot have static initializer"); + return; + } + } + ei = new ExpInitializer(init->loc, e); + init = ei; + } + + Expression *e1 = new VarExp(loc, this); + + Type *t = type->toBasetype(); + if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) + { + ei->exp = ei->exp->semantic(sc); + if (!ei->exp->implicitConvTo(type)) + { + int dim = ((TypeSArray *)t)->dim->toInteger(); + // If multidimensional static array, treat as one large array + while (1) + { + t = t->nextOf()->toBasetype(); + if (t->ty != Tsarray) + break; + dim *= ((TypeSArray *)t)->dim->toInteger(); + e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); + } + } + e1 = new SliceExp(loc, e1, NULL, NULL); + } + else if (t->ty == Tstruct) + { + ei->exp = ei->exp->semantic(sc); + ei->exp = resolveProperties(sc, ei->exp); + StructDeclaration *sd = ((TypeStruct *)t)->sym; +#if DMDV2 + /* Look to see if initializer is a call to the constructor + */ + if (sd->ctor && // there are constructors + ei->exp->type->ty == Tstruct && // rvalue is the same struct + ((TypeStruct *)ei->exp->type)->sym == sd && + ei->exp->op == TOKstar) + { + /* Look for form of constructor call which is: + * *__ctmp.ctor(arguments...) + */ + PtrExp *pe = (PtrExp *)ei->exp; + if (pe->e1->op == TOKcall) + { CallExp *ce = (CallExp *)pe->e1; + if (ce->e1->op == TOKdotvar) + { DotVarExp *dve = (DotVarExp *)ce->e1; + if (dve->var->isCtorDeclaration()) + { /* It's a constructor call, currently constructing + * a temporary __ctmp. + */ + /* Before calling the constructor, initialize + * variable with a bit copy of the default + * initializer + */ + Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); + e->op = TOKblit; + e->type = t; + ei->exp = new CommaExp(loc, e, ei->exp); + + /* Replace __ctmp being constructed with e1 + */ + dve->e1 = e1; + return; + } + } + } + } +#endif + if (!ei->exp->implicitConvTo(type)) + { + /* Look for opCall + * See bugzilla 2702 for more discussion + */ + Type *ti = ei->exp->type->toBasetype(); + // Don't cast away invariant or mutability in initializer + if (search_function(sd, Id::call) && + /* Initializing with the same type is done differently + */ + !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) + { // Rewrite as e1.call(arguments) + Expression * eCall = new DotIdExp(loc, e1, Id::call); + ei->exp = new CallExp(loc, eCall, ei->exp); + } + } + } + ei->exp = new AssignExp(loc, e1, ei->exp); + ei->exp->op = TOKconstruct; + canassign++; + ei->exp = ei->exp->semantic(sc); + canassign--; + ei->exp->optimize(WANTvalue); + } + else + { + init = init->semantic(sc, type); + if (fd && isConst() && !isStatic()) + { // Make it static + storage_class |= STCstatic; + } + } + } + else if (isConst() || isFinal() || + parent->isAggregateDeclaration()) + { + /* Because we may need the results of a const declaration in a + * subsequent type, such as an array dimension, before semantic2() + * gets ordinarily run, try to run semantic2() now. + * Ignore failure. + */ + + if (!global.errors && !inferred) + { + unsigned errors = global.errors; + global.gag++; + //printf("+gag\n"); + Expression *e; + Initializer *i2 = init; + inuse++; + if (ei) + { + e = ei->exp->syntaxCopy(); + e = e->semantic(sc); + e = e->implicitCastTo(sc, type); + } + else if (si || ai) + { i2 = init->syntaxCopy(); + i2 = i2->semantic(sc, type); + } + inuse--; + global.gag--; + //printf("-gag\n"); + if (errors != global.errors) // if errors happened + { + if (global.gag == 0) + global.errors = errors; // act as if nothing happened +#if DMDV2 + /* Save scope for later use, to try again + */ + scope = new Scope(*sc); + scope->setNoFree(); +#endif + } + else if (ei) + { + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKint64 || e->op == TOKstring || e->op == TOKfloat64) + { + ei->exp = e; // no errors, keep result + } +#if DMDV2 + else + { + /* Save scope for later use, to try again + */ + scope = new Scope(*sc); + scope->setNoFree(); + } +#endif + } + else + init = i2; // no errors, keep result + } + } + sc = sc->pop(); + } +} + +ExpInitializer *VarDeclaration::getExpInitializer() +{ + ExpInitializer *ei; + + if (init) + ei = init->isExpInitializer(); + else + { + Expression *e = type->defaultInit(loc); + if (e) + ei = new ExpInitializer(loc, e); + else + ei = NULL; + } + return ei; +} + +void VarDeclaration::semantic2(Scope *sc) +{ + //printf("VarDeclaration::semantic2('%s')\n", toChars()); + if (init && !toParent()->isFuncDeclaration()) + { inuse++; +#if 0 + ExpInitializer *ei = init->isExpInitializer(); + if (ei) + { + ei->exp->dump(0); + printf("type = %p\n", ei->exp->type); + } +#endif + init = init->semantic(sc, type); + inuse--; + } +} + +void VarDeclaration::semantic3(Scope *sc) +{ + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; + + // Preserve call chain + Declaration::semantic3(sc); +} + +const char *VarDeclaration::kind() +{ + return "variable"; +} + +Dsymbol *VarDeclaration::toAlias() +{ + //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); + assert(this != aliassym); + Dsymbol *s = aliassym ? aliassym->toAlias() : this; + return s; +} + +void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + StorageClassDeclaration::stcToCBuffer(buf, storage_class); + + /* If changing, be sure and fix CompoundDeclarationStatement::toCBuffer() + * too. + */ + if (type) + type->toCBuffer(buf, ident, hgs); + else + buf->writestring(ident->toChars()); + if (init) + { buf->writestring(" = "); +#if DMDV2 + ExpInitializer *ie = init->isExpInitializer(); + if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) + ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); + else +#endif + init->toCBuffer(buf, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +int VarDeclaration::needThis() +{ + //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); + return storage_class & STCfield; +} + +int VarDeclaration::isImportedSymbol() +{ + if (protection == PROTexport && !init && (isStatic() || isConst() || parent->isModule())) + return TRUE; + return FALSE; +} + +void VarDeclaration::checkCtorConstInit() +{ + if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) + error("missing initializer in static constructor for const variable"); +} + +/************************************ + * Check to see if this variable is actually in an enclosing function + * rather than the current one. + */ + +void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) +{ + //printf("VarDeclaration::checkNestedReference() %s\n", toChars()); + if (parent && !isDataseg() && parent != sc->parent) + { + // The function that this variable is in + FuncDeclaration *fdv = toParent()->isFuncDeclaration(); + // The current function + FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); + + if (fdv && fdthis) + { + if (loc.filename) + fdthis->getLevel(loc, fdv); + nestedref = 1; + fdv->nestedFrameRef = 1; +#if IN_LLVM +#if DMDV1 + fdv->nestedVars.insert(this); +#endif +#endif + //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); + } + } +} + +/******************************* + * Does symbol go into data segment? + * Includes extern variables. + */ + +int VarDeclaration::isDataseg() +{ +#if 0 + printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); + printf("%x, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); + printf("parent = '%s'\n", parent->toChars()); +#endif + Dsymbol *parent = this->toParent(); + if (!parent && !(storage_class & (STCstatic | STCconst))) + { error("forward referenced"); + type = Type::terror; + return 0; + } + return (storage_class & (STCstatic | STCconst) || + parent->isModule() || + parent->isTemplateInstance()); +} + +/************************************ + * Does symbol go into thread local storage? + */ + +int VarDeclaration::isThreadlocal() +{ + return 0; +} + +int VarDeclaration::hasPointers() +{ + //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); + return (!isDataseg() && type->hasPointers()); +} + +int VarDeclaration::isSameAsInitializer() +{ + if (init && init->isExpInitializer() && + init->isExpInitializer()->exp->op == TOKstructliteral) + return 0; + return isConst(); +} + +/****************************************** + * If a variable has an scope destructor call, return call for it. + * Otherwise, return NULL. + */ + +Expression *VarDeclaration::callScopeDtor(Scope *sc) +{ Expression *e = NULL; + + //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); + if (storage_class & STCscope && !noscope) + { + for (ClassDeclaration *cd = type->isClassHandle(); + cd; + cd = cd->baseClass) + { + /* We can do better if there's a way with onstack + * classes to determine if there's no way the monitor + * could be set. + */ + //if (cd->isInterfaceDeclaration()) + //error("interface %s cannot be scope", cd->toChars()); + if (1 || onstack || cd->dtors.dim) // if any destructors + { + // delete this; + Expression *ec; + + ec = new VarExp(loc, this); + e = new DeleteExp(loc, ec); + e->type = Type::tvoid; + break; + } + } + } + return e; +} + + +/********************************* ClassInfoDeclaration ****************************/ + +ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) + : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) +{ + this->cd = cd; + storage_class = STCstatic; +} + +Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +void ClassInfoDeclaration::semantic(Scope *sc) +{ +} + +/********************************* ModuleInfoDeclaration ****************************/ + +ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) + : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL) +{ + this->mod = mod; + storage_class = STCstatic; +} + +Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +void ModuleInfoDeclaration::semantic(Scope *sc) +{ +} + +/********************************* TypeInfoDeclaration ****************************/ + +TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) + : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) +{ + this->tinfo = tinfo; + storage_class = STCstatic; + protection = PROTpublic; + linkage = LINKc; +} + +Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +void TypeInfoDeclaration::semantic(Scope *sc) +{ + assert(linkage == LINKc); + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; +} + +/***************************** TypeInfoConstDeclaration **********************/ + +#if DMDV2 +TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} +#endif + +/***************************** TypeInfoInvariantDeclaration **********************/ + +#if DMDV2 +TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} +#endif + +/***************************** TypeInfoSharedDeclaration **********************/ + +#if DMDV2 +TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} +#endif + +/***************************** TypeInfoStructDeclaration **********************/ + +TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoClassDeclaration ***********************/ + +TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoInterfaceDeclaration *******************/ + +TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoTypedefDeclaration *********************/ + +TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoPointerDeclaration *********************/ + +TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoArrayDeclaration ***********************/ + +TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoStaticArrayDeclaration *****************/ + +TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoAssociativeArrayDeclaration ************/ + +TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoEnumDeclaration ***********************/ + +TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoFunctionDeclaration ********************/ + +TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoDelegateDeclaration ********************/ + +TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/***************************** TypeInfoTupleDeclaration **********************/ + +TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ +} + +/********************************* ThisDeclaration ****************************/ + +// For the "this" parameter to member functions + +ThisDeclaration::ThisDeclaration(Loc loc, Type *t) + : VarDeclaration(loc, t, Id::This, NULL) +{ + noscope = 1; +} + +Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +/********************** StaticStructInitDeclaration ***************************/ + +StaticStructInitDeclaration::StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym) + : Declaration(new Identifier("", TOKidentifier)) +{ + this->loc = loc; + this->dsym = dsym; + storage_class |= STCconst; +}
--- a/dmd/declaration.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/declaration.h Fri Nov 06 23:58:01 2009 +0100 @@ -1,951 +1,1004 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DECLARATION_H -#define DMD_DECLARATION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include <set> -#include <map> -#include <string> - -#include "dsymbol.h" -#include "lexer.h" -#include "mtype.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -struct LabelStatement; -struct Initializer; -struct Module; -struct InlineScanState; -struct ForeachStatement; -struct FuncDeclaration; -struct ExpInitializer; -struct StructDeclaration; -struct TupleType; -struct InterState; -struct IRState; -struct AnonDeclaration; - -enum PROT; -enum LINK; -enum TOK; -enum MATCH; - -enum STC -{ - STCundefined = 0, - STCstatic = 1, - STCextern = 2, - STCconst = 4, - STCfinal = 8, - STCabstract = 0x10, - STCparameter = 0x20, - STCfield = 0x40, - STCoverride = 0x80, - STCauto = 0x100, - STCsynchronized = 0x200, - STCdeprecated = 0x400, - STCin = 0x800, // in parameter - STCout = 0x1000, // out parameter - STClazy = 0x2000, // lazy parameter - STCforeach = 0x4000, // variable for foreach loop - STCcomdat = 0x8000, // should go into COMDAT record - STCvariadic = 0x10000, // variadic function argument - STCctorinit = 0x20000, // can only be set inside constructor - STCtemplateparameter = 0x40000, // template parameter - STCscope = 0x80000, // template parameter - STCinvariant = 0x100000, - STCimmutable = 0x100000, - STCref = 0x200000, - STCinit = 0x400000, // has explicit initializer - STCmanifest = 0x800000, // manifest constant - STCnodtor = 0x1000000, // don't run destructor - STCnothrow = 0x2000000, // never throws exceptions - STCpure = 0x4000000, // pure function - STCtls = 0x8000000, // thread local - STCalias = 0x10000000, // alias parameter - STCshared = 0x20000000, // accessible from multiple threads - STCgshared = 0x40000000, // accessible from multiple threads - // but not typed as "shared" - STC_TYPECTOR = (STCconst | STCimmutable | STCshared), -}; - -struct Match -{ - int count; // number of matches found - MATCH last; // match level of lastf - FuncDeclaration *lastf; // last matching function we found - FuncDeclaration *nextf; // current matching function - FuncDeclaration *anyf; // pick a func, any func, to use for error recovery -}; - -void overloadResolveX(Match *m, FuncDeclaration *f, Expressions *arguments, Module* from); -int overloadApply(Module* from, FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param); - -/**************************************************************/ - -struct Declaration : Dsymbol -{ - Type *type; - Type *originalType; // before semantic analysis - unsigned storage_class; - enum PROT protection; - enum LINK linkage; - int inuse; // used to detect cycles - - Declaration(Identifier *id); - void semantic(Scope *sc); - const char *kind(); - unsigned size(Loc loc); - void checkModify(Loc loc, Scope *sc, Type *t); - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - char *mangle(); - int isStatic() { return storage_class & STCstatic; } - virtual int isStaticConstructor(); - virtual int isStaticDestructor(); - virtual int isDelete(); - virtual int isDataseg(); - virtual int isCodeseg(); - int isCtorinit() { return storage_class & STCctorinit; } - int isFinal() { return storage_class & STCfinal; } - int isAbstract() { return storage_class & STCabstract; } - int isConst() { return storage_class & STCconst; } - int isInvariant() { return 0; } - int isAuto() { return storage_class & STCauto; } - int isScope() { return storage_class & STCscope; } - int isSynchronized() { return storage_class & STCsynchronized; } - int isParameter() { return storage_class & STCparameter; } - int isDeprecated() { return storage_class & STCdeprecated; } - int isOverride() { return storage_class & STCoverride; } - - virtual int isSameAsInitializer() { return isConst(); }; - - int isIn() { return storage_class & STCin; } - int isOut() { return storage_class & STCout; } - int isRef() { return storage_class & STCref; } - - enum PROT prot(); - - Declaration *isDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TupleDeclaration : Declaration -{ - Objects *objects; - int isexp; // 1: expression tuple - - TypeTuple *tupletype; // !=NULL if this is a type tuple - - TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); - Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); - Type *getType(); - int needThis(); - - TupleDeclaration *isTupleDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TypedefDeclaration : Declaration -{ - Type *basetype; - Initializer *init; - int sem; // 0: semantic() has not been run - // 1: semantic() is in progress - // 2: semantic() has been run - // 3: semantic2() has been run - - TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - char *mangle(); - const char *kind(); - Type *getType(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Type *hbasetype; -#endif - - void toDocBuffer(OutBuffer *buf); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); -#endif - - TypedefDeclaration *isTypedefDeclaration() { return this; } - -#if IN_DMD - Symbol *sinit; - Symbol *toInitializer(); -#endif - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct AliasDeclaration : Declaration -{ - Dsymbol *aliassym; - Dsymbol *overnext; // next in overload list - int inSemantic; - PROT importprot; // if generated by import, store its protection - - AliasDeclaration(Loc loc, Identifier *ident, Type *type); - AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); - const char *kind(); - Type *getType(); - Dsymbol *toAlias(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Dsymbol *haliassym; -#endif - - void toDocBuffer(OutBuffer *buf); - - AliasDeclaration *isAliasDeclaration() { return this; } -}; - -/**************************************************************/ - -struct VarDeclaration : Declaration -{ - Initializer *init; - unsigned offset; - int noscope; // no scope semantics - int nestedref; // referenced by a lexically nested function - int ctorinit; // it has been initialized in a ctor - int onstack; // 1: it has been allocated on the stack - // 2: on stack, run destructor anyway - int canassign; // it can be assigned to - Dsymbol *aliassym; // if redone as alias to another symbol - Expression *value; // when interpreting, this is the value - // (NULL if value not determinable) - Scope *scope; // !=NULL means context to use - - VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Initializer *hinit; -#endif - int needThis(); - int isImportedSymbol(); - int isDataseg(); - int hasPointers(); - Expression *callScopeDtor(); - ExpInitializer *getExpInitializer(); - void checkCtorConstInit(); - void checkNestedReference(Scope *sc, Loc loc); - Dsymbol *toAlias(); - - virtual int isSameAsInitializer(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); - int cvMember(unsigned char *p); -#endif - - // Eliminate need for dynamic_cast - VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); - - /// Index into parent aggregate. - /// Set during type generation. - unsigned aggrIndex; - - /// Variables that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; - /// Override added to set above flag. - void semantic3(Scope *sc); - - // FIXME: we're not using these anymore! - AnonDeclaration* anonDecl; - unsigned offset2; - - /// This var is used by a naked function. - bool nakedUse; -#endif -}; - -/**************************************************************/ - -// LDC uses this to denote static struct initializers - -struct StaticStructInitDeclaration : Declaration -{ - StructDeclaration *dsym; - - StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym); - -#if IN_DMD - Symbol *toSymbol(); -#endif - - // Eliminate need for dynamic_cast - StaticStructInitDeclaration *isStaticStructInitDeclaration() { return (StaticStructInitDeclaration *)this; } -}; - -struct ClassInfoDeclaration : VarDeclaration -{ - ClassDeclaration *cd; - - ClassInfoDeclaration(ClassDeclaration *cd); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - -#if IN_DMD - Symbol *toSymbol(); -#endif - - ClassInfoDeclaration* isClassInfoDeclaration() { return this; } -}; - -struct ModuleInfoDeclaration : VarDeclaration -{ - Module *mod; - - ModuleInfoDeclaration(Module *mod); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct TypeInfoDeclaration : VarDeclaration -{ - Type *tinfo; - - TypeInfoDeclaration(Type *tinfo, int internal); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); - virtual void toDt(dt_t **pdt); -#endif - - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); - virtual void llvmDefine(); -#endif -}; - -struct TypeInfoStructDeclaration : TypeInfoDeclaration -{ - TypeInfoStructDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoClassDeclaration : TypeInfoDeclaration -{ - TypeInfoClassDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration -{ - TypeInfoInterfaceDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTypedefDeclaration : TypeInfoDeclaration -{ - TypeInfoTypedefDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoPointerDeclaration : TypeInfoDeclaration -{ - TypeInfoPointerDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoStaticArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoAssociativeArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoEnumDeclaration : TypeInfoDeclaration -{ - TypeInfoEnumDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoFunctionDeclaration : TypeInfoDeclaration -{ - TypeInfoFunctionDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoDelegateDeclaration : TypeInfoDeclaration -{ - TypeInfoDelegateDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTupleDeclaration : TypeInfoDeclaration -{ - TypeInfoTupleDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -#if DMDV2 -struct TypeInfoConstDeclaration : TypeInfoDeclaration -{ - TypeInfoConstDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoInvariantDeclaration : TypeInfoDeclaration -{ - TypeInfoInvariantDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoSharedDeclaration : TypeInfoDeclaration -{ - TypeInfoSharedDeclaration(Type *tinfo); - - void toDt(dt_t **pdt); -}; -#endif - -/**************************************************************/ - -struct ThisDeclaration : VarDeclaration -{ - ThisDeclaration(Loc loc, Type *t); - Dsymbol *syntaxCopy(Dsymbol *); - ThisDeclaration *isThisDeclaration() { return this; } -}; - -enum ILS -{ - ILSuninitialized, // not computed yet - ILSno, // cannot inline - ILSyes, // can inline -}; - -/**************************************************************/ -#if DMDV2 - -enum BUILTIN -{ - BUILTINunknown = -1, // not known if this is a builtin - BUILTINnot, // this is not a builtin - BUILTINsin, // std.math.sin - BUILTINcos, // std.math.cos - BUILTINtan, // std.math.tan - BUILTINsqrt, // std.math.sqrt - BUILTINfabs, // std.math.fabs -}; - -Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments); - -#endif - -struct FuncDeclaration : Declaration -{ - Array *fthrows; // Array of Type's of exceptions (not used) - Statement *frequire; - Statement *fensure; - Statement *fbody; - - Identifier *outId; // identifier for out statement - VarDeclaration *vresult; // variable corresponding to outId - LabelDsymbol *returnLabel; // where the return goes - - DsymbolTable *localsymtab; // used to prevent symbols in different - // scopes from having the same name - VarDeclaration *vthis; // 'this' parameter (member and nested) - VarDeclaration *v_arguments; // '_arguments' parameter -#if IN_GCC - VarDeclaration *v_argptr; // '_argptr' variable -#endif - Dsymbols *parameters; // Array of VarDeclaration's for parameters - DsymbolTable *labtab; // statement label symbol table - Declaration *overnext; // next in overload list - Loc endloc; // location of closing curly bracket - int vtblIndex; // for member functions, index into vtbl[] - int naked; // !=0 if naked - int inlineAsm; // !=0 if has inline assembler - ILS inlineStatus; - int inlineNest; // !=0 if nested inline - int cantInterpret; // !=0 if cannot interpret function - int semanticRun; // 1 semantic() run - // 2 semantic2() run - // 3 semantic3() started - // 4 semantic3() done - // 5 toObjFile() run - // this function's frame ptr - ForeachStatement *fes; // if foreach body, this is the foreach - int introducing; // !=0 if 'introducing' function - Type *tintro; // if !=NULL, then this is the type - // of the 'introducing' function - // this one is overriding - int inferRetType; // !=0 if return type is to be inferred - Scope *scope; // !=NULL means context to use - - // Things that should really go into Scope - int hasReturnExp; // 1 if there's a return exp; statement - // 2 if there's a throw statement - // 4 if there's an assert(0) - // 8 if there's inline asm - - // Support for NRVO (named return value optimization) - int nrvo_can; // !=0 means we can do it - VarDeclaration *nrvo_var; // variable to replace with shidden -#if IN_DMD - Symbol *shidden; // hidden pointer passed to function -#endif - -#if DMDV2 - enum BUILTIN builtin; // set if this is a known, builtin - // function we can evaluate at compile - // time - - int tookAddressOf; // set if someone took the address of - // this function - Dsymbols closureVars; // local variables in this function - // which are referenced by nested - // functions -#else - int nestedFrameRef; // !=0 if nested variables referenced -#endif - - FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); - int overrides(FuncDeclaration *fd); - int findVtblIndex(Array *vtbl, int dim); - int overloadInsert(Dsymbol *s); - FuncDeclaration *overloadExactMatch(Type *t, Module* from); - FuncDeclaration *overloadResolve(Loc loc, Expressions *arguments, Module* from); - LabelDsymbol *searchLabel(Identifier *ident); - AggregateDeclaration *isThis(); - AggregateDeclaration *isMember2(); - int getLevel(Loc loc, FuncDeclaration *fd); // lexical nesting level difference - void appendExp(Expression *e); - void appendState(Statement *s); - char *mangle(); - int isMain(); - int isWinMain(); - int isDllMain(); - int isExport(); - int isImportedSymbol(); - int isAbstract(); - int isCodeseg(); - virtual int isNested(); - int needThis(); - virtual int isVirtual(); - virtual int isFinal(); - virtual int addPreInvariant(); - virtual int addPostInvariant(); - Expression *interpret(InterState *istate, Expressions *arguments); - void inlineScan(); - int canInline(int hasthis, int hdrscan = 0); - Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); - const char *kind(); - void toDocBuffer(OutBuffer *buf); - -// LDC: give argument types to runtime functions - static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, const char *name); - static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, Identifier *id); - -#if IN_DMD - Symbol *toSymbol(); - Symbol *toThunkSymbol(int offset); // thunk version - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); -#endif - - FuncDeclaration *isFuncDeclaration() { return this; } - -#if IN_LLVM - // LDC stuff - - /// Codegen traversal - void codegen(Ir* ir); - - // vars declared in this function that nested funcs reference - // is this is not empty, nestedFrameRef is set and these VarDecls - // probably have nestedref set too, see VarDeclaration::checkNestedReference - std::set<VarDeclaration*> nestedVars; - - std::string intrinsicName; - - bool isIntrinsic(); - bool isVaIntrinsic(); - - // we keep our own table of label statements as LabelDsymbolS - // don't always carry their corresponding statement along ... - typedef std::map<const char*, LabelStatement*> LabelMap; - LabelMap labmap; - - // if this is an array operation it gets a little special attention - bool isArrayOp; - - // Functions that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; - - // true if overridden with the pragma(allow_inline); stmt - bool allowInlining; -#endif -}; - -struct FuncAliasDeclaration : FuncDeclaration -{ - FuncDeclaration *funcalias; - PROT importprot; // if generated by import, store its protection - - FuncAliasDeclaration(FuncDeclaration *funcalias); - - FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - const char *kind(); -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct FuncLiteralDeclaration : FuncDeclaration -{ - enum TOK tok; // TOKfunction or TOKdelegate - - FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, - ForeachStatement *fes); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *syntaxCopy(Dsymbol *); - int isNested(); - int isVirtual(); - - FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - const char *kind(); -}; - -struct CtorDeclaration : FuncDeclaration -{ Arguments *arguments; - int varargs; - - CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toDocBuffer(OutBuffer *buf); - - CtorDeclaration *isCtorDeclaration() { return this; } -}; - -#if DMDV2 -struct PostBlitDeclaration : FuncDeclaration -{ - PostBlitDeclaration(Loc loc, Loc endloc); - PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - - PostBlitDeclaration *isPostBlitDeclaration() { return this; } -}; -#endif - -struct DtorDeclaration : FuncDeclaration -{ - DtorDeclaration(Loc loc, Loc endloc); - DtorDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - - DtorDeclaration *isDtorDeclaration() { return this; } -}; - -struct StaticCtorDeclaration : FuncDeclaration -{ - StaticCtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticConstructor(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } -}; - -struct StaticDtorDeclaration : FuncDeclaration -{ VarDeclaration *vgate; // 'gate' variable - - StaticDtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticDestructor(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } -}; - -struct InvariantDeclaration : FuncDeclaration -{ - InvariantDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - InvariantDeclaration *isInvariantDeclaration() { return this; } -}; - - -struct UnitTestDeclaration : FuncDeclaration -{ - UnitTestDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - UnitTestDeclaration *isUnitTestDeclaration() { return this; } -}; - -struct NewDeclaration : FuncDeclaration -{ Arguments *arguments; - int varargs; - - NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - - NewDeclaration *isNewDeclaration() { return this; } -}; - - -struct DeleteDeclaration : FuncDeclaration -{ Arguments *arguments; - - DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isDelete(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); -#ifdef _DH - DeleteDeclaration *isDeleteDeclaration() { return this; } -#endif -}; - -#endif /* DMD_DECLARATION_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_DECLARATION_H +#define DMD_DECLARATION_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include <set> +#include <map> +#include <string> + +#include "dsymbol.h" +#include "lexer.h" +#include "mtype.h" + +struct Expression; +struct Statement; +struct LabelDsymbol; +struct LabelStatement; +struct Initializer; +struct Module; +struct InlineScanState; +struct ForeachStatement; +struct FuncDeclaration; +struct ExpInitializer; +struct StructDeclaration; +struct TupleType; +struct InterState; +struct IRState; +struct AnonDeclaration; + +enum PROT; +enum LINK; +enum TOK; +enum MATCH; + +enum STC +{ + STCundefined = 0, + STCstatic = 1, + STCextern = 2, + STCconst = 4, + STCfinal = 8, + STCabstract = 0x10, + STCparameter = 0x20, + STCfield = 0x40, + STCoverride = 0x80, + STCauto = 0x100, + STCsynchronized = 0x200, + STCdeprecated = 0x400, + STCin = 0x800, // in parameter + STCout = 0x1000, // out parameter + STClazy = 0x2000, // lazy parameter + STCforeach = 0x4000, // variable for foreach loop + STCcomdat = 0x8000, // should go into COMDAT record + STCvariadic = 0x10000, // variadic function argument + STCctorinit = 0x20000, // can only be set inside constructor + STCtemplateparameter = 0x40000, // template parameter + STCscope = 0x80000, // template parameter + STCinvariant = 0x100000, + STCimmutable = 0x100000, + STCref = 0x200000, + STCinit = 0x400000, // has explicit initializer + STCmanifest = 0x800000, // manifest constant + STCnodtor = 0x1000000, // don't run destructor + STCnothrow = 0x2000000, // never throws exceptions + STCpure = 0x4000000, // pure function + STCtls = 0x8000000, // thread local + STCalias = 0x10000000, // alias parameter + STCshared = 0x20000000, // accessible from multiple threads + STCgshared = 0x40000000, // accessible from multiple threads + // but not typed as "shared" + STC_TYPECTOR = (STCconst | STCimmutable | STCshared), +}; + +struct Match +{ + int count; // number of matches found + MATCH last; // match level of lastf + FuncDeclaration *lastf; // last matching function we found + FuncDeclaration *nextf; // current matching function + FuncDeclaration *anyf; // pick a func, any func, to use for error recovery +}; + +void overloadResolveX(Match *m, FuncDeclaration *f, + Expression *ethis, Expressions *arguments, Module *from); +int overloadApply(Module* from, FuncDeclaration *fstart, + int (*fp)(void *, FuncDeclaration *), + void *param); + +/**************************************************************/ + +struct Declaration : Dsymbol +{ + Type *type; + Type *originalType; // before semantic analysis + unsigned storage_class; + enum PROT protection; + enum LINK linkage; + int inuse; // used to detect cycles + + Declaration(Identifier *id); + void semantic(Scope *sc); + const char *kind(); + unsigned size(Loc loc); + void checkModify(Loc loc, Scope *sc, Type *t); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toDocBuffer(OutBuffer *buf); + + char *mangle(); + int isStatic() { return storage_class & STCstatic; } + virtual int isStaticConstructor(); + virtual int isStaticDestructor(); + virtual int isDelete(); + virtual int isDataseg(); + virtual int isThreadlocal(); + virtual int isCodeseg(); + int isCtorinit() { return storage_class & STCctorinit; } + int isFinal() { return storage_class & STCfinal; } + int isAbstract() { return storage_class & STCabstract; } + int isConst() { return storage_class & STCconst; } + int isInvariant() { return storage_class & STCinvariant; } + int isAuto() { return storage_class & STCauto; } + int isScope() { return storage_class & STCscope; } + int isSynchronized() { return storage_class & STCsynchronized; } + int isParameter() { return storage_class & STCparameter; } + int isDeprecated() { return storage_class & STCdeprecated; } + int isOverride() { return storage_class & STCoverride; } + + virtual int isSameAsInitializer() { return isConst(); }; + + int isIn() { return storage_class & STCin; } + int isOut() { return storage_class & STCout; } + int isRef() { return storage_class & STCref; } + + enum PROT prot(); + + Declaration *isDeclaration() { return this; } + +#if IN_LLVM + /// Codegen traversal + virtual void codegen(Ir* ir); +#endif +}; + +/**************************************************************/ + +struct TupleDeclaration : Declaration +{ + Objects *objects; + int isexp; // 1: expression tuple + + TypeTuple *tupletype; // !=NULL if this is a type tuple + + TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); + Dsymbol *syntaxCopy(Dsymbol *); + const char *kind(); + Type *getType(); + int needThis(); + + TupleDeclaration *isTupleDeclaration() { return this; } + +#if IN_LLVM + /// Codegen traversal + void codegen(Ir* ir); +#endif +}; + +/**************************************************************/ + +struct TypedefDeclaration : Declaration +{ + Type *basetype; + Initializer *init; + int sem; // 0: semantic() has not been run + // 1: semantic() is in progress + // 2: semantic() has been run + // 3: semantic2() has been run + + TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + char *mangle(); + const char *kind(); + Type *getType(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Type *hbasetype; +#endif + + void toDocBuffer(OutBuffer *buf); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + void toDebug(); + int cvMember(unsigned char *p); +#endif + + TypedefDeclaration *isTypedefDeclaration() { return this; } + +#if IN_DMD + Symbol *sinit; + Symbol *toInitializer(); +#endif + +#if IN_LLVM + /// Codegen traversal + void codegen(Ir* ir); +#endif +}; + +/**************************************************************/ + +struct AliasDeclaration : Declaration +{ + Dsymbol *aliassym; + Dsymbol *overnext; // next in overload list + int inSemantic; + PROT importprot; // if generated by import, store its protection + + AliasDeclaration(Loc loc, Identifier *ident, Type *type); + AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + int overloadInsert(Dsymbol *s); + const char *kind(); + Type *getType(); + Dsymbol *toAlias(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Dsymbol *haliassym; +#endif + + void toDocBuffer(OutBuffer *buf); + + AliasDeclaration *isAliasDeclaration() { return this; } +}; + +/**************************************************************/ + +struct VarDeclaration : Declaration +{ + Initializer *init; + unsigned offset; + int noscope; // no scope semantics +#if DMDV2 + FuncDeclarations nestedrefs; // referenced by these lexically nested functions +#else + int nestedref; // referenced by a lexically nested function +#endif + int ctorinit; // it has been initialized in a ctor + int onstack; // 1: it has been allocated on the stack + // 2: on stack, run destructor anyway + int canassign; // it can be assigned to + Dsymbol *aliassym; // if redone as alias to another symbol + Expression *value; // when interpreting, this is the value + // (NULL if value not determinable) +#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 +#endif + + VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + const char *kind(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Initializer *hinit; +#endif + int needThis(); + int isImportedSymbol(); + int isDataseg(); + int isThreadlocal(); + int hasPointers(); +#if DMDV2 + int canTakeAddressOf(); + int needsAutoDtor(); +#endif + Expression *callScopeDtor(Scope *sc); + ExpInitializer *getExpInitializer(); + Expression *getConstInitializer(); + void checkCtorConstInit(); + void checkNestedReference(Scope *sc, Loc loc); + Dsymbol *toAlias(); + + virtual int isSameAsInitializer(); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + Symbol *toSymbol(); + int cvMember(unsigned char *p); +#endif + + // Eliminate need for dynamic_cast + VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } + +#if IN_LLVM + /// Codegen traversal + virtual void codegen(Ir* ir); + + /// Index into parent aggregate. + /// Set during type generation. + unsigned aggrIndex; + + /// Variables that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. + bool availableExternally; + /// Override added to set above flag. + void semantic3(Scope *sc); + + // FIXME: we're not using these anymore! + AnonDeclaration* anonDecl; + unsigned offset2; + + /// This var is used by a naked function. + bool nakedUse; +#endif +}; + +/**************************************************************/ + +// LDC uses this to denote static struct initializers + +struct StaticStructInitDeclaration : Declaration +{ + StructDeclaration *dsym; + + StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym); + +#if IN_DMD + Symbol *toSymbol(); +#endif + + // Eliminate need for dynamic_cast + StaticStructInitDeclaration *isStaticStructInitDeclaration() { return (StaticStructInitDeclaration *)this; } +}; + +struct ClassInfoDeclaration : VarDeclaration +{ + ClassDeclaration *cd; + + ClassInfoDeclaration(ClassDeclaration *cd); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + +#if IN_DMD + Symbol *toSymbol(); +#endif + + ClassInfoDeclaration* isClassInfoDeclaration() { return this; } +}; + +struct ModuleInfoDeclaration : VarDeclaration +{ + Module *mod; + + ModuleInfoDeclaration(Module *mod); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + +#if IN_DMD + Symbol *toSymbol(); +#endif +}; + +struct TypeInfoDeclaration : VarDeclaration +{ + Type *tinfo; + + TypeInfoDeclaration(Type *tinfo, int internal); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + Symbol *toSymbol(); + virtual void toDt(dt_t **pdt); +#endif + + virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } + +#if IN_LLVM + /// Codegen traversal + void codegen(Ir* ir); + virtual void llvmDefine(); +#endif +}; + +struct TypeInfoStructDeclaration : TypeInfoDeclaration +{ + TypeInfoStructDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoClassDeclaration : TypeInfoDeclaration +{ + TypeInfoClassDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration +{ + TypeInfoInterfaceDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoTypedefDeclaration : TypeInfoDeclaration +{ + TypeInfoTypedefDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoPointerDeclaration : TypeInfoDeclaration +{ + TypeInfoPointerDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoArrayDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoStaticArrayDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoAssociativeArrayDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoEnumDeclaration : TypeInfoDeclaration +{ + TypeInfoEnumDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoFunctionDeclaration : TypeInfoDeclaration +{ + TypeInfoFunctionDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoDelegateDeclaration : TypeInfoDeclaration +{ + TypeInfoDelegateDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoTupleDeclaration : TypeInfoDeclaration +{ + TypeInfoTupleDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +#if DMDV2 +struct TypeInfoConstDeclaration : TypeInfoDeclaration +{ + TypeInfoConstDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoInvariantDeclaration : TypeInfoDeclaration +{ + TypeInfoInvariantDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoSharedDeclaration : TypeInfoDeclaration +{ + TypeInfoSharedDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); +}; +#endif + +/**************************************************************/ + +struct ThisDeclaration : VarDeclaration +{ + ThisDeclaration(Loc loc, Type *t); + Dsymbol *syntaxCopy(Dsymbol *); + ThisDeclaration *isThisDeclaration() { return this; } +}; + +enum ILS +{ + ILSuninitialized, // not computed yet + ILSno, // cannot inline + ILSyes, // can inline +}; + +/**************************************************************/ +#if DMDV2 + +enum BUILTIN +{ + BUILTINunknown = -1, // not known if this is a builtin + BUILTINnot, // this is not a builtin + BUILTINsin, // std.math.sin + BUILTINcos, // std.math.cos + BUILTINtan, // std.math.tan + BUILTINsqrt, // std.math.sqrt + BUILTINfabs, // std.math.fabs +}; + +Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments); + +#else +enum BUILTIN { }; +#endif + +struct FuncDeclaration : Declaration +{ + Array *fthrows; // Array of Type's of exceptions (not used) + Statement *frequire; + Statement *fensure; + Statement *fbody; + + FuncDeclarations foverrides; // functions this function overrides + FuncDeclaration *fdrequire; // function that does the in contract + FuncDeclaration *fdensure; // function that does the out contract + + Identifier *outId; // identifier for out statement + VarDeclaration *vresult; // variable corresponding to outId + LabelDsymbol *returnLabel; // where the return goes + + DsymbolTable *localsymtab; // used to prevent symbols in different + // scopes from having the same name + VarDeclaration *vthis; // 'this' parameter (member and nested) + VarDeclaration *v_arguments; // '_arguments' parameter +#if IN_GCC + VarDeclaration *v_argptr; // '_argptr' variable +#endif + Dsymbols *parameters; // Array of VarDeclaration's for parameters + DsymbolTable *labtab; // statement label symbol table + Declaration *overnext; // next in overload list + Loc endloc; // location of closing curly bracket + int vtblIndex; // for member functions, index into vtbl[] + int naked; // !=0 if naked + int inlineAsm; // !=0 if has inline assembler + ILS inlineStatus; + int inlineNest; // !=0 if nested inline + int cantInterpret; // !=0 if cannot interpret function + int semanticRun; // 1 semantic() run + // 2 semantic2() run + // 3 semantic3() started + // 4 semantic3() done + // 5 toObjFile() run + // this function's frame ptr + ForeachStatement *fes; // if foreach body, this is the foreach + int introducing; // !=0 if 'introducing' function + Type *tintro; // if !=NULL, then this is the type + // of the 'introducing' function + // this one is overriding + int inferRetType; // !=0 if return type is to be inferred + + // Things that should really go into Scope + int hasReturnExp; // 1 if there's a return exp; statement + // 2 if there's a throw statement + // 4 if there's an assert(0) + // 8 if there's inline asm + + // Support for NRVO (named return value optimization) + int nrvo_can; // !=0 means we can do it + VarDeclaration *nrvo_var; // variable to replace with shidden +#if IN_DMD + Symbol *shidden; // hidden pointer passed to function +#endif + +#if DMDV2 + enum BUILTIN builtin; // set if this is a known, builtin + // function we can evaluate at compile + // time + + int tookAddressOf; // set if someone took the address of + // this function + Dsymbols closureVars; // local variables in this function + // which are referenced by nested + // functions +#else + int nestedFrameRef; // !=0 if nested variables referenced +#endif + + FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + // called from semantic3 + void varArgs(Scope *sc, TypeFunction*, VarDeclaration *&, VarDeclaration *&); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); + int overrides(FuncDeclaration *fd); + int findVtblIndex(Array *vtbl, int dim); + int overloadInsert(Dsymbol *s); + FuncDeclaration *overloadExactMatch(Type *t, Module* from); + FuncDeclaration *overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, Module *from, int flags = 0); + MATCH leastAsSpecialized(FuncDeclaration *g); + LabelDsymbol *searchLabel(Identifier *ident); + AggregateDeclaration *isThis(); + AggregateDeclaration *isMember2(); + int getLevel(Loc loc, FuncDeclaration *fd); // lexical nesting level difference + void appendExp(Expression *e); + void appendState(Statement *s); + char *mangle(); + const char *toPrettyChars(); + int isMain(); + int isWinMain(); + int isDllMain(); + enum BUILTIN isBuiltin(); + int isExport(); + int isImportedSymbol(); + int isAbstract(); + int isCodeseg(); + int isOverloadable(); + int isPure(); + virtual int isNested(); + int needThis(); + virtual int isVirtual(); + virtual int isFinal(); + virtual int addPreInvariant(); + virtual int addPostInvariant(); + Expression *interpret(InterState *istate, Expressions *arguments, Expression *thisexp = NULL); + void inlineScan(); + int canInline(int hasthis, int hdrscan = 0); + Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); + const char *kind(); + void toDocBuffer(OutBuffer *buf); + FuncDeclaration *isUnique(); + int needsClosure(); + Statement *mergeFrequire(Statement *); + Statement *mergeFensure(Statement *); + +// LDC: give argument types to runtime functions + static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, const char *name); + static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, Identifier *id); + +#if IN_DMD + Symbol *toSymbol(); + Symbol *toThunkSymbol(int offset); // thunk version + void toObjFile(int multiobj); // compile to .obj file + int cvMember(unsigned char *p); + void buildClosure(IRState *irs); +#endif + + FuncDeclaration *isFuncDeclaration() { return this; } + +#if IN_LLVM + // LDC stuff + + /// Codegen traversal + void codegen(Ir* ir); + + // vars declared in this function that nested funcs reference + // is this is not empty, nestedFrameRef is set and these VarDecls + // probably have nestedref set too, see VarDeclaration::checkNestedReference + std::set<VarDeclaration*> nestedVars; + + std::string intrinsicName; + + bool isIntrinsic(); + bool isVaIntrinsic(); + + // we keep our own table of label statements as LabelDsymbolS + // don't always carry their corresponding statement along ... + typedef std::map<const char*, LabelStatement*> LabelMap; + LabelMap labmap; + + // if this is an array operation it gets a little special attention + bool isArrayOp; + + // Functions that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. + bool availableExternally; + + // true if overridden with the pragma(allow_inline); stmt + bool allowInlining; +#endif +}; + +#if DMDV2 +FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, + Objects *tiargs, + Expression *ethis, + Expressions *arguments, + int flags); +#endif + +struct FuncAliasDeclaration : FuncDeclaration +{ + FuncDeclaration *funcalias; + PROT importprot; // if generated by import, store its protection + + FuncAliasDeclaration(FuncDeclaration *funcalias); + + FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } + const char *kind(); +#if IN_DMD + Symbol *toSymbol(); +#endif +}; + +struct FuncLiteralDeclaration : FuncDeclaration +{ + enum TOK tok; // TOKfunction or TOKdelegate + + FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, + ForeachStatement *fes); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Dsymbol *syntaxCopy(Dsymbol *); + int isNested(); + int isVirtual(); + + FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } + const char *kind(); +}; + +struct CtorDeclaration : FuncDeclaration +{ Arguments *arguments; + int varargs; + + CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + char *toChars(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void toDocBuffer(OutBuffer *buf); + + CtorDeclaration *isCtorDeclaration() { return this; } +}; + +#if DMDV2 +struct PostBlitDeclaration : FuncDeclaration +{ + PostBlitDeclaration(Loc loc, Loc endloc); + PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + int overloadInsert(Dsymbol *s); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + + PostBlitDeclaration *isPostBlitDeclaration() { return this; } +}; +#endif + +struct DtorDeclaration : FuncDeclaration +{ + DtorDeclaration(Loc loc, Loc endloc); + DtorDeclaration(Loc loc, Loc endloc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + char *toChars(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + int overloadInsert(Dsymbol *s); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + + DtorDeclaration *isDtorDeclaration() { return this; } +}; + +struct StaticCtorDeclaration : FuncDeclaration +{ + StaticCtorDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isStaticConstructor(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } +}; + +struct StaticDtorDeclaration : FuncDeclaration +{ VarDeclaration *vgate; // 'gate' variable + + StaticDtorDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isStaticDestructor(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } +}; + +struct InvariantDeclaration : FuncDeclaration +{ + InvariantDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + InvariantDeclaration *isInvariantDeclaration() { return this; } +}; + + +struct UnitTestDeclaration : FuncDeclaration +{ + UnitTestDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + UnitTestDeclaration *isUnitTestDeclaration() { return this; } +}; + +struct NewDeclaration : FuncDeclaration +{ Arguments *arguments; + int varargs; + + NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + + NewDeclaration *isNewDeclaration() { return this; } +}; + + +struct DeleteDeclaration : FuncDeclaration +{ Arguments *arguments; + + DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + int isDelete(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); +#ifdef _DH + DeleteDeclaration *isDeleteDeclaration() { return this; } +#endif +}; + +#endif /* DMD_DECLARATION_H */
--- a/dmd/doc.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/doc.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -33,6 +33,7 @@ #include "hdrgen.h" #include "doc.h" #include "mtype.h" +#include "utf.h" struct Escape { @@ -89,14 +90,18 @@ int icmp(const char *stringz, void *s, size_t slen); int isDitto(unsigned char *comment); unsigned char *skipwhitespace(unsigned char *p); -unsigned skiptoident(OutBuffer *buf, unsigned i); -unsigned skippastident(OutBuffer *buf, unsigned i); -unsigned skippastURL(OutBuffer *buf, unsigned i); +unsigned skiptoident(OutBuffer *buf, size_t i); +unsigned skippastident(OutBuffer *buf, size_t i); +unsigned skippastURL(OutBuffer *buf, size_t i); void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); +int isIdStart(unsigned char *p); +int isIdTail(unsigned char *p); +int utfStride(unsigned char *p); + static unsigned char ddoc_default[] = "\ DDOC = <html><head>\n\ <META http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n\ @@ -238,7 +243,7 @@ // Generate predefined macros // Set the title to be the name of the module - { char *p = toPrettyChars(); + { const char *p = toPrettyChars(); Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); } @@ -674,7 +679,7 @@ buf->writestring("const "); #if DMDV2 if (d->isInvariant()) - buf->writestring("invariant "); + buf->writestring("immutable "); #endif if (d->isFinal()) buf->writestring("final "); @@ -948,7 +953,6 @@ { unsigned char *p; unsigned char *pstart; unsigned char *pend; - unsigned char *q; unsigned char *idstart; unsigned idlen; @@ -963,17 +967,32 @@ pstart = p; /* Find end of section, which is ended by one of: - * 'identifier:' + * 'identifier:' (but not inside a code section) * '\0' */ idlen = 0; + int inCode = 0; while (1) { - if (isalpha(*p) || *p == '_') + // Check for start/end of a code section + if (*p == '-') { - q = p + 1; - while (isalnum(*q) || *q == '_') - q++; + int numdash = 0; + while (*p == '-') + { + ++numdash; + p++; + } + // BUG: handle UTF PS and LS too + if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) + inCode ^= 1; + } + + if (!inCode && isIdStart(p)) + { + unsigned char *q = p + utfStride(p); + while (isIdTail(q)) + q += utfStride(q); if (*q == ':') // identifier: ends it { idlen = q - p; idstart = p; @@ -1141,12 +1160,13 @@ while (p < pend) { // Skip to start of macro - for (; 1; p++) + while (1) { switch (*p) { case ' ': case '\t': + p++; continue; case '\n': @@ -1154,20 +1174,18 @@ goto Lcont; default: - if (!(isalpha(*p) || *p == '_')) - { - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; + if (isIdStart(p)) + break; + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; } break; } tempstart = p; - while (isalnum(*p) || *p == '_') - p++; + while (isIdTail(p)) + p += utfStride(p); templen = p - tempstart; while (*p == ' ' || *p == '\t') @@ -1269,7 +1287,7 @@ while (p < pend) { // Skip to start of macro - for (; 1; p++) + while (1) { if (p >= pend) goto Ldone; @@ -1277,6 +1295,7 @@ { case ' ': case '\t': + p++; continue; case '\n': @@ -1284,13 +1303,11 @@ goto Lcont; default: - if (!(isalpha(*p) || *p == '_')) - { - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; + if (isIdStart(p)) + break; + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; } break; } @@ -1300,9 +1317,9 @@ { if (p >= pend) goto Ldone; - if (!(isalnum(*p) || *p == '_')) + if (!isIdTail(p)) break; - p++; + p += utfStride(p); } templen = p - tempstart; @@ -1486,16 +1503,25 @@ * end of buf */ -unsigned skiptoident(OutBuffer *buf, unsigned i) +unsigned skiptoident(OutBuffer *buf, size_t i) { - for (; i < buf->offset; i++) - { - // BUG: handle unicode alpha's - unsigned char c = buf->data[i]; - if (isalpha(c) || c == '_') + while (i < buf->offset) + { dchar_t c; + + size_t oi = i; + if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + /* Ignore UTF errors, but still consume input + */ break; - if (c == '\n') - break; + if (c >= 0x80) + { + if (!isUniAlpha(c)) + continue; + } + else if (!(isalpha(c) || c == '_' || c == '\n')) + continue; + i = oi; + break; } return i; } @@ -1504,14 +1530,25 @@ * Scan forward past end of identifier. */ -unsigned skippastident(OutBuffer *buf, unsigned i) +unsigned skippastident(OutBuffer *buf, size_t i) { - for (; i < buf->offset; i++) - { - // BUG: handle unicode alpha's - unsigned char c = buf->data[i]; - if (!(isalnum(c) || c == '_')) + while (i < buf->offset) + { dchar_t c; + + size_t oi = i; + if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + /* Ignore UTF errors, but still consume input + */ break; + if (c >= 0x80) + { + if (isUniAlpha(c)) + continue; + } + else if (isalnum(c) || c == '_') + continue; + i = oi; + break; } return i; } @@ -1525,7 +1562,7 @@ * index just past it if it is a URL */ -unsigned skippastURL(OutBuffer *buf, unsigned i) +unsigned skippastURL(OutBuffer *buf, size_t i) { unsigned length = buf->offset - i; unsigned char *p = &buf->data[i]; unsigned j; @@ -1810,7 +1847,7 @@ default: leadingBlank = 0; - if (sc && !inCode && (isalpha(c) || c == '_')) + if (sc && !inCode && isIdStart(&buf->data[i])) { unsigned j; j = skippastident(buf, i); @@ -1881,7 +1918,7 @@ i = buf->insert(i, se, len); i--; // point to ';' } - else if (isalpha(c) || c == '_') + else if (isIdStart(&buf->data[i])) { unsigned j; j = skippastident(buf, i); @@ -2017,3 +2054,54 @@ return s; } +/**************************************** + * Determine if p points to the start of an identifier. + */ + +int isIdStart(unsigned char *p) +{ + unsigned c = *p; + if (isalpha(c) || c == '_') + return 1; + if (c >= 0x80) + { size_t i = 0; + if (utf_decodeChar(p, 4, &i, &c)) + return 0; // ignore errors + if (isUniAlpha(c)) + return 1; + } + return 0; +} + +/**************************************** + * Determine if p points to the rest of an identifier. + */ + +int isIdTail(unsigned char *p) +{ + unsigned c = *p; + if (isalnum(c) || c == '_') + return 1; + if (c >= 0x80) + { size_t i = 0; + if (utf_decodeChar(p, 4, &i, &c)) + return 0; // ignore errors + if (isUniAlpha(c)) + return 1; + } + return 0; +} + +/***************************************** + * Return number of bytes in UTF character. + */ + +int utfStride(unsigned char *p) +{ + unsigned c = *p; + if (c < 0x80) + return 1; + size_t i = 0; + utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input + return i; +}
--- a/dmd/dsymbol.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/dsymbol.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -28,7 +28,7 @@ #include "init.h" #include "import.h" #include "template.h" - +#include "attrib.h" #include "../gen/enums.h" /****************************** Dsymbol ******************************/ @@ -45,7 +45,7 @@ #endif this->loc = 0; this->comment = NULL; - + this->scope = NULL; #if IN_LLVM this->llvmInternal = LLVMnone; this->irsym = NULL; @@ -64,7 +64,7 @@ #endif this->loc = 0; this->comment = NULL; - + this->scope = NULL; #if IN_LLVM this->llvmInternal = LLVMnone; this->irsym = NULL; @@ -164,7 +164,7 @@ return ident ? ident->toChars() : (char *)"__anonymous"; } -char *Dsymbol::toPrettyChars() +const char *Dsymbol::toPrettyChars() { Dsymbol *p; char *s; char *q; @@ -190,6 +190,16 @@ if (q == s) break; q--; +#if TARGET_NET + if (AggregateDeclaration* ad = p->isAggregateDeclaration()) + { + if (ad->isNested() && p->parent && p->parent->isAggregateDeclaration()) + { + *q = '/'; + continue; + } + } +#endif *q = '.'; } return s; @@ -266,24 +276,57 @@ return ident ? 0 : 1; } +/************************************* + * Set scope for future semantic analysis so we can + * deal better with forward references. + */ + +void Dsymbol::setScope(Scope *sc) +{ + //printf("Dsymbol::setScope() %p %s\n", this, toChars()); + if (!sc->nofree) + sc->setNoFree(); // may need it even after semantic() finishes + scope = sc; +} + +void Dsymbol::importAll(Scope *sc) +{ +} + +/************************************* + * Does semantic analysis on the public face of declarations. + */ + void Dsymbol::semantic(Scope *sc) { error("%p has no semantic routine", this); } +/************************************* + * Does semantic analysis on initializers and members of aggregates. + */ + void Dsymbol::semantic2(Scope *sc) { // Most Dsymbols have no further semantic analysis needed } +/************************************* + * Does semantic analysis on function bodies. + */ + void Dsymbol::semantic3(Scope *sc) { // Most Dsymbols have no further semantic analysis needed } +/************************************* + * Look for function inlining possibilities. + */ + void Dsymbol::inlineScan() { - // Most Dsymbols have no further semantic analysis needed + // Most Dsymbols aren't functions } /********************************************* @@ -341,7 +384,7 @@ return NULL; } ti->tempdecl = td; - if (!ti->semanticdone) + if (!ti->semanticRun) ti->semantic(sc); sm = ti->toAlias(); break; @@ -408,6 +451,13 @@ return FALSE; } +#if DMDV2 +int Dsymbol::isOverloadable() +{ + return 0; +} +#endif + LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? { return NULL; @@ -439,7 +489,7 @@ parent = sd; if (!isAnonymous()) // no name, so can't add it to symbol table { - if (!sd->symtab->insert(this)) // if name is already defined + if (!sd->symtabInsert(this)) // if name is already defined { Dsymbol *s2; @@ -631,8 +681,8 @@ void Dsymbol::addComment(unsigned char *comment) { -// if (comment) -// printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); + //if (comment) + //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); if (!this->comment) this->comment = comment; @@ -644,6 +694,25 @@ #endif } +/********************************* OverloadSet ****************************/ + +#if DMDV2 +OverloadSet::OverloadSet() + : Dsymbol() +{ +} + +void OverloadSet::push(Dsymbol *s) +{ + a.push(s); +} + +const char *OverloadSet::kind() +{ + return "overloadset"; +} +#endif + /********************************* ScopeDsymbol ****************************/ @@ -681,6 +750,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) { //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); + //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; // Look in symbols declared in this module Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; @@ -771,7 +841,7 @@ { ScopeDsymbol *ss; ss = (ScopeDsymbol *) imports->data[i]; - if (ss == s) + if (ss == s) // if already imported { if (protection > prots[i]) prots[i] = protection; // upgrade access @@ -849,6 +919,73 @@ return "ScopeDsymbol"; } +Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) +{ + return symtab->insert(s); +} + +/*************************************** + * Determine number of Dsymbols, folding in AttribDeclaration members. + */ + +#if DMDV2 +size_t ScopeDsymbol::dim(Array *members) +{ + size_t n = 0; + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + AttribDeclaration *a = s->isAttribDeclaration(); + + if (a) + { + n += dim(a->decl); + } + else + n++; + } + } + return n; +} +#endif + +/*************************************** + * Get nth Dsymbol, folding in AttribDeclaration members. + * Returns: + * Dsymbol* nth Dsymbol + * NULL not found, *pn gets incremented by the number + * of Dsymbols + */ + +#if DMDV2 +Dsymbol *ScopeDsymbol::getNth(Array *members, size_t nth, size_t *pn) +{ + if (!members) + return NULL; + + size_t n = 0; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + AttribDeclaration *a = s->isAttribDeclaration(); + + if (a) + { + s = getNth(a->decl, nth - n, &n); + if (s) + return s; + } + else if (n == nth) + return s; + else + n++; + } + + if (pn) + *pn += n; + return NULL; +} +#endif /******************************************* * Look for member of the form: @@ -938,7 +1075,8 @@ L1: if (td) - { + { /* $ gives the number of elements in the tuple + */ VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); v->init = new ExpInitializer(0, e); @@ -947,7 +1085,8 @@ } if (type) - { + { /* $ gives the number of type entries in the type tuple + */ VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); v->init = new ExpInitializer(0, e); @@ -956,22 +1095,30 @@ } if (exp->op == TOKindex) - { + { /* array[index] where index is some function of $ + */ IndexExp *ie = (IndexExp *)exp; pvar = &ie->lengthVar; ce = ie->e1; } else if (exp->op == TOKslice) - { + { /* array[lwr .. upr] where lwr or upr is some function of $ + */ SliceExp *se = (SliceExp *)exp; pvar = &se->lengthVar; ce = se->e1; } else + /* Didn't find $, look in enclosing scope(s). + */ return NULL; + /* If we are indexing into an array that is really a type + * tuple, rewrite this as an index into a type tuple and + * try again. + */ if (ce->op == TOKtype) { Type *t = ((TypeExp *)ce)->type; @@ -981,8 +1128,13 @@ } } - if (!*pvar) - { + /* *pvar is lazily initialized, so if we refer to $ + * multiple times, it gets set only once. + */ + if (!*pvar) // if not already initialized + { /* Create variable v and set it to the value of $, + * which will be a constant. + */ VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); if (ce->op == TOKstring) @@ -1030,13 +1182,12 @@ } Dsymbol *DsymbolTable::lookup(Identifier *ident) -{ StringValue *sv; - +{ #ifdef DEBUG assert(ident); assert(tab); #endif - sv = tab->lookup((char*)ident->string, ident->len); + StringValue *sv = tab->lookup((char*)ident->string, ident->len); return (Dsymbol *)(sv ? sv->ptrvalue : NULL); }
--- a/dmd/dsymbol.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/dsymbol.h Fri Nov 06 23:58:01 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -28,6 +28,7 @@ struct Scope; struct DsymbolTable; struct Declaration; +struct ThisDeclaration; struct TupleDeclaration; struct TypedefDeclaration; struct AliasDeclaration; @@ -41,6 +42,7 @@ struct FuncAliasDeclaration; struct FuncLiteralDeclaration; struct CtorDeclaration; +struct PostBlitDeclaration; struct DtorDeclaration; struct StaticCtorDeclaration; struct StaticDtorDeclaration; @@ -70,11 +72,13 @@ struct HdrGenState; struct TypeInfoDeclaration; struct ClassInfoDeclaration; - +struct OverloadSet; +#if TARGET_NET +struct PragmaScope; +#endif #if IN_DMD struct Symbol; #endif - #if IN_GCC union tree_node; typedef union tree_node TYPE; @@ -82,6 +86,9 @@ struct TYPE; #endif +// Back end +struct Classsym; + #if IN_LLVM class Ir; class IrSymbol; @@ -114,11 +121,11 @@ #endif unsigned char *comment; // documentation comment for this Dsymbol Loc loc; // where defined + Scope *scope; // !=NULL means context to use for semantic() Dsymbol(); Dsymbol(Identifier *); char *toChars(); - char *toPrettyChars(); char *locToChars(); int equals(Object *o); int isAnonymous(); @@ -136,9 +143,12 @@ static Array *arraySyntaxCopy(Array *a); + virtual const char *toPrettyChars(); virtual const char *kind(); virtual Dsymbol *toAlias(); // resolve real symbol virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + virtual void setScope(Scope *sc); + virtual void importAll(Scope *sc); virtual void semantic(Scope *sc); virtual void semantic2(Scope *sc); virtual void semantic3(Scope *sc); @@ -152,6 +162,7 @@ #endif virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual void toDocBuffer(OutBuffer *buf); + virtual void toJsonBuffer(OutBuffer *buf); virtual unsigned size(Loc loc); virtual int isforwardRef(); virtual void defineRef(Dsymbol *s); @@ -160,6 +171,9 @@ virtual int isExport(); // is Dsymbol exported? virtual int isImportedSymbol(); // is Dsymbol imported? virtual int isDeprecated(); // is Dsymbol deprecated? +#if DMDV2 + virtual int isOverloadable(); +#endif virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? virtual Type *getType(); // is this a type? @@ -198,6 +212,7 @@ virtual TemplateInstance *isTemplateInstance() { return NULL; } virtual TemplateMixin *isTemplateMixin() { return NULL; } virtual Declaration *isDeclaration() { return NULL; } + virtual ThisDeclaration *isThisDeclaration() { return NULL; } virtual TupleDeclaration *isTupleDeclaration() { return NULL; } virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } virtual AliasDeclaration *isAliasDeclaration() { return NULL; } @@ -206,6 +221,7 @@ virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } virtual CtorDeclaration *isCtorDeclaration() { return NULL; } + virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } virtual DtorDeclaration *isDtorDeclaration() { return NULL; } virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } @@ -230,6 +246,11 @@ virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } + virtual OverloadSet *isOverloadSet() { return NULL; } +#if TARGET_NET + virtual PragmaScope* isPragmaScope() { return NULL; } +#endif + #if IN_LLVM /// Codegen traversal virtual void codegen(Ir* ir); @@ -250,7 +271,7 @@ DsymbolTable *symtab; // members[] sorted into table Array *imports; // imported ScopeDsymbol's - unsigned char *prots; // PROT for each import + unsigned char *prots; // array of PROT, one for each import ScopeDsymbol(); ScopeDsymbol(Identifier *id); @@ -262,9 +283,14 @@ static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); Dsymbol *nameCollision(Dsymbol *s); const char *kind(); + FuncDeclaration *findGetMembers(); + virtual Dsymbol *symtabInsert(Dsymbol *s); void emitMemberComments(Scope *sc); + static size_t dim(Array *members); + static Dsymbol *getNth(Array *members, size_t nth, size_t *pn = NULL); + ScopeDsymbol *isScopeDsymbol() { return this; } }; @@ -287,6 +313,7 @@ Expression *exp; // IndexExp or SliceExp TypeTuple *type; // for tuple[length] TupleDeclaration *td; // for tuples of objects + Scope *sc; ArrayScopeSymbol(Expression *e); ArrayScopeSymbol(TypeTuple *t); @@ -296,6 +323,20 @@ ArrayScopeSymbol *isArrayScopeSymbol() { return this; } }; +// Overload Sets + +#if DMDV2 +struct OverloadSet : Dsymbol +{ + Dsymbols a; // array of Dsymbols + + OverloadSet(); + void push(Dsymbol *s); + OverloadSet *isOverloadSet() { return this; } + const char *kind(); +}; +#endif + // Table of Dsymbol's struct DsymbolTable : Object
--- a/dmd/enum.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/enum.h Fri Nov 06 23:58:01 2009 +0100 @@ -1,94 +1,95 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_ENUM_H -#define DMD_ENUM_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -struct Identifier; -struct Type; -struct Expression; -#ifdef _DH -struct HdrGenState; -#endif - - -struct EnumDeclaration : ScopeDsymbol -{ - Type *type; // the TypeEnum - Type *memtype; // type of the members - -#if DMDV1 - dinteger_t maxval; - dinteger_t minval; - dinteger_t defaultval; // default initializer -#else - Expression *maxval; - Expression *minval; - Expression *defaultval; // default initializer - - Scope *scope; // !=NULL means context to use -#endif - int isdeprecated; - - EnumDeclaration(Loc loc, Identifier *id, Type *memtype); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - int oneMember(Dsymbol **ps); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *getType(); - const char *kind(); -#if DMDV2 - Dsymbol *search(Loc, Identifier *ident, int flags); -#endif - int isDeprecated(); // is Dsymbol deprecated? - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - EnumDeclaration *isEnumDeclaration() { return this; } - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); - - Symbol *sinit; - Symbol *toInitializer(); -#endif - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - - -struct EnumMember : Dsymbol -{ - Expression *value; - - EnumMember(Loc loc, Identifier *id, Expression *value); - Dsymbol *syntaxCopy(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - EnumMember *isEnumMember() { return this; } -}; - -#endif /* DMD_ENUM_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_ENUM_H +#define DMD_ENUM_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "dsymbol.h" + +struct Identifier; +struct Type; +struct Expression; +#ifdef _DH +struct HdrGenState; +#endif + + +struct EnumDeclaration : ScopeDsymbol +{ /* enum ident : memtype { ... } + */ + Type *type; // the TypeEnum + Type *memtype; // type of the members + +#if DMDV1 + dinteger_t maxval; + dinteger_t minval; + dinteger_t defaultval; // default initializer +#else + Expression *maxval; + Expression *minval; + Expression *defaultval; // default initializer +#endif + int isdeprecated; + + EnumDeclaration(Loc loc, Identifier *id, Type *memtype); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + int oneMember(Dsymbol **ps); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Type *getType(); + const char *kind(); +#if DMDV2 + Dsymbol *search(Loc, Identifier *ident, int flags); +#endif + int isDeprecated(); // is Dsymbol deprecated? + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toDocBuffer(OutBuffer *buf); + + EnumDeclaration *isEnumDeclaration() { return this; } + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + void toDebug(); + int cvMember(unsigned char *p); + + Symbol *sinit; + Symbol *toInitializer(); +#endif + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + + +struct EnumMember : Dsymbol +{ + Expression *value; + + EnumMember(Loc loc, Identifier *id, Expression *value); + Dsymbol *syntaxCopy(Dsymbol *s); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toDocBuffer(OutBuffer *buf); + + EnumMember *isEnumMember() { return this; } +}; + +#endif /* DMD_ENUM_H */
--- a/dmd/expression.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/expression.c Fri Nov 06 23:58:01 2009 +0100 @@ -35,8 +35,8 @@ #endif #include "rmem.h" - -//#include "port.h" +#include "port.h" + #include "mtype.h" #include "init.h" #include "expression.h" @@ -373,6 +373,11 @@ } } + else if (e->op == TOKdottd) + { + e = new CallExp(e->loc, e); + e = e->semantic(sc); + } return e; } @@ -543,7 +548,7 @@ size_t nparams = Argument::dim(tf->parameters); if (nargs > nparams && tf->varargs == 0) - error(loc, "expected %zu arguments, not %zu", nparams, nargs); + error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars()); n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) @@ -568,7 +573,7 @@ { if (tf->varargs == 2 && i + 1 == nparams) goto L2; - error(loc, "expected %zu arguments, not %zu", nparams, nargs); + error(loc, "expected %zu function arguments, not %zu", nparams, nargs); break; } arg = p->defaultArg; @@ -590,7 +595,7 @@ if (arg->implicitConvTo(p->type)) { if (nargs != nparams) - error(loc, "expected %zu arguments, not %zu", nparams, nargs); + error(loc, "expected %zu function arguments, not %zu", nparams, nargs); goto L1; } L2: @@ -669,7 +674,16 @@ L1: if (!(p->storageClass & STClazy && p->type->ty == Tvoid)) - arg = arg->implicitCastTo(sc, p->type); + { + if (p->type != arg->type) + { + //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars()); + if (arg->op == TOKtype) + arg->error("cannot pass type %s as function argument", arg->toChars()); + arg = arg->implicitCastTo(sc, p->type); + arg = arg->optimize(WANTvalue); + } + } if (p->storageClass & (STCout | STCref)) { // BUG: should check that argument to ref is type 'invariant' @@ -773,11 +787,15 @@ { arg = callCpCtor(loc, sc, arg); } +#endif // Give error for overloaded function addresses +#if DMDV2 if (arg->op == TOKsymoff) { SymOffExp *se = (SymOffExp *)arg; - if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) + if ( + se->hasOverloads && + !se->var->isFuncDeclaration()->isUnique()) arg->error("function %s is overloaded", arg->toChars()); } #endif @@ -1214,10 +1232,10 @@ Expression *Expression::deref() { //printf("Expression::deref()\n"); - if (type->ty == Treference) - { Expression *e; - - e = new PtrExp(loc, this); + // type could be null if forward referencing an 'auto' variable + if (type && type->ty == Treference) + { + Expression *e = new PtrExp(loc, this); e->type = ((TypeReference *)type)->next; return e; } @@ -2155,6 +2173,10 @@ f = s->isFuncDeclaration(); if (f) { //printf("'%s' is a function\n", f->toChars()); + if (!f->type->deco) + { + error("forward reference to %s", toChars()); + } return new VarExp(loc, f); } cd = s->isClassDeclaration(); @@ -2209,7 +2231,7 @@ TemplateInstance *ti = s->isTemplateInstance(); if (ti && !global.errors) - { if (!ti->semanticdone) + { if (!ti->semanticRun) ti->semantic(sc); s = ti->inst->toAlias(); if (!s->isTemplateInstance()) @@ -3166,7 +3188,16 @@ if (v->init) { e = v->init->toExpression(); if (!e) - error("cannot make expression out of initializer for %s", v->toChars()); + { error("cannot make expression out of initializer for %s", v->toChars()); + e = new ErrorExp(); + } + else if (v->scope) + { // Do deferred semantic anaylsis + Initializer *i2 = v->init->syntaxCopy(); + i2 = i2->semantic(v->scope, v->type); + e = i2->toExpression(); + v->scope = NULL; + } } else { e = v->type->defaultInit(); @@ -3200,8 +3231,26 @@ e = (Expression *)elements->data[i]; if (e) { - e = e->copy(); - e->type = type; + //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars()); + + /* If type is a static array, and e is an initializer for that array, + * then the field initializer should be an array literal of e. + */ + if (e->type != type && type->ty == Tsarray) + { TypeSArray *tsa = (TypeSArray *)type; + uinteger_t length = tsa->dim->toInteger(); + Expressions *z = new Expressions; + z->setDim(length); + for (int q = 0; q < length; ++q) + z->data[q] = e->copy(); + e = new ArrayLiteralExp(loc, z); + e->type = type; + } + else + { + e = e->copy(); + e->type = type; + } } } return e; @@ -3216,20 +3265,23 @@ { /* Find which field offset is by looking at the field offsets */ - for (size_t i = 0; i < sd->fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - if (offset == v->offset && - type->size() == v->type->size()) - { Expression *e = (Expression *)elements->data[i]; - if (e) - { - return i; - } - break; + if (elements->dim) + { + for (size_t i = 0; i < sd->fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + + if (offset == v->offset && + type->size() == v->type->size()) + { Expression *e = (Expression *)elements->data[i]; + if (e) + { + return i; + } + break; + } } } return -1; @@ -3365,7 +3417,7 @@ ti = sds->isTemplateInstance(); if (ti && !global.errors) { Dsymbol *s; - if (!ti->semanticdone) + if (!ti->semanticRun) ti->semantic(sc); s = ti->inst->toAlias(); sds2 = s->isScopeDsymbol(); @@ -3583,7 +3635,7 @@ else if (thisexp) error("e.new is only for allocating nested classes"); else if (fdn) - { + { // make sure the parent context fdn of cd is reachable from sc for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) { @@ -3606,7 +3658,7 @@ if (f) { assert(f); - f = f->overloadResolve(loc, arguments, sc->module); + f = f->overloadResolve(loc, NULL, arguments, sc->module); checkDeprecated(sc, f); member = f->isCtorDeclaration(); assert(member); @@ -3634,7 +3686,7 @@ newargs = new Expressions(); newargs->shift(e); - f = cd->aggNew->overloadResolve(loc, newargs, sc->module); + f = cd->aggNew->overloadResolve(loc, NULL, newargs, sc->module); allocator = f->isNewDeclaration(); assert(allocator); @@ -3667,7 +3719,7 @@ newargs = new Expressions(); newargs->shift(e); - f = f->overloadResolve(loc, newargs, sc->module); + f = f->overloadResolve(loc, NULL, newargs, sc->module); allocator = f->isNewDeclaration(); assert(allocator); @@ -4200,6 +4252,7 @@ return (Expression *)exps->data[0]; } type = new TypeTuple(exps); + type = type->semantic(loc, sc); //printf("-TupleExp::semantic(%s)\n", toChars()); return this; } @@ -4263,13 +4316,13 @@ fd->parent = sc->parent; if (global.errors) { - if (!fd->type->next) - fd->type->next = Type::terror; } else { fd->semantic2(sc); - if (!global.errors) + if (!global.errors || + // need to infer return type + (fd->type && fd->type->ty == Tfunction && !fd->type->nextOf())) { fd->semantic3(sc); @@ -4278,6 +4331,10 @@ } } + // need to infer return type + if (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 if (fd->isNested()) { @@ -4377,7 +4434,13 @@ } if (!s->isVarDeclaration()) { - declaration->semantic(sc); + Scope *sc2 = sc; + if (sc2->stc & (STCpure | STCnothrow)) + sc2 = sc->push(); + sc2->stc &= ~(STCpure | STCnothrow); + declaration->semantic(sc2); + if (sc2 != sc) + sc2->pop(); s->parent = sc->parent; } if (!global.errors) @@ -4920,7 +4983,7 @@ if (op == TOKmodass && e2->type->iscomplex()) { error("cannot perform modulo complex arithmetic"); - return new IntegerExp(0); + return new ErrorExp(); } } return this; @@ -4985,6 +5048,46 @@ return Expression::checkSideEffect(flag); } +// generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary +void BinExp::checkComplexMulAssign() +{ + // Any multiplication by an imaginary or complex number yields a complex result. + // r *= c, i*=c, r*=i, i*=i are all forbidden operations. + const char *opstr = Token::toChars(op); + if ( e1->type->isreal() && e2->type->iscomplex()) + { + error("%s %s %s is undefined. Did you mean %s %s %s.re ?", + e1->type->toChars(), opstr, e2->type->toChars(), + e1->type->toChars(), opstr, e2->type->toChars()); + } + else if (e1->type->isimaginary() && e2->type->iscomplex()) + { + error("%s %s %s is undefined. Did you mean %s %s %s.im ?", + e1->type->toChars(), opstr, e2->type->toChars(), + e1->type->toChars(), opstr, e2->type->toChars()); + } + else if ((e1->type->isreal() || e1->type->isimaginary()) && + e2->type->isimaginary()) + { + error("%s %s %s is an undefined operation", e1->type->toChars(), + opstr, e2->type->toChars()); + } +} + +// generate an error if this is a nonsensical += or -=, eg real += imaginary +void BinExp::checkComplexAddAssign() +{ + // Addition or subtraction of a real and an imaginary is a complex result. + // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. + if ( (e1->type->isreal() && (e2->type->isimaginary() || e2->type->iscomplex())) || + (e1->type->isimaginary() && (e2->type->isreal() || e2->type->iscomplex())) + ) + { + error("%s %s %s is undefined (result is complex)", + e1->type->toChars(), Token::toChars(op), e2->type->toChars()); + } +} + void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { expToCBuffer(buf, hgs, e1, precedence[op]); @@ -5094,7 +5197,7 @@ } if (global.params.verbose) - printf("file %s\t(%s)\n", (char*)se->string, name); + printf("file %s\t(%s)\n", (char *)se->string, name); { File f(name); if (f.read()) @@ -5177,7 +5280,10 @@ #if DMDV2 int AssertExp::canThrow() { - return (global.params.useAssert != 0); + /* assert()s are non-recoverable errors, so functions that + * use them can be considered "nothrow" + */ + return 0; //(global.params.useAssert != 0); } #endif @@ -5479,7 +5585,11 @@ ident != Id::init && ident != Id::__sizeof && ident != Id::alignof && ident != Id::offsetof && ident != Id::mangleof && ident != Id::stringof) - { + { /* Rewrite: + * p.ident + * as: + * (*p).ident + */ e = new PtrExp(loc, e1); e->type = ((TypePointer *)e1->type)->next; return e->type->dotExp(sc, e, ident); @@ -5598,7 +5708,7 @@ type = var->type; if (!type && global.errors) { // var is goofed up, just return 0 - return new IntegerExp(0); + return new ErrorExp(); } assert(type); @@ -5935,9 +6045,10 @@ : UnaExp(loc, TOKcall, sizeof(CallExp), e) { Expressions *arguments = new Expressions(); - arguments->setDim(1); - arguments->data[0] = (void *)earg1; - + if (earg1) + { arguments->setDim(1); + arguments->data[0] = (void *)earg1; + } this->arguments = arguments; } @@ -6040,7 +6151,7 @@ if (e1->op == TOKimport && !e1->type) { ScopeExp *se = (ScopeExp *)e1; TemplateInstance *ti = se->sds->isTemplateInstance(); - if (ti && !ti->semanticdone) + if (ti && !ti->semanticRun) { /* Attempt to instantiate ti. If that works, go with it. * If not, go with partial explicit specialization. @@ -6067,7 +6178,7 @@ if (e1->op == TOKdotti && !e1->type) { DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)e1; TemplateInstance *ti = se->ti; - if (!ti->semanticdone) + if (!ti->semanticRun) { /* Attempt to instantiate ti. If that works, go with it. * If not, go with partial explicit specialization. @@ -6163,6 +6274,36 @@ if (t1->ty == Tstruct) { ad = ((TypeStruct *)t1)->sym; +#if DMDV2 + // First look for constructor + if (ad->ctor && arguments && arguments->dim) + { + // Create variable that will get constructed + Identifier *idtmp = Lexer::uniqueId("__ctmp"); + VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL); + Expression *av = new DeclarationExp(loc, tmp); + av = new CommaExp(loc, av, new VarExp(loc, tmp)); + + Expression *e; + CtorDeclaration *cf = ad->ctor->isCtorDeclaration(); + if (cf) + e = new DotVarExp(loc, av, cf, 1); + else + { TemplateDeclaration *td = ad->ctor->isTemplateDeclaration(); + assert(td); + e = new DotTemplateExp(loc, av, td); + } + e = new CallExp(loc, e, arguments); +#if !STRUCTTHISREF + /* Constructors return a pointer to the instance + */ + e = new PtrExp(loc, e); +#endif + e = e->semantic(sc); + return e; + } +#endif + // No constructor, look for overload of opCall if (search_function(ad, Id::call)) goto L1; // overload of opCall, therefore it's a call @@ -6205,7 +6346,7 @@ f = dve->var->isFuncDeclaration(); assert(f); - f = f->overloadResolve(loc, arguments, sc->module); + f = f->overloadResolve(loc, NULL, arguments, sc->module); ad = f->toParent()->isAggregateDeclaration(); } @@ -6306,7 +6447,7 @@ sc->callSuper |= CSXany_ctor | CSXsuper_ctor; } - f = f->overloadResolve(loc, arguments, sc->module); + f = f->overloadResolve(loc, NULL, arguments, sc->module); checkDeprecated(sc, f); #if DMDV2 checkPurity(sc, f); @@ -6346,7 +6487,7 @@ } f = cd->ctor; - f = f->overloadResolve(loc, arguments, sc->module); + f = f->overloadResolve(loc, NULL, arguments, sc->module); checkDeprecated(sc, f); #if DMDV2 checkPurity(sc, f); @@ -6440,7 +6581,7 @@ } } - f = f->overloadResolve(loc, arguments, sc->module); + f = f->overloadResolve(loc, NULL, arguments, sc->module); checkDeprecated(sc, f); #if DMDV2 checkPurity(sc, f); @@ -6523,6 +6664,7 @@ #if DMDV2 int CallExp::canThrow() { + //printf("CallExp::canThrow() %s\n", toChars()); if (e1->canThrow()) return 1; @@ -6531,10 +6673,13 @@ for (size_t i = 0; i < arguments->dim; i++) { Expression *e = (Expression *)arguments->data[i]; - if (e->canThrow()) + if (e && e->canThrow()) return 1; } + if (global.errors && !e1->type) + return 0; // error recovery + /* If calling a function or delegate that is typed as nothrow, * then this expression cannot throw. * Note that pure functions can throw. @@ -6552,8 +6697,8 @@ #if DMDV2 int CallExp::isLvalue() { - if (type->toBasetype()->ty == Tstruct) - return 1; +// if (type->toBasetype()->ty == Tstruct) +// return 1; Type *tb = e1->type->toBasetype(); if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) return 1; // function returns a reference @@ -6563,12 +6708,28 @@ Expression *CallExp::toLvalue(Scope *sc, Expression *e) { +#if 1 if (type->toBasetype()->ty == Tstruct) return this; else +#endif return Expression::toLvalue(sc, e); } +Expression *CallExp::modifiableLvalue(Scope *sc, Expression *e) +{ +#if 1 + return Expression::modifiableLvalue(sc, e); +#else + /* Although function return values being usable as "ref" parameters is + * unsound, disabling it breaks existing code. + * Bugzilla 3167 + */ + error("cannot assign to function call"); + return toLvalue(sc, e); +#endif +} + void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { int i; @@ -6600,8 +6761,19 @@ if (!e1->type) { error("cannot take address of %s", e1->toChars()); - type = Type::tint32; - return this; + return new ErrorExp(); + } + if (!e1->type->deco) + { + /* No deco means semantic() was not run on the type. + * We have to run semantic() on the symbol to get the right type: + * auto x = &bar; + * pure: int bar() { return 1;} + * otherwise the 'pure' is missing from the type assigned to x. + */ + + error("forward reference to %s", e1->toChars()); + return new ErrorExp(); } type = e1->type->pointerTo(); @@ -6653,8 +6825,8 @@ PtrExp::PtrExp(Loc loc, Expression *e) : UnaExp(loc, TOKstar, sizeof(PtrExp), e) { - if (e->type) - type = ((TypePointer *)e->type)->next; +// if (e->type) +// type = ((TypePointer *)e->type)->next; } PtrExp::PtrExp(Loc loc, Expression *e, Type *t) @@ -6664,43 +6836,35 @@ } Expression *PtrExp::semantic(Scope *sc) -{ Type *tb; - +{ #if LOGSEMANTIC printf("PtrExp::semantic('%s')\n", toChars()); #endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (type) - return this; - if (!e1->type) - printf("PtrExp::semantic('%s')\n", toChars()); - tb = e1->type->toBasetype(); - switch (tb->ty) - { - case Tpointer: - type = tb->next; - if (type->isbit()) - { Expression *e; - - // Rewrite *p as p[0] - e = new IndexExp(loc, e1, new IntegerExp(0)); - return e->semantic(sc); - } - break; - - case Tsarray: - case Tarray: - type = tb->next; - e1 = e1->castTo(sc, type->pointerTo()); - break; - - default: - error("can only * a pointer, not a '%s'", e1->type->toChars()); - type = Type::tint32; - break; - } - rvalue(); + if (!type) + { + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + if (!e1->type) + printf("PtrExp::semantic('%s')\n", toChars()); + Type *tb = e1->type->toBasetype(); + switch (tb->ty) + { + case Tpointer: + type = tb->next; + break; + + case Tsarray: + case Tarray: + type = tb->next; + e1 = e1->castTo(sc, type->pointerTo()); + break; + + default: + error("can only * a pointer, not a '%s'", e1->type->toChars()); + return new ErrorExp(); + } + rvalue(); + } return this; } @@ -6766,7 +6930,7 @@ return e; e1->checkNoBool(); - if (e1->op != TOKslice) + if (!e1->isArrayOperand()) e1->checkArithmetic(); type = e1->type; } @@ -6816,7 +6980,7 @@ return e; e1->checkNoBool(); - if (e1->op != TOKslice) + if (!e1->isArrayOperand()) e1 = e1->checkIntegral(); type = e1->type; } @@ -7012,9 +7176,16 @@ return e->implicitCastTo(sc, to); } + if (e1->op == TOKtemplate) + { + error("cannot cast template %s to type %s", e1->toChars(), to->toChars()); + return new ErrorExp(); + } + + Type *t1b = e1->type->toBasetype(); Type *tob = to->toBasetype(); if (tob->ty == Tstruct && - !tob->equals(e1->type->toBasetype()) && + !tob->equals(t1b) && ((TypeStruct *)to)->sym->search(0, Id::call, 0) ) { @@ -7031,6 +7202,18 @@ e = e->semantic(sc); return e; } + + // Struct casts are possible only when the sizes match + if (tob->ty == Tstruct || t1b->ty == Tstruct) + { + size_t fromsize = t1b->size(loc); + size_t tosize = tob->size(loc); + if (fromsize != tosize) + { + error("cannot cast from %s to %s", e1->type->toChars(), to->toChars()); + return new ErrorExp(); + } + } } e = e1->castTo(sc, to); return e; @@ -7737,7 +7920,7 @@ /************************************************************/ -/* Can be TOKconstruct too */ +/* op can be TOKassign, TOKconstruct, or TOKblit */ AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) @@ -7746,26 +7929,39 @@ } Expression *AssignExp::semantic(Scope *sc) -{ Type *t1; +{ Expression *e1old = e1; #if LOGSEMANTIC printf("AssignExp::semantic('%s')\n", toChars()); #endif //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); + //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op)); + + if (type) + return this; + + if (e2->op == TOKcomma) + { /* Rewrite to get rid of the comma from rvalue + */ + AssignExp *ea = new AssignExp(loc, e1, ((CommaExp *)e2)->e2); + ea->op = op; + Expression *e = new CommaExp(loc, ((CommaExp *)e2)->e1, ea); + return e->semantic(sc); + } /* Look for operator overloading of a[i]=value. * Do it before semantic() otherwise the a[i] will have been * converted to a.opIndex() already. */ if (e1->op == TOKarray) - { Type *t1; + { ArrayExp *ae = (ArrayExp *)e1; AggregateDeclaration *ad; Identifier *id = Id::index; ae->e1 = ae->e1->semantic(sc); - t1 = ae->e1->type->toBasetype(); + Type *t1 = ae->e1->type->toBasetype(); if (t1->ty == Tstruct) { ad = ((TypeStruct *)t1)->sym; @@ -7880,13 +8076,20 @@ } } - t1 = e1->type->toBasetype(); + // Determine if this is an initialization of a reference + int refinit = 0; + if (op == TOKconstruct && e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v->storage_class & (STCout | STCref)) + refinit = 1; + } + + Type *t1 = e1->type->toBasetype(); if (t1->ty == Tfunction) { // Rewrite f=value to f(value) - Expression *e; - - e = new CallExp(loc, e1, e2); + Expression *e = new CallExp(loc, e1, e2); e = e->semantic(sc); return e; } @@ -7918,7 +8121,8 @@ else { // Try to do a decent error message with the expression // before it got constant folded - e1 = e1->modifiableLvalue(sc, e1old); + if (op != TOKconstruct) + e1 = e1->modifiableLvalue(sc, e1old); } if (e1->op == TOKslice && @@ -7930,7 +8134,7 @@ ismemset = 1; // make it easy for back end to tell what this is e2 = e2->implicitCastTo(sc, t1->next); } - else if (t1->ty == Tsarray) + else if (t1->ty == Tsarray && !refinit) { error("cannot assign to static array %s", e1->toChars()); } @@ -8061,6 +8265,7 @@ typeCombine(sc); e1->checkArithmetic(); e2->checkArithmetic(); + checkComplexAddAssign(); if (type->isreal() || type->isimaginary()) { assert(global.errors || e2->type->isfloating()); @@ -8111,6 +8316,7 @@ { e1 = e1->checkArithmetic(); e2 = e2->checkArithmetic(); + checkComplexAddAssign(); type = e1->type; typeCombine(sc); if (type->isreal() || type->isimaginary()) @@ -8215,6 +8421,7 @@ typeCombine(sc); e1->checkArithmetic(); e2->checkArithmetic(); + checkComplexMulAssign(); if (e2->type->isfloating()) { Type *t1; Type *t2; @@ -8281,6 +8488,7 @@ typeCombine(sc); e1->checkArithmetic(); e2->checkArithmetic(); + checkComplexMulAssign(); if (e2->type->isimaginary()) { Type *t1; Type *t2; @@ -8328,6 +8536,8 @@ Expression *ModAssignExp::semantic(Scope *sc) { + BinExp::semantic(sc); + checkComplexMulAssign(); return commonSemanticAssign(sc); } @@ -8736,10 +8946,10 @@ return e; typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkArithmetic(); + if (!e1->isArrayOperand()) + e1->checkArithmetic(); + if (!e2->isArrayOperand()) e2->checkArithmetic(); - } if (type->isfloating()) { Type *t1 = e1->type; Type *t2 = e2->type; @@ -8802,10 +9012,10 @@ return e; typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkArithmetic(); + if (!e1->isArrayOperand()) + e1->checkArithmetic(); + if (!e2->isArrayOperand()) e2->checkArithmetic(); - } if (type->isfloating()) { Type *t1 = e1->type; Type *t2 = e2->type; @@ -8869,10 +9079,10 @@ return e; typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkArithmetic(); + if (!e1->isArrayOperand()) + e1->checkArithmetic(); + if (!e2->isArrayOperand()) e2->checkArithmetic(); - } if (type->isfloating()) { type = e1->type; if (e2->type->iscomplex()) @@ -8983,10 +9193,10 @@ else { typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkIntegral(); + if (!e1->isArrayOperand()) + e1->checkIntegral(); + if (!e2->isArrayOperand()) e2->checkIntegral(); - } } } return this; @@ -9016,10 +9226,10 @@ else { typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkIntegral(); + if (!e1->isArrayOperand()) + e1->checkIntegral(); + if (!e2->isArrayOperand()) e2->checkIntegral(); - } } } return this; @@ -9049,10 +9259,10 @@ else { typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkIntegral(); + if (!e1->isArrayOperand()) + e1->checkIntegral(); + if (!e2->isArrayOperand()) e2->checkIntegral(); - } } } return this; @@ -9254,8 +9464,6 @@ Expression *CmpExp::semantic(Scope *sc) { Expression *e; - Type *t1; - Type *t2; #if LOGSEMANTIC printf("CmpExp::semantic('%s')\n", toChars()); @@ -9265,8 +9473,10 @@ BinExp::semanticp(sc); - if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || - e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + if (t1->ty == Tclass && e2->op == TOKnull || + t2->ty == Tclass && e1->op == TOKnull) { error("do not use null when comparing class types"); } @@ -9286,6 +9496,15 @@ return e; } + /* Disallow comparing T[]==T and T==T[] + */ + if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || + e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) + { + incompatibleTypes(); + return new ErrorExp(); + } + typeCombine(sc); type = Type::tboolean; @@ -9337,8 +9556,6 @@ Expression *EqualExp::semantic(Scope *sc) { Expression *e; - Type *t1; - Type *t2; //printf("EqualExp::semantic('%s')\n", toChars()); if (type) @@ -9367,8 +9584,10 @@ } } - if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || - e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + if (t1->ty == Tclass && e2->op == TOKnull || + t2->ty == Tclass && e1->op == TOKnull) { error("use '%s' instead of '%s' when comparing with null", Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity), @@ -9389,6 +9608,15 @@ } } + /* Disallow comparing T[]==T and T==T[] + */ + if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || + e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) + { + incompatibleTypes(); + return new ErrorExp(); + } + e = typeCombine(sc); type = Type::tboolean;
--- a/dmd/expression.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/expression.h Fri Nov 06 23:58:01 2009 +0100 @@ -81,6 +81,11 @@ Expression *fromConstInitializer(int result, Expression *e); int arrayExpressionCanThrow(Expressions *exps); +struct IntRange +{ uinteger_t imin; + uinteger_t imax; +}; + struct Expression : Object { Loc loc; // file location @@ -157,6 +162,7 @@ // For array ops virtual void buildArrayIdent(OutBuffer *buf, Expressions *arguments); virtual Expression *buildArrayLoop(Arguments *fparams); + int isArrayOperand(); #if IN_DMD // Back end @@ -291,6 +297,7 @@ struct DsymbolExp : Expression { Dsymbol *s; + int hasOverloads; DsymbolExp(Loc loc, Dsymbol *s); Expression *semantic(Scope *sc); @@ -306,6 +313,7 @@ ThisExp(Loc loc); Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); int isBool(int result); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *toLvalue(Scope *sc, Expression *e); @@ -343,6 +351,7 @@ NullExp(Loc loc); Expression *semantic(Scope *sc); int isBool(int result); + int isConst(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toMangleBuffer(OutBuffer *buf); MATCH implicitConvTo(Type *t); @@ -591,6 +600,7 @@ Type *newtype, Expressions *arguments); Expression *syntaxCopy(); Expression *semantic(Scope *sc); + Expression *optimize(int result); #if IN_DMD elem *toElem(IRState *irs); #endif @@ -842,6 +852,8 @@ Expression *commonSemanticAssign(Scope *sc); Expression *commonSemanticAssignIntegral(Scope *sc); int checkSideEffect(int flag); + void checkComplexMulAssign(); + void checkComplexAddAssign(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *scaleFactor(Scope *sc); Expression *typeCombine(Scope *sc); @@ -1022,6 +1034,7 @@ #endif void scanForNestedRef(Scope *sc); Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); @@ -1182,6 +1195,8 @@ int checkSideEffect(int flag); void checkEscape(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Arguments *fparams); #if IN_DMD elem *toElem(IRState *irs); #endif
--- a/dmd/func.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/func.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,3081 +1,3451 @@ -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <assert.h> - -#include "mars.h" -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "expression.h" -#include "scope.h" -#include "mtype.h" -#include "aggregate.h" -#include "identifier.h" -#include "id.h" -#include "module.h" -#include "statement.h" -#include "template.h" -#include "hdrgen.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -/********************************* FuncDeclaration ****************************/ - -FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) - : Declaration(id) -{ - //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - this->storage_class = storage_class; - this->type = type; - this->loc = loc; - this->endloc = endloc; - fthrows = NULL; - frequire = NULL; - outId = NULL; - vresult = NULL; - returnLabel = NULL; - fensure = NULL; - fbody = NULL; - localsymtab = NULL; - vthis = NULL; - v_arguments = NULL; -#if IN_GCC - v_argptr = NULL; -#endif - parameters = NULL; - labtab = NULL; - overnext = NULL; - vtblIndex = -1; - hasReturnExp = 0; - naked = 0; - inlineStatus = ILSuninitialized; - inlineNest = 0; - inlineAsm = 0; - cantInterpret = 0; - semanticRun = 0; - nestedFrameRef = 0; - fes = NULL; - introducing = 0; - tintro = NULL; - /* The type given for "infer the return type" is a TypeFunction with - * NULL for the return type. - */ - inferRetType = (type && type->nextOf() == NULL); - scope = NULL; - hasReturnExp = 0; - nrvo_can = 1; - nrvo_var = NULL; -#if IN_DMD - shidden = NULL; -#endif - -#if IN_LLVM - // LDC - isArrayOp = false; - allowInlining = false; - - availableExternally = true; // assume this unless proven otherwise - - // function types in ldc don't merge if the context parameter differs - // so we actually don't care about the function declaration, but only - // what kind of context parameter it has. - // however, this constructor is usually called from the parser, which - // unfortunately doesn't provide the information needed to get to the - // aggregate type. So we have to stick with the FuncDeclaration and - // just be sure we don't actually rely on the symbol it points to, - // but rather just the type of its context parameter. - // this means some function might have a function type pointing to - // another function declaration - - if (type) - { - assert(type->ty == Tfunction && "invalid function type"); - TypeFunction* tf = (TypeFunction*)type; - if (tf->funcdecl == NULL) - tf->funcdecl = this; - } -#endif -} - -Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncDeclaration *f; - - //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncDeclaration *)s; - else - f = new FuncDeclaration(loc, endloc, ident, (enum STC) storage_class, type->syntaxCopy()); - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - // LDC - f->intrinsicName = intrinsicName; - - return f; -} - - -// Do the semantic analysis on the external interface to the function. - -void FuncDeclaration::semantic(Scope *sc) -{ TypeFunction *f; - StructDeclaration *sd; - ClassDeclaration *cd; - InterfaceDeclaration *id; - Dsymbol *pd; - -#if 0 - printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); - if (isFuncLiteralDeclaration()) - printf("\tFuncLiteralDeclaration()\n"); - printf("sc->parent = %s\n", sc->parent->toChars()); - printf("type: %p, %s\n", type, type->toChars()); -#endif - - if (semanticRun && isFuncLiteralDeclaration()) - { - /* Member functions that have return types that are - * forward references can have semantic() run more than - * once on them. - * See test\interface2.d, test20 - */ - return; - } - assert(semanticRun <= 1); - semanticRun = 1; - - if (type->nextOf()) - type = type->semantic(loc, sc); - //type->print(); - if (type->ty != Tfunction) - { - error("%s must be a function", toChars()); - return; - } - f = (TypeFunction *)(type); - size_t nparams = Argument::dim(f->parameters); - - linkage = sc->linkage; -// if (!parent) - { - //parent = sc->scopesym; - parent = sc->parent; - } - protection = sc->protection; - storage_class |= sc->stc; - //printf("function storage_class = x%x\n", storage_class); - Dsymbol *parent = toParent(); - - if (ident == Id::ctor && !isCtorDeclaration()) - error("_ctor is reserved for constructors"); - - if (isConst() || isAuto() || isScope()) - error("functions cannot be const, auto or scope"); - - if (isAbstract() && !isVirtual()) - error("non-virtual functions cannot be abstract"); - - if (isAbstract() && isFinal()) - error("cannot be both final and abstract"); -#if 0 - if (isAbstract() && fbody) - error("abstract functions cannot have bodies"); -#endif - -#if 0 - if (isStaticConstructor() || isStaticDestructor()) - { - if (!isStatic() || type->nextOf()->ty != Tvoid) - error("static constructors / destructors must be static void"); - if (f->arguments && f->arguments->dim) - error("static constructors / destructors must have empty parameter list"); - // BUG: check for invalid storage classes - } -#endif - -#ifdef IN_GCC - AggregateDeclaration *ad; - - ad = parent->isAggregateDeclaration(); - if (ad) - ad->methods.push(this); -#endif - sd = parent->isStructDeclaration(); - if (sd) - { - // Verify no constructors, destructors, etc. - if (isCtorDeclaration() || - isDtorDeclaration() - //|| isInvariantDeclaration() - //|| isUnitTestDeclaration() - ) - { - error("special member functions not allowed for %ss", sd->kind()); - } - -#if 0 - if (!sd->inv) - sd->inv = isInvariantDeclaration(); - - if (!sd->aggNew) - sd->aggNew = isNewDeclaration(); - - if (isDelete()) - { - if (sd->aggDelete) - error("multiple delete's for struct %s", sd->toChars()); - sd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - } - - id = parent->isInterfaceDeclaration(); - if (id) - { - storage_class |= STCabstract; - - if (isCtorDeclaration() || - isDtorDeclaration() || - isInvariantDeclaration() || - isUnitTestDeclaration() || isNewDeclaration() || isDelete()) - error("special function not allowed in interface %s", id->toChars()); - if (fbody) - error("function body is not abstract in interface %s", id->toChars()); - } - - /* Template member functions aren't virtual: - * interface TestInterface { void tpl(T)(); } - * and so won't work in interfaces - */ - if ((pd = toParent()) != NULL && - pd->isTemplateInstance() && - (pd = toParent2()) != NULL && - (id = pd->isInterfaceDeclaration()) != NULL) - { - error("template member function not allowed in interface %s", id->toChars()); - } - - cd = parent->isClassDeclaration(); - if (cd) - { int vi; - CtorDeclaration *ctor; - DtorDeclaration *dtor; - InvariantDeclaration *inv; - - if (isCtorDeclaration()) - { -// ctor = (CtorDeclaration *)this; -// if (!cd->ctor) -// cd->ctor = ctor; - return; - } - -#if 0 - dtor = isDtorDeclaration(); - if (dtor) - { - if (cd->dtor) - error("multiple destructors for class %s", cd->toChars()); - cd->dtor = dtor; - } - - inv = isInvariantDeclaration(); - if (inv) - { - cd->inv = inv; - } - - if (isNewDeclaration()) - { - if (!cd->aggNew) - cd->aggNew = (NewDeclaration *)(this); - } - - if (isDelete()) - { - if (cd->aggDelete) - error("multiple delete's for class %s", cd->toChars()); - cd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - - if (storage_class & STCabstract) - cd->isabstract = 1; - - // if static function, do not put in vtbl[] - if (!isVirtual()) - { - //printf("\tnot virtual\n"); - goto Ldone; - } - - // Find index of existing function in vtbl[] to override - vi = findVtblIndex(&cd->vtbl, cd->baseClass ? cd->baseClass->vtbl.dim : 0); - switch (vi) - { - case -1: - /* Didn't find one, so - * This is an 'introducing' function which gets a new - * slot in the vtbl[]. - */ - - // Verify this doesn't override previous final function - if (cd->baseClass) - { Dsymbol *s = cd->baseClass->search(loc, ident, 0); - if (s) - { - FuncDeclaration *f = s->isFuncDeclaration(); - f = f->overloadExactMatch(type, getModule()); - if (f && f->isFinal() && f->prot() != PROTprivate) - error("cannot override final function %s", f->toPrettyChars()); - } - } - - if (isFinal()) - { - if (isOverride()) - error("does not override any function"); - cd->vtblFinal.push(this); - } - else - { - // Append to end of vtbl[] - //printf("\tintroducing function\n"); - introducing = 1; - vi = cd->vtbl.dim; - cd->vtbl.push(this); - vtblIndex = vi; - } - break; - - case -2: // can't determine because of fwd refs - cd->sizeok = 2; // can't finish due to forward reference - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)cd->vtbl.data[vi]; - // This function is covariant with fdv - if (fdv->isFinal()) - error("cannot override final function %s", fdv->toPrettyChars()); - -#if DMDV2 - if (!isOverride()) - warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); -#endif - - if (fdv->toParent() == parent) - { - // If both are mixins, then error. - // If either is not, the one that is not overrides - // the other. - if (fdv->parent->isClassDeclaration()) - break; - if (!this->parent->isClassDeclaration() -#if !BREAKABI - && !isDtorDeclaration() -#endif -#if DMDV2 - && !isPostBlitDeclaration() -#endif - ) - error("multiple overrides of same function"); - } - cd->vtbl.data[vi] = (void *)this; - vtblIndex = vi; - - /* This works by whenever this function is called, - * it actually returns tintro, which gets dynamically - * cast to type. But we know that tintro is a base - * of type, so we could optimize it by not doing a - * dynamic cast, but just subtracting the isBaseOf() - * offset if the value is != null. - */ - - if (fdv->tintro) - tintro = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - tintro = fdv->type; - } - } - break; - } - } - - /* Go through all the interface bases. - * If this function is covariant with any members of those interface - * functions, set the tintro. - */ - for (int i = 0; i < cd->interfaces_dim; i++) - { -#if 1 - BaseClass *b = cd->interfaces[i]; - vi = findVtblIndex(&b->base->vtbl, b->base->vtbl.dim); - switch (vi) - { - case -1: - break; - - case -2: - cd->sizeok = 2; // can't finish due to forward reference - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; - Type *ti = NULL; - - if (fdv->tintro) - ti = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - ti = fdv->type; -#if 0 - if (offset) - ti = fdv->type; - else if (type->nextOf()->ty == Tclass) - { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; - if (cdn && cdn->sizeok != 1) - ti = fdv->type; - } -#endif - } - } - if (ti) - { - if (tintro && !tintro->equals(ti)) - { - error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); - } - tintro = ti; - } - goto L2; - } - } -#else - BaseClass *b = cd->interfaces[i]; - for (vi = 0; vi < b->base->vtbl.dim; vi++) - { - Dsymbol *s = (Dsymbol *)b->base->vtbl.data[vi]; - //printf("interface %d vtbl[%d] %p %s\n", i, vi, s, s->toChars()); - FuncDeclaration *fdv = s->isFuncDeclaration(); - if (fdv && fdv->ident == ident) - { - int cov = type->covariant(fdv->type); - //printf("\tcov = %d\n", cov); - if (cov == 2) - { - //type->print(); - //fdv->type->print(); - //printf("%s %s\n", type->deco, fdv->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); - } - if (cov == 1) - { Type *ti = NULL; - - if (fdv->tintro) - ti = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - ti = fdv->type; -#if 0 - if (offset) - ti = fdv->type; - else if (type->nextOf()->ty == Tclass) - { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; - if (cdn && cdn->sizeok != 1) - ti = fdv->type; - } -#endif - } - } - if (ti) - { - if (tintro && !tintro->equals(ti)) - { - error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); - } - tintro = ti; - } - goto L2; - } - if (cov == 3) - { - cd->sizeok = 2; // can't finish due to forward reference - return; - } - } - } -#endif - } - - if (introducing && isOverride()) - { - error("does not override any function"); - } - - L2: ; - } - else if (isOverride() && !parent->isTemplateInstance()) - error("override only applies to class member functions"); - - /* Do not allow template instances to add virtual functions - * to a class. - */ - if (isVirtual()) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - ClassDeclaration *cd = ti->tempdecl->isClassMember(); - if (cd) - { - error("cannot use template to add virtual function to class '%s'", cd->toChars()); - } - } - } - - if (isMain()) - { - // Check parameters to see if they are either () or (char[][] args) - switch (nparams) - { - case 0: - break; - - case 1: - { - Argument *arg0 = Argument::getNth(f->parameters, 0); - if (arg0->type->ty != Tarray || - arg0->type->nextOf()->ty != Tarray || - arg0->type->nextOf()->nextOf()->ty != Tchar || - arg0->storageClass & (STCout | STCref | STClazy)) - goto Lmainerr; - break; - } - - default: - goto Lmainerr; - } - - if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) - error("must return int or void, not %s", f->nextOf()->toChars()); - if (f->varargs) - { - Lmainerr: - error("parameters must be main() or main(char[][] args)"); - } - } - - if (ident == Id::assign && (sd || cd)) - { // Disallow identity assignment operator. - - // opAssign(...) - if (nparams == 0) - { if (f->varargs == 1) - goto Lassignerr; - } - else - { - Argument *arg0 = Argument::getNth(f->parameters, 0); - Type *t0 = arg0->type->toBasetype(); - Type *tb = sd ? sd->type : cd->type; - if (arg0->type->implicitConvTo(tb) || - (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) - ) - { - if (nparams == 1) - goto Lassignerr; - Argument *arg1 = Argument::getNth(f->parameters, 1); - if (arg1->defaultArg) - goto Lassignerr; - } - } - } - -Ldone: - /* Save scope for possible later use (if we need the - * function internals) - */ - scope = new Scope(*sc); - scope->setNoFree(); - return; - -Lassignerr: - error("identity assignment operator overload is illegal"); -} - -void FuncDeclaration::semantic2(Scope *sc) -{ -} - -// Do the semantic analysis on the internals of the function. - -void FuncDeclaration::semantic3(Scope *sc) -{ TypeFunction *f; - AggregateDeclaration *ad; - VarDeclaration *argptr = NULL; - VarDeclaration *_arguments = NULL; - - if (!parent) - { - if (global.errors) - return; - //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); - assert(0); - } - //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); - //fflush(stdout); - //{ static int x; if (++x == 2) *(char*)0=0; } - //printf("\tlinkage = %d\n", sc->linkage); - - //printf(" sc->incontract = %d\n", sc->incontract); - if (semanticRun >= 3) - return; - semanticRun = 3; - - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - if (!type || type->ty != Tfunction) - return; - f = (TypeFunction *)(type); - size_t nparams = Argument::dim(f->parameters); - - // Check the 'throws' clause - if (fthrows) - { - for (int i = 0; i < fthrows->dim; i++) - { - Type *t = (Type *)fthrows->data[i]; - - t = t->semantic(loc, sc); - if (!t->isClassHandle()) - error("can only throw classes, not %s", t->toChars()); - } - } - - if (fbody || frequire) - { - /* Symbol table into which we place parameters and nested functions, - * solely to diagnose name collisions. - */ - localsymtab = new DsymbolTable(); - - // Establish function scope - ScopeDsymbol *ss = new ScopeDsymbol(); - ss->parent = sc->scopesym; - Scope *sc2 = sc->push(ss); - sc2->func = this; - sc2->parent = this; - sc2->callSuper = 0; - sc2->sbreak = NULL; - sc2->scontinue = NULL; - sc2->sw = NULL; - sc2->fes = fes; - sc2->linkage = LINKd; - sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STCfinal); - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - sc2->structalign = 8; - sc2->incontract = 0; - sc2->enclosingFinally = NULL; - sc2->enclosingScopeExit = NULL; - sc2->noctor = 0; - - // Declare 'this' - ad = isThis(); - if (ad) - { VarDeclaration *v; - - if (isFuncLiteralDeclaration() && isNested()) - { - error("literals cannot be class members"); - return; - } - else - { - assert(!isNested()); // can't be both member and nested - assert(ad->handle); - v = new ThisDeclaration(loc, ad->handle); - v->storage_class |= STCparameter | STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - } - else if (isNested()) - { - /* The 'this' for a nested function is the link to the - * enclosing function's stack frame. - * Note that nested functions and member functions are disjoint. - */ - VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo()); - v->storage_class |= STCparameter | STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - - // Declare hidden variable _arguments[] and _argptr - if (f->varargs == 1) - { Type *t; - - if (f->linkage == LINKd) - { // Declare _arguments[] -#if BREAKABI - v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; - - t = Type::typeinfo->type->arrayOf(); - _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - _arguments->semantic(sc2); - sc2->insert(_arguments); - _arguments->parent = this; -#else - t = Type::typeinfo->type->arrayOf(); - v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; -#endif - } - if (f->linkage == LINKd || (parameters && parameters->dim)) - { // Declare _argptr -#if IN_GCC - t = d_gcc_builtin_va_list_d_type; -#else - t = Type::tvoid->pointerTo(); -#endif - argptr = new VarDeclaration(0, t, Id::_argptr, NULL); - argptr->semantic(sc2); - sc2->insert(argptr); - argptr->parent = this; - } - } - -#if IN_LLVM - // LDC make sure argument type is semanticed. - // Turns TypeTuple!(int, int) into two int parameters, for instance. - if (f->parameters) - { - for (size_t i = 0; i < Argument::dim(f->parameters); i++) - { Argument *arg = (Argument *)Argument::getNth(f->parameters, i); - Type* nw = arg->type->semantic(0, sc); - if (arg->type != nw) { - arg->type = nw; - // Examine this index again. - // This is important if it turned into a tuple. - // In particular, the empty tuple should be handled or the - // next parameter will be skipped. - // FIXME: Maybe we only need to do this for tuples, - // and can add tuple.length after decrement? - i--; - } - } - // update nparams to include expanded tuples - nparams = Argument::dim(f->parameters); - } -#endif - - // Propagate storage class from tuple parameters to their element-parameters. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Argument *arg = (Argument *)f->parameters->data[i]; - - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Argument::dim(t->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *narg = Argument::getNth(t->arguments, j); - narg->storageClass = arg->storageClass; - } - } - } - } - - // Declare all the function parameters as variables - if (nparams) - { /* parameters[] has all the tuples removed, as the back end - * doesn't know about tuples - */ - parameters = new Dsymbols(); - parameters->reserve(nparams); - for (size_t i = 0; i < nparams; i++) - { - Argument *arg = Argument::getNth(f->parameters, i); - Identifier *id = arg->ident; - if (!id) - { - /* Generate identifier for un-named parameter, - * because we need it later on. - */ - arg->ident = id = Identifier::generateId("_param_", i); - } - VarDeclaration *v = new VarDeclaration(loc, arg->type, id, NULL); - //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); - v->storage_class |= STCparameter; - if (f->varargs == 2 && i + 1 == nparams) - v->storage_class |= STCvariadic; - v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy); - if (v->storage_class & STClazy) - v->storage_class |= STCin; - v->semantic(sc2); - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - parameters->push(v); - localsymtab->insert(v); - v->parent = this; - } - } - - // Declare the tuple symbols and put them in the symbol table, - // but not in parameters[]. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Argument *arg = (Argument *)f->parameters->data[i]; - - if (!arg->ident) - continue; // never used, so ignore - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Argument::dim(t->arguments); - Objects *exps = new Objects(); - exps->setDim(dim); - for (size_t j = 0; j < dim; j++) - { Argument *narg = Argument::getNth(t->arguments, j); - assert(narg->ident); - VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); - assert(v); - Expression *e = new VarExp(v->loc, v); - exps->data[j] = (void *)e; - } - assert(arg->ident); - TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); - //printf("declaring tuple %s\n", v->toChars()); - v->isexp = 1; - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - localsymtab->insert(v); - v->parent = this; - } - } - } - - /* Do the semantic analysis on the [in] preconditions and - * [out] postconditions. - */ - sc2->incontract++; - - if (frequire) - { /* frequire is composed of the [in] contracts - */ - // BUG: need to error if accessing out parameters - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - // BUG: verify that all in and ref parameters are read - frequire = frequire->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (fensure || addPostInvariant()) - { /* fensure is composed of the [out] contracts - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - sc2 = sc2->push(sym); - - assert(type->nextOf()); - if (type->nextOf()->ty == Tvoid) - { - if (outId) - error("void functions have no result"); - } - else - { - if (!outId) - outId = Id::result; // provide a default - } - - if (outId) - { // Declare result variable - VarDeclaration *v; - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - v->noscope = 1; - sc2->incontract--; - v->semantic(sc2); - sc2->incontract++; - if (!sc2->insert(v)) - error("out result %s is already defined", v->toChars()); - v->parent = this; - vresult = v; - - // vresult gets initialized with the function return value - // in ReturnStatement::semantic() - } - - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - if (fensure) - { fensure = fensure->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (!global.params.useOut) - { fensure = NULL; // discard - vresult = NULL; - } - - // Postcondition invariant - if (addPostInvariant()) - { - Expression *e = NULL; - if (isCtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - ThisExp *v = new ThisExp(0); - v->type = vthis->type; - e = new AssertExp(0, v); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - if (fensure) - fensure = new CompoundStatement(0, s, fensure); - else - fensure = s; - } - } - - if (fensure) - { returnLabel = new LabelDsymbol(Id::returnLabel); - LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); - ls->isReturnLabel = 1; - returnLabel->statement = ls; - } - sc2 = sc2->pop(); - } - - sc2->incontract--; - - if (fbody) - { ClassDeclaration *cd = isClassMember(); - - /* If this is a class constructor - */ - if (isCtorDeclaration() && cd) - { - for (int i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - v->ctorinit = 0; - } - } - - if (inferRetType || f->retStyle() != RETstack) - nrvo_can = 0; - - fbody = fbody->semantic(sc2); - - if (inferRetType) - { // If no return type inferred yet, then infer a void - if (!type->nextOf()) - { - ((TypeFunction *)type)->next = Type::tvoid; - type = type->semantic(loc, sc); - } - f = (TypeFunction *)type; - } - - int offend = fbody ? fbody->blockExit() & BEfallthru : TRUE; - - if (isStaticCtorDeclaration()) - { /* It's a static constructor. Ensure that all - * ctor consts were initialized. - */ - - Dsymbol *p = toParent(); - ScopeDsymbol *ad = p->isScopeDsymbol(); - if (!ad) - { - error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); - } - else - { - for (int i = 0; i < ad->members->dim; i++) - { Dsymbol *s = (Dsymbol *)ad->members->data[i]; - - s->checkCtorConstInit(); - } - } - } - - if (isCtorDeclaration() && cd) - { - //printf("callSuper = x%x\n", sc2->callSuper); - - // Verify that all the ctorinit fields got initialized - if (!(sc2->callSuper & CSXthis_ctor)) - { - for (int i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - if (v->ctorinit == 0 && v->isCtorinit()) - error("missing initializer for const field %s", v->toChars()); - } - } - - if (!(sc2->callSuper & CSXany_ctor) && - cd->baseClass && cd->baseClass->ctor) - { - sc2->callSuper = 0; - - // Insert implicit super() at start of fbody - Expression *e1 = new SuperExp(0); - Expression *e = new CallExp(0, e1); - - unsigned errors = global.errors; - global.gag++; - e = e->semantic(sc2); - global.gag--; - if (errors != global.errors) - error("no match for implicit super() call in constructor"); - - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, s, fbody); - } - } - else if (fes) - { // For foreach(){} body, append a return 0; - Expression *e = new IntegerExp(0); - Statement *s = new ReturnStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - assert(!returnLabel); - } - else if (!hasReturnExp && type->nextOf()->ty != Tvoid) - error("expected to return a value of type %s", type->nextOf()->toChars()); - else if (!inlineAsm) - { - if (type->nextOf()->ty == Tvoid) - { - if (offend && isMain()) - { // Add a return 0; statement - Statement *s = new ReturnStatement(0, new IntegerExp(0)); - fbody = new CompoundStatement(0, fbody, s); - } - } - else - { - if (offend) - { Expression *e; - - warning(loc, "no return at end of function"); - - if (global.params.useAssert && - !global.params.useInline) - { /* Add an assert(0, msg); where the missing return - * should be. - */ - e = new AssertExp( - endloc, - new IntegerExp(0), - new StringExp(loc, (char *)"missing return expression") - ); - } - else - e = new HaltExp(endloc); - e = new CommaExp(0, e, type->nextOf()->defaultInit()); - e = e->semantic(sc2); - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - } - } - } - } - - { - Statements *a = new Statements(); - - // Merge in initialization of 'out' parameters - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - if (v->storage_class & STCout) - { - assert(v->init); - ExpInitializer *ie = v->init->isExpInitializer(); - assert(ie); - a->push(new ExpStatement(0, ie->exp)); - } - } - } - -// we'll handle variadics ourselves -#if !IN_LLVM - if (argptr) - { // Initialize _argptr to point past non-variadic arg -#if IN_GCC - // Handled in FuncDeclaration::toObjFile - v_argptr = argptr; - v_argptr->init = new VoidInitializer(loc); -#else - Expression *e1; - Expression *e; - Type *t = argptr->type; - VarDeclaration *p; - unsigned offset; - - e1 = new VarExp(0, argptr); - if (parameters && parameters->dim) - p = (VarDeclaration *)parameters->data[parameters->dim - 1]; - else - p = v_arguments; // last parameter is _arguments[] - offset = p->type->size(); - offset = (offset + 3) & ~3; // assume stack aligns on 4 - e = new SymOffExp(0, p, offset); - e = new AssignExp(0, e1, e); - e->type = t; - a->push(new ExpStatement(0, e)); -#endif // IN_GCC - } - - if (_arguments) - { - /* Advance to elements[] member of TypeInfo_Tuple with: - * _arguments = v_arguments.elements; - */ - Expression *e = new VarExp(0, v_arguments); - e = new DotIdExp(0, e, Id::elements); - Expression *e1 = new VarExp(0, _arguments); - e = new AssignExp(0, e1, e); - e = e->semantic(sc); - a->push(new ExpStatement(0, e)); - } - -#endif // !IN_LLVM - - // Merge contracts together with body into one compound statement - -#ifdef _DH - if (frequire && global.params.useIn) - { frequire->incontract = 1; - a->push(frequire); - } -#else - if (frequire && global.params.useIn) - a->push(frequire); -#endif - - // Precondition invariant - if (addPreInvariant()) - { - Expression *e = NULL; - Expression *ee = NULL; - if (isDtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - // LDC: unless this is a struct without invariant - StructDeclaration* sd = ad->isStructDeclaration(); - if (!sd || sd->inv) - { - ThisExp *v = new ThisExp(0); - v->type = vthis->type; - e = new AssertExp(loc, v, NULL); - } - - // LDC: check for null this - ThisExp* v = new ThisExp(0); - v->type = vthis->type; - v->var = vthis; - - NullExp *nv = new NullExp(0); - nv->type = v->type; - - IdentityExp *ie = new IdentityExp(TOKnotidentity, 0, v, nv); - ie->type = Type::tbool; - - Expression *se = new StringExp(0, (char *)"null this"); - se = se->semantic(sc); - se->type = Type::tchar->arrayOf(); - - ee = new AssertExp(loc, ie, se); - } - if (ee) - { - ExpStatement *s = new ExpStatement(0, ee); - a->push(s); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - a->push(s); - } - } - - if (fbody) - a->push(fbody); - - if (fensure) - { - a->push(returnLabel->statement); - - if (type->nextOf()->ty != Tvoid) - { - // Create: return vresult; - assert(vresult); - Expression *e = new VarExp(0, vresult); - if (tintro) - { e = e->implicitCastTo(sc, tintro->nextOf()); - e = e->semantic(sc); - } - ReturnStatement *s = new ReturnStatement(0, e); - a->push(s); - } - } - - fbody = new CompoundStatement(0, a); - - // wrap body of synchronized functions in a synchronized statement - if (isSynchronized()) - { - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd) - error("synchronized function %s must be a member of a class", toChars()); - - Expression *sync; - if (isStatic()) - { - // static member functions synchronize on classinfo - sync = cd->type->dotExp(sc2, new TypeExp(loc, cd->type), Id::classinfo); - } - else - { - // non-static member functions synchronize on this - sync = new VarExp(loc, vthis); - } - - // we do not want to rerun semantics on the whole function, so we - // manually adjust all labels in the function that currently don't - // have an enclosingScopeExit to use the new SynchronizedStatement - SynchronizedStatement* s = new SynchronizedStatement(loc, sync, NULL); - s->semantic(sc2); - s->body = fbody; - - // LDC - LabelMap::iterator it, end = labmap.end(); - for (it = labmap.begin(); it != end; ++it) - if (it->second->enclosingScopeExit == NULL) - it->second->enclosingScopeExit = s; - - a = new Statements; - a->push(s); - fbody = new CompoundStatement(0, a); - } - } - - sc2->callSuper = 0; - sc2->pop(); - } - semanticRun = 4; -} - -void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); - - type->toCBuffer(buf, ident, hgs); - bodyToCBuffer(buf, hgs); -} - - -void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (fbody && - (!hgs->hdrgen || hgs->tpltMember || canInline(1,1)) - ) - { buf->writenl(); - - // in{} - if (frequire) - { buf->writestring("in"); - buf->writenl(); - frequire->toCBuffer(buf, hgs); - } - - // out{} - if (fensure) - { buf->writestring("out"); - if (outId) - { buf->writebyte('('); - buf->writestring(outId->toChars()); - buf->writebyte(')'); - } - buf->writenl(); - fensure->toCBuffer(buf, hgs); - } - - if (frequire || fensure) - { buf->writestring("body"); - buf->writenl(); - } - - buf->writebyte('{'); - buf->writenl(); - fbody->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { buf->writeByte(';'); - buf->writenl(); - } -} - -/**************************************************** - * Determine if 'this' overrides fd. - * Return !=0 if it does. - */ - -int FuncDeclaration::overrides(FuncDeclaration *fd) -{ int result = 0; - - if (fd->ident == ident) - { - int cov = type->covariant(fd->type); - if (cov) - { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); - ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); - - if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) - result = 1; - } - } - return result; -} - -/************************************************* - * Find index of function in vtbl[0..dim] that - * this function overrides. - * Returns: - * -1 didn't find one - * -2 can't determine because of forward references - */ - -int FuncDeclaration::findVtblIndex(Array *vtbl, int dim) -{ - for (int vi = 0; vi < dim; vi++) - { - FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration(); - if (fdv && fdv->ident == ident) - { - int cov = type->covariant(fdv->type); - //printf("\tbaseclass cov = %d\n", cov); - switch (cov) - { - case 0: // types are distinct - break; - - case 1: - return vi; - - case 2: - //type->print(); - //fdv->type->print(); - //printf("%s %s\n", type->deco, fdv->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); - break; - - case 3: - return -2; // forward references - - default: - assert(0); - } - } - } - return -1; -} - -/**************************************************** - * Overload this FuncDeclaration with the new one f. - * Return !=0 if successful; i.e. no conflict. - */ - -int FuncDeclaration::overloadInsert(Dsymbol *s) -{ - FuncDeclaration *f; - AliasDeclaration *a; - - //printf("FuncDeclaration::overloadInsert(%s)\n", s->toChars()); - a = s->isAliasDeclaration(); - if (a) - { - if (overnext) - return overnext->overloadInsert(a); - if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) - { - //printf("\ta = '%s'\n", a->type->toChars()); - return FALSE; - } - overnext = a; - //printf("\ttrue: no conflict\n"); - return TRUE; - } - f = s->isFuncDeclaration(); - if (!f) - return FALSE; - - if (type && f->type && // can be NULL for overloaded constructors - f->type->covariant(type) && - !isFuncAliasDeclaration()) - { - //printf("\tfalse: conflict %s\n", kind()); - return FALSE; - } - - if (overnext) - return overnext->overloadInsert(f); - overnext = f; - //printf("\ttrue: no conflict\n"); - return TRUE; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -/*************************************************** - * Visit each overloaded function in turn, and call - * (*fp)(param, f) on it. - * Exit when no more, or (*fp)(param, f) returns 1. - * Returns: - * 0 continue - * 1 done - */ - -int overloadApply(Module* from, FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param) -{ - FuncDeclaration *f; - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) - { - if (fa->getModule() == from || fa->importprot != PROTprivate) - if (overloadApply(from, fa->funcalias, fp, param)) - return 1; - next = fa->overnext; - } - else - { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - if (a->importprot == PROTprivate && a->getModule() != from) - if (FuncDeclaration* fd = next->isFuncDeclaration()) - next = fd->overnext; - } - else - { - f = d->isFuncDeclaration(); - if (!f) - { d->error("is aliased to a function"); - break; // BUG: should print error message? - } - if ((*fp)(param, f)) - return 1; - - next = f->overnext; - } - } - } - return 0; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -struct Param1 -{ - Type *t; // type to match - FuncDeclaration *f; // return value -}; - -int fp1(void *param, FuncDeclaration *f) -{ Param1 *p = (Param1 *)param; - Type *t = p->t; - - if (t->equals(f->type)) - { p->f = f; - return 1; - } - -#if DMDV2 - /* Allow covariant matches, if it's just a const conversion - * of the return type - */ - if (t->ty == Tfunction) - { TypeFunction *tf = (TypeFunction *)f->type; - if (tf->covariant(t) == 1 && - tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) - { - p->f = f; - return 1; - } - } -#endif - return 0; -} - -FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t, Module* from) -{ - Param1 p; - p.t = t; - p.f = NULL; - overloadApply(from, this, &fp1, &p); - return p.f; -} - -#if 0 -FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t) -{ - FuncDeclaration *f; - Declaration *d; - Declaration *next; - - for (d = this; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) - { - FuncDeclaration *f2 = fa->funcalias->overloadExactMatch(t); - if (f2) - return f2; - next = fa->overnext; - } - else - { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - } - else - { - f = d->isFuncDeclaration(); - if (!f) - break; // BUG: should print error message? - if (t->equals(d->type)) - return f; - next = f->overnext; - } - } - } - return NULL; -} -#endif - -/******************************************** - * Decide which function matches the arguments best. - */ - -struct Param2 -{ - Match *m; - Expressions *arguments; -}; - -int fp2(void *param, FuncDeclaration *f) -{ Param2 *p = (Param2 *)param; - Match *m = p->m; - Expressions *arguments = p->arguments; - MATCH match; - - if (f != m->lastf) // skip duplicates - { - m->anyf = f; - TypeFunction *tf = (TypeFunction *)f->type; - match = (MATCH) tf->callMatch(arguments); - //printf("1match = %d\n", match); - if (match != MATCHnomatch) - { - if (match > m->last) - goto LfIsBetter; - - if (match < m->last) - goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - if (m->lastf->overrides(f)) - goto LlastIsBetter; - else if (f->overrides(m->lastf)) - goto LfIsBetter; - - Lambiguous: - m->nextf = f; - m->count++; - return 0; - - LfIsBetter: - m->last = match; - m->lastf = f; - m->count = 1; - return 0; - - LlastIsBetter: - return 0; - } - } - return 0; -} - - -void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments, Module* from) -{ - Param2 p; - p.m = m; - p.arguments = arguments; - overloadApply(from, fstart, &fp2, &p); -} - -#if 0 -// Recursive helper function - -void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments) -{ - MATCH match; - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { - FuncDeclaration *f; - FuncAliasDeclaration *fa; - AliasDeclaration *a; - - fa = d->isFuncAliasDeclaration(); - if (fa) - { - overloadResolveX(m, fa->funcalias, arguments); - next = fa->overnext; - } - else if ((f = d->isFuncDeclaration()) != NULL) - { - next = f->overnext; - if (f == m->lastf) - continue; // skip duplicates - else - { - TypeFunction *tf; - - m->anyf = f; - tf = (TypeFunction *)f->type; - match = (MATCH) tf->callMatch(arguments); - //printf("2match = %d\n", match); - if (match != MATCHnomatch) - { - if (match > m->last) - goto LfIsBetter; - - if (match < m->last) - goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - if (m->lastf->overrides(f)) - goto LlastIsBetter; - else if (f->overrides(m->lastf)) - goto LfIsBetter; - - Lambiguous: - m->nextf = f; - m->count++; - continue; - - LfIsBetter: - m->last = match; - m->lastf = f; - m->count = 1; - continue; - - LlastIsBetter: - continue; - } - } - } - else if ((a = d->isAliasDeclaration()) != NULL) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - } - else - { d->error("is aliased to a function"); - break; - } - } -} -#endif - -FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expressions *arguments, Module* from) -{ - TypeFunction *tf; - Match m; - -#if 0 -printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); -if (arguments) -{ int i; - - for (i = 0; i < arguments->dim; i++) - { Expression *arg; - - arg = (Expression *)arguments->data[i]; - assert(arg->type); - printf("\t%s: ", arg->toChars()); - arg->type->print(); - } -} -#endif - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - overloadResolveX(&m, this, arguments, from); - - if (m.count == 1) // exactly one match - { - return m.lastf; - } - else - { - OutBuffer buf; - - if (arguments) - { - HdrGenState hgs; - - argExpTypesToCBuffer(&buf, arguments, &hgs); - } - - if (m.last == MATCHnomatch) - { - tf = (TypeFunction *)type; - - //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); - error(loc, "%s does not match parameter types (%s)", - Argument::argsTypesToChars(tf->parameters, tf->varargs), - buf.toChars()); - return m.anyf; // as long as it's not a FuncAliasDeclaration - } - else - { -#if 1 - TypeFunction *t1 = (TypeFunction *)m.lastf->type; - TypeFunction *t2 = (TypeFunction *)m.nextf->type; - - error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", - buf.toChars(), - m.lastf->toPrettyChars(), Argument::argsTypesToChars(t1->parameters, t1->varargs), - m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs)); -#else - error(loc, "overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); -#endif - return m.lastf; - } - } -} - -/******************************** - * Labels are in a separate scope, one per function. - */ - -LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident) -{ Dsymbol *s; - - if (!labtab) - labtab = new DsymbolTable(); // guess we need one - - s = labtab->lookup(ident); - if (!s) - { - s = new LabelDsymbol(ident); - labtab->insert(s); - } - return (LabelDsymbol *)s; -} - -/**************************************** - * If non-static member function that has a 'this' pointer, - * return the aggregate it is a member of. - * Otherwise, return NULL. - */ - -AggregateDeclaration *FuncDeclaration::isThis() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); - ad = NULL; - if ((storage_class & STCstatic) == 0) - { - ad = isMember2(); - } - //printf("-FuncDeclaration::isThis() %p\n", ad); - return ad; -} - -AggregateDeclaration *FuncDeclaration::isMember2() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isMember2() '%s'\n", toChars()); - ad = NULL; - for (Dsymbol *s = this; s; s = s->parent) - { -//printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind()); - ad = s->isMember(); - if (ad) -{ //printf("test4\n"); - break; -} - if (!s->parent || - (!s->parent->isTemplateInstance())) -{ //printf("test5\n"); - break; -} - } - //printf("-FuncDeclaration::isMember2() %p\n", ad); - return ad; -} - -/***************************************** - * Determine lexical level difference from 'this' to nested function 'fd'. - * Error if this cannot call fd. - * Returns: - * 0 same level - * -1 increase nesting by 1 (fd is nested within 'this') - * >0 decrease nesting by number - */ - -int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) -{ int level; - Dsymbol *s; - Dsymbol *fdparent; - - //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); - fdparent = fd->toParent2(); - if (fdparent == this) - return -1; - s = this; - level = 0; - while (fd != s && fdparent != s->toParent2()) - { - //printf("\ts = '%s'\n", s->toChars()); - FuncDeclaration *thisfd = s->isFuncDeclaration(); - if (thisfd) - { if (!thisfd->isNested() && !thisfd->vthis) - goto Lerr; - } - else - { - ClassDeclaration *thiscd = s->isClassDeclaration(); - if (thiscd) - { if (!thiscd->isNested()) - goto Lerr; - } - else - goto Lerr; - } - - s = s->toParent2(); - assert(s); - level++; - } - return level; - -Lerr: - error(loc, "cannot access frame of function %s", fd->toChars()); - return 1; -} - -void FuncDeclaration::appendExp(Expression *e) -{ Statement *s; - - s = new ExpStatement(0, e); - appendState(s); -} - -void FuncDeclaration::appendState(Statement *s) -{ CompoundStatement *cs; - - if (!fbody) - { Statements *a; - - a = new Statements(); - fbody = new CompoundStatement(0, a); - } - cs = fbody->isCompoundStatement(); - cs->statements->push(s); -} - - -int FuncDeclaration::isMain() -{ - return ident == Id::main && - linkage != LINKc && !isMember() && !isNested(); -} - -int FuncDeclaration::isWinMain() -{ - //printf("FuncDeclaration::isWinMain() %s\n", toChars()); -#if 0 - int x = ident == Id::WinMain && - linkage != LINKc && !isMember(); - printf("%s\n", x ? "yes" : "no"); - return x; -#else - return ident == Id::WinMain && - linkage != LINKc && !isMember(); -#endif -} - -int FuncDeclaration::isDllMain() -{ - return ident == Id::DllMain && - linkage != LINKc && !isMember(); -} - -int FuncDeclaration::isExport() -{ - return protection == PROTexport; -} - -int FuncDeclaration::isImportedSymbol() -{ - //printf("isImportedSymbol()\n"); - //printf("protection = %d\n", protection); - return (protection == PROTexport) && !fbody; -} - -// Determine if function goes into virtual function pointer table - -int FuncDeclaration::isVirtual() -{ -#if 0 - printf("FuncDeclaration::isVirtual(%s)\n", toChars()); - printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration()); -#endif - return isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration(); -} - -int FuncDeclaration::isFinal() -{ - ClassDeclaration *cd; -#if 0 - printf("FuncDeclaration::isFinal(%s)\n", toChars()); - printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - (cd = toParent()->isClassDeclaration()) != NULL && - cd->storage_class & STCfinal); -#endif - return isMember() && - (Declaration::isFinal() || - ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); -} - -int FuncDeclaration::isAbstract() -{ - return storage_class & STCabstract; -} - -int FuncDeclaration::isCodeseg() -{ - return TRUE; // functions are always in the code segment -} - -// Determine if function needs -// a static frame pointer to its lexically enclosing function - -int FuncDeclaration::isNested() -{ - //if (!toParent()) - //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); - //printf("\ttoParent() = '%s'\n", toParent()->toChars()); - return ((storage_class & STCstatic) == 0) && toParent2() && - (toParent2()->isFuncDeclaration() != NULL); -} - -int FuncDeclaration::needThis() -{ - //printf("FuncDeclaration::needThis() '%s'\n", toChars()); - int i = isThis() != NULL; - //printf("\t%d\n", i); - if (!i && isFuncAliasDeclaration()) - i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); - return i; -} - -int FuncDeclaration::addPreInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked); -} - -int FuncDeclaration::addPostInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - ad->inv && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked); -} - -/********************************** - * Generate a FuncDeclaration for a runtime library function. - */ - -// -// LDC: Adjusted to give argument info to the runtime function decl. -// - -FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, const char *name) -{ - return genCfunc(args, treturn, Lexer::idPool(name)); -} - -FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, Identifier *id) -{ - FuncDeclaration *fd; - TypeFunction *tf; - Dsymbol *s; - static DsymbolTable *st = NULL; - - //printf("genCfunc(name = '%s')\n", id->toChars()); - //printf("treturn\n\t"); treturn->print(); - - // See if already in table - if (!st) - st = new DsymbolTable(); - s = st->lookup(id); - if (s) - { - fd = s->isFuncDeclaration(); - assert(fd); - assert(fd->type->nextOf()->equals(treturn)); - } - else - { - tf = new TypeFunction(args, treturn, 0, LINKc); - fd = new FuncDeclaration(0, 0, id, STCstatic, tf); - fd->protection = PROTpublic; - fd->linkage = LINKc; - - st->insert(fd); - } - return fd; -} - -const char *FuncDeclaration::kind() -{ - return "function"; -} - -/******************************* - * Look at all the variables in this function that are referenced - * by nested functions, and determine if a closure needs to be - * created for them. - */ - -#if DMDV2 -int FuncDeclaration::needsClosure() -{ - /* Need a closure for all the closureVars[] if any of the - * closureVars[] are accessed by a - * function that escapes the scope of this function. - * We take the conservative approach and decide that any function that: - * 1) is a virtual function - * 2) has its address taken - * 3) has a parent that escapes - * - * Note that since a non-virtual function can be called by - * a virtual one, if that non-virtual function accesses a closure - * var, the closure still has to be taken. Hence, we check for isThis() - * instead of isVirtual(). (thanks to David Friedman) - */ - - //printf("FuncDeclaration::needsClosure() %s\n", toChars()); - for (int i = 0; i < closureVars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)closureVars.data[i]; - assert(v->isVarDeclaration()); - //printf("\tv = %s\n", v->toChars()); - - for (int j = 0; j < v->nestedrefs.dim; j++) - { FuncDeclaration *f = (FuncDeclaration *)v->nestedrefs.data[j]; - assert(f != this); - - //printf("\t\tf = %s, %d, %d\n", f->toChars(), f->isVirtual(), f->tookAddressOf); - if (f->isThis() || f->tookAddressOf) - goto Lyes; // assume f escapes this function's scope - - // Look to see if any parents of f that are below this escape - for (Dsymbol *s = f->parent; s && s != this; s = s->parent) - { - f = s->isFuncDeclaration(); - if (f && (f->isThis() || f->tookAddressOf)) - goto Lyes; - } - } - } - return 0; - -Lyes: - //printf("\tneeds closure\n"); - return 1; -} -#endif - -/****************************** FuncAliasDeclaration ************************/ - -// Used as a way to import a set of functions from another scope into this one. - -FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) - : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, - (enum STC)funcalias->storage_class, funcalias->type) -{ - assert(funcalias != this); - this->funcalias = funcalias; - importprot = PROTundefined; -} - -const char *FuncAliasDeclaration::kind() -{ - return "function alias"; -} - - -/****************************** FuncLiteralDeclaration ************************/ - -FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, - enum TOK tok, ForeachStatement *fes) - : FuncDeclaration(loc, endloc, NULL, STCundefined, type) -{ - const char *id; - - if (fes) - id = "__foreachbody"; - else if (tok == TOKdelegate) - id = "__dgliteral"; - else - id = "__funcliteral"; - this->ident = Identifier::generateId(id); - this->tok = tok; - this->fes = fes; - //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); -} - -Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncLiteralDeclaration *f; - - //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncLiteralDeclaration *)s; - else - f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); - FuncDeclaration::syntaxCopy(f); - return f; -} - -int FuncLiteralDeclaration::isNested() -{ - //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); - return (tok == TOKdelegate); -} - -int FuncLiteralDeclaration::isVirtual() -{ - return FALSE; -} - -const char *FuncLiteralDeclaration::kind() -{ - // GCC requires the (char*) casts - return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; -} - -void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - static Identifier *idfunc; - static Identifier *iddel; - - if (!idfunc) - idfunc = new Identifier("function", 0); - if (!iddel) - iddel = new Identifier("delegate", 0); - - type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* CtorDeclaration ****************************/ - -CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; - //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); -} - -Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) -{ - CtorDeclaration *f; - - f = new CtorDeclaration(loc, endloc, NULL, varargs); - - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - f->arguments = Argument::arraySyntaxCopy(arguments); - return f; -} - - -void CtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - //printf("CtorDeclaration::semantic()\n"); - if (type) - return; - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static constructor - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd) - { - error("constructors are only for class definitions"); - fatal(); - tret = Type::tvoid; - } - else - tret = cd->type; //->referenceTo(); - type = new TypeFunction(arguments, tret, varargs, LINKd); - if (!originalType) - originalType = type; - - sc->flags |= SCOPEctor; - type = type->semantic(loc, sc); - sc->flags &= ~SCOPEctor; - - // Append: - // return this; - // to the function body - if (fbody) - { Expression *e; - Statement *s; - - e = new ThisExp(0); - s = new ReturnStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - } - - FuncDeclaration::semantic(sc); - - sc->pop(); - - // See if it's the default constructor - if (cd && varargs == 0 && Argument::dim(arguments) == 0) - cd->defaultCtor = this; -} - -const char *CtorDeclaration::kind() -{ - return "constructor"; -} - -char *CtorDeclaration::toChars() -{ - return (char *)"this"; -} - -int CtorDeclaration::isVirtual() -{ - return FALSE; -} - -int CtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int CtorDeclaration::addPostInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - - -void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); - Argument::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - -/********************************* DtorDeclaration ****************************/ - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) -{ -} - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void DtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd) - { - error("destructors only are for class definitions"); - fatal(); - } - else - cd->dtors.push(this); - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static destructor - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int DtorDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload destructors -} - -int DtorDeclaration::addPreInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - -int DtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -int DtorDeclaration::isVirtual() -{ - /* This should be FALSE so that dtor's don't get put into the vtbl[], - * but doing so will require recompiling everything. - */ -#if BREAKABI - return FALSE; -#else - return FuncDeclaration::isVirtual(); -#endif -} - -void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticCtorDeclaration ****************************/ - -StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticCtor"), STCstatic, NULL) -{ -} - -Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticCtorDeclaration *scd; - - assert(!s); - scd = new StaticCtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(scd); -} - - -void StaticCtorDeclaration::semantic(Scope *sc) -{ - //printf("StaticCtorDeclaration::semantic()\n"); - - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance()) - { - /* Add this prefix to the function: - * static int gate; - * if (++gate != 1) return; - * Note that this is not thread safe; should not have threads - * during static construction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = STCstatic; - Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp(1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticCtorDeclaration::isThis() -{ - return NULL; -} - -int StaticCtorDeclaration::isStaticConstructor() -{ - return TRUE; -} - -int StaticCtorDeclaration::isVirtual() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - { buf->writestring("static this();\n"); - return; - } - buf->writestring("static this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticDtorDeclaration ****************************/ - -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticDtor"), STCstatic, NULL) -{ - vgate = NULL; -} - -Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticDtorDeclaration *sdd; - - assert(!s); - sdd = new StaticDtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(sdd); -} - - -void StaticDtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - cd = sc->scopesym->isClassDeclaration(); - if (!cd) - { - } - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance()) - { - /* Add this prefix to the function: - * static int gate; - * if (--gate != 0) return; - * Increment gate during constructor execution. - * Note that this is not thread safe; should not have threads - * during static destruction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = STCstatic; - Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(0)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - vgate = v; - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticDtorDeclaration::isThis() -{ - return NULL; -} - -int StaticDtorDeclaration::isStaticDestructor() -{ - return TRUE; -} - -int StaticDtorDeclaration::isVirtual() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("static ~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* InvariantDeclaration ****************************/ - -InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) -{ -} - -Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) -{ - InvariantDeclaration *id; - - assert(!s); - id = new InvariantDeclaration(loc, endloc); - FuncDeclaration::syntaxCopy(id); - return id; -} - - -void InvariantDeclaration::semantic(Scope *sc) -{ - AggregateDeclaration *ad; - Type *tret; - - parent = sc->parent; - Dsymbol *parent = toParent(); - ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("invariants are only for struct/union/class definitions"); - return; - } - else if (ad->inv && ad->inv != this) - { - error("more than one invariant for %s", ad->toChars()); - } - ad->inv = this; - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static invariant - sc->incontract++; - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int InvariantDeclaration::isVirtual() -{ - return FALSE; -} - -int InvariantDeclaration::addPreInvariant() -{ - return FALSE; -} - -int InvariantDeclaration::addPostInvariant() -{ - return FALSE; -} - -void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("invariant"); - bodyToCBuffer(buf, hgs); -} - - -/********************************* UnitTestDeclaration ****************************/ - -/******************************* - * Generate unique unittest function Id so we can have multiple - * instances per module. - */ - -static Identifier *unitTestId() -{ - return Lexer::uniqueId("__unittest"); -} - -UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) -{ -} - -Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) -{ - UnitTestDeclaration *utd; - - assert(!s); - utd = new UnitTestDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(utd); -} - - -void UnitTestDeclaration::semantic(Scope *sc) -{ - if (global.params.useUnitTests) - { - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - Scope *sc2 = sc->push(); - sc2->linkage = LINKd; - FuncDeclaration::semantic(sc2); - sc2->pop(); - } - - // We're going to need ModuleInfo even if the unit tests are not - // compiled in, because other modules may import this module and refer - // to this ModuleInfo. - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - m->needmoduleinfo = 1; -} - -AggregateDeclaration *UnitTestDeclaration::isThis() -{ - return NULL; -} - -int UnitTestDeclaration::isVirtual() -{ - return FALSE; -} - -int UnitTestDeclaration::addPreInvariant() -{ - return FALSE; -} - -int UnitTestDeclaration::addPostInvariant() -{ - return FALSE; -} - -void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("unittest"); - bodyToCBuffer(buf, hgs); -} - -/********************************* NewDeclaration ****************************/ - -NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; -} - -Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) -{ - NewDeclaration *f; - - f = new NewDeclaration(loc, endloc, NULL, varargs); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Argument::arraySyntaxCopy(arguments); - - return f; -} - - -void NewDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - //printf("NewDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - tret = Type::tvoid->pointerTo(); - type = new TypeFunction(arguments, tret, varargs, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is at least one argument of type size_t - TypeFunction *tf = (TypeFunction *)type; - if (Argument::dim(tf->parameters) < 1) - { - error("at least one argument of type size_t expected"); - } - else - { - Argument *a = Argument::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tsize_t)) - error("first argument must be type size_t, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *NewDeclaration::kind() -{ - return "allocator"; -} - -int NewDeclaration::isVirtual() -{ - return FALSE; -} - -int NewDeclaration::addPreInvariant() -{ - return FALSE; -} - -int NewDeclaration::addPostInvariant() -{ - return FALSE; -} - -void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("new"); - Argument::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* DeleteDeclaration ****************************/ - -DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments) - : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) -{ - this->arguments = arguments; -} - -Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) -{ - DeleteDeclaration *f; - - f = new DeleteDeclaration(loc, endloc, NULL); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Argument::arraySyntaxCopy(arguments); - - return f; -} - - -void DeleteDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - - //printf("DeleteDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is only one argument of type void* - TypeFunction *tf = (TypeFunction *)type; - if (Argument::dim(tf->parameters) != 1) - { - error("one argument of type void* expected"); - } - else - { - Argument *a = Argument::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tvoid->pointerTo())) - error("one argument of type void* expected, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *DeleteDeclaration::kind() -{ - return "deallocator"; -} - -int DeleteDeclaration::isDelete() -{ - return TRUE; -} - -int DeleteDeclaration::isVirtual() -{ - return FALSE; -} - -int DeleteDeclaration::addPreInvariant() -{ - return FALSE; -} - -int DeleteDeclaration::addPostInvariant() -{ - return FALSE; -} - -void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete"); - Argument::argsToCBuffer(buf, hgs, arguments, 0); - bodyToCBuffer(buf, hgs); -} - - - - +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <assert.h> + +#include "mars.h" +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "expression.h" +#include "scope.h" +#include "mtype.h" +#include "aggregate.h" +#include "identifier.h" +#include "id.h" +#include "module.h" +#include "statement.h" +#include "template.h" +#include "hdrgen.h" + +#ifdef IN_GCC +#include "d-dmd-gcc.h" +#endif + +/********************************* FuncDeclaration ****************************/ + +FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) + : Declaration(id) +{ + //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); + //printf("storage_class = x%x\n", storage_class); + this->storage_class = storage_class; + this->type = type; + this->loc = loc; + this->endloc = endloc; + fthrows = NULL; + frequire = NULL; + fdrequire = NULL; + fdensure = NULL; + outId = NULL; + vresult = NULL; + returnLabel = NULL; + fensure = NULL; + fbody = NULL; + localsymtab = NULL; + vthis = NULL; + v_arguments = NULL; +#if IN_GCC + v_argptr = NULL; +#endif + parameters = NULL; + labtab = NULL; + overnext = NULL; + vtblIndex = -1; + hasReturnExp = 0; + naked = 0; + inlineStatus = ILSuninitialized; + inlineNest = 0; + inlineAsm = 0; + cantInterpret = 0; + semanticRun = 0; +#if DMDV1 + nestedFrameRef = 0; +#endif + fes = NULL; + introducing = 0; + tintro = NULL; + /* The type given for "infer the return type" is a TypeFunction with + * NULL for the return type. + */ + inferRetType = (type && type->nextOf() == NULL); + hasReturnExp = 0; + nrvo_can = 1; + nrvo_var = NULL; +#if IN_DMD + shidden = NULL; +#endif + +#if DMDV2 + builtin = BUILTINunknown; + tookAddressOf = 0; +#endif + +#if IN_LLVM + // LDC + isArrayOp = false; + allowInlining = false; + + availableExternally = true; // assume this unless proven otherwise + + // function types in ldc don't merge if the context parameter differs + // so we actually don't care about the function declaration, but only + // what kind of context parameter it has. + // however, this constructor is usually called from the parser, which + // unfortunately doesn't provide the information needed to get to the + // aggregate type. So we have to stick with the FuncDeclaration and + // just be sure we don't actually rely on the symbol it points to, + // but rather just the type of its context parameter. + // this means some function might have a function type pointing to + // another function declaration + + if (type) + { + assert(type->ty == Tfunction && "invalid function type"); + TypeFunction* tf = (TypeFunction*)type; + if (tf->funcdecl == NULL) + tf->funcdecl = this; + } +#endif +} + +Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) +{ + FuncDeclaration *f; + + //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + f = (FuncDeclaration *)s; + else + f = new FuncDeclaration(loc, endloc, ident, (enum STC) storage_class, type->syntaxCopy()); + f->outId = outId; + f->frequire = frequire ? frequire->syntaxCopy() : NULL; + f->fensure = fensure ? fensure->syntaxCopy() : NULL; + f->fbody = fbody ? fbody->syntaxCopy() : NULL; + assert(!fthrows); // deprecated + + // LDC + f->intrinsicName = intrinsicName; + + return f; +} + + +// Do the semantic analysis on the external interface to the function. + +void FuncDeclaration::semantic(Scope *sc) +{ TypeFunction *f; + StructDeclaration *sd; + ClassDeclaration *cd; + InterfaceDeclaration *id; + Dsymbol *pd; + +#if 0 + printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); + if (isFuncLiteralDeclaration()) + printf("\tFuncLiteralDeclaration()\n"); + printf("sc->parent = %s, parent = %s\n", sc->parent->toChars(), parent ? parent->toChars() : ""); + printf("type: %p, %s\n", type, type->toChars()); +#endif + + if (semanticRun && isFuncLiteralDeclaration()) + { + /* Member functions that have return types that are + * forward references can have semantic() run more than + * once on them. + * See test\interface2.d, test20 + */ + return; + } + assert(semanticRun <= 1); + semanticRun = 1; + + if (!type->deco) + { + type = type->semantic(loc, sc); + } + //type->print(); + if (type->ty != Tfunction) + { + error("%s must be a function", toChars()); + return; + } + f = (TypeFunction *)(type); + size_t nparams = Argument::dim(f->parameters); + + linkage = sc->linkage; +// if (!parent) + { + //parent = sc->scopesym; + parent = sc->parent; + } + protection = sc->protection; + storage_class |= sc->stc; + //printf("function storage_class = x%x\n", storage_class); + Dsymbol *parent = toParent(); + + if (ident == Id::ctor && !isCtorDeclaration()) + error("_ctor is reserved for constructors"); + + if (isConst() || isAuto() || isScope()) + error("functions cannot be const, auto or scope"); + + if (isAbstract() && !isVirtual()) + error("non-virtual functions cannot be abstract"); + + if (isAbstract() && isFinal()) + error("cannot be both final and abstract"); +#if 0 + if (isAbstract() && fbody) + error("abstract functions cannot have bodies"); +#endif + +#if 0 + if (isStaticConstructor() || isStaticDestructor()) + { + if (!isStatic() || type->nextOf()->ty != Tvoid) + error("static constructors / destructors must be static void"); + if (f->arguments && f->arguments->dim) + error("static constructors / destructors must have empty parameter list"); + // BUG: check for invalid storage classes + } +#endif + +#ifdef IN_GCC + AggregateDeclaration *ad; + + ad = parent->isAggregateDeclaration(); + if (ad) + ad->methods.push(this); +#endif + sd = parent->isStructDeclaration(); + if (sd) + { + // Verify no constructors, destructors, etc. + if (isCtorDeclaration() || + isDtorDeclaration() + //|| isInvariantDeclaration() + //|| isUnitTestDeclaration() + ) + { + error("special member functions not allowed for %ss", sd->kind()); + } + +#if 0 + if (!sd->inv) + sd->inv = isInvariantDeclaration(); + + if (!sd->aggNew) + sd->aggNew = isNewDeclaration(); + + if (isDelete()) + { + if (sd->aggDelete) + error("multiple delete's for struct %s", sd->toChars()); + sd->aggDelete = (DeleteDeclaration *)(this); + } +#endif + } + + id = parent->isInterfaceDeclaration(); + if (id) + { + storage_class |= STCabstract; + + if (isCtorDeclaration() || +#if DMDV2 + isPostBlitDeclaration() || +#endif + isDtorDeclaration() || + isInvariantDeclaration() || + isUnitTestDeclaration() || isNewDeclaration() || isDelete()) + error("special function not allowed in interface %s", id->toChars()); + if (fbody) + error("function body is not abstract in interface %s", id->toChars()); + } + + /* Template member functions aren't virtual: + * interface TestInterface { void tpl(T)(); } + * and so won't work in interfaces + */ + if ((pd = toParent()) != NULL && + pd->isTemplateInstance() && + (pd = toParent2()) != NULL && + (id = pd->isInterfaceDeclaration()) != NULL) + { + error("template member function not allowed in interface %s", id->toChars()); + } + + cd = parent->isClassDeclaration(); + if (cd) + { int vi; + CtorDeclaration *ctor; + DtorDeclaration *dtor; + InvariantDeclaration *inv; + + if (isCtorDeclaration()) + { +// ctor = (CtorDeclaration *)this; +// if (!cd->ctor) +// cd->ctor = ctor; + return; + } + +#if 0 + dtor = isDtorDeclaration(); + if (dtor) + { + if (cd->dtor) + error("multiple destructors for class %s", cd->toChars()); + cd->dtor = dtor; + } + + inv = isInvariantDeclaration(); + if (inv) + { + cd->inv = inv; + } + + if (isNewDeclaration()) + { + if (!cd->aggNew) + cd->aggNew = (NewDeclaration *)(this); + } + + if (isDelete()) + { + if (cd->aggDelete) + error("multiple delete's for class %s", cd->toChars()); + cd->aggDelete = (DeleteDeclaration *)(this); + } +#endif + + if (storage_class & STCabstract) + cd->isabstract = 1; + + // if static function, do not put in vtbl[] + if (!isVirtual()) + { + //printf("\tnot virtual\n"); + goto Ldone; + } + + // Find index of existing function in vtbl[] to override + vi = findVtblIndex(&cd->vtbl, cd->baseClass ? cd->baseClass->vtbl.dim : 0); + switch (vi) + { + case -1: + /* Didn't find one, so + * This is an 'introducing' function which gets a new + * slot in the vtbl[]. + */ + + // Verify this doesn't override previous final function + if (cd->baseClass) + { Dsymbol *s = cd->baseClass->search(loc, ident, 0); + if (s) + { + FuncDeclaration *f = s->isFuncDeclaration(); + f = f->overloadExactMatch(type, getModule()); + if (f && f->isFinal() && f->prot() != PROTprivate) + error("cannot override final function %s", f->toPrettyChars()); + } + } + + if (isFinal()) + { + if (isOverride()) + error("does not override any function"); + cd->vtblFinal.push(this); + } + else + { + // Append to end of vtbl[] + //printf("\tintroducing function\n"); + introducing = 1; + vi = cd->vtbl.dim; + cd->vtbl.push(this); + vtblIndex = vi; + } + break; + + case -2: // can't determine because of fwd refs + cd->sizeok = 2; // can't finish due to forward reference + return; + + default: + { FuncDeclaration *fdv = (FuncDeclaration *)cd->vtbl.data[vi]; + // This function is covariant with fdv + if (fdv->isFinal()) + error("cannot override final function %s", fdv->toPrettyChars()); + +#if DMDV2 + if (!isOverride()) + warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); +#endif + + if (fdv->toParent() == parent) + { + // If both are mixins, then error. + // If either is not, the one that is not overrides + // the other. + if (fdv->parent->isClassDeclaration()) + break; + if (!this->parent->isClassDeclaration() +#if !BREAKABI + && !isDtorDeclaration() +#endif +#if DMDV2 + && !isPostBlitDeclaration() +#endif + ) + error("multiple overrides of same function"); + } + cd->vtbl.data[vi] = (void *)this; + vtblIndex = vi; + + /* Remember which functions this overrides + */ + foverrides.push(fdv); + + /* This works by whenever this function is called, + * it actually returns tintro, which gets dynamically + * cast to type. But we know that tintro is a base + * of type, so we could optimize it by not doing a + * dynamic cast, but just subtracting the isBaseOf() + * offset if the value is != null. + */ + + if (fdv->tintro) + tintro = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) + { + tintro = fdv->type; + } + } + break; + } + } + + /* Go through all the interface bases. + * If this function is covariant with any members of those interface + * functions, set the tintro. + */ + for (int i = 0; i < cd->interfaces_dim; i++) + { +#if 1 + BaseClass *b = cd->interfaces[i]; + vi = findVtblIndex(&b->base->vtbl, b->base->vtbl.dim); + switch (vi) + { + case -1: + break; + + case -2: + cd->sizeok = 2; // can't finish due to forward reference + return; + + default: + { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; + Type *ti = NULL; + + /* Remember which functions this overrides + */ + foverrides.push(fdv); + + if (fdv->tintro) + ti = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) + { + ti = fdv->type; +#if 0 + if (offset) + ti = fdv->type; + else if (type->nextOf()->ty == Tclass) + { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; + if (cdn && cdn->sizeok != 1) + ti = fdv->type; + } +#endif + } + } + if (ti) + { + if (tintro && !tintro->equals(ti)) + { + error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); + } + tintro = ti; + } + goto L2; + } + } +#else + BaseClass *b = cd->interfaces[i]; + for (vi = 0; vi < b->base->vtbl.dim; vi++) + { + Dsymbol *s = (Dsymbol *)b->base->vtbl.data[vi]; + //printf("interface %d vtbl[%d] %p %s\n", i, vi, s, s->toChars()); + FuncDeclaration *fdv = s->isFuncDeclaration(); + if (fdv && fdv->ident == ident) + { + int cov = type->covariant(fdv->type); + //printf("\tcov = %d\n", cov); + if (cov == 2) + { + //type->print(); + //fdv->type->print(); + //printf("%s %s\n", type->deco, fdv->type->deco); + error("of type %s overrides but is not covariant with %s of type %s", + type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); + } + if (cov == 1) + { Type *ti = NULL; + + if (fdv->tintro) + ti = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) + { + ti = fdv->type; +#if 0 + if (offset) + ti = fdv->type; + else if (type->nextOf()->ty == Tclass) + { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; + if (cdn && cdn->sizeok != 1) + ti = fdv->type; + } +#endif + } + } + if (ti) + { + if (tintro && !tintro->equals(ti)) + { + error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); + } + tintro = ti; + } + goto L2; + } + if (cov == 3) + { + cd->sizeok = 2; // can't finish due to forward reference + return; + } + } + } +#endif + } + + if (introducing && isOverride()) + { + error("does not override any function"); + } + + L2: ; + } + else if (isOverride() && !parent->isTemplateInstance()) + error("override only applies to class member functions"); + + /* Do not allow template instances to add virtual functions + * to a class. + */ + if (isVirtual()) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + ClassDeclaration *cd = ti->tempdecl->isClassMember(); + if (cd) + { + error("cannot use template to add virtual function to class '%s'", cd->toChars()); + } + } + } + + if (isMain()) + { + // Check parameters to see if they are either () or (char[][] args) + switch (nparams) + { + case 0: + break; + + case 1: + { + Argument *arg0 = Argument::getNth(f->parameters, 0); + if (arg0->type->ty != Tarray || + arg0->type->nextOf()->ty != Tarray || + arg0->type->nextOf()->nextOf()->ty != Tchar || + arg0->storageClass & (STCout | STCref | STClazy)) + goto Lmainerr; + break; + } + + default: + goto Lmainerr; + } + + if (!f->nextOf()) + error("must return int or void"); + else if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) + error("must return int or void, not %s", f->nextOf()->toChars()); + if (f->varargs) + { + Lmainerr: + error("parameters must be main() or main(char[][] args)"); + } + } + + if (ident == Id::assign && (sd || cd)) + { // Disallow identity assignment operator. + + // opAssign(...) + if (nparams == 0) + { if (f->varargs == 1) + goto Lassignerr; + } + else + { + Argument *arg0 = Argument::getNth(f->parameters, 0); + Type *t0 = arg0->type->toBasetype(); + Type *tb = sd ? sd->type : cd->type; + if (arg0->type->implicitConvTo(tb) || + (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) + ) + { + if (nparams == 1) + goto Lassignerr; + Argument *arg1 = Argument::getNth(f->parameters, 1); + if (arg1->defaultArg) + goto Lassignerr; + } + } + } + + if (isVirtual()) + { + /* Rewrite contracts as nested functions, then call them. + * Doing it as nested functions means that overriding functions + * can call them. + */ + if (frequire) + { /* in { ... } + * becomes: + * void __require() { ... } + * __require(); + */ + Loc loc = frequire->loc; + TypeFunction *tf = new TypeFunction(NULL, Type::tvoid, 0, LINKd); + FuncDeclaration *fd = new FuncDeclaration(loc, loc, + Id::require, STCundefined, tf); + fd->fbody = frequire; + Statement *s1 = new DeclarationStatement(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); + fdrequire = fd; + } + + if (fensure) + { /* out (result) { ... } + * becomes: + * tret __ensure(ref tret result) { ... } + * __ensure(result); + */ + if (!outId && f->nextOf()->toBasetype()->ty != Tvoid) + outId = Id::result; // provide a default + + Loc loc = fensure->loc; + Arguments *arguments = new Arguments(); + Argument *a = NULL; + if (outId) + { a = new Argument(STCref, f->nextOf(), outId, NULL); + arguments->push(a); + } + TypeFunction *tf = new TypeFunction(arguments, Type::tvoid, 0, LINKd); + FuncDeclaration *fd = new FuncDeclaration(loc, loc, + Id::ensure, STCundefined, tf); + fd->fbody = fensure; + Statement *s1 = new DeclarationStatement(loc, fd); + Expression *eresult = NULL; + if (outId) + eresult = new IdentifierExp(loc, outId); + Expression *e = new CallExp(loc, new VarExp(loc, fd), eresult); + Statement *s2 = new ExpStatement(loc, e); + fensure = new CompoundStatement(loc, s1, s2); + fdensure = fd; + } + } + +Ldone: + /* Save scope for possible later use (if we need the + * function internals) + */ + scope = new Scope(*sc); + scope->setNoFree(); + return; + +Lassignerr: + error("identity assignment operator overload is illegal"); +} + +void FuncDeclaration::semantic2(Scope *sc) +{ +} + +// Do the semantic analysis on the internals of the function. + +void FuncDeclaration::semantic3(Scope *sc) +{ TypeFunction *f; + VarDeclaration *argptr = NULL; + VarDeclaration *_arguments = NULL; + + if (!parent) + { + if (global.errors) + return; + //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); + assert(0); + } + //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); + //fflush(stdout); + //printf("storage class = x%x %x\n", sc->stc, storage_class); + //{ static int x; if (++x == 2) *(char*)0=0; } + //printf("\tlinkage = %d\n", sc->linkage); + + //printf(" sc->incontract = %d\n", sc->incontract); + if (semanticRun >= 3) + return; + semanticRun = 3; + + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; + + if (!type || type->ty != Tfunction) + return; + f = (TypeFunction *)(type); + + // Check the 'throws' clause + if (fthrows) + { + for (int i = 0; i < fthrows->dim; i++) + { + Type *t = (Type *)fthrows->data[i]; + + t = t->semantic(loc, sc); + if (!t->isClassHandle()) + error("can only throw classes, not %s", t->toChars()); + } + } + + frequire = mergeFrequire(frequire); + fensure = mergeFensure(fensure); + + if (fbody || frequire) + { + /* Symbol table into which we place parameters and nested functions, + * solely to diagnose name collisions. + */ + localsymtab = new DsymbolTable(); + + // Establish function scope + ScopeDsymbol *ss = new ScopeDsymbol(); + ss->parent = sc->scopesym; + Scope *sc2 = sc->push(ss); + sc2->func = this; + sc2->parent = this; + sc2->callSuper = 0; + sc2->sbreak = NULL; + sc2->scontinue = NULL; + sc2->sw = NULL; + sc2->fes = fes; + sc2->linkage = LINKd; + sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STCfinal); + sc2->protection = PROTpublic; + sc2->explicitProtection = 0; + sc2->structalign = 8; + sc2->incontract = 0; + sc2->enclosingFinally = NULL; + sc2->enclosingScopeExit = NULL; + sc2->noctor = 0; + + // Declare 'this' + AggregateDeclaration *ad = isThis(); + if (ad) + { VarDeclaration *v; + + if (isFuncLiteralDeclaration() && isNested()) + { + error("literals cannot be class members"); + return; + } + else + { + assert(!isNested()); // can't be both member and nested + assert(ad->handle); + v = new ThisDeclaration(loc, ad->handle); + v->storage_class |= STCparameter | STCin; + v->semantic(sc2); + if (!sc2->insert(v)) + assert(0); + v->parent = this; + vthis = v; + } + } + else if (isNested()) + { + /* The 'this' for a nested function is the link to the + * enclosing function's stack frame. + * Note that nested functions and member functions are disjoint. + */ + VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo()); + v->storage_class |= STCparameter | STCin; + v->semantic(sc2); + if (!sc2->insert(v)) + assert(0); + v->parent = this; + vthis = v; + } + + // Declare hidden variable _arguments[] and _argptr + if (f->varargs == 1) + { +#if TARGET_NET + varArgs(sc2, f, argptr, _arguments); +#else + Type *t; + + if (f->linkage == LINKd) + { // Declare _arguments[] +#if BREAKABI + v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); + v_arguments->storage_class = STCparameter | STCin; + v_arguments->semantic(sc2); + sc2->insert(v_arguments); + v_arguments->parent = this; + + t = Type::typeinfo->type->arrayOf(); + _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); + _arguments->semantic(sc2); + sc2->insert(_arguments); + _arguments->parent = this; +#else + t = Type::typeinfo->type->arrayOf(); + v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); + v_arguments->storage_class = STCparameter | STCin; + v_arguments->semantic(sc2); + sc2->insert(v_arguments); + v_arguments->parent = this; +#endif + } + if (f->linkage == LINKd || (parameters && parameters->dim)) + { // Declare _argptr +#if IN_GCC + t = d_gcc_builtin_va_list_d_type; +#else + t = Type::tvoid->pointerTo(); +#endif + argptr = new VarDeclaration(0, t, Id::_argptr, NULL); + argptr->semantic(sc2); + sc2->insert(argptr); + argptr->parent = this; + } +#endif + } + +#if IN_LLVM + // LDC make sure argument type is semanticed. + // Turns TypeTuple!(int, int) into two int parameters, for instance. + if (f->parameters) + { + for (size_t i = 0; i < Argument::dim(f->parameters); i++) + { Argument *arg = (Argument *)Argument::getNth(f->parameters, i); + Type* nw = arg->type->semantic(0, sc); + if (arg->type != nw) { + arg->type = nw; + // Examine this index again. + // This is important if it turned into a tuple. + // In particular, the empty tuple should be handled or the + // next parameter will be skipped. + // FIXME: Maybe we only need to do this for tuples, + // and can add tuple.length after decrement? + i--; + } + } + } +#endif + + // Propagate storage class from tuple parameters to their element-parameters. + if (f->parameters) + { + for (size_t i = 0; i < f->parameters->dim; i++) + { Argument *arg = (Argument *)f->parameters->data[i]; + + //printf("[%d] arg->type->ty = %d %s\n", i, arg->type->ty, arg->type->toChars()); + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + size_t dim = Argument::dim(t->arguments); + for (size_t j = 0; j < dim; j++) + { Argument *narg = Argument::getNth(t->arguments, j); + narg->storageClass = arg->storageClass; + } + } + } + } + + /* Declare all the function parameters as variables + * and install them in parameters[] + */ + size_t nparams = Argument::dim(f->parameters); + if (nparams) + { /* parameters[] has all the tuples removed, as the back end + * doesn't know about tuples + */ + parameters = new Dsymbols(); + parameters->reserve(nparams); + for (size_t i = 0; i < nparams; i++) + { + Argument *arg = Argument::getNth(f->parameters, i); + Identifier *id = arg->ident; + if (!id) + { + /* Generate identifier for un-named parameter, + * because we need it later on. + */ + arg->ident = id = Identifier::generateId("_param_", i); + } + Type *vtype = arg->type; + VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL); + //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); + v->storage_class |= STCparameter; + if (f->varargs == 2 && i + 1 == nparams) + v->storage_class |= STCvariadic; + v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy); + if (v->storage_class & STClazy) + v->storage_class |= STCin; + v->semantic(sc2); + if (!sc2->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + else + parameters->push(v); + localsymtab->insert(v); + v->parent = this; + } + } + + // Declare the tuple symbols and put them in the symbol table, + // but not in parameters[]. + if (f->parameters) + { + for (size_t i = 0; i < f->parameters->dim; i++) + { Argument *arg = (Argument *)f->parameters->data[i]; + + if (!arg->ident) + continue; // never used, so ignore + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + size_t dim = Argument::dim(t->arguments); + Objects *exps = new Objects(); + exps->setDim(dim); + for (size_t j = 0; j < dim; j++) + { Argument *narg = Argument::getNth(t->arguments, j); + assert(narg->ident); + VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); + assert(v); + Expression *e = new VarExp(v->loc, v); + exps->data[j] = (void *)e; + } + assert(arg->ident); + TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); + //printf("declaring tuple %s\n", v->toChars()); + v->isexp = 1; + if (!sc2->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + localsymtab->insert(v); + v->parent = this; + } + } + } + + /* Do the semantic analysis on the [in] preconditions and + * [out] postconditions. + */ + sc2->incontract++; + + if (frequire) + { /* frequire is composed of the [in] contracts + */ + // BUG: need to error if accessing out parameters + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + // BUG: verify that all in and ref parameters are read + frequire = frequire->semantic(sc2); + labtab = NULL; // so body can't refer to labels + } + + if (fensure || addPostInvariant()) + { /* fensure is composed of the [out] contracts + */ + if (!type->nextOf()) + { // Have to do semantic() on fbody first + error("post conditions are not supported if the return type is inferred"); + return; + } + + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc2->scopesym; + sc2 = sc2->push(sym); + + assert(type->nextOf()); + if (type->nextOf()->ty == Tvoid) + { + if (outId) + error("void functions have no result"); + } + else + { + if (!outId) + outId = Id::result; // provide a default + } + + if (outId) + { // Declare result variable + VarDeclaration *v; + Loc loc = this->loc; + + if (fensure) + loc = fensure->loc; + + v = new VarDeclaration(loc, type->nextOf(), outId, NULL); + v->noscope = 1; +#if DMDV2 + if (f->isref) + { + v->storage_class |= STCref | STCforeach; + } +#endif + sc2->incontract--; + v->semantic(sc2); + sc2->incontract++; + if (!sc2->insert(v)) + error("out result %s is already defined", v->toChars()); + v->parent = this; + vresult = v; + + // vresult gets initialized with the function return value + // in ReturnStatement::semantic() + } + + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + if (fensure) + { fensure = fensure->semantic(sc2); + labtab = NULL; // so body can't refer to labels + } + + if (!global.params.useOut) + { fensure = NULL; // discard + vresult = NULL; + } + + // Postcondition invariant + if (addPostInvariant()) + { + Expression *e = NULL; + if (isCtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + Expression *v = new ThisExp(0); + v->type = vthis->type; +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif + e = new AssertExp(0, v); + } + if (e) + { + ExpStatement *s = new ExpStatement(0, e); + if (fensure) + fensure = new CompoundStatement(0, s, fensure); + else + fensure = s; + } + } + + if (fensure) + { returnLabel = new LabelDsymbol(Id::returnLabel); + LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); + ls->isReturnLabel = 1; + returnLabel->statement = ls; + } + sc2 = sc2->pop(); + } + + sc2->incontract--; + + if (fbody) + { ClassDeclaration *cd = isClassMember(); + + /* If this is a class constructor + */ + if (isCtorDeclaration() && cd) + { + for (int i = 0; i < cd->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; + + v->ctorinit = 0; + } + } + + if (inferRetType || f->retStyle() != RETstack) + nrvo_can = 0; + + fbody = fbody->semantic(sc2); + + if (inferRetType) + { // If no return type inferred yet, then infer a void + if (!type->nextOf()) + { + ((TypeFunction *)type)->next = Type::tvoid; + type = type->semantic(loc, sc); + } + f = (TypeFunction *)type; + } + + int offend = fbody ? fbody->blockExit() & BEfallthru : TRUE; + + if (isStaticCtorDeclaration()) + { /* It's a static constructor. Ensure that all + * ctor consts were initialized. + */ + + Dsymbol *p = toParent(); + ScopeDsymbol *ad = p->isScopeDsymbol(); + if (!ad) + { + error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); + } + else + { + for (int i = 0; i < ad->members->dim; i++) + { Dsymbol *s = (Dsymbol *)ad->members->data[i]; + + s->checkCtorConstInit(); + } + } + } + + if (isCtorDeclaration() && cd) + { + //printf("callSuper = x%x\n", sc2->callSuper); + + // Verify that all the ctorinit fields got initialized + if (!(sc2->callSuper & CSXthis_ctor)) + { + for (int i = 0; i < cd->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; + + if (v->ctorinit == 0 && v->isCtorinit()) + error("missing initializer for const field %s", v->toChars()); + } + } + + if (!(sc2->callSuper & CSXany_ctor) && + cd->baseClass && cd->baseClass->ctor) + { + sc2->callSuper = 0; + + // Insert implicit super() at start of fbody + Expression *e1 = new SuperExp(0); + Expression *e = new CallExp(0, e1); + + unsigned errors = global.errors; + global.gag++; + e = e->semantic(sc2); + global.gag--; + if (errors != global.errors) + error("no match for implicit super() call in constructor"); + + Statement *s = new ExpStatement(0, e); + fbody = new CompoundStatement(0, s, fbody); + } + } + else if (fes) + { // For foreach(){} body, append a return 0; + Expression *e = new IntegerExp(0); + Statement *s = new ReturnStatement(0, e); + fbody = new CompoundStatement(0, fbody, s); + assert(!returnLabel); + } + else if (!hasReturnExp && type->nextOf()->ty != Tvoid) + error("expected to return a value of type %s", type->nextOf()->toChars()); + else if (!inlineAsm) + { +#if DMDV2 + int blockexit = fbody ? fbody->blockExit() : BEfallthru; + if (f->isnothrow && blockexit & BEthrow) + error("'%s' is nothrow yet may throw", toChars()); + + int offend = blockexit & BEfallthru; +#endif + if (type->nextOf()->ty == Tvoid) + { + if (offend && isMain()) + { // Add a return 0; statement + Statement *s = new ReturnStatement(0, new IntegerExp(0)); + fbody = new CompoundStatement(0, fbody, s); + } + } + else + { + if (offend) + { Expression *e; +#if DMDV1 + warning(loc, "no return exp; or assert(0); at end of function"); +#else + error("no return exp; or assert(0); at end of function"); +#endif + if (global.params.useAssert && + !global.params.useInline) + { /* Add an assert(0, msg); where the missing return + * should be. + */ + e = new AssertExp( + endloc, + new IntegerExp(0), + new StringExp(loc, (char *)"missing return expression") + ); + } + else + e = new HaltExp(endloc); + e = new CommaExp(0, e, type->nextOf()->defaultInit()); + e = e->semantic(sc2); + Statement *s = new ExpStatement(0, e); + fbody = new CompoundStatement(0, fbody, s); + } + } + } + } + + { + Statements *a = new Statements(); + + // Merge in initialization of 'out' parameters + if (parameters) + { for (size_t i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + if (v->storage_class & STCout) + { + assert(v->init); + ExpInitializer *ie = v->init->isExpInitializer(); + assert(ie); + a->push(new ExpStatement(0, ie->exp)); + } + } + } + +// we'll handle variadics ourselves +#if !IN_LLVM + if (argptr) + { // Initialize _argptr to point past non-variadic arg +#if IN_GCC + // Handled in FuncDeclaration::toObjFile + v_argptr = argptr; + v_argptr->init = new VoidInitializer(loc); +#else + Expression *e1; + Expression *e; + Type *t = argptr->type; + VarDeclaration *p; + unsigned offset; + + e1 = new VarExp(0, argptr); + if (parameters && parameters->dim) + p = (VarDeclaration *)parameters->data[parameters->dim - 1]; + else + p = v_arguments; // last parameter is _arguments[] + if (p->storage_class & STClazy) + // If the last parameter is lazy, it's the size of a delegate + offset = PTRSIZE * 2; + else + offset = p->type->size(); + offset = (offset + 3) & ~3; // assume stack aligns on 4 + e = new SymOffExp(0, p, offset); + e = new AssignExp(0, e1, e); + e->type = t; + a->push(new ExpStatement(0, e)); +#endif // IN_GCC + } + + if (_arguments) + { + /* Advance to elements[] member of TypeInfo_Tuple with: + * _arguments = v_arguments.elements; + */ + Expression *e = new VarExp(0, v_arguments); + e = new DotIdExp(0, e, Id::elements); + Expression *e1 = new VarExp(0, _arguments); + e = new AssignExp(0, e1, e); + e->op = TOKconstruct; + e = e->semantic(sc2); + a->push(new ExpStatement(0, e)); + } + +#endif // !IN_LLVM + + // Merge contracts together with body into one compound statement + +#ifdef _DH + if (frequire && global.params.useIn) + { frequire->incontract = 1; + a->push(frequire); + } +#else + if (frequire && global.params.useIn) + a->push(frequire); +#endif + + // Precondition invariant + if (addPreInvariant()) + { + Expression *e = NULL; + Expression *ee = NULL; + if (isDtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + // LDC: unless this is a struct without invariant + StructDeclaration* sd = ad->isStructDeclaration(); + if (!sd || sd->inv) + { + ThisExp *v = new ThisExp(0); + v->type = vthis->type; + e = new AssertExp(loc, v, NULL); + } + + // LDC: check for null this + ThisExp* v = new ThisExp(0); + v->type = vthis->type; +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif + v->var = vthis; + + NullExp *nv = new NullExp(0); + nv->type = v->type; + + IdentityExp *ie = new IdentityExp(TOKnotidentity, 0, v, nv); + ie->type = Type::tbool; + + Expression *se = new StringExp(0, (char *)"null this"); + se = se->semantic(sc); + se->type = Type::tchar->arrayOf(); + + ee = new AssertExp(loc, ie, se); + } + if (ee) + { + ExpStatement *s = new ExpStatement(0, ee); + a->push(s); + } + if (e) + { + ExpStatement *s = new ExpStatement(0, e); + a->push(s); + } + } + + if (fbody) + a->push(fbody); + + if (fensure) + { + a->push(returnLabel->statement); + + if (type->nextOf()->ty != Tvoid) + { + // Create: return vresult; + assert(vresult); + Expression *e = new VarExp(0, vresult); + if (tintro) + { e = e->implicitCastTo(sc, tintro->nextOf()); + e = e->semantic(sc); + } + ReturnStatement *s = new ReturnStatement(0, e); + a->push(s); + } + } + + fbody = new CompoundStatement(0, a); +#if DMDV2 + /* Append destructor calls for parameters as finally blocks. + */ + if (parameters) + { for (size_t i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + + if (v->storage_class & (STCref | STCout)) + continue; + + /* Don't do this for static arrays, since static + * arrays are called by reference. Remove this + * when we change them to call by value. + */ + if (v->type->toBasetype()->ty == Tsarray) + continue; + + Expression *e = v->callAutoDtor(sc); + if (e) + { Statement *s = new ExpStatement(0, e); + s = s->semantic(sc); + if (fbody->blockExit() == BEfallthru) + fbody = new CompoundStatement(0, fbody, s); + else + fbody = new TryFinallyStatement(0, fbody, s); + } + } + } +#endif + + // wrap body of synchronized functions in a synchronized statement + if (isSynchronized()) + { + ClassDeclaration *cd = parent->isClassDeclaration(); + if (!cd) + error("synchronized function %s must be a member of a class", toChars()); + + Expression *sync; + if (isStatic()) + { + // static member functions synchronize on classinfo + sync = cd->type->dotExp(sc2, new TypeExp(loc, cd->type), Id::classinfo); + } + else + { + // non-static member functions synchronize on this + sync = new VarExp(loc, vthis); + } + + // we do not want to rerun semantics on the whole function, so we + // manually adjust all labels in the function that currently don't + // have an enclosingScopeExit to use the new SynchronizedStatement + SynchronizedStatement* s = new SynchronizedStatement(loc, sync, NULL); + s->semantic(sc2); + s->body = fbody; + + // LDC + LabelMap::iterator it, end = labmap.end(); + for (it = labmap.begin(); it != end; ++it) + if (it->second->enclosingScopeExit == NULL) + it->second->enclosingScopeExit = s; + + a = new Statements; + a->push(s); + fbody = new CompoundStatement(0, a); + } + } + + sc2->callSuper = 0; + sc2->pop(); + } + semanticRun = 4; +} + +void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); + + type->toCBuffer(buf, ident, hgs); + bodyToCBuffer(buf, hgs); +} + + +void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (fbody && + (!hgs->hdrgen || hgs->tpltMember || canInline(1,1)) + ) + { buf->writenl(); + + // in{} + if (frequire) + { buf->writestring("in"); + buf->writenl(); + frequire->toCBuffer(buf, hgs); + } + + // out{} + if (fensure) + { buf->writestring("out"); + if (outId) + { buf->writebyte('('); + buf->writestring(outId->toChars()); + buf->writebyte(')'); + } + buf->writenl(); + fensure->toCBuffer(buf, hgs); + } + + if (frequire || fensure) + { buf->writestring("body"); + buf->writenl(); + } + + buf->writebyte('{'); + buf->writenl(); + fbody->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); + } + else + { buf->writeByte(';'); + buf->writenl(); + } +} + +/**************************************************** + * Merge into this function the 'in' contracts of all it overrides. + * 'in's are OR'd together, i.e. only one of them needs to pass. + */ + +Statement *FuncDeclaration::mergeFrequire(Statement *sf) +{ + /* Implementing this is done by having the overriding function call + * nested functions (the fdrequire functions) nested inside the overridden + * function. This requires that the stack layout of the calling function's + * parameters and 'this' pointer be in the same place (as the nested + * function refers to them). + * This is easy for the parameters, as they are all on the stack in the same + * place by definition, since it's an overriding function. The problem is + * getting the 'this' pointer in the same place, since it is a local variable. + * We did some hacks in the code generator to make this happen: + * 1. always generate exception handler frame, or at least leave space for it + * in the frame (Windows 32 SEH only) + * 2. always generate an EBP style frame + * 3. since 'this' is passed in a register that is subsequently copied into + * a stack local, allocate that local immediately following the exception + * handler block, so it is always at the same offset from EBP. + */ + for (int i = 0; i < foverrides.dim; i++) + { + FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; + sf = fdv->mergeFrequire(sf); + if (fdv->fdrequire) + { + //printf("fdv->frequire: %s\n", fdv->frequire->toChars()); + /* Make the call: + * try { __require(); } + * catch { frequire; } + */ + Expression *eresult = NULL; + 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); + Array *catches = new Array(); + catches->push(c); + sf = new TryCatchStatement(loc, s2, catches); + } + else + sf = s2; + } + } + return sf; +} + +/**************************************************** + * Merge into this function the 'out' contracts of all it overrides. + * 'out's are AND'd together, i.e. all of them need to pass. + */ + +Statement *FuncDeclaration::mergeFensure(Statement *sf) +{ + /* Same comments as for mergeFrequire(), except that we take care + * of generating a consistent reference to the 'result' local by + * explicitly passing 'result' to the nested function as a reference + * argument. + * This won't work for the 'this' parameter as it would require changing + * the semantic code for the nested function so that it looks on the parameter + * list for the 'this' pointer, something that would need an unknown amount + * of tweaking of various parts of the compiler that I'd rather leave alone. + */ + for (int i = 0; i < foverrides.dim; i++) + { + FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; + sf = fdv->mergeFensure(sf); + if (fdv->fdensure) + { + //printf("fdv->fensure: %s\n", fdv->fensure->toChars()); + // Make the call: __ensure(result) + Expression *eresult = NULL; + if (outId) + eresult = new IdentifierExp(loc, outId); + Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure), eresult); + Statement *s2 = new ExpStatement(loc, e); + + if (sf) + { + sf = new CompoundStatement(fensure->loc, s2, sf); + } + else + sf = s2; + } + } + return sf; +} + +/**************************************************** + * Determine if 'this' overrides fd. + * Return !=0 if it does. + */ + +int FuncDeclaration::overrides(FuncDeclaration *fd) +{ int result = 0; + + if (fd->ident == ident) + { + int cov = type->covariant(fd->type); + if (cov) + { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); + ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); + + if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) + result = 1; + } + } + return result; +} + +/************************************************* + * Find index of function in vtbl[0..dim] that + * this function overrides. + * Returns: + * -1 didn't find one + * -2 can't determine because of forward references + */ + +int FuncDeclaration::findVtblIndex(Array *vtbl, int dim) +{ + for (int vi = 0; vi < dim; vi++) + { + FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration(); + if (fdv && fdv->ident == ident) + { + int cov = type->covariant(fdv->type); + //printf("\tbaseclass cov = %d\n", cov); + switch (cov) + { + case 0: // types are distinct + break; + + case 1: + return vi; + + case 2: + //type->print(); + //fdv->type->print(); + //printf("%s %s\n", type->deco, fdv->type->deco); + error("of type %s overrides but is not covariant with %s of type %s", + type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); + break; + + case 3: + return -2; // forward references + + default: + assert(0); + } + } + } + return -1; +} + +/**************************************************** + * Overload this FuncDeclaration with the new one f. + * Return !=0 if successful; i.e. no conflict. + */ + +int FuncDeclaration::overloadInsert(Dsymbol *s) +{ + FuncDeclaration *f; + AliasDeclaration *a; + + //printf("FuncDeclaration::overloadInsert(%s)\n", s->toChars()); + a = s->isAliasDeclaration(); + if (a) + { + if (overnext) + return overnext->overloadInsert(a); + if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) + { + //printf("\ta = '%s'\n", a->type->toChars()); + return FALSE; + } + overnext = a; + //printf("\ttrue: no conflict\n"); + return TRUE; + } + f = s->isFuncDeclaration(); + if (!f) + return FALSE; + + if (type && f->type && // can be NULL for overloaded constructors + f->type->covariant(type) && + !isFuncAliasDeclaration()) + { + //printf("\tfalse: conflict %s\n", kind()); + return FALSE; + } + + if (overnext) + return overnext->overloadInsert(f); + overnext = f; + //printf("\ttrue: no conflict\n"); + return TRUE; +} + +/******************************************** + * Find function in overload list that exactly matches t. + */ + +/*************************************************** + * Visit each overloaded function in turn, and call + * (*fp)(param, f) on it. + * Exit when no more, or (*fp)(param, f) returns 1. + * Returns: + * 0 continue + * 1 done + */ + +int overloadApply(Module* from, FuncDeclaration *fstart, + int (*fp)(void *, FuncDeclaration *), + void *param) +{ + FuncDeclaration *f; + Declaration *d; + Declaration *next; + + for (d = fstart; d; d = next) + { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); + + if (fa) + { + if (fa->getModule() == from || fa->importprot != PROTprivate) + if (overloadApply(from, fa->funcalias, fp, param)) + return 1; + next = fa->overnext; + } + else + { + AliasDeclaration *a = d->isAliasDeclaration(); + + if (a) + { + Dsymbol *s = a->toAlias(); + next = s->isDeclaration(); + if (next == a) + break; + if (next == fstart) + break; + if (a->importprot == PROTprivate && a->getModule() != from) + if (FuncDeclaration* fd = next->isFuncDeclaration()) + next = fd->overnext; + } + else + { + f = d->isFuncDeclaration(); + if (!f) + { d->error("is aliased to a function"); + break; // BUG: should print error message? + } + if ((*fp)(param, f)) + return 1; + + next = f->overnext; + } + } + } + return 0; +} + +/******************************************** + * If there are no overloads of function f, return that function, + * otherwise return NULL. + */ + +static int fpunique(void *param, FuncDeclaration *f) +{ FuncDeclaration **pf = (FuncDeclaration **)param; + + if (*pf) + { *pf = NULL; + return 1; // ambiguous, done + } + else + { *pf = f; + return 0; + } +} + +FuncDeclaration *FuncDeclaration::isUnique() +{ FuncDeclaration *result = NULL; + + overloadApply(getModule(), this, &fpunique, &result); + return result; +} + +/******************************************** + * Find function in overload list that exactly matches t. + */ + +struct Param1 +{ + Type *t; // type to match + FuncDeclaration *f; // return value +}; + +int fp1(void *param, FuncDeclaration *f) +{ Param1 *p = (Param1 *)param; + Type *t = p->t; + + if (t->equals(f->type)) + { p->f = f; + return 1; + } + +#if DMDV2 + /* Allow covariant matches, if it's just a const conversion + * of the return type + */ + if (t->ty == Tfunction) + { TypeFunction *tf = (TypeFunction *)f->type; + if (tf->covariant(t) == 1 && + tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) + { + p->f = f; + return 1; + } + } +#endif + return 0; +} + +FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t, Module* from) +{ + Param1 p; + p.t = t; + p.f = NULL; + overloadApply(from, this, &fp1, &p); + return p.f; +} + +#if 0 +FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t) +{ + FuncDeclaration *f; + Declaration *d; + Declaration *next; + + for (d = this; d; d = next) + { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); + + if (fa) + { + FuncDeclaration *f2 = fa->funcalias->overloadExactMatch(t); + if (f2) + return f2; + next = fa->overnext; + } + else + { + AliasDeclaration *a = d->isAliasDeclaration(); + + if (a) + { + Dsymbol *s = a->toAlias(); + next = s->isDeclaration(); + if (next == a) + break; + } + else + { + f = d->isFuncDeclaration(); + if (!f) + break; // BUG: should print error message? + if (t->equals(d->type)) + return f; + next = f->overnext; + } + } + } + return NULL; +} +#endif + +/******************************************** + * Decide which function matches the arguments best. + */ + +struct Param2 +{ + Match *m; + Expressions *arguments; +}; + +int fp2(void *param, FuncDeclaration *f) +{ Param2 *p = (Param2 *)param; + Match *m = p->m; + Expressions *arguments = p->arguments; + MATCH match; + + if (f != m->lastf) // skip duplicates + { + m->anyf = f; + TypeFunction *tf = (TypeFunction *)f->type; + match = (MATCH) tf->callMatch(arguments); + //printf("1match = %d\n", match); + if (match != MATCHnomatch) + { + if (match > m->last) + goto LfIsBetter; + + if (match < m->last) + goto LlastIsBetter; + + /* See if one of the matches overrides the other. + */ + if (m->lastf->overrides(f)) + goto LlastIsBetter; + else if (f->overrides(m->lastf)) + goto LfIsBetter; + + Lambiguous: + m->nextf = f; + m->count++; + return 0; + + LfIsBetter: + m->last = match; + m->lastf = f; + m->count = 1; + return 0; + + LlastIsBetter: + return 0; + } + } + return 0; +} + + +void overloadResolveX(Match *m, FuncDeclaration *fstart, + Expression *ethis, Expressions *arguments, Module *from) +{ + Param2 p; + p.m = m; + p.arguments = arguments; + overloadApply(from, fstart, &fp2, &p); +} + +#if 0 +// Recursive helper function + +void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments) +{ + MATCH match; + Declaration *d; + Declaration *next; + + for (d = fstart; d; d = next) + { + FuncDeclaration *f; + FuncAliasDeclaration *fa; + AliasDeclaration *a; + + fa = d->isFuncAliasDeclaration(); + if (fa) + { + overloadResolveX(m, fa->funcalias, NULL, arguments); + next = fa->overnext; + } + else if ((f = d->isFuncDeclaration()) != NULL) + { + next = f->overnext; + if (f == m->lastf) + continue; // skip duplicates + else + { + TypeFunction *tf; + + m->anyf = f; + tf = (TypeFunction *)f->type; + match = (MATCH) tf->callMatch(arguments); + //printf("2match = %d\n", match); + if (match != MATCHnomatch) + { + if (match > m->last) + goto LfIsBetter; + + if (match < m->last) + goto LlastIsBetter; + + /* See if one of the matches overrides the other. + */ + if (m->lastf->overrides(f)) + goto LlastIsBetter; + else if (f->overrides(m->lastf)) + goto LfIsBetter; + + Lambiguous: + m->nextf = f; + m->count++; + continue; + + LfIsBetter: + m->last = match; + m->lastf = f; + m->count = 1; + continue; + + LlastIsBetter: + continue; + } + } + } + else if ((a = d->isAliasDeclaration()) != NULL) + { + Dsymbol *s = a->toAlias(); + next = s->isDeclaration(); + if (next == a) + break; + if (next == fstart) + break; + } + else + { d->error("is aliased to a function"); + break; + } + } +} +#endif + +FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, Module *from, int flags) +{ + TypeFunction *tf; + Match m; + +#if 0 +printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); +if (arguments) +{ int i; + + for (i = 0; i < arguments->dim; i++) + { Expression *arg; + + arg = (Expression *)arguments->data[i]; + assert(arg->type); + printf("\t%s: ", arg->toChars()); + arg->type->print(); + } +} +#endif + + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + overloadResolveX(&m, this, NULL, arguments, from); + + if (m.count == 1) // exactly one match + { + return m.lastf; + } + else + { + OutBuffer buf; + + if (arguments) + { + HdrGenState hgs; + + argExpTypesToCBuffer(&buf, arguments, &hgs); + } + + if (m.last == MATCHnomatch) + { + tf = (TypeFunction *)type; + + //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); + error(loc, "%s does not match parameter types (%s)", + Argument::argsTypesToChars(tf->parameters, tf->varargs), + buf.toChars()); + return m.anyf; // as long as it's not a FuncAliasDeclaration + } + else + { +#if 1 + TypeFunction *t1 = (TypeFunction *)m.lastf->type; + TypeFunction *t2 = (TypeFunction *)m.nextf->type; + + error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", + buf.toChars(), + m.lastf->toPrettyChars(), Argument::argsTypesToChars(t1->parameters, t1->varargs), + m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs)); +#else + error(loc, "overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); +#endif + return m.lastf; + } + } +} + +/******************************** + * Labels are in a separate scope, one per function. + */ + +LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident) +{ Dsymbol *s; + + if (!labtab) + labtab = new DsymbolTable(); // guess we need one + + s = labtab->lookup(ident); + if (!s) + { + s = new LabelDsymbol(ident); + labtab->insert(s); + } + return (LabelDsymbol *)s; +} + +/**************************************** + * If non-static member function that has a 'this' pointer, + * return the aggregate it is a member of. + * Otherwise, return NULL. + */ + +AggregateDeclaration *FuncDeclaration::isThis() +{ AggregateDeclaration *ad; + + //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); + ad = NULL; + if ((storage_class & STCstatic) == 0) + { + ad = isMember2(); + } + //printf("-FuncDeclaration::isThis() %p\n", ad); + return ad; +} + +AggregateDeclaration *FuncDeclaration::isMember2() +{ AggregateDeclaration *ad; + + //printf("+FuncDeclaration::isMember2() '%s'\n", toChars()); + ad = NULL; + for (Dsymbol *s = this; s; s = s->parent) + { +//printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind()); + ad = s->isMember(); + if (ad) +{ //printf("test4\n"); + break; +} + if (!s->parent || + (!s->parent->isTemplateInstance())) +{ //printf("test5\n"); + break; +} + } + //printf("-FuncDeclaration::isMember2() %p\n", ad); + return ad; +} + +/***************************************** + * Determine lexical level difference from 'this' to nested function 'fd'. + * Error if this cannot call fd. + * Returns: + * 0 same level + * -1 increase nesting by 1 (fd is nested within 'this') + * >0 decrease nesting by number + */ + +int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) +{ int level; + Dsymbol *s; + Dsymbol *fdparent; + + //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); + fdparent = fd->toParent2(); + if (fdparent == this) + return -1; + s = this; + level = 0; + while (fd != s && fdparent != s->toParent2()) + { + //printf("\ts = '%s'\n", s->toChars()); + FuncDeclaration *thisfd = s->isFuncDeclaration(); + if (thisfd) + { if (!thisfd->isNested() && !thisfd->vthis) + goto Lerr; + } + else + { + ClassDeclaration *thiscd = s->isClassDeclaration(); + if (thiscd) + { if (!thiscd->isNested()) + goto Lerr; + } + else + goto Lerr; + } + + s = s->toParent2(); + assert(s); + level++; + } + return level; + +Lerr: + error(loc, "cannot access frame of function %s", fd->toChars()); + return 1; +} + +void FuncDeclaration::appendExp(Expression *e) +{ Statement *s; + + s = new ExpStatement(0, e); + appendState(s); +} + +void FuncDeclaration::appendState(Statement *s) +{ CompoundStatement *cs; + + if (!fbody) + { Statements *a; + + a = new Statements(); + fbody = new CompoundStatement(0, a); + } + cs = fbody->isCompoundStatement(); + cs->statements->push(s); +} + +const char *FuncDeclaration::toPrettyChars() +{ + if (isMain()) + return "D main"; + else + return Dsymbol::toPrettyChars(); +} + +int FuncDeclaration::isMain() +{ + return ident == Id::main && + linkage != LINKc && !isMember() && !isNested(); +} + +int FuncDeclaration::isWinMain() +{ + //printf("FuncDeclaration::isWinMain() %s\n", toChars()); +#if 0 + int x = ident == Id::WinMain && + linkage != LINKc && !isMember(); + printf("%s\n", x ? "yes" : "no"); + return x; +#else + return ident == Id::WinMain && + linkage != LINKc && !isMember(); +#endif +} + +int FuncDeclaration::isDllMain() +{ + return ident == Id::DllMain && + linkage != LINKc && !isMember(); +} + +int FuncDeclaration::isExport() +{ + return protection == PROTexport; +} + +int FuncDeclaration::isImportedSymbol() +{ + //printf("isImportedSymbol()\n"); + //printf("protection = %d\n", protection); + return (protection == PROTexport) && !fbody; +} + +// Determine if function goes into virtual function pointer table + +int FuncDeclaration::isVirtual() +{ +#if 0 + printf("FuncDeclaration::isVirtual(%s)\n", toChars()); + printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); + printf("result is %d\n", + isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + toParent()->isClassDeclaration()); +#endif + return isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + toParent()->isClassDeclaration(); +} + +int FuncDeclaration::isFinal() +{ + ClassDeclaration *cd; +#if 0 + printf("FuncDeclaration::isFinal(%s)\n", toChars()); + printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); + printf("result is %d\n", + isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + (cd = toParent()->isClassDeclaration()) != NULL && + cd->storage_class & STCfinal); +#endif + return isMember() && + (Declaration::isFinal() || + ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); +} + +int FuncDeclaration::isAbstract() +{ + return storage_class & STCabstract; +} + +int FuncDeclaration::isCodeseg() +{ + return TRUE; // functions are always in the code segment +} + +// Determine if function needs +// a static frame pointer to its lexically enclosing function + +int FuncDeclaration::isNested() +{ + //if (!toParent()) + //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); + //printf("\ttoParent() = '%s'\n", toParent()->toChars()); + return ((storage_class & STCstatic) == 0) && toParent2() && + (toParent2()->isFuncDeclaration() != NULL); +} + +int FuncDeclaration::needThis() +{ + //printf("FuncDeclaration::needThis() '%s'\n", toChars()); + int i = isThis() != NULL; + //printf("\t%d\n", i); + if (!i && isFuncAliasDeclaration()) + i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); + return i; +} + +int FuncDeclaration::addPreInvariant() +{ + AggregateDeclaration *ad = isThis(); + return (ad && + //ad->isClassDeclaration() && + global.params.useInvariants && + (protection == PROTpublic || protection == PROTexport) && + !naked); +} + +int FuncDeclaration::addPostInvariant() +{ + AggregateDeclaration *ad = isThis(); + return (ad && + ad->inv && + //ad->isClassDeclaration() && + global.params.useInvariants && + (protection == PROTpublic || protection == PROTexport) && + !naked); +} + +/********************************** + * Generate a FuncDeclaration for a runtime library function. + */ + +// +// LDC: Adjusted to give argument info to the runtime function decl. +// + +FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, const char *name) +{ + return genCfunc(args, treturn, Lexer::idPool(name)); +} + +FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, Identifier *id) +{ + FuncDeclaration *fd; + TypeFunction *tf; + Dsymbol *s; + static DsymbolTable *st = NULL; + + //printf("genCfunc(name = '%s')\n", id->toChars()); + //printf("treturn\n\t"); treturn->print(); + + // See if already in table + if (!st) + st = new DsymbolTable(); + s = st->lookup(id); + if (s) + { + fd = s->isFuncDeclaration(); + assert(fd); + assert(fd->type->nextOf()->equals(treturn)); + } + else + { + tf = new TypeFunction(args, treturn, 0, LINKc); + fd = new FuncDeclaration(0, 0, id, STCstatic, tf); + fd->protection = PROTpublic; + fd->linkage = LINKc; + + st->insert(fd); + } + return fd; +} + +const char *FuncDeclaration::kind() +{ + return "function"; +} + +/******************************* + * Look at all the variables in this function that are referenced + * by nested functions, and determine if a closure needs to be + * created for them. + */ + +#if DMDV2 +int FuncDeclaration::needsClosure() +{ + /* Need a closure for all the closureVars[] if any of the + * closureVars[] are accessed by a + * function that escapes the scope of this function. + * We take the conservative approach and decide that any function that: + * 1) is a virtual function + * 2) has its address taken + * 3) has a parent that escapes + * + * Note that since a non-virtual function can be called by + * a virtual one, if that non-virtual function accesses a closure + * var, the closure still has to be taken. Hence, we check for isThis() + * instead of isVirtual(). (thanks to David Friedman) + */ + + //printf("FuncDeclaration::needsClosure() %s\n", toChars()); + for (int i = 0; i < closureVars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)closureVars.data[i]; + assert(v->isVarDeclaration()); + //printf("\tv = %s\n", v->toChars()); + + for (int j = 0; j < v->nestedrefs.dim; j++) + { FuncDeclaration *f = (FuncDeclaration *)v->nestedrefs.data[j]; + assert(f != this); + + //printf("\t\tf = %s, %d, %d\n", f->toChars(), f->isVirtual(), f->tookAddressOf); + if (f->isThis() || f->tookAddressOf) + goto Lyes; // assume f escapes this function's scope + + // Look to see if any parents of f that are below this escape + for (Dsymbol *s = f->parent; s && s != this; s = s->parent) + { + f = s->isFuncDeclaration(); + if (f && (f->isThis() || f->tookAddressOf)) + goto Lyes; + } + } + } + return 0; + +Lyes: + //printf("\tneeds closure\n"); + return 1; +} +#endif + +/****************************** FuncAliasDeclaration ************************/ + +// Used as a way to import a set of functions from another scope into this one. + +FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) + : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, + (enum STC)funcalias->storage_class, funcalias->type) +{ + assert(funcalias != this); + this->funcalias = funcalias; + importprot = PROTundefined; +} + +const char *FuncAliasDeclaration::kind() +{ + return "function alias"; +} + + +/****************************** FuncLiteralDeclaration ************************/ + +FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, + enum TOK tok, ForeachStatement *fes) + : FuncDeclaration(loc, endloc, NULL, STCundefined, type) +{ + const char *id; + + if (fes) + id = "__foreachbody"; + else if (tok == TOKdelegate) + id = "__dgliteral"; + else + id = "__funcliteral"; + this->ident = Identifier::generateId(id); + this->tok = tok; + this->fes = fes; + //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); +} + +Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) +{ + FuncLiteralDeclaration *f; + + //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + f = (FuncLiteralDeclaration *)s; + else + f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); + FuncDeclaration::syntaxCopy(f); + return f; +} + +int FuncLiteralDeclaration::isNested() +{ + //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); + return (tok == TOKdelegate); +} + +int FuncLiteralDeclaration::isVirtual() +{ + return FALSE; +} + +const char *FuncLiteralDeclaration::kind() +{ + // GCC requires the (char*) casts + return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; +} + +void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + static Identifier *idfunc; + static Identifier *iddel; + + if (!idfunc) + idfunc = new Identifier("function", 0); + if (!iddel) + iddel = new Identifier("delegate", 0); + + type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs); + bodyToCBuffer(buf, hgs); +} + + +/********************************* CtorDeclaration ****************************/ + +CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) + : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) +{ + this->arguments = arguments; + this->varargs = varargs; + //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); +} + +Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) +{ + CtorDeclaration *f; + + f = new CtorDeclaration(loc, endloc, NULL, varargs); + + f->outId = outId; + f->frequire = frequire ? frequire->syntaxCopy() : NULL; + f->fensure = fensure ? fensure->syntaxCopy() : NULL; + f->fbody = fbody ? fbody->syntaxCopy() : NULL; + assert(!fthrows); // deprecated + + f->arguments = Argument::arraySyntaxCopy(arguments); + return f; +} + + +void CtorDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + Type *tret; + + //printf("CtorDeclaration::semantic()\n"); + if (type) + return; + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static constructor + + parent = sc->parent; + Dsymbol *parent = toParent(); + cd = parent->isClassDeclaration(); + if (!cd) + { + error("constructors are only for class definitions"); + fatal(); + tret = Type::tvoid; + } + else + tret = cd->type; //->referenceTo(); + type = new TypeFunction(arguments, tret, varargs, LINKd); +#if STRUCTTHISREF + if (ad && ad->isStructDeclaration()) + ((TypeFunction *)type)->isref = 1; +#endif + if (!originalType) + originalType = type; + + sc->flags |= SCOPEctor; + type = type->semantic(loc, sc); + sc->flags &= ~SCOPEctor; + + // Append: + // return this; + // to the function body + if (fbody) + { + Expression *e = new ThisExp(loc); + Statement *s = new ReturnStatement(loc, e); + fbody = new CompoundStatement(loc, fbody, s); + } + + FuncDeclaration::semantic(sc); + + sc->pop(); + + // See if it's the default constructor + if (cd && varargs == 0 && Argument::dim(arguments) == 0) + cd->defaultCtor = this; +} + +const char *CtorDeclaration::kind() +{ + return "constructor"; +} + +char *CtorDeclaration::toChars() +{ + return (char *)"this"; +} + +int CtorDeclaration::isVirtual() +{ + return FALSE; +} + +int CtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int CtorDeclaration::addPostInvariant() +{ + return (isThis() && vthis && global.params.useInvariants); +} + + +void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this"); + Argument::argsToCBuffer(buf, hgs, arguments, varargs); + bodyToCBuffer(buf, hgs); +} + +/********************************* PostBlitDeclaration ****************************/ + +#if DMDV2 +PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::_postblit, STCundefined, NULL) +{ +} + +PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id) + : FuncDeclaration(loc, endloc, id, STCundefined, NULL) +{ +} + +Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, ident); + return FuncDeclaration::syntaxCopy(dd); +} + + +void PostBlitDeclaration::semantic(Scope *sc) +{ + //printf("PostBlitDeclaration::semantic() %s\n", toChars()); + //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); + parent = sc->parent; + Dsymbol *parent = toParent(); + StructDeclaration *ad = parent->isStructDeclaration(); + if (!ad) + { + error("post blits are only for struct/union definitions, not %s %s", parent->kind(), parent->toChars()); + } + else if (ident == Id::_postblit) + ad->postblits.push(this); + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not static + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int PostBlitDeclaration::overloadInsert(Dsymbol *s) +{ + return FALSE; // cannot overload postblits +} + +int PostBlitDeclaration::addPreInvariant() +{ + return FALSE; +} + +int PostBlitDeclaration::addPostInvariant() +{ + return (isThis() && vthis && global.params.useInvariants); +} + +int PostBlitDeclaration::isVirtual() +{ + return FALSE; +} + +void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("=this()"); + bodyToCBuffer(buf, hgs); +} +#endif + +/********************************* DtorDeclaration ****************************/ + +DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) +{ +} + +DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) + : FuncDeclaration(loc, endloc, id, STCundefined, NULL) +{ +} + +Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); + return FuncDeclaration::syntaxCopy(dd); +} + + +void DtorDeclaration::semantic(Scope *sc) +{ + //printf("DtorDeclaration::semantic() %s\n", toChars()); + //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); + parent = sc->parent; + Dsymbol *parent = toParent(); + ClassDeclaration *cd = parent->isClassDeclaration(); + if (!cd) + { + error("destructors are only for class/struct/union definitions, not %s %s", parent->kind(), parent->toChars()); + fatal(); + } + else + cd->dtors.push(this); + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static destructor + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int DtorDeclaration::overloadInsert(Dsymbol *s) +{ + return FALSE; // cannot overload destructors +} + +int DtorDeclaration::addPreInvariant() +{ + return (isThis() && vthis && global.params.useInvariants); +} + +int DtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +const char *DtorDeclaration::kind() +{ + return "destructor"; +} + +char *DtorDeclaration::toChars() +{ + return (char *)"~this"; +} + +int DtorDeclaration::isVirtual() +{ + /* This should be FALSE so that dtor's don't get put into the vtbl[], + * but doing so will require recompiling everything. + */ +#if BREAKABI + return FALSE; +#else + return FuncDeclaration::isVirtual(); +#endif +} + +void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("~this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* StaticCtorDeclaration ****************************/ + +StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, + Identifier::generateId("_staticCtor"), STCstatic, NULL) +{ +} + +Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticCtorDeclaration *scd; + + assert(!s); + scd = new StaticCtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(scd); +} + + +void StaticCtorDeclaration::semantic(Scope *sc) +{ + //printf("StaticCtorDeclaration::semantic()\n"); + + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + /* If the static ctor appears within a template instantiation, + * it could get called multiple times by the module constructors + * for different modules. Thus, protect it with a gate. + */ + if (inTemplateInstance()) + { + /* Add this prefix to the function: + * static int gate; + * if (++gate != 1) return; + * Note that this is not thread safe; should not have threads + * during static construction. + */ + Identifier *id = Lexer::idPool("__gate"); + VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); + v->storage_class = STCstatic; + Statements *sa = new Statements(); + Statement *s = new DeclarationStatement(0, v); + sa->push(s); + Expression *e = new IdentifierExp(0, id); + e = new AddAssignExp(0, e, new IntegerExp(1)); + e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); + s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); + sa->push(s); + if (fbody) + sa->push(fbody); + fbody = new CompoundStatement(0, sa); + } + + FuncDeclaration::semantic(sc); + + // We're going to need ModuleInfo + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { m->needmoduleinfo = 1; +#ifdef IN_GCC + m->strictlyneedmoduleinfo = 1; +#endif + } +} + +AggregateDeclaration *StaticCtorDeclaration::isThis() +{ + return NULL; +} + +int StaticCtorDeclaration::isStaticConstructor() +{ + return TRUE; +} + +int StaticCtorDeclaration::isVirtual() +{ + return FALSE; +} + +int StaticCtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int StaticCtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + { buf->writestring("static this();\n"); + return; + } + buf->writestring("static this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* StaticDtorDeclaration ****************************/ + +StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, + Identifier::generateId("_staticDtor"), STCstatic, NULL) +{ + vgate = NULL; +} + +Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticDtorDeclaration *sdd; + + assert(!s); + sdd = new StaticDtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(sdd); +} + + +void StaticDtorDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + Type *tret; + + cd = sc->scopesym->isClassDeclaration(); + if (!cd) + { + } + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + /* If the static ctor appears within a template instantiation, + * it could get called multiple times by the module constructors + * for different modules. Thus, protect it with a gate. + */ + if (inTemplateInstance()) + { + /* Add this prefix to the function: + * static int gate; + * if (--gate != 0) return; + * Increment gate during constructor execution. + * Note that this is not thread safe; should not have threads + * during static destruction. + */ + Identifier *id = Lexer::idPool("__gate"); + VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); + v->storage_class = STCstatic; + Statements *sa = new Statements(); + Statement *s = new DeclarationStatement(0, v); + sa->push(s); + Expression *e = new IdentifierExp(0, id); + e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); + e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(0)); + s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); + sa->push(s); + if (fbody) + sa->push(fbody); + fbody = new CompoundStatement(0, sa); + vgate = v; + } + + FuncDeclaration::semantic(sc); + + // We're going to need ModuleInfo + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { m->needmoduleinfo = 1; +#ifdef IN_GCC + m->strictlyneedmoduleinfo = 1; +#endif + } +} + +AggregateDeclaration *StaticDtorDeclaration::isThis() +{ + return NULL; +} + +int StaticDtorDeclaration::isStaticDestructor() +{ + return TRUE; +} + +int StaticDtorDeclaration::isVirtual() +{ + return FALSE; +} + +int StaticDtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int StaticDtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("static ~this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* InvariantDeclaration ****************************/ + +InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) +{ +} + +Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) +{ + InvariantDeclaration *id; + + assert(!s); + id = new InvariantDeclaration(loc, endloc); + FuncDeclaration::syntaxCopy(id); + return id; +} + + +void InvariantDeclaration::semantic(Scope *sc) +{ + AggregateDeclaration *ad; + Type *tret; + + parent = sc->parent; + Dsymbol *parent = toParent(); + ad = parent->isAggregateDeclaration(); + if (!ad) + { + error("invariants are only for struct/union/class definitions"); + return; + } + else if (ad->inv && ad->inv != this) + { + error("more than one invariant for %s", ad->toChars()); + } + ad->inv = this; + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static invariant + sc->incontract++; + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int InvariantDeclaration::isVirtual() +{ + return FALSE; +} + +int InvariantDeclaration::addPreInvariant() +{ + return FALSE; +} + +int InvariantDeclaration::addPostInvariant() +{ + return FALSE; +} + +void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("invariant"); + bodyToCBuffer(buf, hgs); +} + + +/********************************* UnitTestDeclaration ****************************/ + +/******************************* + * Generate unique unittest function Id so we can have multiple + * instances per module. + */ + +static Identifier *unitTestId() +{ + return Lexer::uniqueId("__unittest"); +} + +UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) +{ +} + +Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) +{ + UnitTestDeclaration *utd; + + assert(!s); + utd = new UnitTestDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(utd); +} + + +void UnitTestDeclaration::semantic(Scope *sc) +{ + if (global.params.useUnitTests) + { + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + Scope *sc2 = sc->push(); + sc2->linkage = LINKd; + FuncDeclaration::semantic(sc2); + sc2->pop(); + } + +#if 0 + // We're going to need ModuleInfo even if the unit tests are not + // compiled in, because other modules may import this module and refer + // to this ModuleInfo. + // (This doesn't make sense to me?) + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { + //printf("module3 %s needs moduleinfo\n", m->toChars()); + m->needmoduleinfo = 1; + } +#endif +} + +AggregateDeclaration *UnitTestDeclaration::isThis() +{ + return NULL; +} + +int UnitTestDeclaration::isVirtual() +{ + return FALSE; +} + +int UnitTestDeclaration::addPreInvariant() +{ + return FALSE; +} + +int UnitTestDeclaration::addPostInvariant() +{ + return FALSE; +} + +void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("unittest"); + bodyToCBuffer(buf, hgs); +} + +/********************************* NewDeclaration ****************************/ + +NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) + : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) +{ + this->arguments = arguments; + this->varargs = varargs; +} + +Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) +{ + NewDeclaration *f; + + f = new NewDeclaration(loc, endloc, NULL, varargs); + + FuncDeclaration::syntaxCopy(f); + + f->arguments = Argument::arraySyntaxCopy(arguments); + + return f; +} + + +void NewDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + Type *tret; + + //printf("NewDeclaration::semantic()\n"); + + parent = sc->parent; + Dsymbol *parent = toParent(); + cd = parent->isClassDeclaration(); + if (!cd && !parent->isStructDeclaration()) + { + error("new allocators only are for class or struct definitions"); + } + tret = Type::tvoid->pointerTo(); + type = new TypeFunction(arguments, tret, varargs, LINKd); + + type = type->semantic(loc, sc); + assert(type->ty == Tfunction); + + // Check that there is at least one argument of type size_t + TypeFunction *tf = (TypeFunction *)type; + if (Argument::dim(tf->parameters) < 1) + { + error("at least one argument of type size_t expected"); + } + else + { + Argument *a = Argument::getNth(tf->parameters, 0); + if (!a->type->equals(Type::tsize_t)) + error("first argument must be type size_t, not %s", a->type->toChars()); + } + + FuncDeclaration::semantic(sc); +} + +const char *NewDeclaration::kind() +{ + return "allocator"; +} + +int NewDeclaration::isVirtual() +{ + return FALSE; +} + +int NewDeclaration::addPreInvariant() +{ + return FALSE; +} + +int NewDeclaration::addPostInvariant() +{ + return FALSE; +} + +void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("new"); + Argument::argsToCBuffer(buf, hgs, arguments, varargs); + bodyToCBuffer(buf, hgs); +} + + +/********************************* DeleteDeclaration ****************************/ + +DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments) + : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) +{ + this->arguments = arguments; +} + +Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) +{ + DeleteDeclaration *f; + + f = new DeleteDeclaration(loc, endloc, NULL); + + FuncDeclaration::syntaxCopy(f); + + f->arguments = Argument::arraySyntaxCopy(arguments); + + return f; +} + + +void DeleteDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd; + + //printf("DeleteDeclaration::semantic()\n"); + + parent = sc->parent; + Dsymbol *parent = toParent(); + cd = parent->isClassDeclaration(); + if (!cd && !parent->isStructDeclaration()) + { + error("new allocators only are for class or struct definitions"); + } + type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); + + type = type->semantic(loc, sc); + assert(type->ty == Tfunction); + + // Check that there is only one argument of type void* + TypeFunction *tf = (TypeFunction *)type; + if (Argument::dim(tf->parameters) != 1) + { + error("one argument of type void* expected"); + } + else + { + Argument *a = Argument::getNth(tf->parameters, 0); + if (!a->type->equals(Type::tvoid->pointerTo())) + error("one argument of type void* expected, not %s", a->type->toChars()); + } + + FuncDeclaration::semantic(sc); +} + +const char *DeleteDeclaration::kind() +{ + return "deallocator"; +} + +int DeleteDeclaration::isDelete() +{ + return TRUE; +} + +int DeleteDeclaration::isVirtual() +{ + return FALSE; +} + +int DeleteDeclaration::addPreInvariant() +{ + return FALSE; +} + +int DeleteDeclaration::addPostInvariant() +{ + return FALSE; +} + +void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("delete"); + Argument::argsToCBuffer(buf, hgs, arguments, 0); + bodyToCBuffer(buf, hgs); +} + + + +
--- a/dmd/idgen.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/idgen.c Fri Nov 06 23:58:01 2009 +0100 @@ -38,6 +38,8 @@ { "dtor", "_dtor" }, { "classInvariant", "__invariant" }, { "unitTest", "_unitTest" }, + { "require", "__require" }, + { "ensure", "__ensure" }, { "init" }, { "size" }, { "__sizeof", "sizeof" }, @@ -207,6 +209,10 @@ { "aaKeys", "_aaKeys" }, { "aaValues", "_aaValues" }, { "aaRehash", "_aaRehash" }, + { "monitorenter", "_d_monitorenter" }, + { "monitorexit", "_d_monitorexit" }, + { "criticalenter", "_d_criticalenter" }, + { "criticalexit", "_d_criticalexit" }, // For pragma's { "GNU_asm" },
--- a/dmd/import.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/import.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -21,6 +21,7 @@ #include "mtype.h" #include "declaration.h" #include "id.h" +#include "attrib.h" /********************************* Import ****************************/ @@ -28,6 +29,7 @@ int isstatic) : Dsymbol(id) { + assert(id); this->loc = loc; this->packages = packages; this->id = id; @@ -84,21 +86,22 @@ void Import::load(Scope *sc) { - DsymbolTable *dst; - Dsymbol *s; - //printf("Import::load('%s')\n", toChars()); // See if existing module - dst = Package::resolve(packages, NULL, &pkg); + DsymbolTable *dst = Package::resolve(packages, NULL, &pkg); - s = dst->lookup(id); + Dsymbol *s = dst->lookup(id); if (s) { +#if TARGET_NET + mod = (Module *)s; +#else if (s->isModule()) mod = (Module *)s; else error("package and module have the same name"); +#endif } if (!mod) @@ -116,31 +119,54 @@ //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); } -char* escapePath(char* fname, char* buffer, int bufLen) { - char* res = buffer; - bufLen -= 2; // for \0 and an occasional escape char - int dst = 0; - for (; dst < bufLen && *fname; ++dst, ++fname) { - switch (*fname) { +void escapePath(OutBuffer *buf, const char *fname) +{ + while (1) + { + switch (*fname) + { + case 0: + return; case '(': case ')': case '\\': - buffer[dst++] = '\\'; - // fall through - + buf->writebyte('\\'); default: - buffer[dst] = *fname; + buf->writebyte(*fname); + break; } + fname++; } - buffer[dst] = '\0'; - return buffer; +} + +void Import::importAll(Scope *sc) +{ + if (!mod) + { + load(sc); + mod->importAll(0); + + if (!isstatic && !aliasId && !names.dim) + { + /* Default to private importing + */ + enum PROT prot = sc->protection; + if (!sc->explicitProtection) + prot = PROTprivate; + sc->scopesym->importScope(mod, prot); + } + } } void Import::semantic(Scope *sc) { //printf("Import::semantic('%s')\n", toChars()); - load(sc); + // Load if not already done so + if (!mod) + { load(sc); + mod->importAll(0); + } if (mod) { @@ -158,8 +184,6 @@ //printf("%s imports %s\n", sc->module->toChars(), mod->toChars()); sc->module->aimports.push(mod); - mod->semantic(); - /* Default to private importing */ protection = sc->protection; @@ -171,6 +195,8 @@ sc->scopesym->importScope(mod, protection); } + mod->semantic(); + if (mod->needmoduleinfo) sc->module->needmoduleinfo = 1; @@ -189,67 +215,76 @@ } //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); - - if (global.params.moduleDeps != NULL) { - char fnameBuf[262]; // MAX_PATH+2 - - OutBuffer *const ob = global.params.moduleDeps; - ob->printf("%s (%s) : ", - sc->module->toPrettyChars(), - escapePath(sc->module->srcfile->toChars(), fnameBuf, sizeof(fnameBuf) / sizeof(*fnameBuf)) - ); + if (global.params.moduleDeps != NULL) + { + /* The grammar of the file is: + * ImportDeclaration + * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " + * ModuleAliasIdentifier ] "\n" + * + * BasicImportDeclaration + * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection + * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" + * + * FilePath + * - any string with '(', ')' and '\' escaped with the '\' character + */ - char* protStr = ""; - switch (sc->protection) { - case PROTpublic: protStr = "public"; break; - case PROTprivate: protStr = "private"; break; - case PROTpackage: protStr = "package"; break; - default: break; - } - ob->writestring(protStr); - if (isstatic) { - ob->writestring(" static"); - } - ob->writestring(" : "); + OutBuffer *ob = global.params.moduleDeps; + + ob->writestring(sc->module->toPrettyChars()); + ob->writestring(" ("); + escapePath(ob, sc->module->srcfile->toChars()); + ob->writestring(") : "); - if (this->packages) { - for (size_t i = 0; i < this->packages->dim; i++) { - Identifier *pid = (Identifier *)this->packages->data[i]; + ProtDeclaration::protectionToCBuffer(ob, sc->protection); + if (isstatic) + StorageClassDeclaration::stcToCBuffer(ob, STCstatic); + ob->writestring(": "); + + if (packages) + { + for (size_t i = 0; i < packages->dim; i++) + { + Identifier *pid = (Identifier *)packages->data[i]; ob->printf("%s.", pid->toChars()); } } - ob->printf("%s (%s)", - this->id->toChars(), - mod ? escapePath(mod->srcfile->toChars(), fnameBuf, sizeof(fnameBuf) / sizeof(*fnameBuf)) : "???" - ); + ob->writestring(id->toChars()); + ob->writestring(" ("); + if (mod) + escapePath(ob, mod->srcfile->toChars()); + else + ob->writestring("???"); + ob->writebyte(')'); + + for (size_t i = 0; i < names.dim; i++) + { + if (i == 0) + ob->writebyte(':'); + else + ob->writebyte(','); - if (aliasId) { - ob->printf(" -> %s", aliasId->toChars()); - } else { - if (names.dim > 0) { - ob->writestring(" : "); - for (size_t i = 0; i < names.dim; i++) - { - if (i > 0) { - ob->writebyte(','); - } + Identifier *name = (Identifier *)names.data[i]; + Identifier *alias = (Identifier *)aliases.data[i]; - Identifier *name = (Identifier *)names.data[i]; - Identifier *alias = (Identifier *)aliases.data[i]; + if (!alias) + { + ob->printf("%s", name->toChars()); + alias = name; + } + else + ob->printf("%s=%s", alias->toChars(), name->toChars()); + } - if (!alias) { - ob->printf("%s", name->toChars()); - alias = name; - } else { - ob->printf("%s=%s", alias->toChars(), name->toChars()); - } - } - } - } + if (aliasId) + ob->printf(" -> %s", aliasId->toChars()); ob->writenl(); } + + //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); } void Import::semantic2(Scope *sc)
--- a/dmd/import.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/import.h Fri Nov 06 23:58:01 2009 +0100 @@ -1,67 +1,68 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_IMPORT_H -#define DMD_IMPORT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - - -struct Identifier; -struct Scope; -struct OutBuffer; -struct Module; -struct Package; -struct AliasDeclaration; -#ifdef _DH -struct HdrGenState; -#endif - -struct Import : Dsymbol -{ - Array *packages; // array of Identifier's representing packages - Identifier *id; // module Identifier - Identifier *aliasId; - int isstatic; // !=0 if static import - enum PROT protection; - - // Pairs of alias=name to bind into current namespace - Array names; - Array aliases; - - Array aliasdecls; // AliasDeclarations for names/aliases - - Module *mod; - Package *pkg; // leftmost package/module - - Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId, - int isstatic); - void addAlias(Identifier *name, Identifier *alias); - - const char *kind(); - enum PROT prot(); - Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - void load(Scope *sc); - void semantic(Scope *sc); - void semantic2(Scope *sc); - Dsymbol *toAlias(); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - int overloadInsert(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Import *isImport() { return this; } -}; - -#endif /* DMD_IMPORT_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_IMPORT_H +#define DMD_IMPORT_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "dsymbol.h" + + +struct Identifier; +struct Scope; +struct OutBuffer; +struct Module; +struct Package; +struct AliasDeclaration; +#ifdef _DH +struct HdrGenState; +#endif + +struct Import : Dsymbol +{ + Array *packages; // array of Identifier's representing packages + Identifier *id; // module Identifier + Identifier *aliasId; + int isstatic; // !=0 if static import + enum PROT protection; + + // Pairs of alias=name to bind into current namespace + Array names; + Array aliases; + + Array aliasdecls; // AliasDeclarations for names/aliases + + Module *mod; + Package *pkg; // leftmost package/module + + Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId, + int isstatic); + void addAlias(Identifier *name, Identifier *alias); + + const char *kind(); + enum PROT prot(); + Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees + void load(Scope *sc); + void importAll(Scope *sc); + void semantic(Scope *sc); + void semantic2(Scope *sc); + Dsymbol *toAlias(); + int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + int overloadInsert(Dsymbol *s); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Import *isImport() { return this; } +}; + +#endif /* DMD_IMPORT_H */
--- a/dmd/init.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/init.c Fri Nov 06 23:58:01 2009 +0100 @@ -396,32 +396,89 @@ { Expressions *elements; Expression *e; - //printf("ArrayInitializer::toExpression()\n"); + //printf("ArrayInitializer::toExpression(), dim = %d\n", dim); //static int i; if (++i == 2) halt(); + + size_t edim; + Type *t = NULL; + if (type) + { + if (type == Type::terror) + return new ErrorExp(); + + t = type->toBasetype(); + switch (t->ty) + { + case Tsarray: + edim = ((TypeSArray *)t)->dim->toInteger(); + break; + + case Tpointer: + case Tarray: + edim = dim; + break; + + default: + assert(0); + } + } + else + { + 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 (j >= edim) + edim = j + 1; + } + } + elements = new Expressions(); - for (size_t i = 0; i < value.dim; i++) + elements->setDim(edim); + for (size_t i = 0, j = 0; i < value.dim; i++, j++) { if (index.data[i]) - goto Lno; + j = ((Expression *)index.data[i])->toInteger(); + assert(j < edim); Initializer *iz = (Initializer *)value.data[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); if (!ex) + { goto Lno; - elements->push(ex); + } + elements->data[j] = ex; } - e = new ArrayLiteralExp(loc, elements); + + /* Fill in any missing elements with the default initializer + */ + { + Expression *init = NULL; + for (size_t i = 0; i < edim; i++) + { + if (!elements->data[i]) + { + if (!type) + goto Lno; + if (!init) + init = t->next->defaultInit(); + elements->data[i] = init; + } + } + + Expression *e = new ArrayLiteralExp(loc, elements); e->type = type; return e; + } Lno: delete elements; error(loc, "array initializers as expressions are not allowed"); - return NULL; + return new ErrorExp(); } - /******************************** * If possible, convert array initializer to associative array initializer. */ @@ -469,7 +526,7 @@ for (size_t i = 0; i < value.dim; i++) { if (index.data[i]) - goto Lno; + goto Laa; } if (value.dim) { @@ -482,9 +539,21 @@ } } -Lno: - error(loc, "cannot infer type from this array initializer"); - return Type::terror; +Laa: + /* It's possibly an associative array initializer + */ + Initializer *iz = (Initializer *)value.data[0]; + Expression *indexinit = (Expression *)index.data[0]; + if (iz && indexinit) + { Type *t = iz->inferType(sc); + indexinit = indexinit->semantic(sc); + Type *indext = indexinit->type; + t = new TypeAArray(t, indext); + type = t->semantic(loc, sc); + } + else + error(loc, "cannot infer type from this array initializer"); + return type; } @@ -569,14 +638,27 @@ exp = exp->semantic(sc); exp = resolveProperties(sc, exp); -#if DMDV2 // Give error for overloaded function addresses if (exp->op == TOKsymoff) { SymOffExp *se = (SymOffExp *)exp; - if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) + if ( +#if DMDV2 + se->hasOverloads && +#else + se->var->isFuncDeclaration() && +#endif + !se->var->isFuncDeclaration()->isUnique()) exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); } -#endif + + // Give error for overloaded function addresses + if (exp->op == TOKdelegate) + { DelegateExp *se = (DelegateExp *)exp; + if ( + se->func->isFuncDeclaration() && + !se->func->isFuncDeclaration()->isUnique()) + exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); + } Type *t = exp->type; if (!t)
--- a/dmd/inline.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/inline.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,1487 +1,1535 @@ - -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Routines to perform function inlining - -#define LOG 0 - -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#include "id.h" -#include "init.h" -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" - -/* ========== Compute cost of inlining =============== */ - -/* Walk trees to determine if inlining can be done, and if so, - * if it is too complex to be worth inlining or not. - */ - -struct InlineCostState -{ - int nested; - int hasthis; - int hdrscan; // !=0 if inline scan for 'header' content - FuncDeclaration *fd; -}; - -const int COST_MAX = 250; - -int Statement::inlineCost(InlineCostState *ics) -{ - return COST_MAX; // default is we can't inline it -} - -int ExpStatement::inlineCost(InlineCostState *ics) -{ - return exp ? exp->inlineCost(ics) : 0; -} - -int CompoundStatement::inlineCost(InlineCostState *ics) -{ int cost = 0; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - cost += s->inlineCost(ics); - if (cost >= COST_MAX) - break; - } - } - return cost; -} - -int UnrolledLoopStatement::inlineCost(InlineCostState *ics) -{ int cost = 0; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - cost += s->inlineCost(ics); - if (cost >= COST_MAX) - break; - } - } - return cost; -} - -int IfStatement::inlineCost(InlineCostState *ics) -{ - int cost; - -#if !IN_LLVM - /* Can't declare variables inside ?: expressions, so - * we cannot inline if a variable is declared. - */ - if (arg) - return COST_MAX; -#endif - - cost = condition->inlineCost(ics); - -#if !IN_LLVM - /* Specifically allow: - * if (condition) - * return exp1; - * else - * return exp2; - * Otherwise, we can't handle return statements nested in if's. - */ - - if (elsebody && ifbody && - ifbody->isReturnStatement() && - elsebody->isReturnStatement()) - { - cost += ifbody->inlineCost(ics); - cost += elsebody->inlineCost(ics); - //printf("cost = %d\n", cost); - } - else -#endif - { - ics->nested += 1; - if (ifbody) - cost += ifbody->inlineCost(ics); - if (elsebody) - cost += elsebody->inlineCost(ics); - ics->nested -= 1; - } - return cost; -} - -int ReturnStatement::inlineCost(InlineCostState *ics) -{ -#if !IN_LLVM - // Can't handle return statements nested in if's - if (ics->nested) - return COST_MAX; -#endif - return exp ? exp->inlineCost(ics) : 0; -} - -/* -------------------------- */ - -int arrayInlineCost(InlineCostState *ics, Array *arguments) -{ int cost = 0; - - if (arguments) - { - for (int i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - if (e) - cost += e->inlineCost(ics); - } - } - return cost; -} - -int Expression::inlineCost(InlineCostState *ics) -{ - return 1; -} - -int VarExp::inlineCost(InlineCostState *ics) -{ - //printf("VarExp::inlineCost() %s\n", toChars()); - return 1; -} - -int ThisExp::inlineCost(InlineCostState *ics) -{ -#if !IN_LLVM - FuncDeclaration *fd = ics->fd; - if (!ics->hdrscan) - if (fd->isNested() || !ics->hasthis) - return COST_MAX; -#endif - return 1; -} - -int SuperExp::inlineCost(InlineCostState *ics) -{ -#if !IN_LLVM - FuncDeclaration *fd = ics->fd; - if (!ics->hdrscan) - if (fd->isNested() || !ics->hasthis) - return COST_MAX; -#endif - return 1; -} - -int TupleExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, exps); -} - -int ArrayLiteralExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, elements); -} - -int AssocArrayLiteralExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, keys) + arrayInlineCost(ics, values); -} - -int StructLiteralExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, elements); -} - -int FuncExp::inlineCost(InlineCostState *ics) -{ - // This breaks on LDC too, since nested functions have internal linkage - // and thus can't be referenced from other objects. - // Right now, this makes the function be output to the .obj file twice. - return COST_MAX; -} - -int DelegateExp::inlineCost(InlineCostState *ics) -{ - // This breaks on LDC too, since nested functions have internal linkage - // and thus can't be referenced from other objects. - return COST_MAX; -} - -int DeclarationExp::inlineCost(InlineCostState *ics) -{ int cost = 0; - VarDeclaration *vd; - - //printf("DeclarationExp::inlineCost()\n"); - vd = declaration->isVarDeclaration(); - if (vd) - { - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { -#if 1 - return COST_MAX; // finish DeclarationExp::doInline -#else - for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = (Object *)td->objects->data[i]; - if (o->dyncast() != DYNCAST_EXPRESSION) - return COST_MAX; - Expression *eo = (Expression *)o; - if (eo->op != TOKdsymbol) - return COST_MAX; - } - return td->objects->dim; -#endif - } - // This breaks on LDC too, since nested static variables have internal - // linkage and thus can't be referenced from other objects. - if (!ics->hdrscan && vd->isDataseg()) - return COST_MAX; - cost += 1; - - // Scan initializer (vd->init) - if (vd->init) - { - ExpInitializer *ie = vd->init->isExpInitializer(); - - if (ie) - { - cost += ie->exp->inlineCost(ics); - } - } - } - - // These can contain functions, which when copied, get output twice. - // These break on LDC too, since nested static variables and functions have - // internal linkage and thus can't be referenced from other objects. - if (declaration->isStructDeclaration() || - declaration->isClassDeclaration() || - declaration->isFuncDeclaration() || - declaration->isTypedefDeclaration() || - declaration->isTemplateMixin()) - return COST_MAX; - - //printf("DeclarationExp::inlineCost('%s')\n", toChars()); - return cost; -} - -int UnaExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics); -} - -int AssertExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + (msg ? msg->inlineCost(ics) : 0); -} - -int BinExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + e2->inlineCost(ics); -} - -int CallExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); -} - -int SliceExp::inlineCost(InlineCostState *ics) -{ int cost; - - cost = 1 + e1->inlineCost(ics); - if (lwr) - cost += lwr->inlineCost(ics); - if (upr) - cost += upr->inlineCost(ics); - return cost; -} - -int ArrayExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); -} - - -int CondExp::inlineCost(InlineCostState *ics) -{ - return 1 + - e1->inlineCost(ics) + - e2->inlineCost(ics) + - econd->inlineCost(ics); -} - - -/* ======================== Perform the inlining ============================== */ - -/* Inlining is done by: - * o Converting to an Expression - * o Copying the trees of the function to be inlined - * o Renaming the variables - */ - -struct InlineDoState -{ - VarDeclaration *vthis; - Array from; // old Dsymbols - Array to; // parallel array of new Dsymbols - Dsymbol *parent; // new parent -}; - -Expression *Statement::doInline(InlineDoState *ids) -{ - assert(0); - return NULL; // default is we can't inline it -} - -Expression *ExpStatement::doInline(InlineDoState *ids) -{ -#if LOG - if (exp) printf("ExpStatement::doInline() '%s'\n", exp->toChars()); -#endif - return exp ? exp->doInline(ids) : NULL; -} - -Expression *CompoundStatement::doInline(InlineDoState *ids) -{ - Expression *e = NULL; - - //printf("CompoundStatement::doInline() %d\n", statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - Expression *e2 = s->doInline(ids); - e = Expression::combine(e, e2); - if (s->isReturnStatement()) - break; - - /* Check for: - * if (condition) - * return exp1; - * else - * return exp2; - */ - IfStatement *ifs = s->isIfStatement(); - if (ifs && ifs->elsebody && ifs->ifbody && - ifs->ifbody->isReturnStatement() && - ifs->elsebody->isReturnStatement() - ) - break; - - } - } - return e; -} - -Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) -{ - Expression *e = NULL; - - //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - Expression *e2 = s->doInline(ids); - e = Expression::combine(e, e2); - if (s->isReturnStatement()) - break; - } - } - return e; -} - -Expression *IfStatement::doInline(InlineDoState *ids) -{ - Expression *econd; - Expression *e1; - Expression *e2; - Expression *e; - - assert(!arg); - econd = condition->doInline(ids); - assert(econd); - if (ifbody) - e1 = ifbody->doInline(ids); - else - e1 = NULL; - if (elsebody) - e2 = elsebody->doInline(ids); - else - e2 = NULL; - if (e1 && e2) - { - e = new CondExp(econd->loc, econd, e1, e2); - e->type = e1->type; - } - else if (e1) - { - e = new AndAndExp(econd->loc, econd, e1); - e->type = Type::tvoid; - } - else if (e2) - { - e = new OrOrExp(econd->loc, econd, e2); - e->type = Type::tvoid; - } - else - { - e = econd; - } - return e; -} - -Expression *ReturnStatement::doInline(InlineDoState *ids) -{ - //printf("ReturnStatement::doInline() '%s'\n", exp ? exp->toChars() : ""); - return exp ? exp->doInline(ids) : 0; -} - -/* --------------------------------------------------------------- */ - -/****************************** - * Perform doInline() on an array of Expressions. - */ - -Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) -{ Expressions *newa = NULL; - - if (a) - { - newa = new Expressions(); - newa->setDim(a->dim); - - for (int i = 0; i < a->dim; i++) - { Expression *e = (Expression *)a->data[i]; - - if (e) - { - e = e->doInline(ids); - newa->data[i] = (void *)e; - } - } - } - return newa; -} - -Expression *Expression::doInline(InlineDoState *ids) -{ - //printf("Expression::doInline(%s): %s\n", Token::toChars(op), toChars()); - return copy(); -} - -Expression *SymOffExp::doInline(InlineDoState *ids) -{ - int i; - - //printf("SymOffExp::doInline(%s)\n", toChars()); - for (i = 0; i < ids->from.dim; i++) - { - if (var == (Declaration *)ids->from.data[i]) - { - SymOffExp *se = (SymOffExp *)copy(); - - se->var = (Declaration *)ids->to.data[i]; - return se; - } - } - return this; -} - -Expression *VarExp::doInline(InlineDoState *ids) -{ - int i; - - //printf("VarExp::doInline(%s)\n", toChars()); - for (i = 0; i < ids->from.dim; i++) - { - if (var == (Declaration *)ids->from.data[i]) - { - VarExp *ve = (VarExp *)copy(); - - ve->var = (Declaration *)ids->to.data[i]; - return ve; - } - } - return this; -} - -Expression *ThisExp::doInline(InlineDoState *ids) -{ - //if (!ids->vthis) - //error("no 'this' when inlining %s", ids->parent->toChars()); - if (!ids->vthis) - { - return this; - } - - VarExp *ve = new VarExp(loc, ids->vthis); - ve->type = type; - return ve; -} - -Expression *SuperExp::doInline(InlineDoState *ids) -{ - assert(ids->vthis); - - VarExp *ve = new VarExp(loc, ids->vthis); - ve->type = type; - return ve; -} - -Expression *DeclarationExp::doInline(InlineDoState *ids) -{ DeclarationExp *de = (DeclarationExp *)copy(); - VarDeclaration *vd; - - //printf("DeclarationExp::doInline(%s)\n", toChars()); - vd = declaration->isVarDeclaration(); - if (vd) - { -#if 0 - // Need to figure this out before inlining can work for tuples - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { - for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; - assert(se->op == TOKdsymbol); - se->s; - } - return st->objects->dim; - } -#endif - if (vd->isStatic() || vd->isConst()) - ; - else - { - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init) - { - if (vd->init->isVoidInitializer()) - { - vto->init = new VoidInitializer(vd->init->loc); - } - else - { - ExpInitializer *ie = vd->init->isExpInitializer(); - assert(ie); - vto->init = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - } - } - de->declaration = (Dsymbol *) (void *)vto; - } - } - /* This needs work, like DeclarationExp::toElem(), if we are - * to handle TemplateMixin's. For now, we just don't inline them. - */ - return de; -} - -Expression *NewExp::doInline(InlineDoState *ids) -{ - //printf("NewExp::doInline(): %s\n", toChars()); - NewExp *ne = (NewExp *)copy(); - - if (thisexp) - ne->thisexp = thisexp->doInline(ids); - ne->newargs = arrayExpressiondoInline(ne->newargs, ids); - ne->arguments = arrayExpressiondoInline(ne->arguments, ids); - return ne; -} - -Expression *UnaExp::doInline(InlineDoState *ids) -{ - UnaExp *ue = (UnaExp *)copy(); - - ue->e1 = e1->doInline(ids); - return ue; -} - -Expression *AssertExp::doInline(InlineDoState *ids) -{ - AssertExp *ae = (AssertExp *)copy(); - - ae->e1 = e1->doInline(ids); - if (msg) - ae->msg = msg->doInline(ids); - return ae; -} - -Expression *BinExp::doInline(InlineDoState *ids) -{ - BinExp *be = (BinExp *)copy(); - - be->e1 = e1->doInline(ids); - be->e2 = e2->doInline(ids); - return be; -} - -Expression *CallExp::doInline(InlineDoState *ids) -{ - CallExp *ce; - - ce = (CallExp *)copy(); - ce->e1 = e1->doInline(ids); - ce->arguments = arrayExpressiondoInline(arguments, ids); - return ce; -} - - -Expression *IndexExp::doInline(InlineDoState *ids) -{ - IndexExp *are = (IndexExp *)copy(); - - are->e1 = e1->doInline(ids); - - if (lengthVar) - { //printf("lengthVar\n"); - VarDeclaration *vd = lengthVar; - ExpInitializer *ie; - ExpInitializer *ieto; - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init) - { - ie = vd->init->isExpInitializer(); - assert(ie); - ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - vto->init = ieto; - } - - are->lengthVar = (VarDeclaration *) (void *)vto; - } - are->e2 = e2->doInline(ids); - return are; -} - - -Expression *SliceExp::doInline(InlineDoState *ids) -{ - SliceExp *are = (SliceExp *)copy(); - - are->e1 = e1->doInline(ids); - - if (lengthVar) - { //printf("lengthVar\n"); - VarDeclaration *vd = lengthVar; - ExpInitializer *ie; - ExpInitializer *ieto; - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init) - { - ie = vd->init->isExpInitializer(); - assert(ie); - ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - vto->init = ieto; - } - - are->lengthVar = (VarDeclaration *) (void *)vto; - } - if (lwr) - are->lwr = lwr->doInline(ids); - if (upr) - are->upr = upr->doInline(ids); - return are; -} - - -Expression *TupleExp::doInline(InlineDoState *ids) -{ - TupleExp *ce; - - ce = (TupleExp *)copy(); - ce->exps = arrayExpressiondoInline(exps, ids); - return ce; -} - - -Expression *ArrayLiteralExp::doInline(InlineDoState *ids) -{ - ArrayLiteralExp *ce; - - ce = (ArrayLiteralExp *)copy(); - ce->elements = arrayExpressiondoInline(elements, ids); - return ce; -} - - -Expression *AssocArrayLiteralExp::doInline(InlineDoState *ids) -{ - AssocArrayLiteralExp *ce; - - ce = (AssocArrayLiteralExp *)copy(); - ce->keys = arrayExpressiondoInline(keys, ids); - ce->values = arrayExpressiondoInline(values, ids); - return ce; -} - - -Expression *StructLiteralExp::doInline(InlineDoState *ids) -{ - StructLiteralExp *ce; - - ce = (StructLiteralExp *)copy(); - ce->elements = arrayExpressiondoInline(elements, ids); - return ce; -} - - -Expression *ArrayExp::doInline(InlineDoState *ids) -{ - ArrayExp *ce; - - ce = (ArrayExp *)copy(); - ce->e1 = e1->doInline(ids); - ce->arguments = arrayExpressiondoInline(arguments, ids); - return ce; -} - - -Expression *CondExp::doInline(InlineDoState *ids) -{ - CondExp *ce = (CondExp *)copy(); - - ce->econd = econd->doInline(ids); - ce->e1 = e1->doInline(ids); - ce->e2 = e2->doInline(ids); - return ce; -} - - -/* ========== Walk the parse trees, and inline expand functions ============= */ - -/* Walk the trees, looking for functions to inline. - * Inline any that can be. - */ - -struct InlineScanState -{ - FuncDeclaration *fd; // function being scanned -}; - -Statement *Statement::inlineScan(InlineScanState *iss) -{ - return this; -} - -Statement *ExpStatement::inlineScan(InlineScanState *iss) -{ -#if LOG - printf("ExpStatement::inlineScan(%s)\n", toChars()); -#endif - if (exp) - exp = exp->inlineScan(iss); - return this; -} - -Statement *CompoundStatement::inlineScan(InlineScanState *iss) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - statements->data[i] = (void *)s->inlineScan(iss); - } - return this; -} - -Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - statements->data[i] = (void *)s->inlineScan(iss); - } - return this; -} - -Statement *ScopeStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - -Statement *WhileStatement::inlineScan(InlineScanState *iss) -{ - condition = condition->inlineScan(iss); - body = body ? body->inlineScan(iss) : NULL; - return this; -} - - -Statement *DoStatement::inlineScan(InlineScanState *iss) -{ - body = body ? body->inlineScan(iss) : NULL; - condition = condition->inlineScan(iss); - return this; -} - - -Statement *ForStatement::inlineScan(InlineScanState *iss) -{ - if (init) - init = init->inlineScan(iss); - if (condition) - condition = condition->inlineScan(iss); - if (increment) - increment = increment->inlineScan(iss); - body = body->inlineScan(iss); - return this; -} - - -Statement *ForeachStatement::inlineScan(InlineScanState *iss) -{ - aggr = aggr->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -#if DMDV2 -Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss) -{ - lwr = lwr->inlineScan(iss); - upr = upr->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} -#endif - - -Statement *IfStatement::inlineScan(InlineScanState *iss) -{ - condition = condition->inlineScan(iss); - if (ifbody) - ifbody = ifbody->inlineScan(iss); - if (elsebody) - elsebody = elsebody->inlineScan(iss); - return this; -} - - -Statement *SwitchStatement::inlineScan(InlineScanState *iss) -{ - //printf("SwitchStatement::inlineScan()\n"); - condition = condition->inlineScan(iss); - body = body ? body->inlineScan(iss) : NULL; - if (sdefault) - sdefault = (DefaultStatement *)sdefault->inlineScan(iss); - if (cases) - { - for (int i = 0; i < cases->dim; i++) - { Statement *s; - - s = (Statement *) cases->data[i]; - cases->data[i] = (void *)s->inlineScan(iss); - } - } - return this; -} - - -Statement *CaseStatement::inlineScan(InlineScanState *iss) -{ - //printf("CaseStatement::inlineScan()\n"); - exp = exp->inlineScan(iss); - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *DefaultStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *ReturnStatement::inlineScan(InlineScanState *iss) -{ - //printf("ReturnStatement::inlineScan()\n"); - if (exp) - { - exp = exp->inlineScan(iss); - } - return this; -} - - -Statement *SynchronizedStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *WithStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *TryCatchStatement::inlineScan(InlineScanState *iss) -{ - if (body) - body = body->inlineScan(iss); - if (catches) - { - for (int i = 0; i < catches->dim; i++) - { Catch *c = (Catch *)catches->data[i]; - - if (c->handler) - c->handler = c->handler->inlineScan(iss); - } - } - return this; -} - - -Statement *TryFinallyStatement::inlineScan(InlineScanState *iss) -{ - if (body) - body = body->inlineScan(iss); - if (finalbody) - finalbody = finalbody->inlineScan(iss); - return this; -} - - -Statement *ThrowStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - return this; -} - - -Statement *VolatileStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *LabelStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - -/* -------------------------- */ - -void arrayInlineScan(InlineScanState *iss, Array *arguments) -{ - if (arguments) - { - for (int i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - if (e) - { - e = e->inlineScan(iss); - arguments->data[i] = (void *)e; - } - } - } -} - -Expression *Expression::inlineScan(InlineScanState *iss) -{ - return this; -} - -void scanVar(Dsymbol *s, InlineScanState *iss) -{ - VarDeclaration *vd = s->isVarDeclaration(); - if (vd) - { - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { - for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; - assert(se->op == TOKdsymbol); - scanVar(se->s, iss); - } - } - else - { - // Scan initializer (vd->init) - if (vd->init) - { - ExpInitializer *ie = vd->init->isExpInitializer(); - - if (ie) - { - ie->exp = ie->exp->inlineScan(iss); - } - } - } - } -} - -Expression *DeclarationExp::inlineScan(InlineScanState *iss) -{ - //printf("DeclarationExp::inlineScan()\n"); - scanVar(declaration, iss); - return this; -} - -Expression *UnaExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - return this; -} - -Expression *AssertExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - if (msg) - msg = msg->inlineScan(iss); - return this; -} - -Expression *BinExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - e2 = e2->inlineScan(iss); - return this; -} - - -Expression *CallExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("CallExp::inlineScan()\n"); - e1 = e1->inlineScan(iss); - arrayInlineScan(iss, arguments); - - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - FuncDeclaration *fd = ve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(0)) - { - e = fd->doInline(iss, NULL, arguments); - } - } - else if (e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *fd = dve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(1)) - { - if (dve->e1->op == TOKcall && - dve->e1->type->toBasetype()->ty == Tstruct) - { - /* To create ethis, we'll need to take the address - * of dve->e1, but this won't work if dve->e1 is - * a function call. - */ - ; - } - else - e = fd->doInline(iss, dve->e1, arguments); - } - } - - return e; -} - - -Expression *SliceExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - if (lwr) - lwr = lwr->inlineScan(iss); - if (upr) - upr = upr->inlineScan(iss); - return this; -} - - -Expression *TupleExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("TupleExp::inlineScan()\n"); - arrayInlineScan(iss, exps); - - return e; -} - - -Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("ArrayLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, elements); - - return e; -} - - -Expression *AssocArrayLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("AssocArrayLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, keys); - arrayInlineScan(iss, values); - - return e; -} - - -Expression *StructLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("StructLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, elements); - - return e; -} - - -Expression *ArrayExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("ArrayExp::inlineScan()\n"); - e1 = e1->inlineScan(iss); - arrayInlineScan(iss, arguments); - - return e; -} - - -Expression *CondExp::inlineScan(InlineScanState *iss) -{ - econd = econd->inlineScan(iss); - e1 = e1->inlineScan(iss); - e2 = e2->inlineScan(iss); - return this; -} - - -/* ========== =============== */ - -void FuncDeclaration::inlineScan() -{ - InlineScanState iss; - -#if LOG - printf("FuncDeclaration::inlineScan('%s')\n", toChars()); -#endif - memset(&iss, 0, sizeof(iss)); - iss.fd = this; - if (fbody) - { - inlineNest++; - fbody = fbody->inlineScan(&iss); - inlineNest--; - } -} - -int FuncDeclaration::canInline(int hasthis, int hdrscan) -{ - InlineCostState ics; - int cost; - -#define CANINLINE_LOG 0 - -#if CANINLINE_LOG - printf("FuncDeclaration::canInline(hasthis = %d, '%s')\n", hasthis, toChars()); -#endif - - if (needThis() && !hasthis) - return 0; - - if (inlineNest || (semanticRun < 3 && !hdrscan)) - { -#if CANINLINE_LOG - printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); -#endif - return 0; - } - - switch (inlineStatus) - { - case ILSyes: -#if CANINLINE_LOG - printf("\t1: yes %s\n", toChars()); -#endif - return 1; - - case ILSno: -#if CANINLINE_LOG - printf("\t1: no %s\n", toChars()); -#endif - return 0; - - case ILSuninitialized: - break; - - default: - assert(0); - } - - if (type) - { assert(type->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)(type); -#if IN_LLVM - // LDC: Only extern(C) varargs count. - if (tf->linkage != LINKd) -#endif - if (tf->varargs == 1) // no variadic parameter lists - goto Lno; - - /* Don't inline a function that returns non-void, but has - * no return expression. - */ - if (tf->next && tf->next->ty != Tvoid && - !(hasReturnExp & 1) && - !hdrscan) - goto Lno; - } -#if !IN_LLVM - // LDC: Only extern(C) varargs count, and ctors use extern(D). - else - { CtorDeclaration *ctor = isCtorDeclaration(); - - if (ctor && ctor->varargs == 1) - goto Lno; - } -#endif - - if ( - !fbody || - !hdrscan && - ( -#if 0 - isCtorDeclaration() || // cannot because need to convert: - // return; - // to: - // return this; -#endif - isSynchronized() || - isImportedSymbol() || -#if !IN_LLVM -#if DMDV2 - closureVars.dim || // no nested references to this frame -#else - nestedFrameRef || // no nested references to this frame -#endif -#endif // !IN_LLVM - (isVirtual() && !isFinal()) - )) - { - goto Lno; - } - -#if !IN_LLVM - /* If any parameters are Tsarray's (which are passed by reference) - * or out parameters (also passed by reference), don't do inlining. - */ - if (parameters) - { - for (int i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - if (v->isOut() || v->isRef() || v->type->toBasetype()->ty == Tsarray) - goto Lno; - } - } -#endif - - memset(&ics, 0, sizeof(ics)); - ics.hasthis = hasthis; - ics.fd = this; - ics.hdrscan = hdrscan; - cost = fbody->inlineCost(&ics); -#if CANINLINE_LOG - printf("cost = %d\n", cost); -#endif - if (cost >= COST_MAX) - goto Lno; - -#if !IN_LLVM - if (!hdrscan) // Don't scan recursively for header content scan - inlineScan(); -#endif - -Lyes: - if (!hdrscan) // Don't modify inlineStatus for header content scan - inlineStatus = ILSyes; -#if CANINLINE_LOG - printf("\t2: yes %s\n", toChars()); -#endif - return 1; - -Lno: - if (!hdrscan) // Don't modify inlineStatus for header content scan - inlineStatus = ILSno; -#if CANINLINE_LOG - printf("\t2: no %s\n", toChars()); -#endif - return 0; -} - -Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, Array *arguments) -{ - InlineDoState ids; - DeclarationExp *de; - Expression *e = NULL; - -#if LOG - printf("FuncDeclaration::doInline('%s')\n", toChars()); -#endif - - memset(&ids, 0, sizeof(ids)); - ids.parent = iss->fd; - - // Set up vthis - if (ethis) - { - VarDeclaration *vthis; - ExpInitializer *ei; - VarExp *ve; - - if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer) - { - ethis = ethis->addressOf(NULL); - } - - ei = new ExpInitializer(ethis->loc, ethis); - - vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); - vthis->storage_class = STCin; - vthis->linkage = LINKd; - vthis->parent = iss->fd; - - ve = new VarExp(vthis->loc, vthis); - ve->type = vthis->type; - - ei->exp = new AssignExp(vthis->loc, ve, ethis); - ei->exp->type = ve->type; - - ids.vthis = vthis; - } - - // Set up parameters - if (ethis) - { - e = new DeclarationExp(0, ids.vthis); - e->type = Type::tvoid; - } - - if (arguments && arguments->dim) - { - assert(parameters->dim == arguments->dim); - - for (int i = 0; i < arguments->dim; i++) - { - VarDeclaration *vfrom = (VarDeclaration *)parameters->data[i]; - VarDeclaration *vto; - Expression *arg = (Expression *)arguments->data[i]; - ExpInitializer *ei; - VarExp *ve; - - ei = new ExpInitializer(arg->loc, arg); - - vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei); - vto->storage_class |= vfrom->storage_class & (STCin | STCout | STClazy | STCref); - vto->linkage = vfrom->linkage; - vto->parent = iss->fd; - //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class); - //printf("vto->parent = '%s'\n", iss->fd->toChars()); - - ve = new VarExp(vto->loc, vto); - //ve->type = vto->type; - ve->type = arg->type; - - ei->exp = new AssignExp(vto->loc, ve, arg); - ei->exp->type = ve->type; -//ve->type->print(); -//arg->type->print(); -//ei->exp->print(); - - ids.from.push(vfrom); - ids.to.push(vto); - - de = new DeclarationExp(0, vto); - de->type = Type::tvoid; - - e = Expression::combine(e, de); - } - } - - inlineNest++; - Expression *eb = fbody->doInline(&ids); - inlineNest--; -//eb->type->print(); -//eb->print(); -//eb->dump(0); - return Expression::combine(e, eb); -} - - - + +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +// Routines to perform function inlining + +#define LOG 0 + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "id.h" +#include "init.h" +#include "declaration.h" +#include "aggregate.h" +#include "expression.h" +#include "statement.h" +#include "mtype.h" + +/* ========== Compute cost of inlining =============== */ + +/* Walk trees to determine if inlining can be done, and if so, + * if it is too complex to be worth inlining or not. + */ + +struct InlineCostState +{ + int nested; + int hasthis; + int hdrscan; // !=0 if inline scan for 'header' content + FuncDeclaration *fd; +}; + +const int COST_MAX = 250; + +int Statement::inlineCost(InlineCostState *ics) +{ + return COST_MAX; // default is we can't inline it +} + +int ExpStatement::inlineCost(InlineCostState *ics) +{ + return exp ? exp->inlineCost(ics) : 0; +} + +int CompoundStatement::inlineCost(InlineCostState *ics) +{ int cost = 0; + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + cost += s->inlineCost(ics); + if (cost >= COST_MAX) + break; + } + } + return cost; +} + +int UnrolledLoopStatement::inlineCost(InlineCostState *ics) +{ int cost = 0; + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + cost += s->inlineCost(ics); + if (cost >= COST_MAX) + break; + } + } + return cost; +} + +int IfStatement::inlineCost(InlineCostState *ics) +{ + int cost; + +#if !IN_LLVM + /* Can't declare variables inside ?: expressions, so + * we cannot inline if a variable is declared. + */ + if (arg) + return COST_MAX; +#endif + + cost = condition->inlineCost(ics); + +#if !IN_LLVM + /* Specifically allow: + * if (condition) + * return exp1; + * else + * return exp2; + * Otherwise, we can't handle return statements nested in if's. + */ + + if (elsebody && ifbody && + ifbody->isReturnStatement() && + elsebody->isReturnStatement()) + { + cost += ifbody->inlineCost(ics); + cost += elsebody->inlineCost(ics); + //printf("cost = %d\n", cost); + } + else +#endif + { + ics->nested += 1; + if (ifbody) + cost += ifbody->inlineCost(ics); + if (elsebody) + cost += elsebody->inlineCost(ics); + ics->nested -= 1; + } + return cost; +} + +int ReturnStatement::inlineCost(InlineCostState *ics) +{ +#if !IN_LLVM + // Can't handle return statements nested in if's + if (ics->nested) + return COST_MAX; +#endif + return exp ? exp->inlineCost(ics) : 0; +} + +/* -------------------------- */ + +int arrayInlineCost(InlineCostState *ics, Array *arguments) +{ int cost = 0; + + if (arguments) + { + for (int i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e) + cost += e->inlineCost(ics); + } + } + return cost; +} + +int Expression::inlineCost(InlineCostState *ics) +{ + return 1; +} + +int VarExp::inlineCost(InlineCostState *ics) +{ + //printf("VarExp::inlineCost() %s\n", toChars()); + return 1; +} + +int ThisExp::inlineCost(InlineCostState *ics) +{ +#if !IN_LLVM + FuncDeclaration *fd = ics->fd; + if (!ics->hdrscan) + if (fd->isNested() || !ics->hasthis) + return COST_MAX; +#endif + return 1; +} + +int SuperExp::inlineCost(InlineCostState *ics) +{ +#if !IN_LLVM + FuncDeclaration *fd = ics->fd; + if (!ics->hdrscan) + if (fd->isNested() || !ics->hasthis) + return COST_MAX; +#endif + return 1; +} + +int TupleExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, exps); +} + +int ArrayLiteralExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, elements); +} + +int AssocArrayLiteralExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, keys) + arrayInlineCost(ics, values); +} + +int StructLiteralExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, elements); +} + +int FuncExp::inlineCost(InlineCostState *ics) +{ + // This breaks on LDC too, since nested functions have internal linkage + // and thus can't be referenced from other objects. + // Right now, this makes the function be output to the .obj file twice. + return COST_MAX; +} + +int DelegateExp::inlineCost(InlineCostState *ics) +{ + // This breaks on LDC too, since nested functions have internal linkage + // and thus can't be referenced from other objects. + return COST_MAX; +} + +int DeclarationExp::inlineCost(InlineCostState *ics) +{ int cost = 0; + VarDeclaration *vd; + + //printf("DeclarationExp::inlineCost()\n"); + vd = declaration->isVarDeclaration(); + if (vd) + { + TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); + if (td) + { +#if 1 + return COST_MAX; // finish DeclarationExp::doInline +#else + for (size_t i = 0; i < td->objects->dim; i++) + { Object *o = (Object *)td->objects->data[i]; + if (o->dyncast() != DYNCAST_EXPRESSION) + return COST_MAX; + Expression *eo = (Expression *)o; + if (eo->op != TOKdsymbol) + return COST_MAX; + } + return td->objects->dim; +#endif + } + // This breaks on LDC too, since nested static variables have internal + // linkage and thus can't be referenced from other objects. + if (!ics->hdrscan && vd->isDataseg()) + return COST_MAX; + cost += 1; + + // Scan initializer (vd->init) + if (vd->init) + { + ExpInitializer *ie = vd->init->isExpInitializer(); + + if (ie) + { + cost += ie->exp->inlineCost(ics); + } + } + } + + // These can contain functions, which when copied, get output twice. + // These break on LDC too, since nested static variables and functions have + // internal linkage and thus can't be referenced from other objects. + if (declaration->isStructDeclaration() || + declaration->isClassDeclaration() || + declaration->isFuncDeclaration() || + declaration->isTypedefDeclaration() || + declaration->isTemplateMixin()) + return COST_MAX; + + //printf("DeclarationExp::inlineCost('%s')\n", toChars()); + return cost; +} + +int UnaExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics); +} + +int AssertExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + (msg ? msg->inlineCost(ics) : 0); +} + +int BinExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + e2->inlineCost(ics); +} + +int CallExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); +} + +int SliceExp::inlineCost(InlineCostState *ics) +{ int cost; + + cost = 1 + e1->inlineCost(ics); + if (lwr) + cost += lwr->inlineCost(ics); + if (upr) + cost += upr->inlineCost(ics); + return cost; +} + +int ArrayExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); +} + + +int CondExp::inlineCost(InlineCostState *ics) +{ + return 1 + + e1->inlineCost(ics) + + e2->inlineCost(ics) + + econd->inlineCost(ics); +} + + +/* ======================== Perform the inlining ============================== */ + +/* Inlining is done by: + * o Converting to an Expression + * o Copying the trees of the function to be inlined + * o Renaming the variables + */ + +struct InlineDoState +{ + VarDeclaration *vthis; + Array from; // old Dsymbols + Array to; // parallel array of new Dsymbols + Dsymbol *parent; // new parent +}; + +Expression *Statement::doInline(InlineDoState *ids) +{ + assert(0); + return NULL; // default is we can't inline it +} + +Expression *ExpStatement::doInline(InlineDoState *ids) +{ +#if LOG + if (exp) printf("ExpStatement::doInline() '%s'\n", exp->toChars()); +#endif + return exp ? exp->doInline(ids) : NULL; +} + +Expression *CompoundStatement::doInline(InlineDoState *ids) +{ + Expression *e = NULL; + + //printf("CompoundStatement::doInline() %d\n", statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + Expression *e2 = s->doInline(ids); + e = Expression::combine(e, e2); + if (s->isReturnStatement()) + break; + + /* Check for: + * if (condition) + * return exp1; + * else + * return exp2; + */ + IfStatement *ifs = s->isIfStatement(); + if (ifs && ifs->elsebody && ifs->ifbody && + ifs->ifbody->isReturnStatement() && + ifs->elsebody->isReturnStatement() + ) + break; + + } + } + return e; +} + +Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) +{ + Expression *e = NULL; + + //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + Expression *e2 = s->doInline(ids); + e = Expression::combine(e, e2); + if (s->isReturnStatement()) + break; + } + } + return e; +} + +Expression *IfStatement::doInline(InlineDoState *ids) +{ + Expression *econd; + Expression *e1; + Expression *e2; + Expression *e; + + assert(!arg); + econd = condition->doInline(ids); + assert(econd); + if (ifbody) + e1 = ifbody->doInline(ids); + else + e1 = NULL; + if (elsebody) + e2 = elsebody->doInline(ids); + else + e2 = NULL; + if (e1 && e2) + { + e = new CondExp(econd->loc, econd, e1, e2); + e->type = e1->type; + } + else if (e1) + { + e = new AndAndExp(econd->loc, econd, e1); + e->type = Type::tvoid; + } + else if (e2) + { + e = new OrOrExp(econd->loc, econd, e2); + e->type = Type::tvoid; + } + else + { + e = econd; + } + return e; +} + +Expression *ReturnStatement::doInline(InlineDoState *ids) +{ + //printf("ReturnStatement::doInline() '%s'\n", exp ? exp->toChars() : ""); + return exp ? exp->doInline(ids) : 0; +} + +/* --------------------------------------------------------------- */ + +/****************************** + * Perform doInline() on an array of Expressions. + */ + +Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) +{ Expressions *newa = NULL; + + if (a) + { + newa = new Expressions(); + newa->setDim(a->dim); + + for (int i = 0; i < a->dim; i++) + { Expression *e = (Expression *)a->data[i]; + + if (e) + { + e = e->doInline(ids); + newa->data[i] = (void *)e; + } + } + } + return newa; +} + +Expression *Expression::doInline(InlineDoState *ids) +{ + //printf("Expression::doInline(%s): %s\n", Token::toChars(op), toChars()); + return copy(); +} + +Expression *SymOffExp::doInline(InlineDoState *ids) +{ + int i; + + //printf("SymOffExp::doInline(%s)\n", toChars()); + for (i = 0; i < ids->from.dim; i++) + { + if (var == (Declaration *)ids->from.data[i]) + { + SymOffExp *se = (SymOffExp *)copy(); + + se->var = (Declaration *)ids->to.data[i]; + return se; + } + } + return this; +} + +Expression *VarExp::doInline(InlineDoState *ids) +{ + int i; + + //printf("VarExp::doInline(%s)\n", toChars()); + for (i = 0; i < ids->from.dim; i++) + { + if (var == (Declaration *)ids->from.data[i]) + { + VarExp *ve = (VarExp *)copy(); + + ve->var = (Declaration *)ids->to.data[i]; + return ve; + } + } + return this; +} + +Expression *ThisExp::doInline(InlineDoState *ids) +{ + //if (!ids->vthis) + //error("no 'this' when inlining %s", ids->parent->toChars()); + if (!ids->vthis) + { + return this; + } + + VarExp *ve = new VarExp(loc, ids->vthis); + ve->type = type; + return ve; +} + +Expression *SuperExp::doInline(InlineDoState *ids) +{ + assert(ids->vthis); + + VarExp *ve = new VarExp(loc, ids->vthis); + ve->type = type; + return ve; +} + +Expression *DeclarationExp::doInline(InlineDoState *ids) +{ DeclarationExp *de = (DeclarationExp *)copy(); + VarDeclaration *vd; + + //printf("DeclarationExp::doInline(%s)\n", toChars()); + vd = declaration->isVarDeclaration(); + if (vd) + { +#if 0 + // Need to figure this out before inlining can work for tuples + TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); + if (td) + { + for (size_t i = 0; i < td->objects->dim; i++) + { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; + assert(se->op == TOKdsymbol); + se->s; + } + return st->objects->dim; + } +#endif + if (vd->isStatic() || vd->isConst()) + ; + else + { + VarDeclaration *vto; + + vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); + *vto = *vd; + vto->parent = ids->parent; +#if IN_DMD + vto->csym = NULL; + vto->isym = NULL; +#endif + + ids->from.push(vd); + ids->to.push(vto); + + if (vd->init) + { + if (vd->init->isVoidInitializer()) + { + vto->init = new VoidInitializer(vd->init->loc); + } + else + { + ExpInitializer *ie = vd->init->isExpInitializer(); + assert(ie); + vto->init = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); + } + } + de->declaration = (Dsymbol *) (void *)vto; + } + } + /* This needs work, like DeclarationExp::toElem(), if we are + * to handle TemplateMixin's. For now, we just don't inline them. + */ + return de; +} + +Expression *NewExp::doInline(InlineDoState *ids) +{ + //printf("NewExp::doInline(): %s\n", toChars()); + NewExp *ne = (NewExp *)copy(); + + if (thisexp) + ne->thisexp = thisexp->doInline(ids); + ne->newargs = arrayExpressiondoInline(ne->newargs, ids); + ne->arguments = arrayExpressiondoInline(ne->arguments, ids); + return ne; +} + +Expression *UnaExp::doInline(InlineDoState *ids) +{ + UnaExp *ue = (UnaExp *)copy(); + + ue->e1 = e1->doInline(ids); + return ue; +} + +Expression *AssertExp::doInline(InlineDoState *ids) +{ + AssertExp *ae = (AssertExp *)copy(); + + ae->e1 = e1->doInline(ids); + if (msg) + ae->msg = msg->doInline(ids); + return ae; +} + +Expression *BinExp::doInline(InlineDoState *ids) +{ + BinExp *be = (BinExp *)copy(); + + be->e1 = e1->doInline(ids); + be->e2 = e2->doInline(ids); + return be; +} + +Expression *CallExp::doInline(InlineDoState *ids) +{ + CallExp *ce; + + ce = (CallExp *)copy(); + ce->e1 = e1->doInline(ids); + ce->arguments = arrayExpressiondoInline(arguments, ids); + return ce; +} + + +Expression *IndexExp::doInline(InlineDoState *ids) +{ + IndexExp *are = (IndexExp *)copy(); + + are->e1 = e1->doInline(ids); + + if (lengthVar) + { //printf("lengthVar\n"); + VarDeclaration *vd = lengthVar; + ExpInitializer *ie; + ExpInitializer *ieto; + VarDeclaration *vto; + + vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); + *vto = *vd; + vto->parent = ids->parent; +#if IN_DMD + vto->csym = NULL; + vto->isym = NULL; +#endif + + ids->from.push(vd); + ids->to.push(vto); + + if (vd->init) + { + ie = vd->init->isExpInitializer(); + assert(ie); + ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); + vto->init = ieto; + } + + are->lengthVar = (VarDeclaration *) (void *)vto; + } + are->e2 = e2->doInline(ids); + return are; +} + + +Expression *SliceExp::doInline(InlineDoState *ids) +{ + SliceExp *are = (SliceExp *)copy(); + + are->e1 = e1->doInline(ids); + + if (lengthVar) + { //printf("lengthVar\n"); + VarDeclaration *vd = lengthVar; + ExpInitializer *ie; + ExpInitializer *ieto; + VarDeclaration *vto; + + vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); + *vto = *vd; + vto->parent = ids->parent; +#if IN_DMD + vto->csym = NULL; + vto->isym = NULL; +#endif + + ids->from.push(vd); + ids->to.push(vto); + + if (vd->init) + { + ie = vd->init->isExpInitializer(); + assert(ie); + ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); + vto->init = ieto; + } + + are->lengthVar = (VarDeclaration *) (void *)vto; + } + if (lwr) + are->lwr = lwr->doInline(ids); + if (upr) + are->upr = upr->doInline(ids); + return are; +} + + +Expression *TupleExp::doInline(InlineDoState *ids) +{ + TupleExp *ce; + + ce = (TupleExp *)copy(); + ce->exps = arrayExpressiondoInline(exps, ids); + return ce; +} + + +Expression *ArrayLiteralExp::doInline(InlineDoState *ids) +{ + ArrayLiteralExp *ce; + + ce = (ArrayLiteralExp *)copy(); + ce->elements = arrayExpressiondoInline(elements, ids); + return ce; +} + + +Expression *AssocArrayLiteralExp::doInline(InlineDoState *ids) +{ + AssocArrayLiteralExp *ce; + + ce = (AssocArrayLiteralExp *)copy(); + ce->keys = arrayExpressiondoInline(keys, ids); + ce->values = arrayExpressiondoInline(values, ids); + return ce; +} + + +Expression *StructLiteralExp::doInline(InlineDoState *ids) +{ + StructLiteralExp *ce; + + ce = (StructLiteralExp *)copy(); + ce->elements = arrayExpressiondoInline(elements, ids); + return ce; +} + + +Expression *ArrayExp::doInline(InlineDoState *ids) +{ + ArrayExp *ce; + + ce = (ArrayExp *)copy(); + ce->e1 = e1->doInline(ids); + ce->arguments = arrayExpressiondoInline(arguments, ids); + return ce; +} + + +Expression *CondExp::doInline(InlineDoState *ids) +{ + CondExp *ce = (CondExp *)copy(); + + ce->econd = econd->doInline(ids); + ce->e1 = e1->doInline(ids); + ce->e2 = e2->doInline(ids); + return ce; +} + + +/* ========== Walk the parse trees, and inline expand functions ============= */ + +/* Walk the trees, looking for functions to inline. + * Inline any that can be. + */ + +struct InlineScanState +{ + FuncDeclaration *fd; // function being scanned +}; + +Statement *Statement::inlineScan(InlineScanState *iss) +{ + return this; +} + +Statement *ExpStatement::inlineScan(InlineScanState *iss) +{ +#if LOG + printf("ExpStatement::inlineScan(%s)\n", toChars()); +#endif + if (exp) + exp = exp->inlineScan(iss); + return this; +} + +Statement *CompoundStatement::inlineScan(InlineScanState *iss) +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + statements->data[i] = (void *)s->inlineScan(iss); + } + return this; +} + +Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss) +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + statements->data[i] = (void *)s->inlineScan(iss); + } + return this; +} + +Statement *ScopeStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + +Statement *WhileStatement::inlineScan(InlineScanState *iss) +{ + condition = condition->inlineScan(iss); + body = body ? body->inlineScan(iss) : NULL; + return this; +} + + +Statement *DoStatement::inlineScan(InlineScanState *iss) +{ + body = body ? body->inlineScan(iss) : NULL; + condition = condition->inlineScan(iss); + return this; +} + + +Statement *ForStatement::inlineScan(InlineScanState *iss) +{ + if (init) + init = init->inlineScan(iss); + if (condition) + condition = condition->inlineScan(iss); + if (increment) + increment = increment->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +Statement *ForeachStatement::inlineScan(InlineScanState *iss) +{ + aggr = aggr->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +#if DMDV2 +Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss) +{ + lwr = lwr->inlineScan(iss); + upr = upr->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} +#endif + + +Statement *IfStatement::inlineScan(InlineScanState *iss) +{ + condition = condition->inlineScan(iss); + if (ifbody) + ifbody = ifbody->inlineScan(iss); + if (elsebody) + elsebody = elsebody->inlineScan(iss); + return this; +} + + +Statement *SwitchStatement::inlineScan(InlineScanState *iss) +{ + //printf("SwitchStatement::inlineScan()\n"); + condition = condition->inlineScan(iss); + body = body ? body->inlineScan(iss) : NULL; + if (sdefault) + sdefault = (DefaultStatement *)sdefault->inlineScan(iss); + if (cases) + { + for (int i = 0; i < cases->dim; i++) + { Statement *s; + + s = (Statement *) cases->data[i]; + cases->data[i] = (void *)s->inlineScan(iss); + } + } + return this; +} + + +Statement *CaseStatement::inlineScan(InlineScanState *iss) +{ + //printf("CaseStatement::inlineScan()\n"); + exp = exp->inlineScan(iss); + if (statement) + statement = statement->inlineScan(iss); + return this; +} + + +Statement *DefaultStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + + +Statement *ReturnStatement::inlineScan(InlineScanState *iss) +{ + //printf("ReturnStatement::inlineScan()\n"); + if (exp) + { + exp = exp->inlineScan(iss); + } + return this; +} + + +Statement *SynchronizedStatement::inlineScan(InlineScanState *iss) +{ + if (exp) + exp = exp->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +Statement *WithStatement::inlineScan(InlineScanState *iss) +{ + if (exp) + exp = exp->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +Statement *TryCatchStatement::inlineScan(InlineScanState *iss) +{ + if (body) + body = body->inlineScan(iss); + if (catches) + { + for (int i = 0; i < catches->dim; i++) + { Catch *c = (Catch *)catches->data[i]; + + if (c->handler) + c->handler = c->handler->inlineScan(iss); + } + } + return this; +} + + +Statement *TryFinallyStatement::inlineScan(InlineScanState *iss) +{ + if (body) + body = body->inlineScan(iss); + if (finalbody) + finalbody = finalbody->inlineScan(iss); + return this; +} + + +Statement *ThrowStatement::inlineScan(InlineScanState *iss) +{ + if (exp) + exp = exp->inlineScan(iss); + return this; +} + + +Statement *VolatileStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + + +Statement *LabelStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + +/* -------------------------- */ + +void arrayInlineScan(InlineScanState *iss, Array *arguments) +{ + if (arguments) + { + for (int i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e) + { + e = e->inlineScan(iss); + arguments->data[i] = (void *)e; + } + } + } +} + +Expression *Expression::inlineScan(InlineScanState *iss) +{ + return this; +} + +void scanVar(Dsymbol *s, InlineScanState *iss) +{ + VarDeclaration *vd = s->isVarDeclaration(); + if (vd) + { + TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); + if (td) + { + for (size_t i = 0; i < td->objects->dim; i++) + { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; + assert(se->op == TOKdsymbol); + scanVar(se->s, iss); + } + } + else + { + // Scan initializer (vd->init) + if (vd->init) + { + ExpInitializer *ie = vd->init->isExpInitializer(); + + if (ie) + { +#if DMDV2 + if (vd->type) + { Type *tb = vd->type->toBasetype(); + if (tb->ty == Tstruct) + { StructDeclaration *sd = ((TypeStruct *)tb)->sym; + if (sd->cpctor) + { /* The problem here is that if the initializer is a + * function call that returns a struct S with a cpctor: + * S s = foo(); + * the postblit is done by the return statement in foo() + * in s2ir.c, the intermediate code generator. + * But, if foo() is inlined and now the code looks like: + * S s = x; + * the postblit is not there, because such assignments + * are rewritten as s.cpctor(&x) by the front end. + * So, the inlining won't get the postblit called. + * Work around by not inlining these cases. + * A proper fix would be to move all the postblit + * additions to the front end. + */ + return; + } + } + } +#endif + ie->exp = ie->exp->inlineScan(iss); + } + } + } + } +} + +Expression *DeclarationExp::inlineScan(InlineScanState *iss) +{ + //printf("DeclarationExp::inlineScan()\n"); + scanVar(declaration, iss); + return this; +} + +Expression *UnaExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + return this; +} + +Expression *AssertExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + if (msg) + msg = msg->inlineScan(iss); + return this; +} + +Expression *BinExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + e2 = e2->inlineScan(iss); + return this; +} + + +Expression *CallExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("CallExp::inlineScan()\n"); + e1 = e1->inlineScan(iss); + arrayInlineScan(iss, arguments); + + if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + FuncDeclaration *fd = ve->var->isFuncDeclaration(); + + if (fd && fd != iss->fd && fd->canInline(0)) + { + e = fd->doInline(iss, NULL, arguments); + } + } + else if (e1->op == TOKdotvar) + { + DotVarExp *dve = (DotVarExp *)e1; + FuncDeclaration *fd = dve->var->isFuncDeclaration(); + + if (fd && fd != iss->fd && fd->canInline(1)) + { + if (dve->e1->op == TOKcall && + dve->e1->type->toBasetype()->ty == Tstruct) + { + /* To create ethis, we'll need to take the address + * of dve->e1, but this won't work if dve->e1 is + * a function call. + */ + ; + } + else + e = fd->doInline(iss, dve->e1, arguments); + } + } + + return e; +} + + +Expression *SliceExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + if (lwr) + lwr = lwr->inlineScan(iss); + if (upr) + upr = upr->inlineScan(iss); + return this; +} + + +Expression *TupleExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("TupleExp::inlineScan()\n"); + arrayInlineScan(iss, exps); + + return e; +} + + +Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("ArrayLiteralExp::inlineScan()\n"); + arrayInlineScan(iss, elements); + + return e; +} + + +Expression *AssocArrayLiteralExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("AssocArrayLiteralExp::inlineScan()\n"); + arrayInlineScan(iss, keys); + arrayInlineScan(iss, values); + + return e; +} + + +Expression *StructLiteralExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("StructLiteralExp::inlineScan()\n"); + arrayInlineScan(iss, elements); + + return e; +} + + +Expression *ArrayExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("ArrayExp::inlineScan()\n"); + e1 = e1->inlineScan(iss); + arrayInlineScan(iss, arguments); + + return e; +} + + +Expression *CondExp::inlineScan(InlineScanState *iss) +{ + econd = econd->inlineScan(iss); + e1 = e1->inlineScan(iss); + e2 = e2->inlineScan(iss); + return this; +} + + +/* ========== =============== */ + +void FuncDeclaration::inlineScan() +{ + InlineScanState iss; + +#if LOG + printf("FuncDeclaration::inlineScan('%s')\n", toChars()); +#endif + memset(&iss, 0, sizeof(iss)); + iss.fd = this; + if (fbody) + { + inlineNest++; + fbody = fbody->inlineScan(&iss); + inlineNest--; + } +} + +int FuncDeclaration::canInline(int hasthis, int hdrscan) +{ + InlineCostState ics; + int cost; + +#define CANINLINE_LOG 0 + +#if CANINLINE_LOG + printf("FuncDeclaration::canInline(hasthis = %d, '%s')\n", hasthis, toChars()); +#endif + + if (needThis() && !hasthis) + return 0; + + if (inlineNest || (semanticRun < 3 && !hdrscan)) + { +#if CANINLINE_LOG + printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); +#endif + return 0; + } + + switch (inlineStatus) + { + case ILSyes: +#if CANINLINE_LOG + printf("\t1: yes %s\n", toChars()); +#endif + return 1; + + case ILSno: +#if CANINLINE_LOG + printf("\t1: no %s\n", toChars()); +#endif + return 0; + + case ILSuninitialized: + break; + + default: + assert(0); + } + + if (type) + { assert(type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)(type); +#if IN_LLVM + // LDC: Only extern(C) varargs count. + if (tf->linkage != LINKd) +#endif + if (tf->varargs == 1) // no variadic parameter lists + goto Lno; + + /* Don't inline a function that returns non-void, but has + * no return expression. + */ + if (tf->next && tf->next->ty != Tvoid && + !(hasReturnExp & 1) && + !hdrscan) + goto Lno; + } +#if !IN_LLVM + // LDC: Only extern(C) varargs count, and ctors use extern(D). + else + { CtorDeclaration *ctor = isCtorDeclaration(); + + if (ctor && ctor->varargs == 1) + goto Lno; + } +#endif + + if ( + !fbody || + !hdrscan && + ( +#if 0 + isCtorDeclaration() || // cannot because need to convert: + // return; + // to: + // return this; +#endif + isSynchronized() || + isImportedSymbol() || +#if !IN_LLVM +#if DMDV2 + closureVars.dim || // no nested references to this frame +#else + nestedFrameRef || // no nested references to this frame +#endif +#endif // !IN_LLVM + (isVirtual() && !isFinal()) + )) + { + goto Lno; + } + +#if !IN_LLVM + /* If any parameters are Tsarray's (which are passed by reference) + * or out parameters (also passed by reference), don't do inlining. + */ + if (parameters) + { + for (int i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + if (v->isOut() || v->isRef() || v->type->toBasetype()->ty == Tsarray) + goto Lno; + } + } +#endif + + memset(&ics, 0, sizeof(ics)); + ics.hasthis = hasthis; + ics.fd = this; + ics.hdrscan = hdrscan; + cost = fbody->inlineCost(&ics); +#if CANINLINE_LOG + printf("cost = %d\n", cost); +#endif + if (cost >= COST_MAX) + goto Lno; + +#if !IN_LLVM + if (!hdrscan) // Don't scan recursively for header content scan + inlineScan(); +#endif + +Lyes: + if (!hdrscan) // Don't modify inlineStatus for header content scan + inlineStatus = ILSyes; +#if CANINLINE_LOG + printf("\t2: yes %s\n", toChars()); +#endif + return 1; + +Lno: + if (!hdrscan) // Don't modify inlineStatus for header content scan + inlineStatus = ILSno; +#if CANINLINE_LOG + printf("\t2: no %s\n", toChars()); +#endif + return 0; +} + +Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, Array *arguments) +{ + InlineDoState ids; + DeclarationExp *de; + Expression *e = NULL; + +#if LOG + printf("FuncDeclaration::doInline('%s')\n", toChars()); +#endif + + memset(&ids, 0, sizeof(ids)); + ids.parent = iss->fd; + + // Set up vthis + if (ethis) + { + VarDeclaration *vthis; + ExpInitializer *ei; + VarExp *ve; + +#if STRUCTTHISREF + if (ethis->type->ty == Tpointer) + { Type *t = ethis->type->nextOf(); + ethis = new PtrExp(ethis->loc, ethis); + ethis->type = t; + } + ei = new ExpInitializer(ethis->loc, ethis); + + vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); + if (ethis->type->ty != Tclass) + vthis->storage_class = STCref; + else + vthis->storage_class = STCin; +#else + if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer) + { + ethis = ethis->addressOf(NULL); + } + + ei = new ExpInitializer(ethis->loc, ethis); + + vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); + vthis->storage_class = STCin; +#endif + vthis->linkage = LINKd; + vthis->parent = iss->fd; + + ve = new VarExp(vthis->loc, vthis); + ve->type = vthis->type; + + ei->exp = new AssignExp(vthis->loc, ve, ethis); + ei->exp->type = ve->type; +#if STRUCTTHISREF + if (ethis->type->ty != Tclass) + { /* This is a reference initialization, not a simple assignment. + */ + ei->exp->op = TOKconstruct; + } +#endif + + ids.vthis = vthis; + } + + // Set up parameters + if (ethis) + { + e = new DeclarationExp(0, ids.vthis); + e->type = Type::tvoid; + } + + if (arguments && arguments->dim) + { + assert(parameters->dim == arguments->dim); + + for (int i = 0; i < arguments->dim; i++) + { + VarDeclaration *vfrom = (VarDeclaration *)parameters->data[i]; + VarDeclaration *vto; + Expression *arg = (Expression *)arguments->data[i]; + ExpInitializer *ei; + VarExp *ve; + + ei = new ExpInitializer(arg->loc, arg); + + vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei); + vto->storage_class |= vfrom->storage_class & (STCin | STCout | STClazy | STCref); + vto->linkage = vfrom->linkage; + vto->parent = iss->fd; + //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class); + //printf("vto->parent = '%s'\n", iss->fd->toChars()); + + ve = new VarExp(vto->loc, vto); + //ve->type = vto->type; + ve->type = arg->type; + + ei->exp = new AssignExp(vto->loc, ve, arg); + ei->exp->type = ve->type; +//ve->type->print(); +//arg->type->print(); +//ei->exp->print(); + + ids.from.push(vfrom); + ids.to.push(vto); + + de = new DeclarationExp(0, vto); + de->type = Type::tvoid; + + e = Expression::combine(e, de); + } + } + + inlineNest++; + Expression *eb = fbody->doInline(&ids); + inlineNest--; +//eb->type->print(); +//eb->print(); +//eb->dump(0); + return Expression::combine(e, eb); +} + + +
--- a/dmd/interpret.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/interpret.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -34,6 +34,7 @@ Dsymbols vars; // variables used in this function Statement *start; // if !=NULL, start execution at this statement Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result + Expression *localThis; // value of 'this', or NULL if none InterState(); }; @@ -50,11 +51,14 @@ /************************************* * Attempt to interpret a function given the arguments. * Input: - * istate state for calling function (NULL if none) + * istate state for calling function (NULL if none) + * arguments function arguments + * thisarg 'this', if a needThis() function, NULL if not. + * * Return result expression if successful, NULL if not. */ -Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments) +Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg) { #if LOG printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); @@ -72,7 +76,7 @@ if (cantInterpret || semanticRun == 3) return NULL; - if (needThis() || isNested() || !fbody) + if (!fbody) { cantInterpret = 1; return NULL; } @@ -90,11 +94,13 @@ assert(tb->ty == Tfunction); TypeFunction *tf = (TypeFunction *)tb; Type *tret = tf->next->toBasetype(); - if (tf->varargs /*|| tret->ty == Tvoid*/) + if (tf->varargs) { cantInterpret = 1; + error("Variadic functions are not yet implemented in CTFE"); return NULL; } - + + // Ensure there are no lazy parameters if (tf->parameters) { size_t dim = Argument::dim(tf->parameters); for (size_t i = 0; i < dim; i++) @@ -109,13 +115,20 @@ InterState istatex; istatex.caller = istate; istatex.fd = this; + istatex.localThis = thisarg; Expressions vsave; // place to save previous parameter values size_t dim = 0; + if (needThis() && !thisarg) + { cantInterpret = 1; + // error, no this. Prevent segfault. + error("need 'this' to access member %s", toChars()); + return NULL; + } if (arguments) { dim = arguments->dim; - assert(!dim || parameters->dim == dim); + assert(!dim || (parameters && (parameters->dim == dim))); vsave.setDim(dim); /* Evaluate all the arguments to the function, @@ -144,7 +157,9 @@ } earg = earg->interpret(istate ? istate : &istatex); if (earg == EXP_CANT_INTERPRET) + { cantInterpret = 1; return NULL; + } } eargs.data[i] = earg; } @@ -157,23 +172,39 @@ #if LOG printf("arg[%d] = %s\n", i, earg->toChars()); #endif - if (arg->storageClass & (STCout | STCref)) + if (arg->storageClass & (STCout | STCref) && earg->op==TOKvar) { /* Bind out or ref parameter to the corresponding * variable v2 */ - if (!istate || earg->op != TOKvar) + if (!istate) + { cantInterpret = 1; + error("%s cannot be by passed by reference at compile time", earg->toChars()); return NULL; // can't bind to non-interpreted vars - + } + // We need to chase down all of the the passed parameters until + // we find something that isn't a TOKvar, then create a variable + // containg that expression. VarDeclaration *v2; while (1) { VarExp *ve = (VarExp *)earg; v2 = ve->var->isVarDeclaration(); if (!v2) + { cantInterpret = 1; return NULL; + } if (!v2->value || v2->value->op != TOKvar) break; +//TODO +#ifdef IN_DMD + if (((VarExp *)v2->value)->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + break; // eg default-initialized variable + } +#endif earg = v2->value; } @@ -191,8 +222,7 @@ } } else - { /* Value parameters - */ + { // Value parameters and non-trivial references v->value = earg; } #if LOG @@ -200,11 +230,22 @@ #endif } } + // Don't restore the value of 'this' upon function return + if (needThis() && thisarg->op==TOKvar) { + VarDeclaration *thisvar = ((VarExp *)(thisarg))->var->isVarDeclaration(); + 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) + if (istate && !isNested()) { //printf("saving local variables...\n"); valueSaves.setDim(istate->vars.dim); @@ -220,7 +261,6 @@ } Expression *e = NULL; - while (1) { e = fbody->interpret(&istatex); @@ -246,7 +286,6 @@ else break; } - /* Restore the parameter values */ for (size_t i = 0; i < dim; i++) @@ -255,7 +294,7 @@ v->value = (Expression *)vsave.data[i]; } - if (istate) + if (istate && !isNested()) { /* Restore the variable values */ @@ -268,7 +307,6 @@ } } } - return e; } @@ -478,7 +516,7 @@ return e; if (e == EXP_BREAK_INTERPRET) return NULL; - if (e != EXP_CONTINUE_INTERPRET) + if (e && e != EXP_CONTINUE_INTERPRET) return e; } @@ -758,7 +796,7 @@ while (1) { - e = Cmp(TOKlt, key->value->type, key->value, upr); + e = Cmp(TOKlt, key->value->type, key->value, eupr); if (e == EXP_CANT_INTERPRET) break; if (e->isBool(TRUE) == FALSE) @@ -773,19 +811,23 @@ { e = NULL; break; } - e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) + 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; - key->value = e; } } else // TOKforeach_reverse { key->value = eupr; - while (1) + do { - e = Cmp(TOKgt, key->value->type, key->value, lwr); + e = Cmp(TOKgt, key->value->type, key->value, elwr); if (e == EXP_CANT_INTERPRET) break; if (e->isBool(TRUE) == FALSE) @@ -805,7 +847,7 @@ { e = NULL; break; } - } + } while (e == NULL || e == EXP_CONTINUE_INTERPRET); } key->value = keysave; return e; @@ -946,6 +988,14 @@ printf("type = %s\n", type->toChars()); dump(0); #endif + error("Cannot interpret %s at compile time", toChars()); + return EXP_CANT_INTERPRET; +} + +Expression *ThisExp::interpret(InterState *istate) +{ + if (istate->localThis) + return istate->localThis->interpret(istate); return EXP_CANT_INTERPRET; } @@ -991,7 +1041,7 @@ if (v) { #if DMDV2 - if ((v->isConst() || v->isInvariant()) && v->init && !v->value) + if ((v->isConst() || v->isInvariant() || v->storage_class & STCmanifest) && v->init && !v->value) #else if (v->isConst() && v->init) #endif @@ -1001,7 +1051,11 @@ } else { e = v->value; - if (!e) + if (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); @@ -1060,6 +1114,8 @@ declaration->isTemplateMixin() || declaration->isTupleDeclaration()) { // These can be made to work, too lazy now + error("Declaration %s is not yet implemented in CTFE", toChars()); + e = EXP_CANT_INTERPRET; } else @@ -1067,7 +1123,7 @@ e = NULL; } #if LOG - printf("-DeclarationExp::interpret(): %p\n", e); + printf("-DeclarationExp::interpret(%s): %p\n", toChars(), e); #endif return e; } @@ -1257,7 +1313,9 @@ /* We don't know how to deal with overlapping fields */ if (sd->hasUnions) - return EXP_CANT_INTERPRET; + { error("Unions with overlapping fields are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; + } if (elements) { @@ -1429,6 +1487,98 @@ BIN_INTERPRET2(Identity) BIN_INTERPRET2(Cmp) +/* Helper functions for BinExp::interpretAssignCommon + */ + +/*************************************** + * Duplicate the elements array, then set field 'indexToChange' = newelem. + */ +Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, void *newelem) +{ + Expressions *expsx = new Expressions(); + expsx->setDim(oldelems->dim); + for (size_t j = 0; j < expsx->dim; j++) + { + if (j == indexToChange) + expsx->data[j] = newelem; + else + expsx->data[j] = oldelems->data[j]; + } + return expsx; +} + +/*************************************** + * Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint..$] + */ +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; +} + +/****************************** + * 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; +} + + +/******************************** + * Necessary because defaultInit() for a struct is a VarExp, not a StructLiteralExp. + */ +StructLiteralExp *createDefaultInitStructLiteral(Loc loc, StructDeclaration *sym) +{ + Expressions *structelems = new Expressions(); + structelems->setDim(sym->fields.dim); + for (size_t j = 0; j < structelems->dim; j++) + { + structelems->data[j] = ((VarDeclaration *)(sym->fields.data[j]))->type->defaultInit(); + } + StructLiteralExp *structinit = new StructLiteralExp(loc, sym, structelems); + // Why doesn't the StructLiteralExp constructor do this, when + // sym->type != NULL ? + structinit->type = sym->type; + return structinit; +} + +/******************************** + * 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; + } + } +} + Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) { #if LOG @@ -1449,7 +1599,43 @@ Expression *e2 = this->e2->interpret(istate); if (e2 == EXP_CANT_INTERPRET) return e2; + + // Chase down rebinding of out and ref. + if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && v->value && v->value->op == TOKvar) + { + VarExp *ve2 = (VarExp *)v->value; +//TODO +#ifdef IN_DMD + if (ve2->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + } + else +#endif + e1 = v->value; + } + else if (v && v->value && (v->value->op==TOKindex || v->value->op == TOKdotvar)) + { + // It is no longer be a TOKvar, eg when a[4] is passed by ref. + e1 = v->value; + } + } + // To reduce code complexity of handling dotvar expressions, + // extract the aggregate now. + Expression *aggregate; + if (e1->op == TOKdotvar) { + aggregate = ((DotVarExp *)e1)->e1; + // Get rid of 'this'. + if (aggregate->op == TOKthis && istate->localThis) + aggregate = istate->localThis; + } + /* Assignment to variable of the form: * v = e2 */ @@ -1457,25 +1643,14 @@ { VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); + assert(v); + if (v && v->isDataseg()) + { // Can't modify global or static data + error("%s cannot be modified at compile time", v->toChars()); + return EXP_CANT_INTERPRET; + } if (v && !v->isDataseg()) { - /* Chase down rebinding of out and ref - */ - if (v->value && v->value->op == TOKvar) - { - VarExp *ve2 = (VarExp *)v->value; - if (ve2->var->isStaticStructInitDeclaration()) - { - /* This can happen if v is a struct initialized to - * 0 using an StaticStructInitDeclaration from - * TypeStruct::defaultInit() - */ - } - else - v = ve2->var->isVarDeclaration(); - assert(v); - } - Expression *ev = v->value; if (fp && !ev) { error("variable %s is used before initialization", v->toChars()); @@ -1492,35 +1667,46 @@ } e2 = Cast(v->type, v->type, e2); } - if (e2 != EXP_CANT_INTERPRET) - { - 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; - } - } - v->value = e2; - e = Cast(type, type, post ? ev : e2); - } + if (e2 == EXP_CANT_INTERPRET) + return e2; + + addVarToInterstate(istate, v); + v->value = e2; + e = Cast(type, type, post ? ev : e2); } } + else if (e1->op == TOKdotvar && aggregate->op == TOKdotvar) + { // eg v.u.var = e2, v[3].u.var = e2, etc. + error("Nested struct assignment %s is not yet supported in CTFE", toChars()); + } /* Assignment to struct member of the form: * v.var = e2 */ - else if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKvar) - { VarExp *ve = (VarExp *)((DotVarExp *)e1)->e1; - VarDeclaration *v = ve->var->isVarDeclaration(); + else if (e1->op == TOKdotvar && aggregate->op == TOKvar) + { VarDeclaration *v = ((VarExp *)aggregate)->var->isVarDeclaration(); if (v->isDataseg()) + { // Can't modify global or static data + error("%s cannot be modified at compile time", v->toChars()); return EXP_CANT_INTERPRET; + } else { + // Chase down rebinding of out and ref + if (v->value && v->value->op == TOKvar) + { + VarExp *ve2 = (VarExp *)v->value; +//TODO +#ifdef IN_DMD + if (ve2->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + } + else +#endif + v = ve2->var->isVarDeclaration(); + assert(v); + } + } if (fp && !v->value) { error("variable %s is used before initialization", v->toChars()); return e; @@ -1557,30 +1743,11 @@ if (e2 == EXP_CANT_INTERPRET) return e2; - if (!v->isParameter()) - { - for (size_t i = 0; 1; i++) - { - if (i == istate->vars.dim) - { istate->vars.push(v); - break; - } - if (v == (VarDeclaration *)istate->vars.data[i]) - break; - } - } + addVarToInterstate(istate, v); /* Create new struct literal reflecting updated fieldi */ - Expressions *expsx = new Expressions(); - expsx->setDim(se->elements->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j == fieldi) - expsx->data[j] = (void *)e2; - else - expsx->data[j] = se->elements->data[j]; - } + Expressions *expsx = changeOneElement(se->elements, fieldi, e2); v->value = new StructLiteralExp(se->loc, se->sd, expsx); v->value->type = se->type; @@ -1594,7 +1761,10 @@ VarDeclaration *v = soe->var->isVarDeclaration(); if (v->isDataseg()) + { + 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; @@ -1619,30 +1789,11 @@ if (e2 == EXP_CANT_INTERPRET) return e2; - if (!v->isParameter()) - { - for (size_t i = 0; 1; i++) - { - if (i == istate->vars.dim) - { istate->vars.push(v); - break; - } - if (v == (VarDeclaration *)istate->vars.data[i]) - break; - } - } + addVarToInterstate(istate, v); /* Create new struct literal reflecting updated fieldi */ - Expressions *expsx = new Expressions(); - expsx->setDim(se->elements->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j == fieldi) - expsx->data[j] = (void *)e2; - else - expsx->data[j] = se->elements->data[j]; - } + Expressions *expsx = changeOneElement(se->elements, fieldi, e2); v->value = new StructLiteralExp(se->loc, se->sd, expsx); v->value->type = se->type; @@ -1655,9 +1806,26 @@ { IndexExp *ie = (IndexExp *)e1; VarExp *ve = (VarExp *)ie->e1; VarDeclaration *v = ve->var->isVarDeclaration(); - if (!v || v->isDataseg()) + { + error("%s cannot be modified at compile time", v ? v->toChars(): "void"); return EXP_CANT_INTERPRET; + } + if (v->value && v->value->op == TOKvar) + { + VarExp *ve2 = (VarExp *)v->value; +// TODO +#ifdef IN_DMD + if (ve2->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + } + else +#endif + v = ve2->var->isVarDeclaration(); + assert(v); + } if (!v->value) { if (fp) @@ -1675,15 +1843,10 @@ * But we're too lazy at the moment to do it, as that * involves redoing Index() and whoever calls it. */ - Expression *ev = v->type->defaultInit(); + size_t dim = ((TypeSArray *)t)->dim->toInteger(); - Expressions *elements = new Expressions(); - elements->setDim(dim); - for (size_t i = 0; i < dim; i++) - elements->data[i] = (void *)ev; - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); - ae->type = v->type; - v->value = ae; + v->value = createBlockDuplicatedArrayLiteral(v->type, + v->type->defaultInit(), dim); } else return EXP_CANT_INTERPRET; @@ -1698,9 +1861,20 @@ aae = (AssocArrayLiteralExp *)v->value; else if (v->value->op == TOKstring) se = (StringExp *)v->value; + else if (v->value->op == TOKnull) + { + // This would be a runtime segfault + error("Cannot index null array %s", v->toChars()); + return EXP_CANT_INTERPRET; + } else return EXP_CANT_INTERPRET; + /* Set the $ variable + */ + Expression *ee = ArrayLength(Type::tsize_t, v->value); + if (ee != EXP_CANT_INTERPRET && ie->lengthVar) + ie->lengthVar->value = ee; Expression *index = ie->e2->interpret(istate); if (index == EXP_CANT_INTERPRET) return EXP_CANT_INTERPRET; @@ -1718,34 +1892,14 @@ e2 = Cast(type, type, e2); if (e2 == EXP_CANT_INTERPRET) return e2; - - if (!v->isParameter()) - { - for (size_t i = 0; 1; i++) - { - if (i == istate->vars.dim) - { istate->vars.push(v); - break; - } - if (v == (VarDeclaration *)istate->vars.data[i]) - break; - } - } - + + addVarToInterstate(istate, v); if (ae) { /* Create new array literal reflecting updated elem */ int elemi = index->toInteger(); - Expressions *expsx = new Expressions(); - expsx->setDim(ae->elements->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j == elemi) - expsx->data[j] = (void *)e2; - else - expsx->data[j] = ae->elements->data[j]; - } + Expressions *expsx = changeOneElement(ae->elements, elemi, e2); v->value = new ArrayLiteralExp(ae->loc, expsx); v->value->type = ae->type; } @@ -1808,8 +1962,248 @@ e = Cast(type, type, post ? ev : e2); } + + /* Assignment to struct element in array, of the form: + * a[i].var = e2 + */ + else if (e1->op == TOKdotvar && aggregate->op == TOKindex && + ((IndexExp *)aggregate)->e1->op == TOKvar) + { + IndexExp * ie = (IndexExp *)aggregate; + VarExp *ve = (VarExp *)(ie->e1); + VarDeclaration *v = ve->var->isVarDeclaration(); + if (!v || v->isDataseg()) + { + error("%s cannot be modified at compile time", v ? v->toChars(): "void"); + return EXP_CANT_INTERPRET; + } + Type *t = ve->type->toBasetype(); + ArrayLiteralExp *ae = (ArrayLiteralExp *)v->value; + if (!ae) + { + // assignment to one element in an uninitialized (static) array. + // This is quite difficult, because defaultInit() for a struct is a VarExp, + // not a StructLiteralExp. + Type *t = v->type->toBasetype(); + if (t->ty != Tsarray) + { + error("Cannot index an uninitialized variable"); + return EXP_CANT_INTERPRET; + } + + Type *telem = ((TypeSArray *)t)->nextOf()->toBasetype(); + if (telem->ty != Tstruct) { return EXP_CANT_INTERPRET; } + + // Create a default struct literal... + StructDeclaration *sym = ((TypeStruct *)telem)->sym; + StructLiteralExp *structinit = createDefaultInitStructLiteral(v->loc, sym); + + // ... and use to create a blank array literal + size_t dim = ((TypeSArray *)t)->dim->toInteger(); + ae = createBlockDuplicatedArrayLiteral(v->type, structinit, dim); + v->value = ae; + } + if ((Expression *)(ae->elements) == EXP_CANT_INTERPRET) + { + // Note that this would be a runtime segfault + error("Cannot index null array %s", v->toChars()); + return EXP_CANT_INTERPRET; + } + // Set the $ variable + Expression *ee = ArrayLength(Type::tsize_t, v->value); + if (ee != EXP_CANT_INTERPRET && ie->lengthVar) + ie->lengthVar->value = ee; + // Determine the index, and check that it's OK. + Expression *index = ie->e2->interpret(istate); + if (index == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + int elemi = index->toInteger(); + if (elemi >= ae->elements->dim) + { + error("array index %d is out of bounds %s[0..%d]", elemi, + v->toChars(), ae->elements->dim); + return EXP_CANT_INTERPRET; + } + // Get old element + Expression *vie = (Expression *)(ae->elements->data[elemi]); + if (vie->op != TOKstructliteral) + return EXP_CANT_INTERPRET; + + // Work out which field needs to be changed + StructLiteralExp *se = (StructLiteralExp *)vie; + VarDeclaration *vf = ((DotVarExp *)e1)->var->isVarDeclaration(); + if (!vf) + return EXP_CANT_INTERPRET; + + int fieldi = se->getFieldIndex(type, vf->offset); + if (fieldi == -1) + return EXP_CANT_INTERPRET; + + Expression *ev = se->getField(type, vf->offset); + if (fp) + e2 = (*fp)(type, ev, e2); + else + e2 = Cast(type, type, e2); + if (e2 == EXP_CANT_INTERPRET) + return e2; + + // Create new struct literal reflecting updated field + Expressions *expsx = changeOneElement(se->elements, fieldi, e2); + Expression * newstruct = new StructLiteralExp(se->loc, se->sd, expsx); + + // Create new array literal reflecting updated struct elem + ae->elements = changeOneElement(ae->elements, elemi, newstruct); + return ae; + } + /* Slice assignment, initialization of static arrays + * a[] = e + */ + else if (e1->op == TOKslice && ((SliceExp *)e1)->e1->op==TOKvar) + { + SliceExp * sexp = (SliceExp *)e1; + VarExp *ve = (VarExp *)(sexp->e1); + VarDeclaration *v = ve->var->isVarDeclaration(); + if (!v || v->isDataseg()) + { + error("%s cannot be modified at compile time", v->toChars()); + return EXP_CANT_INTERPRET; + } + // Chase down rebinding of out and ref + if (v->value && v->value->op == TOKvar) + { + VarExp *ve2 = (VarExp *)v->value; +// TODO +#ifdef IN_DMD + if (ve2->var->isSymbolDeclaration()) + { // This can happen if v is a struct initialized to + // 0 using an __initZ SymbolDeclaration from + // TypeStruct::defaultInit() + } + else +#endif + v = ve2->var->isVarDeclaration(); + assert(v); + } + /* 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; + Expression *upper = NULL; + Expression *lower = NULL; + if (sexp->upr) + { + upper = sexp->upr->interpret(istate); + if (upper == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + if (sexp->lwr) + { + lower = sexp->lwr->interpret(istate); + if (lower == EXP_CANT_INTERPRET) + 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 (!v->value || v->value->op == TOKnull) + { + error("cannot assign to null array %s", v->toChars()); + return EXP_CANT_INTERPRET; + } + if (v->value->op == TOKarrayliteral) + dim = ((ArrayLiteralExp *)v->value)->elements->dim; + else if (v->value->op ==TOKstring) + { + error("String slice assignment is not yet supported in CTFE"); + return EXP_CANT_INTERPRET; + } + } + else + { + error("%s cannot be evaluated at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + int upperbound = upper ? upper->toInteger() : dim; + int lowerbound = lower ? lower->toInteger() : 0; + + ArrayLiteralExp *existing; + if (((int)lowerbound < 0) || (upperbound > dim)) + { + error("Array bounds [0..%d] exceeded in slice [%d..%d]", dim, lowerbound, upperbound); + return EXP_CANT_INTERPRET; + } + if (upperbound-lowerbound != dim) + { + // 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) + existing = (ArrayLiteralExp *)v->value; + else + { + // this can only happen with static arrays + existing = createBlockDuplicatedArrayLiteral(v->type, v->type->defaultInit(), dim); + } + } + + if (e2->op == TOKarrayliteral) + { + // Static array assignment from literal + ArrayLiteralExp *ae = (ArrayLiteralExp *)e2; + if (ae->elements->dim != (upperbound - lowerbound)) + { + error("Array length mismatch assigning [0..%d] to [%d..%d]", ae->elements->dim, lowerbound, upperbound); + return e; + } + if (upperbound - lowerbound == dim) + v->value = ae; + else + { + // value[] = value[0..lower] ~ ae ~ value[upper..$] + existing->elements = spliceElements(existing->elements, ae->elements, lowerbound); + v->value = existing; + } + return e2; + } + else if (t->nextOf()->ty == e2->type->ty) + { + // Static array block assignment + if (upperbound-lowerbound ==dim) + v->value = createBlockDuplicatedArrayLiteral(v->type, e2, dim); + else + { + // value[] = value[0..lower] ~ ae ~ value[upper..$] + existing->elements = spliceElements(existing->elements, createBlockDuplicatedArrayLiteral(v->type, e2, upperbound-lowerbound)->elements, lowerbound); + v->value = existing; + } + return e2; + } + else if (e2->op == TOKstring) + { + StringExp *se = (StringExp *)e2; + // This is problematic. char[8] should be storing + // values as a string literal, not + // as an array literal. Then, for static arrays, we + // could do modifications + // in-place, with a dramatic memory and speed improvement. + error("String slice assignment is not yet supported in CTFE"); + return e2; + } + else + { + error("Slice operation %s cannot be evaluated at compile time", toChars()); + return e; + } + } else { + error("%s cannot be evaluated at compile time", toChars()); #ifdef DEBUG dump(0); #endif @@ -1923,6 +2317,27 @@ #if LOG printf("CallExp::interpret() %s\n", toChars()); #endif + if (e1->op == TOKdotvar) + { + Expression * pthis = ((DotVarExp*)e1)->e1; + FuncDeclaration *fd = ((DotVarExp*)e1)->var->isFuncDeclaration(); + TypeFunction *tf = fd ? (TypeFunction *)(fd->type) : NULL; + if (tf) + { // Member function call + if(pthis->op == TOKthis) + pthis = istate->localThis; + Expression *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; + } + error("cannot evaluate %s at compile time", toChars()); + return EXP_CANT_INTERPRET; + } if (e1->op == TOKvar) { FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); @@ -2155,6 +2570,17 @@ #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) + return istate->localThis->interpret(istate); + } +if (this->e1->op == TOKthis) +{ + if(istate->localThis) + return istate->localThis->interpret(istate); +} e1 = this->e1->interpret(istate); if (e1 == EXP_CANT_INTERPRET) goto Lcant; @@ -2223,6 +2649,14 @@ } } } +#if DMDV2 +#else // this is required for D1, where structs return *this instead of 'this'. + else if (e1->op == TOKthis) + { + if(istate->localThis) + return istate->localThis->interpret(istate); + } +#endif #if LOG if (e == EXP_CANT_INTERPRET) printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); @@ -2249,7 +2683,7 @@ e = EXP_CANT_INTERPRET; return e; } - } + } else error("%s.%s is not yet implemented at compile time", ex->toChars(), var->toChars()); } #if LOG @@ -2278,7 +2712,9 @@ Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) { - //printf("interpret_aaKeys()\n"); +#if LOG + printf("interpret_aaKeys()\n"); +#endif if (!arguments || arguments->dim != 2) return NULL; Expression *earg = (Expression *)arguments->data[0]; @@ -2289,6 +2725,8 @@ return NULL; 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; } @@ -2305,6 +2743,8 @@ return NULL; 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)); //printf("result is %s\n", e->toChars()); return e; }
--- a/dmd/lexer.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/lexer.c Fri Nov 06 23:58:01 2009 +0100 @@ -1266,7 +1266,9 @@ } } if (ndigits != 2 && !utf_isValidDchar(v)) - error("invalid UTF character \\U%08x", v); + { error("invalid UTF character \\U%08x", v); + v = '?'; // recover with valid UTF character + } c = v; } else @@ -3071,6 +3073,7 @@ Token::tochars[TOKidentifier] = "identifier"; // For debugging + Token::tochars[TOKerror] = "error"; Token::tochars[TOKdotexp] = "dotexp"; Token::tochars[TOKdotti] = "dotti"; Token::tochars[TOKdotvar] = "dotvar";
--- a/dmd/lexer.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/lexer.h Fri Nov 06 23:58:01 2009 +0100 @@ -1,305 +1,307 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_LEXER_H -#define DMD_LEXER_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "mars.h" - -struct StringTable; -struct Identifier; -struct Module; - -/* Tokens: - ( ) - [ ] - { } - < > <= >= == != === !== - << >> <<= >>= >>> >>>= - + - += -= - * / % *= /= %= - & | ^ &= |= ^= - = ! ~ - ++ -- - . -> : , - ? && || - */ - -enum TOK -{ - TOKreserved, - - // Other - TOKlparen, TOKrparen, - TOKlbracket, TOKrbracket, - TOKlcurly, TOKrcurly, - TOKcolon, TOKneg, - TOKsemicolon, TOKdotdotdot, - TOKeof, TOKcast, - TOKnull, TOKassert, - TOKtrue, TOKfalse, - TOKarray, TOKcall, - TOKaddress, - TOKtype, TOKthrow, - TOKnew, TOKdelete, - TOKstar, TOKsymoff, - TOKvar, TOKdotvar, - TOKdotti, TOKdotexp, - TOKdottype, TOKslice, - TOKarraylength, TOKversion, - TOKmodule, TOKdollar, - TOKtemplate, TOKdottd, - TOKdeclaration, TOKtypeof, - TOKpragma, TOKdsymbol, - TOKtypeid, TOKuadd, - TOKremove, - TOKnewanonclass, TOKcomment, - TOKarrayliteral, TOKassocarrayliteral, - TOKstructliteral, - - // Operators - TOKlt, TOKgt, - TOKle, TOKge, - TOKequal, TOKnotequal, - TOKidentity, TOKnotidentity, - TOKindex, TOKis, - TOKtobool, - -// 60 - // NCEG floating point compares - // !<>= <> <>= !> !>= !< !<= !<> - TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue, - - TOKshl, TOKshr, - TOKshlass, TOKshrass, - TOKushr, TOKushrass, - TOKcat, TOKcatass, // ~ ~= - TOKadd, TOKmin, TOKaddass, TOKminass, - TOKmul, TOKdiv, TOKmod, - TOKmulass, TOKdivass, TOKmodass, - TOKand, TOKor, TOKxor, - TOKandass, TOKorass, TOKxorass, - TOKassign, TOKnot, TOKtilde, - TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, - TOKdot, TOKarrow, TOKcomma, - TOKquestion, TOKandand, TOKoror, - -// 104 - // Numeric literals - TOKint32v, TOKuns32v, - TOKint64v, TOKuns64v, - TOKfloat32v, TOKfloat64v, TOKfloat80v, - TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, - - // Char constants - TOKcharv, TOKwcharv, TOKdcharv, - - // Leaf operators - TOKidentifier, TOKstring, - TOKthis, TOKsuper, - TOKhalt, TOKtuple, - - // Basic types - TOKvoid, - TOKint8, TOKuns8, - TOKint16, TOKuns16, - TOKint32, TOKuns32, - TOKint64, TOKuns64, - TOKfloat32, TOKfloat64, TOKfloat80, - TOKimaginary32, TOKimaginary64, TOKimaginary80, - TOKcomplex32, TOKcomplex64, TOKcomplex80, - TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool, - TOKcent, TOKucent, - - // Aggregates - TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, - TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction, - TOKmixin, - - TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, - TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile, - TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, - TOKauto, TOKpackage, TOKmanifest, - - // Statements - TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, - TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, - TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, - TOKasm, TOKforeach, TOKforeach_reverse, - TOKscope, - TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, - - // Contracts - TOKbody, TOKinvariant, - - // Testing - TOKunittest, - - // Added after 1.0 - TOKref, - TOKmacro, -#if DMDV2 - TOKtraits, - TOKoverloadset, - TOKpure, - TOKnothrow, - TOKtls, - TOKline, - TOKfile, - TOKshared, -#endif - -// LDC specific -#if IN_LLVM - TOKgep, -#endif - - TOKMAX -}; - -#define CASE_BASIC_TYPES \ - case TOKwchar: case TOKdchar: \ - case TOKbit: case TOKbool: case TOKchar: \ - case TOKint8: case TOKuns8: \ - case TOKint16: case TOKuns16: \ - case TOKint32: case TOKuns32: \ - case TOKint64: case TOKuns64: \ - case TOKfloat32: case TOKfloat64: case TOKfloat80: \ - case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: \ - case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: \ - case TOKvoid - -#define CASE_BASIC_TYPES_X(t) \ - case TOKvoid: t = Type::tvoid; goto LabelX; \ - case TOKint8: t = Type::tint8; goto LabelX; \ - case TOKuns8: t = Type::tuns8; goto LabelX; \ - case TOKint16: t = Type::tint16; goto LabelX; \ - case TOKuns16: t = Type::tuns16; goto LabelX; \ - case TOKint32: t = Type::tint32; goto LabelX; \ - case TOKuns32: t = Type::tuns32; goto LabelX; \ - case TOKint64: t = Type::tint64; goto LabelX; \ - case TOKuns64: t = Type::tuns64; goto LabelX; \ - case TOKfloat32: t = Type::tfloat32; goto LabelX; \ - case TOKfloat64: t = Type::tfloat64; goto LabelX; \ - case TOKfloat80: t = Type::tfloat80; goto LabelX; \ - case TOKimaginary32: t = Type::timaginary32; goto LabelX; \ - case TOKimaginary64: t = Type::timaginary64; goto LabelX; \ - case TOKimaginary80: t = Type::timaginary80; goto LabelX; \ - 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; \ - case TOKdchar: t = Type::tdchar; goto LabelX; \ - LabelX - -struct Token -{ - Token *next; - unsigned char *ptr; // pointer to first character of this token within buffer - enum TOK value; - unsigned char *blockComment; // doc comment string prior to this token - unsigned char *lineComment; // doc comment for previous token - union - { - // Integers - d_int64 int64value; - d_uns64 uns64value; - - // Floats -#ifdef IN_GCC - // real_t float80value; // can't use this in a union! -#else - d_float80 float80value; -#endif - - struct - { unsigned char *ustring; // UTF8 string - unsigned len; - unsigned char postfix; // 'c', 'w', 'd' - }; - - Identifier *ident; - }; -#ifdef IN_GCC - real_t float80value; // can't use this in a union! -#endif - - static const char *tochars[TOKMAX]; - static void *operator new(size_t sz); - - int isKeyword(); - void print(); - const char *toChars(); - static const char *toChars(enum TOK); -}; - -struct Lexer -{ - static StringTable stringtable; - static OutBuffer stringbuffer; - static Token *freelist; - - Loc loc; // for error messages - - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character - Token token; - Module *mod; - int doDocComment; // collect doc comment information - int anyToken; // !=0 means seen at least one token - int commentToken; // !=0 means comments are TOKcomment's - - Lexer(Module *mod, - unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken); - - static void initKeywords(); - static Identifier *idPool(const char *s); - static Identifier *uniqueId(const char *s); - static Identifier *uniqueId(const char *s, int num); - - TOK nextToken(); - TOK peekNext(); - void scan(Token *t); - Token *peek(Token *t); - Token *peekPastParen(Token *t); - unsigned escapeSequence(); - TOK wysiwygStringConstant(Token *t, int tc); - TOK hexStringConstant(Token *t); -#if DMDV2 - TOK delimitedStringConstant(Token *t); - TOK tokenStringConstant(Token *t); -#endif - TOK escapeStringConstant(Token *t, int wide); - TOK charConstant(Token *t, int wide); - void stringPostfix(Token *t); - unsigned wchar(unsigned u); - TOK number(Token *t); - TOK inreal(Token *t); - void error(const char *format, ...) IS_PRINTF(2); - void error(Loc loc, const char *format, ...) IS_PRINTF(3); - void pragma(); - unsigned decodeUTF(); - void getDocComment(Token *t, unsigned lineComment); - - static int isValidIdentifier(char *p); - static unsigned char *combineComments(unsigned char *c1, unsigned char *c2); -}; - -#endif /* DMD_LEXER_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_LEXER_H +#define DMD_LEXER_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "mars.h" + +struct StringTable; +struct Identifier; +struct Module; + +/* Tokens: + ( ) + [ ] + { } + < > <= >= == != === !== + << >> <<= >>= >>> >>>= + + - += -= + * / % *= /= %= + & | ^ &= |= ^= + = ! ~ + ++ -- + . -> : , + ? && || + */ + +enum TOK +{ + TOKreserved, + + // Other + TOKlparen, TOKrparen, + TOKlbracket, TOKrbracket, + TOKlcurly, TOKrcurly, + TOKcolon, TOKneg, + TOKsemicolon, TOKdotdotdot, + TOKeof, TOKcast, + TOKnull, TOKassert, + TOKtrue, TOKfalse, + TOKarray, TOKcall, + TOKaddress, + TOKtype, TOKthrow, + TOKnew, TOKdelete, + TOKstar, TOKsymoff, + TOKvar, TOKdotvar, + TOKdotti, TOKdotexp, + TOKdottype, TOKslice, + TOKarraylength, TOKversion, + TOKmodule, TOKdollar, + TOKtemplate, TOKdottd, + TOKdeclaration, TOKtypeof, + TOKpragma, TOKdsymbol, + TOKtypeid, TOKuadd, + TOKremove, + TOKnewanonclass, TOKcomment, + TOKarrayliteral, TOKassocarrayliteral, + TOKstructliteral, + + // Operators + TOKlt, TOKgt, + TOKle, TOKge, + TOKequal, TOKnotequal, + TOKidentity, TOKnotidentity, + TOKindex, TOKis, + TOKtobool, + +// 60 + // NCEG floating point compares + // !<>= <> <>= !> !>= !< !<= !<> + TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue, + + TOKshl, TOKshr, + TOKshlass, TOKshrass, + TOKushr, TOKushrass, + TOKcat, TOKcatass, // ~ ~= + TOKadd, TOKmin, TOKaddass, TOKminass, + TOKmul, TOKdiv, TOKmod, + TOKmulass, TOKdivass, TOKmodass, + TOKand, TOKor, TOKxor, + TOKandass, TOKorass, TOKxorass, + TOKassign, TOKnot, TOKtilde, + TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, + TOKdot, TOKarrow, TOKcomma, + TOKquestion, TOKandand, TOKoror, + +// 104 + // Numeric literals + TOKint32v, TOKuns32v, + TOKint64v, TOKuns64v, + TOKfloat32v, TOKfloat64v, TOKfloat80v, + TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, + + // Char constants + TOKcharv, TOKwcharv, TOKdcharv, + + // Leaf operators + TOKidentifier, TOKstring, + TOKthis, TOKsuper, + TOKhalt, TOKtuple, + TOKerror, + + // Basic types + TOKvoid, + TOKint8, TOKuns8, + TOKint16, TOKuns16, + TOKint32, TOKuns32, + TOKint64, TOKuns64, + TOKfloat32, TOKfloat64, TOKfloat80, + TOKimaginary32, TOKimaginary64, TOKimaginary80, + TOKcomplex32, TOKcomplex64, TOKcomplex80, + TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool, + TOKcent, TOKucent, + +// 150 + // Aggregates + TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, + TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction, + TOKmixin, + + TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, + TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile, + TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, + TOKauto, TOKpackage, TOKmanifest, + + // Statements + TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, + TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, + TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, + TOKasm, TOKforeach, TOKforeach_reverse, + TOKscope, + TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, + + // Contracts + TOKbody, TOKinvariant, + + // Testing + TOKunittest, + + // Added after 1.0 + TOKref, + TOKmacro, +#if DMDV2 + TOKtraits, + TOKoverloadset, + TOKpure, + TOKnothrow, + TOKtls, + TOKline, + TOKfile, + TOKshared, +#endif + +// LDC specific +#if IN_LLVM + TOKgep, +#endif + + TOKMAX +}; + +#define CASE_BASIC_TYPES \ + case TOKwchar: case TOKdchar: \ + case TOKbit: case TOKbool: case TOKchar: \ + case TOKint8: case TOKuns8: \ + case TOKint16: case TOKuns16: \ + case TOKint32: case TOKuns32: \ + case TOKint64: case TOKuns64: \ + case TOKfloat32: case TOKfloat64: case TOKfloat80: \ + case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: \ + case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: \ + case TOKvoid + +#define CASE_BASIC_TYPES_X(t) \ + case TOKvoid: t = Type::tvoid; goto LabelX; \ + case TOKint8: t = Type::tint8; goto LabelX; \ + case TOKuns8: t = Type::tuns8; goto LabelX; \ + case TOKint16: t = Type::tint16; goto LabelX; \ + case TOKuns16: t = Type::tuns16; goto LabelX; \ + case TOKint32: t = Type::tint32; goto LabelX; \ + case TOKuns32: t = Type::tuns32; goto LabelX; \ + case TOKint64: t = Type::tint64; goto LabelX; \ + case TOKuns64: t = Type::tuns64; goto LabelX; \ + case TOKfloat32: t = Type::tfloat32; goto LabelX; \ + case TOKfloat64: t = Type::tfloat64; goto LabelX; \ + case TOKfloat80: t = Type::tfloat80; goto LabelX; \ + case TOKimaginary32: t = Type::timaginary32; goto LabelX; \ + case TOKimaginary64: t = Type::timaginary64; goto LabelX; \ + case TOKimaginary80: t = Type::timaginary80; goto LabelX; \ + 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; \ + case TOKdchar: t = Type::tdchar; goto LabelX; \ + LabelX + +struct Token +{ + Token *next; + unsigned char *ptr; // pointer to first character of this token within buffer + enum TOK value; + unsigned char *blockComment; // doc comment string prior to this token + unsigned char *lineComment; // doc comment for previous token + union + { + // Integers + d_int64 int64value; + d_uns64 uns64value; + + // Floats +#ifdef IN_GCC + // real_t float80value; // can't use this in a union! +#else + d_float80 float80value; +#endif + + struct + { unsigned char *ustring; // UTF8 string + unsigned len; + unsigned char postfix; // 'c', 'w', 'd' + }; + + Identifier *ident; + }; +#ifdef IN_GCC + real_t float80value; // can't use this in a union! +#endif + + static const char *tochars[TOKMAX]; + static void *operator new(size_t sz); + + int isKeyword(); + void print(); + const char *toChars(); + static const char *toChars(enum TOK); +}; + +struct Lexer +{ + static StringTable stringtable; + static OutBuffer stringbuffer; + static Token *freelist; + + Loc loc; // for error messages + + unsigned char *base; // pointer to start of buffer + unsigned char *end; // past end of buffer + unsigned char *p; // current character + Token token; + Module *mod; + int doDocComment; // collect doc comment information + int anyToken; // !=0 means seen at least one token + int commentToken; // !=0 means comments are TOKcomment's + + Lexer(Module *mod, + unsigned char *base, unsigned begoffset, unsigned endoffset, + int doDocComment, int commentToken); + + static void initKeywords(); + static Identifier *idPool(const char *s); + static Identifier *uniqueId(const char *s); + static Identifier *uniqueId(const char *s, int num); + + TOK nextToken(); + TOK peekNext(); + void scan(Token *t); + Token *peek(Token *t); + Token *peekPastParen(Token *t); + unsigned escapeSequence(); + TOK wysiwygStringConstant(Token *t, int tc); + TOK hexStringConstant(Token *t); +#if DMDV2 + TOK delimitedStringConstant(Token *t); + TOK tokenStringConstant(Token *t); +#endif + TOK escapeStringConstant(Token *t, int wide); + TOK charConstant(Token *t, int wide); + void stringPostfix(Token *t); + unsigned wchar(unsigned u); + TOK number(Token *t); + TOK inreal(Token *t); + void error(const char *format, ...) IS_PRINTF(2); + void error(Loc loc, const char *format, ...) IS_PRINTF(3); + void pragma(); + unsigned decodeUTF(); + void getDocComment(Token *t, unsigned lineComment); + + static int isValidIdentifier(char *p); + static unsigned char *combineComments(unsigned char *c1, unsigned char *c2); +}; + +#endif /* DMD_LEXER_H */
--- a/dmd/mangle.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/mangle.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,292 +1,297 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <assert.h> - -#include "root.h" - -#include "init.h" -#include "declaration.h" -#include "aggregate.h" -#include "mtype.h" -#include "attrib.h" -#include "template.h" -#include "id.h" -#include "module.h" - -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS -char *cpp_mangle(Dsymbol *s); -#endif - -char *mangle(Declaration *sthis) -{ - OutBuffer buf; - char *id; - Dsymbol *s; - - //printf("::mangle(%s)\n", sthis->toChars()); - s = sthis; - do - { - //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); - if (s->ident) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (s != sthis && fd) - { - id = mangle(fd); - buf.prependstring(id); - goto L1; - } - else - { - id = s->ident->toChars(); - int len = strlen(id); - char tmp[sizeof(len) * 3 + 1]; - buf.prependstring(id); - sprintf(tmp, "%d", len); - buf.prependstring(tmp); - } - } - else - buf.prependstring("0"); - s = s->parent; - } while (s); - -// buf.prependstring("_D"); -L1: - //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); - //printf("sthis->type = %s\n", sthis->type->toChars()); - FuncDeclaration *fd = sthis->isFuncDeclaration(); - if (fd && (fd->needThis() || fd->isNested())) - buf.writeByte(Type::needThisPrefix()); - if (sthis->type->deco) - buf.writestring(sthis->type->deco); - else - { assert(fd->inferRetType); - } - - id = buf.toChars(); - buf.data = NULL; - return id; -} - -char *Declaration::mangle() -#if __DMC__ - __out(result) - { - int len = strlen(result); - - assert(len > 0); - //printf("mangle: '%s' => '%s'\n", toChars(), result); - for (int i = 0; i < len; i++) - { - assert(result[i] == '_' || - result[i] == '@' || - isalnum(result[i]) || result[i] & 0x80); - } - } - __body -#endif - { - //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent->toChars() : "null", linkage); - if (!parent || parent->isModule()) // if at global scope - { - // If it's not a D declaration, no mangling - switch (linkage) - { - case LINKd: - break; - - // LDC - case LINKintrinsic: - - case LINKc: - case LINKwindows: - case LINKpascal: - return ident->toChars(); - - case LINKcpp: -#if DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS) - return cpp_mangle(this); -#else - // Windows C++ mangling is done by C++ back end - return ident->toChars(); -#endif - - case LINKdefault: - error("forward declaration"); - return ident->toChars(); - - default: - fprintf(stdmsg, "'%s', linkage = %d\n", toChars(), linkage); - assert(0); - } - } - char *p = ::mangle(this); - OutBuffer buf; - buf.writestring("_D"); - buf.writestring(p); - p = buf.toChars(); - buf.data = NULL; - //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent->toChars() : "null", linkage, p); - return p; - } - -char *FuncDeclaration::mangle() -#if __DMC__ - __out(result) - { - assert(strlen(result) > 0); - } - __body -#endif - { - if (isMain()) - return (char *)"_Dmain"; - - if (isWinMain() || isDllMain()) - return ident->toChars(); - - assert(this); - return Declaration::mangle(); - } - -char *StructDeclaration::mangle() -{ - //printf("StructDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *TypedefDeclaration::mangle() -{ - //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *ClassDeclaration::mangle() -{ - Dsymbol *parentsave = parent; - - //printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars()); - - /* These are reserved to the compiler, so keep simple - * names for them. - */ - if (ident == Id::Exception) - { if (parent->ident == Id::object) - parent = NULL; - } - else if (ident == Id::TypeInfo || -// ident == Id::Exception || - ident == Id::TypeInfo_Struct || - ident == Id::TypeInfo_Class || - ident == Id::TypeInfo_Typedef || - ident == Id::TypeInfo_Tuple || - this == object || - this == classinfo || - this == Module::moduleinfo || - memcmp(ident->toChars(), "TypeInfo_", 9) == 0 - ) - parent = NULL; - - char *id = Dsymbol::mangle(); - parent = parentsave; - return id; -} - - -char *TemplateInstance::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("TemplateInstance::mangle() %s", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (!tempdecl) - error("is not defined"); - else if (tempdecl->parent) - { - char *p = tempdecl->parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); - return id; -} - - -char *TemplateMixin::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("TemplateMixin::mangle() %s", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (parent) - { - char *p = parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("TemplateMixin::mangle() %s = %s\n", toChars(), id); - return id; -} - -char *Dsymbol::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("Dsymbol::mangle() '%s'", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (parent) - { - char *p = parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); - return id; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> + +#include "root.h" + +#include "init.h" +#include "declaration.h" +#include "aggregate.h" +#include "mtype.h" +#include "attrib.h" +#include "template.h" +#include "id.h" +#include "module.h" + +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +char *cpp_mangle(Dsymbol *s); +#endif + +char *mangle(Declaration *sthis) +{ + OutBuffer buf; + char *id; + Dsymbol *s; + + //printf("::mangle(%s)\n", sthis->toChars()); + s = sthis; + do + { + //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); + if (s->ident) + { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (s != sthis && fd) + { + id = mangle(fd); + buf.prependstring(id); + goto L1; + } + else + { + id = s->ident->toChars(); + int len = strlen(id); + char tmp[sizeof(len) * 3 + 1]; + buf.prependstring(id); + sprintf(tmp, "%d", len); + buf.prependstring(tmp); + } + } + else + buf.prependstring("0"); + s = s->parent; + } while (s); + +// buf.prependstring("_D"); +L1: + //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); + //printf("sthis->type = %s\n", sthis->type->toChars()); + FuncDeclaration *fd = sthis->isFuncDeclaration(); + if (fd && (fd->needThis() || fd->isNested())) + buf.writeByte(Type::needThisPrefix()); + if (sthis->type->deco) + buf.writestring(sthis->type->deco); + else + { +#ifdef DEBUG + if (!fd->inferRetType) + printf("%s\n", fd->toChars()); +#endif + assert(fd && fd->inferRetType); + } + + id = buf.toChars(); + buf.data = NULL; + return id; +} + +char *Declaration::mangle() +#if __DMC__ + __out(result) + { + int len = strlen(result); + + assert(len > 0); + //printf("mangle: '%s' => '%s'\n", toChars(), result); + for (int i = 0; i < len; i++) + { + assert(result[i] == '_' || + result[i] == '@' || + isalnum(result[i]) || result[i] & 0x80); + } + } + __body +#endif + { + //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent->toChars() : "null", linkage); + if (!parent || parent->isModule()) // if at global scope + { + // If it's not a D declaration, no mangling + switch (linkage) + { + case LINKd: + break; + + // LDC + case LINKintrinsic: + + case LINKc: + case LINKwindows: + case LINKpascal: + return ident->toChars(); + + case LINKcpp: +#if DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS) + return cpp_mangle(this); +#else + // Windows C++ mangling is done by C++ back end + return ident->toChars(); +#endif + + case LINKdefault: + error("forward declaration"); + return ident->toChars(); + + default: + fprintf(stdmsg, "'%s', linkage = %d\n", toChars(), linkage); + assert(0); + } + } + char *p = ::mangle(this); + OutBuffer buf; + buf.writestring("_D"); + buf.writestring(p); + p = buf.toChars(); + buf.data = NULL; + //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent->toChars() : "null", linkage, p); + return p; + } + +char *FuncDeclaration::mangle() +#if __DMC__ + __out(result) + { + assert(strlen(result) > 0); + } + __body +#endif + { + if (isMain()) + return (char *)"_Dmain"; + + if (isWinMain() || isDllMain()) + return ident->toChars(); + + assert(this); + return Declaration::mangle(); + } + +char *StructDeclaration::mangle() +{ + //printf("StructDeclaration::mangle() '%s'\n", toChars()); + return Dsymbol::mangle(); +} + + +char *TypedefDeclaration::mangle() +{ + //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); + return Dsymbol::mangle(); +} + + +char *ClassDeclaration::mangle() +{ + Dsymbol *parentsave = parent; + + //printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars()); + + /* These are reserved to the compiler, so keep simple + * names for them. + */ + if (ident == Id::Exception) + { if (parent->ident == Id::object) + parent = NULL; + } + else if (ident == Id::TypeInfo || +// ident == Id::Exception || + ident == Id::TypeInfo_Struct || + ident == Id::TypeInfo_Class || + ident == Id::TypeInfo_Typedef || + ident == Id::TypeInfo_Tuple || + this == object || + this == classinfo || + this == Module::moduleinfo || + memcmp(ident->toChars(), "TypeInfo_", 9) == 0 + ) + parent = NULL; + + char *id = Dsymbol::mangle(); + parent = parentsave; + return id; +} + + +char *TemplateInstance::mangle() +{ + OutBuffer buf; + char *id; + +#if 0 + printf("TemplateInstance::mangle() %s", toChars()); + if (parent) + printf(" parent = %s %s", parent->kind(), parent->toChars()); + printf("\n"); +#endif + id = ident ? ident->toChars() : toChars(); + if (!tempdecl) + error("is not defined"); + else if (tempdecl->parent) + { + char *p = tempdecl->parent->mangle(); + if (p[0] == '_' && p[1] == 'D') + p += 2; + buf.writestring(p); + } + buf.printf("%zu%s", strlen(id), id); + id = buf.toChars(); + buf.data = NULL; + //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); + return id; +} + + +char *TemplateMixin::mangle() +{ + OutBuffer buf; + char *id; + +#if 0 + printf("TemplateMixin::mangle() %s", toChars()); + if (parent) + printf(" parent = %s %s", parent->kind(), parent->toChars()); + printf("\n"); +#endif + id = ident ? ident->toChars() : toChars(); + if (parent) + { + char *p = parent->mangle(); + if (p[0] == '_' && p[1] == 'D') + p += 2; + buf.writestring(p); + } + buf.printf("%zu%s", strlen(id), id); + id = buf.toChars(); + buf.data = NULL; + //printf("TemplateMixin::mangle() %s = %s\n", toChars(), id); + return id; +} + +char *Dsymbol::mangle() +{ + OutBuffer buf; + char *id; + +#if 0 + printf("Dsymbol::mangle() '%s'", toChars()); + if (parent) + printf(" parent = %s %s", parent->kind(), parent->toChars()); + printf("\n"); +#endif + id = ident ? ident->toChars() : toChars(); + if (parent) + { + char *p = parent->mangle(); + if (p[0] == '_' && p[1] == 'D') + p += 2; + buf.writestring(p); + } + buf.printf("%zu%s", strlen(id), id); + id = buf.toChars(); + buf.data = NULL; + //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); + return id; +} + +
--- a/dmd/mars.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/mars.c Fri Nov 06 23:58:01 2009 +0100 @@ -32,6 +32,7 @@ #include "cond.h" #include "expression.h" #include "lexer.h" +#include "json.h" #include "gen/revisions.h" @@ -44,6 +45,7 @@ hdr_ext = "di"; doc_ext = "html"; ddoc_ext = "ddoc"; + json_ext = "json"; // LDC ll_ext = "ll"; @@ -56,7 +58,7 @@ copyright = "Copyright (c) 1999-2009 by Digital Mars and Tomas Lindquist Olsen"; written = "written by Walter Bright and Tomas Lindquist Olsen"; - version = "v1.045"; + version = "v1.051"; ldc_version = LDC_REV; llvm_version = LLVM_REV_STR; global.structalign = 8; @@ -90,6 +92,11 @@ this->filename = mod ? mod->srcfile->toChars() : NULL; } +bool Loc::equals(const Loc& loc) +{ + return linnum == loc.linnum && FileName::equals(filename, loc.filename); +} + /************************************** * Print error message and exit. */ @@ -180,25 +187,20 @@ void getenv_setargv(const char *envvar, int *pargc, char** *pargv) { - char *env; char *p; - Array *argv; - int argc; - int wildcard; // do wildcard expansion int instring; int slash; char c; - int j; - env = getenv(envvar); + char *env = getenv(envvar); if (!env) return; env = mem.strdup(env); // create our own writable copy - argc = *pargc; - argv = new Array(); + int argc = *pargc; + Array *argv = new Array(); argv->setDim(argc); int argc_left = 0; @@ -220,10 +222,10 @@ argv->push((char*)""); argc++; - j = 1; // leave argv[0] alone + int j = 1; // leave argv[0] alone while (1) { - wildcard = 1; + int wildcard = 1; // do wildcard expansion switch (*env) { case ' ':
--- a/dmd/mars.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/mars.h Fri Nov 06 23:58:01 2009 +0100 @@ -48,6 +48,7 @@ TARGET_OSX Covers 32 and 64 bit Mac OSX TARGET_FREEBSD Covers 32 and 64 bit FreeBSD TARGET_SOLARIS Covers 32 and 64 bit Solaris + TARGET_NET Covers .Net It is expected that the compiler for each platform will be able to generate 32 and 64 bit code from the same compiler binary. @@ -161,6 +162,7 @@ bool optimize; // run optimizer char optimizeLevel; // optimization level #endif + char vtls; // identify thread local variables ARCH cpu; // target CPU OS os; // target OS bool is64bit; // generate 64 bit code @@ -193,6 +195,9 @@ char *hdrdir; // write 'header' file to docdir directory char *hdrname; // write 'header' file to docname + char doXGeneration; // write JSON file + char *xfilename; // write JSON file to xfilename + unsigned debuglevel; // debug level Array *debugids; // debug identifiers @@ -204,11 +209,9 @@ Array *defaultlibnames; // default libraries for non-debug builds Array *debuglibnames; // default libraries for debug builds - const char *xmlname; // filename for XML output - - OutBuffer *moduleDeps; // buffer and filename for emitting module deps - char *moduleDepsFile; - + char *moduleDepsFile; // filename for deps output + OutBuffer *moduleDeps; // contents to be written to deps file + // Hidden debug switches bool debuga; bool debugb; @@ -260,6 +263,7 @@ const char *doc_ext; // for Ddoc generated files const char *ddoc_ext; // for Ddoc macro include files const char *hdr_ext; // for D 'header' import files + const char *json_ext; // for JSON files const char *copyright; const char *written; Array *path; // Array of char*'s which form the import lookup path @@ -344,7 +348,7 @@ //typedef unsigned Loc; // file location struct Loc { - char *filename; + const char *filename; unsigned linnum; Loc() @@ -362,6 +366,7 @@ Loc(Module *mod, unsigned linnum); char *toChars() const; + bool equals(const Loc& loc); }; #ifndef GCC_SAFE_DMD @@ -426,7 +431,7 @@ #if IN_GCC || IN_LLVM #define stdmsg stderr #else -#define stdmsg stdout +#define stdmsg stderr #endif #endif /* DMD_MARS_H */
--- a/dmd/module.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/module.c Fri Nov 06 23:58:01 2009 +0100 @@ -95,7 +95,7 @@ searchCacheSymbol = NULL; searchCacheFlags = 0; semanticstarted = 0; - semanticdone = 0; + semanticRun = 0; decldefs = NULL; vmoduleinfo = NULL; #if IN_DMD @@ -123,6 +123,7 @@ macrotable = NULL; escapetable = NULL; + safe = FALSE; #if IN_DMD doppelganger = 0; cov = NULL; @@ -661,9 +662,65 @@ } } -void Module::semantic(Scope* unused_sc) -{ int i; +void Module::importAll(Scope *prevsc) +{ + //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); + + if (scope) + return; // already done + + /* Note that modules get their own scope, from scratch. + * This is so regardless of where in the syntax a module + * gets imported, it is unaffected by context. + * Ignore prevsc. + */ + Scope *sc = Scope::createGlobal(this); // create root scope + + // 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) + { + Import *im = new Import(0, NULL, Id::object, NULL, 0); + members->shift(im); + } + } + if (!symtab) + { + // Add all symbols into module's symbol table + symtab = new DsymbolTable(); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->addMember(NULL, sc->scopesym, 1); + } + } + // anything else should be run after addMember, so version/debug symbols are defined + + /* Set scope for the symbols so that if we forward reference + * a symbol, it can possibly be resolved on the spot. + * If this works out well, it can be extended to all modules + * 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]; + s->setScope(sc); + } + + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->importAll(sc); + } + + sc = sc->pop(); + sc->pop(); // 2 pops because Scope::createGlobal() created 2 +} + +void Module::semantic(Scope *unused_sc) +{ if (semanticstarted) return; @@ -673,10 +730,15 @@ // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. - Scope *sc = Scope::createGlobal(this); // create root scope + Scope *sc = scope; // see if already got one from importAll() + if (!sc) + { printf("test2\n"); + Scope::createGlobal(this); // create root scope + } //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage); +#if 0 // Add import of "object" if this module isn't "object" if (ident != Id::object) { @@ -686,26 +748,36 @@ // Add all symbols into module's symbol table symtab = new DsymbolTable(); - for (i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)members->data[i]; + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; s->addMember(NULL, sc->scopesym, 1); } + /* Set scope for the symbols so that if we forward reference + * a symbol, it can possibly be resolved on the spot. + * 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++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + s->setScope(sc); + } +#endif + // Pass 1 semantic routines: do public side of the definition - for (i = 0; i < members->dim; i++) - { Dsymbol *s; + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; - s = (Dsymbol *)members->data[i]; //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); s->semantic(sc); runDeferredSemantic(); } - sc = sc->pop(); - sc->pop(); - semanticdone = semanticstarted; + if (!scope) + { sc = sc->pop(); + sc->pop(); // 2 pops because Scope::createGlobal() created 2 + } + semanticRun = semanticstarted; //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); } @@ -744,7 +816,7 @@ sc = sc->pop(); sc->pop(); - semanticdone = semanticstarted; + semanticRun = semanticstarted; //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); } @@ -774,12 +846,11 @@ sc = sc->pop(); sc->pop(); - semanticdone = semanticstarted; + semanticRun = semanticstarted; } void Module::inlineScan() -{ int i; - +{ if (semanticstarted >= 4) return; assert(semanticstarted == 3); @@ -790,16 +861,14 @@ // gets imported, it is unaffected by context. //printf("Module = %p\n", sc.scopesym); - for (i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)members->data[i]; + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; //if (global.params.verbose) //printf("inline scan symbol %s\n", s->toChars()); s->inlineScan(); } - semanticdone = semanticstarted; + semanticRun = semanticstarted; } /**************************************************** @@ -844,6 +913,7 @@ { /* Since modules can be circularly referenced, * need to stop infinite recursive searches. + * This is done with the cache. */ //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch); @@ -851,7 +921,10 @@ if (insearch) s = NULL; else if (searchCacheIdent == ident && searchCacheFlags == flags) + { s = searchCacheSymbol; + //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", toChars(), ident->toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol->toChars() : "null"); + } else { insearch = 1; @@ -865,6 +938,13 @@ return s; } +Dsymbol *Module::symtabInsert(Dsymbol *s) +{ + searchCacheIdent = 0; // symbol is inserted, so invalidate cache + return Package::symtabInsert(s); +} + + /******************************************* * Can't run semantic on s now, try again later. */ @@ -1059,11 +1139,14 @@ else { assert(p->isPackage()); +#if TARGET_NET //dot net needs modules and packages with same name +#else if (p->isModule()) { p->error("module and package have the same name"); fatal(); break; } +#endif } parent = p; dst = ((Package *)p)->symtab;
--- a/dmd/module.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/module.h Fri Nov 06 23:58:01 2009 +0100 @@ -94,7 +94,7 @@ int searchCacheFlags; // cached flags int semanticstarted; // has semantic() been started? - int semanticdone; // has semantic() been done? + int semanticRun; // has semantic() been done? int root; // != 0 if this is a 'root' module, // i.e. a module that will be taken all the // way to an object file @@ -119,8 +119,10 @@ Macro *macrotable; // document comment macros struct Escape *escapetable; // document comment escapes - int doDocComment; // enable generating doc comments for this module - int doHdrGen; // enable generating header file for this module + int doDocComment; // enable generating doc comments for this module + int doHdrGen; // enable generating header file for this module + + bool safe; // TRUE if module is marked as 'safe' Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen); ~Module(); @@ -128,6 +130,7 @@ static Module *load(Loc loc, Array *packages, Identifier *ident); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJsonBuffer(OutBuffer *buf); const char *kind(); void read(Loc loc); // read file #if IN_GCC @@ -135,6 +138,7 @@ #else 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 @@ -146,6 +150,7 @@ void gendocfile(); int needModuleInfo(); Dsymbol *search(Loc loc, Identifier *ident, int flags); + Dsymbol *symtabInsert(Dsymbol *s); void deleteObjFile(); void addDeferredSemantic(Dsymbol *s); void runDeferredSemantic(); @@ -198,6 +203,7 @@ { Identifier *id; Array *packages; // array of Identifier's representing packages + bool safe; ModuleDeclaration(Array *packages, Identifier *id);
--- a/dmd/mtype.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/mtype.c Fri Nov 06 23:58:01 2009 +0100 @@ -1514,16 +1514,8 @@ if (ty == Tvoid || to->ty == Tvoid) return MATCHnomatch; - if (1 || global.params.Dversion == 1) - { - if (to->ty == Tbool) - return MATCHnomatch; - } - else - { - if (ty == Tbool || to->ty == Tbool) - return MATCHnomatch; - } + if (to->ty == Tbool) + return MATCHnomatch; if (!to->isTypeBasic()) return MATCHnomatch; @@ -1534,6 +1526,7 @@ if (tob->flags & (TFLAGSimaginary | TFLAGScomplex)) return MATCHnomatch; +#if DMDV2 // If converting to integral if (0 && global.params.Dversion > 1 && tob->flags & TFLAGSintegral) { d_uns64 sz = size(0); @@ -1547,6 +1540,7 @@ /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned) return MATCHnomatch;*/ } +#endif } else if (flags & TFLAGSfloating) { @@ -2347,6 +2341,7 @@ case Tfunction: case Tvoid: case Tnone: + case Ttuple: error(loc, "can't have associative array key of %s", key->toChars()); break; } @@ -2557,6 +2552,9 @@ Type *TypePointer::semantic(Loc loc, Scope *sc) { + if (deco) + return this; + //printf("TypePointer::semantic()\n"); Type *n = next->semantic(loc, sc); switch (n->toBasetype()->ty) @@ -2792,6 +2790,9 @@ Type *t1n = t1->next; Type *t2n = t2->next; + if (!t1n || !t2n) // happens with return type inference + goto Lnotcovariant; + if (t1n->equals(t2n)) goto Lcovariant; if (t1n->ty != Tclass || t2n->ty != Tclass) @@ -2936,10 +2937,10 @@ switch (linkage) { case LINKd: p = NULL; break; - case LINKc: p = "C "; break; - case LINKwindows: p = "Windows "; break; - case LINKpascal: p = "Pascal "; break; - case LINKcpp: p = "C++ "; break; + case LINKc: p = " C"; break; + case LINKwindows: p = " Windows"; break; + case LINKpascal: p = " Pascal"; break; + case LINKcpp: p = " C++"; break; // LDC case LINKintrinsic: p = "Intrinsic"; break; @@ -2978,36 +2979,39 @@ } tf->linkage = sc->linkage; - if (!tf->next) + if (tf->next) { - assert(global.errors); - tf->next = tvoid; - } - tf->next = tf->next->semantic(loc,sc); - if (tf->next->toBasetype()->ty == Tsarray) - { error(loc, "functions cannot return static array %s", tf->next->toChars()); - tf->next = Type::terror; - } - if (tf->next->toBasetype()->ty == Tfunction) - { error(loc, "functions cannot return a function"); - tf->next = Type::terror; - } - if (tf->next->toBasetype()->ty == Ttuple) - { error(loc, "functions cannot return a tuple"); - tf->next = Type::terror; - } - if (tf->next->isscope() && !(sc->flags & SCOPEctor)) - error(loc, "functions cannot return scope %s", tf->next->toChars()); + tf->next = tf->next->semantic(loc,sc); + if (tf->next->toBasetype()->ty == Tsarray) + { error(loc, "functions cannot return static array %s", tf->next->toChars()); + tf->next = Type::terror; + } + if (tf->next->toBasetype()->ty == Tfunction) + { error(loc, "functions cannot return a function"); + tf->next = Type::terror; + } + if (tf->next->toBasetype()->ty == Ttuple) + { error(loc, "functions cannot return a tuple"); + tf->next = Type::terror; + } + if (tf->next->isscope() && !(sc->flags & SCOPEctor)) + error(loc, "functions cannot return scope %s", tf->next->toChars()); + } if (tf->parameters) - { size_t dim = Argument::dim(tf->parameters); - + { + /* Create a scope for evaluating the default arguments for the parameters + */ + Scope *argsc = sc->push(); + argsc->stc = 0; // don't inherit storage class + argsc->protection = PROTpublic; + + size_t dim = Argument::dim(tf->parameters); for (size_t i = 0; i < dim; i++) { Argument *arg = Argument::getNth(tf->parameters, i); - Type *t; tf->inuse++; - arg->type = arg->type->semantic(loc,sc); + arg->type = arg->type->semantic(loc, argsc); if (tf->inuse == 1) tf->inuse--; // each function needs its own copy of a tuple arg, since @@ -3019,7 +3023,7 @@ if (tf->inuse == 1) tf->inuse--; } - t = arg->type->toBasetype(); + Type *t = arg->type->toBasetype(); if (arg->storageClass & (STCout | STCref | STClazy)) { @@ -3031,9 +3035,9 @@ if (arg->defaultArg) { - arg->defaultArg = arg->defaultArg->semantic(sc); - arg->defaultArg = resolveProperties(sc, arg->defaultArg); - arg->defaultArg = arg->defaultArg->implicitCastTo(sc, arg->type); + arg->defaultArg = arg->defaultArg->semantic(argsc); + arg->defaultArg = resolveProperties(argsc, arg->defaultArg); + arg->defaultArg = arg->defaultArg->implicitCastTo(argsc, arg->type); } /* If arg turns out to be a tuple, the number of parameters may @@ -3044,8 +3048,10 @@ i--; } } - } - tf->deco = tf->merge()->deco; + argsc->pop(); + } + if (tf->next) + tf->deco = tf->merge()->deco; if (tf->inuse) { error(loc, "recursive type"); @@ -3419,6 +3425,19 @@ goto Lerror; goto L3; } + else if (v && id == Id::stringof) + { + e = new DsymbolExp(loc, s); + do + { + id = (Identifier *)idents.data[i]; + e = new DotIdExp(loc, e, id); + } while (++i < idents.dim); + e = e->semantic(sc); + *pe = e; + return; + } + t = s->getType(); if (!t && s->isDeclaration()) t = s->isDeclaration()->type; @@ -3515,23 +3534,33 @@ { if (t->reliesOnTident()) { - Scope *scx; - - for (scx = sc; 1; scx = scx->enclosing) + if (s->scope) + t = t->semantic(loc, s->scope); + else { - if (!scx) - { error(loc, "forward reference to '%s'", t->toChars()); - return; + /* Attempt to find correct scope in which to evaluate t. + * Not sure if this is right or not, or if we should just + * give forward reference error if s->scope is not set. + */ + for (Scope *scx = sc; 1; scx = scx->enclosing) + { + if (!scx) + { error(loc, "forward reference to '%s'", t->toChars()); + return; + } + if (scx->scopesym == scopesym) + { + t = t->semantic(loc, scx); + break; + } } - if (scx->scopesym == scopesym) - break; } - t = t->semantic(loc, scx); - //((TypeIdentifier *)t)->resolve(loc, scx, pe, &t, ps); } } if (t->ty == Ttuple) *pt = t; + else if (t->ty == Ttypeof) + *pt = t->semantic(loc, sc); else *pt = t->merge(); } @@ -3762,7 +3791,8 @@ if (!t) { #ifdef DEBUG - printf("2: "); + if (s) printf("s = %s\n", s->kind()); + printf("2: e:%p s:%p ", e, s); #endif error(loc, "%s is used as a type", toChars()); t = tvoid; @@ -3839,6 +3869,11 @@ toCBuffer2Helper(buf, hgs); } +void TypeTypeof::toDecoBuffer(OutBuffer *buf, bool mangle) +{ + assert(0); +} + Type *TypeTypeof::semantic(Loc loc, Scope *sc) { Expression *e; Type *t; @@ -3970,7 +4005,7 @@ Type *TypeEnum::semantic(Loc loc, Scope *sc) { - sym->semantic(sc); + //sym->semantic(sc); return merge(); } @@ -4562,7 +4597,7 @@ TemplateInstance *ti = s->isTemplateInstance(); if (ti) - { if (!ti->semanticdone) + { if (!ti->semanticRun) ti->semantic(sc); s = ti->inst->toAlias(); if (!s->isTemplateInstance()) @@ -4695,7 +4730,7 @@ char *TypeClass::toChars() { - return sym->toPrettyChars(); + return (char *)sym->toPrettyChars(); } Type *TypeClass::syntaxCopy() @@ -4706,8 +4741,8 @@ Type *TypeClass::semantic(Loc loc, Scope *sc) { //printf("TypeClass::semantic(%s)\n", sym->toChars()); - if (sym->scope) - sym->semantic(sym->scope); + if (deco) + return this; return merge(); } @@ -4975,7 +5010,7 @@ TemplateInstance *ti = s->isTemplateInstance(); if (ti) - { if (!ti->semanticdone) + { if (!ti->semanticRun) ti->semantic(sc); s = ti->inst->toAlias(); if (!s->isTemplateInstance()) @@ -4994,9 +5029,16 @@ if (e->op == TOKtype) { - VarExp *ve; - - if (d->needThis() && (hasThis(sc) || !d->isFuncDeclaration())) + /* It's: + * Class.d + */ + if (d->isTupleDeclaration()) + { + e = new TupleExp(e->loc, d->isTupleDeclaration()); + e = e->semantic(sc); + return e; + } + else if (d->needThis() && (hasThis(sc) || !(sc->intypeof || d->isFuncDeclaration()))) { if (sc->func) { @@ -5025,15 +5067,11 @@ e = de->semantic(sc); return e; } - else if (d->isTupleDeclaration()) + else { - e = new TupleExp(e->loc, d->isTupleDeclaration()); - e = e->semantic(sc); - return e; + VarExp *ve = new VarExp(e->loc, d); + return ve; } - else - ve = new VarExp(e->loc, d); - return ve; } if (d->isDataseg())
--- a/dmd/mtype.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/mtype.h Fri Nov 06 23:58:01 2009 +0100 @@ -561,6 +561,7 @@ Type *syntaxCopy(); Dsymbol *toDsymbol(Scope *sc); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toDecoBuffer(OutBuffer *buf, bool mangle); Type *semantic(Loc loc, Scope *sc); d_uns64 size(Loc loc); };
--- a/dmd/opover.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/opover.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -33,7 +33,7 @@ static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id); static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Arguments *arguments); static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments); -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments); +static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments); /******************************** Expression **************************/ @@ -158,6 +158,7 @@ Expression *UnaExp::op_overload(Scope *sc) { + //printf("UnaExp::op_overload() (%s)\n", toChars()); AggregateDeclaration *ad; Dsymbol *fd; Type *t1 = e1->type->toBasetype(); @@ -177,10 +178,11 @@ { if (op == TOKarray) { - Expression *e; + /* Rewrite op e1[arguments] as: + * e1.fd(arguments) + */ + Expression *e = new DotIdExp(loc, e1, fd->ident); ArrayExp *ae = (ArrayExp *)this; - - e = new DotIdExp(loc, e1, fd->ident); e = new CallExp(loc, e, ae->arguments); e = e->semantic(sc); return e; @@ -191,6 +193,21 @@ return build_overload(loc, sc, e1, NULL, fd->ident); } } + +#if DMDV2 + // Didn't find it. Forward to aliasthis + if (ad->aliasthis) + { + /* Rewrite op(e1) as: + * op(e1.aliasthis) + */ + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } +#endif } return NULL; } @@ -264,11 +281,11 @@ fd = s->isFuncDeclaration(); if (fd) { - overloadResolveX(&m, fd, &args2, sc->module); + overloadResolveX(&m, fd, NULL, &args2, sc->module); } else { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, &args2); + templateResolve(&m, td, sc, loc, NULL, NULL, &args2); } } @@ -279,11 +296,11 @@ fd = s_r->isFuncDeclaration(); if (fd) { - overloadResolveX(&m, fd, &args1, sc->module); + overloadResolveX(&m, fd, NULL, &args1, sc->module); } else { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, &args1); + templateResolve(&m, td, sc, loc, NULL, NULL, &args1); } } @@ -335,7 +352,6 @@ * b.opfunc(a) * and see which is better. */ - Expression *e; FuncDeclaration *lastf; if (!argsset) @@ -353,11 +369,11 @@ fd = s_r->isFuncDeclaration(); if (fd) { - overloadResolveX(&m, fd, &args2, sc->module); + overloadResolveX(&m, fd, NULL, &args2, sc->module); } else { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, &args2); + templateResolve(&m, td, sc, loc, NULL, NULL, &args2); } } lastf = m.lastf; @@ -367,11 +383,11 @@ fd = s->isFuncDeclaration(); if (fd) { - overloadResolveX(&m, fd, &args1, sc->module); + overloadResolveX(&m, fd, NULL, &args1, sc->module); } else { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, &args1); + templateResolve(&m, td, sc, loc, NULL, NULL, &args1); } } @@ -388,6 +404,7 @@ m.lastf = m.anyf; } + Expression *e; if (lastf && m.lastf == lastf || id_r && m.last == MATCHnomatch) // Rewrite (e1 op e2) as e1.opfunc_r(e2) @@ -423,6 +440,33 @@ } } +#if DMDV2 + // Try alias this on first operand + if (ad1 && ad1->aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1.aliasthis op e2) + */ + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + + // Try alias this on second operand + if (ad2 && ad2->aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1 op e2.aliasthis) + */ + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->semantic(sc); + return e; + } +#endif return NULL; } @@ -430,7 +474,7 @@ * Utility to build a function call out of this reference and argument. */ -static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id) +Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id) { Expression *e; @@ -499,7 +543,6 @@ } AggregateDeclaration *ad; - FuncDeclaration *fd; Argument *arg = (Argument *)arguments->data[0]; Type *taggr = aggr->type; @@ -570,7 +613,7 @@ : Id::apply); if (s) { - fd = s->isFuncDeclaration(); + FuncDeclaration *fd = s->isFuncDeclaration(); if (fd) inferApplyArgTypesX(from, fd, arguments); } @@ -582,7 +625,7 @@ if (0 && aggr->op == TOKdelegate) { DelegateExp *de = (DelegateExp *)aggr; - fd = de->func->isFuncDeclaration(); + FuncDeclaration *fd = de->func->isFuncDeclaration(); if (fd) inferApplyArgTypesX(from, fd, arguments); } @@ -719,7 +762,7 @@ /************************************** */ -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments) +static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments) { FuncDeclaration *fd;
--- a/dmd/optimize.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/optimize.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,793 +1,834 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <ctype.h> -#include <assert.h> -#include <math.h> - -#if __DMC__ -#include <complex.h> -#endif - -#include "lexer.h" -#include "mtype.h" -#include "expression.h" -#include "declaration.h" -#include "aggregate.h" -#include "init.h" - - -#ifdef IN_GCC -#include "d-gcc-real.h" - -/* %% fix? */ -extern "C" bool real_isnan (const real_t *); -#endif - -static real_t zero; // work around DMC bug for now - - -/************************************* - * If expression is a variable with a const initializer, - * return that initializer. - */ - -Expression *fromConstInitializer(Expression *e1) -{ - //printf("fromConstInitializer(%s)\n", e1->toChars()); - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && v->isConst() && v->init) - { Expression *ei = v->init->toExpression(); - if (ei && ei->type) - e1 = ei; - } - } - return e1; -} - - -Expression *Expression::optimize(int result) -{ - //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); - return this; -} - -Expression *VarExp::optimize(int result) -{ - if (result & WANTinterpret) - { - return fromConstInitializer(this); - } - return this; -} - -Expression *TupleExp::optimize(int result) -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - exps->data[i] = (void *)e; - } - return this; -} - -Expression *ArrayLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - elements->data[i] = (void *)e; - } - } - return this; -} - -Expression *AssocArrayLiteralExp::optimize(int result) -{ - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = (Expression *)keys->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - keys->data[i] = (void *)e; - - e = (Expression *)values->data[i]; - e = e->optimize(WANTvalue | (result & WANTinterpret)); - values->data[i] = (void *)e; - } - return this; -} - -Expression *StructLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (!e) - continue; - e = e->optimize(WANTvalue | (result & WANTinterpret)); - elements->data[i] = (void *)e; - } - } - return this; -} - -Expression *TypeExp::optimize(int result) -{ - return this; -} - -Expression *UnaExp::optimize(int result) -{ - e1 = e1->optimize(result); - return this; -} - -Expression *NegExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Neg(type, e1); - } - else - e = this; - return e; -} - -Expression *ComExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Com(type, e1); - } - else - e = this; - return e; -} - -Expression *NotExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Not(type, e1); - } - else - e = this; - return e; -} - -Expression *BoolExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Bool(type, e1); - } - else - e = this; - return e; -} - -Expression *AddrExp::optimize(int result) -{ Expression *e; - - //printf("AddrExp::optimize(result = %d) %s\n", result, toChars()); - // never try to interpret: it could change the semantics by turning - // const p = &s; into an something like const p = &(Struct()); - e1 = e1->optimize(result & ~WANTinterpret); - // Convert &*ex to ex - if (e1->op == TOKstar) - { Expression *ex; - - ex = ((PtrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } -#if !IN_LLVM - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - if (!ve->var->isOut() && !ve->var->isRef() && - !ve->var->isImportedSymbol()) - { - e = new SymOffExp(loc, ve->var, 0); - e->type = type; - return e; - } - } - if (e1->op == TOKindex) - { // Convert &array[n] to &array+n - IndexExp *ae = (IndexExp *)e1; - - if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) - { - dinteger_t index = ae->e2->toInteger(); - VarExp *ve = (VarExp *)ae->e1; - if (ve->type->ty == Tsarray && ve->type->next->ty != Tbit - && !ve->var->isImportedSymbol()) - { - TypeSArray *ts = (TypeSArray *)ve->type; - dinteger_t dim = ts->dim->toInteger(); - if (index < 0 || index >= dim) - error("array index %jd is out of bounds [0..%jd]", index, dim); - e = new SymOffExp(loc, ve->var, index * ts->next->size()); - e->type = type; - return e; - } - } - } -#endif - return this; -} - -Expression *PtrExp::optimize(int result) -{ - //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - // Convert *&ex to ex - if (e1->op == TOKaddress) - { Expression *e; - Expression *ex; - - ex = ((AddrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { - Expression *e; - e = Ptr(type, e1); - if (e != EXP_CANT_INTERPRET) - return e; - } - - return this; -} - -Expression *DotVarExp::optimize(int result) -{ - //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - -#if DMDV2 - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - Expression *e = expandVar(result, v); - if (e && e->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e; - VarDeclaration *vf = var->isVarDeclaration(); - if (vf) - { - e = sle->getField(type, vf->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - } - else -#endif - if (e1->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e1; - VarDeclaration *vf = var->isVarDeclaration(); - if (vf) - { - Expression *e = sle->getField(type, vf->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - - return this; -} - -Expression *CallExp::optimize(int result) -{ Expression *e = this; - - e1 = e1->optimize(result); - if (e1->op == TOKvar && result & WANTinterpret) - { - FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); - if (fd) - { - Expression *eresult = fd->interpret(NULL, arguments); - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else if (result & WANTinterpret) - error("cannot evaluate %s at compile time", toChars()); - } - } - return e; -} - - -Expression *CastExp::optimize(int result) -{ - //printf("CastExp::optimize(result = %d) %s\n", result, toChars()); - //printf("from %s to %s\n", type->toChars(), to->toChars()); - //printf("from %s\n", type->toChars()); - //printf("e1->type %s\n", e1->type->toChars()); - //printf("type = %p\n", type); - assert(type); - enum TOK op1 = e1->op; - - e1 = e1->optimize(result); - if (result & WANTinterpret) - e1 = fromConstInitializer(e1); - - if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && - (type->ty == Tpointer || type->ty == Tarray) && - type->next->equals(e1->type->next) - ) - { - // make a copy before adjusting type to avoid - // messing up the type of an existing initializer - e1 = e1->syntaxCopy(); - e1->type = type; - return e1; - } - /* The first test here is to prevent infinite loops - */ - if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral) - return e1->castTo(NULL, to); - if (e1->op == TOKnull && - (type->ty == Tpointer || type->ty == Tclass)) - { - e1->type = type; - return e1; - } - - if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass) - { - // See if we can remove an unnecessary cast - ClassDeclaration *cdfrom; - ClassDeclaration *cdto; - int offset; - - cdfrom = e1->type->isClassHandle(); - cdto = type->isClassHandle(); - if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) - { - e1->type = type; - return e1; - } - } - - Expression *e; - - if (e1->isConst()) - { - if (e1->op == TOKsymoff) - { - if (type->size() == e1->type->size() && - type->toBasetype()->ty != Tsarray) - { - e1->type = type; - return e1; - } - return this; - } - if (to->toBasetype()->ty == Tvoid) - e = this; - else - e = Cast(type, to, e1); - } - else - e = this; - return e; -} - -Expression *BinExp::optimize(int result) -{ - //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (op == TOKshlass || op == TOKshrass || op == TOKushrass) - { - if (e2->isConst() == 1) - { - dinteger_t i2 = e2->toInteger(); - d_uns64 sz = e1->type->size() * 8; - if (i2 < 0 || i2 > sz) - { error("shift assign by %jd is outside the range 0..%zu", i2, sz); - e2 = new IntegerExp(0); - } - } - } - return this; -} - -Expression *AddExp::optimize(int result) -{ Expression *e; - - //printf("AddExp::optimize(%s)\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() && e2->isConst()) - { - if (e1->op == TOKsymoff && e2->op == TOKsymoff) - return this; - e = Add(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *MinExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() && e2->isConst()) - { - if (e2->op == TOKsymoff) - return this; - e = Min(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *MulExp::optimize(int result) -{ Expression *e; - - //printf("MulExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Mul(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *DivExp::optimize(int result) -{ Expression *e; - - //printf("DivExp::optimize(%s)\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Div(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *ModExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Mod(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *)) -{ Expression *ex = e; - - e->e1 = e->e1->optimize(result); - e->e2 = e->e2->optimize(result); - if (e->e2->isConst() == 1) - { - dinteger_t i2 = e->e2->toInteger(); - d_uns64 sz = e->e1->type->size() * 8; - if (i2 < 0 || i2 > sz) - { e->error("shift by %jd is outside the range 0..%zu", i2, sz); - e->e2 = new IntegerExp(0); - } - if (e->e1->isConst() == 1) - ex = (*shift)(e->type, e->e1, e->e2); - } - return ex; -} - -Expression *ShlExp::optimize(int result) -{ - //printf("ShlExp::optimize(result = %d) %s\n", result, toChars()); - return shift_optimize(result, this, Shl); -} - -Expression *ShrExp::optimize(int result) -{ - //printf("ShrExp::optimize(result = %d) %s\n", result, toChars()); - return shift_optimize(result, this, Shr); -} - -Expression *UshrExp::optimize(int result) -{ - //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); - return shift_optimize(result, this, Ushr); -} - -Expression *AndExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - e = And(type, e1, e2); - else - e = this; - return e; -} - -Expression *OrExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - e = Or(type, e1, e2); - else - e = this; - return e; -} - -Expression *XorExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - e = Xor(type, e1, e2); - else - e = this; - return e; -} - -Expression *CommaExp::optimize(int result) -{ Expression *e; - - //printf("CommaExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result & WANTinterpret); - e2 = e2->optimize(result); - if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2)) - { - e = e2; - if (e) - e->type = type; - } - else - e = this; - //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars()); - return e; -} - -Expression *ArrayLengthExp::optimize(int result) -{ Expression *e; - - //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e = this; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) - { - e = ArrayLength(type, e1); - } - return e; -} - -Expression *EqualExp::optimize(int result) -{ Expression *e; - - //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - e = this; - - Expression *e1 = fromConstInitializer(this->e1); - Expression *e2 = fromConstInitializer(this->e2); - - e = Equal(op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - -Expression *IdentityExp::optimize(int result) -{ Expression *e; - - //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - e = this; - - if (this->e1->isConst() && this->e2->isConst()) - { - e = Identity(op, type, this->e1, this->e2); - } - return e; -} - -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); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - e = Index(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - -Expression *SliceExp::optimize(int result) -{ Expression *e; - - //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); - e = this; - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - if (!lwr) - { if (e1->op == TOKstring) - { // Convert slice of string literal into dynamic array - Type *t = e1->type->toBasetype(); - if (t->next) - e = e1->castTo(NULL, t->next->arrayOf()); - } - return e; - } - if (result & WANTinterpret) - e1 = fromConstInitializer(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; - return e; -} - -Expression *AndAndExp::optimize(int result) -{ Expression *e; - - //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(WANTflags | (result & WANTinterpret)); - e = this; - if (e1->isBool(FALSE)) - { - e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); - e->type = type; - e = e->optimize(result); - } - else - { - e2 = e2->optimize(WANTflags | (result & WANTinterpret)); - if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) - error("void has no value"); - if (e1->isConst()) - { - if (e2->isConst()) - { int n1 = e1->isBool(1); - int n2 = e2->isBool(1); - - e = new IntegerExp(loc, n1 && n2, type); - } - else if (e1->isBool(TRUE)) - e = new BoolExp(loc, e2, type); - } - } - return e; -} - -Expression *OrOrExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(WANTflags | (result & WANTinterpret)); - e = this; - if (e1->isBool(TRUE)) - { // Replace with (e1, 1) - e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type)); - e->type = type; - e = e->optimize(result); - } - else - { - e2 = e2->optimize(WANTflags | (result & WANTinterpret)); - if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) - error("void has no value"); - if (e1->isConst()) - { - if (e2->isConst()) - { int n1 = e1->isBool(1); - int n2 = e2->isBool(1); - - e = new IntegerExp(loc, n1 || n2, type); - } - else if (e1->isBool(FALSE)) - e = new BoolExp(loc, e2, type); - } - } - return e; -} - -Expression *CmpExp::optimize(int result) -{ Expression *e; - - //printf("CmpExp::optimize() %s\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Cmp(op, type, this->e1, this->e2); - } - else - e = this; - return e; -} - -Expression *CatExp::optimize(int result) -{ Expression *e; - - //printf("CatExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = Cat(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - - -Expression *CondExp::optimize(int result) -{ Expression *e; - - econd = econd->optimize(WANTflags | (result & WANTinterpret)); - if (econd->isBool(TRUE)) - e = e1->optimize(result); - else if (econd->isBool(FALSE)) - e = e2->optimize(result); - else - { e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = this; - } - return e; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <ctype.h> +#include <assert.h> +#include <math.h> + +#if __DMC__ +#include <complex.h> +#endif + +#include "lexer.h" +#include "mtype.h" +#include "expression.h" +#include "declaration.h" +#include "aggregate.h" +#include "init.h" + + +#ifdef IN_GCC +#include "d-gcc-real.h" + +/* %% fix? */ +extern "C" bool real_isnan (const real_t *); +#endif + +static real_t zero; // work around DMC bug for now + + +/************************************* + * If expression is a variable with a const initializer, + * return that initializer. + */ + +Expression *fromConstInitializer(Expression *e1) +{ + //printf("fromConstInitializer(%s)\n", e1->toChars()); + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && v->isConst() && v->init) + { Expression *ei = v->init->toExpression(); + if (ei && ei->type) + e1 = ei; + } + } + return e1; +} + + +Expression *Expression::optimize(int result) +{ + //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); + return this; +} + +Expression *VarExp::optimize(int result) +{ + if (result & WANTinterpret) + { + return fromConstInitializer(this); + } + return this; +} + +Expression *TupleExp::optimize(int result) +{ + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->optimize(WANTvalue | (result & WANTinterpret)); + exps->data[i] = (void *)e; + } + return this; +} + +Expression *ArrayLiteralExp::optimize(int result) +{ + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + + e = e->optimize(WANTvalue | (result & WANTinterpret)); + elements->data[i] = (void *)e; + } + } + return this; +} + +Expression *AssocArrayLiteralExp::optimize(int result) +{ + assert(keys->dim == values->dim); + for (size_t i = 0; i < keys->dim; i++) + { Expression *e = (Expression *)keys->data[i]; + + e = e->optimize(WANTvalue | (result & WANTinterpret)); + keys->data[i] = (void *)e; + + e = (Expression *)values->data[i]; + e = e->optimize(WANTvalue | (result & WANTinterpret)); + values->data[i] = (void *)e; + } + return this; +} + +Expression *StructLiteralExp::optimize(int result) +{ + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + if (!e) + continue; + e = e->optimize(WANTvalue | (result & WANTinterpret)); + elements->data[i] = (void *)e; + } + } + return this; +} + +Expression *TypeExp::optimize(int result) +{ + return this; +} + +Expression *UnaExp::optimize(int result) +{ + e1 = e1->optimize(result); + return this; +} + +Expression *NegExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + if (e1->isConst() == 1) + { + e = Neg(type, e1); + } + else + e = this; + return e; +} + +Expression *ComExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + if (e1->isConst() == 1) + { + e = Com(type, e1); + } + else + e = this; + return e; +} + +Expression *NotExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + if (e1->isConst() == 1) + { + e = Not(type, e1); + } + else + e = this; + return e; +} + +Expression *BoolExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + if (e1->isConst() == 1) + { + e = Bool(type, e1); + } + else + e = this; + return e; +} + +Expression *AddrExp::optimize(int result) +{ Expression *e; + + //printf("AddrExp::optimize(result = %d) %s\n", result, toChars()); + // never try to interpret: it could change the semantics by turning + // const p = &s; into an something like const p = &(Struct()); + e1 = e1->optimize(result & ~WANTinterpret); + // Convert &*ex to ex + if (e1->op == TOKstar) + { Expression *ex; + + ex = ((PtrExp *)e1)->e1; + if (type->equals(ex->type)) + e = ex; + else + { + e = ex->copy(); + e->type = type; + } + return e; + } +#if !IN_LLVM + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + if (!ve->var->isOut() && !ve->var->isRef() && + !ve->var->isImportedSymbol()) + { + e = new SymOffExp(loc, ve->var, 0); + e->type = type; + return e; + } + } + if (e1->op == TOKindex) + { // Convert &array[n] to &array+n + IndexExp *ae = (IndexExp *)e1; + + if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) + { + dinteger_t index = ae->e2->toInteger(); + VarExp *ve = (VarExp *)ae->e1; + if (ve->type->ty == Tsarray && ve->type->next->ty != Tbit + && !ve->var->isImportedSymbol()) + { + TypeSArray *ts = (TypeSArray *)ve->type; + dinteger_t dim = ts->dim->toInteger(); + if (index < 0 || index >= dim) + error("array index %jd is out of bounds [0..%jd]", index, dim); + e = new SymOffExp(loc, ve->var, index * ts->next->size()); + e->type = type; + return e; + } + } + } +#endif + return this; +} + +Expression *PtrExp::optimize(int result) +{ + //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars()); + e1 = e1->optimize(result); + // Convert *&ex to ex + if (e1->op == TOKaddress) + { Expression *e; + Expression *ex; + + ex = ((AddrExp *)e1)->e1; + if (type->equals(ex->type)) + e = ex; + else + { + e = ex->copy(); + e->type = type; + } + return e; + } + // Constant fold *(&structliteral + offset) + if (e1->op == TOKadd) + { + Expression *e; + e = Ptr(type, e1); + if (e != EXP_CANT_INTERPRET) + return e; + } + + return this; +} + +Expression *DotVarExp::optimize(int result) +{ + //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars()); + e1 = e1->optimize(result); + +#if DMDV2 + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + Expression *e = expandVar(result, v); + if (e && e->op == TOKstructliteral) + { StructLiteralExp *sle = (StructLiteralExp *)e; + VarDeclaration *vf = var->isVarDeclaration(); + if (vf) + { + e = sle->getField(type, vf->offset); + if (e && e != EXP_CANT_INTERPRET) + return e; + } + } + } + else +#endif + if (e1->op == TOKstructliteral) + { StructLiteralExp *sle = (StructLiteralExp *)e1; + VarDeclaration *vf = var->isVarDeclaration(); + if (vf) + { + Expression *e = sle->getField(type, vf->offset); + if (e && e != EXP_CANT_INTERPRET) + return e; + } + } + + return this; +} + +Expression *NewExp::optimize(int result) +{ + if (thisexp) + thisexp = thisexp->optimize(WANTvalue); + + // Optimize parameters + if (newargs) + { + for (size_t i = 0; i < newargs->dim; i++) + { Expression *e = (Expression *)newargs->data[i]; + + e = e->optimize(WANTvalue); + newargs->data[i] = (void *)e; + } + } + + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + e = e->optimize(WANTvalue); + arguments->data[i] = (void *)e; + } + } + return this; +} + +Expression *CallExp::optimize(int result) +{ Expression *e = this; + + // Optimize parameters + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + e = e->optimize(WANTvalue); + arguments->data[i] = (void *)e; + } + } + + e1 = e1->optimize(result); + if (e1->op == TOKvar && result & WANTinterpret) + { + FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); + if (fd) + { + Expression *eresult = fd->interpret(NULL, arguments); + if (eresult && eresult != EXP_VOID_INTERPRET) + e = eresult; + else if (result & WANTinterpret) + error("cannot evaluate %s at compile time", toChars()); + } + } + return e; +} + + +Expression *CastExp::optimize(int result) +{ + //printf("CastExp::optimize(result = %d) %s\n", result, toChars()); + //printf("from %s to %s\n", type->toChars(), to->toChars()); + //printf("from %s\n", type->toChars()); + //printf("e1->type %s\n", e1->type->toChars()); + //printf("type = %p\n", type); + assert(type); + enum TOK op1 = e1->op; + + e1 = e1->optimize(result); + if (result & WANTinterpret) + e1 = fromConstInitializer(e1); + + if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && + (type->ty == Tpointer || type->ty == Tarray) && + type->next->equals(e1->type->next) + ) + { + // make a copy before adjusting type to avoid + // messing up the type of an existing initializer + e1 = e1->syntaxCopy(); + e1->type = type; + return e1; + } + /* The first test here is to prevent infinite loops + */ + if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral) + return e1->castTo(NULL, to); + if (e1->op == TOKnull && + (type->ty == Tpointer || type->ty == Tclass)) + { + e1->type = type; + return e1; + } + + if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass) + { + // See if we can remove an unnecessary cast + ClassDeclaration *cdfrom; + ClassDeclaration *cdto; + int offset; + + cdfrom = e1->type->isClassHandle(); + cdto = type->isClassHandle(); + if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) + { + e1->type = type; + return e1; + } + } + + Expression *e; + + if (e1->isConst()) + { + if (e1->op == TOKsymoff) + { + if (type->size() == e1->type->size() && + type->toBasetype()->ty != Tsarray) + { + e1->type = type; + return e1; + } + return this; + } + if (to->toBasetype()->ty == Tvoid) + e = this; + else + e = Cast(type, to, e1); + } + else + e = this; + return e; +} + +Expression *BinExp::optimize(int result) +{ + //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (op == TOKshlass || op == TOKshrass || op == TOKushrass) + { + if (e2->isConst() == 1) + { + dinteger_t i2 = e2->toInteger(); + d_uns64 sz = e1->type->size() * 8; + if (i2 < 0 || i2 > sz) + { error("shift assign by %jd is outside the range 0..%zu", i2, sz); + e2 = new IntegerExp(0); + } + } + } + return this; +} + +Expression *AddExp::optimize(int result) +{ Expression *e; + + //printf("AddExp::optimize(%s)\n", toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() && e2->isConst()) + { + if (e1->op == TOKsymoff && e2->op == TOKsymoff) + return this; + e = Add(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *MinExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() && e2->isConst()) + { + if (e2->op == TOKsymoff) + return this; + e = Min(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *MulExp::optimize(int result) +{ Expression *e; + + //printf("MulExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + { + e = Mul(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *DivExp::optimize(int result) +{ Expression *e; + + //printf("DivExp::optimize(%s)\n", toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + { + e = Div(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *ModExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + { + e = Mod(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *)) +{ Expression *ex = e; + + e->e1 = e->e1->optimize(result); + e->e2 = e->e2->optimize(result); + if (e->e2->isConst() == 1) + { + dinteger_t i2 = e->e2->toInteger(); + d_uns64 sz = e->e1->type->size() * 8; + if (i2 < 0 || i2 > sz) + { e->error("shift by %jd is outside the range 0..%zu", i2, sz); + e->e2 = new IntegerExp(0); + } + if (e->e1->isConst() == 1) + ex = (*shift)(e->type, e->e1, e->e2); + } + return ex; +} + +Expression *ShlExp::optimize(int result) +{ + //printf("ShlExp::optimize(result = %d) %s\n", result, toChars()); + return shift_optimize(result, this, Shl); +} + +Expression *ShrExp::optimize(int result) +{ + //printf("ShrExp::optimize(result = %d) %s\n", result, toChars()); + return shift_optimize(result, this, Shr); +} + +Expression *UshrExp::optimize(int result) +{ + //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); + return shift_optimize(result, this, Ushr); +} + +Expression *AndExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + e = And(type, e1, e2); + else + e = this; + return e; +} + +Expression *OrExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + e = Or(type, e1, e2); + else + e = this; + return e; +} + +Expression *XorExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + e = Xor(type, e1, e2); + else + e = this; + return e; +} + +Expression *CommaExp::optimize(int result) +{ Expression *e; + + //printf("CommaExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1->optimize(result & WANTinterpret); + e2 = e2->optimize(result); + if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2)) + { + e = e2; + if (e) + e->type = type; + } + else + e = this; + //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars()); + return e; +} + +Expression *ArrayLengthExp::optimize(int result) +{ Expression *e; + + //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e = this; + if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) + { + e = ArrayLength(type, e1); + } + return e; +} + +Expression *EqualExp::optimize(int result) +{ Expression *e; + + //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); + e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + e = this; + + Expression *e1 = fromConstInitializer(this->e1); + Expression *e2 = fromConstInitializer(this->e2); + + e = Equal(op, type, e1, e2); + if (e == EXP_CANT_INTERPRET) + e = this; + return e; +} + +Expression *IdentityExp::optimize(int result) +{ Expression *e; + + //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + e = this; + + if (this->e1->isConst() && this->e2->isConst()) + { + e = Identity(op, type, this->e1, this->e2); + if (e == EXP_CANT_INTERPRET) + e = this; + } + return e; +} + +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); + e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + e = Index(type, e1, e2); + if (e == EXP_CANT_INTERPRET) + e = this; + return e; +} + +Expression *SliceExp::optimize(int result) +{ Expression *e; + + //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); + e = this; + e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + if (!lwr) + { if (e1->op == TOKstring) + { // Convert slice of string literal into dynamic array + Type *t = e1->type->toBasetype(); + if (t->next) + e = e1->castTo(NULL, t->next->arrayOf()); + } + return e; + } + if (result & WANTinterpret) + e1 = fromConstInitializer(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; + return e; +} + +Expression *AndAndExp::optimize(int result) +{ Expression *e; + + //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); + e1 = e1->optimize(WANTflags | (result & WANTinterpret)); + e = this; + if (e1->isBool(FALSE)) + { + e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); + e->type = type; + e = e->optimize(result); + } + else + { + e2 = e2->optimize(WANTflags | (result & WANTinterpret)); + if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) + error("void has no value"); + if (e1->isConst()) + { + if (e2->isConst()) + { int n1 = e1->isBool(1); + int n2 = e2->isBool(1); + + e = new IntegerExp(loc, n1 && n2, type); + } + else if (e1->isBool(TRUE)) + e = new BoolExp(loc, e2, type); + } + } + return e; +} + +Expression *OrOrExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(WANTflags | (result & WANTinterpret)); + e = this; + if (e1->isBool(TRUE)) + { // Replace with (e1, 1) + e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type)); + e->type = type; + e = e->optimize(result); + } + else + { + e2 = e2->optimize(WANTflags | (result & WANTinterpret)); + if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) + error("void has no value"); + if (e1->isConst()) + { + if (e2->isConst()) + { int n1 = e1->isBool(1); + int n2 = e2->isBool(1); + + e = new IntegerExp(loc, n1 || n2, type); + } + else if (e1->isBool(FALSE)) + e = new BoolExp(loc, e2, type); + } + } + return e; +} + +Expression *CmpExp::optimize(int result) +{ Expression *e; + + //printf("CmpExp::optimize() %s\n", toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + { + e = Cmp(op, type, this->e1, this->e2); + } + else + e = this; + return e; +} + +Expression *CatExp::optimize(int result) +{ Expression *e; + + //printf("CatExp::optimize(%d) %s\n", result, toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + e = Cat(type, e1, e2); + if (e == EXP_CANT_INTERPRET) + e = this; + return e; +} + + +Expression *CondExp::optimize(int result) +{ Expression *e; + + econd = econd->optimize(WANTflags | (result & WANTinterpret)); + if (econd->isBool(TRUE)) + e = e1->optimize(result); + else if (econd->isBool(FALSE)) + e = e2->optimize(result); + else + { e1 = e1->optimize(result); + e2 = e2->optimize(result); + e = this; + } + return e; +} + +
--- a/dmd/parse.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/parse.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,5338 +1,5339 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// This is the D parser - -#include <stdio.h> -#include <assert.h> - -#include "rmem.h" -#include "lexer.h" -#include "parse.h" -#include "init.h" -#include "attrib.h" -#include "cond.h" -#include "mtype.h" -#include "template.h" -#include "staticassert.h" -#include "expression.h" -#include "statement.h" -#include "module.h" -#include "dsymbol.h" -#include "import.h" -#include "declaration.h" -#include "aggregate.h" -#include "enum.h" -#include "id.h" -#include "version.h" -#if DMDV2 -#include "aliasthis.h" -#endif - -// How multiple declarations are parsed. -// If 1, treat as C. -// If 0, treat: -// int *p, i; -// as: -// int* p; -// int* i; -#define CDECLSYNTAX 0 - -// Support C cast syntax: -// (type)(expression) -#define CCASTSYNTAX 1 - -// Support postfix C array declarations, such as -// int a[3][4]; -#define CARRAYDECL 1 - -// Support left-to-right array declarations -#define LTORARRAYDECL 1 - - -Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment) - : Lexer(module, base, 0, length, doDocComment, 0) -{ - //printf("Parser::Parser()\n"); - md = NULL; - linkage = LINKd; - endloc = 0; - inBrackets = 0; - //nextToken(); // start up the scanner -} - -Array *Parser::parseModule() -{ - Array *decldefs; - - // ModuleDeclation leads off - if (token.value == TOKmodule) - { - unsigned char *comment = token.blockComment; - - nextToken(); -#if DMDV2 - if (token.value == TOKlparen) - { - nextToken(); - if (token.value != TOKidentifier) - { error("module (system) identifier expected"); - goto Lerr; - } - Identifier *id = token.ident; - - if (id == Id::system) - safe = TRUE; - else - error("(safe) expected, not %s", id->toChars()); - nextToken(); - check(TOKrparen); - } -#endif - - if (token.value != TOKidentifier) - { error("Identifier expected following module"); - goto Lerr; - } - else - { - Array *a = NULL; - Identifier *id; - - id = token.ident; - while (nextToken() == TOKdot) - { - if (!a) - a = new Array(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following package"); - goto Lerr; - } - id = token.ident; - } - - md = new ModuleDeclaration(a, id); - - if (token.value != TOKsemicolon) - error("';' expected following module declaration instead of %s", token.toChars()); - nextToken(); - addComment(mod, comment); - } - } - - decldefs = parseDeclDefs(0); - if (token.value != TOKeof) - { error("unrecognized declaration"); - goto Lerr; - } - return decldefs; - -Lerr: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - return new Array(); -} - -Array *Parser::parseDeclDefs(int once) -{ Dsymbol *s; - Array *decldefs; - Array *a; - Array *aelse; - enum PROT prot; - unsigned stc; - Condition *condition; - unsigned char *comment; - - //printf("Parser::parseDeclDefs()\n"); - decldefs = new Array(); - do - { - comment = token.blockComment; - switch (token.value) - { - case TOKenum: - s = parseEnum(); - break; - - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - s = parseAggregate(); - break; - - case TOKimport: - s = parseImport(decldefs, 0); - break; - - case TOKtemplate: - s = (Dsymbol *)parseTemplateDeclaration(); - break; - - case TOKmixin: - { Loc loc = this->loc; - if (peek(&token)->value == TOKlparen) - { // mixin(string) - nextToken(); - check(TOKlparen, "mixin"); - Expression *e = parseAssignExp(); - check(TOKrparen); - check(TOKsemicolon); - s = new CompileDeclaration(loc, e); - break; - } - s = parseMixin(); - break; - } - - CASE_BASIC_TYPES: - case TOKalias: - case TOKtypedef: - case TOKidentifier: - case TOKtypeof: - case TOKdot: - Ldeclaration: - a = parseDeclarations(); - decldefs->append(a); - continue; - - case TOKthis: - s = parseCtor(); - break; - - case TOKtilde: - s = parseDtor(); - break; - - case TOKinvariant: -#if 1 - s = parseInvariant(); -#else - if (peek(&token)->value == TOKlcurly) - s = parseInvariant(); - else - { - stc = STCinvariant; - goto Lstc; - } -#endif - break; - - case TOKunittest: - s = parseUnitTest(); - break; - - case TOKnew: - s = parseNew(); - break; - - case TOKdelete: - s = parseDelete(); - break; - - case TOKeof: - case TOKrcurly: - return decldefs; - - case TOKstatic: - nextToken(); - if (token.value == TOKthis) - s = parseStaticCtor(); - else if (token.value == TOKtilde) - s = parseStaticDtor(); - else if (token.value == TOKassert) - s = parseStaticAssert(); - else if (token.value == TOKif) - { condition = parseStaticIfCondition(); - a = parseBlock(); - aelse = NULL; - if (token.value == TOKelse) - { nextToken(); - aelse = parseBlock(); - } - s = new StaticIfDeclaration(condition, a, aelse); - break; - } - else if (token.value == TOKimport) - { - s = parseImport(decldefs, 1); - } - else - { stc = STCstatic; - goto Lstc2; - } - break; - - case TOKconst: stc = STCconst; goto Lstc; - case TOKfinal: stc = STCfinal; goto Lstc; - case TOKauto: stc = STCauto; goto Lstc; - case TOKscope: stc = STCscope; goto Lstc; - case TOKoverride: stc = STCoverride; goto Lstc; - case TOKabstract: stc = STCabstract; goto Lstc; - case TOKsynchronized: stc = STCsynchronized; goto Lstc; - case TOKdeprecated: stc = STCdeprecated; goto Lstc; -#if DMDV2 - case TOKnothrow: stc = STCnothrow; goto Lstc; - case TOKpure: stc = STCpure; goto Lstc; - case TOKref: stc = STCref; goto Lstc; - case TOKtls: stc = STCtls; goto Lstc; - //case TOKmanifest: stc = STCmanifest; goto Lstc; -#endif - - Lstc: - nextToken(); - Lstc2: - switch (token.value) - { - case TOKconst: stc |= STCconst; goto Lstc; - case TOKfinal: stc |= STCfinal; goto Lstc; - case TOKauto: stc |= STCauto; goto Lstc; - case TOKscope: stc |= STCscope; goto Lstc; - case TOKoverride: stc |= STCoverride; goto Lstc; - case TOKabstract: stc |= STCabstract; goto Lstc; - case TOKsynchronized: stc |= STCsynchronized; goto Lstc; - case TOKdeprecated: stc |= STCdeprecated; goto Lstc; - //case TOKinvariant: stc |= STCinvariant; goto Lstc; - default: - break; - } - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - while (1) - { - Identifier *ident = token.ident; - nextToken(); - nextToken(); - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = stc; - s = v; - if (token.value == TOKsemicolon) - { - nextToken(); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - decldefs->push(s); - addComment(s, comment); - continue; - } - else - error("Identifier expected following comma"); - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - break; - } - } - else - { a = parseBlock(); - s = new StorageClassDeclaration(stc, a); - } - break; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto Lstc; - } - { - enum LINK linksave = linkage; - linkage = parseLinkage(); - a = parseBlock(); - s = new LinkDeclaration(linkage, a); - linkage = linksave; - break; - } - case TOKprivate: prot = PROTprivate; goto Lprot; - case TOKpackage: prot = PROTpackage; goto Lprot; - case TOKprotected: prot = PROTprotected; goto Lprot; - case TOKpublic: prot = PROTpublic; goto Lprot; - case TOKexport: prot = PROTexport; goto Lprot; - - Lprot: - nextToken(); - switch (token.value) - { - case TOKprivate: - case TOKpackage: - case TOKprotected: - case TOKpublic: - case TOKexport: - error("redundant protection attribute"); - break; - } - a = parseBlock(); - s = new ProtDeclaration(prot, a); - break; - - case TOKalign: - { unsigned n; - - // LDC better align code locations - Loc alignloc = loc; - - s = NULL; - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - if (token.value == TOKint32v) - n = (unsigned)token.uns64value; - else - { error("integer expected, not %s", token.toChars()); - n = 1; - } - nextToken(); - check(TOKrparen); - } - else - n = global.structalign; // default - - a = parseBlock(); - s = new AlignDeclaration(alignloc, n, a); - break; - } - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...) - else - check(TOKrparen); // pragma(identifier) - - if (token.value == TOKsemicolon) - a = NULL; - else - a = parseBlock(); - s = new PragmaDeclaration(loc, ident, args, a); - break; - } - - case TOKdebug: - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value == TOKidentifier) - s = new DebugSymbol(loc, token.ident); - else if (token.value == TOKint32v) - s = new DebugSymbol(loc, (unsigned)token.uns64value); - else - { error("identifier or integer expected, not %s", token.toChars()); - s = NULL; - } - nextToken(); - if (token.value != TOKsemicolon) - error("semicolon expected"); - nextToken(); - break; - } - - condition = parseDebugCondition(); - goto Lcondition; - - case TOKversion: - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value == TOKidentifier) - s = new VersionSymbol(loc, token.ident); - else if (token.value == TOKint32v) - s = new VersionSymbol(loc, (unsigned)token.uns64value); - else - { error("identifier or integer expected, not %s", token.toChars()); - s = NULL; - } - nextToken(); - if (token.value != TOKsemicolon) - error("semicolon expected"); - nextToken(); - break; - } - condition = parseVersionCondition(); - goto Lcondition; - - Lcondition: - a = parseBlock(); - aelse = NULL; - if (token.value == TOKelse) - { nextToken(); - aelse = parseBlock(); - } - s = new ConditionalDeclaration(condition, a, aelse); - break; - - case TOKsemicolon: // empty declaration - nextToken(); - continue; - - default: - error("Declaration expected, not '%s'",token.toChars()); - Lerror: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - s = NULL; - continue; - } - if (s) - { decldefs->push(s); - addComment(s, comment); - } - } while (!once); - return decldefs; -} - - -/******************************************** - * Parse declarations after an align, protection, or extern decl. - */ - -Array *Parser::parseBlock() -{ - Array *a = NULL; - Dsymbol *s; - - //printf("parseBlock()\n"); - switch (token.value) - { - case TOKsemicolon: - error("declaration expected following attribute, not ';'"); - nextToken(); - break; - - case TOKeof: - error("declaration expected following attribute, not EOF"); - break; - - case TOKlcurly: - nextToken(); - a = parseDeclDefs(0); - if (token.value != TOKrcurly) - { /* { */ - error("matching '}' expected, not %s", token.toChars()); - } - else - nextToken(); - break; - - case TOKcolon: - nextToken(); -#if 0 - a = NULL; -#else - a = parseDeclDefs(0); // grab declarations up to closing curly bracket -#endif - break; - - default: - a = parseDeclDefs(1); - break; - } - return a; -} - -/********************************** - * Parse a static assertion. - */ - -StaticAssert *Parser::parseStaticAssert() -{ - Loc loc = this->loc; - Expression *exp; - Expression *msg = NULL; - - //printf("parseStaticAssert()\n"); - nextToken(); - check(TOKlparen); - exp = parseAssignExp(); - if (token.value == TOKcomma) - { nextToken(); - msg = parseAssignExp(); - } - check(TOKrparen); - check(TOKsemicolon); - return new StaticAssert(loc, exp, msg); -} - -/*********************************** - * Parse typeof(expression). - * Current token is on the 'typeof'. - */ - -#if DMDV2 -TypeQualified *Parser::parseTypeof() -{ TypeQualified *t; - Loc loc = this->loc; - - nextToken(); - check(TOKlparen); - if (token.value == TOKreturn) // typeof(return) - { - nextToken(); - t = new TypeReturn(loc); - } - else - { Expression *exp = parseExpression(); // typeof(expression) - t = new TypeTypeof(loc, exp); - } - check(TOKrparen); - return t; -} -#endif - -/*********************************** - * Parse extern (linkage) - * The parser is on the 'extern' token. - */ - -enum LINK Parser::parseLinkage() -{ - enum LINK link = LINKdefault; - nextToken(); - assert(token.value == TOKlparen); - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (id == Id::Windows) - link = LINKwindows; - else if (id == Id::Pascal) - link = LINKpascal; - else if (id == Id::D) - link = LINKd; - else if (id == Id::C) - { - link = LINKc; - if (token.value == TOKplusplus) - { link = LINKcpp; - nextToken(); - } - } - else if (id == Id::System) - { - // LDC we configure target at runtime - if (global.params.os == OSWindows) - link = LINKwindows; - else - link = LINKc; - } - else - { - error("valid linkage identifiers are D, C, C++, Pascal, Windows, System"); - link = LINKd; - } - } - else - { - link = LINKd; // default - } - check(TOKrparen); - return link; -} - -/************************************** - * Parse a debug conditional - */ - -Condition *Parser::parseDebugCondition() -{ - Condition *c; - - if (token.value == TOKlparen) - { - nextToken(); - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v) - level = (unsigned)token.uns64value; - else - error("identifier or integer expected, not %s", token.toChars()); - nextToken(); - check(TOKrparen); - c = new DebugCondition(mod, level, id); - } - else - c = new DebugCondition(mod, 1, NULL); - return c; - -} - -/************************************** - * Parse a version conditional - */ - -Condition *Parser::parseVersionCondition() -{ - Condition *c; - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKlparen) - { - nextToken(); - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v) - level = (unsigned)token.uns64value; -#if DMDV2 - /* Allow: - * version (unittest) - * even though unittest is a keyword - */ - else if (token.value == TOKunittest) - id = Lexer::idPool(Token::toChars(TOKunittest)); -#endif - else - error("identifier or integer expected, not %s", token.toChars()); - nextToken(); - check(TOKrparen); - - } - else - error("(condition) expected following version"); - c = new VersionCondition(mod, level, id); - return c; - -} - -/*********************************************** - * static if (expression) - * body - * else - * body - */ - -Condition *Parser::parseStaticIfCondition() -{ Expression *exp; - Condition *condition; - Array *aif; - Array *aelse; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseAssignExp(); - check(TOKrparen); - } - else - { error("(expression) expected following static if"); - exp = NULL; - } - condition = new StaticIfCondition(loc, exp); - return condition; -} - - -/***************************************** - * Parse a constructor definition: - * this(arguments) { body } - * Current token is 'this'. - */ - -CtorDeclaration *Parser::parseCtor() -{ - CtorDeclaration *f; - Arguments *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - f = new CtorDeclaration(loc, 0, arguments, varargs); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a destructor definition: - * ~this() { body } - * Current token is '~'. - */ - -DtorDeclaration *Parser::parseDtor() -{ - DtorDeclaration *f; - Loc loc = this->loc; - - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - f = new DtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a static constructor definition: - * static this() { body } - * Current token is 'this'. - */ - -StaticCtorDeclaration *Parser::parseStaticCtor() -{ - StaticCtorDeclaration *f; - Loc loc = this->loc; - - nextToken(); - check(TOKlparen); - check(TOKrparen); - - f = new StaticCtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a static destructor definition: - * static ~this() { body } - * Current token is '~'. - */ - -StaticDtorDeclaration *Parser::parseStaticDtor() -{ - StaticDtorDeclaration *f; - Loc loc = this->loc; - - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - f = new StaticDtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse an invariant definition: - * invariant() { body } - * Current token is 'invariant'. - */ - -InvariantDeclaration *Parser::parseInvariant() -{ - InvariantDeclaration *f; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) // optional () - { - nextToken(); - check(TOKrparen); - } - - f = new InvariantDeclaration(loc, 0); - f->fbody = parseStatement(PScurly); - return f; -} - -/***************************************** - * Parse a unittest definition: - * unittest { body } - * Current token is 'unittest'. - */ - -UnitTestDeclaration *Parser::parseUnitTest() -{ - UnitTestDeclaration *f; - Statement *body; - Loc loc = this->loc; - - nextToken(); - - body = parseStatement(PScurly); - - f = new UnitTestDeclaration(loc, this->loc); - f->fbody = body; - return f; -} - -/***************************************** - * Parse a new definition: - * new(arguments) { body } - * Current token is 'new'. - */ - -NewDeclaration *Parser::parseNew() -{ - NewDeclaration *f; - Arguments *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - f = new NewDeclaration(loc, 0, arguments, varargs); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a delete definition: - * delete(arguments) { body } - * Current token is 'delete'. - */ - -DeleteDeclaration *Parser::parseDelete() -{ - DeleteDeclaration *f; - Arguments *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - if (varargs) - error("... not allowed in delete function parameter list"); - f = new DeleteDeclaration(loc, 0, arguments); - parseContracts(f); - return f; -} - -/********************************************** - * Parse parameter list. - */ - -Arguments *Parser::parseParameters(int *pvarargs) -{ - Arguments *arguments = new Arguments(); - int varargs = 0; - int hasdefault = 0; - - check(TOKlparen); - while (1) - { Type *tb; - Identifier *ai = NULL; - Type *at; - Argument *a; - unsigned storageClass; - Expression *ae; - - storageClass = STCin; // parameter is "in" by default - switch (token.value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - varargs = 1; - nextToken(); - break; - - case TOKin: - storageClass = STCin; - nextToken(); - goto L1; - - case TOKout: - storageClass = STCout; - nextToken(); - goto L1; - - case TOKinout: - case TOKref: - storageClass = STCref; - nextToken(); - goto L1; - - case TOKlazy: - storageClass = STClazy; - nextToken(); - goto L1; - - default: - L1: - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - ae = NULL; - if (token.value == TOKassign) // = defaultArg - { nextToken(); - ae = parseAssignExp(); - hasdefault = 1; - } - else - { if (hasdefault) - error("default argument expected for %s", - ai ? ai->toChars() : at->toChars()); - } - if (token.value == TOKdotdotdot) - { /* This is: - * at ai ... - */ - - if (storageClass & (STCout | STCref)) - error("variadic argument cannot be out or ref"); - varargs = 2; - a = new Argument(storageClass, at, ai, ae); - arguments->push(a); - nextToken(); - break; - } - a = new Argument(storageClass, at, ai, ae); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - break; - } - check(TOKrparen); - *pvarargs = varargs; - return arguments; -} - - -/************************************* - */ - -EnumDeclaration *Parser::parseEnum() -{ EnumDeclaration *e; - Identifier *id; - Type *memtype; - Loc loc = this->loc; - - //printf("Parser::parseEnum()\n"); - nextToken(); - if (token.value == TOKidentifier) - { id = token.ident; - nextToken(); - } - else - id = NULL; - - if (token.value == TOKcolon) - { - nextToken(); - memtype = parseBasicType(); - } - else - memtype = NULL; - - e = new EnumDeclaration(loc, id, memtype); - if (token.value == TOKsemicolon && id) - nextToken(); - else if (token.value == TOKlcurly) - { - //printf("enum definition\n"); - e->members = new Array(); - nextToken(); - unsigned char *comment = token.blockComment; - while (token.value != TOKrcurly) - { - if (token.value == TOKidentifier) - { EnumMember *em; - Expression *value; - Identifier *ident; - - loc = this->loc; - ident = token.ident; - value = NULL; - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - value = parseAssignExp(); - } - em = new EnumMember(loc, ident, value); - e->members->push(em); - if (token.value == TOKrcurly) - ; - else - { addComment(em, comment); - comment = NULL; - check(TOKcomma); - } - addComment(em, comment); - comment = token.blockComment; - } - else - { error("enum member expected"); - nextToken(); - } - } - nextToken(); - } - else - error("enum declaration is invalid"); - - //printf("-parseEnum() %s\n", e->toChars()); - return e; -} - -/******************************** - * Parse struct, union, interface, class. - */ - -Dsymbol *Parser::parseAggregate() -{ AggregateDeclaration *a = NULL; - int anon = 0; - enum TOK tok; - Identifier *id; - TemplateParameters *tpl = NULL; - - //printf("Parser::parseAggregate()\n"); - tok = token.value; - nextToken(); - if (token.value != TOKidentifier) - { id = NULL; - } - else - { id = token.ident; - nextToken(); - - if (token.value == TOKlparen) - { // Class template declaration. - - // Gather template parameter list - tpl = parseTemplateParameterList(); - } - } - - Loc loc = this->loc; - switch (tok) - { case TOKclass: - case TOKinterface: - { - if (!id) - error("anonymous classes not allowed"); - - // Collect base class(es) - BaseClasses *baseclasses = NULL; - if (token.value == TOKcolon) - { - nextToken(); - baseclasses = parseBaseClasses(); - - if (token.value != TOKlcurly) - error("members expected"); - } - - if (tok == TOKclass) - a = new ClassDeclaration(loc, id, baseclasses); - else - a = new InterfaceDeclaration(loc, id, baseclasses); - break; - } - - case TOKstruct: - if (id) - a = new StructDeclaration(loc, id); - else - anon = 1; - break; - - case TOKunion: - if (id) - a = new UnionDeclaration(loc, id); - else - anon = 2; - break; - - default: - assert(0); - break; - } - if (a && token.value == TOKsemicolon) - { nextToken(); - } - else if (token.value == TOKlcurly) - { - //printf("aggregate definition\n"); - nextToken(); - Array *decl = parseDeclDefs(0); - if (token.value != TOKrcurly) - error("} expected following member declarations in aggregate"); - nextToken(); - if (anon) - { - /* Anonymous structs/unions are more like attributes. - */ - return new AnonDeclaration(loc, anon - 1, decl); - } - else - a->members = decl; - } - else - { - error("{ } expected following aggregate declaration"); - a = new StructDeclaration(loc, NULL); - } - - if (tpl) - { Array *decldefs; - TemplateDeclaration *tempdecl; - - // Wrap a template around the aggregate declaration - decldefs = new Array(); - decldefs->push(a); - tempdecl = new TemplateDeclaration(loc, id, tpl, NULL, decldefs); - return tempdecl; - } - - return a; -} - -/******************************************* - */ - -BaseClasses *Parser::parseBaseClasses() -{ - enum PROT protection = PROTpublic; - BaseClasses *baseclasses = new BaseClasses(); - - for (; 1; nextToken()) - { - switch (token.value) - { - case TOKidentifier: - break; - case TOKprivate: - protection = PROTprivate; - continue; - case TOKpackage: - protection = PROTpackage; - continue; - case TOKprotected: - protection = PROTprotected; - continue; - case TOKpublic: - protection = PROTpublic; - continue; - default: - error("base classes expected instead of %s", token.toChars()); - return NULL; - } - BaseClass *b = new BaseClass(parseBasicType(), protection); - baseclasses->push(b); - if (token.value != TOKcomma) - break; - protection = PROTpublic; - } - return baseclasses; -} - -/************************************** - * Parse constraint. - * Constraint is of the form: - * if ( ConstraintExpression ) - */ - -#if DMDV2 -Expression *Parser::parseConstraint() -{ Expression *e = NULL; - - if (token.value == TOKif) - { - nextToken(); // skip over 'if' - check(TOKlparen); - e = parseExpression(); - check(TOKrparen); - } - return e; -} -#endif - -/************************************** - * Parse a TemplateDeclaration. - */ - -TemplateDeclaration *Parser::parseTemplateDeclaration() -{ - TemplateDeclaration *tempdecl; - Identifier *id; - TemplateParameters *tpl; - Array *decldefs; - Loc loc = this->loc; - - nextToken(); - if (token.value != TOKidentifier) - { error("TemplateIdentifier expected following template"); - goto Lerr; - } - id = token.ident; - nextToken(); - tpl = parseTemplateParameterList(); - if (!tpl) - goto Lerr; - - if (token.value != TOKlcurly) - { error("members of template declaration expected"); - goto Lerr; - } - else - { - nextToken(); - decldefs = parseDeclDefs(0); - if (token.value != TOKrcurly) - { error("template member expected"); - goto Lerr; - } - nextToken(); - } - - tempdecl = new TemplateDeclaration(loc, id, tpl, NULL, decldefs); - return tempdecl; - -Lerr: - return NULL; -} - -/****************************************** - * Parse template parameter list. - */ - -TemplateParameters *Parser::parseTemplateParameterList() -{ - TemplateParameters *tpl = new TemplateParameters(); - - if (token.value != TOKlparen) - { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); - goto Lerr; - } - nextToken(); - - // Get array of TemplateParameters - if (token.value != TOKrparen) - { int isvariadic = 0; - - while (1) - { TemplateParameter *tp; - Identifier *tp_ident = NULL; - Type *tp_spectype = NULL; - Type *tp_valtype = NULL; - Type *tp_defaulttype = NULL; - Expression *tp_specvalue = NULL; - Expression *tp_defaultvalue = NULL; - Token *t; - - // Get TemplateParameter - - // First, look ahead to see if it is a TypeParameter or a ValueParameter - t = peek(&token); - if (token.value == TOKalias) - { // AliasParameter - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected for template parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseBasicType(); - tp_spectype = parseDeclarator(tp_spectype, NULL); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseBasicType(); - tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); - } - tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (t->value == TOKcolon || t->value == TOKassign || - t->value == TOKcomma || t->value == TOKrparen) - { // TypeParameter - if (token.value != TOKidentifier) - { error("Identifier expected for template parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseBasicType(); - tp_spectype = parseDeclarator(tp_spectype, NULL); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseBasicType(); - tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); - } - tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (token.value == TOKidentifier && t->value == TOKdotdotdot) - { // ident... - if (isvariadic) - error("variadic template parameter must be last"); - isvariadic = 1; - tp_ident = token.ident; - nextToken(); - nextToken(); - tp = new TemplateTupleParameter(loc, tp_ident); - } -#if DMDV2 - else if (token.value == TOKthis) - { // ThisParameter - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected for template this parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseType(); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseType(); - } - tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } -#endif - else - { // ValueParameter - tp_valtype = parseBasicType(); - tp_valtype = parseDeclarator(tp_valtype, &tp_ident); - if (!tp_ident) - { - error("identifier expected for template value parameter"); - tp_ident = new Identifier("error", TOKidentifier); - } - if (token.value == TOKcolon) // : CondExpression - { - nextToken(); - tp_specvalue = parseCondExp(); - } - if (token.value == TOKassign) // = CondExpression - { - nextToken(); - tp_defaultvalue = parseCondExp(); - } - tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); - } - tpl->push(tp); - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen); -Lerr: - return tpl; -} - -/****************************************** - * Parse template mixin. - * mixin Foo; - * mixin Foo!(args); - * mixin a.b.c!(args).Foo!(args); - * mixin Foo!(args) identifier; - * mixin typeof(expr).identifier!(args); - */ - -Dsymbol *Parser::parseMixin() -{ - TemplateMixin *tm; - Identifier *id; - Type *tqual; - Objects *tiargs; - Array *idents; - - //printf("parseMixin()\n"); - nextToken(); - tqual = NULL; - if (token.value == TOKdot) - { - id = Id::empty; - } - else - { - if (token.value == TOKtypeof) - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - tqual = new TypeTypeof(loc, exp); - check(TOKdot); - } - if (token.value != TOKidentifier) - { - error("identifier expected, not %s", token.toChars()); - id = Id::empty; - } - else - id = token.ident; - nextToken(); - } - - idents = new Array(); - while (1) - { - tiargs = NULL; - if (token.value == TOKnot) - { - nextToken(); - tiargs = parseTemplateArgumentList(); - } - - if (token.value != TOKdot) - break; - - if (tiargs) - { TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = tiargs; - id = (Identifier *)tempinst; - tiargs = NULL; - } - idents->push(id); - - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - } - idents->push(id); - - if (token.value == TOKidentifier) - { - id = token.ident; - nextToken(); - } - else - id = NULL; - - tm = new TemplateMixin(loc, id, tqual, idents, tiargs); - if (token.value != TOKsemicolon) - error("';' expected after mixin"); - nextToken(); - - return tm; -} - -/****************************************** - * Parse template argument list. - * Input: - * current token is opening '(' - * Output: - * current token is one after closing ')' - */ - -Objects *Parser::parseTemplateArgumentList() -{ - //printf("Parser::parseTemplateArgumentList()\n"); - Objects *tiargs = new Objects(); - if (token.value != TOKlparen) - { error("!(TemplateArgumentList) expected following TemplateIdentifier"); - return tiargs; - } - nextToken(); - - // Get TemplateArgumentList - if (token.value != TOKrparen) - { - while (1) - { - // See if it is an Expression or a Type - if (isDeclaration(&token, 0, TOKreserved, NULL)) - { // Type - Type *ta; - - // Get TemplateArgument - ta = parseBasicType(); - ta = parseDeclarator(ta, NULL); - tiargs->push(ta); - } - else - { // Expression - Expression *ea; - - ea = parseAssignExp(); - tiargs->push(ea); - } - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen, "template argument list"); - return tiargs; -} - -Import *Parser::parseImport(Array *decldefs, int isstatic) -{ Import *s; - Identifier *id; - Identifier *aliasid = NULL; - Array *a; - Loc loc; - - //printf("Parser::parseImport()\n"); - do - { - L1: - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following import"); - break; - } - - loc = this->loc; - a = NULL; - id = token.ident; - nextToken(); - if (!aliasid && token.value == TOKassign) - { - aliasid = id; - goto L1; - } - while (token.value == TOKdot) - { - if (!a) - a = new Array(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following package"); - break; - } - id = token.ident; - nextToken(); - } - - s = new Import(loc, a, id, aliasid, isstatic); - decldefs->push(s); - - /* Look for - * : alias=name, alias=name; - * syntax. - */ - if (token.value == TOKcolon) - { - do - { Identifier *name; - Identifier *alias; - - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following :"); - break; - } - alias = token.ident; - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following %s=", alias->toChars()); - break; - } - name = token.ident; - nextToken(); - } - else - { name = alias; - alias = NULL; - } - s->addAlias(name, alias); - } while (token.value == TOKcomma); - break; // no comma-separated imports of this form - } - - aliasid = NULL; - } while (token.value == TOKcomma); - - if (token.value == TOKsemicolon) - nextToken(); - else - { - error("';' expected"); - nextToken(); - } - - return NULL; -} - -#if DMDV2 -Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) -{ Type *t; - - /* Take care of the storage class prefixes that - * serve as type attributes: - * const shared, shared const, const, invariant, shared - */ - if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() != TOKlparen || - token.value == TOKshared && peekNext() == TOKconst && peekNext2() != TOKlparen) - { - nextToken(); - nextToken(); - /* shared const type - */ - t = parseType(pident, tpl); - t = t->makeSharedConst(); - return t; - } - else if (token.value == TOKconst && peekNext() != TOKlparen) - { - nextToken(); - /* const type - */ - t = parseType(pident, tpl); - t = t->makeConst(); - return t; - } - else if ((token.value == TOKinvariant || token.value == TOKimmutable) && - peekNext() != TOKlparen) - { - nextToken(); - /* invariant type - */ - t = parseType(pident, tpl); - t = t->makeInvariant(); - return t; - } - else if (token.value == TOKshared && peekNext() != TOKlparen) - { - nextToken(); - /* shared type - */ - t = parseType(pident, tpl); - t = t->makeShared(); - return t; - } - else - t = parseBasicType(); - t = parseDeclarator(t, pident, tpl); - return t; -} -#endif - -Type *Parser::parseBasicType() -{ Type *t; - Identifier *id; - TypeQualified *tid; - TemplateInstance *tempinst; - - //printf("parseBasicType()\n"); - switch (token.value) - { - CASE_BASIC_TYPES_X(t): - nextToken(); - break; - - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { - nextToken(); - tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = parseTemplateArgumentList(); - tid = new TypeInstance(loc, tempinst); - goto Lident2; - } - Lident: - tid = new TypeIdentifier(loc, id); - Lident2: - while (token.value == TOKdot) - { nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { - nextToken(); - tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = parseTemplateArgumentList(); - tid->addIdent((Identifier *)tempinst); - } - else - tid->addIdent(id); - } - t = tid; - break; - - case TOKdot: - // Leading . as in .foo - id = Id::empty; - goto Lident; - - case TOKtypeof: - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - tid = new TypeTypeof(loc, exp); - goto Lident2; - } - - default: - error("basic type expected, not %s", token.toChars()); - t = Type::tint32; - break; - } - return t; -} - -/****************************************** - * Parse things that follow the initial type t. - * t * - * t [] - * t [type] - * t [expression] - * t [expression .. expression] - * t function - * t delegate - */ - -Type *Parser::parseBasicType2(Type *t) -{ - Type *ts; - Type *ta; - - //printf("parseBasicType2()\n"); - while (1) - { - switch (token.value) - { - case TOKmul: - t = new TypePointer(t); - nextToken(); - continue; - - case TOKlbracket: -#if LTORARRAYDECL - // Handle []. Make sure things like - // int[3][1] a; - // is (array[1] of array[3] of int) - nextToken(); - if (token.value == TOKrbracket) - { - t = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - Type *index; - - //printf("it's an associative array\n"); - index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - t = new TypeAArray(t, index); - check(TOKrbracket); - } - else - { - //printf("it's [expression]\n"); - inBrackets++; - Expression *e = parseExpression(); // [ expression ] - if (token.value == TOKslice) - { Expression *e2; - - nextToken(); - e2 = parseExpression(); // [ exp .. exp ] - t = new TypeSlice(t, e, e2); - } - else - t = new TypeSArray(t,e); - inBrackets--; - check(TOKrbracket); - } - continue; -#else - // Handle []. Make sure things like - // int[3][1] a; - // is (array[3] of array[1] of int) - ts = t; - while (token.value == TOKlbracket) - { - nextToken(); - if (token.value == TOKrbracket) - { - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - Type *index; - - //printf("it's an associative array\n"); - index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("it's [expression]\n"); - Expression *e = parseExpression(); // [ expression ] - ta = new TypeSArray(t,e); - check(TOKrbracket); - } - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - } - t = ts; - continue; -#endif - - case TOKdelegate: - case TOKfunction: - { // Handle delegate declaration: - // t delegate(parameter list) - // t function(parameter list) - Arguments *arguments; - int varargs; - enum TOK save = token.value; - - nextToken(); - arguments = parseParameters(&varargs); - t = new TypeFunction(arguments, t, varargs, linkage); - if (save == TOKdelegate) - t = new TypeDelegate(t); - else - t = new TypePointer(t); // pointer to function - continue; - } - - default: - ts = t; - break; - } - break; - } - return ts; -} - -Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl) -{ Type *ts; - Type *ta; - - //printf("parseDeclarator(tpl = %p)\n", tpl); - t = parseBasicType2(t); - - switch (token.value) - { - - case TOKidentifier: - if (pident) - *pident = token.ident; - else - error("unexpected identifer '%s' in declarator", token.ident->toChars()); - ts = t; - nextToken(); - break; - - case TOKlparen: - /* Parse things with parentheses around the identifier, like: - * int (*ident[3])[] - * although the D style would be: - * int[]*[3] ident - */ - nextToken(); - ts = parseDeclarator(t, pident); - check(TOKrparen); - break; - - default: - ts = t; - break; - } - - // parse DeclaratorSuffixes - while (1) - { - switch (token.value) - { -#if CARRAYDECL - /* Support C style array syntax: - * int ident[] - * as opposed to D-style: - * int[] ident - */ - case TOKlbracket: - { // This is the old C-style post [] syntax. - nextToken(); - if (token.value == TOKrbracket) - { // It's a dynamic array - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - Type *index; - - //printf("it's an associative array\n"); - index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("it's [expression]\n"); - Expression *e = parseExpression(); // [ expression ] - ta = new TypeSArray(t, e); - check(TOKrbracket); - } - - /* Insert ta into - * ts -> ... -> t - * so that - * ts -> ... -> ta -> t - */ - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - continue; - } -#endif - case TOKlparen: - { Arguments *arguments; - int varargs; - - if (tpl) - { - /* Look ahead to see if this is (...)(...), - * i.e. a function template declaration - */ - if (peekPastParen(&token)->value == TOKlparen) - { // It's a function template declaration - //printf("function template declaration\n"); - - // Gather template parameter list - *tpl = parseTemplateParameterList(); - } - } - - arguments = parseParameters(&varargs); - Type *ta = new TypeFunction(arguments, t, varargs, linkage); - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - break; - } - } - break; - } - - return ts; -} - -/********************************** - * Parse Declarations. - * These can be: - * 1. declarations at global/class level - * 2. declarations at statement level - * Return array of Declaration *'s. - */ - -Array *Parser::parseDeclarations() -{ - enum STC storage_class; - enum STC stc; - Type *ts; - Type *t; - Type *tfirst; - Identifier *ident; - Array *a; - enum TOK tok = TOKreserved; - unsigned char *comment = token.blockComment; - enum LINK link = linkage; - - //printf("parseDeclarations()\n"); - switch (token.value) - { - case TOKtypedef: - case TOKalias: - tok = token.value; - nextToken(); - break; - - default: - tok = TOKreserved; - break; - } - - storage_class = STCundefined; - while (1) - { - switch (token.value) - { - case TOKconst: stc = STCconst; goto L1; - case TOKstatic: stc = STCstatic; goto L1; - case TOKfinal: stc = STCfinal; goto L1; - case TOKauto: stc = STCauto; goto L1; - case TOKscope: stc = STCscope; goto L1; - case TOKoverride: stc = STCoverride; goto L1; - case TOKabstract: stc = STCabstract; goto L1; - case TOKsynchronized: stc = STCsynchronized; goto L1; - case TOKdeprecated: stc = STCdeprecated; goto L1; -#if DMDV2 - case TOKnothrow: stc = STCnothrow; goto L1; - case TOKpure: stc = STCpure; goto L1; - case TOKref: stc = STCref; goto L1; - case TOKtls: stc = STCtls; goto L1; - case TOKenum: stc = STCmanifest; goto L1; -#endif - L1: - if (storage_class & stc) - error("redundant storage class '%s'", token.toChars()); - storage_class = (STC) (storage_class | stc); - nextToken(); - continue; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto L1; - } - - link = parseLinkage(); - continue; - - default: - break; - } - break; - } - - a = new Array(); - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - while (storage_class && - token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - ident = token.ident; - nextToken(); - nextToken(); - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storage_class; - a->push(v); - if (token.value == TOKsemicolon) - { - nextToken(); - addComment(v, comment); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign)) - { - error("Identifier expected following comma"); - } - else - continue; - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - return a; - } - - if (token.value == TOKclass) - { AggregateDeclaration *s; - - s = (AggregateDeclaration *)parseAggregate(); - s->storage_class |= storage_class; - a->push(s); - addComment(s, comment); - return a; - } - - ts = parseBasicType(); - ts = parseBasicType2(ts); - tfirst = NULL; - - while (1) - { - Loc loc = this->loc; - TemplateParameters *tpl = NULL; - - ident = NULL; - t = parseDeclarator(ts, &ident, &tpl); - assert(t); - if (!tfirst) - tfirst = t; - else if (t != tfirst) - error("multiple declarations must have the same type, not %s and %s", - tfirst->toChars(), t->toChars()); - if (!ident) - error("no identifier for declarator %s", t->toChars()); - - if (tok == TOKtypedef || tok == TOKalias) - { Declaration *v; - Initializer *init = NULL; - - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - if (tok == TOKtypedef) - v = new TypedefDeclaration(loc, ident, t, init); - else - { if (init) - error("alias cannot have initializer"); - v = new AliasDeclaration(loc, ident, t); - } - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - Array *ax = new Array(); - ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); - } - switch (token.value) - { case TOKsemicolon: - nextToken(); - addComment(v, comment); - break; - - case TOKcomma: - nextToken(); - addComment(v, comment); - continue; - - default: - error("semicolon expected to close %s declaration", Token::toChars(tok)); - break; - } - } - else if (t->ty == Tfunction) - { FuncDeclaration *f = - new FuncDeclaration(loc, 0, ident, storage_class, t); - addComment(f, comment); - parseContracts(f); - addComment(f, NULL); - Dsymbol *s; - if (link == linkage) - { - s = f; - } - else - { - Array *ax = new Array(); - ax->push(f); - s = new LinkDeclaration(link, ax); - } - if (tpl) // it's a function template - { Array *decldefs; - TemplateDeclaration *tempdecl; - - // Wrap a template around the aggregate declaration - decldefs = new Array(); - decldefs->push(s); - tempdecl = new TemplateDeclaration(loc, s->ident, tpl, NULL, decldefs); - s = tempdecl; - } - addComment(s, comment); - a->push(s); - } - else - { - Initializer *init = NULL; - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - - VarDeclaration *v = new VarDeclaration(loc, t, ident, init); - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - Array *ax = new Array(); - ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); - } - switch (token.value) - { case TOKsemicolon: - nextToken(); - addComment(v, comment); - break; - - case TOKcomma: - nextToken(); - addComment(v, comment); - continue; - - default: - error("semicolon expected, not '%s'", token.toChars()); - break; - } - } - break; - } - return a; -} - -/***************************************** - * Parse auto declarations of the form: - * storageClass ident = init, ident = init, ... ; - * and return the array of them. - * Starts with token on the first ident. - * Ends with scanner past closing ';' - */ - -#if DMDV2 -Array *Parser::parseAutoDeclarations(unsigned storageClass, unsigned char *comment) -{ - Array *a = new Array; - - while (1) - { - Identifier *ident = token.ident; - nextToken(); // skip over ident - assert(token.value == TOKassign); - nextToken(); // skip over '=' - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storageClass; - a->push(v); - if (token.value == TOKsemicolon) - { - nextToken(); - addComment(v, comment); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - addComment(v, comment); - continue; - } - else - error("Identifier expected following comma"); - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - break; - } - return a; -} -#endif - -/***************************************** - * Parse contracts following function declaration. - */ - -void Parser::parseContracts(FuncDeclaration *f) -{ - Type *tb; - enum LINK linksave = linkage; - - // The following is irrelevant, as it is overridden by sc->linkage in - // TypeFunction::semantic - linkage = LINKd; // nested functions have D linkage -L1: - switch (token.value) - { - case TOKlcurly: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - f->fbody = parseStatement(PSsemi); - f->endloc = endloc; - break; - - case TOKbody: - nextToken(); - f->fbody = parseStatement(PScurly); - f->endloc = endloc; - break; - - case TOKsemicolon: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - nextToken(); - break; - -#if 0 // Do we want this for function declarations, so we can do: - // int x, y, foo(), z; - case TOKcomma: - nextToken(); - continue; -#endif - -#if 0 // Dumped feature - case TOKthrow: - if (!f->fthrows) - f->fthrows = new Array(); - nextToken(); - check(TOKlparen); - while (1) - { - tb = parseBasicType(); - f->fthrows->push(tb); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKrparen); - goto L1; -#endif - - case TOKin: - nextToken(); - if (f->frequire) - error("redundant 'in' statement"); - f->frequire = parseStatement(PScurly | PSscope); - goto L1; - - case TOKout: - // parse: out (identifier) { statement } - nextToken(); - if (token.value != TOKlcurly) - { - check(TOKlparen); - if (token.value != TOKidentifier) - error("(identifier) following 'out' expected, not %s", token.toChars()); - f->outId = token.ident; - nextToken(); - check(TOKrparen); - } - if (f->fensure) - error("redundant 'out' statement"); - f->fensure = parseStatement(PScurly | PSscope); - goto L1; - - default: - error("semicolon expected following function declaration"); - break; - } - linkage = linksave; -} - -/***************************************** - * Parse initializer for variable declaration. - */ - -Initializer *Parser::parseInitializer() -{ - StructInitializer *is; - ArrayInitializer *ia; - ExpInitializer *ie; - Expression *e; - Identifier *id; - Initializer *value; - int comma; - Loc loc = this->loc; - Token *t; - int braces; - int brackets; - - switch (token.value) - { - case TOKlcurly: - /* Scan ahead to see if it is a struct initializer or - * a function literal. - * If it contains a ';', it is a function literal. - * Treat { } as a struct initializer. - */ - braces = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKsemicolon: - case TOKreturn: - goto Lexpression; - - case TOKlcurly: - braces++; - continue; - - case TOKrcurly: - if (--braces == 0) - break; - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - is = new StructInitializer(loc); - nextToken(); - comma = 0; - while (1) - { - switch (token.value) - { - case TOKidentifier: - if (comma == 1) - error("comma expected separating field initializers"); - t = peek(&token); - if (t->value == TOKcolon) - { - id = token.ident; - nextToken(); - nextToken(); // skip over ':' - } - else - { id = NULL; - } - value = parseInitializer(); - is->addInit(id, value); - comma = 1; - continue; - - case TOKcomma: - nextToken(); - comma = 2; - continue; - - case TOKrcurly: // allow trailing comma's - nextToken(); - break; - - case TOKeof: - error("found EOF instead of initializer"); - break; - - default: - value = parseInitializer(); - is->addInit(NULL, value); - comma = 1; - continue; - //error("found '%s' instead of field initializer", token.toChars()); - //break; - } - break; - } - return is; - - case TOKlbracket: - /* Scan ahead to see if it is an array initializer or - * an expression. - * If it ends with a ';', it is an array initializer. - */ - brackets = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brackets++; - continue; - - case TOKrbracket: - if (--brackets == 0) - { t = peek(t); - if (t->value != TOKsemicolon && - t->value != TOKcomma && - t->value != TOKrcurly) - goto Lexpression; - break; - } - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - ia = new ArrayInitializer(loc); - nextToken(); - comma = 0; - while (1) - { - switch (token.value) - { - default: - if (comma == 1) - { error("comma expected separating array initializers, not %s", token.toChars()); - nextToken(); - break; - } - e = parseAssignExp(); - if (!e) - break; - if (token.value == TOKcolon) - { - nextToken(); - value = parseInitializer(); - } - else - { value = new ExpInitializer(e->loc, e); - e = NULL; - } - ia->addInit(e, value); - comma = 1; - continue; - - case TOKlcurly: - case TOKlbracket: - if (comma == 1) - error("comma expected separating array initializers, not %s", token.toChars()); - value = parseInitializer(); - ia->addInit(NULL, value); - comma = 1; - continue; - - case TOKcomma: - nextToken(); - comma = 2; - continue; - - case TOKrbracket: // allow trailing comma's - nextToken(); - break; - - case TOKeof: - error("found '%s' instead of array initializer", token.toChars()); - break; - } - break; - } - return ia; - - case TOKvoid: - t = peek(&token); - if (t->value == TOKsemicolon || t->value == TOKcomma) - { - nextToken(); - return new VoidInitializer(loc); - } - goto Lexpression; - - default: - Lexpression: - e = parseAssignExp(); - ie = new ExpInitializer(loc, e); - return ie; - } -} - -/***************************************** - * Parses default argument initializer expression that is an assign expression, - * with special handling for __FILE__ and __LINE__. - */ - -#if DMDV2 -Expression *Parser::parseDefaultInitExp() -{ - if (token.value == TOKfile || - token.value == TOKline) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKrparen) - { Expression *e; - - if (token.value == TOKfile) - e = new FileInitExp(loc); - else - e = new LineInitExp(loc); - nextToken(); - return e; - } - } - - Expression *e = parseAssignExp(); - return e; -} -#endif - -/***************************************** - * Input: - * flags PSxxxx - */ - -Statement *Parser::parseStatement(int flags) -{ Statement *s; - Token *t; - Condition *condition; - Statement *ifbody; - Statement *elsebody; - Loc loc = this->loc; - - //printf("parseStatement()\n"); - - if (flags & PScurly && token.value != TOKlcurly) - error("statement expected to be { }, not %s", token.toChars()); - - switch (token.value) - { - case TOKidentifier: - /* A leading identifier can be a declaration, label, or expression. - * The easiest case to check first is label: - */ - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - - Identifier *ident = token.ident; - nextToken(); - nextToken(); - s = parseStatement(PSsemi); - s = new LabelStatement(loc, ident, s); - break; - } - // fallthrough to TOKdot - case TOKdot: - case TOKtypeof: - if (isDeclaration(&token, 2, TOKreserved, NULL)) - goto Ldeclaration; - else - goto Lexp; - break; - - case TOKassert: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKstring: - case TOKlparen: - case TOKcast: - case TOKmul: - case TOKmin: - case TOKadd: - case TOKplusplus: - case TOKminusminus: - case TOKnew: - case TOKdelete: - case TOKdelegate: - case TOKfunction: - case TOKtypeid: - case TOKis: - case TOKlbracket: -#if DMDV2 - case TOKtraits: - case TOKfile: - case TOKline: -#endif - Lexp: - { Expression *exp; - - exp = parseExpression(); - check(TOKsemicolon, "statement"); - s = new ExpStatement(loc, exp); - break; - } - - case TOKstatic: - { // Look ahead to see if it's static assert() or static if() - Token *t; - - t = peek(&token); - if (t->value == TOKassert) - { - nextToken(); - s = new StaticAssertStatement(parseStaticAssert()); - break; - } - if (t->value == TOKif) - { - nextToken(); - condition = parseStaticIfCondition(); - goto Lcondition; - } - goto Ldeclaration; - } - - CASE_BASIC_TYPES: - case TOKtypedef: - case TOKalias: - case TOKconst: - case TOKauto: - case TOKextern: - case TOKfinal: - case TOKinvariant: -#if DMDV2 - case TOKimmutable: - case TOKshared: -#endif -// case TOKtypeof: - Ldeclaration: - { Array *a; - - a = parseDeclarations(); - if (a->dim > 1) - { - Statements *as = new Statements(); - as->reserve(a->dim); - for (int i = 0; i < a->dim; i++) - { - Dsymbol *d = (Dsymbol *)a->data[i]; - s = new DeclarationStatement(loc, d); - as->push(s); - } - s = new CompoundDeclarationStatement(loc, as); - } - else if (a->dim == 1) - { - Dsymbol *d = (Dsymbol *)a->data[0]; - s = new DeclarationStatement(loc, d); - } - else - assert(0); - if (flags & PSscope) - s = new ScopeStatement(loc, s); - break; - } - - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - { Dsymbol *d; - - d = parseAggregate(); - s = new DeclarationStatement(loc, d); - break; - } - - case TOKenum: - { Dsymbol *d; - - d = parseEnum(); - s = new DeclarationStatement(loc, d); - break; - } - - case TOKmixin: - { t = peek(&token); - if (t->value == TOKlparen) - { // mixin(string) - nextToken(); - check(TOKlparen, "mixin"); - Expression *e = parseAssignExp(); - check(TOKrparen); - check(TOKsemicolon); - s = new CompileStatement(loc, e); - break; - } - Dsymbol *d = parseMixin(); - s = new DeclarationStatement(loc, d); - break; - } - - case TOKlcurly: - { Statements *statements; - - nextToken(); - statements = new Statements(); - while (token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - endloc = this->loc; - s = new CompoundStatement(loc, statements); - if (flags & (PSscope | PScurlyscope)) - s = new ScopeStatement(loc, s); - nextToken(); - break; - } - - case TOKwhile: - { Expression *condition; - Statement *body; - - nextToken(); - check(TOKlparen); - condition = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new WhileStatement(loc, condition, body); - break; - } - - case TOKsemicolon: - if (!(flags & PSsemi)) - error("use '{ }' for an empty statement, not a ';'"); - nextToken(); - s = new ExpStatement(loc, NULL); - break; - - case TOKdo: - { Statement *body; - Expression *condition; - - nextToken(); - body = parseStatement(PSscope); - check(TOKwhile); - check(TOKlparen); - condition = parseExpression(); - check(TOKrparen); - s = new DoStatement(loc, body, condition); - break; - } - - case TOKfor: - { - Statement *init; - Expression *condition; - Expression *increment; - Statement *body; - - nextToken(); - check(TOKlparen); - if (token.value == TOKsemicolon) - { init = NULL; - nextToken(); - } - else - { init = parseStatement(0); - } - if (token.value == TOKsemicolon) - { - condition = NULL; - nextToken(); - } - else - { - condition = parseExpression(); - check(TOKsemicolon, "for condition"); - } - if (token.value == TOKrparen) - { increment = NULL; - nextToken(); - } - else - { increment = parseExpression(); - check(TOKrparen); - } - body = parseStatement(PSscope); - s = new ForStatement(loc, init, condition, increment, body); - if (init) - s = new ScopeStatement(loc, s); - break; - } - - case TOKforeach: - case TOKforeach_reverse: - { - enum TOK op = token.value; - Arguments *arguments; - - Statement *d; - Statement *body; - Expression *aggr; - - nextToken(); - check(TOKlparen); - - arguments = new Arguments(); - - while (1) - { - Type *tb; - Identifier *ai = NULL; - Type *at; - unsigned storageClass; - Argument *a; - - storageClass = STCin; - if (token.value == TOKinout || token.value == TOKref) - { storageClass = STCref; - nextToken(); - } - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { ai = token.ident; - at = NULL; // infer argument type - nextToken(); - goto Larg; - } - } - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - if (!ai) - error("no identifier for declarator %s", at->toChars()); - Larg: - a = new Argument(storageClass, at, ai, NULL); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKsemicolon); - - aggr = parseExpression(); - check(TOKrparen); - body = parseStatement(0); - s = new ForeachStatement(loc, op, arguments, aggr, body); - break; - } - - case TOKif: - { Argument *arg = NULL; - Expression *condition; - Statement *ifbody; - Statement *elsebody; - - nextToken(); - check(TOKlparen); - - if (token.value == TOKauto) - { - nextToken(); - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKassign) - { - arg = new Argument(STCin, NULL, token.ident, NULL); - nextToken(); - nextToken(); - } - else - { error("= expected following auto identifier"); - goto Lerror; - } - } - else - { error("identifier expected following auto"); - goto Lerror; - } - } - else if (isDeclaration(&token, 2, TOKassign, NULL)) - { - Type *tb; - Type *at; - Identifier *ai; - - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - check(TOKassign); - arg = new Argument(STCin, at, ai, NULL); - } - - // Check for " ident;" - else if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { - arg = new Argument(STCin, NULL, token.ident, NULL); - nextToken(); - nextToken(); - if (1 || !global.params.useDeprecated) - error("if (v; e) is deprecated, use if (auto v = e)"); - } - } - - condition = parseExpression(); - check(TOKrparen); - ifbody = parseStatement(PSscope); - if (token.value == TOKelse) - { - nextToken(); - elsebody = parseStatement(PSscope); - } - else - elsebody = NULL; - s = new IfStatement(loc, arg, condition, ifbody, elsebody); - break; - } - - case TOKscope: - if (peek(&token)->value != TOKlparen) - goto Ldeclaration; // scope used as storage class - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("scope identifier expected"); - goto Lerror; - } - else - { TOK t = TOKon_scope_exit; - Identifier *id = token.ident; - - if (id == Id::exit) - t = TOKon_scope_exit; - else if (id == Id::failure) - t = TOKon_scope_failure; - else if (id == Id::success) - t = TOKon_scope_success; - else - error("valid scope identifiers are exit, failure, or success, not %s", id->toChars()); - nextToken(); - check(TOKrparen); - Statement *st = parseStatement(PScurlyscope); - s = new OnScopeStatement(loc, t, st); - break; - } - - case TOKdebug: - nextToken(); - condition = parseDebugCondition(); - goto Lcondition; - - case TOKversion: - nextToken(); - condition = parseVersionCondition(); - goto Lcondition; - - Lcondition: - ifbody = parseStatement(0 /*PSsemi*/); - elsebody = NULL; - if (token.value == TOKelse) - { - nextToken(); - elsebody = parseStatement(0 /*PSsemi*/); - } - s = new ConditionalStatement(loc, condition, ifbody, elsebody); - break; - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - Statement *body; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...); - else - check(TOKrparen); // pragma(identifier); - if (token.value == TOKsemicolon) - { nextToken(); - body = NULL; - } - else - body = parseStatement(PSsemi); - s = new PragmaStatement(loc, ident, args, body); - break; - } - - case TOKswitch: - { Expression *condition; - Statement *body; - - nextToken(); - check(TOKlparen); - condition = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new SwitchStatement(loc, condition, body); - break; - } - - case TOKcase: - { Expression *exp; - Statements *statements; - Array cases; // array of Expression's - - while (1) - { - nextToken(); - exp = parseAssignExp(); - cases.push(exp); - if (token.value != TOKcomma) - break; - } - check(TOKcolon); - - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - s = new ScopeStatement(loc, s); - - // Keep cases in order by building the case statements backwards - for (int i = cases.dim; i; i--) - { - exp = (Expression *)cases.data[i - 1]; - s = new CaseStatement(loc, exp, s); - } - break; - } - - case TOKdefault: - { - Statements *statements; - - nextToken(); - check(TOKcolon); - - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - s = new ScopeStatement(loc, s); - s = new DefaultStatement(loc, s); - break; - } - - case TOKreturn: - { Expression *exp; - - nextToken(); - if (token.value == TOKsemicolon) - exp = NULL; - else - exp = parseExpression(); - check(TOKsemicolon, "return statement"); - s = new ReturnStatement(loc, exp); - break; - } - - case TOKbreak: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "break statement"); - s = new BreakStatement(loc, ident); - break; - } - - case TOKcontinue: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "continue statement"); - s = new ContinueStatement(loc, ident); - break; - } - - case TOKgoto: - { Identifier *ident; - - nextToken(); - if (token.value == TOKdefault) - { - nextToken(); - s = new GotoDefaultStatement(loc); - } - else if (token.value == TOKcase) - { - Expression *exp = NULL; - - nextToken(); - if (token.value != TOKsemicolon) - exp = parseExpression(); - s = new GotoCaseStatement(loc, exp); - } - else - { - if (token.value != TOKidentifier) - { error("Identifier expected following goto"); - ident = NULL; - } - else - { ident = token.ident; - nextToken(); - } - s = new GotoStatement(loc, ident); - } - check(TOKsemicolon, "goto statement"); - break; - } - - case TOKsynchronized: - { Expression *exp; - Statement *body; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseExpression(); - check(TOKrparen); - } - else - exp = NULL; - body = parseStatement(PSscope); - s = new SynchronizedStatement(loc, exp, body); - break; - } - - case TOKwith: - { Expression *exp; - Statement *body; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new WithStatement(loc, exp, body); - break; - } - - case TOKtry: - { Statement *body; - Array *catches = NULL; - Statement *finalbody = NULL; - - nextToken(); - body = parseStatement(PSscope); - while (token.value == TOKcatch) - { - Statement *handler; - Catch *c; - Type *t; - Identifier *id; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlcurly) - { - t = NULL; - id = NULL; - } - else - { - check(TOKlparen); - t = parseBasicType(); - id = NULL; - t = parseDeclarator(t, &id); - check(TOKrparen); - } - handler = parseStatement(0); - c = new Catch(loc, t, id, handler); - if (!catches) - catches = new Array(); - catches->push(c); - } - - if (token.value == TOKfinally) - { nextToken(); - finalbody = parseStatement(0); - } - - s = body; - if (!catches && !finalbody) - error("catch or finally expected following try"); - else - { if (catches) - s = new TryCatchStatement(loc, body, catches); - if (finalbody) - s = new TryFinallyStatement(loc, s, finalbody); - } - break; - } - - case TOKthrow: - { Expression *exp; - - nextToken(); - exp = parseExpression(); - check(TOKsemicolon, "throw statement"); - s = new ThrowStatement(loc, exp); - break; - } - - case TOKvolatile: - nextToken(); - s = parseStatement(PSsemi | PScurlyscope); -#if DMDV2 - if (!global.params.useDeprecated) - error("volatile statements deprecated; used synchronized statements instead"); -#endif - s = new VolatileStatement(loc, s); - break; - - case TOKasm: - { Statements *statements; - Identifier *label; - Loc labelloc; - Token *toklist; - Token **ptoklist; - - // Parse the asm block into a sequence of AsmStatements, - // each AsmStatement is one instruction. - // Separate out labels. - // Defer parsing of AsmStatements until semantic processing. - - nextToken(); - check(TOKlcurly); - toklist = NULL; - ptoklist = &toklist; - label = NULL; - statements = new Statements(); - while (1) - { - switch (token.value) - { - case TOKidentifier: - if (!toklist) - { - // Look ahead to see if it is a label - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - label = token.ident; - labelloc = this->loc; - nextToken(); - nextToken(); - continue; - } - } - goto Ldefault; - - case TOKrcurly: - if (toklist || label) - { - error("asm statements must end in ';'"); - } - break; - - case TOKsemicolon: - s = NULL; - if (toklist || label) - { // Create AsmStatement from list of tokens we've saved - s = new AsmStatement(this->loc, toklist); - toklist = NULL; - ptoklist = &toklist; - if (label) - { s = new LabelStatement(labelloc, label, s); - label = NULL; - } - statements->push(s); - } - nextToken(); - continue; - - case TOKeof: - /* { */ - error("matching '}' expected, not end of file"); - break; - - default: - Ldefault: - *ptoklist = new Token(); - memcpy(*ptoklist, &token, sizeof(Token)); - ptoklist = &(*ptoklist)->next; - *ptoklist = NULL; - - nextToken(); - continue; - } - break; - } - s = new AsmBlockStatement(loc, statements); - nextToken(); - break; - } - - default: - error("found '%s' instead of statement", token.toChars()); - goto Lerror; - - Lerror: - while (token.value != TOKrcurly && - token.value != TOKsemicolon && - token.value != TOKeof) - nextToken(); - if (token.value == TOKsemicolon) - nextToken(); - s = NULL; - break; - } - - return s; -} - -void Parser::check(enum TOK value) -{ - check(loc, value); -} - -void Parser::check(Loc loc, enum TOK value) -{ - if (token.value != value) - error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value)); - nextToken(); -} - -void Parser::check(enum TOK value, const char *string) -{ - if (token.value != value) - error("found '%s' when expecting '%s' following '%s'", - token.toChars(), Token::toChars(value), string); - nextToken(); -} - -/************************************ - * Determine if the scanner is sitting on the start of a declaration. - * Input: - * needId 0 no identifier - * 1 identifier optional - * 2 must have identifier - */ - -int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) -{ - //printf("isDeclaration(needId = %d)\n", needId); - int haveId = 0; - -#if DMDV2 - if ((t->value == TOKconst || t->value == TOKinvariant) && - peek(t)->value != TOKlparen) - { /* const type - * invariant type - */ - t = peek(t); - } -#endif - - if (!isBasicType(&t)) - return FALSE; - if (!isDeclarator(&t, &haveId, endtok)) - return FALSE; - if ( needId == 1 || - (needId == 0 && !haveId) || - (needId == 2 && haveId)) - { if (pt) - *pt = t; - return TRUE; - } - else - return FALSE; -} - -int Parser::isBasicType(Token **pt) -{ - // This code parallels parseBasicType() - Token *t = *pt; - Token *t2; - int parens; - - switch (t->value) - { - CASE_BASIC_TYPES: - t = peek(t); - break; - - case TOKidentifier: - t = peek(t); - if (t->value == TOKnot) - { - goto L4; - } - goto L3; - while (1) - { - L2: - t = peek(t); - L3: - if (t->value == TOKdot) - { - Ldot: - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - if (t->value != TOKnot) - goto L3; - L4: - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - if (!skipParens(t, &t)) - goto Lfalse; - } - else - break; - } - break; - - case TOKdot: - goto Ldot; - - case TOKtypeof: - /* typeof(exp).identifier... - */ - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - if (!skipParens(t, &t)) - goto Lfalse; - goto L2; - - default: - goto Lfalse; - } - *pt = t; - //printf("is\n"); - return TRUE; - -Lfalse: - //printf("is not\n"); - return FALSE; -} - -int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) -{ // This code parallels parseDeclarator() - Token *t = *pt; - int parens; - - //printf("Parser::isDeclarator()\n"); - //t->print(); - if (t->value == TOKassign) - return FALSE; - - while (1) - { - parens = FALSE; - switch (t->value) - { - case TOKmul: - //case TOKand: - t = peek(t); - continue; - - case TOKlbracket: - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { // It's an associative array declaration - t = peek(t); - } - else - { - // [ expression ] - // [ expression .. expression ] - if (!isExpression(&t)) - return FALSE; - if (t->value == TOKslice) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - if (t->value != TOKrbracket) - return FALSE; - t = peek(t); - } - continue; - - case TOKidentifier: - if (*haveId) - return FALSE; - *haveId = TRUE; - t = peek(t); - break; - - case TOKlparen: - t = peek(t); - - if (t->value == TOKrparen) - return FALSE; // () is not a declarator - - /* Regard ( identifier ) as not a declarator - * BUG: what about ( *identifier ) in - * f(*p)(x); - * where f is a class instance with overloaded () ? - * Should we just disallow C-style function pointer declarations? - */ - if (t->value == TOKidentifier) - { Token *t2 = peek(t); - if (t2->value == TOKrparen) - return FALSE; - } - - - if (!isDeclarator(&t, haveId, TOKrparen)) - return FALSE; - t = peek(t); - parens = TRUE; - break; - - case TOKdelegate: - case TOKfunction: - t = peek(t); - if (!isParameters(&t)) - return FALSE; - continue; - } - break; - } - - while (1) - { - switch (t->value) - { -#if CARRAYDECL - case TOKlbracket: - parens = FALSE; - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { // It's an associative array declaration - t = peek(t); - } - else - { - // [ expression ] - if (!isExpression(&t)) - return FALSE; - if (t->value != TOKrbracket) - return FALSE; - t = peek(t); - } - continue; -#endif - - case TOKlparen: - parens = FALSE; - if (!isParameters(&t)) - return FALSE; -#if DMDV2 - while (1) - { - switch (t->value) - { - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - case TOKpure: - case TOKnothrow: - t = peek(t); - continue; - default: - break; - } - break; - } -#endif - continue; - - // Valid tokens that follow a declaration - case TOKrparen: - case TOKrbracket: - case TOKassign: - case TOKcomma: - case TOKsemicolon: - case TOKlcurly: - case TOKin: - // The !parens is to disallow unnecessary parentheses - if (!parens && (endtok == TOKreserved || endtok == t->value)) - { *pt = t; - return TRUE; - } - return FALSE; - - default: - return FALSE; - } - } -} - - -int Parser::isParameters(Token **pt) -{ // This code parallels parseParameters() - Token *t = *pt; - int tmp; - - //printf("isParameters()\n"); - if (t->value != TOKlparen) - return FALSE; - - t = peek(t); - while (1) - { - switch (t->value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - t = peek(t); - break; - - case TOKin: - case TOKout: - case TOKinout: - case TOKref: - case TOKlazy: - t = peek(t); - default: - if (!isBasicType(&t)) - return FALSE; - tmp = FALSE; - if (t->value != TOKdotdotdot && - !isDeclarator(&t, &tmp, TOKreserved)) - return FALSE; - if (t->value == TOKassign) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - if (t->value == TOKdotdotdot) - { - t = peek(t); - break; - } - if (t->value == TOKcomma) - { t = peek(t); - continue; - } - break; - } - break; - } - if (t->value != TOKrparen) - return FALSE; - t = peek(t); - *pt = t; - return TRUE; -} - -int Parser::isExpression(Token **pt) -{ - // This is supposed to determine if something is an expression. - // What it actually does is scan until a closing right bracket - // is found. - - Token *t = *pt; - int brnest = 0; - int panest = 0; - - for (;; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brnest++; - continue; - - case TOKrbracket: - if (--brnest >= 0) - continue; - break; - - case TOKlparen: - panest++; - continue; - - case TOKcomma: - if (brnest || panest) - continue; - break; - - case TOKrparen: - if (--panest >= 0) - continue; - break; - - case TOKslice: - if (brnest) - continue; - break; - - case TOKeof: - return FALSE; - - default: - continue; - } - break; - } - - *pt = t; - return TRUE; -} - -/********************************************** - * Skip over - * instance foo.bar(parameters...) - * Output: - * if (pt), *pt is set to the token following the closing ) - * Returns: - * 1 it's valid instance syntax - * 0 invalid instance syntax - */ - -int Parser::isTemplateInstance(Token *t, Token **pt) -{ - t = peek(t); - if (t->value != TOKdot) - { - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - while (t->value == TOKdot) - { - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - if (t->value != TOKlparen) - goto Lfalse; - - // Skip over the template arguments - while (1) - { - while (1) - { - t = peek(t); - switch (t->value) - { - case TOKlparen: - if (!skipParens(t, &t)) - goto Lfalse; - continue; - case TOKrparen: - break; - case TOKcomma: - break; - case TOKeof: - case TOKsemicolon: - goto Lfalse; - default: - continue; - } - break; - } - - if (t->value != TOKcomma) - break; - } - if (t->value != TOKrparen) - goto Lfalse; - t = peek(t); - if (pt) - *pt = t; - return 1; - -Lfalse: - return 0; -} - -/******************************************* - * Skip parens, brackets. - * Input: - * t is on opening ( - * Output: - * *pt is set to closing token, which is ')' on success - * Returns: - * !=0 successful - * 0 some parsing error - */ - -int Parser::skipParens(Token *t, Token **pt) -{ - int parens = 0; - - while (1) - { - switch (t->value) - { - case TOKlparen: - parens++; - break; - - case TOKrparen: - parens--; - if (parens < 0) - goto Lfalse; - if (parens == 0) - goto Ldone; - break; - - case TOKeof: - case TOKsemicolon: - goto Lfalse; - - default: - break; - } - t = peek(t); - } - - Ldone: - if (*pt) - *pt = t; - return 1; - - Lfalse: - return 0; -} - -/********************************* Expression Parser ***************************/ - -Expression *Parser::parsePrimaryExp() -{ Expression *e; - Type *t; - Identifier *id; - enum TOK save; - Loc loc = this->loc; - - //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); - switch (token.value) - { - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot && peek(&token)->value == TOKlparen) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - e = new ScopeExp(loc, tempinst); - } - else - e = new IdentifierExp(loc, id); - break; - - case TOKdollar: - if (!inBrackets) - error("'$' is valid only inside [] of index or slice"); - e = new DollarExp(loc); - nextToken(); - break; - - case TOKdot: - // Signal global scope '.' operator with "" identifier - e = new IdentifierExp(loc, Id::empty); - break; - - case TOKthis: - e = new ThisExp(loc); - nextToken(); - break; - - case TOKsuper: - e = new SuperExp(loc); - nextToken(); - break; - - case TOKint32v: - e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32); - nextToken(); - break; - - case TOKuns32v: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32); - nextToken(); - break; - - case TOKint64v: - e = new IntegerExp(loc, token.int64value, Type::tint64); - nextToken(); - break; - - case TOKuns64v: - e = new IntegerExp(loc, token.uns64value, Type::tuns64); - nextToken(); - break; - - case TOKfloat32v: - e = new RealExp(loc, token.float80value, Type::tfloat32); - nextToken(); - break; - - case TOKfloat64v: - e = new RealExp(loc, token.float80value, Type::tfloat64); - nextToken(); - break; - - case TOKfloat80v: - e = new RealExp(loc, token.float80value, Type::tfloat80); - nextToken(); - break; - - case TOKimaginary32v: - e = new RealExp(loc, token.float80value, Type::timaginary32); - nextToken(); - break; - - case TOKimaginary64v: - e = new RealExp(loc, token.float80value, Type::timaginary64); - nextToken(); - break; - - case TOKimaginary80v: - e = new RealExp(loc, token.float80value, Type::timaginary80); - nextToken(); - break; - - case TOKnull: - e = new NullExp(loc); - nextToken(); - break; - -#if DMDV2 - case TOKfile: - { char *s = loc.filename ? loc.filename : mod->ident->toChars(); - e = new StringExp(loc, s, strlen(s), 0); - nextToken(); - break; - } - - case TOKline: - e = new IntegerExp(loc, loc.linnum, Type::tint32); - nextToken(); - break; -#endif - - case TOKtrue: - e = new IntegerExp(loc, 1, Type::tbool); - nextToken(); - break; - - case TOKfalse: - e = new IntegerExp(loc, 0, Type::tbool); - nextToken(); - break; - - case TOKcharv: - e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar); - nextToken(); - break; - - case TOKwcharv: - e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar); - nextToken(); - break; - - case TOKdcharv: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar); - nextToken(); - break; - - case TOKstring: - { unsigned char *s; - unsigned len; - unsigned char postfix; - - // cat adjacent strings - s = token.ustring; - len = token.len; - postfix = token.postfix; - while (1) - { - nextToken(); - if (token.value == TOKstring) - { unsigned len1; - unsigned len2; - unsigned char *s2; - - if (token.postfix) - { if (token.postfix != postfix) - error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix); - postfix = token.postfix; - } - - len1 = len; - len2 = token.len; - len = len1 + len2; - s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char)); - memcpy(s2, s, len1 * sizeof(unsigned char)); - memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char)); - s = s2; - } - else - break; - } - e = new StringExp(loc, s, len, postfix); - break; - } - - 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()); - goto Lerr; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - break; - - case TOKtypeof: - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - t = new TypeTypeof(loc, exp); - e = new TypeExp(loc, t); - break; - } - - case TOKtypeid: - { Type *t; - - nextToken(); - check(TOKlparen, "typeid"); - t = parseBasicType(); - t = parseDeclarator(t,NULL); // ( type ) - check(TOKrparen); - e = new TypeidExp(loc, t); - break; - } - -#if DMDV2 - case TOKtraits: - { /* __traits(identifier, args...) - */ - Identifier *ident; - Objects *args = NULL; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("__traits(identifier, args...) expected"); - goto Lerr; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma) - args = parseTemplateArgumentList2(); // __traits(identifier, args...) - else - check(TOKrparen); // __traits(identifier) - - e = new TraitsExp(loc, ident, args); - break; - } -#endif - - case TOKis: - { Type *targ; - Identifier *ident = NULL; - Type *tspec = NULL; - enum TOK tok = TOKreserved; - enum TOK tok2 = TOKreserved; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - targ = parseBasicType(); - targ = parseDeclarator(targ, &ident); - if (token.value == TOKcolon || token.value == TOKequal) - { - tok = token.value; - nextToken(); - if (tok == TOKequal && - (token.value == TOKtypedef || - token.value == TOKstruct || - token.value == TOKunion || - token.value == TOKclass || - token.value == TOKsuper || - token.value == TOKenum || - token.value == TOKinterface || -#if DMDV2 - token.value == TOKconst && peek(&token)->value == TOKrparen || - token.value == TOKinvariant && peek(&token)->value == TOKrparen || - token.value == TOKimmutable && peek(&token)->value == TOKrparen || - token.value == TOKshared && peek(&token)->value == TOKrparen || -#endif - token.value == TOKfunction || - token.value == TOKdelegate || - token.value == TOKreturn)) - { - tok2 = token.value; - nextToken(); - } - else - { - tspec = parseBasicType(); - tspec = parseDeclarator(tspec, NULL); - } - } - check(TOKrparen); - } - else - { error("(type identifier : specialization) expected following is"); - goto Lerr; - } - e = new IsExp(loc, targ, ident, tok, tspec, tok2); - break; - } - - case TOKassert: - { Expression *msg = NULL; - - nextToken(); - check(TOKlparen, "assert"); - e = parseAssignExp(); - if (token.value == TOKcomma) - { nextToken(); - msg = parseAssignExp(); - } - check(TOKrparen); - e = new AssertExp(loc, e, msg); - break; - } - - case TOKmixin: - { - nextToken(); - check(TOKlparen, "mixin"); - e = parseAssignExp(); - check(TOKrparen); - e = new CompileExp(loc, e); - break; - } - - case TOKimport: - { - nextToken(); - check(TOKlparen, "import"); - e = parseAssignExp(); - check(TOKrparen); - e = new FileExp(loc, e); - break; - } - - case TOKlparen: - if (peekPastParen(&token)->value == TOKlcurly) - { // (arguments) { statements... } - save = TOKdelegate; - goto case_delegate; - } - // ( expression ) - nextToken(); - e = parseExpression(); - check(loc, TOKrparen); - break; - - case TOKlbracket: - { /* Parse array literals and associative array literals: - * [ value, value, value ... ] - * [ key:value, key:value, key:value ... ] - */ - Expressions *values = new Expressions(); - Expressions *keys = NULL; - - nextToken(); - if (token.value != TOKrbracket) - { - while (token.value != TOKeof) - { - Expression *e = parseAssignExp(); - if (token.value == TOKcolon && (keys || values->dim == 0)) - { nextToken(); - if (!keys) - keys = new Expressions(); - keys->push(e); - e = parseAssignExp(); - } - else if (keys) - { error("'key:value' expected for associative array literal"); - delete keys; - keys = NULL; - } - values->push(e); - if (token.value == TOKrbracket) - break; - check(TOKcomma); - } - } - check(TOKrbracket); - - if (keys) - e = new AssocArrayLiteralExp(loc, keys, values); - else - e = new ArrayLiteralExp(loc, values); - break; - } - - case TOKlcurly: - // { statements... } - save = TOKdelegate; - goto case_delegate; - - case TOKfunction: - case TOKdelegate: - save = token.value; - nextToken(); - case_delegate: - { - /* function type(parameters) { body } - * delegate type(parameters) { body } - */ - Arguments *arguments; - int varargs; - FuncLiteralDeclaration *fd; - Type *t; - - if (token.value == TOKlcurly) - { - t = NULL; - varargs = 0; - arguments = new Arguments(); - } - else - { - if (token.value == TOKlparen) - t = NULL; - else - { - t = parseBasicType(); - t = parseBasicType2(t); // function return type - } - arguments = parseParameters(&varargs); - } - t = new TypeFunction(arguments, t, varargs, linkage); - fd = new FuncLiteralDeclaration(loc, 0, t, save, NULL); - parseContracts(fd); - e = new FuncExp(loc, fd); - break; - } - - default: - error("expression expected, not '%s'", token.toChars()); - Lerr: - // Anything for e, as long as it's not NULL - e = new IntegerExp(loc, 0, Type::tint32); - nextToken(); - break; - } - return parsePostExp(e); -} - -Expression *Parser::parsePostExp(Expression *e) -{ - Loc loc; - - while (1) - { - loc = this->loc; - switch (token.value) - { - case TOKdot: - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (token.value == TOKnot && peek(&token)->value == TOKlparen) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - e = new DotTemplateInstanceExp(loc, e, tempinst); - } - else - e = new DotIdExp(loc, e, id); - continue; - } - else if (token.value == TOKnew) - { - e = parseNewExp(e); - continue; - } - else - error("identifier expected following '.', not '%s'", token.toChars()); - break; - - case TOKplusplus: - e = new PostExp(TOKplusplus, loc, e); - break; - - case TOKminusminus: - e = new PostExp(TOKminusminus, loc, e); - break; - - case TOKlparen: - e = new CallExp(loc, e, parseArguments()); - continue; - - case TOKlbracket: - { // array dereferences: - // array[index] - // array[] - // array[lwr .. upr] - Expression *index; - Expression *upr; - - inBrackets++; - nextToken(); - if (token.value == TOKrbracket) - { // array[] - e = new SliceExp(loc, e, NULL, NULL); - nextToken(); - } - else - { - index = parseAssignExp(); - if (token.value == TOKslice) - { // array[lwr .. upr] - nextToken(); - upr = parseAssignExp(); - e = new SliceExp(loc, e, index, upr); - } - else - { // array[index, i2, i3, i4, ...] - Expressions *arguments = new Expressions(); - arguments->push(index); - if (token.value == TOKcomma) - { - nextToken(); - while (1) - { Expression *arg; - - arg = parseAssignExp(); - arguments->push(arg); - if (token.value == TOKrbracket) - break; - check(TOKcomma); - } - } - e = new ArrayExp(loc, e, arguments); - } - check(TOKrbracket); - inBrackets--; - } - continue; - } - - default: - return e; - } - nextToken(); - } -} - -Expression *Parser::parseUnaryExp() -{ Expression *e; - Loc loc = this->loc; - - switch (token.value) - { - case TOKand: - nextToken(); - e = parseUnaryExp(); - e = new AddrExp(loc, e); - break; - - case TOKplusplus: - nextToken(); - e = parseUnaryExp(); - e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - break; - - case TOKminusminus: - nextToken(); - e = parseUnaryExp(); - e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - break; - - case TOKmul: - nextToken(); - e = parseUnaryExp(); - e = new PtrExp(loc, e); - break; - - case TOKmin: - nextToken(); - e = parseUnaryExp(); - e = new NegExp(loc, e); - break; - - case TOKadd: - nextToken(); - e = parseUnaryExp(); - e = new UAddExp(loc, e); - break; - - case TOKnot: - nextToken(); - e = parseUnaryExp(); - e = new NotExp(loc, e); - break; - - case TOKtilde: - nextToken(); - e = parseUnaryExp(); - e = new ComExp(loc, e); - break; - - case TOKdelete: - nextToken(); - e = parseUnaryExp(); - e = new DeleteExp(loc, e); - break; - - case TOKnew: - e = parseNewExp(NULL); - break; - - case TOKcast: // cast(type) expression - { Type *t; - - nextToken(); - check(TOKlparen); - t = parseBasicType(); - t = parseDeclarator(t,NULL); // ( type ) - check(TOKrparen); - - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - break; - } - - case TOKlparen: - { Token *tk; - - tk = peek(&token); -#if CCASTSYNTAX - // If cast - if (isDeclaration(tk, 0, TOKrparen, &tk)) - { - tk = peek(tk); // skip over right parenthesis - switch (tk->value) - { - case TOKnot: - tk = peek(tk); - if (tk->value == TOKis) // !is - break; - case TOKdot: - case TOKplusplus: - case TOKminusminus: - case TOKdelete: - case TOKnew: - case TOKlparen: - case TOKidentifier: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: -#if 0 - case TOKtilde: - case TOKand: - case TOKmul: - case TOKmin: - case TOKadd: -#endif - case TOKfunction: - case TOKdelegate: - case TOKtypeof: -#if DMDV2 - case TOKfile: - case TOKline: -#endif - CASE_BASIC_TYPES: // (type)int.size - { // (type) una_exp - Type *t; - - nextToken(); - t = parseBasicType(); - t = parseDeclarator(t,NULL); - check(TOKrparen); - - // if .identifier - if (token.value == TOKdot) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following (type)."); - return NULL; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - e = parsePostExp(e); - } - else - { - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - error("C style cast illegal, use %s", e->toChars()); - } - return e; - } - } - } -#endif - e = parsePrimaryExp(); - break; - } - default: - e = parsePrimaryExp(); - break; - } - assert(e); - return e; -} - -Expression *Parser::parseMulExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseUnaryExp(); - while (1) - { - switch (token.value) - { - case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; - case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; - case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseAddExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseMulExp(); - while (1) - { - switch (token.value) - { - case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue; - case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue; - case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseShiftExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAddExp(); - while (1) - { - switch (token.value) - { - case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue; - case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue; - case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseRelExp() -{ Expression *e; - Expression *e2; - enum TOK op; - Loc loc = this->loc; - - e = parseShiftExp(); - while (1) - { - switch (token.value) - { - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - op = token.value; - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - continue; - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseEqualExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseRelExp(); - while (1) - { enum TOK value = token.value; - - switch (value) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseRelExp(); - e = new EqualExp(value, loc, e, e2); - continue; - - case TOKidentity: - error("'===' is no longer legal, use 'is' instead"); - goto L1; - - case TOKnotidentity: - error("'!==' is no longer legal, use '!is' instead"); - goto L1; - - case TOKis: - value = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); - if (t->value != TOKis) - break; - nextToken(); - value = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseRelExp(); - e = new IdentityExp(value, loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseCmpExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseShiftExp(); - enum TOK op = token.value; - - switch (op) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseShiftExp(); - e = new EqualExp(op, loc, e, e2); - break; - - case TOKis: - op = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); - if (t->value != TOKis) - break; - nextToken(); - op = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseShiftExp(); - e = new IdentityExp(op, loc, e, e2); - break; - - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - break; - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - break; - - default: - break; - } - return e; -} - -Expression *Parser::parseAndExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - if (global.params.Dversion == 1) - { - e = parseEqualExp(); - while (token.value == TOKand) - { - nextToken(); - e2 = parseEqualExp(); - e = new AndExp(loc,e,e2); - loc = this->loc; - } - } - else - { - e = parseCmpExp(); - while (token.value == TOKand) - { - nextToken(); - e2 = parseCmpExp(); - e = new AndExp(loc,e,e2); - loc = this->loc; - } - } - return e; -} - -Expression *Parser::parseXorExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAndExp(); - while (token.value == TOKxor) - { - nextToken(); - e2 = parseAndExp(); - e = new XorExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseXorExp(); - while (token.value == TOKor) - { - nextToken(); - e2 = parseXorExp(); - e = new OrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseAndAndExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseOrExp(); - while (token.value == TOKandand) - { - nextToken(); - e2 = parseOrExp(); - e = new AndAndExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrOrExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAndAndExp(); - while (token.value == TOKoror) - { - nextToken(); - e2 = parseAndAndExp(); - e = new OrOrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseCondExp() -{ Expression *e; - Expression *e1; - Expression *e2; - Loc loc = this->loc; - - e = parseOrOrExp(); - if (token.value == TOKquestion) - { - nextToken(); - e1 = parseExpression(); - check(TOKcolon); - e2 = parseCondExp(); - e = new CondExp(loc, e, e1, e2); - } - return e; -} - -Expression *Parser::parseAssignExp() -{ Expression *e; - Expression *e2; - Loc loc; - - e = parseCondExp(); - while (1) - { - loc = this->loc; - switch (token.value) - { -#define X(tok,ector) \ - case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue; - - X(TOKassign, AssignExp); - X(TOKaddass, AddAssignExp); - X(TOKminass, MinAssignExp); - X(TOKmulass, MulAssignExp); - X(TOKdivass, DivAssignExp); - X(TOKmodass, ModAssignExp); - X(TOKandass, AndAssignExp); - X(TOKorass, OrAssignExp); - X(TOKxorass, XorAssignExp); - X(TOKshlass, ShlAssignExp); - X(TOKshrass, ShrAssignExp); - X(TOKushrass, UshrAssignExp); - X(TOKcatass, CatAssignExp); - -#undef X - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseExpression() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - //printf("Parser::parseExpression() loc = %d\n", loc.linnum); - e = parseAssignExp(); - while (token.value == TOKcomma) - { - nextToken(); - e2 = parseAssignExp(); - e = new CommaExp(loc, e, e2); - loc = this->loc; - } - return e; -} - - -/************************* - * Collect argument list. - * Assume current token is '(' or '['. - */ - -Expressions *Parser::parseArguments() -{ // function call - Expressions *arguments; - Expression *arg; - enum TOK endtok; - - arguments = new Expressions(); - if (token.value == TOKlbracket) - endtok = TOKrbracket; - else - endtok = TOKrparen; - - { - nextToken(); - if (token.value != endtok) - { - while (1) - { - arg = parseAssignExp(); - arguments->push(arg); - if (token.value == endtok) - break; - check(TOKcomma); - } - } - check(endtok); - } - return arguments; -} - -/******************************************* - */ - -Expression *Parser::parseNewExp(Expression *thisexp) -{ Type *t; - Expressions *newargs; - Expressions *arguments = NULL; - Expression *e; - Loc loc = this->loc; - - nextToken(); - newargs = NULL; - if (token.value == TOKlparen) - { - newargs = parseArguments(); - } - - // An anonymous nested class starts with "class" - if (token.value == TOKclass) - { - nextToken(); - if (token.value == TOKlparen) - arguments = parseArguments(); - - BaseClasses *baseclasses = NULL; - if (token.value != TOKlcurly) - baseclasses = parseBaseClasses(); - - Identifier *id = NULL; - ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses); - - if (token.value != TOKlcurly) - { error("{ members } expected for anonymous class"); - cd->members = NULL; - } - else - { - nextToken(); - Array *decl = parseDeclDefs(0); - if (token.value != TOKrcurly) - error("class member expected"); - nextToken(); - cd->members = decl; - } - - e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments); - - return e; - } - -#if LTORARRAYDECL - t = parseBasicType(); - t = parseBasicType2(t); - if (t->ty == Taarray) - { - Type *index = ((TypeAArray *)t)->index; - - Expression *e = index->toExpression(); - if (e) - { arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(t->next); - } - else - { - error("need size of rightmost array, not type %s", index->toChars()); - return new NullExp(loc); - } - } - else if (t->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)t; - Expression *e = tsa->dim; - - arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(t->next); - } - else if (token.value == TOKlparen) - { - arguments = parseArguments(); - } -#else - t = parseBasicType(); - while (token.value == TOKmul) - { t = new TypePointer(t); - nextToken(); - } - if (token.value == TOKlbracket) - { - Expression *e; - - nextToken(); - e = parseAssignExp(); - arguments = new Array(); - arguments->push(e); - check(TOKrbracket); - t = parseDeclarator(t, NULL); - t = new TypeDArray(t); - } - else if (token.value == TOKlparen) - arguments = parseArguments(); -#endif - e = new NewExp(loc, thisexp, newargs, t, arguments); - return e; -} - -/********************************************** - */ - -void Parser::addComment(Dsymbol *s, unsigned char *blockComment) -{ - s->addComment(combineComments(blockComment, token.lineComment)); - token.lineComment = NULL; -} - - -/********************************* ***************************/ - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +// This is the D parser + +#include <stdio.h> +#include <assert.h> + +#include "rmem.h" +#include "lexer.h" +#include "parse.h" +#include "init.h" +#include "attrib.h" +#include "cond.h" +#include "mtype.h" +#include "template.h" +#include "staticassert.h" +#include "expression.h" +#include "statement.h" +#include "module.h" +#include "dsymbol.h" +#include "import.h" +#include "declaration.h" +#include "aggregate.h" +#include "enum.h" +#include "id.h" +#include "version.h" +#if DMDV2 +#include "aliasthis.h" +#endif + +// How multiple declarations are parsed. +// If 1, treat as C. +// If 0, treat: +// int *p, i; +// as: +// int* p; +// int* i; +#define CDECLSYNTAX 0 + +// Support C cast syntax: +// (type)(expression) +#define CCASTSYNTAX 1 + +// Support postfix C array declarations, such as +// int a[3][4]; +#define CARRAYDECL 1 + +// Support left-to-right array declarations +#define LTORARRAYDECL 1 + + +Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment) + : Lexer(module, base, 0, length, doDocComment, 0) +{ + //printf("Parser::Parser()\n"); + md = NULL; + linkage = LINKd; + endloc = 0; + inBrackets = 0; + //nextToken(); // start up the scanner +} + +Array *Parser::parseModule() +{ + Array *decldefs; + + // ModuleDeclation leads off + if (token.value == TOKmodule) + { + unsigned char *comment = token.blockComment; + + nextToken(); +#if DMDV2 + if (token.value == TOKlparen) + { + nextToken(); + if (token.value != TOKidentifier) + { error("module (system) identifier expected"); + goto Lerr; + } + Identifier *id = token.ident; + + if (id == Id::system) + safe = TRUE; + else + error("(safe) expected, not %s", id->toChars()); + nextToken(); + check(TOKrparen); + } +#endif + + if (token.value != TOKidentifier) + { error("Identifier expected following module"); + goto Lerr; + } + else + { + Array *a = NULL; + Identifier *id; + + id = token.ident; + while (nextToken() == TOKdot) + { + if (!a) + a = new Array(); + a->push(id); + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following package"); + goto Lerr; + } + id = token.ident; + } + + md = new ModuleDeclaration(a, id); + + if (token.value != TOKsemicolon) + error("';' expected following module declaration instead of %s", token.toChars()); + nextToken(); + addComment(mod, comment); + } + } + + decldefs = parseDeclDefs(0); + if (token.value != TOKeof) + { error("unrecognized declaration"); + goto Lerr; + } + return decldefs; + +Lerr: + while (token.value != TOKsemicolon && token.value != TOKeof) + nextToken(); + nextToken(); + return new Array(); +} + +Array *Parser::parseDeclDefs(int once) +{ Dsymbol *s; + Array *decldefs; + Array *a; + Array *aelse; + enum PROT prot; + unsigned stc; + Condition *condition; + unsigned char *comment; + + //printf("Parser::parseDeclDefs()\n"); + decldefs = new Array(); + do + { + comment = token.blockComment; + switch (token.value) + { + case TOKenum: + s = parseEnum(); + break; + + case TOKstruct: + case TOKunion: + case TOKclass: + case TOKinterface: + s = parseAggregate(); + break; + + case TOKimport: + s = parseImport(decldefs, 0); + break; + + case TOKtemplate: + s = (Dsymbol *)parseTemplateDeclaration(); + break; + + case TOKmixin: + { Loc loc = this->loc; + if (peek(&token)->value == TOKlparen) + { // mixin(string) + nextToken(); + check(TOKlparen, "mixin"); + Expression *e = parseAssignExp(); + check(TOKrparen); + check(TOKsemicolon); + s = new CompileDeclaration(loc, e); + break; + } + s = parseMixin(); + break; + } + + CASE_BASIC_TYPES: + case TOKalias: + case TOKtypedef: + case TOKidentifier: + case TOKtypeof: + case TOKdot: + Ldeclaration: + a = parseDeclarations(); + decldefs->append(a); + continue; + + case TOKthis: + s = parseCtor(); + break; + + case TOKtilde: + s = parseDtor(); + break; + + case TOKinvariant: +#if 1 + s = parseInvariant(); +#else + if (peek(&token)->value == TOKlcurly) + s = parseInvariant(); + else + { + stc = STCinvariant; + goto Lstc; + } +#endif + break; + + case TOKunittest: + s = parseUnitTest(); + break; + + case TOKnew: + s = parseNew(); + break; + + case TOKdelete: + s = parseDelete(); + break; + + case TOKeof: + case TOKrcurly: + return decldefs; + + case TOKstatic: + nextToken(); + if (token.value == TOKthis) + s = parseStaticCtor(); + else if (token.value == TOKtilde) + s = parseStaticDtor(); + else if (token.value == TOKassert) + s = parseStaticAssert(); + else if (token.value == TOKif) + { condition = parseStaticIfCondition(); + a = parseBlock(); + aelse = NULL; + if (token.value == TOKelse) + { nextToken(); + aelse = parseBlock(); + } + s = new StaticIfDeclaration(condition, a, aelse); + break; + } + else if (token.value == TOKimport) + { + s = parseImport(decldefs, 1); + } + else + { stc = STCstatic; + goto Lstc2; + } + break; + + case TOKconst: stc = STCconst; goto Lstc; + case TOKfinal: stc = STCfinal; goto Lstc; + case TOKauto: stc = STCauto; goto Lstc; + case TOKscope: stc = STCscope; goto Lstc; + case TOKoverride: stc = STCoverride; goto Lstc; + case TOKabstract: stc = STCabstract; goto Lstc; + case TOKsynchronized: stc = STCsynchronized; goto Lstc; + case TOKdeprecated: stc = STCdeprecated; goto Lstc; +#if DMDV2 + case TOKnothrow: stc = STCnothrow; goto Lstc; + case TOKpure: stc = STCpure; goto Lstc; + case TOKref: stc = STCref; goto Lstc; + case TOKtls: stc = STCtls; goto Lstc; + //case TOKmanifest: stc = STCmanifest; goto Lstc; +#endif + + Lstc: + nextToken(); + Lstc2: + switch (token.value) + { + case TOKconst: stc |= STCconst; goto Lstc; + case TOKfinal: stc |= STCfinal; goto Lstc; + case TOKauto: stc |= STCauto; goto Lstc; + case TOKscope: stc |= STCscope; goto Lstc; + case TOKoverride: stc |= STCoverride; goto Lstc; + case TOKabstract: stc |= STCabstract; goto Lstc; + case TOKsynchronized: stc |= STCsynchronized; goto Lstc; + case TOKdeprecated: stc |= STCdeprecated; goto Lstc; + //case TOKinvariant: stc |= STCinvariant; goto Lstc; + default: + break; + } + + /* Look for auto initializers: + * storage_class identifier = initializer; + */ + if (token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + while (1) + { + Identifier *ident = token.ident; + nextToken(); + nextToken(); + Initializer *init = parseInitializer(); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = stc; + s = v; + if (token.value == TOKsemicolon) + { + nextToken(); + } + else if (token.value == TOKcomma) + { + nextToken(); + if (token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + decldefs->push(s); + addComment(s, comment); + continue; + } + else + error("Identifier expected following comma"); + } + else + error("semicolon expected following auto declaration, not '%s'", token.toChars()); + break; + } + } + else + { a = parseBlock(); + s = new StorageClassDeclaration(stc, a); + } + break; + + case TOKextern: + if (peek(&token)->value != TOKlparen) + { stc = STCextern; + goto Lstc; + } + { + enum LINK linksave = linkage; + linkage = parseLinkage(); + a = parseBlock(); + s = new LinkDeclaration(linkage, a); + linkage = linksave; + break; + } + case TOKprivate: prot = PROTprivate; goto Lprot; + case TOKpackage: prot = PROTpackage; goto Lprot; + case TOKprotected: prot = PROTprotected; goto Lprot; + case TOKpublic: prot = PROTpublic; goto Lprot; + case TOKexport: prot = PROTexport; goto Lprot; + + Lprot: + nextToken(); + switch (token.value) + { + case TOKprivate: + case TOKpackage: + case TOKprotected: + case TOKpublic: + case TOKexport: + error("redundant protection attribute"); + break; + } + a = parseBlock(); + s = new ProtDeclaration(prot, a); + break; + + case TOKalign: + { unsigned n; + + // LDC better align code locations + Loc alignloc = loc; + + s = NULL; + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + if (token.value == TOKint32v) + n = (unsigned)token.uns64value; + else + { error("integer expected, not %s", token.toChars()); + n = 1; + } + nextToken(); + check(TOKrparen); + } + else + n = global.structalign; // default + + a = parseBlock(); + s = new AlignDeclaration(alignloc, n, a); + break; + } + + case TOKpragma: + { Identifier *ident; + Expressions *args = NULL; + + nextToken(); + check(TOKlparen); + if (token.value != TOKidentifier) + { error("pragma(identifier expected"); + goto Lerror; + } + ident = token.ident; + nextToken(); + if (token.value == TOKcomma && peekNext() != TOKrparen) + args = parseArguments(); // pragma(identifier, args...) + else + check(TOKrparen); // pragma(identifier) + + if (token.value == TOKsemicolon) + a = NULL; + else + a = parseBlock(); + s = new PragmaDeclaration(loc, ident, args, a); + break; + } + + case TOKdebug: + nextToken(); + if (token.value == TOKassign) + { + nextToken(); + if (token.value == TOKidentifier) + s = new DebugSymbol(loc, token.ident); + else if (token.value == TOKint32v) + s = new DebugSymbol(loc, (unsigned)token.uns64value); + else + { error("identifier or integer expected, not %s", token.toChars()); + s = NULL; + } + nextToken(); + if (token.value != TOKsemicolon) + error("semicolon expected"); + nextToken(); + break; + } + + condition = parseDebugCondition(); + goto Lcondition; + + case TOKversion: + nextToken(); + if (token.value == TOKassign) + { + nextToken(); + if (token.value == TOKidentifier) + s = new VersionSymbol(loc, token.ident); + else if (token.value == TOKint32v) + s = new VersionSymbol(loc, (unsigned)token.uns64value); + else + { error("identifier or integer expected, not %s", token.toChars()); + s = NULL; + } + nextToken(); + if (token.value != TOKsemicolon) + error("semicolon expected"); + nextToken(); + break; + } + condition = parseVersionCondition(); + goto Lcondition; + + Lcondition: + a = parseBlock(); + aelse = NULL; + if (token.value == TOKelse) + { nextToken(); + aelse = parseBlock(); + } + s = new ConditionalDeclaration(condition, a, aelse); + break; + + case TOKsemicolon: // empty declaration + nextToken(); + continue; + + default: + error("Declaration expected, not '%s'",token.toChars()); + Lerror: + while (token.value != TOKsemicolon && token.value != TOKeof) + nextToken(); + nextToken(); + s = NULL; + continue; + } + if (s) + { decldefs->push(s); + addComment(s, comment); + } + } while (!once); + return decldefs; +} + + +/******************************************** + * Parse declarations after an align, protection, or extern decl. + */ + +Array *Parser::parseBlock() +{ + Array *a = NULL; + Dsymbol *s; + + //printf("parseBlock()\n"); + switch (token.value) + { + case TOKsemicolon: + error("declaration expected following attribute, not ';'"); + nextToken(); + break; + + case TOKeof: + error("declaration expected following attribute, not EOF"); + break; + + case TOKlcurly: + nextToken(); + a = parseDeclDefs(0); + if (token.value != TOKrcurly) + { /* { */ + error("matching '}' expected, not %s", token.toChars()); + } + else + nextToken(); + break; + + case TOKcolon: + nextToken(); +#if 0 + a = NULL; +#else + a = parseDeclDefs(0); // grab declarations up to closing curly bracket +#endif + break; + + default: + a = parseDeclDefs(1); + break; + } + return a; +} + +/********************************** + * Parse a static assertion. + */ + +StaticAssert *Parser::parseStaticAssert() +{ + Loc loc = this->loc; + Expression *exp; + Expression *msg = NULL; + + //printf("parseStaticAssert()\n"); + nextToken(); + check(TOKlparen); + exp = parseAssignExp(); + if (token.value == TOKcomma) + { nextToken(); + msg = parseAssignExp(); + } + check(TOKrparen); + check(TOKsemicolon); + return new StaticAssert(loc, exp, msg); +} + +/*********************************** + * Parse typeof(expression). + * Current token is on the 'typeof'. + */ + +#if DMDV2 +TypeQualified *Parser::parseTypeof() +{ TypeQualified *t; + Loc loc = this->loc; + + nextToken(); + check(TOKlparen); + if (token.value == TOKreturn) // typeof(return) + { + nextToken(); + t = new TypeReturn(loc); + } + else + { Expression *exp = parseExpression(); // typeof(expression) + t = new TypeTypeof(loc, exp); + } + check(TOKrparen); + return t; +} +#endif + +/*********************************** + * Parse extern (linkage) + * The parser is on the 'extern' token. + */ + +enum LINK Parser::parseLinkage() +{ + enum LINK link = LINKdefault; + nextToken(); + assert(token.value == TOKlparen); + nextToken(); + if (token.value == TOKidentifier) + { Identifier *id = token.ident; + + nextToken(); + if (id == Id::Windows) + link = LINKwindows; + else if (id == Id::Pascal) + link = LINKpascal; + else if (id == Id::D) + link = LINKd; + else if (id == Id::C) + { + link = LINKc; + if (token.value == TOKplusplus) + { link = LINKcpp; + nextToken(); + } + } + else if (id == Id::System) + { + // LDC we configure target at runtime + if (global.params.os == OSWindows) + link = LINKwindows; + else + link = LINKc; + } + else + { + error("valid linkage identifiers are D, C, C++, Pascal, Windows, System"); + link = LINKd; + } + } + else + { + link = LINKd; // default + } + check(TOKrparen); + return link; +} + +/************************************** + * Parse a debug conditional + */ + +Condition *Parser::parseDebugCondition() +{ + Condition *c; + + if (token.value == TOKlparen) + { + nextToken(); + unsigned level = 1; + Identifier *id = NULL; + + if (token.value == TOKidentifier) + id = token.ident; + else if (token.value == TOKint32v) + level = (unsigned)token.uns64value; + else + error("identifier or integer expected, not %s", token.toChars()); + nextToken(); + check(TOKrparen); + c = new DebugCondition(mod, level, id); + } + else + c = new DebugCondition(mod, 1, NULL); + return c; + +} + +/************************************** + * Parse a version conditional + */ + +Condition *Parser::parseVersionCondition() +{ + Condition *c; + unsigned level = 1; + Identifier *id = NULL; + + if (token.value == TOKlparen) + { + nextToken(); + if (token.value == TOKidentifier) + id = token.ident; + else if (token.value == TOKint32v) + level = (unsigned)token.uns64value; +#if DMDV2 + /* Allow: + * version (unittest) + * even though unittest is a keyword + */ + else if (token.value == TOKunittest) + id = Lexer::idPool(Token::toChars(TOKunittest)); +#endif + else + error("identifier or integer expected, not %s", token.toChars()); + nextToken(); + check(TOKrparen); + + } + else + error("(condition) expected following version"); + c = new VersionCondition(mod, level, id); + return c; + +} + +/*********************************************** + * static if (expression) + * body + * else + * body + */ + +Condition *Parser::parseStaticIfCondition() +{ Expression *exp; + Condition *condition; + Array *aif; + Array *aelse; + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + exp = parseAssignExp(); + check(TOKrparen); + } + else + { error("(expression) expected following static if"); + exp = NULL; + } + condition = new StaticIfCondition(loc, exp); + return condition; +} + + +/***************************************** + * Parse a constructor definition: + * this(arguments) { body } + * Current token is 'this'. + */ + +CtorDeclaration *Parser::parseCtor() +{ + CtorDeclaration *f; + Arguments *arguments; + int varargs; + Loc loc = this->loc; + + nextToken(); + arguments = parseParameters(&varargs); + f = new CtorDeclaration(loc, 0, arguments, varargs); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a destructor definition: + * ~this() { body } + * Current token is '~'. + */ + +DtorDeclaration *Parser::parseDtor() +{ + DtorDeclaration *f; + Loc loc = this->loc; + + nextToken(); + check(TOKthis); + check(TOKlparen); + check(TOKrparen); + + f = new DtorDeclaration(loc, 0); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a static constructor definition: + * static this() { body } + * Current token is 'this'. + */ + +StaticCtorDeclaration *Parser::parseStaticCtor() +{ + StaticCtorDeclaration *f; + Loc loc = this->loc; + + nextToken(); + check(TOKlparen); + check(TOKrparen); + + f = new StaticCtorDeclaration(loc, 0); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a static destructor definition: + * static ~this() { body } + * Current token is '~'. + */ + +StaticDtorDeclaration *Parser::parseStaticDtor() +{ + StaticDtorDeclaration *f; + Loc loc = this->loc; + + nextToken(); + check(TOKthis); + check(TOKlparen); + check(TOKrparen); + + f = new StaticDtorDeclaration(loc, 0); + parseContracts(f); + return f; +} + +/***************************************** + * Parse an invariant definition: + * invariant() { body } + * Current token is 'invariant'. + */ + +InvariantDeclaration *Parser::parseInvariant() +{ + InvariantDeclaration *f; + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlparen) // optional () + { + nextToken(); + check(TOKrparen); + } + + f = new InvariantDeclaration(loc, 0); + f->fbody = parseStatement(PScurly); + return f; +} + +/***************************************** + * Parse a unittest definition: + * unittest { body } + * Current token is 'unittest'. + */ + +UnitTestDeclaration *Parser::parseUnitTest() +{ + UnitTestDeclaration *f; + Statement *body; + Loc loc = this->loc; + + nextToken(); + + body = parseStatement(PScurly); + + f = new UnitTestDeclaration(loc, this->loc); + f->fbody = body; + return f; +} + +/***************************************** + * Parse a new definition: + * new(arguments) { body } + * Current token is 'new'. + */ + +NewDeclaration *Parser::parseNew() +{ + NewDeclaration *f; + Arguments *arguments; + int varargs; + Loc loc = this->loc; + + nextToken(); + arguments = parseParameters(&varargs); + f = new NewDeclaration(loc, 0, arguments, varargs); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a delete definition: + * delete(arguments) { body } + * Current token is 'delete'. + */ + +DeleteDeclaration *Parser::parseDelete() +{ + DeleteDeclaration *f; + Arguments *arguments; + int varargs; + Loc loc = this->loc; + + nextToken(); + arguments = parseParameters(&varargs); + if (varargs) + error("... not allowed in delete function parameter list"); + f = new DeleteDeclaration(loc, 0, arguments); + parseContracts(f); + return f; +} + +/********************************************** + * Parse parameter list. + */ + +Arguments *Parser::parseParameters(int *pvarargs) +{ + Arguments *arguments = new Arguments(); + int varargs = 0; + int hasdefault = 0; + + check(TOKlparen); + while (1) + { Type *tb; + Identifier *ai = NULL; + Type *at; + Argument *a; + unsigned storageClass; + Expression *ae; + + storageClass = STCin; // parameter is "in" by default + switch (token.value) + { + case TOKrparen: + break; + + case TOKdotdotdot: + varargs = 1; + nextToken(); + break; + + case TOKin: + storageClass = STCin; + nextToken(); + goto L1; + + case TOKout: + storageClass = STCout; + nextToken(); + goto L1; + + case TOKinout: + case TOKref: + storageClass = STCref; + nextToken(); + goto L1; + + case TOKlazy: + storageClass = STClazy; + nextToken(); + goto L1; + + default: + L1: + tb = parseBasicType(); + at = parseDeclarator(tb, &ai); + ae = NULL; + if (token.value == TOKassign) // = defaultArg + { nextToken(); + ae = parseAssignExp(); + hasdefault = 1; + } + else + { if (hasdefault) + error("default argument expected for %s", + ai ? ai->toChars() : at->toChars()); + } + if (token.value == TOKdotdotdot) + { /* This is: + * at ai ... + */ + + if (storageClass & (STCout | STCref)) + error("variadic argument cannot be out or ref"); + varargs = 2; + a = new Argument(storageClass, at, ai, ae); + arguments->push(a); + nextToken(); + break; + } + a = new Argument(storageClass, at, ai, ae); + arguments->push(a); + if (token.value == TOKcomma) + { nextToken(); + continue; + } + break; + } + break; + } + check(TOKrparen); + *pvarargs = varargs; + return arguments; +} + + +/************************************* + */ + +EnumDeclaration *Parser::parseEnum() +{ EnumDeclaration *e; + Identifier *id; + Type *memtype; + Loc loc = this->loc; + + //printf("Parser::parseEnum()\n"); + nextToken(); + if (token.value == TOKidentifier) + { id = token.ident; + nextToken(); + } + else + id = NULL; + + if (token.value == TOKcolon) + { + nextToken(); + memtype = parseBasicType(); + } + else + memtype = NULL; + + e = new EnumDeclaration(loc, id, memtype); + if (token.value == TOKsemicolon && id) + nextToken(); + else if (token.value == TOKlcurly) + { + //printf("enum definition\n"); + e->members = new Array(); + nextToken(); + unsigned char *comment = token.blockComment; + while (token.value != TOKrcurly) + { + if (token.value == TOKidentifier) + { EnumMember *em; + Expression *value; + Identifier *ident; + + loc = this->loc; + ident = token.ident; + value = NULL; + nextToken(); + if (token.value == TOKassign) + { + nextToken(); + value = parseAssignExp(); + } + em = new EnumMember(loc, ident, value); + e->members->push(em); + if (token.value == TOKrcurly) + ; + else + { addComment(em, comment); + comment = NULL; + check(TOKcomma); + } + addComment(em, comment); + comment = token.blockComment; + } + else + { error("enum member expected"); + nextToken(); + } + } + nextToken(); + } + else + error("enum declaration is invalid"); + + //printf("-parseEnum() %s\n", e->toChars()); + return e; +} + +/******************************** + * Parse struct, union, interface, class. + */ + +Dsymbol *Parser::parseAggregate() +{ AggregateDeclaration *a = NULL; + int anon = 0; + enum TOK tok; + Identifier *id; + TemplateParameters *tpl = NULL; + + //printf("Parser::parseAggregate()\n"); + tok = token.value; + nextToken(); + if (token.value != TOKidentifier) + { id = NULL; + } + else + { id = token.ident; + nextToken(); + + if (token.value == TOKlparen) + { // Class template declaration. + + // Gather template parameter list + tpl = parseTemplateParameterList(); + } + } + + Loc loc = this->loc; + switch (tok) + { case TOKclass: + case TOKinterface: + { + if (!id) + error("anonymous classes not allowed"); + + // Collect base class(es) + BaseClasses *baseclasses = NULL; + if (token.value == TOKcolon) + { + nextToken(); + baseclasses = parseBaseClasses(); + + if (token.value != TOKlcurly) + error("members expected"); + } + + if (tok == TOKclass) + a = new ClassDeclaration(loc, id, baseclasses); + else + a = new InterfaceDeclaration(loc, id, baseclasses); + break; + } + + case TOKstruct: + if (id) + a = new StructDeclaration(loc, id); + else + anon = 1; + break; + + case TOKunion: + if (id) + a = new UnionDeclaration(loc, id); + else + anon = 2; + break; + + default: + assert(0); + break; + } + if (a && token.value == TOKsemicolon) + { nextToken(); + } + else if (token.value == TOKlcurly) + { + //printf("aggregate definition\n"); + nextToken(); + Array *decl = parseDeclDefs(0); + if (token.value != TOKrcurly) + error("} expected following member declarations in aggregate"); + nextToken(); + if (anon) + { + /* Anonymous structs/unions are more like attributes. + */ + return new AnonDeclaration(loc, anon - 1, decl); + } + else + a->members = decl; + } + else + { + error("{ } expected following aggregate declaration"); + a = new StructDeclaration(loc, NULL); + } + + if (tpl) + { Array *decldefs; + TemplateDeclaration *tempdecl; + + // Wrap a template around the aggregate declaration + decldefs = new Array(); + decldefs->push(a); + tempdecl = new TemplateDeclaration(loc, id, tpl, NULL, decldefs); + return tempdecl; + } + + return a; +} + +/******************************************* + */ + +BaseClasses *Parser::parseBaseClasses() +{ + enum PROT protection = PROTpublic; + BaseClasses *baseclasses = new BaseClasses(); + + for (; 1; nextToken()) + { + switch (token.value) + { + case TOKidentifier: + break; + case TOKprivate: + protection = PROTprivate; + continue; + case TOKpackage: + protection = PROTpackage; + continue; + case TOKprotected: + protection = PROTprotected; + continue; + case TOKpublic: + protection = PROTpublic; + continue; + default: + error("base classes expected instead of %s", token.toChars()); + return NULL; + } + BaseClass *b = new BaseClass(parseBasicType(), protection); + baseclasses->push(b); + if (token.value != TOKcomma) + break; + protection = PROTpublic; + } + return baseclasses; +} + +/************************************** + * Parse constraint. + * Constraint is of the form: + * if ( ConstraintExpression ) + */ + +#if DMDV2 +Expression *Parser::parseConstraint() +{ Expression *e = NULL; + + if (token.value == TOKif) + { + nextToken(); // skip over 'if' + check(TOKlparen); + e = parseExpression(); + check(TOKrparen); + } + return e; +} +#endif + +/************************************** + * Parse a TemplateDeclaration. + */ + +TemplateDeclaration *Parser::parseTemplateDeclaration() +{ + TemplateDeclaration *tempdecl; + Identifier *id; + TemplateParameters *tpl; + Array *decldefs; + Loc loc = this->loc; + + nextToken(); + if (token.value != TOKidentifier) + { error("TemplateIdentifier expected following template"); + goto Lerr; + } + id = token.ident; + nextToken(); + tpl = parseTemplateParameterList(); + if (!tpl) + goto Lerr; + + if (token.value != TOKlcurly) + { error("members of template declaration expected"); + goto Lerr; + } + else + { + nextToken(); + decldefs = parseDeclDefs(0); + if (token.value != TOKrcurly) + { error("template member expected"); + goto Lerr; + } + nextToken(); + } + + tempdecl = new TemplateDeclaration(loc, id, tpl, NULL, decldefs); + return tempdecl; + +Lerr: + return NULL; +} + +/****************************************** + * Parse template parameter list. + */ + +TemplateParameters *Parser::parseTemplateParameterList() +{ + TemplateParameters *tpl = new TemplateParameters(); + + if (token.value != TOKlparen) + { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); + goto Lerr; + } + nextToken(); + + // Get array of TemplateParameters + if (token.value != TOKrparen) + { int isvariadic = 0; + + while (1) + { TemplateParameter *tp; + Identifier *tp_ident = NULL; + Type *tp_spectype = NULL; + Type *tp_valtype = NULL; + Type *tp_defaulttype = NULL; + Expression *tp_specvalue = NULL; + Expression *tp_defaultvalue = NULL; + Token *t; + + // Get TemplateParameter + + // First, look ahead to see if it is a TypeParameter or a ValueParameter + t = peek(&token); + if (token.value == TOKalias) + { // AliasParameter + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected for template parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseBasicType(); + tp_spectype = parseDeclarator(tp_spectype, NULL); + } + if (token.value == TOKassign) // = Type + { + nextToken(); + tp_defaulttype = parseBasicType(); + tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); + } + tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype); + } + else if (t->value == TOKcolon || t->value == TOKassign || + t->value == TOKcomma || t->value == TOKrparen) + { // TypeParameter + if (token.value != TOKidentifier) + { error("Identifier expected for template parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseBasicType(); + tp_spectype = parseDeclarator(tp_spectype, NULL); + } + if (token.value == TOKassign) // = Type + { + nextToken(); + tp_defaulttype = parseBasicType(); + tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); + } + tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); + } + else if (token.value == TOKidentifier && t->value == TOKdotdotdot) + { // ident... + if (isvariadic) + error("variadic template parameter must be last"); + isvariadic = 1; + tp_ident = token.ident; + nextToken(); + nextToken(); + tp = new TemplateTupleParameter(loc, tp_ident); + } +#if DMDV2 + else if (token.value == TOKthis) + { // ThisParameter + nextToken(); + if (token.value != TOKidentifier) + { error("identifier expected for template this parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseType(); + } + if (token.value == TOKassign) // = Type + { + nextToken(); + tp_defaulttype = parseType(); + } + tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); + } +#endif + else + { // ValueParameter + tp_valtype = parseBasicType(); + tp_valtype = parseDeclarator(tp_valtype, &tp_ident); + if (!tp_ident) + { + error("identifier expected for template value parameter"); + tp_ident = new Identifier("error", TOKidentifier); + } + if (token.value == TOKcolon) // : CondExpression + { + nextToken(); + tp_specvalue = parseCondExp(); + } + if (token.value == TOKassign) // = CondExpression + { + nextToken(); + tp_defaultvalue = parseCondExp(); + } + tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); + } + tpl->push(tp); + if (token.value != TOKcomma) + break; + nextToken(); + } + } + check(TOKrparen); +Lerr: + return tpl; +} + +/****************************************** + * Parse template mixin. + * mixin Foo; + * mixin Foo!(args); + * mixin a.b.c!(args).Foo!(args); + * mixin Foo!(args) identifier; + * mixin typeof(expr).identifier!(args); + */ + +Dsymbol *Parser::parseMixin() +{ + TemplateMixin *tm; + Identifier *id; + Type *tqual; + Objects *tiargs; + Array *idents; + + //printf("parseMixin()\n"); + nextToken(); + tqual = NULL; + if (token.value == TOKdot) + { + id = Id::empty; + } + else + { + if (token.value == TOKtypeof) + { Expression *exp; + + nextToken(); + check(TOKlparen); + exp = parseExpression(); + check(TOKrparen); + tqual = new TypeTypeof(loc, exp); + check(TOKdot); + } + if (token.value != TOKidentifier) + { + error("identifier expected, not %s", token.toChars()); + id = Id::empty; + } + else + id = token.ident; + nextToken(); + } + + idents = new Array(); + while (1) + { + tiargs = NULL; + if (token.value == TOKnot) + { + nextToken(); + tiargs = parseTemplateArgumentList(); + } + + if (token.value != TOKdot) + break; + + if (tiargs) + { TemplateInstance *tempinst = new TemplateInstance(loc, id); + tempinst->tiargs = tiargs; + id = (Identifier *)tempinst; + tiargs = NULL; + } + idents->push(id); + + nextToken(); + if (token.value != TOKidentifier) + { error("identifier expected following '.' instead of '%s'", token.toChars()); + break; + } + id = token.ident; + nextToken(); + } + idents->push(id); + + if (token.value == TOKidentifier) + { + id = token.ident; + nextToken(); + } + else + id = NULL; + + tm = new TemplateMixin(loc, id, tqual, idents, tiargs); + if (token.value != TOKsemicolon) + error("';' expected after mixin"); + nextToken(); + + return tm; +} + +/****************************************** + * Parse template argument list. + * Input: + * current token is opening '(' + * Output: + * current token is one after closing ')' + */ + +Objects *Parser::parseTemplateArgumentList() +{ + //printf("Parser::parseTemplateArgumentList()\n"); + Objects *tiargs = new Objects(); + if (token.value != TOKlparen) + { error("!(TemplateArgumentList) expected following TemplateIdentifier"); + return tiargs; + } + nextToken(); + + // Get TemplateArgumentList + if (token.value != TOKrparen) + { + while (1) + { + // See if it is an Expression or a Type + if (isDeclaration(&token, 0, TOKreserved, NULL)) + { // Type + Type *ta; + + // Get TemplateArgument + ta = parseBasicType(); + ta = parseDeclarator(ta, NULL); + tiargs->push(ta); + } + else + { // Expression + Expression *ea; + + ea = parseAssignExp(); + tiargs->push(ea); + } + if (token.value != TOKcomma) + break; + nextToken(); + } + } + check(TOKrparen, "template argument list"); + return tiargs; +} + +Import *Parser::parseImport(Array *decldefs, int isstatic) +{ Import *s; + Identifier *id; + Identifier *aliasid = NULL; + Array *a; + Loc loc; + + //printf("Parser::parseImport()\n"); + do + { + L1: + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following import"); + break; + } + + loc = this->loc; + a = NULL; + id = token.ident; + nextToken(); + if (!aliasid && token.value == TOKassign) + { + aliasid = id; + goto L1; + } + while (token.value == TOKdot) + { + if (!a) + a = new Array(); + a->push(id); + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following package"); + break; + } + id = token.ident; + nextToken(); + } + + s = new Import(loc, a, id, aliasid, isstatic); + decldefs->push(s); + + /* Look for + * : alias=name, alias=name; + * syntax. + */ + if (token.value == TOKcolon) + { + do + { Identifier *name; + Identifier *alias; + + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following :"); + break; + } + alias = token.ident; + nextToken(); + if (token.value == TOKassign) + { + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following %s=", alias->toChars()); + break; + } + name = token.ident; + nextToken(); + } + else + { name = alias; + alias = NULL; + } + s->addAlias(name, alias); + } while (token.value == TOKcomma); + break; // no comma-separated imports of this form + } + + aliasid = NULL; + } while (token.value == TOKcomma); + + if (token.value == TOKsemicolon) + nextToken(); + else + { + error("';' expected"); + nextToken(); + } + + return NULL; +} + +#if DMDV2 +Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) +{ Type *t; + + /* Take care of the storage class prefixes that + * serve as type attributes: + * const shared, shared const, const, invariant, shared + */ + if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() != TOKlparen || + token.value == TOKshared && peekNext() == TOKconst && peekNext2() != TOKlparen) + { + nextToken(); + nextToken(); + /* shared const type + */ + t = parseType(pident, tpl); + t = t->makeSharedConst(); + return t; + } + else if (token.value == TOKconst && peekNext() != TOKlparen) + { + nextToken(); + /* const type + */ + t = parseType(pident, tpl); + t = t->makeConst(); + return t; + } + else if ((token.value == TOKinvariant || token.value == TOKimmutable) && + peekNext() != TOKlparen) + { + nextToken(); + /* invariant type + */ + t = parseType(pident, tpl); + t = t->makeInvariant(); + return t; + } + else if (token.value == TOKshared && peekNext() != TOKlparen) + { + nextToken(); + /* shared type + */ + t = parseType(pident, tpl); + t = t->makeShared(); + return t; + } + else + t = parseBasicType(); + t = parseDeclarator(t, pident, tpl); + return t; +} +#endif + +Type *Parser::parseBasicType() +{ Type *t; + Identifier *id; + TypeQualified *tid; + TemplateInstance *tempinst; + + //printf("parseBasicType()\n"); + switch (token.value) + { + CASE_BASIC_TYPES_X(t): + nextToken(); + break; + + case TOKidentifier: + id = token.ident; + nextToken(); + if (token.value == TOKnot) + { + nextToken(); + tempinst = new TemplateInstance(loc, id); + tempinst->tiargs = parseTemplateArgumentList(); + tid = new TypeInstance(loc, tempinst); + goto Lident2; + } + Lident: + tid = new TypeIdentifier(loc, id); + Lident2: + while (token.value == TOKdot) + { nextToken(); + if (token.value != TOKidentifier) + { error("identifier expected following '.' instead of '%s'", token.toChars()); + break; + } + id = token.ident; + nextToken(); + if (token.value == TOKnot) + { + nextToken(); + tempinst = new TemplateInstance(loc, id); + tempinst->tiargs = parseTemplateArgumentList(); + tid->addIdent((Identifier *)tempinst); + } + else + tid->addIdent(id); + } + t = tid; + break; + + case TOKdot: + // Leading . as in .foo + id = Id::empty; + goto Lident; + + case TOKtypeof: + { Expression *exp; + + nextToken(); + check(TOKlparen); + exp = parseExpression(); + check(TOKrparen); + tid = new TypeTypeof(loc, exp); + goto Lident2; + } + + default: + error("basic type expected, not %s", token.toChars()); + t = Type::tint32; + break; + } + return t; +} + +/****************************************** + * Parse things that follow the initial type t. + * t * + * t [] + * t [type] + * t [expression] + * t [expression .. expression] + * t function + * t delegate + */ + +Type *Parser::parseBasicType2(Type *t) +{ + Type *ts; + Type *ta; + + //printf("parseBasicType2()\n"); + while (1) + { + switch (token.value) + { + case TOKmul: + t = new TypePointer(t); + nextToken(); + continue; + + case TOKlbracket: +#if LTORARRAYDECL + // Handle []. Make sure things like + // int[3][1] a; + // is (array[1] of array[3] of int) + nextToken(); + if (token.value == TOKrbracket) + { + t = new TypeDArray(t); // [] + nextToken(); + } + else if (isDeclaration(&token, 0, TOKrbracket, NULL)) + { // It's an associative array declaration + Type *index; + + //printf("it's an associative array\n"); + index = parseBasicType(); + index = parseDeclarator(index, NULL); // [ type ] + t = new TypeAArray(t, index); + check(TOKrbracket); + } + else + { + //printf("it's [expression]\n"); + inBrackets++; + Expression *e = parseExpression(); // [ expression ] + if (token.value == TOKslice) + { Expression *e2; + + nextToken(); + e2 = parseExpression(); // [ exp .. exp ] + t = new TypeSlice(t, e, e2); + } + else + t = new TypeSArray(t,e); + inBrackets--; + check(TOKrbracket); + } + continue; +#else + // Handle []. Make sure things like + // int[3][1] a; + // is (array[3] of array[1] of int) + ts = t; + while (token.value == TOKlbracket) + { + nextToken(); + if (token.value == TOKrbracket) + { + ta = new TypeDArray(t); // [] + nextToken(); + } + else if (isDeclaration(&token, 0, TOKrbracket, NULL)) + { // It's an associative array declaration + Type *index; + + //printf("it's an associative array\n"); + index = parseBasicType(); + index = parseDeclarator(index, NULL); // [ type ] + check(TOKrbracket); + ta = new TypeAArray(t, index); + } + else + { + //printf("it's [expression]\n"); + Expression *e = parseExpression(); // [ expression ] + ta = new TypeSArray(t,e); + check(TOKrbracket); + } + Type **pt; + for (pt = &ts; *pt != t; pt = &(*pt)->next) + ; + *pt = ta; + } + t = ts; + continue; +#endif + + case TOKdelegate: + case TOKfunction: + { // Handle delegate declaration: + // t delegate(parameter list) + // t function(parameter list) + Arguments *arguments; + int varargs; + enum TOK save = token.value; + + nextToken(); + arguments = parseParameters(&varargs); + t = new TypeFunction(arguments, t, varargs, linkage); + if (save == TOKdelegate) + t = new TypeDelegate(t); + else + t = new TypePointer(t); // pointer to function + continue; + } + + default: + ts = t; + break; + } + break; + } + return ts; +} + +Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl) +{ Type *ts; + Type *ta; + + //printf("parseDeclarator(tpl = %p)\n", tpl); + t = parseBasicType2(t); + + switch (token.value) + { + + case TOKidentifier: + if (pident) + *pident = token.ident; + else + error("unexpected identifer '%s' in declarator", token.ident->toChars()); + ts = t; + nextToken(); + break; + + case TOKlparen: + /* Parse things with parentheses around the identifier, like: + * int (*ident[3])[] + * although the D style would be: + * int[]*[3] ident + */ + nextToken(); + ts = parseDeclarator(t, pident); + check(TOKrparen); + break; + + default: + ts = t; + break; + } + + // parse DeclaratorSuffixes + while (1) + { + switch (token.value) + { +#if CARRAYDECL + /* Support C style array syntax: + * int ident[] + * as opposed to D-style: + * int[] ident + */ + case TOKlbracket: + { // This is the old C-style post [] syntax. + nextToken(); + if (token.value == TOKrbracket) + { // It's a dynamic array + ta = new TypeDArray(t); // [] + nextToken(); + } + else if (isDeclaration(&token, 0, TOKrbracket, NULL)) + { // It's an associative array declaration + Type *index; + + //printf("it's an associative array\n"); + index = parseBasicType(); + index = parseDeclarator(index, NULL); // [ type ] + check(TOKrbracket); + ta = new TypeAArray(t, index); + } + else + { + //printf("it's [expression]\n"); + Expression *e = parseExpression(); // [ expression ] + ta = new TypeSArray(t, e); + check(TOKrbracket); + } + + /* Insert ta into + * ts -> ... -> t + * so that + * ts -> ... -> ta -> t + */ + Type **pt; + for (pt = &ts; *pt != t; pt = &(*pt)->next) + ; + *pt = ta; + continue; + } +#endif + case TOKlparen: + { Arguments *arguments; + int varargs; + + if (tpl) + { + /* Look ahead to see if this is (...)(...), + * i.e. a function template declaration + */ + if (peekPastParen(&token)->value == TOKlparen) + { // It's a function template declaration + //printf("function template declaration\n"); + + // Gather template parameter list + *tpl = parseTemplateParameterList(); + } + } + + arguments = parseParameters(&varargs); + Type *ta = new TypeFunction(arguments, t, varargs, linkage); + Type **pt; + for (pt = &ts; *pt != t; pt = &(*pt)->next) + ; + *pt = ta; + break; + } + } + break; + } + + return ts; +} + +/********************************** + * Parse Declarations. + * These can be: + * 1. declarations at global/class level + * 2. declarations at statement level + * Return array of Declaration *'s. + */ + +Array *Parser::parseDeclarations() +{ + enum STC storage_class; + enum STC stc; + Type *ts; + Type *t; + Type *tfirst; + Identifier *ident; + Array *a; + enum TOK tok = TOKreserved; + unsigned char *comment = token.blockComment; + enum LINK link = linkage; + + //printf("parseDeclarations()\n"); + switch (token.value) + { + case TOKtypedef: + case TOKalias: + tok = token.value; + nextToken(); + break; + + default: + tok = TOKreserved; + break; + } + + storage_class = STCundefined; + while (1) + { + switch (token.value) + { + case TOKconst: stc = STCconst; goto L1; + case TOKstatic: stc = STCstatic; goto L1; + case TOKfinal: stc = STCfinal; goto L1; + case TOKauto: stc = STCauto; goto L1; + case TOKscope: stc = STCscope; goto L1; + case TOKoverride: stc = STCoverride; goto L1; + case TOKabstract: stc = STCabstract; goto L1; + case TOKsynchronized: stc = STCsynchronized; goto L1; + case TOKdeprecated: stc = STCdeprecated; goto L1; +#if DMDV2 + case TOKnothrow: stc = STCnothrow; goto L1; + case TOKpure: stc = STCpure; goto L1; + case TOKref: stc = STCref; goto L1; + case TOKtls: stc = STCtls; goto L1; + case TOKenum: stc = STCmanifest; goto L1; +#endif + L1: + if (storage_class & stc) + error("redundant storage class '%s'", token.toChars()); + storage_class = (STC) (storage_class | stc); + nextToken(); + continue; + + case TOKextern: + if (peek(&token)->value != TOKlparen) + { stc = STCextern; + goto L1; + } + + link = parseLinkage(); + continue; + + default: + break; + } + break; + } + + a = new Array(); + + /* Look for auto initializers: + * storage_class identifier = initializer; + */ + while (storage_class && + token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + ident = token.ident; + nextToken(); + nextToken(); + Initializer *init = parseInitializer(); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = storage_class; + a->push(v); + if (token.value == TOKsemicolon) + { + nextToken(); + addComment(v, comment); + } + else if (token.value == TOKcomma) + { + nextToken(); + if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign)) + { + error("Identifier expected following comma"); + } + else + continue; + } + else + error("semicolon expected following auto declaration, not '%s'", token.toChars()); + return a; + } + + if (token.value == TOKclass) + { AggregateDeclaration *s; + + s = (AggregateDeclaration *)parseAggregate(); + s->storage_class |= storage_class; + a->push(s); + addComment(s, comment); + return a; + } + + ts = parseBasicType(); + ts = parseBasicType2(ts); + tfirst = NULL; + + while (1) + { + Loc loc = this->loc; + TemplateParameters *tpl = NULL; + + ident = NULL; + t = parseDeclarator(ts, &ident, &tpl); + assert(t); + if (!tfirst) + tfirst = t; + else if (t != tfirst) + error("multiple declarations must have the same type, not %s and %s", + tfirst->toChars(), t->toChars()); + if (!ident) + error("no identifier for declarator %s", t->toChars()); + + if (tok == TOKtypedef || tok == TOKalias) + { Declaration *v; + Initializer *init = NULL; + + if (token.value == TOKassign) + { + nextToken(); + init = parseInitializer(); + } + if (tok == TOKtypedef) + v = new TypedefDeclaration(loc, ident, t, init); + else + { if (init) + error("alias cannot have initializer"); + v = new AliasDeclaration(loc, ident, t); + } + v->storage_class = storage_class; + if (link == linkage) + a->push(v); + else + { + Array *ax = new Array(); + ax->push(v); + Dsymbol *s = new LinkDeclaration(link, ax); + a->push(s); + } + switch (token.value) + { case TOKsemicolon: + nextToken(); + addComment(v, comment); + break; + + case TOKcomma: + nextToken(); + addComment(v, comment); + continue; + + default: + error("semicolon expected to close %s declaration", Token::toChars(tok)); + break; + } + } + else if (t->ty == Tfunction) + { FuncDeclaration *f = + new FuncDeclaration(loc, 0, ident, storage_class, t); + addComment(f, comment); + parseContracts(f); + addComment(f, NULL); + Dsymbol *s; + if (link == linkage) + { + s = f; + } + else + { + Array *ax = new Array(); + ax->push(f); + s = new LinkDeclaration(link, ax); + } + if (tpl) // it's a function template + { Array *decldefs; + TemplateDeclaration *tempdecl; + + // Wrap a template around the aggregate declaration + decldefs = new Array(); + decldefs->push(s); + tempdecl = new TemplateDeclaration(loc, s->ident, tpl, NULL, decldefs); + s = tempdecl; + } + addComment(s, comment); + a->push(s); + } + else + { + Initializer *init = NULL; + if (token.value == TOKassign) + { + nextToken(); + init = parseInitializer(); + } + + VarDeclaration *v = new VarDeclaration(loc, t, ident, init); + v->storage_class = storage_class; + if (link == linkage) + a->push(v); + else + { + Array *ax = new Array(); + ax->push(v); + Dsymbol *s = new LinkDeclaration(link, ax); + a->push(s); + } + switch (token.value) + { case TOKsemicolon: + nextToken(); + addComment(v, comment); + break; + + case TOKcomma: + nextToken(); + addComment(v, comment); + continue; + + default: + error("semicolon expected, not '%s'", token.toChars()); + break; + } + } + break; + } + return a; +} + +/***************************************** + * Parse auto declarations of the form: + * storageClass ident = init, ident = init, ... ; + * and return the array of them. + * Starts with token on the first ident. + * Ends with scanner past closing ';' + */ + +#if DMDV2 +Array *Parser::parseAutoDeclarations(unsigned storageClass, unsigned char *comment) +{ + Array *a = new Array; + + while (1) + { + Identifier *ident = token.ident; + nextToken(); // skip over ident + assert(token.value == TOKassign); + nextToken(); // skip over '=' + Initializer *init = parseInitializer(); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = storageClass; + a->push(v); + if (token.value == TOKsemicolon) + { + nextToken(); + addComment(v, comment); + } + else if (token.value == TOKcomma) + { + nextToken(); + if (token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + addComment(v, comment); + continue; + } + else + error("Identifier expected following comma"); + } + else + error("semicolon expected following auto declaration, not '%s'", token.toChars()); + break; + } + return a; +} +#endif + +/***************************************** + * Parse contracts following function declaration. + */ + +void Parser::parseContracts(FuncDeclaration *f) +{ + Type *tb; + enum LINK linksave = linkage; + + // The following is irrelevant, as it is overridden by sc->linkage in + // TypeFunction::semantic + linkage = LINKd; // nested functions have D linkage +L1: + switch (token.value) + { + case TOKlcurly: + if (f->frequire || f->fensure) + error("missing body { ... } after in or out"); + f->fbody = parseStatement(PSsemi); + f->endloc = endloc; + break; + + case TOKbody: + nextToken(); + f->fbody = parseStatement(PScurly); + f->endloc = endloc; + break; + + case TOKsemicolon: + if (f->frequire || f->fensure) + error("missing body { ... } after in or out"); + nextToken(); + break; + +#if 0 // Do we want this for function declarations, so we can do: + // int x, y, foo(), z; + case TOKcomma: + nextToken(); + continue; +#endif + +#if 0 // Dumped feature + case TOKthrow: + if (!f->fthrows) + f->fthrows = new Array(); + nextToken(); + check(TOKlparen); + while (1) + { + tb = parseBasicType(); + f->fthrows->push(tb); + if (token.value == TOKcomma) + { nextToken(); + continue; + } + break; + } + check(TOKrparen); + goto L1; +#endif + + case TOKin: + nextToken(); + if (f->frequire) + error("redundant 'in' statement"); + f->frequire = parseStatement(PScurly | PSscope); + goto L1; + + case TOKout: + // parse: out (identifier) { statement } + nextToken(); + if (token.value != TOKlcurly) + { + check(TOKlparen); + if (token.value != TOKidentifier) + error("(identifier) following 'out' expected, not %s", token.toChars()); + f->outId = token.ident; + nextToken(); + check(TOKrparen); + } + if (f->fensure) + error("redundant 'out' statement"); + f->fensure = parseStatement(PScurly | PSscope); + goto L1; + + default: + error("semicolon expected following function declaration"); + break; + } + linkage = linksave; +} + +/***************************************** + * Parse initializer for variable declaration. + */ + +Initializer *Parser::parseInitializer() +{ + StructInitializer *is; + ArrayInitializer *ia; + ExpInitializer *ie; + Expression *e; + Identifier *id; + Initializer *value; + int comma; + Loc loc = this->loc; + Token *t; + int braces; + int brackets; + + switch (token.value) + { + case TOKlcurly: + /* Scan ahead to see if it is a struct initializer or + * a function literal. + * If it contains a ';', it is a function literal. + * Treat { } as a struct initializer. + */ + braces = 1; + for (t = peek(&token); 1; t = peek(t)) + { + switch (t->value) + { + case TOKsemicolon: + case TOKreturn: + goto Lexpression; + + case TOKlcurly: + braces++; + continue; + + case TOKrcurly: + if (--braces == 0) + break; + continue; + + case TOKeof: + break; + + default: + continue; + } + break; + } + + is = new StructInitializer(loc); + nextToken(); + comma = 0; + while (1) + { + switch (token.value) + { + case TOKidentifier: + if (comma == 1) + error("comma expected separating field initializers"); + t = peek(&token); + if (t->value == TOKcolon) + { + id = token.ident; + nextToken(); + nextToken(); // skip over ':' + } + else + { id = NULL; + } + value = parseInitializer(); + is->addInit(id, value); + comma = 1; + continue; + + case TOKcomma: + nextToken(); + comma = 2; + continue; + + case TOKrcurly: // allow trailing comma's + nextToken(); + break; + + case TOKeof: + error("found EOF instead of initializer"); + break; + + default: + value = parseInitializer(); + is->addInit(NULL, value); + comma = 1; + continue; + //error("found '%s' instead of field initializer", token.toChars()); + //break; + } + break; + } + return is; + + case TOKlbracket: + /* Scan ahead to see if it is an array initializer or + * an expression. + * If it ends with a ';', it is an array initializer. + */ + brackets = 1; + for (t = peek(&token); 1; t = peek(t)) + { + switch (t->value) + { + case TOKlbracket: + brackets++; + continue; + + case TOKrbracket: + if (--brackets == 0) + { t = peek(t); + if (t->value != TOKsemicolon && + t->value != TOKcomma && + t->value != TOKrcurly) + goto Lexpression; + break; + } + continue; + + case TOKeof: + break; + + default: + continue; + } + break; + } + + ia = new ArrayInitializer(loc); + nextToken(); + comma = 0; + while (1) + { + switch (token.value) + { + default: + if (comma == 1) + { error("comma expected separating array initializers, not %s", token.toChars()); + nextToken(); + break; + } + e = parseAssignExp(); + if (!e) + break; + if (token.value == TOKcolon) + { + nextToken(); + value = parseInitializer(); + } + else + { value = new ExpInitializer(e->loc, e); + e = NULL; + } + ia->addInit(e, value); + comma = 1; + continue; + + case TOKlcurly: + case TOKlbracket: + if (comma == 1) + error("comma expected separating array initializers, not %s", token.toChars()); + value = parseInitializer(); + ia->addInit(NULL, value); + comma = 1; + continue; + + case TOKcomma: + nextToken(); + comma = 2; + continue; + + case TOKrbracket: // allow trailing comma's + nextToken(); + break; + + case TOKeof: + error("found '%s' instead of array initializer", token.toChars()); + break; + } + break; + } + return ia; + + case TOKvoid: + t = peek(&token); + if (t->value == TOKsemicolon || t->value == TOKcomma) + { + nextToken(); + return new VoidInitializer(loc); + } + goto Lexpression; + + default: + Lexpression: + e = parseAssignExp(); + ie = new ExpInitializer(loc, e); + return ie; + } +} + +/***************************************** + * Parses default argument initializer expression that is an assign expression, + * with special handling for __FILE__ and __LINE__. + */ + +#if DMDV2 +Expression *Parser::parseDefaultInitExp() +{ + if (token.value == TOKfile || + token.value == TOKline) + { + Token *t = peek(&token); + if (t->value == TOKcomma || t->value == TOKrparen) + { Expression *e; + + if (token.value == TOKfile) + e = new FileInitExp(loc); + else + e = new LineInitExp(loc); + nextToken(); + return e; + } + } + + Expression *e = parseAssignExp(); + return e; +} +#endif + +/***************************************** + * Input: + * flags PSxxxx + */ + +Statement *Parser::parseStatement(int flags) +{ Statement *s; + Token *t; + Condition *condition; + Statement *ifbody; + Statement *elsebody; + Loc loc = this->loc; + + //printf("parseStatement()\n"); + + if (flags & PScurly && token.value != TOKlcurly) + error("statement expected to be { }, not %s", token.toChars()); + + switch (token.value) + { + case TOKidentifier: + /* A leading identifier can be a declaration, label, or expression. + * The easiest case to check first is label: + */ + t = peek(&token); + if (t->value == TOKcolon) + { // It's a label + + Identifier *ident = token.ident; + nextToken(); + nextToken(); + s = parseStatement(PSsemi); + s = new LabelStatement(loc, ident, s); + break; + } + // fallthrough to TOKdot + case TOKdot: + case TOKtypeof: + if (isDeclaration(&token, 2, TOKreserved, NULL)) + goto Ldeclaration; + else + goto Lexp; + break; + + case TOKassert: + case TOKthis: + case TOKsuper: + case TOKint32v: + case TOKuns32v: + case TOKint64v: + case TOKuns64v: + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + case TOKcharv: + case TOKwcharv: + case TOKdcharv: + case TOKnull: + case TOKtrue: + case TOKfalse: + case TOKstring: + case TOKlparen: + case TOKcast: + case TOKmul: + case TOKmin: + case TOKadd: + case TOKplusplus: + case TOKminusminus: + case TOKnew: + case TOKdelete: + case TOKdelegate: + case TOKfunction: + case TOKtypeid: + case TOKis: + case TOKlbracket: +#if DMDV2 + case TOKtraits: + case TOKfile: + case TOKline: +#endif + Lexp: + { Expression *exp; + + exp = parseExpression(); + check(TOKsemicolon, "statement"); + s = new ExpStatement(loc, exp); + break; + } + + case TOKstatic: + { // Look ahead to see if it's static assert() or static if() + Token *t; + + t = peek(&token); + if (t->value == TOKassert) + { + nextToken(); + s = new StaticAssertStatement(parseStaticAssert()); + break; + } + if (t->value == TOKif) + { + nextToken(); + condition = parseStaticIfCondition(); + goto Lcondition; + } + goto Ldeclaration; + } + + CASE_BASIC_TYPES: + case TOKtypedef: + case TOKalias: + case TOKconst: + case TOKauto: + case TOKextern: + case TOKfinal: + case TOKinvariant: +#if DMDV2 + case TOKimmutable: + case TOKshared: +#endif +// case TOKtypeof: + Ldeclaration: + { Array *a; + + a = parseDeclarations(); + if (a->dim > 1) + { + Statements *as = new Statements(); + as->reserve(a->dim); + for (int i = 0; i < a->dim; i++) + { + Dsymbol *d = (Dsymbol *)a->data[i]; + s = new DeclarationStatement(loc, d); + as->push(s); + } + s = new CompoundDeclarationStatement(loc, as); + } + else if (a->dim == 1) + { + Dsymbol *d = (Dsymbol *)a->data[0]; + s = new DeclarationStatement(loc, d); + } + else + assert(0); + if (flags & PSscope) + s = new ScopeStatement(loc, s); + break; + } + + case TOKstruct: + case TOKunion: + case TOKclass: + case TOKinterface: + { Dsymbol *d; + + d = parseAggregate(); + s = new DeclarationStatement(loc, d); + break; + } + + case TOKenum: + { Dsymbol *d; + + d = parseEnum(); + s = new DeclarationStatement(loc, d); + break; + } + + case TOKmixin: + { t = peek(&token); + if (t->value == TOKlparen) + { // mixin(string) + nextToken(); + check(TOKlparen, "mixin"); + Expression *e = parseAssignExp(); + check(TOKrparen); + check(TOKsemicolon); + s = new CompileStatement(loc, e); + break; + } + Dsymbol *d = parseMixin(); + s = new DeclarationStatement(loc, d); + break; + } + + case TOKlcurly: + { + nextToken(); + Statements *statements = new Statements(); + while (token.value != TOKrcurly && token.value != TOKeof) + { + statements->push(parseStatement(PSsemi | PScurlyscope)); + } + endloc = this->loc; + s = new CompoundStatement(loc, statements); + if (flags & (PSscope | PScurlyscope)) + s = new ScopeStatement(loc, s); + nextToken(); + break; + } + + case TOKwhile: + { Expression *condition; + Statement *body; + + nextToken(); + check(TOKlparen); + condition = parseExpression(); + check(TOKrparen); + body = parseStatement(PSscope); + s = new WhileStatement(loc, condition, body); + break; + } + + case TOKsemicolon: + if (!(flags & PSsemi)) + error("use '{ }' for an empty statement, not a ';'"); + nextToken(); + s = new ExpStatement(loc, NULL); + break; + + case TOKdo: + { Statement *body; + Expression *condition; + + nextToken(); + body = parseStatement(PSscope); + check(TOKwhile); + check(TOKlparen); + condition = parseExpression(); + check(TOKrparen); + s = new DoStatement(loc, body, condition); + break; + } + + case TOKfor: + { + Statement *init; + Expression *condition; + Expression *increment; + Statement *body; + + nextToken(); + check(TOKlparen); + if (token.value == TOKsemicolon) + { init = NULL; + nextToken(); + } + else + { init = parseStatement(0); + } + if (token.value == TOKsemicolon) + { + condition = NULL; + nextToken(); + } + else + { + condition = parseExpression(); + check(TOKsemicolon, "for condition"); + } + if (token.value == TOKrparen) + { increment = NULL; + nextToken(); + } + else + { increment = parseExpression(); + check(TOKrparen); + } + body = parseStatement(PSscope); + s = new ForStatement(loc, init, condition, increment, body); + if (init) + s = new ScopeStatement(loc, s); + break; + } + + case TOKforeach: + case TOKforeach_reverse: + { + enum TOK op = token.value; + Arguments *arguments; + + Statement *d; + Statement *body; + Expression *aggr; + + nextToken(); + check(TOKlparen); + + arguments = new Arguments(); + + while (1) + { + Type *tb; + Identifier *ai = NULL; + Type *at; + unsigned storageClass; + Argument *a; + + storageClass = STCin; + if (token.value == TOKinout || token.value == TOKref) + { storageClass = STCref; + nextToken(); + } + if (token.value == TOKidentifier) + { + Token *t = peek(&token); + if (t->value == TOKcomma || t->value == TOKsemicolon) + { ai = token.ident; + at = NULL; // infer argument type + nextToken(); + goto Larg; + } + } + tb = parseBasicType(); + at = parseDeclarator(tb, &ai); + if (!ai) + error("no identifier for declarator %s", at->toChars()); + Larg: + a = new Argument(storageClass, at, ai, NULL); + arguments->push(a); + if (token.value == TOKcomma) + { nextToken(); + continue; + } + break; + } + check(TOKsemicolon); + + aggr = parseExpression(); + check(TOKrparen); + body = parseStatement(0); + s = new ForeachStatement(loc, op, arguments, aggr, body); + break; + } + + case TOKif: + { Argument *arg = NULL; + Expression *condition; + Statement *ifbody; + Statement *elsebody; + + nextToken(); + check(TOKlparen); + + if (token.value == TOKauto) + { + nextToken(); + if (token.value == TOKidentifier) + { + Token *t = peek(&token); + if (t->value == TOKassign) + { + arg = new Argument(STCin, NULL, token.ident, NULL); + nextToken(); + nextToken(); + } + else + { error("= expected following auto identifier"); + goto Lerror; + } + } + else + { error("identifier expected following auto"); + goto Lerror; + } + } + else if (isDeclaration(&token, 2, TOKassign, NULL)) + { + Type *tb; + Type *at; + Identifier *ai; + + tb = parseBasicType(); + at = parseDeclarator(tb, &ai); + check(TOKassign); + arg = new Argument(STCin, at, ai, NULL); + } + + // Check for " ident;" + else if (token.value == TOKidentifier) + { + Token *t = peek(&token); + if (t->value == TOKcomma || t->value == TOKsemicolon) + { + arg = new Argument(STCin, NULL, token.ident, NULL); + nextToken(); + nextToken(); + if (1 || !global.params.useDeprecated) + error("if (v; e) is deprecated, use if (auto v = e)"); + } + } + + condition = parseExpression(); + check(TOKrparen); + ifbody = parseStatement(PSscope); + if (token.value == TOKelse) + { + nextToken(); + elsebody = parseStatement(PSscope); + } + else + elsebody = NULL; + s = new IfStatement(loc, arg, condition, ifbody, elsebody); + break; + } + + case TOKscope: + if (peek(&token)->value != TOKlparen) + goto Ldeclaration; // scope used as storage class + nextToken(); + check(TOKlparen); + if (token.value != TOKidentifier) + { error("scope identifier expected"); + goto Lerror; + } + else + { TOK t = TOKon_scope_exit; + Identifier *id = token.ident; + + if (id == Id::exit) + t = TOKon_scope_exit; + else if (id == Id::failure) + t = TOKon_scope_failure; + else if (id == Id::success) + t = TOKon_scope_success; + else + error("valid scope identifiers are exit, failure, or success, not %s", id->toChars()); + nextToken(); + check(TOKrparen); + Statement *st = parseStatement(PScurlyscope); + s = new OnScopeStatement(loc, t, st); + break; + } + + case TOKdebug: + nextToken(); + condition = parseDebugCondition(); + goto Lcondition; + + case TOKversion: + nextToken(); + condition = parseVersionCondition(); + goto Lcondition; + + Lcondition: + ifbody = parseStatement(0 /*PSsemi*/); + elsebody = NULL; + if (token.value == TOKelse) + { + nextToken(); + elsebody = parseStatement(0 /*PSsemi*/); + } + s = new ConditionalStatement(loc, condition, ifbody, elsebody); + break; + + case TOKpragma: + { Identifier *ident; + Expressions *args = NULL; + Statement *body; + + nextToken(); + check(TOKlparen); + if (token.value != TOKidentifier) + { error("pragma(identifier expected"); + goto Lerror; + } + ident = token.ident; + nextToken(); + if (token.value == TOKcomma && peekNext() != TOKrparen) + args = parseArguments(); // pragma(identifier, args...); + else + check(TOKrparen); // pragma(identifier); + if (token.value == TOKsemicolon) + { nextToken(); + body = NULL; + } + else + body = parseStatement(PSsemi); + s = new PragmaStatement(loc, ident, args, body); + break; + } + + case TOKswitch: + { Expression *condition; + Statement *body; + + nextToken(); + check(TOKlparen); + condition = parseExpression(); + check(TOKrparen); + body = parseStatement(PSscope); + s = new SwitchStatement(loc, condition, body); + break; + } + + case TOKcase: + { Expression *exp; + Statements *statements; + Array cases; // array of Expression's + + while (1) + { + nextToken(); + exp = parseAssignExp(); + cases.push(exp); + if (token.value != TOKcomma) + break; + } + check(TOKcolon); + + statements = new Statements(); + while (token.value != TOKcase && + token.value != TOKdefault && + token.value != TOKeof && + token.value != TOKrcurly) + { + statements->push(parseStatement(PSsemi | PScurlyscope)); + } + s = new CompoundStatement(loc, statements); + s = new ScopeStatement(loc, s); + + // Keep cases in order by building the case statements backwards + for (int i = cases.dim; i; i--) + { + exp = (Expression *)cases.data[i - 1]; + s = new CaseStatement(loc, exp, s); + } + break; + } + + case TOKdefault: + { + Statements *statements; + + nextToken(); + check(TOKcolon); + + statements = new Statements(); + while (token.value != TOKcase && + token.value != TOKdefault && + token.value != TOKeof && + token.value != TOKrcurly) + { + statements->push(parseStatement(PSsemi | PScurlyscope)); + } + s = new CompoundStatement(loc, statements); + s = new ScopeStatement(loc, s); + s = new DefaultStatement(loc, s); + break; + } + + case TOKreturn: + { Expression *exp; + + nextToken(); + if (token.value == TOKsemicolon) + exp = NULL; + else + exp = parseExpression(); + check(TOKsemicolon, "return statement"); + s = new ReturnStatement(loc, exp); + break; + } + + case TOKbreak: + { Identifier *ident; + + nextToken(); + if (token.value == TOKidentifier) + { ident = token.ident; + nextToken(); + } + else + ident = NULL; + check(TOKsemicolon, "break statement"); + s = new BreakStatement(loc, ident); + break; + } + + case TOKcontinue: + { Identifier *ident; + + nextToken(); + if (token.value == TOKidentifier) + { ident = token.ident; + nextToken(); + } + else + ident = NULL; + check(TOKsemicolon, "continue statement"); + s = new ContinueStatement(loc, ident); + break; + } + + case TOKgoto: + { Identifier *ident; + + nextToken(); + if (token.value == TOKdefault) + { + nextToken(); + s = new GotoDefaultStatement(loc); + } + else if (token.value == TOKcase) + { + Expression *exp = NULL; + + nextToken(); + if (token.value != TOKsemicolon) + exp = parseExpression(); + s = new GotoCaseStatement(loc, exp); + } + else + { + if (token.value != TOKidentifier) + { error("Identifier expected following goto"); + ident = NULL; + } + else + { ident = token.ident; + nextToken(); + } + s = new GotoStatement(loc, ident); + } + check(TOKsemicolon, "goto statement"); + break; + } + + case TOKsynchronized: + { Expression *exp; + Statement *body; + + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + exp = parseExpression(); + check(TOKrparen); + } + else + exp = NULL; + body = parseStatement(PSscope); + s = new SynchronizedStatement(loc, exp, body); + break; + } + + case TOKwith: + { Expression *exp; + Statement *body; + + nextToken(); + check(TOKlparen); + exp = parseExpression(); + check(TOKrparen); + body = parseStatement(PSscope); + s = new WithStatement(loc, exp, body); + break; + } + + case TOKtry: + { Statement *body; + Array *catches = NULL; + Statement *finalbody = NULL; + + nextToken(); + body = parseStatement(PSscope); + while (token.value == TOKcatch) + { + Statement *handler; + Catch *c; + Type *t; + Identifier *id; + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlcurly) + { + t = NULL; + id = NULL; + } + else + { + check(TOKlparen); + t = parseBasicType(); + id = NULL; + t = parseDeclarator(t, &id); + check(TOKrparen); + } + handler = parseStatement(0); + c = new Catch(loc, t, id, handler); + if (!catches) + catches = new Array(); + catches->push(c); + } + + if (token.value == TOKfinally) + { nextToken(); + finalbody = parseStatement(0); + } + + s = body; + if (!catches && !finalbody) + error("catch or finally expected following try"); + else + { if (catches) + s = new TryCatchStatement(loc, body, catches); + if (finalbody) + s = new TryFinallyStatement(loc, s, finalbody); + } + break; + } + + case TOKthrow: + { Expression *exp; + + nextToken(); + exp = parseExpression(); + check(TOKsemicolon, "throw statement"); + s = new ThrowStatement(loc, exp); + break; + } + + case TOKvolatile: + nextToken(); + s = parseStatement(PSsemi | PScurlyscope); +#if DMDV2 + if (!global.params.useDeprecated) + error("volatile statements deprecated; used synchronized statements instead"); +#endif + s = new VolatileStatement(loc, s); + break; + + case TOKasm: + { Statements *statements; + Identifier *label; + Loc labelloc; + Token *toklist; + Token **ptoklist; + + // Parse the asm block into a sequence of AsmStatements, + // each AsmStatement is one instruction. + // Separate out labels. + // Defer parsing of AsmStatements until semantic processing. + + nextToken(); + check(TOKlcurly); + toklist = NULL; + ptoklist = &toklist; + label = NULL; + statements = new Statements(); + while (1) + { + switch (token.value) + { + case TOKidentifier: + if (!toklist) + { + // Look ahead to see if it is a label + t = peek(&token); + if (t->value == TOKcolon) + { // It's a label + label = token.ident; + labelloc = this->loc; + nextToken(); + nextToken(); + continue; + } + } + goto Ldefault; + + case TOKrcurly: + if (toklist || label) + { + error("asm statements must end in ';'"); + } + break; + + case TOKsemicolon: + s = NULL; + if (toklist || label) + { // Create AsmStatement from list of tokens we've saved + s = new AsmStatement(this->loc, toklist); + toklist = NULL; + ptoklist = &toklist; + if (label) + { s = new LabelStatement(labelloc, label, s); + label = NULL; + } + statements->push(s); + } + nextToken(); + continue; + + case TOKeof: + /* { */ + error("matching '}' expected, not end of file"); + break; + + default: + Ldefault: + *ptoklist = new Token(); + memcpy(*ptoklist, &token, sizeof(Token)); + ptoklist = &(*ptoklist)->next; + *ptoklist = NULL; + + nextToken(); + continue; + } + break; + } + s = new AsmBlockStatement(loc, statements); + nextToken(); + break; + } + + default: + error("found '%s' instead of statement", token.toChars()); + goto Lerror; + + Lerror: + while (token.value != TOKrcurly && + token.value != TOKsemicolon && + token.value != TOKeof) + nextToken(); + if (token.value == TOKsemicolon) + nextToken(); + s = NULL; + break; + } + + return s; +} + +void Parser::check(enum TOK value) +{ + check(loc, value); +} + +void Parser::check(Loc loc, enum TOK value) +{ + if (token.value != value) + error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value)); + nextToken(); +} + +void Parser::check(enum TOK value, const char *string) +{ + if (token.value != value) + error("found '%s' when expecting '%s' following '%s'", + token.toChars(), Token::toChars(value), string); + nextToken(); +} + +/************************************ + * Determine if the scanner is sitting on the start of a declaration. + * Input: + * needId 0 no identifier + * 1 identifier optional + * 2 must have identifier + */ + +int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) +{ + //printf("isDeclaration(needId = %d)\n", needId); + int haveId = 0; + +#if DMDV2 + if ((t->value == TOKconst || t->value == TOKinvariant) && + peek(t)->value != TOKlparen) + { /* const type + * invariant type + */ + t = peek(t); + } +#endif + + if (!isBasicType(&t)) + return FALSE; + if (!isDeclarator(&t, &haveId, endtok)) + return FALSE; + if ( needId == 1 || + (needId == 0 && !haveId) || + (needId == 2 && haveId)) + { if (pt) + *pt = t; + return TRUE; + } + else + return FALSE; +} + +int Parser::isBasicType(Token **pt) +{ + // This code parallels parseBasicType() + Token *t = *pt; + Token *t2; + int parens; + + switch (t->value) + { + CASE_BASIC_TYPES: + t = peek(t); + break; + + case TOKidentifier: + t = peek(t); + if (t->value == TOKnot) + { + goto L4; + } + goto L3; + while (1) + { + L2: + t = peek(t); + L3: + if (t->value == TOKdot) + { + Ldot: + t = peek(t); + if (t->value != TOKidentifier) + goto Lfalse; + t = peek(t); + if (t->value != TOKnot) + goto L3; + L4: + t = peek(t); + if (t->value != TOKlparen) + goto Lfalse; + if (!skipParens(t, &t)) + goto Lfalse; + } + else + break; + } + break; + + case TOKdot: + goto Ldot; + + case TOKtypeof: + /* typeof(exp).identifier... + */ + t = peek(t); + if (t->value != TOKlparen) + goto Lfalse; + if (!skipParens(t, &t)) + goto Lfalse; + goto L2; + + default: + goto Lfalse; + } + *pt = t; + //printf("is\n"); + return TRUE; + +Lfalse: + //printf("is not\n"); + return FALSE; +} + +int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) +{ // This code parallels parseDeclarator() + Token *t = *pt; + int parens; + + //printf("Parser::isDeclarator()\n"); + //t->print(); + if (t->value == TOKassign) + return FALSE; + + while (1) + { + parens = FALSE; + switch (t->value) + { + case TOKmul: + //case TOKand: + t = peek(t); + continue; + + case TOKlbracket: + t = peek(t); + if (t->value == TOKrbracket) + { + t = peek(t); + } + else if (isDeclaration(t, 0, TOKrbracket, &t)) + { // It's an associative array declaration + t = peek(t); + } + else + { + // [ expression ] + // [ expression .. expression ] + if (!isExpression(&t)) + return FALSE; + if (t->value == TOKslice) + { t = peek(t); + if (!isExpression(&t)) + return FALSE; + } + if (t->value != TOKrbracket) + return FALSE; + t = peek(t); + } + continue; + + case TOKidentifier: + if (*haveId) + return FALSE; + *haveId = TRUE; + t = peek(t); + break; + + case TOKlparen: + t = peek(t); + + if (t->value == TOKrparen) + return FALSE; // () is not a declarator + + /* Regard ( identifier ) as not a declarator + * BUG: what about ( *identifier ) in + * f(*p)(x); + * where f is a class instance with overloaded () ? + * Should we just disallow C-style function pointer declarations? + */ + if (t->value == TOKidentifier) + { Token *t2 = peek(t); + if (t2->value == TOKrparen) + return FALSE; + } + + + if (!isDeclarator(&t, haveId, TOKrparen)) + return FALSE; + t = peek(t); + parens = TRUE; + break; + + case TOKdelegate: + case TOKfunction: + t = peek(t); + if (!isParameters(&t)) + return FALSE; + continue; + } + break; + } + + while (1) + { + switch (t->value) + { +#if CARRAYDECL + case TOKlbracket: + parens = FALSE; + t = peek(t); + if (t->value == TOKrbracket) + { + t = peek(t); + } + else if (isDeclaration(t, 0, TOKrbracket, &t)) + { // It's an associative array declaration + t = peek(t); + } + else + { + // [ expression ] + if (!isExpression(&t)) + return FALSE; + if (t->value != TOKrbracket) + return FALSE; + t = peek(t); + } + continue; +#endif + + case TOKlparen: + parens = FALSE; + if (!isParameters(&t)) + return FALSE; +#if DMDV2 + while (1) + { + switch (t->value) + { + case TOKconst: + case TOKinvariant: + case TOKimmutable: + case TOKshared: + case TOKpure: + case TOKnothrow: + t = peek(t); + continue; + default: + break; + } + break; + } +#endif + continue; + + // Valid tokens that follow a declaration + case TOKrparen: + case TOKrbracket: + case TOKassign: + case TOKcomma: + case TOKsemicolon: + case TOKlcurly: + case TOKin: + // The !parens is to disallow unnecessary parentheses + if (!parens && (endtok == TOKreserved || endtok == t->value)) + { *pt = t; + return TRUE; + } + return FALSE; + + default: + return FALSE; + } + } +} + + +int Parser::isParameters(Token **pt) +{ // This code parallels parseParameters() + Token *t = *pt; + int tmp; + + //printf("isParameters()\n"); + if (t->value != TOKlparen) + return FALSE; + + t = peek(t); + while (1) + { + switch (t->value) + { + case TOKrparen: + break; + + case TOKdotdotdot: + t = peek(t); + break; + + case TOKin: + case TOKout: + case TOKinout: + case TOKref: + case TOKlazy: + t = peek(t); + default: + if (!isBasicType(&t)) + return FALSE; + tmp = FALSE; + if (t->value != TOKdotdotdot && + !isDeclarator(&t, &tmp, TOKreserved)) + return FALSE; + if (t->value == TOKassign) + { t = peek(t); + if (!isExpression(&t)) + return FALSE; + } + if (t->value == TOKdotdotdot) + { + t = peek(t); + break; + } + if (t->value == TOKcomma) + { t = peek(t); + continue; + } + break; + } + break; + } + if (t->value != TOKrparen) + return FALSE; + t = peek(t); + *pt = t; + return TRUE; +} + +int Parser::isExpression(Token **pt) +{ + // This is supposed to determine if something is an expression. + // What it actually does is scan until a closing right bracket + // is found. + + Token *t = *pt; + int brnest = 0; + int panest = 0; + + for (;; t = peek(t)) + { + switch (t->value) + { + case TOKlbracket: + brnest++; + continue; + + case TOKrbracket: + if (--brnest >= 0) + continue; + break; + + case TOKlparen: + panest++; + continue; + + case TOKcomma: + if (brnest || panest) + continue; + break; + + case TOKrparen: + if (--panest >= 0) + continue; + break; + + case TOKslice: + if (brnest) + continue; + break; + + case TOKeof: + return FALSE; + + default: + continue; + } + break; + } + + *pt = t; + return TRUE; +} + +/********************************************** + * Skip over + * instance foo.bar(parameters...) + * Output: + * if (pt), *pt is set to the token following the closing ) + * Returns: + * 1 it's valid instance syntax + * 0 invalid instance syntax + */ + +int Parser::isTemplateInstance(Token *t, Token **pt) +{ + t = peek(t); + if (t->value != TOKdot) + { + if (t->value != TOKidentifier) + goto Lfalse; + t = peek(t); + } + while (t->value == TOKdot) + { + t = peek(t); + if (t->value != TOKidentifier) + goto Lfalse; + t = peek(t); + } + if (t->value != TOKlparen) + goto Lfalse; + + // Skip over the template arguments + while (1) + { + while (1) + { + t = peek(t); + switch (t->value) + { + case TOKlparen: + if (!skipParens(t, &t)) + goto Lfalse; + continue; + case TOKrparen: + break; + case TOKcomma: + break; + case TOKeof: + case TOKsemicolon: + goto Lfalse; + default: + continue; + } + break; + } + + if (t->value != TOKcomma) + break; + } + if (t->value != TOKrparen) + goto Lfalse; + t = peek(t); + if (pt) + *pt = t; + return 1; + +Lfalse: + return 0; +} + +/******************************************* + * Skip parens, brackets. + * Input: + * t is on opening ( + * Output: + * *pt is set to closing token, which is ')' on success + * Returns: + * !=0 successful + * 0 some parsing error + */ + +int Parser::skipParens(Token *t, Token **pt) +{ + int parens = 0; + + while (1) + { + switch (t->value) + { + case TOKlparen: + parens++; + break; + + case TOKrparen: + parens--; + if (parens < 0) + goto Lfalse; + if (parens == 0) + goto Ldone; + break; + + case TOKeof: + case TOKsemicolon: + goto Lfalse; + + default: + break; + } + t = peek(t); + } + + Ldone: + if (*pt) + *pt = t; + return 1; + + Lfalse: + return 0; +} + +/********************************* Expression Parser ***************************/ + +Expression *Parser::parsePrimaryExp() +{ Expression *e; + Type *t; + Identifier *id; + enum TOK save; + Loc loc = this->loc; + + //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); + switch (token.value) + { + case TOKidentifier: + id = token.ident; + nextToken(); + if (token.value == TOKnot && peek(&token)->value == TOKlparen) + { // identifier!(template-argument-list) + TemplateInstance *tempinst; + + tempinst = new TemplateInstance(loc, id); + nextToken(); + tempinst->tiargs = parseTemplateArgumentList(); + e = new ScopeExp(loc, tempinst); + } + else + e = new IdentifierExp(loc, id); + break; + + case TOKdollar: + if (!inBrackets) + error("'$' is valid only inside [] of index or slice"); + e = new DollarExp(loc); + nextToken(); + break; + + case TOKdot: + // Signal global scope '.' operator with "" identifier + e = new IdentifierExp(loc, Id::empty); + break; + + case TOKthis: + e = new ThisExp(loc); + nextToken(); + break; + + case TOKsuper: + e = new SuperExp(loc); + nextToken(); + break; + + case TOKint32v: + e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32); + nextToken(); + break; + + case TOKuns32v: + e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32); + nextToken(); + break; + + case TOKint64v: + e = new IntegerExp(loc, token.int64value, Type::tint64); + nextToken(); + break; + + case TOKuns64v: + e = new IntegerExp(loc, token.uns64value, Type::tuns64); + nextToken(); + break; + + case TOKfloat32v: + e = new RealExp(loc, token.float80value, Type::tfloat32); + nextToken(); + break; + + case TOKfloat64v: + e = new RealExp(loc, token.float80value, Type::tfloat64); + nextToken(); + break; + + case TOKfloat80v: + e = new RealExp(loc, token.float80value, Type::tfloat80); + nextToken(); + break; + + case TOKimaginary32v: + e = new RealExp(loc, token.float80value, Type::timaginary32); + nextToken(); + break; + + case TOKimaginary64v: + e = new RealExp(loc, token.float80value, Type::timaginary64); + nextToken(); + break; + + case TOKimaginary80v: + e = new RealExp(loc, token.float80value, Type::timaginary80); + nextToken(); + break; + + case TOKnull: + e = new NullExp(loc); + nextToken(); + break; + +#if DMDV2 + case TOKfile: + { char *s = loc.filename ? loc.filename : mod->ident->toChars(); + e = new StringExp(loc, s, strlen(s), 0); + nextToken(); + break; + } + + case TOKline: + e = new IntegerExp(loc, loc.linnum, Type::tint32); + nextToken(); + break; +#endif + + case TOKtrue: + e = new IntegerExp(loc, 1, Type::tbool); + nextToken(); + break; + + case TOKfalse: + e = new IntegerExp(loc, 0, Type::tbool); + nextToken(); + break; + + case TOKcharv: + e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar); + nextToken(); + break; + + case TOKwcharv: + e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar); + nextToken(); + break; + + case TOKdcharv: + e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar); + nextToken(); + break; + + case TOKstring: + { unsigned char *s; + unsigned len; + unsigned char postfix; + + // cat adjacent strings + s = token.ustring; + len = token.len; + postfix = token.postfix; + while (1) + { + nextToken(); + if (token.value == TOKstring) + { unsigned len1; + unsigned len2; + unsigned char *s2; + + if (token.postfix) + { if (token.postfix != postfix) + error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix); + postfix = token.postfix; + } + + len1 = len; + len2 = token.len; + len = len1 + len2; + s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char)); + memcpy(s2, s, len1 * sizeof(unsigned char)); + memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char)); + s = s2; + } + else + break; + } + e = new StringExp(loc, s, len, postfix); + break; + } + + 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()); + goto Lerr; + } + e = typeDotIdExp(loc, t, token.ident); + nextToken(); + break; + + case TOKtypeof: + { Expression *exp; + + nextToken(); + check(TOKlparen); + exp = parseExpression(); + check(TOKrparen); + t = new TypeTypeof(loc, exp); + e = new TypeExp(loc, t); + break; + } + + case TOKtypeid: + { Type *t; + + nextToken(); + check(TOKlparen, "typeid"); + t = parseBasicType(); + t = parseDeclarator(t,NULL); // ( type ) + check(TOKrparen); + e = new TypeidExp(loc, t); + break; + } + +#if DMDV2 + case TOKtraits: + { /* __traits(identifier, args...) + */ + Identifier *ident; + Objects *args = NULL; + + nextToken(); + check(TOKlparen); + if (token.value != TOKidentifier) + { error("__traits(identifier, args...) expected"); + goto Lerr; + } + ident = token.ident; + nextToken(); + if (token.value == TOKcomma) + args = parseTemplateArgumentList2(); // __traits(identifier, args...) + else + check(TOKrparen); // __traits(identifier) + + e = new TraitsExp(loc, ident, args); + break; + } +#endif + + case TOKis: + { Type *targ; + Identifier *ident = NULL; + Type *tspec = NULL; + enum TOK tok = TOKreserved; + enum TOK tok2 = TOKreserved; + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + targ = parseBasicType(); + targ = parseDeclarator(targ, &ident); + if (token.value == TOKcolon || token.value == TOKequal) + { + tok = token.value; + nextToken(); + if (tok == TOKequal && + (token.value == TOKtypedef || + token.value == TOKstruct || + token.value == TOKunion || + token.value == TOKclass || + token.value == TOKsuper || + token.value == TOKenum || + token.value == TOKinterface || +#if DMDV2 + token.value == TOKconst && peek(&token)->value == TOKrparen || + token.value == TOKinvariant && peek(&token)->value == TOKrparen || + token.value == TOKimmutable && peek(&token)->value == TOKrparen || + token.value == TOKshared && peek(&token)->value == TOKrparen || +#endif + token.value == TOKfunction || + token.value == TOKdelegate || + token.value == TOKreturn)) + { + tok2 = token.value; + nextToken(); + } + else + { + tspec = parseBasicType(); + tspec = parseDeclarator(tspec, NULL); + } + } + check(TOKrparen); + } + else + { error("(type identifier : specialization) expected following is"); + goto Lerr; + } + e = new IsExp(loc, targ, ident, tok, tspec, tok2); + break; + } + + case TOKassert: + { Expression *msg = NULL; + + nextToken(); + check(TOKlparen, "assert"); + e = parseAssignExp(); + if (token.value == TOKcomma) + { nextToken(); + msg = parseAssignExp(); + } + check(TOKrparen); + e = new AssertExp(loc, e, msg); + break; + } + + case TOKmixin: + { + nextToken(); + check(TOKlparen, "mixin"); + e = parseAssignExp(); + check(TOKrparen); + e = new CompileExp(loc, e); + break; + } + + case TOKimport: + { + nextToken(); + check(TOKlparen, "import"); + e = parseAssignExp(); + check(TOKrparen); + e = new FileExp(loc, e); + break; + } + + case TOKlparen: + if (peekPastParen(&token)->value == TOKlcurly) + { // (arguments) { statements... } + save = TOKdelegate; + goto case_delegate; + } + // ( expression ) + nextToken(); + e = parseExpression(); + check(loc, TOKrparen); + break; + + case TOKlbracket: + { /* Parse array literals and associative array literals: + * [ value, value, value ... ] + * [ key:value, key:value, key:value ... ] + */ + Expressions *values = new Expressions(); + Expressions *keys = NULL; + + nextToken(); + if (token.value != TOKrbracket) + { + while (token.value != TOKeof) + { + Expression *e = parseAssignExp(); + if (token.value == TOKcolon && (keys || values->dim == 0)) + { nextToken(); + if (!keys) + keys = new Expressions(); + keys->push(e); + e = parseAssignExp(); + } + else if (keys) + { error("'key:value' expected for associative array literal"); + delete keys; + keys = NULL; + } + values->push(e); + if (token.value == TOKrbracket) + break; + check(TOKcomma); + } + } + check(TOKrbracket); + + if (keys) + e = new AssocArrayLiteralExp(loc, keys, values); + else + e = new ArrayLiteralExp(loc, values); + break; + } + + case TOKlcurly: + // { statements... } + save = TOKdelegate; + goto case_delegate; + + case TOKfunction: + case TOKdelegate: + save = token.value; + nextToken(); + case_delegate: + { + /* function type(parameters) { body } + * delegate type(parameters) { body } + */ + Arguments *arguments; + int varargs; + FuncLiteralDeclaration *fd; + Type *t; + + if (token.value == TOKlcurly) + { + t = NULL; + varargs = 0; + arguments = new Arguments(); + } + else + { + if (token.value == TOKlparen) + t = NULL; + else + { + t = parseBasicType(); + t = parseBasicType2(t); // function return type + } + arguments = parseParameters(&varargs); + } + t = new TypeFunction(arguments, t, varargs, linkage); + fd = new FuncLiteralDeclaration(loc, 0, t, save, NULL); + parseContracts(fd); + e = new FuncExp(loc, fd); + break; + } + + default: + error("expression expected, not '%s'", token.toChars()); + Lerr: + // Anything for e, as long as it's not NULL + e = new IntegerExp(loc, 0, Type::tint32); + nextToken(); + break; + } + return parsePostExp(e); +} + +Expression *Parser::parsePostExp(Expression *e) +{ + Loc loc; + + while (1) + { + loc = this->loc; + switch (token.value) + { + case TOKdot: + nextToken(); + if (token.value == TOKidentifier) + { Identifier *id = token.ident; + + nextToken(); + if (token.value == TOKnot && peek(&token)->value == TOKlparen) + { // identifier!(template-argument-list) + TemplateInstance *tempinst; + + tempinst = new TemplateInstance(loc, id); + nextToken(); + tempinst->tiargs = parseTemplateArgumentList(); + e = new DotTemplateInstanceExp(loc, e, tempinst); + } + else + e = new DotIdExp(loc, e, id); + continue; + } + else if (token.value == TOKnew) + { + e = parseNewExp(e); + continue; + } + else + error("identifier expected following '.', not '%s'", token.toChars()); + break; + + case TOKplusplus: + e = new PostExp(TOKplusplus, loc, e); + break; + + case TOKminusminus: + e = new PostExp(TOKminusminus, loc, e); + break; + + case TOKlparen: + e = new CallExp(loc, e, parseArguments()); + continue; + + case TOKlbracket: + { // array dereferences: + // array[index] + // array[] + // array[lwr .. upr] + Expression *index; + Expression *upr; + + inBrackets++; + nextToken(); + if (token.value == TOKrbracket) + { // array[] + e = new SliceExp(loc, e, NULL, NULL); + nextToken(); + } + else + { + index = parseAssignExp(); + if (token.value == TOKslice) + { // array[lwr .. upr] + nextToken(); + upr = parseAssignExp(); + e = new SliceExp(loc, e, index, upr); + } + else + { // array[index, i2, i3, i4, ...] + Expressions *arguments = new Expressions(); + arguments->push(index); + if (token.value == TOKcomma) + { + nextToken(); + while (1) + { Expression *arg; + + arg = parseAssignExp(); + arguments->push(arg); + if (token.value == TOKrbracket) + break; + check(TOKcomma); + } + } + e = new ArrayExp(loc, e, arguments); + } + check(TOKrbracket); + inBrackets--; + } + continue; + } + + default: + return e; + } + nextToken(); + } +} + +Expression *Parser::parseUnaryExp() +{ Expression *e; + Loc loc = this->loc; + + switch (token.value) + { + case TOKand: + nextToken(); + e = parseUnaryExp(); + e = new AddrExp(loc, e); + break; + + case TOKplusplus: + nextToken(); + e = parseUnaryExp(); + e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); + break; + + case TOKminusminus: + nextToken(); + e = parseUnaryExp(); + e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); + break; + + case TOKmul: + nextToken(); + e = parseUnaryExp(); + e = new PtrExp(loc, e); + break; + + case TOKmin: + nextToken(); + e = parseUnaryExp(); + e = new NegExp(loc, e); + break; + + case TOKadd: + nextToken(); + e = parseUnaryExp(); + e = new UAddExp(loc, e); + break; + + case TOKnot: + nextToken(); + e = parseUnaryExp(); + e = new NotExp(loc, e); + break; + + case TOKtilde: + nextToken(); + e = parseUnaryExp(); + e = new ComExp(loc, e); + break; + + case TOKdelete: + nextToken(); + e = parseUnaryExp(); + e = new DeleteExp(loc, e); + break; + + case TOKnew: + e = parseNewExp(NULL); + break; + + case TOKcast: // cast(type) expression + { Type *t; + + nextToken(); + check(TOKlparen); + t = parseBasicType(); + t = parseDeclarator(t,NULL); // ( type ) + check(TOKrparen); + + e = parseUnaryExp(); + e = new CastExp(loc, e, t); + break; + } + + case TOKlparen: + { Token *tk; + + tk = peek(&token); +#if CCASTSYNTAX + // If cast + if (isDeclaration(tk, 0, TOKrparen, &tk)) + { + tk = peek(tk); // skip over right parenthesis + switch (tk->value) + { + case TOKnot: + tk = peek(tk); + if (tk->value == TOKis) // !is + break; + case TOKdot: + case TOKplusplus: + case TOKminusminus: + case TOKdelete: + case TOKnew: + case TOKlparen: + case TOKidentifier: + case TOKthis: + case TOKsuper: + case TOKint32v: + case TOKuns32v: + case TOKint64v: + case TOKuns64v: + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + case TOKnull: + case TOKtrue: + case TOKfalse: + case TOKcharv: + case TOKwcharv: + case TOKdcharv: + case TOKstring: +#if 0 + case TOKtilde: + case TOKand: + case TOKmul: + case TOKmin: + case TOKadd: +#endif + case TOKfunction: + case TOKdelegate: + case TOKtypeof: +#if DMDV2 + case TOKfile: + case TOKline: +#endif + CASE_BASIC_TYPES: // (type)int.size + { // (type) una_exp + Type *t; + + nextToken(); + t = parseBasicType(); + t = parseDeclarator(t,NULL); + check(TOKrparen); + + // if .identifier + if (token.value == TOKdot) + { + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following (type)."); + return NULL; + } + e = typeDotIdExp(loc, t, token.ident); + nextToken(); + e = parsePostExp(e); + } + else + { + e = parseUnaryExp(); + e = new CastExp(loc, e, t); + error("C style cast illegal, use %s", e->toChars()); + } + return e; + } + } + } +#endif + e = parsePrimaryExp(); + break; + } + default: + e = parsePrimaryExp(); + break; + } + assert(e); + return e; +} + +Expression *Parser::parseMulExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseUnaryExp(); + while (1) + { + switch (token.value) + { + case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; + case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; + case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; + + default: + break; + } + break; + } + return e; +} + +Expression *Parser::parseAddExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseMulExp(); + while (1) + { + switch (token.value) + { + case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue; + case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue; + case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue; + + default: + break; + } + break; + } + return e; +} + +Expression *Parser::parseShiftExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseAddExp(); + while (1) + { + switch (token.value) + { + case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue; + case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue; + case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue; + + default: + break; + } + break; + } + return e; +} + +Expression *Parser::parseRelExp() +{ Expression *e; + Expression *e2; + enum TOK op; + Loc loc = this->loc; + + e = parseShiftExp(); + while (1) + { + switch (token.value) + { + case TOKlt: + case TOKle: + case TOKgt: + case TOKge: + case TOKunord: + case TOKlg: + case TOKleg: + case TOKule: + case TOKul: + case TOKuge: + case TOKug: + case TOKue: + op = token.value; + nextToken(); + e2 = parseShiftExp(); + e = new CmpExp(op, loc, e, e2); + continue; + + case TOKin: + nextToken(); + e2 = parseShiftExp(); + e = new InExp(loc, e, e2); + continue; + + default: + break; + } + break; + } + return e; +} + +Expression *Parser::parseEqualExp() +{ Expression *e; + Expression *e2; + Token *t; + Loc loc = this->loc; + + e = parseRelExp(); + while (1) + { enum TOK value = token.value; + + switch (value) + { + case TOKequal: + case TOKnotequal: + nextToken(); + e2 = parseRelExp(); + e = new EqualExp(value, loc, e, e2); + continue; + + case TOKidentity: + error("'===' is no longer legal, use 'is' instead"); + goto L1; + + case TOKnotidentity: + error("'!==' is no longer legal, use '!is' instead"); + goto L1; + + case TOKis: + value = TOKidentity; + goto L1; + + case TOKnot: + // Attempt to identify '!is' + t = peek(&token); + if (t->value != TOKis) + break; + nextToken(); + value = TOKnotidentity; + goto L1; + + L1: + nextToken(); + e2 = parseRelExp(); + e = new IdentityExp(value, loc, e, e2); + continue; + + default: + break; + } + break; + } + return e; +} + +Expression *Parser::parseCmpExp() +{ Expression *e; + Expression *e2; + Token *t; + Loc loc = this->loc; + + e = parseShiftExp(); + enum TOK op = token.value; + + switch (op) + { + case TOKequal: + case TOKnotequal: + nextToken(); + e2 = parseShiftExp(); + e = new EqualExp(op, loc, e, e2); + break; + + case TOKis: + op = TOKidentity; + goto L1; + + case TOKnot: + // Attempt to identify '!is' + t = peek(&token); + if (t->value != TOKis) + break; + nextToken(); + op = TOKnotidentity; + goto L1; + + L1: + nextToken(); + e2 = parseShiftExp(); + e = new IdentityExp(op, loc, e, e2); + break; + + case TOKlt: + case TOKle: + case TOKgt: + case TOKge: + case TOKunord: + case TOKlg: + case TOKleg: + case TOKule: + case TOKul: + case TOKuge: + case TOKug: + case TOKue: + nextToken(); + e2 = parseShiftExp(); + e = new CmpExp(op, loc, e, e2); + break; + + case TOKin: + nextToken(); + e2 = parseShiftExp(); + e = new InExp(loc, e, e2); + break; + + default: + break; + } + return e; +} + +Expression *Parser::parseAndExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + if (global.params.Dversion == 1) + { + e = parseEqualExp(); + while (token.value == TOKand) + { + nextToken(); + e2 = parseEqualExp(); + e = new AndExp(loc,e,e2); + loc = this->loc; + } + } + else + { + e = parseCmpExp(); + while (token.value == TOKand) + { + nextToken(); + e2 = parseCmpExp(); + e = new AndExp(loc,e,e2); + loc = this->loc; + } + } + return e; +} + +Expression *Parser::parseXorExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseAndExp(); + while (token.value == TOKxor) + { + nextToken(); + e2 = parseAndExp(); + e = new XorExp(loc, e, e2); + } + return e; +} + +Expression *Parser::parseOrExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseXorExp(); + while (token.value == TOKor) + { + nextToken(); + e2 = parseXorExp(); + e = new OrExp(loc, e, e2); + } + return e; +} + +Expression *Parser::parseAndAndExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseOrExp(); + while (token.value == TOKandand) + { + nextToken(); + e2 = parseOrExp(); + e = new AndAndExp(loc, e, e2); + } + return e; +} + +Expression *Parser::parseOrOrExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseAndAndExp(); + while (token.value == TOKoror) + { + nextToken(); + e2 = parseAndAndExp(); + e = new OrOrExp(loc, e, e2); + } + return e; +} + +Expression *Parser::parseCondExp() +{ Expression *e; + Expression *e1; + Expression *e2; + Loc loc = this->loc; + + e = parseOrOrExp(); + if (token.value == TOKquestion) + { + nextToken(); + e1 = parseExpression(); + check(TOKcolon); + e2 = parseCondExp(); + e = new CondExp(loc, e, e1, e2); + } + return e; +} + +Expression *Parser::parseAssignExp() +{ Expression *e; + Expression *e2; + Loc loc; + + e = parseCondExp(); + while (1) + { + loc = this->loc; + switch (token.value) + { +#define X(tok,ector) \ + case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue; + + X(TOKassign, AssignExp); + X(TOKaddass, AddAssignExp); + X(TOKminass, MinAssignExp); + X(TOKmulass, MulAssignExp); + X(TOKdivass, DivAssignExp); + X(TOKmodass, ModAssignExp); + X(TOKandass, AndAssignExp); + X(TOKorass, OrAssignExp); + X(TOKxorass, XorAssignExp); + X(TOKshlass, ShlAssignExp); + X(TOKshrass, ShrAssignExp); + X(TOKushrass, UshrAssignExp); + X(TOKcatass, CatAssignExp); + +#undef X + default: + break; + } + break; + } + return e; +} + +Expression *Parser::parseExpression() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + //printf("Parser::parseExpression() loc = %d\n", loc.linnum); + e = parseAssignExp(); + while (token.value == TOKcomma) + { + nextToken(); + e2 = parseAssignExp(); + e = new CommaExp(loc, e, e2); + loc = this->loc; + } + return e; +} + + +/************************* + * Collect argument list. + * Assume current token is '(' or '['. + */ + +Expressions *Parser::parseArguments() +{ // function call + Expressions *arguments; + Expression *arg; + enum TOK endtok; + + arguments = new Expressions(); + if (token.value == TOKlbracket) + endtok = TOKrbracket; + else + endtok = TOKrparen; + + { + nextToken(); + if (token.value != endtok) + { + while (1) + { + arg = parseAssignExp(); + arguments->push(arg); + if (token.value == endtok) + break; + check(TOKcomma); + } + } + check(endtok); + } + return arguments; +} + +/******************************************* + */ + +Expression *Parser::parseNewExp(Expression *thisexp) +{ Type *t; + Expressions *newargs; + Expressions *arguments = NULL; + Expression *e; + Loc loc = this->loc; + + nextToken(); + newargs = NULL; + if (token.value == TOKlparen) + { + newargs = parseArguments(); + } + + // An anonymous nested class starts with "class" + if (token.value == TOKclass) + { + nextToken(); + if (token.value == TOKlparen) + arguments = parseArguments(); + + BaseClasses *baseclasses = NULL; + if (token.value != TOKlcurly) + baseclasses = parseBaseClasses(); + + Identifier *id = NULL; + ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses); + + if (token.value != TOKlcurly) + { error("{ members } expected for anonymous class"); + cd->members = NULL; + } + else + { + nextToken(); + Array *decl = parseDeclDefs(0); + if (token.value != TOKrcurly) + error("class member expected"); + nextToken(); + cd->members = decl; + } + + e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments); + + return e; + } + +#if LTORARRAYDECL + t = parseBasicType(); + t = parseBasicType2(t); + if (t->ty == Taarray) + { + Type *index = ((TypeAArray *)t)->index; + + Expression *e = index->toExpression(); + if (e) + { arguments = new Expressions(); + arguments->push(e); + t = new TypeDArray(t->next); + } + else + { + error("need size of rightmost array, not type %s", index->toChars()); + return new NullExp(loc); + } + } + else if (t->ty == Tsarray) + { + TypeSArray *tsa = (TypeSArray *)t; + Expression *e = tsa->dim; + + arguments = new Expressions(); + arguments->push(e); + t = new TypeDArray(t->next); + } + else if (token.value == TOKlparen) + { + arguments = parseArguments(); + } +#else + t = parseBasicType(); + while (token.value == TOKmul) + { t = new TypePointer(t); + nextToken(); + } + if (token.value == TOKlbracket) + { + Expression *e; + + nextToken(); + e = parseAssignExp(); + arguments = new Array(); + arguments->push(e); + check(TOKrbracket); + t = parseDeclarator(t, NULL); + t = new TypeDArray(t); + } + else if (token.value == TOKlparen) + arguments = parseArguments(); +#endif + e = new NewExp(loc, thisexp, newargs, t, arguments); + return e; +} + +/********************************************** + */ + +void Parser::addComment(Dsymbol *s, unsigned char *blockComment) +{ + s->addComment(combineComments(blockComment, token.lineComment)); + token.lineComment = NULL; +} + + +/********************************* ***************************/ +
--- a/dmd/root/async.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/root/async.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,177 +1,182 @@ - -#define _MT 1 - -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#if _WIN32 - -#include <windows.h> -#include <stdio.h> -#include <errno.h> -#include <process.h> - -#include "root.h" -#include "rmem.h" - -static unsigned __stdcall startthread(void *p); - -struct FileData -{ - File *file; - int result; - HANDLE event; -}; - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); - - HANDLE hThread; - - size_t filesdim; - size_t filesmax; - FileData files[1]; -}; - - -AsyncRead *AsyncRead::create(size_t nfiles) -{ - AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); - aw->filesmax = nfiles; - return aw; -} - -void AsyncRead::addFile(File *file) -{ - //printf("addFile(file = %p)\n", file); - //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); - assert(filesdim < filesmax); - files[filesdim].file = file; - files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL); - ResetEvent(files[filesdim].event); - filesdim++; -} - -void AsyncRead::start() -{ - unsigned threadaddr; - hThread = (HANDLE) _beginthreadex(NULL, - 0, - &startthread, - this, - 0, - (unsigned *)&threadaddr); - - if (hThread) - { - SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST); - } - else - { - assert(0); - } -} - -int AsyncRead::read(size_t i) -{ - FileData *f = &files[i]; - WaitForSingleObject(f->event, INFINITE); - Sleep(0); // give up time slice - return f->result; -} - -void AsyncRead::dispose(AsyncRead *aw) -{ - delete aw; -} - - - -unsigned __stdcall startthread(void *p) -{ - AsyncRead *aw = (AsyncRead *)p; - - for (size_t i = 0; i < aw->filesdim; i++) - { FileData *f = &aw->files[i]; - - f->result = f->file->read(); - SetEvent(f->event); - } - _endthreadex(EXIT_SUCCESS); - return EXIT_SUCCESS; // if skidding -} - -#else - -#include <stdio.h> -#include <errno.h> - -#include "root.h" -#include "rmem.h" - -struct FileData -{ - File *file; - int result; - //HANDLE event; -}; - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); - - //HANDLE hThread; - - size_t filesdim; - size_t filesmax; - FileData files[1]; -}; - - -AsyncRead *AsyncRead::create(size_t nfiles) -{ - AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); - aw->filesmax = nfiles; - return aw; -} - -void AsyncRead::addFile(File *file) -{ - //printf("addFile(file = %p)\n", file); - //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); - assert(filesdim < filesmax); - files[filesdim].file = file; - //files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL); - //ResetEvent(files[filesdim].event); - filesdim++; -} - -void AsyncRead::start() -{ -} - -int AsyncRead::read(size_t i) -{ - FileData *f = &files[i]; - f->result = f->file->read(); - return f->result; -} - -void AsyncRead::dispose(AsyncRead *aw) -{ - delete aw; -} - -#endif + +#define _MT 1 + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#if _WIN32 + +#include <windows.h> +#include <stdio.h> +#include <errno.h> +#include <process.h> + +#include "root.h" +#include "rmem.h" + +static unsigned __stdcall startthread(void *p); + +struct FileData +{ + File *file; + int result; + HANDLE event; +}; + +struct AsyncRead +{ + static AsyncRead *create(size_t nfiles); + void addFile(File *file); + void start(); + int read(size_t i); + static void dispose(AsyncRead *); + + HANDLE hThread; + + size_t filesdim; + size_t filesmax; + FileData files[1]; +}; + + +AsyncRead *AsyncRead::create(size_t nfiles) +{ + AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + + (nfiles - 1) * sizeof(FileData)); + aw->filesmax = nfiles; + return aw; +} + +void AsyncRead::addFile(File *file) +{ + //printf("addFile(file = %p)\n", file); + //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); + assert(filesdim < filesmax); + files[filesdim].file = file; + files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL); + ResetEvent(files[filesdim].event); + filesdim++; +} + +void AsyncRead::start() +{ + //printf("aw->filesdim = %p %d\n", this, filesdim); + if (filesdim) + { + unsigned threadaddr; + hThread = (HANDLE) _beginthreadex(NULL, + 0, + &startthread, + this, + 0, + (unsigned *)&threadaddr); + + if (hThread) + { + SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST); + } + else + { + assert(0); + } + } +} + +int AsyncRead::read(size_t i) +{ + FileData *f = &files[i]; + WaitForSingleObject(f->event, INFINITE); + Sleep(0); // give up time slice + return f->result; +} + +void AsyncRead::dispose(AsyncRead *aw) +{ + delete aw; +} + + + +unsigned __stdcall startthread(void *p) +{ + AsyncRead *aw = (AsyncRead *)p; + + //printf("aw->filesdim = %p %d\n", aw, aw->filesdim); + for (size_t i = 0; i < aw->filesdim; i++) + { FileData *f = &aw->files[i]; + + f->result = f->file->read(); + SetEvent(f->event); + } + _endthreadex(EXIT_SUCCESS); + return EXIT_SUCCESS; // if skidding +} + +#else + +#include <stdio.h> +#include <errno.h> + +#include "root.h" +#include "rmem.h" + +struct FileData +{ + File *file; + int result; + //HANDLE event; +}; + +struct AsyncRead +{ + static AsyncRead *create(size_t nfiles); + void addFile(File *file); + void start(); + int read(size_t i); + static void dispose(AsyncRead *); + + //HANDLE hThread; + + size_t filesdim; + size_t filesmax; + FileData files[1]; +}; + + +AsyncRead *AsyncRead::create(size_t nfiles) +{ + AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + + (nfiles - 1) * sizeof(FileData)); + aw->filesmax = nfiles; + return aw; +} + +void AsyncRead::addFile(File *file) +{ + //printf("addFile(file = %p)\n", file); + //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); + assert(filesdim < filesmax); + files[filesdim].file = file; + //files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL); + //ResetEvent(files[filesdim].event); + filesdim++; +} + +void AsyncRead::start() +{ +} + +int AsyncRead::read(size_t i) +{ + FileData *f = &files[i]; + f->result = f->file->read(); + return f->result; +} + +void AsyncRead::dispose(AsyncRead *aw) +{ + delete aw; +} + +#endif
--- a/dmd/root/man.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/root/man.c Fri Nov 06 23:58:01 2009 +0100 @@ -37,7 +37,7 @@ pid_t childpid; const char *args[3]; - char *browser = getenv("BROWSER"); + const char *browser = getenv("BROWSER"); if (browser) browser = strdup(browser); else
--- a/dmd/root/root.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/root/root.c Fri Nov 06 23:58:01 2009 +0100 @@ -415,10 +415,12 @@ continue; #endif +#if 0 case ' ': case '\t': // tabs in filenames? if (!instring) // if not in string break; // treat as end of path +#endif default: Ldefault: buf.writeByte(c);
--- a/dmd/scope.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/scope.c Fri Nov 06 23:58:01 2009 +0100 @@ -71,6 +71,7 @@ this->nofree = 0; this->noctor = 0; this->noaccesscheck = 0; + this->mustsemantic = 0; this->intypeof = 0; this->parameterSpecialization = 0; this->callSuper = 0; @@ -119,6 +120,7 @@ this->nofree = 0; this->noctor = enclosing->noctor; this->noaccesscheck = enclosing->noaccesscheck; + this->mustsemantic = enclosing->mustsemantic; this->intypeof = enclosing->intypeof; this->parameterSpecialization = enclosing->parameterSpecialization; this->callSuper = enclosing->callSuper; @@ -282,7 +284,7 @@ //printf("\t\tsc->scopesym = %p\n", sc->scopesym); if (!sc->scopesym->symtab) sc->scopesym->symtab = new DsymbolTable(); - return sc->scopesym->symtab->insert(s); + return sc->scopesym->symtabInsert(s); } } assert(0);
--- a/dmd/scope.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/scope.h Fri Nov 06 23:58:01 2009 +0100 @@ -1,125 +1,126 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_SCOPE_H -#define DMD_SCOPE_H - -#ifdef __DMC__ -#pragma once -#endif - -struct Dsymbol; -struct ScopeDsymbol; -struct Array; -struct Identifier; -struct Module; -struct Statement; -struct SwitchStatement; -struct TryFinallyStatement; -struct LabelStatement; -struct ForeachStatement; -struct ClassDeclaration; -struct AggregateDeclaration; -struct AnonymousAggregateDeclaration; -struct FuncDeclaration; -struct DocComment; -struct TemplateInstance; - -#if IN_LLVM -struct EnclosingHandler; -struct AnonDeclaration; -#endif - -#if __GNUC__ -// Requires a full definition for PROT and LINK -#include "dsymbol.h" // PROT -#include "mars.h" // LINK -#else -enum LINK; -enum PROT; -#endif - -struct Scope -{ - Scope *enclosing; // enclosing Scope - - Module *module; // Root module - ScopeDsymbol *scopesym; // current symbol - ScopeDsymbol *sd; // if in static if, and declaring new symbols, - // sd gets the addMember() - FuncDeclaration *func; // function we are in - Dsymbol *parent; // parent to use - LabelStatement *slabel; // enclosing labelled statement - SwitchStatement *sw; // enclosing switch statement - TryFinallyStatement *enclosingFinally; // enclosing try finally statement; set inside its finally block - TemplateInstance *tinst; // enclosing template instance - Statement *enclosingScopeExit; // enclosing statement that wants to do something on scope exit - Statement *sbreak; // enclosing statement that supports "break" - Statement *scontinue; // enclosing statement that supports "continue" - ForeachStatement *fes; // if nested function for ForeachStatement, this is it - unsigned offset; // next offset to use in aggregate - int inunion; // we're processing members of a union - int incontract; // we're inside contract code - int nofree; // set if shouldn't free it - int noctor; // set if constructor calls aren't allowed - int intypeof; // in typeof(exp) - int parameterSpecialization; // if in template parameter specialization - int noaccesscheck; // don't do access checks - - unsigned callSuper; // primitive flow analysis for constructors -#define CSXthis_ctor 1 // called this() -#define CSXsuper_ctor 2 // called super() -#define CSXthis 4 // referenced this -#define CSXsuper 8 // referenced super -#define CSXlabel 0x10 // seen a label -#define CSXreturn 0x20 // seen a return statement -#define CSXany_ctor 0x40 // either this() or super() was called - - unsigned structalign; // alignment for struct members - enum LINK linkage; // linkage for external functions - - enum PROT protection; // protection for class members - int explicitProtection; // set if in an explicit protection attribute - - unsigned stc; // storage class - - unsigned flags; -#define SCOPEctor 1 // constructor type -#define SCOPEstaticif 2 // inside static if -#define SCOPEfree 4 // is on free list - - AnonymousAggregateDeclaration *anonAgg; // for temporary analysis - - DocComment *lastdc; // documentation comment for last symbol at this scope - unsigned lastoffset; // offset in docbuf of where to insert next dec - OutBuffer *docbuf; // buffer for documentation output - - static Scope *freelist; - static void *operator new(size_t sz); - static Scope *createGlobal(Module *module); - - Scope(); - Scope(Module *module); - Scope(Scope *enclosing); - - Scope *push(); - Scope *push(ScopeDsymbol *ss); - Scope *pop(); - - void mergeCallSuper(Loc loc, unsigned cs); - - Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); - Dsymbol *insert(Dsymbol *s); - - ClassDeclaration *getClassScope(); - AggregateDeclaration *getStructClassScope(); - void setNoFree(); -}; - -#endif /* DMD_SCOPE_H */ + +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_SCOPE_H +#define DMD_SCOPE_H + +#ifdef __DMC__ +#pragma once +#endif + +struct Dsymbol; +struct ScopeDsymbol; +struct Array; +struct Identifier; +struct Module; +struct Statement; +struct SwitchStatement; +struct TryFinallyStatement; +struct LabelStatement; +struct ForeachStatement; +struct ClassDeclaration; +struct AggregateDeclaration; +struct AnonymousAggregateDeclaration; +struct FuncDeclaration; +struct DocComment; +struct TemplateInstance; + +#if IN_LLVM +struct EnclosingHandler; +struct AnonDeclaration; +#endif + +#if __GNUC__ +// Requires a full definition for PROT and LINK +#include "dsymbol.h" // PROT +#include "mars.h" // LINK +#else +enum LINK; +enum PROT; +#endif + +struct Scope +{ + Scope *enclosing; // enclosing Scope + + Module *module; // Root module + ScopeDsymbol *scopesym; // current symbol + ScopeDsymbol *sd; // if in static if, and declaring new symbols, + // sd gets the addMember() + FuncDeclaration *func; // function we are in + Dsymbol *parent; // parent to use + LabelStatement *slabel; // enclosing labelled statement + SwitchStatement *sw; // enclosing switch statement + TryFinallyStatement *enclosingFinally; // enclosing try finally statement; set inside its finally block + TemplateInstance *tinst; // enclosing template instance + Statement *enclosingScopeExit; // enclosing statement that wants to do something on scope exit + Statement *sbreak; // enclosing statement that supports "break" + Statement *scontinue; // enclosing statement that supports "continue" + ForeachStatement *fes; // if nested function for ForeachStatement, this is it + unsigned offset; // next offset to use in aggregate + int inunion; // we're processing members of a union + int incontract; // we're inside contract code + int nofree; // set if shouldn't free it + int noctor; // set if constructor calls aren't allowed + int intypeof; // in typeof(exp) + int parameterSpecialization; // if in template parameter specialization + int noaccesscheck; // don't do access checks + int mustsemantic; // cannot defer semantic() + + unsigned callSuper; // primitive flow analysis for constructors +#define CSXthis_ctor 1 // called this() +#define CSXsuper_ctor 2 // called super() +#define CSXthis 4 // referenced this +#define CSXsuper 8 // referenced super +#define CSXlabel 0x10 // seen a label +#define CSXreturn 0x20 // seen a return statement +#define CSXany_ctor 0x40 // either this() or super() was called + + unsigned structalign; // alignment for struct members + enum LINK linkage; // linkage for external functions + + enum PROT protection; // protection for class members + int explicitProtection; // set if in an explicit protection attribute + + unsigned stc; // storage class + + unsigned flags; +#define SCOPEctor 1 // constructor type +#define SCOPEstaticif 2 // inside static if +#define SCOPEfree 4 // is on free list + + AnonymousAggregateDeclaration *anonAgg; // for temporary analysis + + DocComment *lastdc; // documentation comment for last symbol at this scope + unsigned lastoffset; // offset in docbuf of where to insert next dec + OutBuffer *docbuf; // buffer for documentation output + + static Scope *freelist; + static void *operator new(size_t sz); + static Scope *createGlobal(Module *module); + + Scope(); + Scope(Module *module); + Scope(Scope *enclosing); + + Scope *push(); + Scope *push(ScopeDsymbol *ss); + Scope *pop(); + + void mergeCallSuper(Loc loc, unsigned cs); + + Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); + Dsymbol *insert(Dsymbol *s); + + ClassDeclaration *getClassScope(); + AggregateDeclaration *getStructClassScope(); + void setNoFree(); +}; + +#endif /* DMD_SCOPE_H */
--- a/dmd/statement.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/statement.c Fri Nov 06 23:58:01 2009 +0100 @@ -29,6 +29,8 @@ #include "template.h" #include "attrib.h" +extern int os_critsecsize(); + /******************************** Statement ***************************/ Statement::Statement(Loc loc) @@ -144,6 +146,13 @@ return FALSE; } +// Return TRUE if statement has no code in it +int Statement::isEmpty() +{ + //printf("Statement::isEmpty()\n"); + return FALSE; +} + /**************************************** * If this statement has code that needs to run in a finally clause * at the end of the current scope, return that code in the form of @@ -154,7 +163,7 @@ * *sfinally code executed in finally block */ -void Statement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) +void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) { //printf("Statement::scopeCode()\n"); //print(); @@ -175,6 +184,22 @@ } +/******************************** PeelStatement ***************************/ + +PeelStatement::PeelStatement(Statement *s) + : Statement(s->loc) +{ + this->s = s; +} + +Statement *PeelStatement::semantic(Scope *sc) +{ + /* "peel" off this wrapper, and don't run semantic() + * on the result. + */ + return s; +} + /******************************** ExpStatement ***************************/ ExpStatement::ExpStatement(Loc loc, Expression *exp) @@ -236,6 +261,11 @@ return result; } +int ExpStatement::isEmpty() +{ + return exp == NULL; +} + /******************************** CompileStatement ***************************/ @@ -315,7 +345,7 @@ return ds; } -void DeclarationStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) +void DeclarationStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) { //printf("DeclarationStatement::scopeCode()\n"); //print(); @@ -333,7 +363,7 @@ if (v) { Expression *e; - e = v->callScopeDtor(); + e = v->callScopeDtor(sc); if (e) { //printf("dtor is: "); e->print(); @@ -407,7 +437,7 @@ Statement *sexception; Statement *sfinally; - s->scopeCode(&sentry, &sexception, &sfinally); + s->scopeCode(sc, &sentry, &sexception, &sfinally); if (sentry) { sentry = sentry->semantic(sc); @@ -555,11 +585,14 @@ //printf("%s\n", s->toChars()); if (!(result & BEfallthru) && !s->comeFrom()) { - s->warning("statement is not reachable"); + if (s->blockExit() != BEhalt && !s->isEmpty()) + s->warning("statement is not reachable"); } - - result &= ~BEfallthru; - result |= s->blockExit(); + else + { + result &= ~BEfallthru; + result |= s->blockExit(); + } } } return result; @@ -580,6 +613,16 @@ return comefrom; } +int CompoundStatement::isEmpty() +{ + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s && !s->isEmpty()) + return FALSE; + } + return TRUE; +} + /******************************** CompoundDeclarationStatement ***************************/ @@ -813,7 +856,7 @@ Statement *sexception; Statement *sfinally; - statement->scopeCode(&sentry, &sexception, &sfinally); + statement->scopeCode(sc, &sentry, &sexception, &sfinally); if (sfinally) { //printf("adding sfinally\n"); @@ -848,12 +891,19 @@ return statement ? statement->blockExit() : BEfallthru; } + int ScopeStatement::comeFrom() { //printf("ScopeStatement::comeFrom()\n"); return statement ? statement->comeFrom() : FALSE; } +int ScopeStatement::isEmpty() +{ + //printf("ScopeStatement::isEmpty() %d\n", statement ? statement->isEmpty() : TRUE); + return statement ? statement->isEmpty() : TRUE; +} + void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('{'); @@ -884,46 +934,12 @@ Statement *WhileStatement::semantic(Scope *sc) { -#if 0 - if (condition->op == TOKmatch) - { - /* Rewrite while (condition) body as: - * if (condition) - * do - * body - * while ((_match = _match.opNext), _match); - */ - - Expression *ew = new IdentifierExp(0, Id::_match); - ew = new DotIdExp(0, ew, Id::next); - ew = new AssignExp(0, new IdentifierExp(0, Id::_match), ew); - ////ew = new EqualExp(TOKnotequal, 0, ew, new NullExp(0)); - Expression *ev = new IdentifierExp(0, Id::_match); - //ev = new CastExp(0, ev, Type::tvoidptr); - ew = new CommaExp(0, ew, ev); - Statement *sw = new DoStatement(loc, body, ew); - Statement *si = new IfStatement(loc, condition, sw, NULL); - return si->semantic(sc); - } -#endif - - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - condition = condition->checkToBoolean(); - - sc->noctor++; - - Scope *scd = sc->push(); - scd->sbreak = this; - scd->scontinue = this; - if (body) - body = body->semantic(scd); - scd->pop(); - - sc->noctor--; - - return this; + /* Rewrite as a for(;condition;) loop + */ + + Statement *s = new ForStatement(loc, NULL, condition, NULL, body); + s = s->semantic(sc); + return s; } int WhileStatement::hasBreak() @@ -938,11 +954,13 @@ int WhileStatement::usesEH() { + assert(0); return body ? body->usesEH() : 0; } int WhileStatement::blockExit() { + assert(0); //printf("WhileStatement::blockExit(%p)\n", this); int result = BEnone; @@ -973,6 +991,7 @@ int WhileStatement::comeFrom() { + assert(0); if (body) return body->comeFrom(); return FALSE; @@ -1124,6 +1143,7 @@ if (increment) { increment = increment->semantic(sc); increment = resolveProperties(sc, increment); + increment = increment->optimize(0); } sc->sbreak = this; @@ -1136,14 +1156,14 @@ return this; } -void ForStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) +void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) { //printf("ForStatement::scopeCode()\n"); //print(); if (init) - init->scopeCode(sentry, sexception, sfinally); + init->scopeCode(sc, sentry, sexception, sfinally); else - Statement::scopeCode(sentry, sexception, sfinally); + Statement::scopeCode(sc, sentry, sexception, sfinally); } int ForStatement::hasBreak() @@ -1173,6 +1193,10 @@ if (condition) { if (condition->canThrow()) result |= BEthrow; + if (condition->isBool(TRUE)) + result &= ~BEfallthru; + else if (condition->isBool(FALSE)) + return result; } else result &= ~BEfallthru; // the body must do the exiting @@ -1352,9 +1376,8 @@ error("no storage class for value %s", arg->ident->toChars()); Dsymbol *var; if (te) - { - if (e->type->toBasetype()->ty == Tfunction && - e->op == TOKvar) + { Type *tb = e->type->toBasetype(); + if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar) { VarExp *ve = (VarExp *)e; var = new AliasDeclaration(loc, arg->ident, ve->var); } @@ -1439,29 +1462,79 @@ for (size_t i = 0; i < dim; i++) { // Declare args Argument *arg = (Argument *)arguments->data[i]; + Type *argtype = arg->type->semantic(loc, sc); VarDeclaration *var; - var = new VarDeclaration(loc, arg->type, arg->ident, NULL); + var = new VarDeclaration(loc, argtype, arg->ident, NULL); var->storage_class |= STCforeach; var->storage_class |= arg->storageClass & (STCin | STCout | STCref); -#if 1 - DeclarationExp *de = new DeclarationExp(loc, var); - de->semantic(sc); -#else - var->semantic(sc); - if (!sc->insert(var)) - error("%s already defined", var->ident->toChars()); -#endif + if (dim == 2 && i == 0) key = var; else value = var; +#if 0 + DeclarationExp *de = new DeclarationExp(loc, var); + de->semantic(sc); +#endif } - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - +#if 1 + { + /* Convert to a ForStatement + * foreach (key, value; a) body => + * for (T[] tmp = a[], size_t key; key < tmp.length; ++key) + * { T value = tmp[k]; body } + * + * foreach_reverse (key, value; a) body => + * for (T[] tmp = a[], size_t key = tmp.length; key--; ) + * { T value = tmp[k]; body } + */ + Identifier *id = Lexer::uniqueId("__aggr"); + ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, aggr, NULL, NULL)); + VarDeclaration *tmp = new VarDeclaration(loc, aggr->type->nextOf()->arrayOf(), id, ie); + + Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length); + + if (!key) + { + Identifier *id = Lexer::uniqueId("__key"); + key = new VarDeclaration(loc, Type::tsize_t, id, NULL); + } + if (op == TOKforeach_reverse) + key->init = new ExpInitializer(loc, tmp_length); + else + 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))); + Statement *forinit = new CompoundDeclarationStatement(loc, cs); + + Expression *cond; + if (op == TOKforeach_reverse) + // key-- + cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); + else + // key < tmp.length + cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), tmp_length); + + Expression *increment = NULL; + if (op == TOKforeach) + // key += 1 + increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); + + // 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)); + + body = new CompoundStatement(loc, ds, body); + + ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); + s = fs->semantic(sc); + break; + } +#else if (!value->type->equals(tab->next)) { if (aggr->op == TOKstring) @@ -1471,20 +1544,28 @@ tab->toChars(), value->type->toChars()); } - if (key && key->type->ty != Tint32 && key->type->ty != Tuns32) + if (key) { - if (global.params.is64bit) + if (key->type->ty != Tint32 && key->type->ty != Tuns32) { - if (key->type->ty != Tint64 && key->type->ty != Tuns64) - error("foreach: key type must be int or uint, long or ulong, not %s", key->type->toChars()); + if (global.params.is64bit) + { + if (key->type->ty != Tint64 && key->type->ty != Tuns64) + error("foreach: key type must be int or uint, long or ulong, not %s", key->type->toChars()); + } + else + error("foreach: key type must be int or uint, not %s", key->type->toChars()); } - else - error("foreach: key type must be int or uint, not %s", key->type->toChars()); + + if (key->storage_class & (STCout | STCref)) + error("foreach: key cannot be out or ref"); } - if (key && key->storage_class & (STCout | STCref)) - error("foreach: key cannot be out or ref"); + sc->sbreak = this; + sc->scontinue = this; + body = body->semantic(sc); break; +#endif case Taarray: taa = (TypeAArray *)tab; @@ -1504,9 +1585,9 @@ #if DMDV2 { /* Look for range iteration, i.e. the properties * .empty, .next, .retreat, .head and .rear - * foreach (e; range) { ... } + * foreach (e; aggr) { ... } * translates to: - * for (auto __r = range; !__r.empty; __r.next) + * for (auto __r = aggr[]; !__r.empty; __r.next) * { auto e = __r.head; * ... * } @@ -1523,7 +1604,7 @@ idnext = Id::Fnext; } else - { idhead = Id::Frear; + { idhead = Id::Ftoe; idnext = Id::Fretreat; } Dsymbol *shead = search_function(ad, idhead); @@ -1533,9 +1614,15 @@ /* Generate a temporary __r and initialize it with the aggregate. */ Identifier *id = Identifier::generateId("__r"); - VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, aggr)); - r->semantic(sc); + Expression *rinit = new SliceExp(loc, aggr, NULL, NULL); + rinit = rinit->trySemantic(sc); + if (!rinit) // if application of [] failed + rinit = aggr; + 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); +//printf("init: %s\n", init->toChars()); // !__r.empty Expression *e = new VarExp(loc, r); @@ -1551,11 +1638,11 @@ */ e = new VarExp(loc, r); Expression *einit = new DotIdExp(loc, e, idhead); - einit = einit->semantic(sc); +// einit = einit->semantic(sc); Argument *arg = (Argument *)arguments->data[0]; VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); ve->storage_class |= STCforeach; - ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STCconst | STCinvariant); + ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); DeclarationExp *de = new DeclarationExp(loc, ve); @@ -1563,6 +1650,12 @@ new DeclarationStatement(loc, de), this->body); s = new ForStatement(loc, init, condition, increment, body); +#if 0 + printf("init: %s\n", init->toChars()); + printf("condition: %s\n", condition->toChars()); + printf("increment: %s\n", increment->toChars()); + printf("body: %s\n", body->toChars()); +#endif s = s->semantic(sc); break; } @@ -1837,6 +1930,7 @@ default: error("foreach: %s is not an aggregate type", aggr->type->toChars()); + s = NULL; // error recovery break; } sc->noctor--; @@ -1872,6 +1966,7 @@ return result; } + int ForeachStatement::comeFrom() { if (body) @@ -1908,6 +2003,216 @@ buf->writenl(); } +/**************************** ForeachRangeStatement ***************************/ + +#if DMDV2 + +ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg, + Expression *lwr, Expression *upr, Statement *body) + : Statement(loc) +{ + this->op = op; + this->arg = arg; + this->lwr = lwr; + this->upr = upr; + this->body = body; + + this->key = NULL; +} + +Statement *ForeachRangeStatement::syntaxCopy() +{ + ForeachRangeStatement *s = new ForeachRangeStatement(loc, op, + arg->syntaxCopy(), + lwr->syntaxCopy(), + upr->syntaxCopy(), + body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *ForeachRangeStatement::semantic(Scope *sc) +{ + //printf("ForeachRangeStatement::semantic() %p\n", this); + ScopeDsymbol *sym; + Statement *s = this; + + lwr = lwr->semantic(sc); + lwr = resolveProperties(sc, lwr); + lwr = lwr->optimize(WANTvalue); + if (!lwr->type) + { + error("invalid range lower bound %s", lwr->toChars()); + return this; + } + + upr = upr->semantic(sc); + upr = resolveProperties(sc, upr); + upr = upr->optimize(WANTvalue); + if (!upr->type) + { + error("invalid range upper bound %s", upr->toChars()); + return this; + } + + if (arg->type) + { + arg->type = arg->type->semantic(loc, sc); + lwr = lwr->implicitCastTo(sc, arg->type); + upr = upr->implicitCastTo(sc, arg->type); + } + else + { + /* Must infer types from lwr and upr + */ + AddExp ea(loc, lwr, upr); + ea.typeCombine(sc); + arg->type = ea.type->mutableOf(); + lwr = ea.e1; + upr = ea.e2; + } +#if 1 + /* Convert to a for loop: + * foreach (key; lwr .. upr) => + * for (auto key = lwr, auto tmp = upr; key < tmp; ++key) + * + * foreach_reverse (key; lwr .. upr) => + * for (auto tmp = lwr, auto key = upr; key-- > tmp;) + */ + + ExpInitializer *ie = new ExpInitializer(loc, (op == TOKforeach) ? lwr : upr); + key = new VarDeclaration(loc, arg->type, arg->ident, ie); + + Identifier *id = Lexer::uniqueId("__limit"); + ie = new ExpInitializer(loc, (op == TOKforeach) ? upr : lwr); + VarDeclaration *tmp = new VarDeclaration(loc, arg->type, id, ie); + + Statements *cs = new Statements(); + // 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))); + } + else + { + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); + } + Statement *forinit = new CompoundDeclarationStatement(loc, cs); + + Expression *cond; + if (op == TOKforeach_reverse) + { // key-- > tmp + cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); + cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp)); + } + else + // key < tmp + cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), new VarExp(loc, tmp)); + + Expression *increment = NULL; + if (op == TOKforeach) + // key += 1 + increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); + + ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); + s = fs->semantic(sc); + return s; +#else + if (!arg->type->isscalar()) + error("%s is not a scalar type", arg->type->toChars()); + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + sc->noctor++; + + key = new VarDeclaration(loc, arg->type, arg->ident, NULL); + DeclarationExp *de = new DeclarationExp(loc, key); + de->semantic(sc); + + if (key->storage_class) + error("foreach range: key cannot have storage class"); + + sc->sbreak = this; + sc->scontinue = this; + body = body->semantic(sc); + + sc->noctor--; + sc->pop(); + return s; +#endif +} + +int ForeachRangeStatement::hasBreak() +{ + return TRUE; +} + +int ForeachRangeStatement::hasContinue() +{ + return TRUE; +} + +int ForeachRangeStatement::usesEH() +{ + assert(0); + return body->usesEH(); +} + +int ForeachRangeStatement::blockExit() +{ + assert(0); + int result = BEfallthru; + + if (lwr && lwr->canThrow()) + result |= BEthrow; + else if (upr && upr->canThrow()) + result |= BEthrow; + + if (body) + { + result |= body->blockExit() & ~(BEbreak | BEcontinue); + } + return result; +} + + +int ForeachRangeStatement::comeFrom() +{ + assert(0); + if (body) + return body->comeFrom(); + return FALSE; +} + +void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); + buf->writestring(" ("); + + if (arg->type) + arg->type->toCBuffer(buf, arg->ident, hgs); + else + buf->writestring(arg->ident->toChars()); + + buf->writestring("; "); + lwr->toCBuffer(buf, hgs); + buf->writestring(" .. "); + upr->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +#endif + /******************************** IfStatement ***************************/ IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody) @@ -2029,6 +2334,7 @@ return result; } + void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("if ("); @@ -2181,10 +2487,10 @@ if (e->op == TOKstring) { StringExp *se = (StringExp *)e; - fprintf(stdmsg, "%.*s", (int)se->len, (char*)se->string); + fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); } else - error("string expected for message, not '%s'", e->toChars()); + fprintf(stdmsg, e->toChars()); } fprintf(stdmsg, "\n"); } @@ -2225,7 +2531,28 @@ { sc->func->allowInlining = true; } - +#if DMDV2 + else if (ident == Id::startaddress) + { + if (!args || args->dim != 1) + error("function name expected for start address"); + else + { + Expression *e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + Dsymbol *sa = getDsymbol(e); + if (!sa || !sa->isFuncDeclaration()) + error("function name expected for start address, not '%s'", e->toChars()); + if (body) + { + body = body->semantic(sc); + } + return this; + } + } +#endif else error("unrecognized pragma(%s)", ident->toChars()); @@ -2253,6 +2580,7 @@ return result; } + void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("pragma ("); @@ -2302,6 +2630,11 @@ return NULL; } +int StaticAssertStatement::blockExit() +{ + return BEfallthru; +} + void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { sa->toCBuffer(buf, hgs); @@ -2425,6 +2758,37 @@ body = cs; } +#if DMDV2 + if (isFinal) + { Type *t = condition->type; + while (t->ty == Ttypedef) + { // Don't use toBasetype() because that will skip past enums + t = ((TypeTypedef *)t)->sym->basetype; + } + if (condition->type->ty == Tenum) + { TypeEnum *te = (TypeEnum *)condition->type; + EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration(); + assert(ed); + size_t dim = ed->members->dim; + for (size_t i = 0; i < dim; i++) + { + EnumMember *em = ((Dsymbol *)ed->members->data[i])->isEnumMember(); + if (em) + { + for (size_t j = 0; j < cases->dim; j++) + { CaseStatement *cs = (CaseStatement *)cases->data[j]; + if (cs->exp->equals(em->value)) + goto L1; + } + error("enum member %s not represented in final switch", em->toChars()); + } + L1: + ; + } + } + } +#endif + sc->pop(); return this; } @@ -2457,6 +2821,7 @@ return result; } + void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("switch ("); @@ -2571,6 +2936,7 @@ return statement->blockExit(); } + int CaseStatement::comeFrom() { return TRUE; @@ -2585,6 +2951,85 @@ statement->toCBuffer(buf, hgs); } +/******************************** CaseRangeStatement ***************************/ + +#if DMDV2 + +CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first, + Expression *last, Statement *s) + : Statement(loc) +{ + this->first = first; + this->last = last; + this->statement = s; +} + +Statement *CaseRangeStatement::syntaxCopy() +{ + CaseRangeStatement *s = new CaseRangeStatement(loc, + first->syntaxCopy(), last->syntaxCopy(), statement->syntaxCopy()); + return s; +} + +Statement *CaseRangeStatement::semantic(Scope *sc) +{ SwitchStatement *sw = sc->sw; + + //printf("CaseRangeStatement::semantic() %s\n", toChars()); + if (sw->isFinal) + error("case ranges not allowed in final switch"); + + 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); + dinteger_t lval = last->toInteger(); + + if (lval - fval > 256) + { error("more than 256 cases in case range"); + lval = fval + 256; + } + + /* This works by replacing the CaseRange with an array of Case's. + * + * case a: .. case b: s; + * => + * case a: + * [...] + * case b: + * s; + */ + + Statements *statements = new Statements(); + for (dinteger_t i = fval; i <= lval; i++) + { + Statement *s = statement; + if (i != lval) + s = new ExpStatement(loc, NULL); + Expression *e = new IntegerExp(loc, i, first->type); + Statement *cs = new CaseStatement(loc, e, s); + statements->push(cs); + } + Statement *s = new CompoundStatement(loc, statements); + s = s->semantic(sc); + return s; +} + +void CaseRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("case "); + first->toCBuffer(buf, hgs); + buf->writestring(": .. case "); + last->toCBuffer(buf, hgs); + buf->writenl(); + statement->toCBuffer(buf, hgs); +} + +#endif + /******************************** DefaultStatement ***************************/ DefaultStatement::DefaultStatement(Loc loc, Statement *s) @@ -2640,6 +3085,7 @@ return statement->blockExit(); } + int DefaultStatement::comeFrom() { return TRUE; @@ -2678,6 +3124,7 @@ return BEgoto; } + void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("goto default;\n"); @@ -2725,6 +3172,7 @@ return BEgoto; } + void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("goto case"); @@ -2748,6 +3196,7 @@ return BEthrow; } + void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("SwitchErrorStatement::toCBuffer()"); @@ -2841,7 +3290,9 @@ fd->nrvo_can = 0; else if (fd->nrvo_var == NULL) { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) + { //printf("Setting nrvo to %s\n", v->toChars()); fd->nrvo_var = v; + } else fd->nrvo_can = 0; } @@ -2944,6 +3395,7 @@ // Construct: { vresult = exp; return cases.dim + 1; } exp = new AssignExp(loc, new VarExp(0, fd->vresult), exp); + exp->op = TOKconstruct; exp = exp->semantic(sc); Statement *s1 = new ExpStatement(loc, exp); Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); @@ -2960,6 +3412,7 @@ VarExp *v = new VarExp(0, fd->vresult); exp = new AssignExp(loc, v, exp); + exp->op = TOKconstruct; exp = exp->semantic(sc); } //exp->dump(0); @@ -2996,7 +3449,7 @@ return gs; } - if (exp && tbret->ty == Tvoid && !fd->isMain()) + if (exp && tbret->ty == Tvoid && !implicit0) { /* Replace: * return exp; @@ -3004,8 +3457,9 @@ * exp; return; */ Statement *s = new ExpStatement(loc, exp); + exp = NULL; + s = s->semantic(sc); loc = 0; - exp = NULL; return new CompoundStatement(loc, s, this); } @@ -3020,6 +3474,7 @@ return result; } + void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->printf("return "); @@ -3112,6 +3567,7 @@ return ident ? BEgoto : BEbreak; } + void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("break"); @@ -3213,6 +3669,7 @@ return ident ? BEgoto : BEcontinue; } + void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("continue"); @@ -3256,21 +3713,87 @@ Statement *SynchronizedStatement::semantic(Scope *sc) { if (exp) - { ClassDeclaration *cd; - + { exp = exp->semantic(sc); exp = resolveProperties(sc, exp); - cd = exp->type->isClassHandle(); + ClassDeclaration *cd = exp->type->isClassHandle(); if (!cd) error("can only synchronize on class objects, not '%s'", exp->type->toChars()); else if (cd->isInterfaceDeclaration()) - { Type *t = new TypeIdentifier(0, Id::Object); + { /* Cast the interface to an object, as the object has the monitor, + * not the interface. + */ + Type *t = new TypeIdentifier(0, Id::Object); t = t->semantic(0, sc); exp = new CastExp(loc, exp, t); exp = exp->semantic(sc); } + +#if 0 + /* Rewrite as: + * auto tmp = exp; + * _d_monitorenter(tmp); + * try { body } finally { _d_monitorexit(tmp); } + */ + Identifier *id = Lexer::uniqueId("__sync"); + ExpInitializer *ie = new ExpInitializer(loc, exp); + VarDeclaration *tmp = new VarDeclaration(loc, exp->type, id, ie); + + Statements *cs = new Statements(); + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + + FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorenter); + Expression *e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp)); + e->type = Type::tvoid; // do not run semantic on e + cs->push(new ExpStatement(loc, e)); + + FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorexit); + e = new CallExp(loc, new VarExp(loc, fdexit), new VarExp(loc, tmp)); + e->type = Type::tvoid; // do not run semantic on e + Statement *s = new ExpStatement(loc, e); + s = new TryFinallyStatement(loc, body, s); + cs->push(s); + + s = new CompoundStatement(loc, cs); + return s->semantic(sc); +#endif } +#if 0 + else + { /* Generate our own critical section, then rewrite as: + * __gshared byte[CriticalSection.sizeof] critsec; + * _d_criticalenter(critsec.ptr); + * try { body } finally { _d_criticalexit(critsec.ptr); } + */ + Identifier *id = Lexer::uniqueId("__critsec"); + Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + os_critsecsize())); + 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))); + + FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalenter); + Expression *e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); + e = e->semantic(sc); + e = new CallExp(loc, new VarExp(loc, fdenter), e); + e->type = Type::tvoid; // do not run semantic on e + cs->push(new ExpStatement(loc, e)); + + FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalexit); + e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); + e = e->semantic(sc); + e = new CallExp(loc, new VarExp(loc, fdexit), e); + e->type = Type::tvoid; // do not run semantic on e + Statement *s = new ExpStatement(loc, e); + s = new TryFinallyStatement(loc, body, s); + cs->push(s); + + s = new CompoundStatement(loc, cs); + return s->semantic(sc); + } +#endif if (body) { Statement* oldScopeExit = sc->enclosingScopeExit; @@ -3301,6 +3824,7 @@ return body ? body->blockExit() : BEfallthru; } + void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("synchronized"); @@ -3418,6 +3942,7 @@ return result; } + /******************************** TryCatchStatement ***************************/ TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) @@ -3462,6 +3987,11 @@ error("catch at %s hides catch at %s", sj, si); } } + + if (!body || body->isEmpty()) + { + return NULL; + } return this; } @@ -3476,10 +4006,9 @@ } int TryCatchStatement::blockExit() -{ int result; - +{ assert(body); - result = body->blockExit(); + int result = body->blockExit(); for (size_t i = 0; i < catches->dim; i++) { @@ -3689,7 +4218,7 @@ return (tok != TOKon_scope_success); } -void OnScopeStatement::scopeCode(Statement **sentry, Statement **sexception, Statement **sfinally) +void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) { //printf("OnScopeStatement::scopeCode()\n"); //print(); @@ -3770,6 +4299,7 @@ return BEthrow; // obviously } + void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->printf("throw "); @@ -3827,6 +4357,7 @@ return statement ? statement->blockExit() : BEfallthru; } + void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("volatile"); @@ -3892,6 +4423,7 @@ return BEgoto; } + void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("goto "); @@ -3983,6 +4515,7 @@ return statement ? statement->blockExit() : BEfallthru; } + int LabelStatement::comeFrom() { //printf("LabelStatement::comeFrom()\n");
--- a/dmd/statement.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/statement.h Fri Nov 06 23:58:01 2009 +0100 @@ -1,889 +1,919 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_STATEMENT_H -#define DMD_STATEMENT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" - -#include "arraytypes.h" -#include "dsymbol.h" -#include "lexer.h" - -struct OutBuffer; -struct Scope; -struct Expression; -struct LabelDsymbol; -struct Identifier; -struct IfStatement; -struct DeclarationStatement; -struct DefaultStatement; -struct VarDeclaration; -struct Condition; -struct Module; -struct Token; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct ReturnStatement; -struct CompoundStatement; -struct Argument; -struct StaticAssert; -struct AsmStatement; -struct AsmBlockStatement; -struct GotoStatement; -struct ScopeStatement; -struct TryCatchStatement; -struct TryFinallyStatement; -struct HdrGenState; -struct InterState; -struct CaseStatement; -struct LabelStatement; -struct VolatileStatement; -struct SynchronizedStatement; - -enum TOK; - -namespace llvm -{ - class Value; - class BasicBlock; - class ConstantInt; -} - -// Back end -struct IRState; -struct Blockx; -#if IN_LLVM -struct DValue; -typedef DValue elem; -#endif - -#if IN_GCC -union tree_node; typedef union tree_node block; -//union tree_node; typedef union tree_node elem; -#else -struct block; -//struct elem; -#endif -struct code; - -/* How a statement exits; this is returned by blockExit() - */ -enum BE -{ - BEnone = 0, - BEfallthru = 1, - BEthrow = 2, - BEreturn = 4, - BEgoto = 8, - BEhalt = 0x10, - BEbreak = 0x20, - BEcontinue = 0x40, - BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), -}; - -struct Statement : Object -{ - Loc loc; - - Statement(Loc loc); - virtual Statement *syntaxCopy(); - - void print(); - char *toChars(); - - void error(const char *format, ...) IS_PRINTF(2); - void warning(const char *format, ...) IS_PRINTF(2); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual TryCatchStatement *isTryCatchStatement() { return NULL; } - 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); - virtual int hasBreak(); - virtual int hasContinue(); - virtual int usesEH(); - virtual int blockExit(); - virtual int comeFrom(); - virtual void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally); - virtual Statements *flatten(Scope *sc); - virtual Expression *interpret(InterState *istate); - - virtual int inlineCost(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Statement *inlineScan(InlineScanState *iss); - - // Back end - virtual void toIR(IRState *irs); - - // Avoid dynamic_cast - virtual DeclarationStatement *isDeclarationStatement() { return NULL; } - virtual CompoundStatement *isCompoundStatement() { return NULL; } - virtual ReturnStatement *isReturnStatement() { return NULL; } - virtual IfStatement *isIfStatement() { return NULL; } - virtual CaseStatement* isCaseStatement() { return NULL; } - - // LDC - virtual void toNakedIR(IRState *irs); - virtual AsmBlockStatement* endsWithAsm(); -}; - -struct ExpStatement : Statement -{ - Expression *exp; - - ExpStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - // LDC - void toNakedIR(IRState *irs); -}; - -struct CompileStatement : Statement -{ - Expression *exp; - - CompileStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statements *flatten(Scope *sc); - 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(Statement **sentry, Statement **sexit, Statement **sfinally); - - DeclarationStatement *isDeclarationStatement() { return this; } -}; - -struct CompoundStatement : Statement -{ - Statements *statements; - - CompoundStatement(Loc loc, Statements *s); - CompoundStatement(Loc loc, Statement *s1, Statement *s2); - virtual Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(); - int comeFrom(); - virtual Statements *flatten(Scope *sc); - ReturnStatement *isReturnStatement(); - Expression *interpret(InterState *istate); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - virtual void toIR(IRState *irs); - - // LDC - virtual void toNakedIR(IRState *irs); - virtual AsmBlockStatement* endsWithAsm(); - - virtual CompoundStatement *isCompoundStatement() { return this; } -}; - -struct CompoundDeclarationStatement : CompoundStatement -{ - CompoundDeclarationStatement(Loc loc, Statements *s); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -/* The purpose of this is so that continue will go to the next - * of the statements, and break will go to the end of the statements. - */ -struct UnrolledLoopStatement : Statement -{ - Statements *statements; - - UnrolledLoopStatement(Loc loc, Statements *statements); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ScopeStatement : Statement -{ - Statement *statement; - - ScopeStatement(Loc loc, Statement *s); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - ScopeStatement *isScopeStatement() { return this; } - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct WhileStatement : Statement -{ - Expression *condition; - Statement *body; - - WhileStatement(Loc loc, Expression *c, Statement *b); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct DoStatement : Statement -{ - Statement *body; - Expression *condition; - - DoStatement(Loc loc, Statement *b, Expression *c); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ForStatement : Statement -{ - Statement *init; - Expression *condition; - Expression *increment; - Statement *body; - - ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ForeachStatement : Statement -{ - enum TOK op; // TOKforeach or TOKforeach_reverse - Arguments *arguments; // array of Argument*'s - Expression *aggr; - Statement *body; - - VarDeclaration *key; - VarDeclaration *value; - - FuncDeclaration *func; // function we're lexically in - - Array cases; // put breaks, continues, gotos and returns here - Array gotos; // forward referenced goto's go here - - ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, Expression *aggr, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -#if DMDV2 -struct ForeachRangeStatement : Statement -{ - enum TOK op; // TOKforeach or TOKforeach_reverse - Argument *arg; // loop index variable - Expression *lwr; - Expression *upr; - Statement *body; - - VarDeclaration *key; - - ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg, - Expression *lwr, Expression *upr, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; -#endif - -struct IfStatement : Statement -{ - Argument *arg; - Expression *condition; - Statement *ifbody; - Statement *elsebody; - - VarDeclaration *match; // for MatchExpression results - - IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int usesEH(); - int blockExit(); - IfStatement *isIfStatement() { return this; } - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ConditionalStatement : Statement -{ - Condition *condition; - Statement *ifbody; - Statement *elsebody; - - ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int usesEH(); - int blockExit(); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct PragmaStatement : Statement -{ - Identifier *ident; - Expressions *args; // array of Expression's - Statement *body; - - PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct StaticAssertStatement : Statement -{ - StaticAssert *sa; - - StaticAssertStatement(StaticAssert *sa); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct SwitchStatement : Statement -{ - Expression *condition; - Statement *body; - - DefaultStatement *sdefault; - - Array gotoCases; // array of unresolved GotoCaseStatement's - Array *cases; // array of CaseStatement's - int hasNoDefault; // !=0 if no default statement - - // LDC - Statement *enclosingScopeExit; - - SwitchStatement(Loc loc, Expression *c, Statement *b); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int usesEH(); - int blockExit(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct CaseStatement : Statement -{ - Expression *exp; - Statement *statement; - int index; // which case it is (since we sort this) - block *cblock; // back end: label for the block - - // LDC - Statement *enclosingScopeExit; - - CaseStatement(Loc loc, Expression *exp, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int compare(Object *obj); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - CaseStatement* isCaseStatement() { return this; } - - // LDC - llvm::BasicBlock* bodyBB; - llvm::ConstantInt* llvmIdx; -}; - -struct DefaultStatement : Statement -{ - Statement *statement; -#if IN_GCC - block *cblock; // back end: label for the block -#endif - - // LDC - Statement *enclosingScopeExit; - - DefaultStatement(Loc loc, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - // LDC - llvm::BasicBlock* bodyBB; -}; - -struct GotoDefaultStatement : Statement -{ - SwitchStatement *sw; - - GotoDefaultStatement(Loc loc); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct GotoCaseStatement : Statement -{ - Expression *exp; // NULL, or which case to goto - CaseStatement *cs; // case statement it resolves to - SwitchStatement *sw; - - GotoCaseStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct SwitchErrorStatement : Statement -{ - SwitchErrorStatement(Loc loc); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct ReturnStatement : Statement -{ - Expression *exp; - - ReturnStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int blockExit(); - Expression *interpret(InterState *istate); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - ReturnStatement *isReturnStatement() { return this; } -}; - -struct BreakStatement : Statement -{ - Identifier *ident; - - BreakStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -}; - -struct ContinueStatement : Statement -{ - Identifier *ident; - - ContinueStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -}; - -struct SynchronizedStatement : Statement -{ - Expression *exp; - Statement *body; - - SynchronizedStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - -// Back end - elem *esync; - SynchronizedStatement(Loc loc, elem *esync, Statement *body); - void toIR(IRState *irs); - llvm::Value* llsync; -}; - -struct WithStatement : Statement -{ - Expression *exp; - Statement *body; - VarDeclaration *wthis; - - WithStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int usesEH(); - int blockExit(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct TryCatchStatement : Statement -{ - Statement *body; - Array *catches; - - TryCatchStatement(Loc loc, Statement *body, Array *catches); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int usesEH(); - int blockExit(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - TryCatchStatement *isTryCatchStatement() { return this; } -}; - -struct Catch : Object -{ - Loc loc; - Type *type; - Identifier *ident; - VarDeclaration *var; - Statement *handler; - - Catch(Loc loc, Type *t, Identifier *id, Statement *handler); - Catch *syntaxCopy(); - void semantic(Scope *sc); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct TryFinallyStatement : Statement -{ - Statement *body; - Statement *finalbody; - - TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct OnScopeStatement : Statement -{ - TOK tok; - Statement *statement; - - OnScopeStatement(Loc loc, TOK tok, Statement *statement); - Statement *syntaxCopy(); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int usesEH(); - void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally); - - void toIR(IRState *irs); -}; - -struct ThrowStatement : Statement -{ - Expression *exp; - - ThrowStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int blockExit(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct VolatileStatement : Statement -{ - Statement *statement; - - VolatileStatement(Loc loc, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct GotoStatement : Statement -{ - Identifier *ident; - LabelDsymbol *label; - TryFinallyStatement *enclosingFinally; - Statement* enclosingScopeExit; - - GotoStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(); - Expression *interpret(InterState *istate); - - void toIR(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - GotoStatement *isGotoStatement() { return this; } -}; - -struct LabelStatement : Statement -{ - Identifier *ident; - Statement *statement; - TryFinallyStatement *enclosingFinally; - Statement* enclosingScopeExit; - block *lblock; // back end - int isReturnLabel; - - LabelStatement(Loc loc, Identifier *ident, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - // LDC - bool asmLabel; // for labels inside inline assembler - void toNakedIR(IRState *irs); -}; - -struct LabelDsymbol : Dsymbol -{ - LabelStatement *statement; - - LabelDsymbol(Identifier *ident); - LabelDsymbol *isLabel(); -}; - -struct AsmStatement : Statement -{ - Token *tokens; - code *asmcode; - unsigned asmalign; // alignment of this statement - unsigned refparam; // !=0 if function parameter is referenced - unsigned naked; // !=0 if function is to be naked - - AsmStatement(Loc loc, Token *tokens); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(); - int comeFrom(); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual AsmStatement *isAsmStatement() { return this; } - - void toIR(IRState *irs); - - // LDC - // non-zero if this is a branch, contains the target labels identifier - Identifier* isBranchToLabel; - - void toNakedIR(IRState *irs); -}; - -struct AsmBlockStatement : CompoundStatement -{ - TryFinallyStatement* enclosingFinally; - Statement* enclosingScopeExit; - - AsmBlockStatement(Loc loc, Statements *s); - Statements *flatten(Scope *sc); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - - CompoundStatement *isCompoundStatement() { return NULL; } - AsmBlockStatement *isAsmBlockStatement() { return this; } - - void toIR(IRState *irs); - void toNakedIR(IRState *irs); - AsmBlockStatement* endsWithAsm(); - - llvm::Value* abiret; -}; - -#endif /* DMD_STATEMENT_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#ifndef DMD_STATEMENT_H +#define DMD_STATEMENT_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" + +#include "arraytypes.h" +#include "dsymbol.h" +#include "lexer.h" + +struct OutBuffer; +struct Scope; +struct Expression; +struct LabelDsymbol; +struct Identifier; +struct IfStatement; +struct DeclarationStatement; +struct DefaultStatement; +struct VarDeclaration; +struct Condition; +struct Module; +struct Token; +struct InlineCostState; +struct InlineDoState; +struct InlineScanState; +struct ReturnStatement; +struct CompoundStatement; +struct Argument; +struct StaticAssert; +struct AsmStatement; +struct AsmBlockStatement; +struct GotoStatement; +struct ScopeStatement; +struct TryCatchStatement; +struct TryFinallyStatement; +struct HdrGenState; +struct InterState; +struct CaseStatement; +struct LabelStatement; +struct VolatileStatement; +struct SynchronizedStatement; + +enum TOK; + +namespace llvm +{ + class Value; + class BasicBlock; + class ConstantInt; +} + +// Back end +struct IRState; +struct Blockx; +#if IN_LLVM +struct DValue; +typedef DValue elem; +#endif + +#if IN_GCC +union tree_node; typedef union tree_node block; +//union tree_node; typedef union tree_node elem; +#else +struct block; +//struct elem; +#endif +struct code; + +/* How a statement exits; this is returned by blockExit() + */ +enum BE +{ + BEnone = 0, + BEfallthru = 1, + BEthrow = 2, + BEreturn = 4, + BEgoto = 8, + BEhalt = 0x10, + BEbreak = 0x20, + BEcontinue = 0x40, + BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), +}; + +struct Statement : Object +{ + Loc loc; + + Statement(Loc loc); + virtual Statement *syntaxCopy(); + + void print(); + char *toChars(); + + void error(const char *format, ...) IS_PRINTF(2); + void warning(const char *format, ...) IS_PRINTF(2); + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual TryCatchStatement *isTryCatchStatement() { return NULL; } + 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); + virtual int hasBreak(); + virtual int hasContinue(); + virtual int usesEH(); + virtual int blockExit(); + virtual int comeFrom(); + virtual int isEmpty(); + virtual void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + virtual Statements *flatten(Scope *sc); + virtual Expression *interpret(InterState *istate); + + virtual int inlineCost(InlineCostState *ics); + virtual Expression *doInline(InlineDoState *ids); + virtual Statement *inlineScan(InlineScanState *iss); + + // Back end + virtual void toIR(IRState *irs); + + // Avoid dynamic_cast + virtual DeclarationStatement *isDeclarationStatement() { return NULL; } + virtual CompoundStatement *isCompoundStatement() { return NULL; } + virtual ReturnStatement *isReturnStatement() { return NULL; } + virtual IfStatement *isIfStatement() { return NULL; } + virtual CaseStatement* isCaseStatement() { return NULL; } + + // LDC + virtual void toNakedIR(IRState *irs); + virtual AsmBlockStatement* endsWithAsm(); +}; + +struct PeelStatement : Statement +{ + Statement *s; + + PeelStatement(Statement *s); + Statement *semantic(Scope *sc); +}; + +struct ExpStatement : Statement +{ + Expression *exp; + + ExpStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + int isEmpty(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + // LDC + void toNakedIR(IRState *irs); +}; + +struct CompileStatement : Statement +{ + Expression *exp; + + CompileStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statements *flatten(Scope *sc); + 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; + + CompoundStatement(Loc loc, Statements *s); + CompoundStatement(Loc loc, Statement *s1, Statement *s2); + virtual Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual Statement *semantic(Scope *sc); + int usesEH(); + int blockExit(); + int comeFrom(); + int isEmpty(); + virtual Statements *flatten(Scope *sc); + ReturnStatement *isReturnStatement(); + Expression *interpret(InterState *istate); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + virtual void toIR(IRState *irs); + + // LDC + virtual void toNakedIR(IRState *irs); + virtual AsmBlockStatement* endsWithAsm(); + + virtual CompoundStatement *isCompoundStatement() { return this; } +}; + +struct CompoundDeclarationStatement : CompoundStatement +{ + CompoundDeclarationStatement(Loc loc, Statements *s); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +/* The purpose of this is so that continue will go to the next + * of the statements, and break will go to the end of the statements. + */ +struct UnrolledLoopStatement : Statement +{ + Statements *statements; + + UnrolledLoopStatement(Loc loc, Statements *statements); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct ScopeStatement : Statement +{ + Statement *statement; + + ScopeStatement(Loc loc, Statement *s); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + ScopeStatement *isScopeStatement() { return this; } + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + int isEmpty(); + Expression *interpret(InterState *istate); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct WhileStatement : Statement +{ + Expression *condition; + Statement *body; + + WhileStatement(Loc loc, Expression *c, Statement *b); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct DoStatement : Statement +{ + Statement *body; + Expression *condition; + + DoStatement(Loc loc, Statement *b, Expression *c); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct ForStatement : Statement +{ + Statement *init; + Expression *condition; + Expression *increment; + Statement *body; + + ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct ForeachStatement : Statement +{ + enum TOK op; // TOKforeach or TOKforeach_reverse + Arguments *arguments; // array of Argument*'s + Expression *aggr; + Statement *body; + + VarDeclaration *key; + VarDeclaration *value; + + FuncDeclaration *func; // function we're lexically in + + Array cases; // put breaks, continues, gotos and returns here + Array gotos; // forward referenced goto's go here + + ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, Expression *aggr, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +#if DMDV2 +struct ForeachRangeStatement : Statement +{ + enum TOK op; // TOKforeach or TOKforeach_reverse + Argument *arg; // loop index variable + Expression *lwr; + Expression *upr; + Statement *body; + + VarDeclaration *key; + + ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg, + Expression *lwr, Expression *upr, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; +#endif + +struct IfStatement : Statement +{ + Argument *arg; + Expression *condition; + Statement *ifbody; + Statement *elsebody; + + VarDeclaration *match; // for MatchExpression results + + IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int usesEH(); + int blockExit(); + IfStatement *isIfStatement() { return this; } + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct ConditionalStatement : Statement +{ + Condition *condition; + Statement *ifbody; + Statement *elsebody; + + ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Statements *flatten(Scope *sc); + int usesEH(); + int blockExit(); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct PragmaStatement : Statement +{ + Identifier *ident; + Expressions *args; // array of Expression's + Statement *body; + + PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int usesEH(); + int blockExit(); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct StaticAssertStatement : Statement +{ + StaticAssert *sa; + + StaticAssertStatement(StaticAssert *sa); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int blockExit(); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct SwitchStatement : Statement +{ + Expression *condition; + Statement *body; + + DefaultStatement *sdefault; + + Array gotoCases; // array of unresolved GotoCaseStatement's + Array *cases; // array of CaseStatement's + int hasNoDefault; // !=0 if no default statement + + // LDC + Statement *enclosingScopeExit; + + SwitchStatement(Loc loc, Expression *c, Statement *b); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int usesEH(); + int blockExit(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct CaseStatement : Statement +{ + Expression *exp; + Statement *statement; + + int index; // which case it is (since we sort this) + block *cblock; // back end: label for the block + + // LDC + Statement *enclosingScopeExit; + + CaseStatement(Loc loc, Expression *exp, Statement *s); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int compare(Object *obj); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + CaseStatement* isCaseStatement() { return this; } + + // LDC + llvm::BasicBlock* bodyBB; + llvm::ConstantInt* llvmIdx; +}; + +#if DMDV2 + +struct CaseRangeStatement : Statement +{ + Expression *first; + Expression *last; + Statement *statement; + + CaseRangeStatement(Loc loc, Expression *first, Expression *last, Statement *s); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +#endif + +struct DefaultStatement : Statement +{ + Statement *statement; +#if IN_GCC + block *cblock; // back end: label for the block +#endif + + // LDC + Statement *enclosingScopeExit; + + DefaultStatement(Loc loc, Statement *s); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + // LDC + llvm::BasicBlock* bodyBB; +}; + +struct GotoDefaultStatement : Statement +{ + SwitchStatement *sw; + + GotoDefaultStatement(Loc loc); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); +}; + +struct GotoCaseStatement : Statement +{ + Expression *exp; // NULL, or which case to goto + CaseStatement *cs; // case statement it resolves to + SwitchStatement *sw; + + GotoCaseStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); +}; + +struct SwitchErrorStatement : Statement +{ + SwitchErrorStatement(Loc loc); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); +}; + +struct ReturnStatement : Statement +{ + Expression *exp; + + ReturnStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statement *semantic(Scope *sc); + int blockExit(); + Expression *interpret(InterState *istate); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + ReturnStatement *isReturnStatement() { return this; } +}; + +struct BreakStatement : Statement +{ + Identifier *ident; + + BreakStatement(Loc loc, Identifier *ident); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); + + // LDC: only set if ident is set: label statement to jump to + LabelStatement *target; +}; + +struct ContinueStatement : Statement +{ + Identifier *ident; + + ContinueStatement(Loc loc, Identifier *ident); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); + + // LDC: only set if ident is set: label statement to jump to + LabelStatement *target; +}; + +struct SynchronizedStatement : Statement +{ + Expression *exp; + Statement *body; + + SynchronizedStatement(Loc loc, Expression *exp, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + +// Back end + elem *esync; + SynchronizedStatement(Loc loc, elem *esync, Statement *body); + void toIR(IRState *irs); + llvm::Value* llsync; +}; + +struct WithStatement : Statement +{ + Expression *exp; + Statement *body; + VarDeclaration *wthis; + + WithStatement(Loc loc, Expression *exp, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int usesEH(); + int blockExit(); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct TryCatchStatement : Statement +{ + Statement *body; + Array *catches; + + TryCatchStatement(Loc loc, Statement *body, Array *catches); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int usesEH(); + int blockExit(); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + TryCatchStatement *isTryCatchStatement() { return this; } +}; + +struct Catch : Object +{ + Loc loc; + Type *type; + Identifier *ident; + VarDeclaration *var; + Statement *handler; + + Catch(Loc loc, Type *t, Identifier *id, Statement *handler); + Catch *syntaxCopy(); + void semantic(Scope *sc); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct TryFinallyStatement : Statement +{ + Statement *body; + Statement *finalbody; + + TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct OnScopeStatement : Statement +{ + TOK tok; + Statement *statement; + + OnScopeStatement(Loc loc, TOK tok, Statement *statement); + Statement *syntaxCopy(); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statement *semantic(Scope *sc); + int usesEH(); + void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + + void toIR(IRState *irs); +}; + +struct ThrowStatement : Statement +{ + Expression *exp; + + ThrowStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int blockExit(); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct VolatileStatement : Statement +{ + Statement *statement; + + VolatileStatement(Loc loc, Statement *statement); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Statements *flatten(Scope *sc); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct GotoStatement : Statement +{ + Identifier *ident; + LabelDsymbol *label; + TryFinallyStatement *enclosingFinally; + Statement* enclosingScopeExit; + + GotoStatement(Loc loc, Identifier *ident); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int blockExit(); + Expression *interpret(InterState *istate); + + void toIR(IRState *irs); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + GotoStatement *isGotoStatement() { return this; } +}; + +struct LabelStatement : Statement +{ + Identifier *ident; + Statement *statement; + TryFinallyStatement *enclosingFinally; + Statement* enclosingScopeExit; + block *lblock; // back end + int isReturnLabel; + + LabelStatement(Loc loc, Identifier *ident, Statement *statement); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Statements *flatten(Scope *sc); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + // LDC + bool asmLabel; // for labels inside inline assembler + void toNakedIR(IRState *irs); +}; + +struct LabelDsymbol : Dsymbol +{ + LabelStatement *statement; + + LabelDsymbol(Identifier *ident); + LabelDsymbol *isLabel(); +}; + +struct AsmStatement : Statement +{ + Token *tokens; + code *asmcode; + unsigned asmalign; // alignment of this statement + unsigned refparam; // !=0 if function parameter is referenced + unsigned naked; // !=0 if function is to be naked + + AsmStatement(Loc loc, Token *tokens); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int blockExit(); + int comeFrom(); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual AsmStatement *isAsmStatement() { return this; } + + void toIR(IRState *irs); + + // LDC + // non-zero if this is a branch, contains the target labels identifier + Identifier* isBranchToLabel; + + void toNakedIR(IRState *irs); +}; + +struct AsmBlockStatement : CompoundStatement +{ + TryFinallyStatement* enclosingFinally; + Statement* enclosingScopeExit; + + AsmBlockStatement(Loc loc, Statements *s); + Statements *flatten(Scope *sc); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + + CompoundStatement *isCompoundStatement() { return NULL; } + AsmBlockStatement *isAsmBlockStatement() { return this; } + + void toIR(IRState *irs); + void toNakedIR(IRState *irs); + AsmBlockStatement* endsWithAsm(); + + llvm::Value* abiret; +}; + +#endif /* DMD_STATEMENT_H */
--- a/dmd/struct.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/struct.c Fri Nov 06 23:58:01 2009 +0100 @@ -1,520 +1,520 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <assert.h> - -#include "root.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "declaration.h" -#include "module.h" -#include "id.h" -#include "statement.h" - -/********************************* AggregateDeclaration ****************************/ - -AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) - : ScopeDsymbol(id) -{ - this->loc = loc; - - storage_class = 0; - protection = PROTpublic; - type = NULL; - handle = NULL; - structsize = 0; // size of struct - alignsize = 0; // size of struct for alignment purposes - structalign = 0; // struct member alignment in effect - hasUnions = 0; - sizeok = 0; // size not determined yet - isdeprecated = 0; - inv = NULL; - aggNew = NULL; - aggDelete = NULL; - -#if IN_DMD - stag = NULL; - sinit = NULL; -#endif - scope = NULL; -#if DMDV2 - dtor = NULL; - - ctor = NULL; - defaultCtor = NULL; -#endif - -#if IN_LLVM - availableExternally = true; // assume this unless proven otherwise -#endif -} - -enum PROT AggregateDeclaration::prot() -{ - return protection; -} - -void AggregateDeclaration::semantic2(Scope *sc) -{ - //printf("AggregateDeclaration::semantic2(%s)\n", toChars()); - if (scope) - { error("has forward references"); - return; - } - if (members) - { - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic2(sc); - } - sc->pop(); - } -} - -void AggregateDeclaration::semantic3(Scope *sc) -{ int i; - - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); - if (members) - { - sc = sc->push(this); - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic3(sc); - } - sc->pop(); - } -} - -void AggregateDeclaration::inlineScan() -{ int i; - - //printf("AggregateDeclaration::inlineScan(%s)\n", toChars()); - if (members) - { - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - //printf("inline scan aggregate symbol '%s'\n", s->toChars()); - s->inlineScan(); - } - } -} - -unsigned AggregateDeclaration::size(Loc loc) -{ - //printf("AggregateDeclaration::size() = %d\n", structsize); - if (!members) - error(loc, "unknown size"); - if (sizeok != 1) - { error(loc, "no size yet for forward reference"); - //*(char*)0=0; - } - return structsize; -} - -Type *AggregateDeclaration::getType() -{ - return type; -} - -int AggregateDeclaration::isDeprecated() -{ - return isdeprecated; -} - -/**************************** - * Do byte or word alignment as necessary. - * Align sizes of 0, as we may not know array sizes yet. - */ - -void AggregateDeclaration::alignmember( - unsigned salign, // struct alignment that is in effect - unsigned size, // alignment requirement of field - unsigned *poffset) -{ - //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); - if (salign > 1) - { - assert(size != 3); - int sa = size; - if (sa == 0 || salign < sa) - sa = salign; - *poffset = (*poffset + sa - 1) & ~(sa - 1); - } - //printf("result = %d\n",offset); -} - - -void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) -{ - unsigned memsize; // size of member - unsigned memalignsize; // size of member for alignment purposes - unsigned xalign; // alignment boundaries - - //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars()); - - // Check for forward referenced types which will fail the size() call - Type *t = v->type->toBasetype(); - if (t->ty == Tstruct /*&& isStructDeclaration()*/) - { TypeStruct *ts = (TypeStruct *)t; -#if DMDV2 - if (ts->sym == this) - { - error("cannot have field %s with same struct type", v->toChars()); - } -#endif - - if (ts->sym->sizeok != 1) - { - sizeok = 2; // cannot finish; flag as forward referenced - return; - } - } - if (t->ty == Tident) - { - sizeok = 2; // cannot finish; flag as forward referenced - return; - } - - memsize = v->type->size(loc); - memalignsize = v->type->alignsize(); - xalign = v->type->memalign(sc->structalign); - alignmember(xalign, memalignsize, &sc->offset); - v->offset = sc->offset; - sc->offset += memsize; - if (sc->offset > structsize) - structsize = sc->offset; - if (sc->structalign < memalignsize) - memalignsize = sc->structalign; - if (alignsize < memalignsize) - alignsize = memalignsize; - //printf("\talignsize = %d\n", alignsize); - - v->storage_class |= STCfield; - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize); - fields.push(v); -} - - -/********************************* StructDeclaration ****************************/ - -StructDeclaration::StructDeclaration(Loc loc, Identifier *id) - : AggregateDeclaration(loc, id) -{ - zeroInit = 0; // assume false until we do semantic processing -#if DMDV2 - hasIdentityAssign = 0; - cpctor = NULL; - postblit = NULL; -#endif - - // For forward references - type = new TypeStruct(this); -} - -Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) -{ - StructDeclaration *sd; - - if (s) - sd = (StructDeclaration *)s; - else - sd = new StructDeclaration(loc, ident); - ScopeDsymbol::syntaxCopy(sd); - return sd; -} - -void StructDeclaration::semantic(Scope *sc) -{ int i; - Scope *sc2; - - //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); - - //static int count; if (++count == 20) *(char*)0=0; - - assert(type); - if (!members) // if forward reference - return; - - if (symtab) - { if (!scope) - return; // semantic() already completed - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - parent = sc->parent; -#if STRUCTTHISREF - handle = type; -#else - handle = type->pointerTo(); -#endif - structalign = sc->structalign; - protection = sc->protection; - if (sc->stc & STCdeprecated) - isdeprecated = 1; - assert(!isAnonymous()); - if (sc->stc & STCabstract) - error("structs, unions cannot be abstract"); -#if DMDV2 - if (storage_class & STCinvariant) - type = type->invariantOf(); - else if (storage_class & STCconst) - type = type->constOf(); -#endif - - if (sizeok == 0) // if not already done the addMember step - { - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); - s->addMember(sc, this, 1); - } - } - - sizeok = 0; - sc2 = sc->push(this); - sc2->stc = 0; - sc2->parent = this; - if (isUnionDeclaration()) - sc2->inunion = 1; - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - - int members_dim = members->dim; - for (i = 0; i < members_dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc2); - if (isUnionDeclaration()) - sc2->offset = 0; -#if 0 - if (sizeok == 2) - { //printf("forward reference\n"); - break; - } -#endif - } - - /* 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 - * another that is a shell around the value: - * int opCmp(struct *p) { return opCmp(*p); } - */ - - TypeFunction *tfeqptr; - { - Arguments *arguments = new Arguments; - Argument *arg = new Argument(STCin, handle, Id::p, NULL); - - arguments->push(arg); - tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); - } - - TypeFunction *tfeq; - { - Arguments *arguments = new Arguments; - Argument *arg = new Argument(STCin, type, NULL, NULL); - - arguments->push(arg); - tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfeq = (TypeFunction *)tfeq->semantic(0, sc); - } - - Identifier *id = Id::eq; - for (int i = 0; i < 2; i++) - { - Dsymbol *s = search_function(this, id); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - if (fdx) - { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr, getModule()); - if (!fd) - { fd = fdx->overloadExactMatch(tfeq, getModule()); - if (fd) - { // Create the thunk, fdptr - FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); - Expression *e = new IdentifierExp(loc, Id::p); - e = new PtrExp(loc, e); - Expressions *args = new Expressions(); - args->push(e); - e = new IdentifierExp(loc, id); - e = new CallExp(loc, e, args); - fdptr->fbody = new ReturnStatement(loc, e); - ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); - assert(s); - s->members->push(fdptr); - fdptr->addMember(sc, s, 1); - fdptr->semantic(sc2); - } - } - } - - id = Id::cmp; - } -#if DMDV2 - dtor = buildDtor(sc2); - postblit = buildPostBlit(sc2); - cpctor = buildCpCtor(sc2); - buildOpAssign(sc2); -#endif - - sc2->pop(); - - if (sizeok == 2) - { // semantic() failed because of forward references. - // Unwind what we did, and defer it for later - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - //printf("\tdeferring %s\n", toChars()); - return; - } - - // 0 sized struct's are set to 1 byte - if (structsize == 0) - { - structsize = 1; - alignsize = 1; - } - - // Round struct size up to next alignsize boundary. - // This will ensure that arrays of structs will get their internals - // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - - sizeok = 1; - Module::dprogress++; - - //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); - - // Determine if struct is all zeros or not - zeroInit = 1; - for (i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd && !vd->isDataseg()) - { - if (vd->init) - { - // Should examine init to see if it is really all 0's - zeroInit = 0; - break; - } - else - { - if (!vd->type->isZeroInit(loc)) - { - zeroInit = 0; - break; - } - } - } - } - - /* Look for special member functions. - */ -#if DMDV2 - ctor = (CtorDeclaration *)search(0, Id::ctor, 0); -#endif - inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); - aggNew = (NewDeclaration *)search(0, Id::classNew, 0); - aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); - - if (sc->func) - { - semantic2(sc); - semantic3(sc); - } -} - -void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - buf->printf("%s ", kind()); - if (!isAnonymous()) - buf->writestring(toChars()); - if (!members) - { - buf->writeByte(';'); - buf->writenl(); - return; - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - buf->writenl(); -} - - -const char *StructDeclaration::kind() -{ - return "struct"; -} - -/********************************* UnionDeclaration ****************************/ - -UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) - : StructDeclaration(loc, id) -{ -} - -Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) -{ - UnionDeclaration *ud; - - if (s) - ud = (UnionDeclaration *)s; - else - ud = new UnionDeclaration(loc, ident); - StructDeclaration::syntaxCopy(ud); - return ud; -} - - -const char *UnionDeclaration::kind() -{ - return "union"; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <assert.h> + +#include "root.h" +#include "aggregate.h" +#include "scope.h" +#include "mtype.h" +#include "declaration.h" +#include "module.h" +#include "id.h" +#include "statement.h" + +/********************************* AggregateDeclaration ****************************/ + +AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) + : ScopeDsymbol(id) +{ + this->loc = loc; + + storage_class = 0; + protection = PROTpublic; + type = NULL; + handle = NULL; + structsize = 0; // size of struct + alignsize = 0; // size of struct for alignment purposes + structalign = 0; // struct member alignment in effect + hasUnions = 0; + sizeok = 0; // size not determined yet + isdeprecated = 0; + inv = NULL; + aggNew = NULL; + aggDelete = NULL; + +#if IN_DMD + stag = NULL; + sinit = NULL; +#endif +#if DMDV2 + dtor = NULL; + + ctor = NULL; + defaultCtor = NULL; +#endif + +#if IN_LLVM + availableExternally = true; // assume this unless proven otherwise +#endif +} + +enum PROT AggregateDeclaration::prot() +{ + return protection; +} + +void AggregateDeclaration::semantic2(Scope *sc) +{ + //printf("AggregateDeclaration::semantic2(%s)\n", toChars()); + if (scope && members) + { error("has forward references"); + return; + } + if (members) + { + sc = sc->push(this); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic2(sc); + } + sc->pop(); + } +} + +void AggregateDeclaration::semantic3(Scope *sc) +{ int i; + + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; + + //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); + if (members) + { + sc = sc->push(this); + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic3(sc); + } + sc->pop(); + } +} + +void AggregateDeclaration::inlineScan() +{ int i; + + //printf("AggregateDeclaration::inlineScan(%s)\n", toChars()); + if (members) + { + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("inline scan aggregate symbol '%s'\n", s->toChars()); + s->inlineScan(); + } + } +} + +unsigned AggregateDeclaration::size(Loc loc) +{ + //printf("AggregateDeclaration::size() = %d\n", structsize); + if (!members) + error(loc, "unknown size"); + if (sizeok != 1) + { error(loc, "no size yet for forward reference"); + //*(char*)0=0; + } + return structsize; +} + +Type *AggregateDeclaration::getType() +{ + return type; +} + +int AggregateDeclaration::isDeprecated() +{ + return isdeprecated; +} + +/**************************** + * Do byte or word alignment as necessary. + * Align sizes of 0, as we may not know array sizes yet. + */ + +void AggregateDeclaration::alignmember( + unsigned salign, // struct alignment that is in effect + unsigned size, // alignment requirement of field + unsigned *poffset) +{ + //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); + if (salign > 1) + { + assert(size != 3); + int sa = size; + if (sa == 0 || salign < sa) + sa = salign; + *poffset = (*poffset + sa - 1) & ~(sa - 1); + } + //printf("result = %d\n",offset); +} + + +void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) +{ + unsigned memsize; // size of member + unsigned memalignsize; // size of member for alignment purposes + unsigned xalign; // alignment boundaries + + //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars()); + + // Check for forward referenced types which will fail the size() call + Type *t = v->type->toBasetype(); + if (t->ty == Tstruct /*&& isStructDeclaration()*/) + { TypeStruct *ts = (TypeStruct *)t; +#if DMDV2 + if (ts->sym == this) + { + error("cannot have field %s with same struct type", v->toChars()); + } +#endif + + if (ts->sym->sizeok != 1) + { + sizeok = 2; // cannot finish; flag as forward referenced + return; + } + } + if (t->ty == Tident) + { + sizeok = 2; // cannot finish; flag as forward referenced + return; + } + + memsize = v->type->size(loc); + memalignsize = v->type->alignsize(); + xalign = v->type->memalign(sc->structalign); + alignmember(xalign, memalignsize, &sc->offset); + v->offset = sc->offset; + sc->offset += memsize; + if (sc->offset > structsize) + structsize = sc->offset; + if (sc->structalign < memalignsize) + memalignsize = sc->structalign; + if (alignsize < memalignsize) + alignsize = memalignsize; + //printf("\talignsize = %d\n", alignsize); + + v->storage_class |= STCfield; + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize); + fields.push(v); +} + + +/********************************* StructDeclaration ****************************/ + +StructDeclaration::StructDeclaration(Loc loc, Identifier *id) + : AggregateDeclaration(loc, id) +{ + zeroInit = 0; // assume false until we do semantic processing +#if DMDV2 + hasIdentityAssign = 0; + cpctor = NULL; + postblit = NULL; +#endif + + // For forward references + type = new TypeStruct(this); +} + +Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) +{ + StructDeclaration *sd; + + if (s) + sd = (StructDeclaration *)s; + else + sd = new StructDeclaration(loc, ident); + ScopeDsymbol::syntaxCopy(sd); + return sd; +} + +void StructDeclaration::semantic(Scope *sc) +{ int i; + Scope *sc2; + + //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); + + //static int count; if (++count == 20) *(char*)0=0; + + assert(type); + if (!members) // if forward reference + return; + + if (symtab) + { if (!scope) + return; // semantic() already completed + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + + parent = sc->parent; + type = type->semantic(loc, sc); +#if STRUCTTHISREF + handle = type; +#else + handle = type->pointerTo(); +#endif + structalign = sc->structalign; + protection = sc->protection; + if (sc->stc & STCdeprecated) + isdeprecated = 1; + assert(!isAnonymous()); + if (sc->stc & STCabstract) + error("structs, unions cannot be abstract"); +#if DMDV2 + if (storage_class & STCinvariant) + type = type->invariantOf(); + else if (storage_class & STCconst) + type = type->constOf(); +#endif + + if (sizeok == 0) // if not already done the addMember step + { + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); + s->addMember(sc, this, 1); + } + } + + sizeok = 0; + sc2 = sc->push(this); + sc2->stc = 0; + sc2->parent = this; + if (isUnionDeclaration()) + sc2->inunion = 1; + sc2->protection = PROTpublic; + sc2->explicitProtection = 0; + + int members_dim = members->dim; + for (i = 0; i < members_dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc2); + if (isUnionDeclaration()) + sc2->offset = 0; +#if 0 + if (sizeok == 2) + { //printf("forward reference\n"); + break; + } +#endif + } + + /* 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 + * another that is a shell around the value: + * int opCmp(struct *p) { return opCmp(*p); } + */ + + TypeFunction *tfeqptr; + { + Arguments *arguments = new Arguments; + Argument *arg = new Argument(STCin, handle, Id::p, NULL); + + arguments->push(arg); + tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); + tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); + } + + TypeFunction *tfeq; + { + Arguments *arguments = new Arguments; + Argument *arg = new Argument(STCin, type, NULL, NULL); + + arguments->push(arg); + tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); + tfeq = (TypeFunction *)tfeq->semantic(0, sc); + } + + Identifier *id = Id::eq; + for (int i = 0; i < 2; i++) + { + Dsymbol *s = search_function(this, id); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + if (fdx) + { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr, getModule()); + if (!fd) + { fd = fdx->overloadExactMatch(tfeq, getModule()); + if (fd) + { // Create the thunk, fdptr + FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); + Expression *e = new IdentifierExp(loc, Id::p); + e = new PtrExp(loc, e); + Expressions *args = new Expressions(); + args->push(e); + e = new IdentifierExp(loc, id); + e = new CallExp(loc, e, args); + fdptr->fbody = new ReturnStatement(loc, e); + ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); + assert(s); + s->members->push(fdptr); + fdptr->addMember(sc, s, 1); + fdptr->semantic(sc2); + } + } + } + + id = Id::cmp; + } +#if DMDV2 + dtor = buildDtor(sc2); + postblit = buildPostBlit(sc2); + cpctor = buildCpCtor(sc2); + buildOpAssign(sc2); +#endif + + sc2->pop(); + + if (sizeok == 2) + { // semantic() failed because of forward references. + // Unwind what we did, and defer it for later + fields.setDim(0); + structsize = 0; + alignsize = 0; + structalign = 0; + + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + //printf("\tdeferring %s\n", toChars()); + return; + } + + // 0 sized struct's are set to 1 byte + if (structsize == 0) + { + structsize = 1; + alignsize = 1; + } + + // Round struct size up to next alignsize boundary. + // This will ensure that arrays of structs will get their internals + // aligned properly. + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + + sizeok = 1; + Module::dprogress++; + + //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); + + // Determine if struct is all zeros or not + zeroInit = 1; + for (i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *vd = s->isVarDeclaration(); + if (vd && !vd->isDataseg()) + { + if (vd->init) + { + // Should examine init to see if it is really all 0's + zeroInit = 0; + break; + } + else + { + if (!vd->type->isZeroInit(loc)) + { + zeroInit = 0; + break; + } + } + } + } + + /* Look for special member functions. + */ +#if DMDV2 + ctor = (CtorDeclaration *)search(0, Id::ctor, 0); +#endif + inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); + aggNew = (NewDeclaration *)search(0, Id::classNew, 0); + aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); + + if (sc->func) + { + semantic2(sc); + semantic3(sc); + } +} + +void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + buf->printf("%s ", kind()); + if (!isAnonymous()) + buf->writestring(toChars()); + if (!members) + { + buf->writeByte(';'); + buf->writenl(); + return; + } + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + buf->writenl(); +} + + +const char *StructDeclaration::kind() +{ + return "struct"; +} + +/********************************* UnionDeclaration ****************************/ + +UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) + : StructDeclaration(loc, id) +{ +} + +Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) +{ + UnionDeclaration *ud; + + if (s) + ud = (UnionDeclaration *)s; + else + ud = new UnionDeclaration(loc, ident); + StructDeclaration::syntaxCopy(ud); + return ud; +} + + +const char *UnionDeclaration::kind() +{ + return "union"; +} + +
--- a/dmd/template.c Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/template.c Fri Nov 06 23:58:01 2009 +0100 @@ -310,7 +310,7 @@ this->members = decldefs; this->overnext = NULL; this->overroot = NULL; - this->scope = NULL; + this->semanticRun = 0; this->onemember = NULL; } @@ -350,8 +350,9 @@ #if LOG printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); #endif - if (scope) + if (semanticRun) return; // semantic() already run + semanticRun = 1; if (sc->func) { @@ -803,16 +804,19 @@ { // Set initial template arguments nargsi = targsi->dim; - if (nargsi > parameters->dim) + size_t n = parameters->dim; + if (nargsi > n) { if (!tp) goto Lnomatch; dedargs->setDim(nargsi); dedargs->zero(); } - - memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data)); - - for (size_t i = 0; i < nargsi; i++) + else + n = nargsi; + + memcpy(dedargs->data, targsi->data, n * sizeof(*dedargs->data)); + + for (size_t i = 0; i < n; i++) { assert(i < parameters->dim); TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; MATCH m; @@ -844,7 +848,7 @@ fdtype = (TypeFunction *)fd->type; nfparams = Argument::dim(fdtype->parameters); // number of function parameters - nfargs = fargs->dim; // number of function arguments + nfargs = fargs ? fargs->dim : 0; // number of function arguments /* Check for match of function arguments with variadic template * parameter, such as: @@ -854,7 +858,7 @@ */ if (tp) // if variadic { - if (nfparams == 0) // if no function parameters + if (nfparams == 0 && nfargs != 0) // if no function parameters { Tuple *t = new Tuple(); //printf("t = %p\n", t); @@ -1293,7 +1297,7 @@ for (TemplateDeclaration *td = this; td; td = td->overnext) { - if (!td->scope) + if (!td->semanticRun) { error("forward reference to template %s", td->toChars()); goto Lerror; @@ -1901,14 +1905,21 @@ L2: - for (int i = 0; i < tempinst->tiargs->dim; i++) + for (int i = 0; 1; i++) { //printf("\ttest: tempinst->tiargs[%d]\n", i); + Object *o1; + if (i < tempinst->tiargs->dim) + o1 = (Object *)tempinst->tiargs->data[i]; + else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) + // Pick up default arg + o1 = (Object *)tempinst->tdtypes.data[i]; + else + break; + if (i >= tp->tempinst->tiargs->dim) goto Lnomatch; - int j; - Object *o1 = (Object *)tempinst->tiargs->data[i]; Object *o2 = (Object *)tp->tempinst->tiargs->data[i]; Type *t1 = isType(o1); @@ -1934,6 +1945,7 @@ #endif TemplateTupleParameter *ttp; + int j; if (t2 && t2->ty == Tident && i == tp->tempinst->tiargs->dim - 1 && @@ -3062,7 +3074,7 @@ this->tinst = NULL; this->argsym = NULL; this->aliasdecl = NULL; - this->semanticdone = 0; + this->semanticRun = 0; this->semantictiargsdone = 0; this->withsym = NULL; this->nest = 0; @@ -3096,7 +3108,7 @@ this->tinst = NULL; this->argsym = NULL; this->aliasdecl = NULL; - this->semanticdone = 0; + this->semanticRun = 0; this->semantictiargsdone = 1; this->withsym = NULL; this->nest = 0; @@ -3179,13 +3191,13 @@ // get the enclosing template instance from the scope tinst tinst = sc->tinst; - if (semanticdone != 0) + if (semanticRun != 0) { error(loc, "recursive template expansion"); // inst = this; return; } - semanticdone = 1; + semanticRun = 1; // get the enclosing template instance from the scope tinst tinst = sc->tinst; @@ -3323,7 +3335,7 @@ { Module *m = sc->module->importedFrom; //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); a = m->members; - if (m->semanticdone >= 3) + if (m->semanticRun >= 3) dosemantic3 = 1; } for (int i = 0; 1; i++) @@ -3344,9 +3356,9 @@ // Create our own scope for the template parameters Scope *scope = tempdecl->scope; - if (!scope) + if (!tempdecl->semanticRun) { - error("forward reference to template declaration %s\n", tempdecl->toChars()); + error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl->toChars()); return; } @@ -3559,6 +3571,7 @@ } else if (ta) { + Ltype: if (ta->ty == Ttuple) { // Expand tuple TypeTuple *tt = (TypeTuple *)ta; @@ -3593,7 +3606,21 @@ ea = ea->optimize(WANTvalue | WANTinterpret); tiargs->data[j] = ea; if (ea->op == TOKtype) - tiargs->data[j] = ea->type; + { ta = ea->type; + goto Ltype; + } + if (ea->op == TOKtuple) + { // Expand tuple + TupleExp *te = (TupleExp *)ea; + size_t dim = te->exps->dim; + tiargs->remove(j); + if (dim) + { tiargs->reserve(dim); + for (size_t i = 0; i < dim; i++) + tiargs->insert(j + i, te->exps->data[i]); + } + j--; + } } else if (sa) { @@ -3736,6 +3763,23 @@ #if LOG printf("TemplateInstance::findBestMatch()\n"); #endif + // First look for forward references + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + if (!td->semanticRun) + { + if (td->scope) + { // Try to fix forward reference + td->semantic(td->scope); + } + if (!td->semanticRun) + { + error("%s forward references template declaration %s\n", toChars(), td->toChars()); + return NULL; + } + } + } + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) { MATCH m; @@ -3752,11 +3796,7 @@ dedtypes.setDim(td->parameters->dim); dedtypes.zero(); - if (!td->scope) - { - error("forward reference to template declaration %s", td->toChars()); - return NULL; - } + assert(td->semanticRun); m = td->matchWithInstance(this, &dedtypes, 0); //printf("matchWithInstance = %d\n", m); if (!m) // no match at all @@ -3964,6 +4004,7 @@ { sinteger_t v; real_t r; + ea = ea->optimize(WANTvalue | WANTinterpret); if (ea->op == TOKvar) { sa = ((VarExp *)ea)->var; @@ -4030,7 +4071,7 @@ * template instance arguments. */ -void TemplateInstance::declareParameters(Scope *scope) +void TemplateInstance::declareParameters(Scope *sc) { //printf("TemplateInstance::declareParameters()\n"); for (int i = 0; i < tdtypes.dim; i++) @@ -4040,7 +4081,7 @@ Object *o = (Object *)tdtypes.data[i]; // initializer for tp //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl->declareParameter(scope, tp, o); + tempdecl->declareParameter(sc, tp, o); } } @@ -4048,9 +4089,9 @@ void TemplateInstance::semantic2(Scope *sc) { int i; - if (semanticdone >= 2) + if (semanticRun >= 2) return; - semanticdone = 2; + semanticRun = 2; #if LOG printf("+TemplateInstance::semantic2('%s')\n", toChars()); #endif @@ -4080,12 +4121,12 @@ void TemplateInstance::semantic3(Scope *sc) { #if LOG - printf("TemplateInstance::semantic3('%s'), semanticdone = %d\n", toChars(), semanticdone); + printf("TemplateInstance::semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun); #endif //if (toChars()[0] == 'D') *(char*)0=0; - if (semanticdone >= 3) + if (semanticRun >= 3) return; - semanticdone = 3; + semanticRun = 3; if (!errors && members) { sc = tempdecl->scope; @@ -4182,6 +4223,7 @@ #endif if (!inst) { error("cannot resolve forward reference"); + errors = 1; return this; } @@ -4274,7 +4316,6 @@ this->tqual = tqual; this->idents = idents; this->tiargs = tiargs ? tiargs : new Objects(); - this->scope = NULL; } Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) @@ -4308,18 +4349,22 @@ printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); fflush(stdout); #endif - if (semanticdone && + if (semanticRun) + { // This for when a class/struct contains mixin members, and // is done over because of forward references - (!parent || !toParent()->isAggregateDeclaration())) - { + if (parent && toParent()->isAggregateDeclaration()) + semanticRun = 1; // do over + else + { #if LOG - printf("\tsemantic done\n"); + printf("\tsemantic done\n"); #endif - return; + return; + } } - if (!semanticdone) - semanticdone = 1; + if (!semanticRun) + semanticRun = 1; #if LOG printf("\tdo semantic\n"); #endif @@ -4394,7 +4439,7 @@ assert(tempdecl); for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) { - if (!td->scope) + if (!td->semanticRun) { /* Cannot handle forward references if mixin is a struct member, * because addField must happen during struct's semantic, not @@ -4402,7 +4447,7 @@ * runDeferred will re-run mixin's semantic outside of the struct's * semantic. */ - semanticdone = 0; + semanticRun = 0; AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); if (ad) ad->sizeok = 2; @@ -4420,6 +4465,8 @@ // Run semantic on each argument, place results in tiargs[] semanticTiargs(sc); + if (errors) + return; tempdecl = findBestMatch(sc); if (!tempdecl) @@ -4508,19 +4555,19 @@ argsym = new ScopeDsymbol(); argsym->parent = scy->parent; - Scope *scope = scy->push(argsym); + Scope *argscope = scy->push(argsym); unsigned errorsave = global.errors; // Declare each template parameter as an alias for the argument type - declareParameters(scope); + declareParameters(argscope); // Add members to enclosing scope, as well as this scope for (unsigned i = 0; i < members->dim; i++) { Dsymbol *s; s = (Dsymbol *)members->data[i]; - s->addMember(scope, this, i); + s->addMember(argscope, this, i); //sc->insert(s); //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); //printf("s->parent = %s\n", s->parent->toChars()); @@ -4531,7 +4578,7 @@ printf("\tdo semantic() on template instance members '%s'\n", toChars()); #endif Scope *sc2; - sc2 = scope->push(this); + sc2 = argscope->push(this); sc2->offset = sc->offset; static int nest; @@ -4574,7 +4621,7 @@ sc2->pop(); - scope->pop(); + argscope->pop(); // if (!isAnonymous()) { @@ -4588,9 +4635,9 @@ void TemplateMixin::semantic2(Scope *sc) { int i; - if (semanticdone >= 2) + if (semanticRun >= 2) return; - semanticdone = 2; + semanticRun = 2; #if LOG printf("+TemplateMixin::semantic2('%s')\n", toChars()); #endif @@ -4618,9 +4665,9 @@ void TemplateMixin::semantic3(Scope *sc) { int i; - if (semanticdone >= 3) + if (semanticRun >= 3) return; - semanticdone = 3; + semanticRun = 3; #if LOG printf("TemplateMixin::semantic3('%s')\n", toChars()); #endif
--- a/dmd/template.h Fri Nov 06 21:51:41 2009 +0100 +++ b/dmd/template.h Fri Nov 06 23:58:01 2009 +0100 @@ -60,7 +60,8 @@ TemplateDeclaration *overnext; // next overloaded TemplateDeclaration TemplateDeclaration *overroot; // first in overnext list - Scope *scope; + int semanticRun; // 1 semantic() run + Dsymbol *onemember; // if !=NULL then one member of this template TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, @@ -73,6 +74,7 @@ char *toChars(); void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); // void toDocBuffer(OutBuffer *buf); MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag); @@ -282,7 +284,7 @@ AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its // sole member WithScopeSymbol *withsym; // if a member of a with statement - int semanticdone; // has semantic() been done? + int semanticRun; // has semantic() been done? int semantictiargsdone; // has semanticTiargs() been done? int nest; // for recursion detection int havetempdecl; // 1 if used second constructor @@ -341,8 +343,6 @@ Array *idents; Type *tqual; - Scope *scope; // for forward referencing - TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Array *idents, Objects *tiargs); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc);
--- a/gen/classes.cpp Fri Nov 06 21:51:41 2009 +0100 +++ b/gen/classes.cpp Fri Nov 06 23:58:01 2009 +0100 @@ -732,11 +732,7 @@ // class name // code from dmd -#if DMDV2 const char *name = cd->ident->toChars(); -#else - char *name = cd->ident->toChars(); -#endif size_t namelen = strlen(name); if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) {
--- a/gen/main.cpp Fri Nov 06 21:51:41 2009 +0100 +++ b/gen/main.cpp Fri Nov 06 23:58:01 2009 +0100 @@ -806,6 +806,17 @@ fatal(); #endif + // load all unconditional imports for better symbol resolving + for (int i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("importall %s\n", m->toChars()); + m->importAll(0); + } + if (global.errors) + fatal(); + // Do semantic analysis for (int i = 0; i < modules.dim; i++) {