Mercurial > projects > ldc
changeset 875:330f999ade44
Merged DMD 1.038
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 06 Jan 2009 16:33:51 +0100 |
parents | 2ddee23bd70e |
children | 27a379f288bf |
files | dmd/attrib.c dmd/class.c dmd/cond.c dmd/doc.c dmd/expression.c dmd/expression.h dmd/func.c dmd/import.c dmd/interpret.c dmd/man.c dmd/mars.c dmd/module.c dmd/module.h dmd/mtype.c dmd/mtype.h dmd/opover.c dmd/optimize.c dmd/statement.c dmd/statement.h dmd/template.c dmd/template.h gen/statements.cpp |
diffstat | 22 files changed, 4321 insertions(+), 3789 deletions(-) [+] |
line wrap: on
line diff
--- a/dmd/attrib.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/attrib.c Tue Jan 06 16:33:51 2009 +0100 @@ -406,7 +406,7 @@ } void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ char *p; +{ const char *p; switch (linkage) { @@ -431,7 +431,7 @@ char *LinkDeclaration::toChars() { - return "extern ()"; + return (char *)"extern ()"; } /********************************* ProtDeclaration ****************************/ @@ -476,7 +476,7 @@ } void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ char *p; +{ const char *p; switch (protection) { @@ -721,7 +721,7 @@ const char *AnonDeclaration::kind() { - return (char *)(isunion ? "anonymous union" : "anonymous struct"); + return (isunion ? "anonymous union" : "anonymous struct"); } /********************************* PragmaDeclaration ****************************/ @@ -1363,6 +1363,7 @@ CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) : AttribDeclaration(NULL) { + //printf("CompileDeclaration(loc = %d)\n", loc.linnum); this->loc = loc; this->exp = exp; this->sd = NULL; @@ -1392,7 +1393,7 @@ void CompileDeclaration::compileIt(Scope *sc) { - //printf("CompileDeclaration::compileIt()\n"); + //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); exp = exp->optimize(WANTvalue | WANTinterpret);
--- a/dmd/class.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/class.c Tue Jan 06 16:33:51 2009 +0100 @@ -539,7 +539,16 @@ sc->inunion = 0; if (isCOMclass()) + { +#if _WIN32 sc->linkage = LINKwindows; +#else + /* This enables us to use COM objects under Linux and + * work with things like XPCOM + */ + sc->linkage = LINKc; +#endif + } sc->protection = PROTpublic; sc->explicitProtection = 0; sc->structalign = 8;
--- a/dmd/cond.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/cond.c Tue Jan 06 16:33:51 2009 +0100 @@ -1,391 +1,391 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <assert.h> - -#include "id.h" -#include "init.h" -#include "declaration.h" -#include "identifier.h" -#include "expression.h" -#include "cond.h" -#include "module.h" -#include "template.h" -#include "lexer.h" -#ifdef _DH -#include "mtype.h" -#include "scope.h" -#endif - -int findCondition(Array *ids, Identifier *ident) -{ - if (ids) - { - for (int i = 0; i < ids->dim; i++) - { - char *id = (char *)ids->data[i]; - - if (strcmp(id, ident->toChars()) == 0) - return TRUE; - } - } - - return FALSE; -} - -/* ============================================================ */ - -Condition::Condition(Loc loc) -{ - this->loc = loc; - inc = 0; -} - -/* ============================================================ */ - -DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) - : Condition(0) -{ - this->mod = mod; - this->level = level; - this->ident = ident; -} - -Condition *DVCondition::syntaxCopy() -{ - return this; // don't need to copy -} - -/* ============================================================ */ - -void DebugCondition::setGlobalLevel(unsigned level) -{ - global.params.debuglevel = level; -} - -void DebugCondition::addGlobalIdent(char *ident) -{ - if (!global.params.debugids) - global.params.debugids = new Array(); - global.params.debugids->push(ident); -} - - -DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int DebugCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->debugids, ident)) - inc = 1; - else if (findCondition(global.params.debugids, ident)) - inc = 1; - else - { if (!mod->debugidsNot) - mod->debugidsNot = new Array(); - mod->debugidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.debuglevel || level <= mod->debuglevel) - inc = 1; - } - return (inc == 1); -} - -void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("debug (%s)", ident->toChars()); - else - buf->printf("debug (%u)", level); -} - -/* ============================================================ */ - -void VersionCondition::setGlobalLevel(unsigned level) -{ - global.params.versionlevel = level; -} - -void VersionCondition::checkPredefined(Loc loc, char *ident) -{ - static char* reserved[] = - { - "DigitalMars", "LLVM", "LDC", "LLVM64", - "X86", "X86_64", "PPC", "PPC64", - "Windows", "Win32", "Win64", - "linux", "darwin", "Posix", - "LittleEndian", "BigEndian", - "all", - "none", - }; - - for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) - { - if (strcmp(ident, reserved[i]) == 0) - goto Lerror; - } - - if (ident[0] == 'D' && ident[1] == '_') - goto Lerror; - - return; - - Lerror: - error(loc, "version identifier '%s' is reserved and cannot be set", ident); -} - -void VersionCondition::addGlobalIdent(char *ident) -{ - checkPredefined(0, ident); - addPredefinedGlobalIdent(ident); -} - -void VersionCondition::addPredefinedGlobalIdent(char *ident) -{ - if (!global.params.versionids) - global.params.versionids = new Array(); - global.params.versionids->push(ident); -} - - -VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int VersionCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); - //if (ident) printf("\tident = '%s'\n", ident->toChars()); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->versionids, ident)) - inc = 1; - else if (findCondition(global.params.versionids, ident)) - inc = 1; - else - { - if (!mod->versionidsNot) - mod->versionidsNot = new Array(); - mod->versionidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.versionlevel || level <= mod->versionlevel) - inc = 1; - } - return (inc == 1); -} - -void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("version (%s)", ident->toChars()); - else - buf->printf("version (%u)", level); -} - - -/**************************** StaticIfCondition *******************************/ - -StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) - : Condition(loc) -{ - this->exp = exp; -} - -Condition *StaticIfCondition::syntaxCopy() -{ - return new StaticIfCondition(loc, exp->syntaxCopy()); -} - -int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) -{ -#if 0 - printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s); - if (s) - { - printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); - } -#endif - if (inc == 0) - { - if (!sc) - { - error(loc, "static if conditional cannot be at global scope"); - inc = 2; - return 0; - } - - sc = sc->push(sc->scopesym); - sc->sd = s; // s gets any addMember() - sc->flags |= SCOPEstaticif; - Expression *e = exp->semantic(sc); - sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - inc = 1; - else if (e->isBool(FALSE)) - inc = 2; - else - { - e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); - inc = 2; - } - } - return (inc == 1); -} - -void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("static if("); - exp->toCBuffer(buf, hgs); - buf->writeByte(')'); -} - - -/**************************** IftypeCondition *******************************/ - -IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) - : Condition(loc) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; -} - -Condition *IftypeCondition::syntaxCopy() -{ - return new IftypeCondition(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL); -} - -int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("IftypeCondition::include()\n"); - if (inc == 0) - { - if (!sc) - { - error(loc, "iftype conditional cannot be at global scope"); - inc = 2; - return 0; - } - unsigned errors = global.errors; - global.gag++; // suppress printing of error messages - targ = targ->semantic(loc, sc); - global.gag--; - if (errors != global.errors) // if any errors happened - { inc = 2; // then condition is false - global.errors = errors; - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - MATCH m; - TemplateTypeParameter tp(loc, id, NULL, NULL); - - TemplateParameters parameters; - parameters.setDim(1); - parameters.data[0] = (void *)&tp; - - Objects dedtypes; - dedtypes.setDim(1); - - m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - inc = 2; - else - { - inc = 1; - Type *tded = (Type *)dedtypes.data[0]; - if (!tded) - tded = targ; - Dsymbol *s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - } - } - else if (id) - { - /* Declare id as an alias for type targ. Evaluate to TRUE - */ - Dsymbol *s = new AliasDeclaration(loc, id, targ); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - inc = 1; - } - else if (tspec) - { - /* Evaluate to TRUE if targ matches tspec - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s\n", targ->toChars()); - //printf("tspec = %s\n", tspec->toChars()); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - inc = 1; - else - inc = 2; - } - else /* == */ - { if (targ->equals(tspec)) - inc = 1; - else - inc = 2; - } - } - else - inc = 1; - //printf("inc = %d\n", inc); - } - return (inc == 1); -} - -void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("iftype("); - targ->toCBuffer(buf, id, hgs); - if (tspec) - { - if (tok == TOKcolon) - buf->writestring(" : "); - else - buf->writestring(" == "); - tspec->toCBuffer(buf, NULL, hgs); - } - buf->writeByte(')'); -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <assert.h> + +#include "id.h" +#include "init.h" +#include "declaration.h" +#include "identifier.h" +#include "expression.h" +#include "cond.h" +#include "module.h" +#include "template.h" +#include "lexer.h" +#ifdef _DH +#include "mtype.h" +#include "scope.h" +#endif + +int findCondition(Array *ids, Identifier *ident) +{ + if (ids) + { + for (int i = 0; i < ids->dim; i++) + { + char *id = (char *)ids->data[i]; + + if (strcmp(id, ident->toChars()) == 0) + return TRUE; + } + } + + return FALSE; +} + +/* ============================================================ */ + +Condition::Condition(Loc loc) +{ + this->loc = loc; + inc = 0; +} + +/* ============================================================ */ + +DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) + : Condition(0) +{ + this->mod = mod; + this->level = level; + this->ident = ident; +} + +Condition *DVCondition::syntaxCopy() +{ + return this; // don't need to copy +} + +/* ============================================================ */ + +void DebugCondition::setGlobalLevel(unsigned level) +{ + global.params.debuglevel = level; +} + +void DebugCondition::addGlobalIdent(char *ident) +{ + if (!global.params.debugids) + global.params.debugids = new Array(); + global.params.debugids->push(ident); +} + + +DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) + : DVCondition(mod, level, ident) +{ +} + +int DebugCondition::include(Scope *sc, ScopeDsymbol *s) +{ + //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); + if (inc == 0) + { + inc = 2; + if (ident) + { + if (findCondition(mod->debugids, ident)) + inc = 1; + else if (findCondition(global.params.debugids, ident)) + inc = 1; + else + { if (!mod->debugidsNot) + mod->debugidsNot = new Array(); + mod->debugidsNot->push(ident->toChars()); + } + } + else if (level <= global.params.debuglevel || level <= mod->debuglevel) + inc = 1; + } + return (inc == 1); +} + +void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (ident) + buf->printf("debug (%s)", ident->toChars()); + else + buf->printf("debug (%u)", level); +} + +/* ============================================================ */ + +void VersionCondition::setGlobalLevel(unsigned level) +{ + global.params.versionlevel = level; +} + +void VersionCondition::checkPredefined(Loc loc, char *ident) +{ + static const char* reserved[] = + { + "DigitalMars", "LLVM", "LDC", "LLVM64", + "X86", "X86_64", "PPC", "PPC64", + "Windows", "Win32", "Win64", + "linux", "darwin", "Posix", + "LittleEndian", "BigEndian", + "all", + "none", + }; + + for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) + { + if (strcmp(ident, reserved[i]) == 0) + goto Lerror; + } + + if (ident[0] == 'D' && ident[1] == '_') + goto Lerror; + + return; + + Lerror: + error(loc, "version identifier '%s' is reserved and cannot be set", ident); +} + +void VersionCondition::addGlobalIdent(char *ident) +{ + checkPredefined(0, ident); + addPredefinedGlobalIdent(ident); +} + +void VersionCondition::addPredefinedGlobalIdent(char *ident) +{ + if (!global.params.versionids) + global.params.versionids = new Array(); + global.params.versionids->push(ident); +} + + +VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) + : DVCondition(mod, level, ident) +{ +} + +int VersionCondition::include(Scope *sc, ScopeDsymbol *s) +{ + //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); + //if (ident) printf("\tident = '%s'\n", ident->toChars()); + if (inc == 0) + { + inc = 2; + if (ident) + { + if (findCondition(mod->versionids, ident)) + inc = 1; + else if (findCondition(global.params.versionids, ident)) + inc = 1; + else + { + if (!mod->versionidsNot) + mod->versionidsNot = new Array(); + mod->versionidsNot->push(ident->toChars()); + } + } + else if (level <= global.params.versionlevel || level <= mod->versionlevel) + inc = 1; + } + return (inc == 1); +} + +void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (ident) + buf->printf("version (%s)", ident->toChars()); + else + buf->printf("version (%u)", level); +} + + +/**************************** StaticIfCondition *******************************/ + +StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) + : Condition(loc) +{ + this->exp = exp; +} + +Condition *StaticIfCondition::syntaxCopy() +{ + return new StaticIfCondition(loc, exp->syntaxCopy()); +} + +int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) +{ +#if 0 + printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s); + if (s) + { + printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); + } +#endif + if (inc == 0) + { + if (!sc) + { + error(loc, "static if conditional cannot be at global scope"); + inc = 2; + return 0; + } + + sc = sc->push(sc->scopesym); + sc->sd = s; // s gets any addMember() + sc->flags |= SCOPEstaticif; + Expression *e = exp->semantic(sc); + sc->pop(); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->isBool(TRUE)) + inc = 1; + else if (e->isBool(FALSE)) + inc = 2; + else + { + e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); + inc = 2; + } + } + return (inc == 1); +} + +void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("static if("); + exp->toCBuffer(buf, hgs); + buf->writeByte(')'); +} + + +/**************************** IftypeCondition *******************************/ + +IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) + : Condition(loc) +{ + this->targ = targ; + this->id = id; + this->tok = tok; + this->tspec = tspec; +} + +Condition *IftypeCondition::syntaxCopy() +{ + return new IftypeCondition(loc, + targ->syntaxCopy(), + id, + tok, + tspec ? tspec->syntaxCopy() : NULL); +} + +int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) +{ + //printf("IftypeCondition::include()\n"); + if (inc == 0) + { + if (!sc) + { + error(loc, "iftype conditional cannot be at global scope"); + inc = 2; + return 0; + } + unsigned errors = global.errors; + global.gag++; // suppress printing of error messages + targ = targ->semantic(loc, sc); + global.gag--; + if (errors != global.errors) // if any errors happened + { inc = 2; // then condition is false + global.errors = errors; + } + else if (id && tspec) + { + /* Evaluate to TRUE if targ matches tspec. + * If TRUE, declare id as an alias for the specialized type. + */ + + MATCH m; + TemplateTypeParameter tp(loc, id, NULL, NULL); + + TemplateParameters parameters; + parameters.setDim(1); + parameters.data[0] = (void *)&tp; + + Objects dedtypes; + dedtypes.setDim(1); + + m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes); + if (m == MATCHnomatch || + (m != MATCHexact && tok == TOKequal)) + inc = 2; + else + { + inc = 1; + Type *tded = (Type *)dedtypes.data[0]; + if (!tded) + tded = targ; + Dsymbol *s = new AliasDeclaration(loc, id, tded); + s->semantic(sc); + sc->insert(s); + if (sd) + s->addMember(sc, sd, 1); + } + } + else if (id) + { + /* Declare id as an alias for type targ. Evaluate to TRUE + */ + Dsymbol *s = new AliasDeclaration(loc, id, targ); + s->semantic(sc); + sc->insert(s); + if (sd) + s->addMember(sc, sd, 1); + inc = 1; + } + else if (tspec) + { + /* Evaluate to TRUE if targ matches tspec + */ + tspec = tspec->semantic(loc, sc); + //printf("targ = %s\n", targ->toChars()); + //printf("tspec = %s\n", tspec->toChars()); + if (tok == TOKcolon) + { if (targ->implicitConvTo(tspec)) + inc = 1; + else + inc = 2; + } + else /* == */ + { if (targ->equals(tspec)) + inc = 1; + else + inc = 2; + } + } + else + inc = 1; + //printf("inc = %d\n", inc); + } + return (inc == 1); +} + +void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("iftype("); + targ->toCBuffer(buf, id, hgs); + if (tspec) + { + if (tok == TOKcolon) + buf->writestring(" : "); + else + buf->writestring(" == "); + tspec->toCBuffer(buf, NULL, hgs); + } + buf->writeByte(')'); +} + +
--- a/dmd/doc.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/doc.c Tue Jan 06 16:33:51 2009 +0100 @@ -47,9 +47,9 @@ struct Escape { - char *strings[256]; + const char *strings[256]; - static char *escapeChar(unsigned c); + static const char *escapeChar(unsigned c); }; struct Section @@ -96,8 +96,8 @@ }; -int cmp(char *stringz, void *s, size_t slen); -int icmp(char *stringz, void *s, size_t slen); +int cmp(const char *stringz, void *s, size_t slen); +int icmp(const char *stringz, void *s, size_t slen); int isDitto(unsigned char *comment); unsigned char *skipwhitespace(unsigned char *p); unsigned skiptoident(OutBuffer *buf, unsigned i); @@ -404,7 +404,7 @@ OutBuffer *buf = sc->docbuf; if (members) - { char *m = "$(DDOC_MEMBERS \n"; + { const char *m = "$(DDOC_MEMBERS \n"; if (isModule()) m = "$(DDOC_MODULE_MEMBERS \n"; @@ -441,7 +441,7 @@ void emitProtection(OutBuffer *buf, PROT prot) { - char *p; + const char *p; switch (prot) { @@ -918,6 +918,7 @@ DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) { unsigned idlen; + //printf("parse(%s): '%s'\n", s->toChars(), comment); if (sc->lastdc && isDitto(comment)) return NULL; @@ -963,6 +964,7 @@ unsigned char *name = NULL; unsigned namelen = 0; + //printf("parseSections('%s')\n", comment); p = comment; while (*p) { @@ -1088,7 +1090,7 @@ { if (namelen) { - static char *table[] = + static const char *table[] = { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", @@ -1432,7 +1434,7 @@ * Return < 0, ==0, > 0 */ -int cmp(char *stringz, void *s, size_t slen) +int cmp(const char *stringz, void *s, size_t slen) { size_t len1 = strlen(stringz); @@ -1441,7 +1443,7 @@ return memcmp(stringz, s, slen); } -int icmp(char *stringz, void *s, size_t slen) +int icmp(const char *stringz, void *s, size_t slen) { size_t len1 = strlen(stringz); @@ -1578,7 +1580,7 @@ int isKeyword(unsigned char *p, unsigned len) { - static char *table[] = { "true", "false", "null" }; + static const char *table[] = { "true", "false", "null" }; for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) { @@ -1629,10 +1631,10 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) { //printf("highlightText()\n"); - char *sid = s->ident->toChars(); + const char *sid = s->ident->toChars(); FuncDeclaration *f = s->isFuncDeclaration(); unsigned char *p; - char *se; + const char *se; int leadingBlank = 1; int inCode = 0; @@ -1878,7 +1880,7 @@ //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); for (unsigned i = offset; i < buf->offset; i++) { unsigned char c = buf->data[i]; - char *se; + const char *se; se = Escape::escapeChar(c); if (se) @@ -1920,7 +1922,7 @@ void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) { for (; p < pend; p++) - { char *s = Escape::escapeChar(*p); + { const char *s = Escape::escapeChar(*p); if (s) buf->writestring(s); else @@ -1942,7 +1944,7 @@ Token tok; OutBuffer res; unsigned char *lastp = buf->data; - char *highlight; + const char *highlight; //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); res.reserve(buf->offset); @@ -2003,8 +2005,8 @@ * Find character string to replace c with. */ -char *Escape::escapeChar(unsigned c) -{ char *s; +const char *Escape::escapeChar(unsigned c) +{ const char *s; switch (c) {
--- a/dmd/expression.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/expression.c Tue Jan 06 16:33:51 2009 +0100 @@ -12,7 +12,10 @@ #include <stdlib.h> #include <ctype.h> #include <assert.h> +#if _MSC_VER #include <complex> +#else +#endif #include <math.h> #if _WIN32 && __DMC__ @@ -68,6 +71,7 @@ #include "parse.h" Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim); +Expression *expandVar(int result, VarDeclaration *v); #define LOGSEMANTIC 0 @@ -168,10 +172,20 @@ precedence[TOKue] = PREC_rel; precedence[TOKin] = PREC_rel; +#if 0 precedence[TOKequal] = PREC_equal; precedence[TOKnotequal] = PREC_equal; precedence[TOKidentity] = PREC_equal; precedence[TOKnotidentity] = PREC_equal; +#else + /* Note that we changed precedence, so that < and != have the same + * precedence. This change is in the parser, too. + */ + precedence[TOKequal] = PREC_rel; + precedence[TOKnotequal] = PREC_rel; + precedence[TOKidentity] = PREC_rel; + precedence[TOKnotidentity] = PREC_rel; +#endif precedence[TOKand] = PREC_and; @@ -352,7 +366,7 @@ { Type *t = e->type->toBasetype(); - if (t->ty == Tfunction) + if (t->ty == Tfunction /*|| e->op == TOKoverloadset*/) { e = new CallExp(e->loc, e); e = e->semantic(sc); @@ -539,8 +553,6 @@ void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) { unsigned n; - int done; - Type *tb; //printf("functionArguments()\n"); assert(arguments); @@ -552,7 +564,7 @@ n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) - done = 0; + int done = 0; for (size_t i = 0; i < n; i++) { Expression *arg; @@ -561,6 +573,7 @@ arg = (Expression *)arguments->data[i]; else arg = NULL; + Type *tb; if (i < nparams) { @@ -615,11 +628,8 @@ break; } #endif - static int idn; - char name[10 + sizeof(idn)*3 + 1]; - sprintf(name, "__arrayArg%d", ++idn); - Identifier *id = Lexer::idPool(name); - Type *t = new TypeSArray(tb->next, new IntegerExp(nargs - i)); + Identifier *id = Lexer::uniqueId("__arrayArg"); + Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i)); t = t->semantic(loc, sc); VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); v->semantic(sc); @@ -631,16 +641,19 @@ for (size_t u = i; u < nargs; u++) { Expression *a = (Expression *)arguments->data[u]; - if (tret && !tb->next->equals(a->type)) + if (tret && !((TypeArray *)tb)->next->equals(a->type)) a = a->toDelegate(sc, tret); Expression *e = new VarExp(loc, v); e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); - e = new AssignExp(loc, e, a); + AssignExp *ae = new AssignExp(loc, e, a); +#if DMDV2 + ae->op = TOKconstruct; +#endif if (c) - c = new CommaExp(loc, c, e); + c = new CommaExp(loc, c, ae); else - c = e; + c = ae; } arg = new VarExp(loc, v); if (c) @@ -694,12 +707,50 @@ } #endif +#if DMDV2 + if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) + { + arg = callCpCtor(loc, sc, arg); + } +#endif + // Convert lazy argument to a delegate if (p->storageClass & STClazy) { arg = arg->toDelegate(sc, p->type); } +#if DMDV2 + /* Look for arguments that cannot 'escape' from the called + * function. + */ + if (!tf->parameterEscapes(p)) + { + /* Function literals can only appear once, so if this + * appearance was scoped, there cannot be any others. + */ + if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + fe->fd->tookAddressOf = 0; + } + + /* For passing a delegate to a scoped parameter, + * this doesn't count as taking the address of it. + * We only worry about 'escaping' references to the function. + */ + else if (arg->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)arg; + if (de->e1->op == TOKvar) + { VarExp *ve = (VarExp *)de->e1; + FuncDeclaration *f = ve->var->isFuncDeclaration(); + if (f) + { f->tookAddressOf--; + //printf("tookAddressOf = %d\n", f->tookAddressOf); + } + } + } + } +#endif } else { @@ -778,7 +829,11 @@ void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) { //if (precedence[e->op] == 0) e->dump(0); - if (precedence[e->op] < pr) + if (precedence[e->op] < pr || + /* Despite precedence, we don't allow a<b<c expressions. + * They must be parenthesized. + */ + (pr == PREC_rel && precedence[e->op] == pr)) { buf->writeByte('('); e->toCBuffer(buf, hgs); @@ -982,6 +1037,16 @@ error("expression %s is not a valid template value argument", toChars()); } +/*************************************** + * Return !=0 if expression is an lvalue. + */ +#if DMDV2 +int Expression::isLvalue() +{ + return 0; +} +#endif + /******************************* * Give error if we're not an lvalue. * If we can, convert expression to be an lvalue. @@ -1002,6 +1067,10 @@ //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars()); // See if this expression is a modifiable lvalue (i.e. not const) +#if DMDV2 + if (type && (!type->isMutable() || !type->isAssignable())) + error("%s is not mutable", e->toChars()); +#endif return toLvalue(sc, e); } @@ -1049,6 +1118,15 @@ s->checkDeprecated(loc, sc); } +#if DMDV2 +void Expression::checkPurity(Scope *sc, FuncDeclaration *f) +{ + if (sc->func && sc->func->isPure() && !sc->intypeof && !f->isPure()) + error("pure function '%s' cannot call impure function '%s'\n", + sc->func->toChars(), f->toChars()); +} +#endif + /******************************** * Check for expressions that have no use. * Input: @@ -1175,7 +1253,11 @@ int Expression::canThrow() { +#if DMDV2 + return FALSE; +#else return TRUE; +#endif } @@ -1849,7 +1931,9 @@ // ArrayScopeSymbol::search() doesn't have access to sc. s->semantic(sc); } - // Look to see if f is really a function template + /* If f is really a function template, + * then replace f with the function template declaration. + */ FuncDeclaration *f = s->isFuncDeclaration(); if (f && f->parent) { TemplateInstance *ti = f->parent->isTemplateInstance(); @@ -1891,6 +1975,13 @@ buf->writestring(ident->toChars()); } +#if DMDV2 +int IdentifierExp::isLvalue() +{ + return 1; +} +#endif + Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e) { #if 0 @@ -1954,7 +2045,11 @@ // BUG: This should happen after overload resolution for functions, not before if (s->needThis()) { - if (hasThis(sc) /*&& !s->isFuncDeclaration()*/) + if (hasThis(sc) +#if DMDV2 + && !s->isFuncDeclaration() +#endif + ) { // Supply an implicit 'this', as in // this.ident @@ -2112,6 +2207,13 @@ buf->writestring(s->toChars()); } +#if DMDV2 +int DsymbolExp::isLvalue() +{ + return 1; +} +#endif + Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) { #if 0 @@ -2214,6 +2316,13 @@ buf->writestring("this"); } +#if DMDV2 +int ThisExp::isLvalue() +{ + return 1; +} +#endif + Expression *ThisExp::toLvalue(Scope *sc, Expression *e) { return this; @@ -2431,7 +2540,7 @@ if (!type) { OutBuffer buffer; size_t newlen = 0; - char *p; + const char *p; size_t u; unsigned c; @@ -2629,7 +2738,7 @@ void StringExp::toMangleBuffer(OutBuffer *buf) { char m; OutBuffer tmp; - char *p; + const char *p; unsigned c; size_t u; unsigned char *q; @@ -2772,6 +2881,13 @@ return result ? (dim != 0) : (dim == 0); } +#if DMDV2 +int ArrayLiteralExp::canThrow() +{ + return 1; // because it can fail allocating memory +} +#endif + void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('['); @@ -2890,6 +3006,13 @@ return result ? (dim != 0) : (dim == 0); } +#if DMDV2 +int AssocArrayLiteralExp::canThrow() +{ + return 1; +} +#endif + void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('['); @@ -3074,6 +3197,12 @@ return -1; } +#if DMDV2 +int StructLiteralExp::isLvalue() +{ + return 1; +} +#endif Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) { @@ -3096,6 +3225,13 @@ return f; } +#if DMDV2 +int StructLiteralExp::canThrow() +{ + return arrayExpressionCanThrow(elements); +} +#endif + void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring(sd->toChars()); @@ -3287,6 +3423,8 @@ /********************** NewExp **************************************/ +/* thisexp.new(newargs) newtype(arguments) */ + NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments) : Expression(loc, TOKnew, sizeof(NewExp)) @@ -3472,17 +3610,14 @@ } if (cd->aggNew) - { Expression *e; - - f = cd->aggNew; - + { // Prepend the uint size argument to newargs[] - e = new IntegerExp(loc, cd->size(loc), Type::tuns32); + Expression *e = new IntegerExp(loc, cd->size(loc), Type::tuns32); if (!newargs) newargs = new Expressions(); newargs->shift(e); - f = f->overloadResolve(loc, newargs); + f = cd->aggNew->overloadResolve(loc, newargs); allocator = f->isNewDeclaration(); assert(allocator); @@ -3494,7 +3629,6 @@ if (newargs && newargs->dim) error("no allocator for %s", cd->toChars()); } - } else if (tb->ty == Tstruct) { @@ -3575,6 +3709,13 @@ return 1; } +#if DMDV2 +int NewExp::canThrow() +{ + return 1; +} +#endif + void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { int i; @@ -3642,6 +3783,13 @@ return 1; } +#if DMDV2 +int NewAnonClassExp::canThrow() +{ + return 1; +} +#endif + void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { int i; @@ -3670,6 +3818,18 @@ } } +/********************** SymbolExp **************************************/ + +#if DMDV2 +SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads) + : Expression(loc, op, size) +{ + assert(var); + this->var = var; + this->hasOverloads = hasOverloads; +} +#endif + /********************** SymOffExp **************************************/ SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset) @@ -3760,6 +3920,11 @@ } #endif } + /* Fix for 1161 doesn't work because it causes protection + * problems when instantiating imported templates passing private + * variables as alias template parameters. + */ + //accessCheck(loc, sc, NULL, var); VarDeclaration *v = var->isVarDeclaration(); if (v) @@ -3774,6 +3939,13 @@ } } v->checkNestedReference(sc, loc); +#if DMDV2 + if (sc->func && sc->func->isPure() && !sc->intypeof) + { + if (v->isDataseg() && !v->isInvariant()) + error("pure function '%s' cannot access mutable static data '%s'", sc->func->toChars(), v->toChars()); + } +#endif } #if 0 else if ((fd = var->isFuncLiteralDeclaration()) != NULL) @@ -3812,6 +3984,15 @@ } } +#if DMDV2 +int VarExp::isLvalue() +{ + if (var->storage_class & STClazy) + return 0; + return 1; +} +#endif + Expression *VarExp::toLvalue(Scope *sc, Expression *e) { #if 0 @@ -4026,6 +4207,13 @@ return f; } +#if DMDV2 +int TupleExp::canThrow() +{ + return arrayExpressionCanThrow(exps); +} +#endif + void TupleExp::checkEscape() { for (size_t i = 0; i < exps->dim; i++) @@ -4195,6 +4383,18 @@ return 1; } +#if DMDV2 +int DeclarationExp::canThrow() +{ + VarDeclaration *v = declaration->isVarDeclaration(); + if (v && v->init) + { ExpInitializer *ie = v->init->isExpInitializer(); + return ie && ie->exp->canThrow(); + } + return 0; +} +#endif + void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { declaration->toCBuffer(buf, hgs); @@ -4398,6 +4598,7 @@ break; case TOKinvariant: + case TOKimmutable: if (!targ->isInvariant()) goto Lno; tded = targ; @@ -4604,6 +4805,13 @@ return this; } +#if DMDV2 +int UnaExp::canThrow() +{ + return e1->canThrow(); +} +#endif + void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring(Token::toChars(op)); @@ -4773,6 +4981,13 @@ return e1->type->isunsigned() || e2->type->isunsigned(); } +#if DMDV2 +int BinExp::canThrow() +{ + return e1->canThrow() || e2->canThrow(); +} +#endif + void BinExp::incompatibleTypes() { error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", @@ -4805,6 +5020,7 @@ Parser p(sc->module, (unsigned char *)se->string, se->len, 0); p.loc = loc; p.nextToken(); + //printf("p.loc.linnum = %d\n", p.loc.linnum); Expression *e = p.parseExpression(); if (p.token.value != TOKeof) error("incomplete mixin expression (%s)", se->toChars()); @@ -4877,7 +5093,7 @@ return se->semantic(sc); Lerror: - se = new StringExp(loc, ""); + se = new StringExp(loc, (char *)""); goto Lret; } @@ -4940,6 +5156,13 @@ return 1; } +#if DMDV2 +int AssertExp::canThrow() +{ + return (global.params.useAssert != 0); +} +#endif + void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("assert("); @@ -5162,6 +5385,13 @@ } return e; } +#if DMDV2 + OverloadSet *o = s->isOverloadSet(); + if (o) + { //printf("'%s' is an overload set\n", o->toChars()); + return new OverExp(o); + } +#endif Type *t = s->getType(); if (t) @@ -5224,6 +5454,29 @@ e->type = ((TypePointer *)e1->type)->next; return e->type->dotExp(sc, e, ident); } +#if DMDV2 + else if (t1b->ty == Tarray || + t1b->ty == Tsarray || + t1b->ty == Taarray) + { /* If ident is not a valid property, rewrite: + * e1.ident + * as: + * .ident(e1) + */ + unsigned errors = global.errors; + global.gag++; + e = e1->type->dotExp(sc, e1, ident); + global.gag--; + if (errors != global.errors) // if failed to find the property + { + global.errors = errors; + e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); + e = new CallExp(loc, e, e1); + } + e = e->semantic(sc); + return e; + } +#endif else { e = e1->type->dotExp(sc, e1, ident); @@ -5341,6 +5594,13 @@ return this; } +#if DMDV2 +int DotVarExp::isLvalue() +{ + return 1; +} +#endif + Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) { //printf("DotVarExp::toLvalue(%s)\n", toChars()); @@ -5391,6 +5651,20 @@ break; } } +#if DMDV2 + else + { + Type *t1 = e1->type->toBasetype(); + + if (!t1->isMutable() || + (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || + !var->type->isMutable() || + !var->type->isAssignable() || + var->storage_class & STCmanifest + ) + error("cannot modify const/invariant %s", toChars()); + } +#endif return this; } @@ -5713,12 +5987,16 @@ if (!arguments) arguments = new Expressions(); arguments->shift(dotid->e1); +#if DMDV2 + e1 = new DotIdExp(dotid->loc, new IdentifierExp(dotid->loc, Id::empty), dotid->ident); +#else e1 = new IdentifierExp(dotid->loc, dotid->ident); - } - } - } - -#if DMDV2 +#endif + } + } + } + +#if 1 /* This recognizes: * foo!(tiargs)(funcargs) */ @@ -5901,7 +6179,7 @@ if (!arguments) // Should fix deduceFunctionTemplate() so it works on NULL argument arguments = new Expressions(); - f = td->deduceFunctionTemplate(sc, loc, NULL, arguments); + f = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); if (!f) { type = Type::terror; return this; @@ -5925,6 +6203,9 @@ } checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif accessCheck(loc, sc, ue->e1, f); if (!f->needThis()) { @@ -5990,6 +6271,9 @@ f = f->overloadResolve(loc, arguments); checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif e1 = new DotVarExp(e1->loc, e1, f); e1 = e1->semantic(sc); t1 = e1->type; @@ -6027,6 +6311,9 @@ f = cd->ctor; f = f->overloadResolve(loc, arguments); checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif e1 = new DotVarExp(e1->loc, e1, f); e1 = e1->semantic(sc); t1 = e1->type; @@ -6062,7 +6349,7 @@ else if (e1->op == TOKtemplate) { TemplateExp *te = (TemplateExp *)e1; - f = te->td->deduceFunctionTemplate(sc, loc, NULL, arguments); + f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); if (!f) { type = Type::terror; return this; @@ -6118,6 +6405,9 @@ f = f->overloadResolve(loc, arguments); checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif if (f->needThis() && hasThis(sc)) { @@ -6165,9 +6455,75 @@ int CallExp::checkSideEffect(int flag) { +#if DMDV2 + if (flag != 2) + return 1; + + if (e1->checkSideEffect(2)) + return 1; + + /* If any of the arguments have side effects, this expression does + */ + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e->checkSideEffect(2)) + return 1; + } + + /* If calling a function or delegate that is typed as pure, + * then this expression has no side effects. + */ + Type *t = e1->type->toBasetype(); + if (t->ty == Tfunction && ((TypeFunction *)t)->ispure) + return 0; + if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->ispure) + return 0; +#endif return 1; } +#if DMDV2 +int CallExp::canThrow() +{ + if (e1->canThrow()) + return 1; + + /* If any of the arguments can throw, then this expression can throw + */ + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e->canThrow()) + return 1; + } + + /* If calling a function or delegate that is typed as nothrow, + * then this expression cannot throw. + * Note that pure functions can throw. + */ + Type *t = e1->type->toBasetype(); + if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) + return 0; + if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) + return 0; + + return 1; +} +#endif + +#if DMDV2 +int CallExp::isLvalue() +{ + if (type->toBasetype()->ty == Tstruct) + return 1; + Type *tb = e1->type->toBasetype(); + if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) + return 1; // function returns a reference + return 0; +} +#endif + Expression *CallExp::toLvalue(Scope *sc, Expression *e) { if (type->toBasetype()->ty == Tstruct) @@ -6309,6 +6665,13 @@ return this; } +#if DMDV2 +int PtrExp::isLvalue() +{ + return 1; +} +#endif + Expression *PtrExp::toLvalue(Scope *sc, Expression *e) { #if 0 @@ -6321,6 +6684,21 @@ return this; } +#if DMDV2 +Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); + + if (e1->op == TOKsymoff) + { SymOffExp *se = (SymOffExp *)e1; + se->var->checkModify(loc, sc, type); + //return toLvalue(sc, e); + } + + return Expression::modifiableLvalue(sc, e); +} +#endif + void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('*'); @@ -6553,6 +6931,17 @@ to = t; } +#if DMDV2 +/* For cast(const) and cast(immutable) + */ +CastExp::CastExp(Loc loc, Expression *e, unsigned mod) + : UnaExp(loc, TOKcast, sizeof(CastExp), e) +{ + to = NULL; + this->mod = mod; +} +#endif + Expression *CastExp::syntaxCopy() { return new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()); @@ -6637,7 +7026,35 @@ void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("cast("); +#if DMDV1 to->toCBuffer(buf, NULL, hgs); +#else + if (to) + to->toCBuffer(buf, NULL, hgs); + else + { + switch (mod) + { case 0: + break; + case MODconst: + buf->writestring(Token::tochars[TOKconst]); + break; + case MODinvariant: + buf->writestring(Token::tochars[TOKimmutable]); + break; + case MODshared: + buf->writestring(Token::tochars[TOKshared]); + break; + case MODshared | MODconst: + buf->writestring(Token::tochars[TOKshared]); + buf->writeByte(' '); + buf->writestring(Token::tochars[TOKconst]); + break; + default: + assert(0); + } + } +#endif buf->writeByte(')'); expToCBuffer(buf, hgs, e1, precedence[op]); } @@ -6831,6 +7248,13 @@ e1->checkEscape(); } +#if DMDV2 +int SliceExp::isLvalue() +{ + return 1; +} +#endif + Expression *SliceExp::toLvalue(Scope *sc, Expression *e) { return this; @@ -6945,6 +7369,14 @@ return e; } +#if DMDV2 +int ArrayExp::isLvalue() +{ + if (type && type->toBasetype()->ty == Tvoid) + return 0; + return 1; +} +#endif Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) { @@ -7015,6 +7447,13 @@ e2->checkEscape(); } +#if DMDV2 +int CommaExp::isLvalue() +{ + return e2->isLvalue(); +} +#endif + Expression *CommaExp::toLvalue(Scope *sc, Expression *e) { e2 = e2->toLvalue(sc, NULL); @@ -7181,6 +7620,13 @@ return e; } +#if DMDV2 +int IndexExp::isLvalue() +{ + return 1; +} +#endif + Expression *IndexExp::toLvalue(Scope *sc, Expression *e) { // if (type && type->toBasetype()->ty == Tvoid) @@ -9034,9 +9480,21 @@ break; } } +#if 0 + printf("res: %s\n", type->toChars()); + printf("e1 : %s\n", e1->type->toChars()); + printf("e2 : %s\n", e2->type->toChars()); +#endif return this; } +#if DMDV2 +int CondExp::isLvalue() +{ + return e1->isLvalue() && e2->isLvalue(); +} +#endif + Expression *CondExp::toLvalue(Scope *sc, Expression *ex) { PtrExp *e; @@ -9092,6 +9550,13 @@ } } +#if DMDV2 +int CondExp::canThrow() +{ + return econd->canThrow() || e1->canThrow() || e2->canThrow(); +} +#endif + void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { expToCBuffer(buf, hgs, econd, PREC_oror);
--- a/dmd/expression.h Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/expression.h Tue Jan 06 16:33:51 2009 +0100 @@ -825,14 +825,11 @@ Expression *semantic(Scope *sc); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); + Expression *optimize(int result); + Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void dump(int indent); elem *toElem(IRState *irs); - - //LDC: since we don't convert abc.def -> *(&abc + ABC.def.offsetof) - // these are needed - Expression *optimize(int result); - Expression *interpret(InterState *istate); }; struct DotTemplateInstanceExp : UnaExp
--- a/dmd/func.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/func.c Tue Jan 06 16:33:51 2009 +0100 @@ -310,6 +310,8 @@ if (isFinal()) { + if (isOverride()) + error("does not override any function"); cd->vtblFinal.push(this); } else @@ -999,7 +1001,6 @@ } int offend = fbody ? fbody->blockExit() & BEfallthru : TRUE; - //int offend = fbody ? fbody->fallOffEnd() : TRUE; if (isStaticCtorDeclaration()) { /* It's a static constructor. Ensure that all
--- a/dmd/import.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/import.c Tue Jan 06 16:33:51 2009 +0100 @@ -112,7 +112,6 @@ } if (!pkg) pkg = mod; - mod->semantic(); //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); } @@ -136,6 +135,12 @@ } #endif + // Modules need a list of each imported module + //printf("%s imports %s\n", sc->module->toChars(), mod->toChars()); + sc->module->aimports.push(mod); + + mod->semantic(); + /* Default to private importing */ protection = sc->protection; @@ -147,9 +152,6 @@ sc->scopesym->importScope(mod, protection); } - // Modules need a list of each imported module - sc->module->aimports.push(mod); - if (mod->needmoduleinfo) sc->module->needmoduleinfo = 1; @@ -224,7 +226,9 @@ //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags); if (!pkg) - load(NULL); + { load(NULL); + mod->semantic(); + } // Forward it to the package/module return pkg->search(loc, ident, flags);
--- a/dmd/interpret.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/interpret.c Tue Jan 06 16:33:51 2009 +0100 @@ -1,2231 +1,2304 @@ - -// 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 <stdlib.h> -#include <assert.h> - -#include "mem.h" - -#include "statement.h" -#include "expression.h" -#include "cond.h" -#include "init.h" -#include "staticassert.h" -#include "mtype.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" - -#define LOG 0 - -struct InterState -{ - InterState *caller; // calling function's InterState - FuncDeclaration *fd; // function being interpreted - Dsymbols vars; // variables used in this function - Statement *start; // if !=NULL, start execution at this statement - Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result - - InterState(); -}; - -InterState::InterState() -{ - memset(this, 0, sizeof(InterState)); -} - -Expression *interpret_aaLen(InterState *istate, Expressions *arguments); -Expression *interpret_aaKeys(InterState *istate, Expressions *arguments); -Expression *interpret_aaValues(InterState *istate, Expressions *arguments); - -/************************************* - * Attempt to interpret a function given the arguments. - * Input: - * istate state for calling function (NULL if none) - * Return result expression if successful, NULL if not. - */ - -Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments) -{ -#if LOG - printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); - printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun); -#endif - if (global.errors) - return NULL; - if (ident == Id::aaLen) - return interpret_aaLen(istate, arguments); - else if (ident == Id::aaKeys) - return interpret_aaKeys(istate, arguments); - else if (ident == Id::aaValues) - return interpret_aaValues(istate, arguments); - - if (cantInterpret || semanticRun == 1) - return NULL; - - if (needThis() || isNested() || !fbody) - { cantInterpret = 1; - return NULL; - } - - if (semanticRun == 0 && scope) - { - semantic3(scope); - if (global.errors) // if errors compiling this function - return NULL; - } - if (semanticRun < 2) - return NULL; - - Type *tb = type->toBasetype(); - assert(tb->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)tb; - Type *tret = tf->next->toBasetype(); - if (tf->varargs /*|| tret->ty == Tvoid*/) - { cantInterpret = 1; - return NULL; - } - - if (tf->parameters) - { size_t dim = Argument::dim(tf->parameters); - for (size_t i = 0; i < dim; i++) - { Argument *arg = Argument::getNth(tf->parameters, i); - if (arg->storageClass & STClazy) - { cantInterpret = 1; - return NULL; - } - } - } - - InterState istatex; - istatex.caller = istate; - istatex.fd = this; - - Expressions vsave; // place to save previous parameter values - size_t dim = 0; - if (arguments) - { - dim = arguments->dim; - assert(!dim || parameters->dim == dim); - vsave.setDim(dim); - - /* Evaluate all the arguments to the function, - * store the results in eargs[] - */ - Expressions eargs; - eargs.setDim(dim); - - for (size_t i = 0; i < dim; i++) - { Expression *earg = (Expression *)arguments->data[i]; - Argument *arg = Argument::getNth(tf->parameters, i); - - if (arg->storageClass & (STCout | STCref)) - { - } - else - { /* Value parameters - */ - Type *ta = arg->type->toBasetype(); - if (ta->ty == Tsarray && earg->op == TOKaddress) - { - /* Static arrays are passed by a simple pointer. - * Skip past this to get at the actual arg. - */ - earg = ((AddrExp *)earg)->e1; - } - earg = earg->interpret(istate ? istate : &istatex); - if (earg == EXP_CANT_INTERPRET) - return NULL; - } - eargs.data[i] = earg; - } - - for (size_t i = 0; i < dim; i++) - { Expression *earg = (Expression *)eargs.data[i]; - Argument *arg = Argument::getNth(tf->parameters, i); - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - vsave.data[i] = v->value; -#if LOG - printf("arg[%d] = %s\n", i, earg->toChars()); -#endif - if (arg->storageClass & (STCout | STCref)) - { - /* Bind out or ref parameter to the corresponding - * variable v2 - */ - if (!istate || earg->op != TOKvar) - return NULL; // can't bind to non-interpreted vars - - VarDeclaration *v2; - while (1) - { - VarExp *ve = (VarExp *)earg; - v2 = ve->var->isVarDeclaration(); - if (!v2) - return NULL; - if (!v2->value || v2->value->op != TOKvar) - break; - earg = v2->value; - } - - v->value = new VarExp(earg->loc, v2); - - /* Don't restore the value of v2 upon function return - */ - assert(istate); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v == v2) - { istate->vars.data[i] = NULL; - break; - } - } - } - else - { /* Value parameters - */ - v->value = earg; - } -#if LOG - printf("interpreted arg[%d] = %s\n", i, earg->toChars()); -#endif - } - } - - /* Save the values of the local variables used - */ - Expressions valueSaves; - if (istate) - { - //printf("saving local variables...\n"); - valueSaves.setDim(istate->vars.dim); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v) - { - //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); - valueSaves.data[i] = v->value; - v->value = NULL; - } - } - } - - Expression *e = NULL; - - while (1) - { - e = fbody->interpret(&istatex); - if (e == EXP_CANT_INTERPRET) - { -#if LOG - printf("function body failed to interpret\n"); -#endif - e = NULL; - } - - /* This is how we deal with a recursive statement AST - * that has arbitrary goto statements in it. - * Bubble up a 'result' which is the target of the goto - * statement, then go recursively down the AST looking - * for that statement, then execute starting there. - */ - if (e == EXP_GOTO_INTERPRET) - { - istatex.start = istatex.gotoTarget; // set starting statement - istatex.gotoTarget = NULL; - } - else - break; - } - - /* Restore the parameter values - */ - for (size_t i = 0; i < dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - v->value = (Expression *)vsave.data[i]; - } - - if (istate) - { - /* Restore the variable values - */ - //printf("restoring local variables...\n"); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v) - { v->value = (Expression *)valueSaves.data[i]; - //printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); - } - } - } - - return e; -} - -/******************************** Statement ***************************/ - -#define START() \ - if (istate->start) \ - { if (istate->start != this) \ - return NULL; \ - istate->start = NULL; \ - } - -/*********************************** - * Interpret the statement. - * Returns: - * NULL continue to next statement - * EXP_CANT_INTERPRET cannot interpret statement at compile time - * !NULL expression from return statement - */ - -Expression *Statement::interpret(InterState *istate) -{ -#if LOG - printf("Statement::interpret()\n"); -#endif - START() - return EXP_CANT_INTERPRET; -} - -Expression *ExpStatement::interpret(InterState *istate) -{ -#if LOG - printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (exp) - { - Expression *e = exp->interpret(istate); - if (e == EXP_CANT_INTERPRET) - { - //printf("-ExpStatement::interpret(): %p\n", e); - return EXP_CANT_INTERPRET; - } - } - return NULL; -} - -Expression *CompoundStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("CompoundStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (s) - { - e = s->interpret(istate); - if (e) - break; - } - } - } -#if LOG - printf("-CompoundStatement::interpret() %p\n", e); -#endif - return e; -} - -Expression *UnrolledLoopStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("UnrolledLoopStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - e = s->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_CONTINUE_INTERPRET) - { e = NULL; - continue; - } - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e) - break; - } - } - return e; -} - -Expression *IfStatement::interpret(InterState *istate) -{ -#if LOG - printf("IfStatement::interpret(%s)\n", condition->toChars()); -#endif - - if (istate->start == this) - istate->start = NULL; - if (istate->start) - { - Expression *e = NULL; - if (ifbody) - e = ifbody->interpret(istate); - if (istate->start && elsebody) - e = elsebody->interpret(istate); - return e; - } - - Expression *e = condition->interpret(istate); - assert(e); - //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n"); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(TRUE)) - e = ifbody ? ifbody->interpret(istate) : NULL; - else if (e->isBool(FALSE)) - e = elsebody ? elsebody->interpret(istate) : NULL; - else - { - e = EXP_CANT_INTERPRET; - } - } - return e; -} - -Expression *ScopeStatement::interpret(InterState *istate) -{ -#if LOG - printf("ScopeStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - -Expression *ReturnStatement::interpret(InterState *istate) -{ -#if LOG - printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (!exp) - return EXP_VOID_INTERPRET; -#if LOG - Expression *e = exp->interpret(istate); - printf("e = %p\n", e); - return e; -#else - return exp->interpret(istate); -#endif -} - -Expression *BreakStatement::interpret(InterState *istate) -{ -#if LOG - printf("BreakStatement::interpret()\n"); -#endif - START() - if (ident) - return EXP_CANT_INTERPRET; - else - return EXP_BREAK_INTERPRET; -} - -Expression *ContinueStatement::interpret(InterState *istate) -{ -#if LOG - printf("ContinueStatement::interpret()\n"); -#endif - START() - if (ident) - return EXP_CANT_INTERPRET; - else - return EXP_CONTINUE_INTERPRET; -} - -Expression *WhileStatement::interpret(InterState *istate) -{ -#if LOG - printf("WhileStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - if (e != EXP_CONTINUE_INTERPRET) - return e; - } - - while (1) - { - e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(TRUE)) - { e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_CONTINUE_INTERPRET) - continue; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e) - break; - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *DoStatement::interpret(InterState *istate) -{ -#if LOG - printf("DoStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - if (e == EXP_CONTINUE_INTERPRET) - goto Lcontinue; - if (e) - return e; - } - - while (1) - { - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - - Lcontinue: - e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(TRUE)) - { - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *ForStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (init) - { - e = init->interpret(istate); - if (e == EXP_CANT_INTERPRET) - return e; - assert(!e); - } - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - if (e == EXP_CONTINUE_INTERPRET) - goto Lcontinue; - if (e) - return e; - } - - while (1) - { - if (!condition) - goto Lhead; - e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(TRUE)) - { - Lhead: - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - Lcontinue: - if (increment) - { - e = increment->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - } - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *ForeachStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForeachStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (istate->start) - return NULL; - - Expression *e = NULL; - Expression *eaggr; - - if (value->isOut() || value->isRef()) - return EXP_CANT_INTERPRET; - - eaggr = aggr->interpret(istate); - if (eaggr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *dim = ArrayLength(Type::tsize_t, eaggr); - if (dim == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *keysave = key ? key->value : NULL; - Expression *valuesave = value->value; - - uinteger_t d = dim->toUInteger(); - uinteger_t index; - - if (op == TOKforeach) - { - for (index = 0; index < d; index++) - { - Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); - if (key) - key->value = ekey; - e = Index(value->type, eaggr, ekey); - if (e == EXP_CANT_INTERPRET) - break; - value->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == EXP_CONTINUE_INTERPRET) - e = NULL; - else if (e) - break; - } - } - else // TOKforeach_reverse - { - for (index = d; index-- != 0;) - { - Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); - if (key) - key->value = ekey; - e = Index(value->type, eaggr, ekey); - if (e == EXP_CANT_INTERPRET) - break; - value->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == EXP_CONTINUE_INTERPRET) - e = NULL; - else if (e) - break; - } - } - value->value = valuesave; - if (key) - key->value = keysave; - return e; -} - -#if DMDV2 -Expression *ForeachRangeStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForeachRangeStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (istate->start) - return NULL; - - Expression *e = NULL; - Expression *elwr = lwr->interpret(istate); - if (elwr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *eupr = upr->interpret(istate); - if (eupr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *keysave = key->value; - - if (op == TOKforeach) - { - key->value = elwr; - - while (1) - { - e = Cmp(TOKlt, key->value->type, key->value, upr); - if (e == EXP_CANT_INTERPRET) - break; - if (e->isBool(TRUE) == FALSE) - { e = NULL; - break; - } - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) - break; - key->value = e; - } - } - else // TOKforeach_reverse - { - key->value = eupr; - - while (1) - { - e = Cmp(TOKgt, key->value->type, key->value, lwr); - if (e == EXP_CANT_INTERPRET) - break; - if (e->isBool(TRUE) == FALSE) - { e = NULL; - break; - } - - e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) - break; - key->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - } - } - key->value = keysave; - return e; -} -#endif - -Expression *SwitchStatement::interpret(InterState *istate) -{ -#if LOG - printf("SwitchStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e = NULL; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - return e; - } - - - Expression *econdition = condition->interpret(istate); - if (econdition == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Statement *s = NULL; - if (cases) - { - for (size_t i = 0; i < cases->dim; i++) - { - CaseStatement *cs = (CaseStatement *)cases->data[i]; - e = Equal(TOKequal, Type::tint32, econdition, cs->exp); - if (e == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - if (e->isBool(TRUE)) - { s = cs; - break; - } - } - } - if (!s) - { if (hasNoDefault) - error("no default or case for %s in switch statement", econdition->toChars()); - s = sdefault; - } - - assert(s); - istate->start = s; - e = body ? body->interpret(istate) : NULL; - assert(!istate->start); - if (e == EXP_BREAK_INTERPRET) - return NULL; - return e; -} - -Expression *CaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *DefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("DefaultStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *GotoStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoStatement::interpret()\n"); -#endif - START() - assert(label && label->statement); - istate->gotoTarget = label->statement; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoCaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoCaseStatement::interpret()\n"); -#endif - START() - assert(cs); - istate->gotoTarget = cs; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoDefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoDefaultStatement::interpret()\n"); -#endif - START() - assert(sw && sw->sdefault); - istate->gotoTarget = sw->sdefault; - return EXP_GOTO_INTERPRET; -} - -Expression *LabelStatement::interpret(InterState *istate) -{ -#if LOG - printf("LabelStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - -/******************************** Expression ***************************/ - -Expression *Expression::interpret(InterState *istate) -{ -#if LOG - printf("Expression::interpret() %s\n", toChars()); - printf("type = %s\n", type->toChars()); - dump(0); -#endif - return EXP_CANT_INTERPRET; -} - -Expression *NullExp::interpret(InterState *istate) -{ - return this; -} - -Expression *IntegerExp::interpret(InterState *istate) -{ -#if LOG - printf("IntegerExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *RealExp::interpret(InterState *istate) -{ -#if LOG - printf("RealExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *ComplexExp::interpret(InterState *istate) -{ - return this; -} - -Expression *StringExp::interpret(InterState *istate) -{ -#if LOG - printf("StringExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) -{ - Expression *e = EXP_CANT_INTERPRET; - VarDeclaration *v = d->isVarDeclaration(); - SymbolDeclaration *s = d->isSymbolDeclaration(); - if (v) - { -#if DMDV2 - if ((v->isConst() || v->isInvariant()) && v->init && !v->value) -#else - if (v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (e && !e->type) - e->type = v->type; - } - else - { e = v->value; - if (!e) - error(loc, "variable %s is used before initialization", v->toChars()); - else if (e != EXP_CANT_INTERPRET) - e = e->interpret(istate); - } - if (!e) - e = EXP_CANT_INTERPRET; - } - else if (s) - { - if (s->dsym->toInitializer() == s->sym) - { Expressions *exps = new Expressions(); - e = new StructLiteralExp(0, s->dsym, exps); - e = e->semantic(NULL); - } - } - return e; -} - -Expression *VarExp::interpret(InterState *istate) -{ -#if LOG - printf("VarExp::interpret() %s\n", toChars()); -#endif - return getVarExp(loc, istate, var); -} - -Expression *DeclarationExp::interpret(InterState *istate) -{ -#if LOG - printf("DeclarationExp::interpret() %s\n", toChars()); -#endif - Expression *e; - VarDeclaration *v = declaration->isVarDeclaration(); - if (v) - { - Dsymbol *s = v->toAlias(); - if (s == v && !v->isStatic() && v->init) - { - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie) - e = ie->exp->interpret(istate); - else if (v->init->isVoidInitializer()) - e = NULL; - } -#if DMDV2 - else if (s == v && (v->isConst() || v->isInvariant()) && v->init) -#else - else if (s == v && v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (!e) - e = EXP_CANT_INTERPRET; - else if (!e->type) - e->type = v->type; - } - } - else if (declaration->isAttribDeclaration() || - declaration->isTemplateMixin() || - declaration->isTupleDeclaration()) - { // These can be made to work, too lazy now - e = EXP_CANT_INTERPRET; - } - else - { // Others should not contain executable code, so are trivial to evaluate - e = NULL; - } -#if LOG - printf("-DeclarationExp::interpret(): %p\n", e); -#endif - return e; -} - -Expression *TupleExp::interpret(InterState *istate) -{ -#if LOG - printf("TupleExp::interpret() %s\n", toChars()); -#endif - Expressions *expsx = NULL; - - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - Expression *ex; - - ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - { delete expsx; - return ex; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - expsx->setDim(exps->dim); - for (size_t j = 0; j < i; j++) - { - expsx->data[j] = exps->data[j]; - } - } - expsx->data[i] = (void *)ex; - } - } - if (expsx) - { TupleExp *te = new TupleExp(loc, expsx); - expandTuples(te->exps); - te->type = new TypeTuple(te->exps); - return te; - } - return this; -} - -Expression *ArrayLiteralExp::interpret(InterState *istate) -{ Expressions *expsx = NULL; - -#if LOG - printf("ArrayLiteralExp::interpret() %s\n", toChars()); -#endif - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - Expression *ex; - - ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - { delete expsx; - return EXP_CANT_INTERPRET; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - expsx->data[j] = elements->data[j]; - } - } - expsx->data[i] = (void *)ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - { delete expsx; - return EXP_CANT_INTERPRET; - } - ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); - ae->type = type; - return ae; - } - return this; -} - -Expression *AssocArrayLiteralExp::interpret(InterState *istate) -{ Expressions *keysx = keys; - Expressions *valuesx = values; - -#if LOG - printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); -#endif - for (size_t i = 0; i < keys->dim; i++) - { Expression *ekey = (Expression *)keys->data[i]; - Expression *evalue = (Expression *)values->data[i]; - Expression *ex; - - ex = ekey->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - - /* If any changes, do Copy On Write - */ - if (ex != ekey) - { - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - keysx->data[i] = (void *)ex; - } - - ex = evalue->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - - /* If any changes, do Copy On Write - */ - if (ex != evalue) - { - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - valuesx->data[i] = (void *)ex; - } - } - if (keysx != keys) - expandTuples(keysx); - if (valuesx != values) - expandTuples(valuesx); - if (keysx->dim != valuesx->dim) - goto Lerr; - - /* Remove duplicate keys - */ - for (size_t i = 1; i < keysx->dim; i++) - { Expression *ekey = (Expression *)keysx->data[i - 1]; - - for (size_t j = i; j < keysx->dim; j++) - { Expression *ekey2 = (Expression *)keysx->data[j]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->isBool(TRUE)) // if a match - { - // Remove ekey - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - keysx->remove(i - 1); - valuesx->remove(i - 1); - i -= 1; // redo the i'th iteration - break; - } - } - } - - if (keysx != keys || valuesx != values) - { - AssocArrayLiteralExp *ae; - ae = new AssocArrayLiteralExp(loc, keysx, valuesx); - ae->type = type; - return ae; - } - return this; - -Lerr: - if (keysx != keys) - delete keysx; - if (valuesx != values) - delete values; - return EXP_CANT_INTERPRET; -} - -Expression *StructLiteralExp::interpret(InterState *istate) -{ Expressions *expsx = NULL; - -#if LOG - printf("StructLiteralExp::interpret() %s\n", toChars()); -#endif - /* We don't know how to deal with overlapping fields - */ - if (sd->hasUnions) - return EXP_CANT_INTERPRET; - - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (!e) - continue; - - Expression *ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - { delete expsx; - return EXP_CANT_INTERPRET; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - expsx->data[j] = elements->data[j]; - } - } - expsx->data[i] = (void *)ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - { delete expsx; - return EXP_CANT_INTERPRET; - } - StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); - se->type = type; - return se; - } - return this; -} - -Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)) -{ Expression *e; - Expression *e1; - -#if LOG - printf("UnaExp::interpretCommon() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1) - goto Lcant; - - e = (*fp)(type, e1); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define UNA_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon(istate, &op); \ -} - -UNA_INTERPRET(Neg) -UNA_INTERPRET(Com) -UNA_INTERPRET(Not) -UNA_INTERPRET(Bool) - - -typedef Expression *(*fp_t)(Type *, Expression *, Expression *); - -Expression *BinExp::interpretCommon(InterState *istate, fp_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1) - goto Lcant; - - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - if (e2->isConst() != 1) - goto Lcant; - - e = (*fp)(type, e1, e2); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon(istate, &op); \ -} - -BIN_INTERPRET(Add) -BIN_INTERPRET(Min) -BIN_INTERPRET(Mul) -BIN_INTERPRET(Div) -BIN_INTERPRET(Mod) -BIN_INTERPRET(Shl) -BIN_INTERPRET(Shr) -BIN_INTERPRET(Ushr) -BIN_INTERPRET(And) -BIN_INTERPRET(Or) -BIN_INTERPRET(Xor) - - -typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); - -Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon2() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1 && - e1->op != TOKnull && - e1->op != TOKstring && - e1->op != TOKarrayliteral && - e1->op != TOKstructliteral) - goto Lcant; - - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - if (e2->isConst() != 1 && - e2->op != TOKnull && - e2->op != TOKstring && - e2->op != TOKarrayliteral && - e2->op != TOKstructliteral) - goto Lcant; - - e = (*fp)(op, type, e1, e2); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET2(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon2(istate, &op); \ -} - -BIN_INTERPRET2(Equal) -BIN_INTERPRET2(Identity) -BIN_INTERPRET2(Cmp) - -Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) -{ -#if LOG - printf("BinExp::interpretAssignCommon() %s\n", toChars()); -#endif - Expression *e = EXP_CANT_INTERPRET; - Expression *e1 = this->e1; - - if (fp) - { - if (e1->op == TOKcast) - { CastExp *ce = (CastExp *)e1; - e1 = ce->e1; - } - } - if (e1 == EXP_CANT_INTERPRET) - return e1; - Expression *e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - return e2; - - /* Assignment to variable of the form: - * v = e2 - */ - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - 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->isSymbolDeclaration()) - { - /* This can happen if v is a struct initialized to - * 0 using an __initZ SymbolDeclaration 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()); - return e; - } - if (fp) - e2 = (*fp)(v->type, ev, e2); - else - { /* Look for special case of struct being initialized with 0. - */ - if (v->type->toBasetype()->ty == Tstruct && e2->op == TOKint64) - { - e2 = v->type->defaultInit(); - } - 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); - } - } - } - /* Assignment to struct member of the form: - * *(symoffexp) = e2 - */ - else if (e1->op == TOKstar && ((PtrExp *)e1)->e1->op == TOKsymoff) - { SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1; - VarDeclaration *v = soe->var->isVarDeclaration(); - - if (v->isDataseg()) - return EXP_CANT_INTERPRET; - if (fp && !v->value) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - Expression *vie = v->value; - if (vie->op == TOKvar) - { - Declaration *d = ((VarExp *)vie)->var; - vie = getVarExp(e1->loc, istate, d); - } - if (vie->op != TOKstructliteral) - return EXP_CANT_INTERPRET; - StructLiteralExp *se = (StructLiteralExp *)vie; - int fieldi = se->getFieldIndex(type, soe->offset); - if (fieldi == -1) - return EXP_CANT_INTERPRET; - Expression *ev = se->getField(type, soe->offset); - if (fp) - e2 = (*fp)(type, ev, e2); - else - 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; - } - } - - /* 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]; - } - v->value = new StructLiteralExp(se->loc, se->sd, expsx); - v->value->type = se->type; - - e = Cast(type, type, post ? ev : e2); - } - /* Assignment to array element of the form: - * a[i] = e2 - */ - else if (e1->op == TOKindex && ((IndexExp *)e1)->e1->op == TOKvar) - { IndexExp *ie = (IndexExp *)e1; - VarExp *ve = (VarExp *)ie->e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - - if (!v || v->isDataseg()) - return EXP_CANT_INTERPRET; - if (!v->value) - { - if (fp) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - - Type *t = v->type->toBasetype(); - if (t->ty == Tsarray) - { - /* This array was void initialized. Create a - * default initializer for it. - * What we should do is fill the array literal with - * NULL data, so use-before-initialized can be detected. - * 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; - } - else - return EXP_CANT_INTERPRET; - } - - ArrayLiteralExp *ae = NULL; - AssocArrayLiteralExp *aae = NULL; - StringExp *se = NULL; - if (v->value->op == TOKarrayliteral) - ae = (ArrayLiteralExp *)v->value; - else if (v->value->op == TOKassocarrayliteral) - aae = (AssocArrayLiteralExp *)v->value; - else if (v->value->op == TOKstring) - se = (StringExp *)v->value; - else - return EXP_CANT_INTERPRET; - - Expression *index = ie->e2->interpret(istate); - if (index == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - Expression *ev; - if (fp || ae || se) // not for aae, because key might not be there - { - ev = Index(type, v->value, index); - if (ev == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - } - - if (fp) - e2 = (*fp)(type, ev, e2); - else - 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; - } - } - - 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]; - } - v->value = new ArrayLiteralExp(ae->loc, expsx); - v->value->type = ae->type; - } - else if (aae) - { - /* Create new associative array literal reflecting updated key/value - */ - Expressions *keysx = aae->keys; - Expressions *valuesx = new Expressions(); - valuesx->setDim(aae->values->dim); - int updated = 0; - for (size_t j = valuesx->dim; j; ) - { j--; - Expression *ekey = (Expression *)aae->keys->data[j]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, index); - if (ex == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - if (ex->isBool(TRUE)) - { valuesx->data[j] = (void *)e2; - updated = 1; - } - else - valuesx->data[j] = aae->values->data[j]; - } - if (!updated) - { // Append index/e2 to keysx[]/valuesx[] - valuesx->push(e2); - keysx = (Expressions *)keysx->copy(); - keysx->push(index); - } - v->value = new AssocArrayLiteralExp(aae->loc, keysx, valuesx); - v->value->type = aae->type; - } - else if (se) - { - /* Create new string literal reflecting updated elem - */ - int elemi = index->toInteger(); - unsigned char *s; - s = (unsigned char *)mem.calloc(se->len + 1, se->sz); - memcpy(s, se->string, se->len * se->sz); - unsigned value = e2->toInteger(); - switch (se->sz) - { - case 1: s[elemi] = value; break; - case 2: ((unsigned short *)s)[elemi] = value; break; - case 4: ((unsigned *)s)[elemi] = value; break; - default: - assert(0); - break; - } - StringExp *se2 = new StringExp(se->loc, s, se->len); - se2->committed = se->committed; - se2->postfix = se->postfix; - se2->type = se->type; - v->value = se2; - } - else - assert(0); - - e = Cast(type, type, post ? ev : e2); - } - else - { -#ifdef DEBUG - dump(0); -#endif - } - return e; -} - -Expression *AssignExp::interpret(InterState *istate) -{ - return interpretAssignCommon(istate, NULL); -} - -#define BIN_ASSIGN_INTERPRET(op) \ -Expression *op##AssignExp::interpret(InterState *istate) \ -{ \ - return interpretAssignCommon(istate, &op); \ -} - -BIN_ASSIGN_INTERPRET(Add) -BIN_ASSIGN_INTERPRET(Min) -BIN_ASSIGN_INTERPRET(Cat) -BIN_ASSIGN_INTERPRET(Mul) -BIN_ASSIGN_INTERPRET(Div) -BIN_ASSIGN_INTERPRET(Mod) -BIN_ASSIGN_INTERPRET(Shl) -BIN_ASSIGN_INTERPRET(Shr) -BIN_ASSIGN_INTERPRET(Ushr) -BIN_ASSIGN_INTERPRET(And) -BIN_ASSIGN_INTERPRET(Or) -BIN_ASSIGN_INTERPRET(Xor) - -Expression *PostExp::interpret(InterState *istate) -{ -#if LOG - printf("PostExp::interpret() %s\n", toChars()); -#endif - Expression *e; - if (op == TOKplusplus) - e = interpretAssignCommon(istate, &Add, 1); - else - e = interpretAssignCommon(istate, &Min, 1); -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PostExp::interpret() CANT\n"); -#endif - return e; -} - -Expression *AndAndExp::interpret(InterState *istate) -{ -#if LOG - printf("AndAndExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - { - e = e2->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); - else - e = EXP_CANT_INTERPRET; - } - } - else - e = EXP_CANT_INTERPRET; - } - return e; -} - -Expression *OrOrExp::interpret(InterState *istate) -{ -#if LOG - printf("OrOrExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); - else if (e->isBool(FALSE)) - { - e = e2->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); - else - e = EXP_CANT_INTERPRET; - } - } - else - e = EXP_CANT_INTERPRET; - } - return e; -} - - -Expression *CallExp::interpret(InterState *istate) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("CallExp::interpret() %s\n", toChars()); -#endif - if (e1->op == TOKvar) - { - FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); - if (fd) - { -#if DMDV2 - enum BUILTIN b = fd->isBuiltin(); - if (b) - { Expressions args; - args.setDim(arguments->dim); - for (size_t i = 0; i < args.dim; i++) - { - Expression *earg = (Expression *)arguments->data[i]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return earg; - args.data[i] = (void *)earg; - } - e = eval_builtin(b, &args); - if (!e) - e = EXP_CANT_INTERPRET; - } - else -#endif - // Inline .dup - if (fd->ident == Id::adDup && arguments && arguments->dim == 2) - { - e = (Expression *)arguments->data[1]; - e = e->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - e = expType(type, e); - } - } - else - { - Expression *eresult = fd->interpret(istate, arguments); - if (eresult) - e = eresult; - else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) - e = EXP_VOID_INTERPRET; - else - error("cannot evaluate %s at compile time", toChars()); - } - } - } - return e; -} - -Expression *CommaExp::interpret(InterState *istate) -{ -#if LOG - printf("CommaExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - e = e2->interpret(istate); - return e; -} - -Expression *CondExp::interpret(InterState *istate) -{ -#if LOG - printf("CondExp::interpret() %s\n", toChars()); -#endif - Expression *e = econd->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(TRUE)) - e = e1->interpret(istate); - else if (e->isBool(FALSE)) - e = e2->interpret(istate); - else - e = EXP_CANT_INTERPRET; - } - return e; -} - -Expression *ArrayLengthExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - -#if LOG - printf("ArrayLengthExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) - { - e = ArrayLength(type, e1); - } - else if (e1->op == TOKnull) - { - e = new IntegerExp(loc, 0, type); - } - else - goto Lcant; - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -Expression *IndexExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("IndexExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - - if (e1->op == TOKstring || e1->op == TOKarrayliteral) - { - /* Set the $ variable - */ - e = ArrayLength(Type::tsize_t, e1); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - if (lengthVar) - lengthVar->value = e; - } - - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - return Index(type, e1, e2); - -Lcant: - return EXP_CANT_INTERPRET; -} - - -Expression *SliceExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - Expression *lwr; - Expression *upr; - -#if LOG - printf("SliceExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (!this->lwr) - { - e = e1->castTo(NULL, type); - return e->interpret(istate); - } - - /* Set the $ variable - */ - e = ArrayLength(Type::tsize_t, e1); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - if (lengthVar) - lengthVar->value = e; - - /* Evaluate lower and upper bounds of slice - */ - lwr = this->lwr->interpret(istate); - if (lwr == EXP_CANT_INTERPRET) - goto Lcant; - upr = this->upr->interpret(istate); - if (upr == EXP_CANT_INTERPRET) - goto Lcant; - - return Slice(type, e1, lwr, upr); - -Lcant: - return EXP_CANT_INTERPRET; -} - - -Expression *CatExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("CatExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - { - goto Lcant; - } - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - return Cat(type, e1, e2); - -Lcant: -#if LOG - printf("CatExp::interpret() %s CANT\n", toChars()); -#endif - return EXP_CANT_INTERPRET; -} - - -Expression *CastExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - -#if LOG - printf("CastExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - return Cast(type, to, e1); - -Lcant: -#if LOG - printf("CastExp::interpret() %s CANT\n", toChars()); -#endif - return EXP_CANT_INTERPRET; -} - - -Expression *AssertExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - -#if LOG - printf("AssertExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isBool(TRUE)) - { - } - else if (e1->isBool(FALSE)) - { - if (msg) - { - e = msg->interpret(istate); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - error("%s", e->toChars()); - } - else - error("%s failed", toChars()); - goto Lcant; - } - else - goto Lcant; - return e1; - -Lcant: - return EXP_CANT_INTERPRET; -} - -Expression *PtrExp::interpret(InterState *istate) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("PtrExp::interpret() %s\n", toChars()); -#endif - - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - Expression *ex = ade->e1; - ex = ex->interpret(istate); - if (ex != EXP_CANT_INTERPRET) - { - if (ex->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ex; - unsigned offset = ae->e2->toInteger(); - e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - } - e = Ptr(type, e1); - } - else if (e1->op == TOKsymoff) - { SymOffExp *soe = (SymOffExp *)e1; - VarDeclaration *v = soe->var->isVarDeclaration(); - if (v) - { Expression *ev = getVarExp(loc, istate, v); - if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ev; - e = se->getField(type, soe->offset); - if (!e) - e = EXP_CANT_INTERPRET; - } - } - } -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); -#endif - return e; -} - -Expression *DotVarExp::interpret(InterState *istate) -{ Expression *e = EXP_CANT_INTERPRET; - - Expression *ex = e1->interpret(istate); - - // Constant fold structliteral.member - if (ex != EXP_CANT_INTERPRET && ex->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ex; - - VarDeclaration* v; - if (v = var->isVarDeclaration()) - { - e = se->getField(type, v->offset); - if (!e) - e = EXP_CANT_INTERPRET; - } - } - - return e; -} - -/******************************* Special Functions ***************************/ - -Expression *interpret_aaLen(InterState *istate, Expressions *arguments) -{ - if (!arguments || arguments->dim != 1) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t); - return e; -} - -Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) -{ - //printf("interpret_aaKeys()\n"); - if (!arguments || arguments->dim != 2) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); - return e; -} - -Expression *interpret_aaValues(InterState *istate, Expressions *arguments) -{ - //printf("interpret_aaValues()\n"); - if (!arguments || arguments->dim != 3) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->values); - //printf("result is %s\n", e->toChars()); - return e; -} - + +// 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 <stdlib.h> +#include <assert.h> + +#include "mem.h" + +#include "statement.h" +#include "expression.h" +#include "cond.h" +#include "init.h" +#include "staticassert.h" +#include "mtype.h" +#include "scope.h" +#include "declaration.h" +#include "aggregate.h" +#include "id.h" + +#define LOG 0 + +struct InterState +{ + InterState *caller; // calling function's InterState + FuncDeclaration *fd; // function being interpreted + Dsymbols vars; // variables used in this function + Statement *start; // if !=NULL, start execution at this statement + Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result + + InterState(); +}; + +InterState::InterState() +{ + memset(this, 0, sizeof(InterState)); +} + +Expression *interpret_aaLen(InterState *istate, Expressions *arguments); +Expression *interpret_aaKeys(InterState *istate, Expressions *arguments); +Expression *interpret_aaValues(InterState *istate, Expressions *arguments); + +/************************************* + * Attempt to interpret a function given the arguments. + * Input: + * istate state for calling function (NULL if none) + * Return result expression if successful, NULL if not. + */ + +Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments) +{ +#if LOG + printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); + printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun); +#endif + if (global.errors) + return NULL; + if (ident == Id::aaLen) + return interpret_aaLen(istate, arguments); + else if (ident == Id::aaKeys) + return interpret_aaKeys(istate, arguments); + else if (ident == Id::aaValues) + return interpret_aaValues(istate, arguments); + + if (cantInterpret || semanticRun == 1) + return NULL; + + if (needThis() || isNested() || !fbody) + { cantInterpret = 1; + return NULL; + } + + if (semanticRun == 0 && scope) + { + semantic3(scope); + if (global.errors) // if errors compiling this function + return NULL; + } + if (semanticRun < 2) + return NULL; + + Type *tb = type->toBasetype(); + assert(tb->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)tb; + Type *tret = tf->next->toBasetype(); + if (tf->varargs /*|| tret->ty == Tvoid*/) + { cantInterpret = 1; + return NULL; + } + + if (tf->parameters) + { size_t dim = Argument::dim(tf->parameters); + for (size_t i = 0; i < dim; i++) + { Argument *arg = Argument::getNth(tf->parameters, i); + if (arg->storageClass & STClazy) + { cantInterpret = 1; + return NULL; + } + } + } + + InterState istatex; + istatex.caller = istate; + istatex.fd = this; + + Expressions vsave; // place to save previous parameter values + size_t dim = 0; + if (arguments) + { + dim = arguments->dim; + assert(!dim || parameters->dim == dim); + vsave.setDim(dim); + + /* Evaluate all the arguments to the function, + * store the results in eargs[] + */ + Expressions eargs; + eargs.setDim(dim); + + for (size_t i = 0; i < dim; i++) + { Expression *earg = (Expression *)arguments->data[i]; + Argument *arg = Argument::getNth(tf->parameters, i); + + if (arg->storageClass & (STCout | STCref)) + { + } + else + { /* Value parameters + */ + Type *ta = arg->type->toBasetype(); + if (ta->ty == Tsarray && earg->op == TOKaddress) + { + /* Static arrays are passed by a simple pointer. + * Skip past this to get at the actual arg. + */ + earg = ((AddrExp *)earg)->e1; + } + earg = earg->interpret(istate ? istate : &istatex); + if (earg == EXP_CANT_INTERPRET) + return NULL; + } + eargs.data[i] = earg; + } + + for (size_t i = 0; i < dim; i++) + { Expression *earg = (Expression *)eargs.data[i]; + Argument *arg = Argument::getNth(tf->parameters, i); + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + vsave.data[i] = v->value; +#if LOG + printf("arg[%d] = %s\n", i, earg->toChars()); +#endif + if (arg->storageClass & (STCout | STCref)) + { + /* Bind out or ref parameter to the corresponding + * variable v2 + */ + if (!istate || earg->op != TOKvar) + return NULL; // can't bind to non-interpreted vars + + VarDeclaration *v2; + while (1) + { + VarExp *ve = (VarExp *)earg; + v2 = ve->var->isVarDeclaration(); + if (!v2) + return NULL; + if (!v2->value || v2->value->op != TOKvar) + break; + earg = v2->value; + } + + v->value = new VarExp(earg->loc, v2); + + /* Don't restore the value of v2 upon function return + */ + assert(istate); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v == v2) + { istate->vars.data[i] = NULL; + break; + } + } + } + else + { /* Value parameters + */ + v->value = earg; + } +#if LOG + printf("interpreted arg[%d] = %s\n", i, earg->toChars()); +#endif + } + } + + /* Save the values of the local variables used + */ + Expressions valueSaves; + if (istate) + { + //printf("saving local variables...\n"); + valueSaves.setDim(istate->vars.dim); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v) + { + //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); + valueSaves.data[i] = v->value; + v->value = NULL; + } + } + } + + Expression *e = NULL; + + while (1) + { + e = fbody->interpret(&istatex); + if (e == EXP_CANT_INTERPRET) + { +#if LOG + printf("function body failed to interpret\n"); +#endif + e = NULL; + } + + /* This is how we deal with a recursive statement AST + * that has arbitrary goto statements in it. + * Bubble up a 'result' which is the target of the goto + * statement, then go recursively down the AST looking + * for that statement, then execute starting there. + */ + if (e == EXP_GOTO_INTERPRET) + { + istatex.start = istatex.gotoTarget; // set starting statement + istatex.gotoTarget = NULL; + } + else + break; + } + + /* Restore the parameter values + */ + for (size_t i = 0; i < dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + v->value = (Expression *)vsave.data[i]; + } + + if (istate) + { + /* Restore the variable values + */ + //printf("restoring local variables...\n"); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v) + { v->value = (Expression *)valueSaves.data[i]; + //printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); + } + } + } + + return e; +} + +/******************************** Statement ***************************/ + +#define START() \ + if (istate->start) \ + { if (istate->start != this) \ + return NULL; \ + istate->start = NULL; \ + } + +/*********************************** + * Interpret the statement. + * Returns: + * NULL continue to next statement + * EXP_CANT_INTERPRET cannot interpret statement at compile time + * !NULL expression from return statement + */ + +Expression *Statement::interpret(InterState *istate) +{ +#if LOG + printf("Statement::interpret()\n"); +#endif + START() + return EXP_CANT_INTERPRET; +} + +Expression *ExpStatement::interpret(InterState *istate) +{ +#if LOG + printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : ""); +#endif + START() + if (exp) + { + Expression *e = exp->interpret(istate); + if (e == EXP_CANT_INTERPRET) + { + //printf("-ExpStatement::interpret(): %p\n", e); + return EXP_CANT_INTERPRET; + } + } + return NULL; +} + +Expression *CompoundStatement::interpret(InterState *istate) +{ Expression *e = NULL; + +#if LOG + printf("CompoundStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (statements) + { + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (s) + { + e = s->interpret(istate); + if (e) + break; + } + } + } +#if LOG + printf("-CompoundStatement::interpret() %p\n", e); +#endif + return e; +} + +Expression *UnrolledLoopStatement::interpret(InterState *istate) +{ Expression *e = NULL; + +#if LOG + printf("UnrolledLoopStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (statements) + { + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + e = s->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_CONTINUE_INTERPRET) + { e = NULL; + continue; + } + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e) + break; + } + } + return e; +} + +Expression *IfStatement::interpret(InterState *istate) +{ +#if LOG + printf("IfStatement::interpret(%s)\n", condition->toChars()); +#endif + + if (istate->start == this) + istate->start = NULL; + if (istate->start) + { + Expression *e = NULL; + if (ifbody) + e = ifbody->interpret(istate); + if (istate->start && elsebody) + e = elsebody->interpret(istate); + return e; + } + + Expression *e = condition->interpret(istate); + assert(e); + //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n"); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(TRUE)) + e = ifbody ? ifbody->interpret(istate) : NULL; + else if (e->isBool(FALSE)) + e = elsebody ? elsebody->interpret(istate) : NULL; + else + { + e = EXP_CANT_INTERPRET; + } + } + return e; +} + +Expression *ScopeStatement::interpret(InterState *istate) +{ +#if LOG + printf("ScopeStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + return statement ? statement->interpret(istate) : NULL; +} + +Expression *ReturnStatement::interpret(InterState *istate) +{ +#if LOG + printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : ""); +#endif + START() + if (!exp) + return EXP_VOID_INTERPRET; +#if LOG + Expression *e = exp->interpret(istate); + printf("e = %p\n", e); + return e; +#else + return exp->interpret(istate); +#endif +} + +Expression *BreakStatement::interpret(InterState *istate) +{ +#if LOG + printf("BreakStatement::interpret()\n"); +#endif + START() + if (ident) + return EXP_CANT_INTERPRET; + else + return EXP_BREAK_INTERPRET; +} + +Expression *ContinueStatement::interpret(InterState *istate) +{ +#if LOG + printf("ContinueStatement::interpret()\n"); +#endif + START() + if (ident) + return EXP_CANT_INTERPRET; + else + return EXP_CONTINUE_INTERPRET; +} + +Expression *WhileStatement::interpret(InterState *istate) +{ +#if LOG + printf("WhileStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e; + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + if (e != EXP_CONTINUE_INTERPRET) + return e; + } + + while (1) + { + e = condition->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(TRUE)) + { e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_CONTINUE_INTERPRET) + continue; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e) + break; + } + else if (e->isBool(FALSE)) + { e = NULL; + break; + } + else + assert(0); + } + return e; +} + +Expression *DoStatement::interpret(InterState *istate) +{ +#if LOG + printf("DoStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e; + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + if (e == EXP_CONTINUE_INTERPRET) + goto Lcontinue; + if (e) + return e; + } + + while (1) + { + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e && e != EXP_CONTINUE_INTERPRET) + break; + + Lcontinue: + e = condition->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(TRUE)) + { + } + else if (e->isBool(FALSE)) + { e = NULL; + break; + } + else + assert(0); + } + return e; +} + +Expression *ForStatement::interpret(InterState *istate) +{ +#if LOG + printf("ForStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e; + + if (init) + { + e = init->interpret(istate); + if (e == EXP_CANT_INTERPRET) + return e; + assert(!e); + } + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + if (e == EXP_CONTINUE_INTERPRET) + goto Lcontinue; + if (e) + return e; + } + + while (1) + { + if (!condition) + goto Lhead; + e = condition->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(TRUE)) + { + Lhead: + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e && e != EXP_CONTINUE_INTERPRET) + break; + Lcontinue: + if (increment) + { + e = increment->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + } + } + else if (e->isBool(FALSE)) + { e = NULL; + break; + } + else + assert(0); + } + return e; +} + +Expression *ForeachStatement::interpret(InterState *istate) +{ +#if LOG + printf("ForeachStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (istate->start) + return NULL; + + Expression *e = NULL; + Expression *eaggr; + + if (value->isOut() || value->isRef()) + return EXP_CANT_INTERPRET; + + eaggr = aggr->interpret(istate); + if (eaggr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *dim = ArrayLength(Type::tsize_t, eaggr); + if (dim == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *keysave = key ? key->value : NULL; + Expression *valuesave = value->value; + + uinteger_t d = dim->toUInteger(); + uinteger_t index; + + if (op == TOKforeach) + { + for (index = 0; index < d; index++) + { + Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); + if (key) + key->value = ekey; + e = Index(value->type, eaggr, ekey); + if (e == EXP_CANT_INTERPRET) + break; + value->value = e; + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e == EXP_CONTINUE_INTERPRET) + e = NULL; + else if (e) + break; + } + } + else // TOKforeach_reverse + { + for (index = d; index-- != 0;) + { + Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); + if (key) + key->value = ekey; + e = Index(value->type, eaggr, ekey); + if (e == EXP_CANT_INTERPRET) + break; + value->value = e; + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e == EXP_CONTINUE_INTERPRET) + e = NULL; + else if (e) + break; + } + } + value->value = valuesave; + if (key) + key->value = keysave; + return e; +} + +#if DMDV2 +Expression *ForeachRangeStatement::interpret(InterState *istate) +{ +#if LOG + printf("ForeachRangeStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (istate->start) + return NULL; + + Expression *e = NULL; + Expression *elwr = lwr->interpret(istate); + if (elwr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *eupr = upr->interpret(istate); + if (eupr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *keysave = key->value; + + if (op == TOKforeach) + { + key->value = elwr; + + while (1) + { + e = Cmp(TOKlt, key->value->type, key->value, upr); + if (e == EXP_CANT_INTERPRET) + break; + if (e->isBool(TRUE) == FALSE) + { e = NULL; + break; + } + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); + if (e == EXP_CANT_INTERPRET) + break; + key->value = e; + } + } + else // TOKforeach_reverse + { + key->value = eupr; + + while (1) + { + e = Cmp(TOKgt, key->value->type, key->value, lwr); + if (e == EXP_CANT_INTERPRET) + break; + if (e->isBool(TRUE) == FALSE) + { e = NULL; + break; + } + + e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); + if (e == EXP_CANT_INTERPRET) + break; + key->value = e; + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + } + } + key->value = keysave; + return e; +} +#endif + +Expression *SwitchStatement::interpret(InterState *istate) +{ +#if LOG + printf("SwitchStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e = NULL; + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + return e; + } + + + Expression *econdition = condition->interpret(istate); + if (econdition == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Statement *s = NULL; + if (cases) + { + for (size_t i = 0; i < cases->dim; i++) + { + CaseStatement *cs = (CaseStatement *)cases->data[i]; + e = Equal(TOKequal, Type::tint32, econdition, cs->exp); + if (e == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + if (e->isBool(TRUE)) + { s = cs; + break; + } + } + } + if (!s) + { if (hasNoDefault) + error("no default or case for %s in switch statement", econdition->toChars()); + s = sdefault; + } + + assert(s); + istate->start = s; + e = body ? body->interpret(istate) : NULL; + assert(!istate->start); + if (e == EXP_BREAK_INTERPRET) + return NULL; + return e; +} + +Expression *CaseStatement::interpret(InterState *istate) +{ +#if LOG + printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this); +#endif + if (istate->start == this) + istate->start = NULL; + if (statement) + return statement->interpret(istate); + else + return NULL; +} + +Expression *DefaultStatement::interpret(InterState *istate) +{ +#if LOG + printf("DefaultStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (statement) + return statement->interpret(istate); + else + return NULL; +} + +Expression *GotoStatement::interpret(InterState *istate) +{ +#if LOG + printf("GotoStatement::interpret()\n"); +#endif + START() + assert(label && label->statement); + istate->gotoTarget = label->statement; + return EXP_GOTO_INTERPRET; +} + +Expression *GotoCaseStatement::interpret(InterState *istate) +{ +#if LOG + printf("GotoCaseStatement::interpret()\n"); +#endif + START() + assert(cs); + istate->gotoTarget = cs; + return EXP_GOTO_INTERPRET; +} + +Expression *GotoDefaultStatement::interpret(InterState *istate) +{ +#if LOG + printf("GotoDefaultStatement::interpret()\n"); +#endif + START() + assert(sw && sw->sdefault); + istate->gotoTarget = sw->sdefault; + return EXP_GOTO_INTERPRET; +} + +Expression *LabelStatement::interpret(InterState *istate) +{ +#if LOG + printf("LabelStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + return statement ? statement->interpret(istate) : NULL; +} + +/******************************** Expression ***************************/ + +Expression *Expression::interpret(InterState *istate) +{ +#if LOG + printf("Expression::interpret() %s\n", toChars()); + printf("type = %s\n", type->toChars()); + dump(0); +#endif + return EXP_CANT_INTERPRET; +} + +Expression *NullExp::interpret(InterState *istate) +{ + return this; +} + +Expression *IntegerExp::interpret(InterState *istate) +{ +#if LOG + printf("IntegerExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *RealExp::interpret(InterState *istate) +{ +#if LOG + printf("RealExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *ComplexExp::interpret(InterState *istate) +{ + return this; +} + +Expression *StringExp::interpret(InterState *istate) +{ +#if LOG + printf("StringExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) +{ + Expression *e = EXP_CANT_INTERPRET; + VarDeclaration *v = d->isVarDeclaration(); + SymbolDeclaration *s = d->isSymbolDeclaration(); + if (v) + { +#if DMDV2 + if ((v->isConst() || v->isInvariant()) && v->init && !v->value) +#else + if (v->isConst() && v->init) +#endif + { e = v->init->toExpression(); + if (e && !e->type) + e->type = v->type; + } + else + { e = v->value; + if (!e) + error(loc, "variable %s is used before initialization", v->toChars()); + else if (e != EXP_CANT_INTERPRET) + e = e->interpret(istate); + } + if (!e) + e = EXP_CANT_INTERPRET; + } + else if (s) + { + if (s->dsym->toInitializer() == s->sym) + { Expressions *exps = new Expressions(); + e = new StructLiteralExp(0, s->dsym, exps); + e = e->semantic(NULL); + } + } + return e; +} + +Expression *VarExp::interpret(InterState *istate) +{ +#if LOG + printf("VarExp::interpret() %s\n", toChars()); +#endif + return getVarExp(loc, istate, var); +} + +Expression *DeclarationExp::interpret(InterState *istate) +{ +#if LOG + printf("DeclarationExp::interpret() %s\n", toChars()); +#endif + Expression *e; + VarDeclaration *v = declaration->isVarDeclaration(); + if (v) + { + Dsymbol *s = v->toAlias(); + if (s == v && !v->isStatic() && v->init) + { + ExpInitializer *ie = v->init->isExpInitializer(); + if (ie) + e = ie->exp->interpret(istate); + else if (v->init->isVoidInitializer()) + e = NULL; + } +#if DMDV2 + else if (s == v && (v->isConst() || v->isInvariant()) && v->init) +#else + else if (s == v && v->isConst() && v->init) +#endif + { e = v->init->toExpression(); + if (!e) + e = EXP_CANT_INTERPRET; + else if (!e->type) + e->type = v->type; + } + } + else if (declaration->isAttribDeclaration() || + declaration->isTemplateMixin() || + declaration->isTupleDeclaration()) + { // These can be made to work, too lazy now + e = EXP_CANT_INTERPRET; + } + else + { // Others should not contain executable code, so are trivial to evaluate + e = NULL; + } +#if LOG + printf("-DeclarationExp::interpret(): %p\n", e); +#endif + return e; +} + +Expression *TupleExp::interpret(InterState *istate) +{ +#if LOG + printf("TupleExp::interpret() %s\n", toChars()); +#endif + Expressions *expsx = NULL; + + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + Expression *ex; + + ex = e->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + { delete expsx; + return ex; + } + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + expsx->setDim(exps->dim); + for (size_t j = 0; j < i; j++) + { + expsx->data[j] = exps->data[j]; + } + } + expsx->data[i] = (void *)ex; + } + } + if (expsx) + { TupleExp *te = new TupleExp(loc, expsx); + expandTuples(te->exps); + te->type = new TypeTuple(te->exps); + return te; + } + return this; +} + +Expression *ArrayLiteralExp::interpret(InterState *istate) +{ Expressions *expsx = NULL; + +#if LOG + printf("ArrayLiteralExp::interpret() %s\n", toChars()); +#endif + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + Expression *ex; + + ex = e->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + { delete expsx; + return EXP_CANT_INTERPRET; + } + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + expsx->setDim(elements->dim); + for (size_t j = 0; j < elements->dim; j++) + { + expsx->data[j] = elements->data[j]; + } + } + expsx->data[i] = (void *)ex; + } + } + } + if (elements && expsx) + { + expandTuples(expsx); + if (expsx->dim != elements->dim) + { delete expsx; + return EXP_CANT_INTERPRET; + } + ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); + ae->type = type; + return ae; + } + return this; +} + +Expression *AssocArrayLiteralExp::interpret(InterState *istate) +{ Expressions *keysx = keys; + Expressions *valuesx = values; + +#if LOG + printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); +#endif + for (size_t i = 0; i < keys->dim; i++) + { Expression *ekey = (Expression *)keys->data[i]; + Expression *evalue = (Expression *)values->data[i]; + Expression *ex; + + ex = ekey->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + goto Lerr; + + /* If any changes, do Copy On Write + */ + if (ex != ekey) + { + if (keysx == keys) + keysx = (Expressions *)keys->copy(); + keysx->data[i] = (void *)ex; + } + + ex = evalue->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + goto Lerr; + + /* If any changes, do Copy On Write + */ + if (ex != evalue) + { + if (valuesx == values) + valuesx = (Expressions *)values->copy(); + valuesx->data[i] = (void *)ex; + } + } + if (keysx != keys) + expandTuples(keysx); + if (valuesx != values) + expandTuples(valuesx); + if (keysx->dim != valuesx->dim) + goto Lerr; + + /* Remove duplicate keys + */ + for (size_t i = 1; i < keysx->dim; i++) + { Expression *ekey = (Expression *)keysx->data[i - 1]; + + for (size_t j = i; j < keysx->dim; j++) + { Expression *ekey2 = (Expression *)keysx->data[j]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2); + if (ex == EXP_CANT_INTERPRET) + goto Lerr; + if (ex->isBool(TRUE)) // if a match + { + // Remove ekey + if (keysx == keys) + keysx = (Expressions *)keys->copy(); + if (valuesx == values) + valuesx = (Expressions *)values->copy(); + keysx->remove(i - 1); + valuesx->remove(i - 1); + i -= 1; // redo the i'th iteration + break; + } + } + } + + if (keysx != keys || valuesx != values) + { + AssocArrayLiteralExp *ae; + ae = new AssocArrayLiteralExp(loc, keysx, valuesx); + ae->type = type; + return ae; + } + return this; + +Lerr: + if (keysx != keys) + delete keysx; + if (valuesx != values) + delete values; + return EXP_CANT_INTERPRET; +} + +Expression *StructLiteralExp::interpret(InterState *istate) +{ Expressions *expsx = NULL; + +#if LOG + printf("StructLiteralExp::interpret() %s\n", toChars()); +#endif + /* We don't know how to deal with overlapping fields + */ + if (sd->hasUnions) + return EXP_CANT_INTERPRET; + + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + if (!e) + continue; + + Expression *ex = e->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + { delete expsx; + return EXP_CANT_INTERPRET; + } + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + expsx->setDim(elements->dim); + for (size_t j = 0; j < elements->dim; j++) + { + expsx->data[j] = elements->data[j]; + } + } + expsx->data[i] = (void *)ex; + } + } + } + if (elements && expsx) + { + expandTuples(expsx); + if (expsx->dim != elements->dim) + { delete expsx; + return EXP_CANT_INTERPRET; + } + StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); + se->type = type; + return se; + } + return this; +} + +Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)) +{ Expression *e; + Expression *e1; + +#if LOG + printf("UnaExp::interpretCommon() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isConst() != 1) + goto Lcant; + + e = (*fp)(type, e1); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +#define UNA_INTERPRET(op) \ +Expression *op##Exp::interpret(InterState *istate) \ +{ \ + return interpretCommon(istate, &op); \ +} + +UNA_INTERPRET(Neg) +UNA_INTERPRET(Com) +UNA_INTERPRET(Not) +UNA_INTERPRET(Bool) + + +typedef Expression *(*fp_t)(Type *, Expression *, Expression *); + +Expression *BinExp::interpretCommon(InterState *istate, fp_t fp) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("BinExp::interpretCommon() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isConst() != 1) + goto Lcant; + + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + if (e2->isConst() != 1) + goto Lcant; + + e = (*fp)(type, e1, e2); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +#define BIN_INTERPRET(op) \ +Expression *op##Exp::interpret(InterState *istate) \ +{ \ + return interpretCommon(istate, &op); \ +} + +BIN_INTERPRET(Add) +BIN_INTERPRET(Min) +BIN_INTERPRET(Mul) +BIN_INTERPRET(Div) +BIN_INTERPRET(Mod) +BIN_INTERPRET(Shl) +BIN_INTERPRET(Shr) +BIN_INTERPRET(Ushr) +BIN_INTERPRET(And) +BIN_INTERPRET(Or) +BIN_INTERPRET(Xor) + + +typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); + +Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("BinExp::interpretCommon2() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isConst() != 1 && + e1->op != TOKnull && + e1->op != TOKstring && + e1->op != TOKarrayliteral && + e1->op != TOKstructliteral) + goto Lcant; + + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + if (e2->isConst() != 1 && + e2->op != TOKnull && + e2->op != TOKstring && + e2->op != TOKarrayliteral && + e2->op != TOKstructliteral) + goto Lcant; + + e = (*fp)(op, type, e1, e2); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +#define BIN_INTERPRET2(op) \ +Expression *op##Exp::interpret(InterState *istate) \ +{ \ + return interpretCommon2(istate, &op); \ +} + +BIN_INTERPRET2(Equal) +BIN_INTERPRET2(Identity) +BIN_INTERPRET2(Cmp) + +Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) +{ +#if LOG + printf("BinExp::interpretAssignCommon() %s\n", toChars()); +#endif + Expression *e = EXP_CANT_INTERPRET; + Expression *e1 = this->e1; + + if (fp) + { + if (e1->op == TOKcast) + { CastExp *ce = (CastExp *)e1; + e1 = ce->e1; + } + } + if (e1 == EXP_CANT_INTERPRET) + return e1; + Expression *e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + return e2; + + /* Assignment to variable of the form: + * v = e2 + */ + if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + 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->isSymbolDeclaration()) + { + /* This can happen if v is a struct initialized to + * 0 using an __initZ SymbolDeclaration 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()); + return e; + } + if (fp) + e2 = (*fp)(v->type, ev, e2); + else + { /* Look for special case of struct being initialized with 0. + */ + if (v->type->toBasetype()->ty == Tstruct && e2->op == TOKint64) + { + e2 = v->type->defaultInit(); + } + 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); + } + } + } + /* 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(); + + if (v->isDataseg()) + return EXP_CANT_INTERPRET; + if (fp && !v->value) + { error("variable %s is used before initialization", v->toChars()); + return e; + } + Expression *vie = v->value; + if (vie->op == TOKvar) + { + Declaration *d = ((VarExp *)vie)->var; + vie = getVarExp(e1->loc, istate, d); + } + if (vie->op != TOKstructliteral) + return EXP_CANT_INTERPRET; + 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; + + 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; + } + } + + /* 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]; + } + v->value = new StructLiteralExp(se->loc, se->sd, expsx); + v->value->type = se->type; + + e = Cast(type, type, post ? ev : e2); + } + /* Assignment to struct member of the form: + * *(symoffexp) = e2 + */ + else if (e1->op == TOKstar && ((PtrExp *)e1)->e1->op == TOKsymoff) + { SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1; + VarDeclaration *v = soe->var->isVarDeclaration(); + + if (v->isDataseg()) + return EXP_CANT_INTERPRET; + if (fp && !v->value) + { error("variable %s is used before initialization", v->toChars()); + return e; + } + Expression *vie = v->value; + if (vie->op == TOKvar) + { + Declaration *d = ((VarExp *)vie)->var; + vie = getVarExp(e1->loc, istate, d); + } + if (vie->op != TOKstructliteral) + return EXP_CANT_INTERPRET; + StructLiteralExp *se = (StructLiteralExp *)vie; + int fieldi = se->getFieldIndex(type, soe->offset); + if (fieldi == -1) + return EXP_CANT_INTERPRET; + Expression *ev = se->getField(type, soe->offset); + if (fp) + e2 = (*fp)(type, ev, e2); + else + 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; + } + } + + /* 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]; + } + v->value = new StructLiteralExp(se->loc, se->sd, expsx); + v->value->type = se->type; + + e = Cast(type, type, post ? ev : e2); + } + /* Assignment to array element of the form: + * a[i] = e2 + */ + else if (e1->op == TOKindex && ((IndexExp *)e1)->e1->op == TOKvar) + { IndexExp *ie = (IndexExp *)e1; + VarExp *ve = (VarExp *)ie->e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + + if (!v || v->isDataseg()) + return EXP_CANT_INTERPRET; + if (!v->value) + { + if (fp) + { error("variable %s is used before initialization", v->toChars()); + return e; + } + + Type *t = v->type->toBasetype(); + if (t->ty == Tsarray) + { + /* This array was void initialized. Create a + * default initializer for it. + * What we should do is fill the array literal with + * NULL data, so use-before-initialized can be detected. + * 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; + } + else + return EXP_CANT_INTERPRET; + } + + ArrayLiteralExp *ae = NULL; + AssocArrayLiteralExp *aae = NULL; + StringExp *se = NULL; + if (v->value->op == TOKarrayliteral) + ae = (ArrayLiteralExp *)v->value; + else if (v->value->op == TOKassocarrayliteral) + aae = (AssocArrayLiteralExp *)v->value; + else if (v->value->op == TOKstring) + se = (StringExp *)v->value; + else + return EXP_CANT_INTERPRET; + + Expression *index = ie->e2->interpret(istate); + if (index == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + Expression *ev; + if (fp || ae || se) // not for aae, because key might not be there + { + ev = Index(type, v->value, index); + if (ev == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + + if (fp) + e2 = (*fp)(type, ev, e2); + else + 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; + } + } + + 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]; + } + v->value = new ArrayLiteralExp(ae->loc, expsx); + v->value->type = ae->type; + } + else if (aae) + { + /* Create new associative array literal reflecting updated key/value + */ + Expressions *keysx = aae->keys; + Expressions *valuesx = new Expressions(); + valuesx->setDim(aae->values->dim); + int updated = 0; + for (size_t j = valuesx->dim; j; ) + { j--; + Expression *ekey = (Expression *)aae->keys->data[j]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, index); + if (ex == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + if (ex->isBool(TRUE)) + { valuesx->data[j] = (void *)e2; + updated = 1; + } + else + valuesx->data[j] = aae->values->data[j]; + } + if (!updated) + { // Append index/e2 to keysx[]/valuesx[] + valuesx->push(e2); + keysx = (Expressions *)keysx->copy(); + keysx->push(index); + } + v->value = new AssocArrayLiteralExp(aae->loc, keysx, valuesx); + v->value->type = aae->type; + } + else if (se) + { + /* Create new string literal reflecting updated elem + */ + int elemi = index->toInteger(); + unsigned char *s; + s = (unsigned char *)mem.calloc(se->len + 1, se->sz); + memcpy(s, se->string, se->len * se->sz); + unsigned value = e2->toInteger(); + switch (se->sz) + { + case 1: s[elemi] = value; break; + case 2: ((unsigned short *)s)[elemi] = value; break; + case 4: ((unsigned *)s)[elemi] = value; break; + default: + assert(0); + break; + } + StringExp *se2 = new StringExp(se->loc, s, se->len); + se2->committed = se->committed; + se2->postfix = se->postfix; + se2->type = se->type; + v->value = se2; + } + else + assert(0); + + e = Cast(type, type, post ? ev : e2); + } + else + { +#ifdef DEBUG + dump(0); +#endif + } + return e; +} + +Expression *AssignExp::interpret(InterState *istate) +{ + return interpretAssignCommon(istate, NULL); +} + +#define BIN_ASSIGN_INTERPRET(op) \ +Expression *op##AssignExp::interpret(InterState *istate) \ +{ \ + return interpretAssignCommon(istate, &op); \ +} + +BIN_ASSIGN_INTERPRET(Add) +BIN_ASSIGN_INTERPRET(Min) +BIN_ASSIGN_INTERPRET(Cat) +BIN_ASSIGN_INTERPRET(Mul) +BIN_ASSIGN_INTERPRET(Div) +BIN_ASSIGN_INTERPRET(Mod) +BIN_ASSIGN_INTERPRET(Shl) +BIN_ASSIGN_INTERPRET(Shr) +BIN_ASSIGN_INTERPRET(Ushr) +BIN_ASSIGN_INTERPRET(And) +BIN_ASSIGN_INTERPRET(Or) +BIN_ASSIGN_INTERPRET(Xor) + +Expression *PostExp::interpret(InterState *istate) +{ +#if LOG + printf("PostExp::interpret() %s\n", toChars()); +#endif + Expression *e; + if (op == TOKplusplus) + e = interpretAssignCommon(istate, &Add, 1); + else + e = interpretAssignCommon(istate, &Min, 1); +#if LOG + if (e == EXP_CANT_INTERPRET) + printf("PostExp::interpret() CANT\n"); +#endif + return e; +} + +Expression *AndAndExp::interpret(InterState *istate) +{ +#if LOG + printf("AndAndExp::interpret() %s\n", toChars()); +#endif + Expression *e = e1->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(FALSE)) + e = new IntegerExp(e1->loc, 0, type); + else if (e->isBool(TRUE)) + { + e = e2->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(FALSE)) + e = new IntegerExp(e1->loc, 0, type); + else if (e->isBool(TRUE)) + e = new IntegerExp(e1->loc, 1, type); + else + e = EXP_CANT_INTERPRET; + } + } + else + e = EXP_CANT_INTERPRET; + } + return e; +} + +Expression *OrOrExp::interpret(InterState *istate) +{ +#if LOG + printf("OrOrExp::interpret() %s\n", toChars()); +#endif + Expression *e = e1->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(TRUE)) + e = new IntegerExp(e1->loc, 1, type); + else if (e->isBool(FALSE)) + { + e = e2->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(FALSE)) + e = new IntegerExp(e1->loc, 0, type); + else if (e->isBool(TRUE)) + e = new IntegerExp(e1->loc, 1, type); + else + e = EXP_CANT_INTERPRET; + } + } + else + e = EXP_CANT_INTERPRET; + } + return e; +} + + +Expression *CallExp::interpret(InterState *istate) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("CallExp::interpret() %s\n", toChars()); +#endif + if (e1->op == TOKvar) + { + FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); + if (fd) + { +#if DMDV2 + enum BUILTIN b = fd->isBuiltin(); + if (b) + { Expressions args; + args.setDim(arguments->dim); + for (size_t i = 0; i < args.dim; i++) + { + Expression *earg = (Expression *)arguments->data[i]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return earg; + args.data[i] = (void *)earg; + } + e = eval_builtin(b, &args); + if (!e) + e = EXP_CANT_INTERPRET; + } + else +#endif + // Inline .dup + if (fd->ident == Id::adDup && arguments && arguments->dim == 2) + { + e = (Expression *)arguments->data[1]; + e = e->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + e = expType(type, e); + } + } + else + { + Expression *eresult = fd->interpret(istate, arguments); + if (eresult) + e = eresult; + else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) + e = EXP_VOID_INTERPRET; + else + error("cannot evaluate %s at compile time", toChars()); + } + } + } + return e; +} + +Expression *CommaExp::interpret(InterState *istate) +{ +#if LOG + printf("CommaExp::interpret() %s\n", toChars()); +#endif + Expression *e = e1->interpret(istate); + if (e != EXP_CANT_INTERPRET) + e = e2->interpret(istate); + return e; +} + +Expression *CondExp::interpret(InterState *istate) +{ +#if LOG + printf("CondExp::interpret() %s\n", toChars()); +#endif + Expression *e = econd->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(TRUE)) + e = e1->interpret(istate); + else if (e->isBool(FALSE)) + e = e2->interpret(istate); + else + e = EXP_CANT_INTERPRET; + } + return e; +} + +Expression *ArrayLengthExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + +#if LOG + printf("ArrayLengthExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) + { + e = ArrayLength(type, e1); + } + else if (e1->op == TOKnull) + { + e = new IntegerExp(loc, 0, type); + } + else + goto Lcant; + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +Expression *IndexExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("IndexExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + + if (e1->op == TOKstring || e1->op == TOKarrayliteral) + { + /* Set the $ variable + */ + e = ArrayLength(Type::tsize_t, e1); + if (e == EXP_CANT_INTERPRET) + goto Lcant; + if (lengthVar) + lengthVar->value = e; + } + + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + return Index(type, e1, e2); + +Lcant: + return EXP_CANT_INTERPRET; +} + + +Expression *SliceExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + Expression *lwr; + Expression *upr; + +#if LOG + printf("SliceExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (!this->lwr) + { + e = e1->castTo(NULL, type); + return e->interpret(istate); + } + + /* Set the $ variable + */ + e = ArrayLength(Type::tsize_t, e1); + if (e == EXP_CANT_INTERPRET) + goto Lcant; + if (lengthVar) + lengthVar->value = e; + + /* Evaluate lower and upper bounds of slice + */ + lwr = this->lwr->interpret(istate); + if (lwr == EXP_CANT_INTERPRET) + goto Lcant; + upr = this->upr->interpret(istate); + if (upr == EXP_CANT_INTERPRET) + goto Lcant; + + return Slice(type, e1, lwr, upr); + +Lcant: + return EXP_CANT_INTERPRET; +} + + +Expression *CatExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("CatExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + { + goto Lcant; + } + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + return Cat(type, e1, e2); + +Lcant: +#if LOG + printf("CatExp::interpret() %s CANT\n", toChars()); +#endif + return EXP_CANT_INTERPRET; +} + + +Expression *CastExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + +#if LOG + printf("CastExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + return Cast(type, to, e1); + +Lcant: +#if LOG + printf("CastExp::interpret() %s CANT\n", toChars()); +#endif + return EXP_CANT_INTERPRET; +} + + +Expression *AssertExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + +#if LOG + printf("AssertExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isBool(TRUE)) + { + } + else if (e1->isBool(FALSE)) + { + if (msg) + { + e = msg->interpret(istate); + if (e == EXP_CANT_INTERPRET) + goto Lcant; + error("%s", e->toChars()); + } + else + error("%s failed", toChars()); + goto Lcant; + } + else + goto Lcant; + return e1; + +Lcant: + return EXP_CANT_INTERPRET; +} + +Expression *PtrExp::interpret(InterState *istate) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("PtrExp::interpret() %s\n", toChars()); +#endif + + // Constant fold *(&structliteral + offset) + if (e1->op == TOKadd) + { AddExp *ae = (AddExp *)e1; + if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) + { AddrExp *ade = (AddrExp *)ae->e1; + Expression *ex = ade->e1; + ex = ex->interpret(istate); + if (ex != EXP_CANT_INTERPRET) + { + if (ex->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ex; + unsigned offset = ae->e2->toInteger(); + e = se->getField(type, offset); + if (!e) + e = EXP_CANT_INTERPRET; + return e; + } + } + } + e = Ptr(type, e1); + } + else if (e1->op == TOKsymoff) + { SymOffExp *soe = (SymOffExp *)e1; + VarDeclaration *v = soe->var->isVarDeclaration(); + if (v) + { Expression *ev = getVarExp(loc, istate, v); + if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ev; + e = se->getField(type, soe->offset); + if (!e) + e = EXP_CANT_INTERPRET; + } + } + } +#if LOG + if (e == EXP_CANT_INTERPRET) + printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); +#endif + return e; +} + +Expression *DotVarExp::interpret(InterState *istate) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("DotVarExp::interpret() %s\n", toChars()); +#endif + + Expression *ex = e1->interpret(istate); + if (ex != EXP_CANT_INTERPRET) + { + if (ex->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ex; + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { e = se->getField(type, v->offset); + if (!e) + e = EXP_CANT_INTERPRET; + return e; + } + } + } + +#if LOG + if (e == EXP_CANT_INTERPRET) + printf("DotVarExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); +#endif + return e; +} + +/******************************* Special Functions ***************************/ + +Expression *interpret_aaLen(InterState *istate, Expressions *arguments) +{ + if (!arguments || arguments->dim != 1) + return NULL; + Expression *earg = (Expression *)arguments->data[0]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t); + return e; +} + +Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) +{ + //printf("interpret_aaKeys()\n"); + if (!arguments || arguments->dim != 2) + return NULL; + Expression *earg = (Expression *)arguments->data[0]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); + return e; +} + +Expression *interpret_aaValues(InterState *istate, Expressions *arguments) +{ + //printf("interpret_aaValues()\n"); + if (!arguments || arguments->dim != 3) + return NULL; + Expression *earg = (Expression *)arguments->data[0]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new ArrayLiteralExp(aae->loc, aae->values); + //printf("result is %s\n", e->toChars()); + return e; +} +
--- a/dmd/man.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/man.c Tue Jan 06 16:33:51 2009 +0100 @@ -1,60 +1,60 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2008-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 <string.h> -#include <stdlib.h> -#include <assert.h> - -#if _WIN32 - -#include <windows.h> - -#pragma comment(lib,"shell32.lib") - -void browse(const char *url) -{ - ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); -} - -#endif - -#if linux || __APPLE__ - -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -void browse(const char *url) -{ - pid_t childpid; - const char *args[3]; - - char *browser = getenv("BROWSER"); - if (browser) - browser = strdup(browser); - else - browser = "firefox"; - - args[0] = browser; - args[1] = url; - args[2] = NULL; - - childpid = fork(); - if (childpid == 0) - { - execvp(args[0], (char**)args); - perror(args[0]); // failed to execute - return; - } -} - -#endif - + +// Compiler implementation of the D programming language +// Copyright (c) 2008-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 <string.h> +#include <stdlib.h> +#include <assert.h> + +#if _WIN32 + +#include <windows.h> + +#pragma comment(lib,"shell32.lib") + +void browse(const char *url) +{ + ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); +} + +#endif + +#if linux || __APPLE__ + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +void browse(const char *url) +{ + pid_t childpid; + const char *args[3]; + + const char *browser = getenv("BROWSER"); + if (browser) + browser = strdup(browser); + else + browser = "firefox"; + + args[0] = browser; + args[1] = url; + args[2] = NULL; + + childpid = fork(); + if (childpid == 0) + { + execvp(args[0], (char**)args); + perror(args[0]); // failed to execute + return; + } +} + +#endif +
--- a/dmd/mars.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/mars.c Tue Jan 06 16:33:51 2009 +0100 @@ -63,7 +63,7 @@ copyright = "Copyright (c) 1999-2008 by Digital Mars and Tomas Lindquist Olsen"; written = "written by Walter Bright and Tomas Lindquist Olsen"; - version = "v1.037"; + version = "v1.038"; ldc_version = LDC_REV; llvm_version = LLVM_REV; global.structalign = 8;
--- a/dmd/module.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/module.c Tue Jan 06 16:33:51 2009 +0100 @@ -889,6 +889,38 @@ //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); } +/************************************ + * Recursively look at every module this module imports, + * return TRUE if it imports m. + * Can be used to detect circular imports. + */ + +int Module::imports(Module *m) +{ + //printf("%s Module::imports(%s)\n", toChars(), m->toChars()); + int aimports_dim = aimports.dim; +#if 0 + for (int i = 0; i < aimports.dim; i++) + { Module *mi = (Module *)aimports.data[i]; + printf("\t[%d] %s\n", i, mi->toChars()); + } +#endif + for (int i = 0; i < aimports.dim; i++) + { Module *mi = (Module *)aimports.data[i]; + if (mi == m) + return TRUE; + if (!mi->insearch) + { + mi->insearch = 1; + int r = mi->imports(m); + mi->insearch = 0; + if (r) + return r; + } + } + return FALSE; +} + /* =========================== ModuleDeclaration ===================== */ ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id)
--- a/dmd/module.h Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/module.h Tue Jan 06 16:33:51 2009 +0100 @@ -141,6 +141,7 @@ void deleteObjFile(); void addDeferredSemantic(Dsymbol *s); void runDeferredSemantic(); + int imports(Module *m); // Back end
--- a/dmd/mtype.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/mtype.c Tue Jan 06 16:33:51 2009 +0100 @@ -3721,6 +3721,34 @@ return t; } +Dsymbol *TypeInstance::toDsymbol(Scope *sc) +{ + Type *t; + Expression *e; + Dsymbol *s; + + //printf("TypeInstance::semantic(%s)\n", toChars()); + + if (sc->parameterSpecialization) + { + unsigned errors = global.errors; + global.gag++; + + resolve(loc, sc, &e, &t, &s); + + global.gag--; + if (errors != global.errors) + { if (global.gag == 0) + global.errors = errors; + return NULL; + } + } + else + resolve(loc, sc, &e, &t, &s); + + return s; +} + /***************************** TypeTypeof *****************************/ @@ -4380,9 +4408,12 @@ return new IntegerExp(e->loc, 0, Type::tint32); } + /* If e.tupleof + */ if (ident == Id::tupleof) { - /* Create a TupleExp + /* Create a TupleExp out of the fields of the struct e: + * (e.field0, e.field1, e.field2, ...) */ e = e->semantic(sc); // do this before turning on noaccesscheck Expressions *exps = new Expressions; @@ -4477,6 +4508,14 @@ return de; } + Import *timp = s->isImport(); + if (timp) + { + e = new DsymbolExp(e->loc, s); + e = e->semantic(sc); + return e; + } + d = s->isDeclaration(); #ifdef DEBUG if (!d) @@ -4521,9 +4560,7 @@ // *(&e + offset) accessCheck(e->loc, sc, e, d); - -// LDC we don't want dot exprs turned into pointer arithmetic. it complicates things for no apparent gain -#ifndef IN_LLVM +#if 0 b = new AddrExp(e->loc, e); b->type = e->type->pointerTo(); b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32));
--- a/dmd/mtype.h Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/mtype.h Tue Jan 06 16:33:51 2009 +0100 @@ -507,6 +507,7 @@ void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); Type *semantic(Loc loc, Scope *sc); + Dsymbol *toDsymbol(Scope *sc); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); };
--- a/dmd/opover.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/opover.c Tue Jan 06 16:33:51 2009 +0100 @@ -1,748 +1,748 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <assert.h> -#include <complex> - -#ifdef __APPLE__ -#define integer_t dmd_integer_t -#endif - -#if IN_GCC || IN_LLVM -#include "mem.h" -#elif POSIX -#include "../root/mem.h" -#elif _WIN32 -#include "..\root\mem.h" -#endif - -//#include "port.h" -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "id.h" -#include "declaration.h" -#include "aggregate.h" -#include "template.h" - -static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id); -static void inferApplyArgTypesX(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); - -/******************************** Expression **************************/ - - -/*********************************** - * Determine if operands of binary op can be reversed - * to fit operator overload. - */ - -int Expression::isCommutative() -{ - return FALSE; // default is no reverse -} - -/*********************************** - * Get Identifier for operator overload. - */ - -Identifier *Expression::opId() -{ - assert(0); - return NULL; -} - -/*********************************** - * Get Identifier for reverse operator overload, - * NULL if not supported for this operator. - */ - -Identifier *Expression::opId_r() -{ - return NULL; -} - -/************************* Operators *****************************/ - -Identifier *UAddExp::opId() { return Id::uadd; } - -Identifier *NegExp::opId() { return Id::neg; } - -Identifier *ComExp::opId() { return Id::com; } - -Identifier *CastExp::opId() { return Id::cast; } - -Identifier *InExp::opId() { return Id::opIn; } -Identifier *InExp::opId_r() { return Id::opIn_r; } - -Identifier *PostExp::opId() { return (op == TOKplusplus) - ? Id::postinc - : Id::postdec; } - -int AddExp::isCommutative() { return TRUE; } -Identifier *AddExp::opId() { return Id::add; } -Identifier *AddExp::opId_r() { return Id::add_r; } - -Identifier *MinExp::opId() { return Id::sub; } -Identifier *MinExp::opId_r() { return Id::sub_r; } - -int MulExp::isCommutative() { return TRUE; } -Identifier *MulExp::opId() { return Id::mul; } -Identifier *MulExp::opId_r() { return Id::mul_r; } - -Identifier *DivExp::opId() { return Id::div; } -Identifier *DivExp::opId_r() { return Id::div_r; } - -Identifier *ModExp::opId() { return Id::mod; } -Identifier *ModExp::opId_r() { return Id::mod_r; } - -Identifier *ShlExp::opId() { return Id::shl; } -Identifier *ShlExp::opId_r() { return Id::shl_r; } - -Identifier *ShrExp::opId() { return Id::shr; } -Identifier *ShrExp::opId_r() { return Id::shr_r; } - -Identifier *UshrExp::opId() { return Id::ushr; } -Identifier *UshrExp::opId_r() { return Id::ushr_r; } - -int AndExp::isCommutative() { return TRUE; } -Identifier *AndExp::opId() { return Id::iand; } -Identifier *AndExp::opId_r() { return Id::iand_r; } - -int OrExp::isCommutative() { return TRUE; } -Identifier *OrExp::opId() { return Id::ior; } -Identifier *OrExp::opId_r() { return Id::ior_r; } - -int XorExp::isCommutative() { return TRUE; } -Identifier *XorExp::opId() { return Id::ixor; } -Identifier *XorExp::opId_r() { return Id::ixor_r; } - -Identifier *CatExp::opId() { return Id::cat; } -Identifier *CatExp::opId_r() { return Id::cat_r; } - -Identifier * AssignExp::opId() { return Id::assign; } -Identifier * AddAssignExp::opId() { return Id::addass; } -Identifier * MinAssignExp::opId() { return Id::subass; } -Identifier * MulAssignExp::opId() { return Id::mulass; } -Identifier * DivAssignExp::opId() { return Id::divass; } -Identifier * ModAssignExp::opId() { return Id::modass; } -Identifier * AndAssignExp::opId() { return Id::andass; } -Identifier * OrAssignExp::opId() { return Id::orass; } -Identifier * XorAssignExp::opId() { return Id::xorass; } -Identifier * ShlAssignExp::opId() { return Id::shlass; } -Identifier * ShrAssignExp::opId() { return Id::shrass; } -Identifier *UshrAssignExp::opId() { return Id::ushrass; } -Identifier * CatAssignExp::opId() { return Id::catass; } - -int EqualExp::isCommutative() { return TRUE; } -Identifier *EqualExp::opId() { return Id::eq; } - -int CmpExp::isCommutative() { return TRUE; } -Identifier *CmpExp::opId() { return Id::cmp; } - -Identifier *ArrayExp::opId() { return Id::index; } - - -/************************************ - * Operator overload. - * Check for operator overload, if so, replace - * with function call. - * Return NULL if not an operator overload. - */ - -Expression *UnaExp::op_overload(Scope *sc) -{ - AggregateDeclaration *ad; - Dsymbol *fd; - Type *t1 = e1->type->toBasetype(); - - if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - } - else if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - - L1: - fd = search_function(ad, opId()); - if (fd) - { - if (op == TOKarray) - { - Expression *e; - ArrayExp *ae = (ArrayExp *)this; - - e = new DotIdExp(loc, e1, fd->ident); - e = new CallExp(loc, e, ae->arguments); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite +e1 as e1.add() - return build_overload(loc, sc, e1, NULL, fd->ident); - } - } - } - return NULL; -} - - -Expression *BinExp::op_overload(Scope *sc) -{ - //printf("BinExp::op_overload() (%s)\n", toChars()); - - AggregateDeclaration *ad; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - Identifier *id = opId(); - Identifier *id_r = opId_r(); - - Match m; - Expressions args1; - Expressions args2; - int argsset = 0; - - AggregateDeclaration *ad1; - if (t1->ty == Tclass) - ad1 = ((TypeClass *)t1)->sym; - else if (t1->ty == Tstruct) - ad1 = ((TypeStruct *)t1)->sym; - else - ad1 = NULL; - - AggregateDeclaration *ad2; - if (t2->ty == Tclass) - ad2 = ((TypeClass *)t2)->sym; - else if (t2->ty == Tstruct) - ad2 = ((TypeStruct *)t2)->sym; - else - ad2 = NULL; - - Dsymbol *s = NULL; - Dsymbol *s_r = NULL; - FuncDeclaration *fd = NULL; - TemplateDeclaration *td = NULL; - if (ad1 && id) - { - s = search_function(ad1, id); - } - if (ad2 && id_r) - { - s_r = search_function(ad2, id_r); - } - - if (s || s_r) - { - /* Try: - * a.opfunc(b) - * b.opfunc_r(a) - * and see which is better. - */ - Expression *e; - FuncDeclaration *lastf; - - args1.setDim(1); - args1.data[0] = (void*) e1; - args2.setDim(1); - args2.data[0] = (void*) e2; - argsset = 1; - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s) - { - fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, &args2); - } - else - { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, &args2); - } - } - - lastf = m.lastf; - - if (s_r) - { - fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, &args1); - } - else - { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - if (op == TOKplusplus || op == TOKminusminus) - // Kludge because operator overloading regards e++ and e-- - // as unary, but it's implemented as a binary. - // Rewrite (e1 ++ e2) as e1.postinc() - // Rewrite (e1 -- e2) as e1.postdec() - e = build_overload(loc, sc, e1, NULL, id); - else if (lastf && m.lastf == lastf || m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc(e2) - e = build_overload(loc, sc, e1, e2, id); - else - // Rewrite (e1 op e2) as e2.opfunc_r(e1) - e = build_overload(loc, sc, e2, e1, id_r); - return e; - } - - if (isCommutative()) - { - s = NULL; - s_r = NULL; - if (ad1 && id_r) - { - s_r = search_function(ad1, id_r); - } - if (ad2 && id) - { - s = search_function(ad2, id); - } - - if (s || s_r) - { - /* Try: - * a.opfunc_r(b) - * b.opfunc(a) - * and see which is better. - */ - Expression *e; - FuncDeclaration *lastf; - - if (!argsset) - { args1.setDim(1); - args1.data[0] = (void*) e1; - args2.setDim(1); - args2.data[0] = (void*) e2; - } - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s_r) - { - fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, &args2); - } - else - { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, &args2); - } - } - lastf = m.lastf; - - if (s) - { - fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, &args1); - } - else - { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - if (lastf && m.lastf == lastf || - id_r && m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc_r(e2) - e = build_overload(loc, sc, e1, e2, id_r); - else - // Rewrite (e1 op e2) as e2.opfunc(e1) - e = build_overload(loc, sc, e2, e1, id); - - // When reversing operands of comparison operators, - // need to reverse the sense of the op - switch (op) - { - case TOKlt: op = TOKgt; break; - case TOKgt: op = TOKlt; break; - case TOKle: op = TOKge; break; - case TOKge: op = TOKle; break; - - // Floating point compares - case TOKule: op = TOKuge; break; - case TOKul: op = TOKug; break; - case TOKuge: op = TOKule; break; - case TOKug: op = TOKul; break; - - // These are symmetric - case TOKunord: - case TOKlg: - case TOKleg: - case TOKue: - break; - } - - return e; - } - } - - return NULL; -} - -/*********************************** - * 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 *e; - - //printf("build_overload(id = '%s')\n", id->toChars()); - //earg->print(); - //earg->type->print(); - e = new DotIdExp(loc, ethis, id); - - if (earg) - e = new CallExp(loc, e, earg); - else - e = new CallExp(loc, e); - - e = e->semantic(sc); - return e; -} - -/*************************************** - * Search for function funcid in aggregate ad. - */ - -Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid) -{ - Dsymbol *s; - FuncDeclaration *fd; - TemplateDeclaration *td; - - s = ad->search(0, funcid, 0); - if (s) - { Dsymbol *s2; - - //printf("search_function: s = '%s'\n", s->kind()); - s2 = s->toAlias(); - //printf("search_function: s2 = '%s'\n", s2->kind()); - fd = s2->isFuncDeclaration(); - if (fd && fd->type->ty == Tfunction) - return fd; - - td = s2->isTemplateDeclaration(); - if (td) - return td; - } - return NULL; -} - - -/***************************************** - * Given array of arguments and an aggregate type, - * if any of the argument types are missing, attempt to infer - * them from the aggregate type. - */ - -void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr) -{ - if (!arguments || !arguments->dim) - return; - - /* Return if no arguments need types. - */ - for (size_t u = 0; 1; u++) - { if (u == arguments->dim) - return; - Argument *arg = (Argument *)arguments->data[u]; - if (!arg->type) - break; - } - - AggregateDeclaration *ad; - FuncDeclaration *fd; - - Argument *arg = (Argument *)arguments->data[0]; - Type *taggr = aggr->type; - if (!taggr) - return; - Type *tab = taggr->toBasetype(); - switch (tab->ty) - { - case Tarray: - case Tsarray: - case Ttuple: - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = Type::tsize_t; // key type - arg = (Argument *)arguments->data[1]; - } - if (!arg->type && tab->ty != Ttuple) - arg->type = tab->nextOf(); // value type - break; - - case Taarray: - { TypeAArray *taa = (TypeAArray *)tab; - - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = taa->index; // key type - arg = (Argument *)arguments->data[1]; - } - if (!arg->type) - arg->type = taa->next; // value type - break; - } - - case Tclass: - ad = ((TypeClass *)tab)->sym; - goto Laggr; - - case Tstruct: - ad = ((TypeStruct *)tab)->sym; - goto Laggr; - - Laggr: -#if 0 - if (arguments->dim == 1) - { - if (!arg->type) - { - /* Look for an opNext() overload - */ - Dsymbol *s = search_function(ad, Id::next); - fd = s ? s->isFuncDeclaration() : NULL; - if (!fd) - goto Lapply; - arg->type = fd->type->next; - } - break; - } -#endif - Lapply: - { /* Look for an - * int opApply(int delegate(ref Type [, ...]) dg); - * overload - */ - Dsymbol *s = search_function(ad, - (op == TOKforeach_reverse) ? Id::applyReverse - : Id::apply); - if (s) - { - fd = s->isFuncDeclaration(); - if (fd) - inferApplyArgTypesX(fd, arguments); - } - break; - } - - case Tdelegate: - { - if (0 && aggr->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)aggr; - - fd = de->func->isFuncDeclaration(); - if (fd) - inferApplyArgTypesX(fd, arguments); - } - else - { - inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments); - } - break; - } - - default: - break; // ignore error, caught later - } -} - -/******************************** - * Recursive helper function, - * analogous to func.overloadResolveX(). - */ - -int fp3(void *param, FuncDeclaration *f) -{ - Arguments *arguments = (Arguments *)param; - TypeFunction *tf = (TypeFunction *)f->type; - if (inferApplyArgTypesY(tf, arguments) == 1) - return 0; - if (arguments->dim == 0) - return 1; - return 0; -} - -static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments) -{ - overloadApply(fstart, &fp3, arguments); -} - -#if 0 -static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments) -{ - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { - FuncDeclaration *f; - FuncAliasDeclaration *fa; - AliasDeclaration *a; - - fa = d->isFuncAliasDeclaration(); - if (fa) - { - inferApplyArgTypesX(fa->funcalias, arguments); - next = fa->overnext; - } - else if ((f = d->isFuncDeclaration()) != NULL) - { - next = f->overnext; - - TypeFunction *tf = (TypeFunction *)f->type; - if (inferApplyArgTypesY(tf, arguments) == 1) - continue; - if (arguments->dim == 0) - return; - } - 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 - -/****************************** - * Infer arguments from type of function. - * Returns: - * 0 match for this function - * 1 no match for this function - */ - -static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments) -{ size_t nparams; - Argument *p; - - if (Argument::dim(tf->parameters) != 1) - goto Lnomatch; - p = Argument::getNth(tf->parameters, 0); - if (p->type->ty != Tdelegate) - goto Lnomatch; - tf = (TypeFunction *)p->type->nextOf(); - assert(tf->ty == Tfunction); - - /* We now have tf, the type of the delegate. Match it against - * the arguments, filling in missing argument types. - */ - nparams = Argument::dim(tf->parameters); - if (nparams == 0 || tf->varargs) - goto Lnomatch; // not enough parameters - if (arguments->dim != nparams) - goto Lnomatch; // not enough parameters - - for (size_t u = 0; u < nparams; u++) - { - Argument *arg = (Argument *)arguments->data[u]; - Argument *param = Argument::getNth(tf->parameters, u); - if (arg->type) - { if (!arg->type->equals(param->type)) - { - /* Cannot resolve argument types. Indicate an - * error by setting the number of arguments to 0. - */ - arguments->dim = 0; - goto Lmatch; - } - continue; - } - arg->type = param->type; - } - Lmatch: - return 0; - - Lnomatch: - return 1; -} - -/************************************** - */ - -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments) -{ - FuncDeclaration *fd; - - assert(td); - fd = td->deduceFunctionTemplate(sc, loc, targsi, arguments); - if (!fd) - return; - m->anyf = fd; - if (m->last >= MATCHexact) - { - m->nextf = fd; - m->count++; - } - else - { - m->last = MATCHexact; - m->lastf = fd; - m->count = 1; - } -} - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <assert.h> +#include <complex> + +#ifdef __APPLE__ +#define integer_t dmd_integer_t +#endif + +#if IN_GCC || IN_LLVM +#include "mem.h" +#elif POSIX +#include "../root/mem.h" +#elif _WIN32 +#include "..\root\mem.h" +#endif + +//#include "port.h" +#include "mtype.h" +#include "init.h" +#include "expression.h" +#include "id.h" +#include "declaration.h" +#include "aggregate.h" +#include "template.h" + +static Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id); +static void inferApplyArgTypesX(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); + +/******************************** Expression **************************/ + + +/*********************************** + * Determine if operands of binary op can be reversed + * to fit operator overload. + */ + +int Expression::isCommutative() +{ + return FALSE; // default is no reverse +} + +/*********************************** + * Get Identifier for operator overload. + */ + +Identifier *Expression::opId() +{ + assert(0); + return NULL; +} + +/*********************************** + * Get Identifier for reverse operator overload, + * NULL if not supported for this operator. + */ + +Identifier *Expression::opId_r() +{ + return NULL; +} + +/************************* Operators *****************************/ + +Identifier *UAddExp::opId() { return Id::uadd; } + +Identifier *NegExp::opId() { return Id::neg; } + +Identifier *ComExp::opId() { return Id::com; } + +Identifier *CastExp::opId() { return Id::cast; } + +Identifier *InExp::opId() { return Id::opIn; } +Identifier *InExp::opId_r() { return Id::opIn_r; } + +Identifier *PostExp::opId() { return (op == TOKplusplus) + ? Id::postinc + : Id::postdec; } + +int AddExp::isCommutative() { return TRUE; } +Identifier *AddExp::opId() { return Id::add; } +Identifier *AddExp::opId_r() { return Id::add_r; } + +Identifier *MinExp::opId() { return Id::sub; } +Identifier *MinExp::opId_r() { return Id::sub_r; } + +int MulExp::isCommutative() { return TRUE; } +Identifier *MulExp::opId() { return Id::mul; } +Identifier *MulExp::opId_r() { return Id::mul_r; } + +Identifier *DivExp::opId() { return Id::div; } +Identifier *DivExp::opId_r() { return Id::div_r; } + +Identifier *ModExp::opId() { return Id::mod; } +Identifier *ModExp::opId_r() { return Id::mod_r; } + +Identifier *ShlExp::opId() { return Id::shl; } +Identifier *ShlExp::opId_r() { return Id::shl_r; } + +Identifier *ShrExp::opId() { return Id::shr; } +Identifier *ShrExp::opId_r() { return Id::shr_r; } + +Identifier *UshrExp::opId() { return Id::ushr; } +Identifier *UshrExp::opId_r() { return Id::ushr_r; } + +int AndExp::isCommutative() { return TRUE; } +Identifier *AndExp::opId() { return Id::iand; } +Identifier *AndExp::opId_r() { return Id::iand_r; } + +int OrExp::isCommutative() { return TRUE; } +Identifier *OrExp::opId() { return Id::ior; } +Identifier *OrExp::opId_r() { return Id::ior_r; } + +int XorExp::isCommutative() { return TRUE; } +Identifier *XorExp::opId() { return Id::ixor; } +Identifier *XorExp::opId_r() { return Id::ixor_r; } + +Identifier *CatExp::opId() { return Id::cat; } +Identifier *CatExp::opId_r() { return Id::cat_r; } + +Identifier * AssignExp::opId() { return Id::assign; } +Identifier * AddAssignExp::opId() { return Id::addass; } +Identifier * MinAssignExp::opId() { return Id::subass; } +Identifier * MulAssignExp::opId() { return Id::mulass; } +Identifier * DivAssignExp::opId() { return Id::divass; } +Identifier * ModAssignExp::opId() { return Id::modass; } +Identifier * AndAssignExp::opId() { return Id::andass; } +Identifier * OrAssignExp::opId() { return Id::orass; } +Identifier * XorAssignExp::opId() { return Id::xorass; } +Identifier * ShlAssignExp::opId() { return Id::shlass; } +Identifier * ShrAssignExp::opId() { return Id::shrass; } +Identifier *UshrAssignExp::opId() { return Id::ushrass; } +Identifier * CatAssignExp::opId() { return Id::catass; } + +int EqualExp::isCommutative() { return TRUE; } +Identifier *EqualExp::opId() { return Id::eq; } + +int CmpExp::isCommutative() { return TRUE; } +Identifier *CmpExp::opId() { return Id::cmp; } + +Identifier *ArrayExp::opId() { return Id::index; } + + +/************************************ + * Operator overload. + * Check for operator overload, if so, replace + * with function call. + * Return NULL if not an operator overload. + */ + +Expression *UnaExp::op_overload(Scope *sc) +{ + AggregateDeclaration *ad; + Dsymbol *fd; + Type *t1 = e1->type->toBasetype(); + + if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + goto L1; + } + else if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; + + L1: + fd = search_function(ad, opId()); + if (fd) + { + if (op == TOKarray) + { + Expression *e; + ArrayExp *ae = (ArrayExp *)this; + + e = new DotIdExp(loc, e1, fd->ident); + e = new CallExp(loc, e, ae->arguments); + e = e->semantic(sc); + return e; + } + else + { + // Rewrite +e1 as e1.add() + return build_overload(loc, sc, e1, NULL, fd->ident); + } + } + } + return NULL; +} + + +Expression *BinExp::op_overload(Scope *sc) +{ + //printf("BinExp::op_overload() (%s)\n", toChars()); + + AggregateDeclaration *ad; + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + Identifier *id = opId(); + Identifier *id_r = opId_r(); + + Match m; + Expressions args1; + Expressions args2; + int argsset = 0; + + AggregateDeclaration *ad1; + if (t1->ty == Tclass) + ad1 = ((TypeClass *)t1)->sym; + else if (t1->ty == Tstruct) + ad1 = ((TypeStruct *)t1)->sym; + else + ad1 = NULL; + + AggregateDeclaration *ad2; + if (t2->ty == Tclass) + ad2 = ((TypeClass *)t2)->sym; + else if (t2->ty == Tstruct) + ad2 = ((TypeStruct *)t2)->sym; + else + ad2 = NULL; + + Dsymbol *s = NULL; + Dsymbol *s_r = NULL; + FuncDeclaration *fd = NULL; + TemplateDeclaration *td = NULL; + if (ad1 && id) + { + s = search_function(ad1, id); + } + if (ad2 && id_r) + { + s_r = search_function(ad2, id_r); + } + + if (s || s_r) + { + /* Try: + * a.opfunc(b) + * b.opfunc_r(a) + * and see which is better. + */ + Expression *e; + FuncDeclaration *lastf; + + args1.setDim(1); + args1.data[0] = (void*) e1; + args2.setDim(1); + args2.data[0] = (void*) e2; + argsset = 1; + + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + + if (s) + { + fd = s->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, &args2); + } + else + { td = s->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, NULL, &args2); + } + } + + lastf = m.lastf; + + if (s_r) + { + fd = s_r->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, &args1); + } + else + { td = s_r->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, NULL, &args1); + } + } + + if (m.count > 1) + { + // Error, ambiguous + error("overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); + } + else if (m.last == MATCHnomatch) + { + m.lastf = m.anyf; + } + + if (op == TOKplusplus || op == TOKminusminus) + // Kludge because operator overloading regards e++ and e-- + // as unary, but it's implemented as a binary. + // Rewrite (e1 ++ e2) as e1.postinc() + // Rewrite (e1 -- e2) as e1.postdec() + e = build_overload(loc, sc, e1, NULL, id); + else if (lastf && m.lastf == lastf || m.last == MATCHnomatch) + // Rewrite (e1 op e2) as e1.opfunc(e2) + e = build_overload(loc, sc, e1, e2, id); + else + // Rewrite (e1 op e2) as e2.opfunc_r(e1) + e = build_overload(loc, sc, e2, e1, id_r); + return e; + } + + if (isCommutative()) + { + s = NULL; + s_r = NULL; + if (ad1 && id_r) + { + s_r = search_function(ad1, id_r); + } + if (ad2 && id) + { + s = search_function(ad2, id); + } + + if (s || s_r) + { + /* Try: + * a.opfunc_r(b) + * b.opfunc(a) + * and see which is better. + */ + Expression *e; + FuncDeclaration *lastf; + + if (!argsset) + { args1.setDim(1); + args1.data[0] = (void*) e1; + args2.setDim(1); + args2.data[0] = (void*) e2; + } + + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + + if (s_r) + { + fd = s_r->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, &args2); + } + else + { td = s_r->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, NULL, &args2); + } + } + lastf = m.lastf; + + if (s) + { + fd = s->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, &args1); + } + else + { td = s->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, NULL, &args1); + } + } + + if (m.count > 1) + { + // Error, ambiguous + error("overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); + } + else if (m.last == MATCHnomatch) + { + m.lastf = m.anyf; + } + + if (lastf && m.lastf == lastf || + id_r && m.last == MATCHnomatch) + // Rewrite (e1 op e2) as e1.opfunc_r(e2) + e = build_overload(loc, sc, e1, e2, id_r); + else + // Rewrite (e1 op e2) as e2.opfunc(e1) + e = build_overload(loc, sc, e2, e1, id); + + // When reversing operands of comparison operators, + // need to reverse the sense of the op + switch (op) + { + case TOKlt: op = TOKgt; break; + case TOKgt: op = TOKlt; break; + case TOKle: op = TOKge; break; + case TOKge: op = TOKle; break; + + // Floating point compares + case TOKule: op = TOKuge; break; + case TOKul: op = TOKug; break; + case TOKuge: op = TOKule; break; + case TOKug: op = TOKul; break; + + // These are symmetric + case TOKunord: + case TOKlg: + case TOKleg: + case TOKue: + break; + } + + return e; + } + } + + return NULL; +} + +/*********************************** + * 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 *e; + + //printf("build_overload(id = '%s')\n", id->toChars()); + //earg->print(); + //earg->type->print(); + e = new DotIdExp(loc, ethis, id); + + if (earg) + e = new CallExp(loc, e, earg); + else + e = new CallExp(loc, e); + + e = e->semantic(sc); + return e; +} + +/*************************************** + * Search for function funcid in aggregate ad. + */ + +Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid) +{ + Dsymbol *s; + FuncDeclaration *fd; + TemplateDeclaration *td; + + s = ad->search(0, funcid, 0); + if (s) + { Dsymbol *s2; + + //printf("search_function: s = '%s'\n", s->kind()); + s2 = s->toAlias(); + //printf("search_function: s2 = '%s'\n", s2->kind()); + fd = s2->isFuncDeclaration(); + if (fd && fd->type->ty == Tfunction) + return fd; + + td = s2->isTemplateDeclaration(); + if (td) + return td; + } + return NULL; +} + + +/***************************************** + * Given array of arguments and an aggregate type, + * if any of the argument types are missing, attempt to infer + * them from the aggregate type. + */ + +void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr) +{ + if (!arguments || !arguments->dim) + return; + + /* Return if no arguments need types. + */ + for (size_t u = 0; 1; u++) + { if (u == arguments->dim) + return; + Argument *arg = (Argument *)arguments->data[u]; + if (!arg->type) + break; + } + + AggregateDeclaration *ad; + FuncDeclaration *fd; + + Argument *arg = (Argument *)arguments->data[0]; + Type *taggr = aggr->type; + if (!taggr) + return; + Type *tab = taggr->toBasetype(); + switch (tab->ty) + { + case Tarray: + case Tsarray: + case Ttuple: + if (arguments->dim == 2) + { + if (!arg->type) + arg->type = Type::tsize_t; // key type + arg = (Argument *)arguments->data[1]; + } + if (!arg->type && tab->ty != Ttuple) + arg->type = tab->nextOf(); // value type + break; + + case Taarray: + { TypeAArray *taa = (TypeAArray *)tab; + + if (arguments->dim == 2) + { + if (!arg->type) + arg->type = taa->index; // key type + arg = (Argument *)arguments->data[1]; + } + if (!arg->type) + arg->type = taa->next; // value type + break; + } + + case Tclass: + ad = ((TypeClass *)tab)->sym; + goto Laggr; + + case Tstruct: + ad = ((TypeStruct *)tab)->sym; + goto Laggr; + + Laggr: +#if 0 + if (arguments->dim == 1) + { + if (!arg->type) + { + /* Look for an opNext() overload + */ + Dsymbol *s = search_function(ad, Id::next); + fd = s ? s->isFuncDeclaration() : NULL; + if (!fd) + goto Lapply; + arg->type = fd->type->next; + } + break; + } +#endif + Lapply: + { /* Look for an + * int opApply(int delegate(ref Type [, ...]) dg); + * overload + */ + Dsymbol *s = search_function(ad, + (op == TOKforeach_reverse) ? Id::applyReverse + : Id::apply); + if (s) + { + fd = s->isFuncDeclaration(); + if (fd) + inferApplyArgTypesX(fd, arguments); + } + break; + } + + case Tdelegate: + { + if (0 && aggr->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)aggr; + + fd = de->func->isFuncDeclaration(); + if (fd) + inferApplyArgTypesX(fd, arguments); + } + else + { + inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments); + } + break; + } + + default: + break; // ignore error, caught later + } +} + +/******************************** + * Recursive helper function, + * analogous to func.overloadResolveX(). + */ + +int fp3(void *param, FuncDeclaration *f) +{ + Arguments *arguments = (Arguments *)param; + TypeFunction *tf = (TypeFunction *)f->type; + if (inferApplyArgTypesY(tf, arguments) == 1) + return 0; + if (arguments->dim == 0) + return 1; + return 0; +} + +static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments) +{ + overloadApply(fstart, &fp3, arguments); +} + +#if 0 +static void inferApplyArgTypesX(FuncDeclaration *fstart, Arguments *arguments) +{ + Declaration *d; + Declaration *next; + + for (d = fstart; d; d = next) + { + FuncDeclaration *f; + FuncAliasDeclaration *fa; + AliasDeclaration *a; + + fa = d->isFuncAliasDeclaration(); + if (fa) + { + inferApplyArgTypesX(fa->funcalias, arguments); + next = fa->overnext; + } + else if ((f = d->isFuncDeclaration()) != NULL) + { + next = f->overnext; + + TypeFunction *tf = (TypeFunction *)f->type; + if (inferApplyArgTypesY(tf, arguments) == 1) + continue; + if (arguments->dim == 0) + return; + } + 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 + +/****************************** + * Infer arguments from type of function. + * Returns: + * 0 match for this function + * 1 no match for this function + */ + +static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments) +{ size_t nparams; + Argument *p; + + if (Argument::dim(tf->parameters) != 1) + goto Lnomatch; + p = Argument::getNth(tf->parameters, 0); + if (p->type->ty != Tdelegate) + goto Lnomatch; + tf = (TypeFunction *)p->type->nextOf(); + assert(tf->ty == Tfunction); + + /* We now have tf, the type of the delegate. Match it against + * the arguments, filling in missing argument types. + */ + nparams = Argument::dim(tf->parameters); + if (nparams == 0 || tf->varargs) + goto Lnomatch; // not enough parameters + if (arguments->dim != nparams) + goto Lnomatch; // not enough parameters + + for (size_t u = 0; u < nparams; u++) + { + Argument *arg = (Argument *)arguments->data[u]; + Argument *param = Argument::getNth(tf->parameters, u); + if (arg->type) + { if (!arg->type->equals(param->type)) + { + /* Cannot resolve argument types. Indicate an + * error by setting the number of arguments to 0. + */ + arguments->dim = 0; + goto Lmatch; + } + continue; + } + arg->type = param->type; + } + Lmatch: + return 0; + + Lnomatch: + return 1; +} + +/************************************** + */ + +static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expressions *arguments) +{ + FuncDeclaration *fd; + + assert(td); + fd = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); + if (!fd) + return; + m->anyf = fd; + if (m->last >= MATCHexact) + { + m->nextf = fd; + m->count++; + } + else + { + m->last = MATCHexact; + m->lastf = fd; + m->count = 1; + } +} +
--- a/dmd/optimize.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/optimize.c Tue Jan 06 16:33:51 2009 +0100 @@ -278,19 +278,35 @@ Expression *DotVarExp::optimize(int result) { + //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars()); e1 = e1->optimize(result); - // Constant fold structliteral.member +#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 != EXP_CANT_INTERPRET) + return e; + } + } + } + else +#endif if (e1->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)e1; - - VarDeclaration* v; - if (v = var->isVarDeclaration()) + { StructLiteralExp *sle = (StructLiteralExp *)e1; + VarDeclaration *vf = var->isVarDeclaration(); + if (vf) { - Expression *e = se->getField(type, v->offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; + Expression *e = sle->getField(type, vf->offset); + if (e != EXP_CANT_INTERPRET) + return e; } } @@ -322,6 +338,7 @@ //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;
--- a/dmd/statement.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/statement.c Tue Jan 06 16:33:51 2009 +0100 @@ -124,13 +124,6 @@ return BEany; } -// TRUE if statement may fall off the end without a throw or return - -int Statement::fallOffEnd() -{ - return TRUE; -} - // TRUE if statement 'comes from' somewhere else, like a goto int Statement::comeFrom() @@ -227,21 +220,6 @@ return result; } -int ExpStatement::fallOffEnd() -{ - if (exp) - { - if (exp->op == TOKassert) - { AssertExp *a = (AssertExp *)exp; - - if (a->e1->isBool(FALSE)) // if it's an assert(0) - return FALSE; - } - else if (exp->op == TOKhalt) - return FALSE; - } - return TRUE; -} /******************************** CompileStatement ***************************/ @@ -574,25 +552,6 @@ return result; } -int CompoundStatement::fallOffEnd() -{ int falloff = TRUE; - - //printf("CompoundStatement::fallOffEnd() %s\n", toChars()); - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (!s) - continue; - - if (!falloff && global.params.warnings && !s->comeFrom()) - { - warning("%s: statement is not reachable", s->loc.toChars()); - } - falloff = s->fallOffEnd(); - } - return falloff; -} - int CompoundStatement::comeFrom() { int comefrom = FALSE; @@ -710,18 +669,6 @@ return result; } -int UnrolledLoopStatement::fallOffEnd() -{ - //printf("UnrolledLoopStatement::fallOffEnd()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (s) - s->fallOffEnd(); - } - return TRUE; -} - int UnrolledLoopStatement::comeFrom() { int comefrom = FALSE; @@ -815,11 +762,6 @@ return statement ? statement->blockExit() : BEfallthru; } -int ScopeStatement::fallOffEnd() -{ - return statement ? statement->fallOffEnd() : TRUE; -} - int ScopeStatement::comeFrom() { //printf("ScopeStatement::comeFrom()\n"); @@ -945,13 +887,6 @@ return result; } -int WhileStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - int WhileStatement::comeFrom() { if (body) @@ -1040,13 +975,6 @@ return result; } -int DoStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - int DoStatement::comeFrom() { if (body) @@ -1177,13 +1105,6 @@ return result; } -int ForStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - int ForStatement::comeFrom() { //printf("ForStatement::comeFrom()\n"); @@ -1878,13 +1799,6 @@ return result; } -int ForeachStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; -} - int ForeachStatement::comeFrom() { if (body) @@ -2042,15 +1956,6 @@ return result; } -int IfStatement::fallOffEnd() -{ - if (!ifbody || ifbody->fallOffEnd() || - !elsebody || elsebody->fallOffEnd()) - return TRUE; - return FALSE; -} - - void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("if ("); @@ -2268,13 +2173,6 @@ return result; } -int PragmaStatement::fallOffEnd() -{ - if (body) - return body->fallOffEnd(); - return TRUE; -} - void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("pragma ("); @@ -2475,13 +2373,6 @@ return result; } -int SwitchStatement::fallOffEnd() -{ - if (body) - body->fallOffEnd(); - return TRUE; // need to do this better -} - void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("switch ("); @@ -2586,11 +2477,6 @@ return statement->blockExit(); } -int CaseStatement::fallOffEnd() -{ - return statement->fallOffEnd(); -} - int CaseStatement::comeFrom() { return TRUE; @@ -2650,11 +2536,6 @@ return statement->blockExit(); } -int DefaultStatement::fallOffEnd() -{ - return statement->fallOffEnd(); -} - int DefaultStatement::comeFrom() { return TRUE; @@ -2695,11 +2576,6 @@ return BEgoto; } -int GotoDefaultStatement::fallOffEnd() -{ - return FALSE; -} - void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("goto default;\n"); @@ -2749,11 +2625,6 @@ return BEgoto; } -int GotoCaseStatement::fallOffEnd() -{ - return FALSE; -} - void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("goto case"); @@ -2777,11 +2648,6 @@ return BEthrow; } -int SwitchErrorStatement::fallOffEnd() -{ - return FALSE; -} - void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("SwitchErrorStatement::toCBuffer()"); @@ -3056,11 +2922,6 @@ return result; } -int ReturnStatement::fallOffEnd() -{ - return FALSE; -} - void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->printf("return "); @@ -3155,11 +3016,6 @@ return ident ? BEgoto : BEbreak; } -int BreakStatement::fallOffEnd() -{ - return FALSE; -} - void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("break"); @@ -3263,11 +3119,6 @@ return ident ? BEgoto : BEcontinue; } -int ContinueStatement::fallOffEnd() -{ - return FALSE; -} - void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("continue"); @@ -3358,11 +3209,6 @@ return body ? body->blockExit() : BEfallthru; } -int SynchronizedStatement::fallOffEnd() -{ - return body ? body->fallOffEnd() : TRUE; -} - void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("synchronized"); @@ -3480,11 +3326,6 @@ return result; } -int WithStatement::fallOffEnd() -{ - return body ? body->fallOffEnd() : TRUE; -} - /******************************** TryCatchStatement ***************************/ TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) @@ -3556,22 +3397,6 @@ return result; } -int TryCatchStatement::fallOffEnd() -{ - int result = FALSE; - - if (body) - result = body->fallOffEnd(); - for (int i = 0; i < catches->dim; i++) - { Catch *c; - - c = (Catch *)catches->data[i]; - if (c->handler) - result |= c->handler->fallOffEnd(); - } - return result; -} - void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("try"); @@ -3728,18 +3553,11 @@ int TryFinallyStatement::blockExit() { - int result = body->blockExit(); - return result; + if (body) + return body->blockExit(); + return BEfallthru; } -int TryFinallyStatement::fallOffEnd() -{ int result; - - result = body ? body->fallOffEnd() : TRUE; -// if (finalbody) -// result = finalbody->fallOffEnd(); - return result; -} /****************************** OnScopeStatement ***************************/ @@ -3861,11 +3679,6 @@ return BEthrow; // obviously } -int ThrowStatement::fallOffEnd() -{ - return FALSE; -} - void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->printf("throw "); @@ -3924,11 +3737,6 @@ return statement ? statement->blockExit() : BEfallthru; } -int VolatileStatement::fallOffEnd() -{ - return statement ? statement->fallOffEnd() : TRUE; -} - void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("volatile"); @@ -3993,11 +3801,6 @@ return BEgoto; } -int GotoStatement::fallOffEnd() -{ - return FALSE; -} - void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("goto "); @@ -4087,11 +3890,6 @@ return statement ? statement->blockExit() : BEfallthru; } -int LabelStatement::fallOffEnd() -{ - return statement ? statement->fallOffEnd() : TRUE; -} - int LabelStatement::comeFrom() { //printf("LabelStatement::comeFrom()\n");
--- a/dmd/statement.h Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/statement.h Tue Jan 06 16:33:51 2009 +0100 @@ -148,7 +148,6 @@ virtual int hasBreak(); virtual int hasContinue(); virtual int usesEH(); - virtual int fallOffEnd(); virtual int blockExit(); virtual int comeFrom(); virtual void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally); @@ -179,7 +178,6 @@ void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); - int fallOffEnd(); int blockExit(); int inlineCost(InlineCostState *ics); @@ -225,7 +223,6 @@ virtual Statement *semantic(Scope *sc); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); virtual Statements *flatten(Scope *sc); ReturnStatement *isReturnStatement(); @@ -255,7 +252,6 @@ int hasContinue(); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -280,7 +276,6 @@ int hasContinue(); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); @@ -302,7 +297,6 @@ int hasContinue(); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -325,7 +319,6 @@ int hasContinue(); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -351,7 +344,6 @@ int hasContinue(); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -384,7 +376,6 @@ int hasContinue(); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -413,7 +404,6 @@ int hasContinue(); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -440,7 +430,6 @@ void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int usesEH(); int blockExit(); - int fallOffEnd(); IfStatement *isIfStatement() { return this; } int inlineCost(InlineCostState *ics); @@ -477,7 +466,6 @@ Statement *semantic(Scope *sc); int usesEH(); int blockExit(); - int fallOffEnd(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; @@ -511,7 +499,6 @@ int hasBreak(); int usesEH(); int blockExit(); - int fallOffEnd(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -533,7 +520,6 @@ int compare(Object *obj); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -561,7 +547,6 @@ Statement *semantic(Scope *sc); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -584,7 +569,6 @@ Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); int blockExit(); - int fallOffEnd(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -602,7 +586,6 @@ Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); int blockExit(); - int fallOffEnd(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -612,7 +595,6 @@ { SwitchErrorStatement(Loc loc); int blockExit(); - int fallOffEnd(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -628,7 +610,6 @@ void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *semantic(Scope *sc); int blockExit(); - int fallOffEnd(); Expression *interpret(InterState *istate); int inlineCost(InlineCostState *ics); @@ -650,7 +631,6 @@ Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); int blockExit(); - int fallOffEnd(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -669,7 +649,6 @@ Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); int blockExit(); - int fallOffEnd(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toIR(IRState *irs); @@ -691,7 +670,6 @@ int hasContinue(); int usesEH(); int blockExit(); - int fallOffEnd(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -715,7 +693,6 @@ void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int usesEH(); int blockExit(); - int fallOffEnd(); Statement *inlineScan(InlineScanState *iss); @@ -733,7 +710,6 @@ int hasBreak(); int usesEH(); int blockExit(); - int fallOffEnd(); Statement *inlineScan(InlineScanState *iss); @@ -771,7 +747,6 @@ int hasContinue(); int usesEH(); int blockExit(); - int fallOffEnd(); Statement *inlineScan(InlineScanState *iss); @@ -803,7 +778,6 @@ Statement *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int blockExit(); - int fallOffEnd(); Statement *inlineScan(InlineScanState *iss); @@ -820,7 +794,6 @@ Statement *semantic(Scope *sc); Statements *flatten(Scope *sc); int blockExit(); - int fallOffEnd(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *inlineScan(InlineScanState *iss); @@ -839,7 +812,6 @@ Statement *syntaxCopy(); Statement *semantic(Scope *sc); int blockExit(); - int fallOffEnd(); Expression *interpret(InterState *istate); void toIR(IRState *irs); @@ -862,7 +834,6 @@ Statements *flatten(Scope *sc); int usesEH(); int blockExit(); - int fallOffEnd(); int comeFrom(); Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
--- a/dmd/template.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/template.c Tue Jan 06 16:33:51 2009 +0100 @@ -201,8 +201,10 @@ goto Lnomatch; } } + //printf("match\n"); return 1; // match Lnomatch: + //printf("nomatch\n"); return 0; // nomatch; } @@ -320,7 +322,9 @@ if (sc->func) { +#if DMDV1 error("cannot declare template at function scope %s", sc->func->toChars()); +#endif } if (/*global.params.useArrayBounds &&*/ sc->module) @@ -551,7 +555,9 @@ if (!flag) { - // Any parameter left without a type gets the type of its corresponding arg + /* Any parameter left without a type gets the type of + * its corresponding arg + */ for (int i = 0; i < dedtypes_dim; i++) { if (!dedtypes->data[i]) @@ -561,6 +567,25 @@ } } +#if DMDV2 + if (m && constraint && !(flag & 1)) + { /* Check to see if constraint is satisfied. + */ + Expression *e = constraint->syntaxCopy(); + paramscope->flags |= SCOPEstaticif; + e = e->semantic(paramscope); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->isBool(TRUE)) + ; + else if (e->isBool(FALSE)) + goto Lnomatch; + else + { + e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); + } + } +#endif + #if LOGM // Print out the results printf("--------------------------\n"); @@ -674,7 +699,9 @@ /************************************************* * Match function arguments against a specific template function. * Input: + * loc instantiation location * targsi Expression/Type initial list of template arguments + * ethis 'this' argument if !NULL * fargs arguments to function * Output: * dedargs Expression/Type deduced template arguments @@ -682,7 +709,8 @@ * match level */ -MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, +MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, + Expression *ethis, Expressions *fargs, Objects *dedargs) { size_t i; @@ -824,6 +852,27 @@ } L2: +#if DMDV2 + // Match 'ethis' to any TemplateThisParameter's + if (ethis) + { + for (size_t i = 0; i < parameters->dim; i++) + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + TemplateThisParameter *ttp = tp->isTemplateThisParameter(); + if (ttp) + { MATCH m; + + Type *t = new TypeIdentifier(0, ttp->ident); + m = ethis->type->deduceType(scope, t, parameters, &dedtypes); + if (!m) + goto Lnomatch; + if (m < match) + match = m; // pick worst match + } + } + } +#endif + // Loop through the function parameters for (i = 0; i < nfparams; i++) { @@ -982,7 +1031,7 @@ } } else - { oded = tp->defaultArg(paramscope); + { oded = tp->defaultArg(loc, paramscope); if (!oded) goto Lnomatch; } @@ -991,6 +1040,25 @@ } } +#if DMDV2 + if (constraint) + { /* Check to see if constraint is satisfied. + */ + Expression *e = constraint->syntaxCopy(); + paramscope->flags |= SCOPEstaticif; + e = e->semantic(paramscope); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->isBool(TRUE)) + ; + else if (e->isBool(FALSE)) + goto Lnomatch; + else + { + e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); + } + } +#endif + #if 0 for (i = 0; i < dedargs->dim; i++) { Type *t = (Type *)dedargs->data[i]; @@ -1096,11 +1164,13 @@ * sc instantiation scope * loc instantiation location * targsi initial list of template arguments + * ethis if !NULL, the 'this' pointer argument * fargs arguments to function + * flags 1: do not issue error message on no match, just return NULL */ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, - Objects *targsi, Expressions *fargs) + Objects *targsi, Expression *ethis, Expressions *fargs, int flags) { MATCH m_best = MATCHnomatch; TemplateDeclaration *td_ambig = NULL; @@ -1142,7 +1212,7 @@ MATCH m; Objects dedargs; - m = td->deduceFunctionTemplateMatch(targsi, fargs, &dedargs); + m = td->deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, &dedargs); //printf("deduceFunctionTemplateMatch = %d\n", m); if (!m) // if no match continue; @@ -1207,14 +1277,26 @@ Lerror: { + HdrGenState hgs; + + OutBuffer bufa; + Objects *args = targsi; + if (args) + { for (int i = 0; i < args->dim; i++) + { + if (i) + bufa.writeByte(','); + Object *oarg = (Object *)args->data[i]; + ObjectToCBuffer(&bufa, &hgs, oarg); + } + } + OutBuffer buf; - HdrGenState hgs; - argExpTypesToCBuffer(&buf, fargs, &hgs); - error(loc, "cannot deduce template function from argument types (%s)", - buf.toChars()); - return NULL; + error(loc, "cannot deduce template function from argument types !(%s)(%s)", + bufa.toChars(), buf.toChars()); } + return NULL; } void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -1237,6 +1319,13 @@ tp->toCBuffer(buf, hgs); } buf->writeByte(')'); +#if DMDV2 + if (constraint) + { buf->writestring(" if ("); + constraint->toCBuffer(buf, hgs); + buf->writeByte(')'); + } +#endif if (hgs->hdrgen) { @@ -1271,6 +1360,13 @@ tp->toCBuffer(&buf, &hgs); } buf.writeByte(')'); +#if DMDV2 + if (constraint) + { buf.writestring(" if ("); + constraint->toCBuffer(&buf, &hgs); + buf.writeByte(')'); + } +#endif buf.writeByte(0); return (char *)buf.extractData(); } @@ -1323,9 +1419,11 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) { - //printf("Type::deduceType()\n"); - //printf("\tthis = %d, ", ty); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#if 0 + printf("Type::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif if (!tparam) goto Lnomatch; @@ -2027,7 +2125,7 @@ oarg = (Object *)tiargs->data[i]; else { // Get default argument instead - oarg = defaultArg(sc); + oarg = defaultArg(loc, sc); if (!oarg) { assert(i < dedtypes->dim); // It might have already been deduced @@ -2141,7 +2239,7 @@ } -Object *TemplateTypeParameter::defaultArg(Scope *sc) +Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) { Type *t; @@ -2271,7 +2369,7 @@ oarg = (Object *)tiargs->data[i]; else { // Get default argument instead - oarg = defaultArg(sc); + oarg = defaultArg(loc, sc); if (!oarg) { assert(i < dedtypes->dim); // It might have already been deduced @@ -2357,7 +2455,7 @@ } -Object *TemplateAliasParameter::defaultArg(Scope *sc) +Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) { Dsymbol *s = NULL; @@ -2485,7 +2583,7 @@ oarg = (Object *)tiargs->data[i]; else { // Get default argument instead - oarg = defaultArg(sc); + oarg = defaultArg(loc, sc); if (!oarg) { assert(i < dedtypes->dim); // It might have already been deduced @@ -2602,7 +2700,7 @@ } -Object *TemplateValueParameter::defaultArg(Scope *sc) +Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) { Expression *e = defaultValue; if (e) @@ -2748,7 +2846,7 @@ } -Object *TemplateTupleParameter::defaultArg(Scope *sc) +Object *TemplateTupleParameter::defaultArg(Loc loc, Scope *sc) { return NULL; } @@ -2778,6 +2876,10 @@ this->tinst = NULL; } +/***************** + * This constructor is only called when we figured out which function + * template to instantiate. + */ TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) : ScopeDsymbol(NULL) @@ -2830,7 +2932,6 @@ Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) { TemplateInstance *ti; - int i; if (s) ti = (TemplateInstance *)s; @@ -2896,7 +2997,9 @@ } else { - // Run semantic on each argument, place results in tiargs[] + /* Run semantic on each argument, place results in tiargs[] + * (if we havetempdecl, then tiargs is already evaluated) + */ semanticTiargs(sc); tempdecl = findTemplateDeclaration(sc); @@ -2974,12 +3077,26 @@ #if 1 int dosemantic3 = 0; { Array *a; - int i; - - if (sc->scopesym && sc->scopesym->members && !sc->scopesym->isTemplateMixin()) + + Scope *scx = sc; +#if 0 + for (scx = sc; scx; scx = scx->enclosing) + if (scx->scopesym) + break; +#endif + + //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); + if (scx && scx->scopesym && + scx->scopesym->members && !scx->scopesym->isTemplateMixin() && + /* The following test should really be if scx->module recursively + * imports itself. Because if it does, see bugzilla 2500. + */ + //scx->module == tempdecl->getModule() + !scx->module->imports(scx->module) + ) { - //printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars()); - a = sc->scopesym->members; + //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); + a = scx->scopesym->members; } else { Module *m = sc->module->importedFrom; @@ -3395,19 +3512,15 @@ return NULL; } m = td->matchWithInstance(this, &dedtypes, 0); - //printf("m = %d\n", m); + //printf("matchWithInstance = %d\n", m); if (!m) // no match at all continue; -#if 1 if (m < m_best) goto Ltd_best; if (m > m_best) goto Ltd; -#else - if (!m_best) - goto Ltd; -#endif + { // Disambiguate by picking the most specialized TemplateDeclaration int c1 = td->leastAsSpecialized(td_best); @@ -3656,6 +3769,7 @@ buf.writeByte('Z'); id = buf.toChars(); buf.data = NULL; + //printf("\tgenIdent = %s\n", id); return new Identifier(id, TOKidentifier); } @@ -3672,7 +3786,7 @@ { TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; //Object *o = (Object *)tiargs->data[i]; - Object *o = (Object *)tdtypes.data[i]; + Object *o = (Object *)tdtypes.data[i]; // initializer for tp //printf("\ttdtypes[%d] = %p\n", i, o); tempdecl->declareParameter(scope, tp, o);
--- a/dmd/template.h Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/template.h Tue Jan 06 16:33:51 2009 +0100 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -54,7 +54,9 @@ TemplateParameters *parameters; // array of TemplateParameter's TemplateParameters *origParameters; // originals for Ddoc - +#if DMDV2 + Expression *constraint; +#endif Array instances; // array of TemplateInstance's TemplateDeclaration *overnext; // next overloaded TemplateDeclaration @@ -63,7 +65,11 @@ Scope *scope; Dsymbol *onemember; // if !=NULL then one member of this template - TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs); + TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, +#if DMDV2 + Expression *constraint, +#endif + Array *decldefs); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); int overloadInsert(Dsymbol *s); @@ -77,8 +83,8 @@ MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag); int leastAsSpecialized(TemplateDeclaration *td2); - MATCH deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, Objects *dedargs); - FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expressions *fargs); + MATCH deduceFunctionTemplateMatch(Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, Objects *dedargs); + FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, int flags = 0); void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); TemplateDeclaration *isTemplateDeclaration() { return this; } @@ -112,6 +118,9 @@ virtual TemplateTypeParameter *isTemplateTypeParameter(); virtual TemplateValueParameter *isTemplateValueParameter(); virtual TemplateAliasParameter *isTemplateAliasParameter(); +#if DMDV2 + virtual TemplateThisParameter *isTemplateThisParameter(); +#endif virtual TemplateTupleParameter *isTemplateTupleParameter(); virtual TemplateParameter *syntaxCopy() = 0; @@ -120,7 +129,7 @@ virtual void print(Object *oarg, Object *oded) = 0; virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; virtual Object *specialization() = 0; - virtual Object *defaultArg(Scope *sc) = 0; + virtual Object *defaultArg(Loc loc, Scope *sc) = 0; /* If TemplateParameter's match as far as overloading goes. */ @@ -152,7 +161,7 @@ void print(Object *oarg, Object *oded); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Object *specialization(); - Object *defaultArg(Scope *sc); + Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); @@ -196,7 +205,7 @@ void print(Object *oarg, Object *oded); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Object *specialization(); - Object *defaultArg(Scope *sc); + Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); @@ -224,7 +233,7 @@ void print(Object *oarg, Object *oded); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Object *specialization(); - Object *defaultArg(Scope *sc); + Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); @@ -245,7 +254,7 @@ void print(Object *oarg, Object *oded); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Object *specialization(); - Object *defaultArg(Scope *sc); + Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg();
--- a/gen/statements.cpp Tue Jan 06 15:54:48 2009 +0100 +++ b/gen/statements.cpp Tue Jan 06 16:33:51 2009 +0100 @@ -1375,7 +1375,7 @@ statement->toIR(p); // no point in a unreachable barrier, terminating statements must insert this themselves. - if (statement->fallOffEnd()) + if (statement->blockExit() & BEfallthru) { // store-load DtoMemoryBarrier(false, false, true, false);