From 462cdda4ae8c0a7b0bc3e30d19098496dc0aff9c Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Tue, 19 Jul 2011 10:14:04 +0400 Subject: [PATCH] Merge dmdfe 2.053beta --- dmd2/aggregate.h | 2 + dmd2/arrayop.c | 2 +- dmd2/attrib.c | 8 + dmd2/builtin.c | 4 +- dmd2/cast.c | 8 +- dmd2/class.c | 16 +- dmd2/clone.c | 12 +- dmd2/cond.h | 5 +- dmd2/constfold.c | 49 +- dmd2/declaration.c | 101 ++- dmd2/declaration.h | 17 +- dmd2/dsymbol.c | 37 +- dmd2/dump.c | 26 +- dmd2/expression.c | 320 +++++++- dmd2/expression.h | 137 ++-- dmd2/func.c | 21 +- dmd2/idgen.c | 4 +- dmd2/init.c | 135 +++- dmd2/init.h | 13 +- dmd2/inline.c | 9 +- dmd2/interpret.c | 1682 +++++++++++++++++++++++++++++++------------ dmd2/irstate.c | 7 +- dmd2/irstate.h | 3 +- dmd2/lexer.c | 7 +- dmd2/mars.c | 4 +- dmd2/mtype.c | 80 +- dmd2/mtype.h | 5 + dmd2/optimize.c | 86 ++- dmd2/parse.c | 32 +- dmd2/scope.h | 2 + dmd2/statement.c | 338 +++++---- dmd2/statement.h | 44 +- dmd2/staticassert.c | 10 +- dmd2/struct.c | 53 +- dmd2/template.c | 18 +- dmd2/traits.c | 17 +- gen/asm-x86-32.h | 8 +- gen/asm-x86-64.h | 8 +- gen/llvmhelpers.cpp | 2 +- 39 files changed, 2441 insertions(+), 891 deletions(-) diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h index cd9d44cd..e1b75c30 100644 --- a/dmd2/aggregate.h +++ b/dmd2/aggregate.h @@ -100,6 +100,8 @@ struct AggregateDeclaration : ScopeDsymbol static void alignmember(unsigned salign, unsigned size, unsigned *poffset); Type *getType(); void addField(Scope *sc, VarDeclaration *v); + int firstFieldInUnion(int indx); // first field in union that includes indx + int numFieldsInUnion(int firstIndex); // #fields in union starting at index int isDeprecated(); // is aggregate deprecated? FuncDeclaration *buildDtor(Scope *sc); int isNested(); diff --git a/dmd2/arrayop.c b/dmd2/arrayop.c index 03336182..9ed42729 100644 --- a/dmd2/arrayop.c +++ b/dmd2/arrayop.c @@ -352,7 +352,7 @@ Expression *BinExp::arrayOp(Scope *sc) */ TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc); //printf("ftype: %s\n", ftype->toChars()); - fd = new FuncDeclaration(0, 0, Lexer::idPool(name), STCundefined, ftype); + fd = new FuncDeclaration(loc, 0, Lexer::idPool(name), STCundefined, ftype); fd->fbody = fbody; fd->protection = PROTpublic; fd->linkage = LINKd; diff --git a/dmd2/attrib.c b/dmd2/attrib.c index 78eddef7..bb62a768 100644 --- a/dmd2/attrib.c +++ b/dmd2/attrib.c @@ -737,6 +737,12 @@ void AnonDeclaration::semantic(Scope *sc) { //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); + if (sem == 1) + { //printf("already completed\n"); + scope = NULL; + return; // semantic() already completed + } + Scope *scx = NULL; if (scope) { sc = scope; @@ -1001,6 +1007,8 @@ void PragmaDeclaration::semantic(Scope *sc) e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); args->data[0] = (void *)e; + if (e->op == TOKerror) + goto Lnodecl; if (e->op != TOKstring) error("string expected for library name, not '%s'", e->toChars()); else if (global.params.verbose) diff --git a/dmd2/builtin.c b/dmd2/builtin.c index 30cd380b..6ec705e6 100644 --- a/dmd2/builtin.c +++ b/dmd2/builtin.c @@ -44,7 +44,7 @@ enum BUILTIN FuncDeclaration::isBuiltin() static const char FeZe [] = "FNaNbNfeZe"; // @safe pure nothrow real function(real) static const char FeZe2[] = "FNaNbNeeZe"; // @trusted pure nothrow real function(real) - //printf("FuncDeclaration::isBuiltin() %s\n", toChars()); + //printf("FuncDeclaration::isBuiltin() %s, %d\n", toChars(), builtin); if (builtin == BUILTINunknown) { builtin = BUILTINnot; @@ -52,7 +52,7 @@ enum BUILTIN FuncDeclaration::isBuiltin() { // If it's in the std.math package if (parent->ident == Id::math && - parent->parent && parent->parent->ident == Id::std && + parent->parent && (parent->parent->ident == Id::std || parent->parent->ident == Id::core) && !parent->parent->parent) { //printf("deco = %s\n", type->deco); diff --git a/dmd2/cast.c b/dmd2/cast.c index ff5b1aae..0f099bc3 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -856,6 +856,12 @@ Expression *Expression::castTo(Scope *sc, Type *t) } +Expression *ErrorExp::castTo(Scope *sc, Type *t) +{ + return this; +} + + Expression *RealExp::castTo(Scope *sc, Type *t) { Expression *e = this; if (type != t) diff --git a/dmd2/class.c b/dmd2/class.c index 2bef13c4..52ddb7ac 100644 --- a/dmd2/class.c +++ b/dmd2/class.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -839,16 +839,18 @@ int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) *poffset = 0; while (cd) { - if (this == cd->baseClass) - return 1; - /* cd->baseClass might not be set if cd is forward referenced. */ if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) { - cd->error("base class is forward referenced by %s", toChars()); + cd->semantic(NULL); + if (!cd->baseClass) + cd->error("base class is forward referenced by %s", toChars()); } + if (this == cd->baseClass) + return 1; + cd = cd->baseClass; } return 0; @@ -876,14 +878,14 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) Dsymbol *s; //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); - if (scope) + if (scope && !symtab) { Scope *sc = scope; sc->mustsemantic++; semantic(sc); sc->mustsemantic--; } - if (!members || !symtab || scope) + if (!members || !symtab) { error("is forward referenced when looking for '%s'", ident->toChars()); //*(char*)0=0; diff --git a/dmd2/clone.c b/dmd2/clone.c index 2c9e2a02..9d568f86 100644 --- a/dmd2/clone.c +++ b/dmd2/clone.c @@ -143,7 +143,7 @@ FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) ((TypeFunction *)ftype)->isref = 1; #endif - fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype); + fop = new FuncDeclaration(loc, 0, Id::assign, STCundefined, ftype); Expression *e = NULL; if (postblit) @@ -335,7 +335,7 @@ FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) fparams->push(param); Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd); - fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype); + fcp = new FuncDeclaration(loc, 0, Id::cpctor, STCundefined, ftype); fcp->storage_class |= postblit->storage_class & STCdisable; // Build *this = p; @@ -434,7 +434,7 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) */ if (e) { //printf("Building __fieldPostBlit()\n"); - PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit")); + PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__fieldPostBlit")); dd->storage_class |= stc; dd->fbody = new ExpStatement(0, e); postblits.shift(dd); @@ -460,7 +460,7 @@ FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) ex = new CallExp(0, ex); e = Expression::combine(e, ex); } - PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit")); + PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__aggrPostBlit")); dd->storage_class |= stc; dd->fbody = new ExpStatement(0, e); members->push(dd); @@ -534,7 +534,7 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) */ if (e) { //printf("Building __fieldDtor()\n"); - DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor")); + DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__fieldDtor")); dd->fbody = new ExpStatement(0, e); dtors.shift(dd); members->push(dd); @@ -559,7 +559,7 @@ FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) ex = new CallExp(0, ex); e = Expression::combine(ex, e); } - DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor")); + DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__aggrDtor")); dd->fbody = new ExpStatement(0, e); members->push(dd); dd->semantic(sc); diff --git a/dmd2/cond.h b/dmd2/cond.h index 5d6fb94d..8302c23d 100644 --- a/dmd2/cond.h +++ b/dmd2/cond.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -17,6 +17,7 @@ struct OutBuffer; struct Module; struct Scope; struct ScopeDsymbol; +struct DebugCondition; #ifdef _DH #include "lexer.h" // dmdhg #endif @@ -39,6 +40,7 @@ struct Condition virtual Condition *syntaxCopy() = 0; virtual int include(Scope *sc, ScopeDsymbol *s) = 0; virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; + virtual DebugCondition *isDebugCondition() { return NULL; } }; struct DVCondition : Condition @@ -62,6 +64,7 @@ struct DebugCondition : DVCondition int include(Scope *sc, ScopeDsymbol *s); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + DebugCondition *isDebugCondition() { return this; } }; struct VersionCondition : DVCondition diff --git a/dmd2/constfold.c b/dmd2/constfold.c index fd0ea546..7551922e 100644 --- a/dmd2/constfold.c +++ b/dmd2/constfold.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -1381,9 +1381,12 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) dinteger_t v = e->toInteger(); - size_t len = utf_codeLength(sz, v); + size_t len = (t->ty == tn->ty) ? 1 : utf_codeLength(sz, v); s = mem.malloc((len + 1) * sz); - utf_encode(sz, s, v); + if (t->ty == tn->ty) + memcpy((unsigned char *)s, &v, sz); + else + utf_encode(sz, s, v); // Add terminating 0 memset((unsigned char *)s + len * sz, 0, sz); @@ -1438,6 +1441,34 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) es->type = type; e = es; } + else if (e2->op == TOKstring && e1->op == TOKarrayliteral && + t1->nextOf()->isintegral()) + { + // Concatenate the strings + StringExp *es1 = (StringExp *)e2; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1; + size_t len = es1->len + es2->elements->dim; + int sz = es1->sz; + + void *s = mem.malloc((len + 1) * sz); + memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz); + for (int i = 0; i < es2->elements->dim; i++) + { Expression *es2e = (Expression *)es2->elements->data[i]; + if (es2e->op != TOKint64) + return EXP_CANT_INTERPRET; + dinteger_t v = es2e->toInteger(); + memcpy((unsigned char *)s + i * sz, &v, sz); + } + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + StringExp *es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = 0; + es->type = type; + e = es; + } else if (e1->op == TOKstring && e2->op == TOKarrayliteral && t2->nextOf()->isintegral()) { @@ -1476,10 +1507,18 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) int sz = es1->sz; dinteger_t v = e2->toInteger(); - size_t len = es1->len + utf_codeLength(sz, v); + // Is it a concatentation of homogenous types? + // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar) + bool homoConcat = (sz == t2->size()); + size_t len = es1->len; + len += homoConcat ? 1 : utf_codeLength(sz, v); + s = mem.malloc((len + 1) * sz); memcpy(s, es1->string, es1->len * sz); - utf_encode(sz, (unsigned char *)s + (sz * es1->len), v); + if (homoConcat) + memcpy((unsigned char *)s + (sz * es1->len), &v, sz); + else + utf_encode(sz, (unsigned char *)s + (sz * es1->len), v); // Add terminating 0 memset((unsigned char *)s + len * sz, 0, sz); diff --git a/dmd2/declaration.c b/dmd2/declaration.c index 698207cf..a0a14b8d 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -344,7 +344,7 @@ void TypedefDeclaration::semantic2(Scope *sc) { sem = Semantic2Done; if (init) { - init = init->semantic(sc, basetype); + init = init->semantic(sc, basetype, WANTinterpret); ExpInitializer *ie = init->isExpInitializer(); if (ie) @@ -556,7 +556,7 @@ void AliasDeclaration::semantic(Scope *sc) } } if (overnext) - ScopeDsymbol::multiplyDefined(0, s, overnext); + ScopeDsymbol::multiplyDefined(0, this, overnext); if (s == this) { assert(global.errors); @@ -695,8 +695,11 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer aliassym = NULL; onstack = 0; canassign = 0; - value = NULL; + setValueNull(); +#if DMDV2 rundtor = NULL; + edtor = NULL; +#endif #if IN_LLVM aggrIndex = 0; @@ -1078,7 +1081,7 @@ Lagain: e = new ConstructExp(loc, e1, e); e->type = e1->type; // don't type check this, it would fail init = new ExpInitializer(loc, e); - return; + goto Ldtor; } else if (type->ty == Ttypedef) { TypeTypedef *td = (TypeTypedef *)type; @@ -1141,7 +1144,7 @@ Lagain: Expression *e = init->toExpression(); if (!e) { - init = init->semantic(sc, type); + init = init->semantic(sc, type, 0); // Don't need to interpret e = init->toExpression(); if (!e) { error("is not a static and cannot have static initializer"); @@ -1155,6 +1158,8 @@ Lagain: Expression *e1 = new VarExp(loc, this); Type *t = type->toBasetype(); + + Linit2: if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) { ei->exp = ei->exp->semantic(sc); @@ -1184,14 +1189,13 @@ Lagain: if (sd->ctor && // there are constructors ei->exp->type->ty == Tstruct && // rvalue is the same struct ((TypeStruct *)ei->exp->type)->sym == sd && - ei->exp->op == TOKstar) + ei->exp->op == TOKcall) { /* Look for form of constructor call which is: * *__ctmp.ctor(arguments...) */ - PtrExp *pe = (PtrExp *)ei->exp; - if (pe->e1->op == TOKcall) - { CallExp *ce = (CallExp *)pe->e1; + if (1) + { CallExp *ce = (CallExp *)ei->exp; if (ce->e1->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)ce->e1; if (dve->var->isCtorDeclaration()) @@ -1202,19 +1206,36 @@ Lagain: * variable with a bit copy of the default * initializer */ - Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); - e->op = TOKblit; + Expression *e; + if (sd->zeroInit == 1) + { + e = new ConstructExp(loc, new VarExp(loc, this), new IntegerExp(loc, 0, Type::tint32)); + } + else + { e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); + e->op = TOKblit; + } e->type = t; ei->exp = new CommaExp(loc, e, ei->exp); /* Replace __ctmp being constructed with e1 */ dve->e1 = e1; - return; + ei->exp = ei->exp->semantic(sc); + goto Ldtor; } } } } + + /* Look for ((S tmp = S()),tmp) and replace it with just S() + */ + Expression *e2 = ei->exp->isTemp(); + if (e2) + { + ei->exp = e2; + goto Linit2; + } #endif if (!ei->exp->implicitConvTo(type)) { @@ -1261,7 +1282,7 @@ Lagain: } else { - init = init->semantic(sc, type); + init = init->semantic(sc, type, WANTinterpret); } } else if (storage_class & (STCconst | STCimmutable | STCmanifest) || @@ -1334,7 +1355,7 @@ Lagain: } else if (si || ai) { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type); + i2 = i2->semantic(sc, type, WANTinterpret); } inuse--; global.gag--; @@ -1384,6 +1405,21 @@ Lagain: } sc = sc->pop(); } + +Ldtor: + /* Build code to execute destruction, if necessary + */ + edtor = callScopeDtor(sc); + if (edtor) + { + edtor = edtor->semantic(sc); + +#if 0 // currently disabled because of std.stdio.stdin, stdout and stderr + if (isDataseg() && !(storage_class & STCextern)) + error("static storage variables cannot have destructors"); +#endif + } + sem = SemanticDone; } @@ -1400,7 +1436,7 @@ void VarDeclaration::semantic2(Scope *sc) printf("type = %p\n", ei->exp->type); } #endif - init = init->semantic(sc, type); + init = init->semantic(sc, type, WANTinterpret); inuse--; } sem = Semantic2Done; @@ -1687,29 +1723,10 @@ int VarDeclaration::needsAutoDtor() { //printf("VarDeclaration::needsAutoDtor() %s\n", toChars()); - if (noscope || storage_class & STCnodtor) + if (noscope || !edtor) return FALSE; - // Destructors for structs and arrays of structs - Type *tv = type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - return TRUE; - } - - // Destructors for classes - if (storage_class & (STCauto | STCscope)) - { - if (type->isClassHandle()) - return TRUE; - } - return FALSE; + return TRUE; } @@ -1723,8 +1740,11 @@ Expression *VarDeclaration::callScopeDtor(Scope *sc) //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); - if (noscope || storage_class & STCnodtor) + // Destruction of STCfield's is handled by buildDtor() + if (noscope || storage_class & (STCnodtor | STCref | STCout | STCfield)) + { return NULL; + } // Destructors for structs and arrays of structs bool array = false; @@ -1759,6 +1779,11 @@ Expression *VarDeclaration::callScopeDtor(Scope *sc) else { e = new VarExp(loc, this); + /* This is a hack so we can call destructors on const/immutable objects. + * Need to add things like "const ~this()" and "immutable ~this()" to + * fix properly. + */ + e->type = e->type->mutableOf(); e = new DotVarExp(loc, e, sd->dtor, 0); e = new CallExp(loc, e); } diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 91b66496..6714f7b9 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -286,12 +286,23 @@ struct VarDeclaration : Declaration // 2: on stack, run destructor anyway int canassign; // it can be assigned to Dsymbol *aliassym; // if redone as alias to another symbol - Expression *value; // when interpreting, this is the value - // (NULL if value not determinable) + + // When interpreting, these hold the value (NULL if value not determinable) + // The various functions are used only to detect compiler CTFE bugs + Expression *literalvalue; + Expression *getValue() { return literalvalue; } + void setValueNull(); + void setValueWithoutChecking(Expression *newval); + void createRefValue(Expression *newval); // struct or array literal + void setRefValue(Expression *newval); + void setStackValue(Expression *newval); + void createStackValue(Expression *newval); + #if DMDV2 VarDeclaration *rundtor; // if !NULL, rundtor is tested at runtime to see // if the destructor should be run. Used to prevent // dtor calls on postblitted vars + Expression *edtor; // if !=NULL, does the destruction of the variable #endif VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c index 258a6622..b617e2e1 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.c @@ -566,6 +566,7 @@ void Dsymbol::error(const char *format, ...) fprintf(stdmsg, "\n"); fflush(stdmsg); +//halt(); } global.errors++; @@ -594,6 +595,7 @@ void Dsymbol::error(Loc loc, const char *format, ...) fprintf(stdmsg, "\n"); fflush(stdmsg); +halt(); } global.errors++; @@ -1223,33 +1225,10 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) * multiple times, it gets set only once. */ if (!*pvar) // if not already initialized - { /* Create variable v and set it to the value of $, - * which will be a constant. + { /* Create variable v and set it to the value of $ */ VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - - if (ce->op == TOKvar) - { // if ce is const, get its initializer - ce = fromConstInitializer(WANTvalue | WANTinterpret, ce); - } - - if (ce->op == TOKstring) - { /* It is for a string literal, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - else if (ce->op == TOKarrayliteral) - { /* It is for an array literal, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - else if (ce->op == TOKtuple) + if (ce->op == TOKtuple) { /* It is for an expression tuple, so the * length will be a const. */ @@ -1257,6 +1236,14 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) v->init = new ExpInitializer(0, e); v->storage_class |= STCstatic | STCconst; } + else + { /* For arrays, $ will either be a compile-time constant + * (in which case its value in set during constant-folding), + * or a variable (in which case an expression is created in + * toir.c). + */ + v->init = new VoidInitializer(0); + } *pvar = v; } (*pvar)->semantic(sc); diff --git a/dmd2/dump.c b/dmd2/dump.c index d1468264..c443d94e 100644 --- a/dmd2/dump.c +++ b/dmd2/dump.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -33,13 +33,16 @@ static char *type_print(Type *type) void dumpExpressions(int i, Expressions *exps) { - for (size_t j = 0; j < exps->dim; j++) - { Expression *e = (Expression *)exps->data[j]; - indent(i); - printf("(\n"); - e->dump(i + 2); - indent(i); - printf(")\n"); + if (exps) + { + for (size_t j = 0; j < exps->dim; j++) + { Expression *e = (Expression *)exps->data[j]; + indent(i); + printf("(\n"); + e->dump(i + 2); + indent(i); + printf(")\n"); + } } } @@ -134,7 +137,12 @@ void DelegateExp::dump(int i) void BinExp::dump(int i) { indent(i); - printf("%p %s type=%s e1=%p e2=%p\n", this, Token::toChars(op), type_print(type), e1, e2); + const char *sop = Token::toChars(op); + if (op == TOKblit) + sop = "blit"; + else if (op == TOKconstruct) + sop = "construct"; + printf("%p %s type=%s e1=%p e2=%p\n", this, sop, type_print(type), e1, e2); if (e1) e1->dump(i + 2); if (e2) diff --git a/dmd2/expression.c b/dmd2/expression.c index 37a1ff3f..b18da014 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -487,7 +487,7 @@ void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) * Call copy constructor for struct value argument. */ #if DMDV2 -Expression *callCpCtor(Loc loc, Scope *sc, Expression *e) +Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope) { Type *tb = e->type->toBasetype(); assert(tb->ty == Tstruct); @@ -500,9 +500,10 @@ Expression *callCpCtor(Loc loc, Scope *sc, Expression *e) * This is not the most efficent, ideally tmp would be constructed * directly onto the stack. */ - Identifier *idtmp = Lexer::uniqueId("__tmp"); + Identifier *idtmp = Lexer::uniqueId("__cpcttmp"); VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); tmp->storage_class |= STCctfe; + tmp->noscope = noscope; Expression *ae = new DeclarationExp(loc, tmp); e = new CommaExp(loc, ae, new VarExp(loc, tmp)); e = e->semantic(sc); @@ -706,10 +707,41 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, #if DMDV2 if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) { - arg = callCpCtor(loc, sc, arg); + if (arg->op == TOKcall) + { + /* The struct value returned from the function is transferred + * to the function, so the callee should not call the destructor + * on it. + * ((S _ctmp = S.init), _ctmp).this(...) + */ + CallExp *ce = (CallExp *)arg; + if (ce->e1->op == TOKdotvar) + { DotVarExp *dve = (DotVarExp *)ce->e1; + if (dve->var->isCtorDeclaration()) + { // It's a constructor call + if (dve->e1->op == TOKcomma) + { CommaExp *comma = (CommaExp *)dve->e1; + if (comma->e2->op == TOKvar) + { VarExp *ve = (VarExp *)comma->e2; + VarDeclaration *ctmp = ve->var->isVarDeclaration(); + if (ctmp) + ctmp->noscope = 1; + } + } + } + } + } + else + { /* Not transferring it, so call the copy constructor + */ + arg = callCpCtor(loc, sc, arg, 1); + } } #endif + //printf("arg: %s\n", arg->toChars()); + //printf("type: %s\n", arg->type->toChars()); + // Convert lazy argument to a delegate if (p->storageClass & STClazy) { @@ -770,7 +802,12 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, } } + // Do not allow types that need destructors + if (arg->type->needsDestruction()) + arg->error("cannot pass types that need destruction as variadic arguments"); + // Convert static arrays to dynamic arrays + // BUG: I don't think this is right for D2 tb = arg->type->toBasetype(); if (tb->ty == Tsarray) { TypeSArray *ts = (TypeSArray *)tb; @@ -783,7 +820,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, #if DMDV2 if (tb->ty == Tstruct) { - arg = callCpCtor(loc, sc, arg); + arg = callCpCtor(loc, sc, arg, 1); } #endif @@ -1251,6 +1288,7 @@ void Expression::checkPurity(Scope *sc, FuncDeclaration *f) // If the caller has a pure parent, then either the called func must be pure, // OR, they must have the same pure parent. if (outerfunc->isPure() && !sc->intypeof && + !(sc->flags & SCOPEdebug) && !(f->isPure() || (calledparent == outerfunc))) { error("pure function '%s' cannot call impure function '%s'", @@ -1464,6 +1502,55 @@ Expressions *Expression::arraySyntaxCopy(Expressions *exps) return a; } +/*************************************************** + * Recognize expressions of the form: + * ((T v = init), v) + * where v is a temp. + * This is used in optimizing out unnecessary temporary generation. + * Returns initializer expression of v if so, NULL if not. + */ + +Expression *Expression::isTemp() +{ + //printf("isTemp() %s\n", toChars()); + if (op == TOKcomma) + { CommaExp *ec = (CommaExp *)this; + if (ec->e1->op == TOKdeclaration && + ec->e2->op == TOKvar) + { DeclarationExp *de = (DeclarationExp *)ec->e1; + VarExp *ve = (VarExp *)ec->e2; + if (ve->var == de->declaration && ve->var->storage_class & STCctfe) + { VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && v->init) + { + ExpInitializer *ei = v->init->isExpInitializer(); + if (ei) + { Expression *e = ei->exp; + if (e->op == TOKconstruct) + { ConstructExp *ce = (ConstructExp *)e; + if (ce->e1->op == TOKvar && ((VarExp *)ce->e1)->var == ve->var) + e = ce->e2; + } + return e; + } + } + } + } + } + return NULL; +} + +/************************************************ + * Destructors are attached to VarDeclarations. + * Hence, if expression returns a temp that needs a destructor, + * make sure and create a VarDeclaration for that temp. + */ + +Expression *Expression::addDtorHook(Scope *sc) +{ + return this; +} + /******************************** IntegerExp **************************/ IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type) @@ -3433,17 +3520,21 @@ Expression *StructLiteralExp::semantic(Scope *sc) else { if (v->init) - { e = v->init->toExpression(); - if (!e) - { error("cannot make expression out of initializer for %s", v->toChars()); - return new ErrorExp(); - } - else if (v->scope) - { // Do deferred semantic analysis - Initializer *i2 = v->init->syntaxCopy(); - i2 = i2->semantic(v->scope, v->type); - e = i2->toExpression(); - v->scope = NULL; + { if (v->init->isVoidInitializer()) + e = NULL; + else + { e = v->init->toExpression(); + if (!e) + { error("cannot make expression out of initializer for %s", v->toChars()); + return new ErrorExp(); + } + else if (v->scope) + { // Do deferred semantic analysis + Initializer *i2 = v->init->syntaxCopy(); + i2 = i2->semantic(v->scope, v->type, WANTinterpret); + e = i2->toExpression(); + v->scope = NULL; + } } } else @@ -3454,6 +3545,22 @@ Expression *StructLiteralExp::semantic(Scope *sc) } type = stype ? stype : sd->type; + + /* If struct requires a destructor, rewrite as: + * (S tmp = S()),tmp + * so that the destructor can be hung on tmp. + */ + if (sd->dtor) + { + Identifier *idtmp = Lexer::uniqueId("__sl"); + VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new ExpInitializer(0, this)); + tmp->storage_class |= STCctfe; + Expression *ae = new DeclarationExp(loc, tmp); + Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp)); + e = e->semantic(sc); + return e; + } + return this; } @@ -3481,7 +3588,7 @@ Expression *StructLiteralExp::getField(Type *type, unsigned offset) /* If type is a static array, and e is an initializer for that array, * then the field initializer should be an array literal of e. */ - if (e->type != type && type->ty == Tsarray) + if (e->type->castMod(0) != type->castMod(0) && type->ty == Tsarray) { TypeSArray *tsa = (TypeSArray *)type; uinteger_t length = tsa->dim->toInteger(); Expressions *z = new Expressions; @@ -3696,6 +3803,8 @@ Lagain: } //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); } + if (global.errors) + return new ErrorExp(); } else { @@ -4344,7 +4453,7 @@ Expression *VarExp::semantic(Scope *sc) v->checkNestedReference(sc, loc); #if DMDV2 #if 1 - if (sc->func && !sc->intypeof) + if (sc->func && !sc->intypeof && !(sc->flags & SCOPEdebug)) { /* Given: * void f() @@ -4551,7 +4660,8 @@ TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) if (o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; - e = e->syntaxCopy(); + if (e->op == TOKdsymbol) + e = e->syntaxCopy(); exps->push(e); } else if (o->dyncast() == DYNCAST_DSYMBOL) @@ -5051,8 +5161,8 @@ Expression *IsExp::semantic(Scope *sc) */ //printf("IsExp::semantic(%s)\n", toChars()); - if (id && !(sc->flags & SCOPEstaticif)) - { error("can only declare type aliases within static if conditionals"); + if (id && !(sc->flags & (SCOPEstaticif | SCOPEstaticassert))) + { error("can only declare type aliases within static if conditionals or static asserts"); return new ErrorExp(); } @@ -5693,6 +5803,8 @@ Expression *CompileExp::semantic(Scope *sc) #endif UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); + if (e1->op == TOKerror) + return e1; if (!e1->type->isString()) { error("argument to mixin must be a string type, not %s\n", e1->type->toChars()); @@ -5740,7 +5852,7 @@ Expression *FileExp::semantic(Scope *sc) #endif UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue); + e1 = e1->optimize(WANTvalue | WANTinterpret); if (e1->op != TOKstring) { error("file name argument must be a string, not (%s)", e1->toChars()); goto Lerror; @@ -6266,6 +6378,7 @@ Expression *DotVarExp::semantic(Scope *sc) } e1 = e1->semantic(sc); + e1 = e1->addDtorHook(sc); type = var->type; if (!type && global.errors) { // var is goofed up, just return 0 @@ -6435,6 +6548,8 @@ Expression *DotTemplateInstanceExp::semantic(Scope *sc) Expression *e = new DotIdExp(loc, e1, ti->name); L1: e = e->semantic(sc); + if (e->op == TOKerror) + return e; if (e->op == TOKdottd) { if (global.errors) @@ -7219,7 +7334,7 @@ Lagain: { TypeDelegate *td = (TypeDelegate *)t1; assert(td->next->ty == Tfunction); tf = (TypeFunction *)(td->next); - if (sc->func && sc->func->isPure() && !tf->purity) + if (sc->func && sc->func->isPure() && !tf->purity && !(sc->flags & SCOPEdebug)) { error("pure function '%s' cannot call impure delegate '%s'", sc->func->toChars(), e1->toChars()); } @@ -7233,7 +7348,7 @@ Lagain: { Expression *e = new PtrExp(loc, e1); t1 = ((TypePointer *)t1)->next; - if (sc->func && sc->func->isPure() && !((TypeFunction *)t1)->purity) + if (sc->func && sc->func->isPure() && !((TypeFunction *)t1)->purity && !(sc->flags & SCOPEdebug)) { error("pure function '%s' cannot call impure function pointer '%s'", sc->func->toChars(), e1->toChars()); } @@ -7356,9 +7471,9 @@ int CallExp::checkSideEffect(int flag) * then this expression has no side effects. */ Type *t = e1->type->toBasetype(); - if (t->ty == Tfunction && ((TypeFunction *)t)->purity) + if (t->ty == Tfunction && ((TypeFunction *)t)->purity > PUREweak) return 0; - if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->purity) + if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->purity > PUREweak) return 0; #endif return 1; @@ -7417,6 +7532,51 @@ Expression *CallExp::toLvalue(Scope *sc, Expression *e) return Expression::toLvalue(sc, e); } +Expression *CallExp::addDtorHook(Scope *sc) +{ + /* Only need to add dtor hook if it's a type that needs destruction. + * Use same logic as VarDeclaration::callScopeDtor() + */ + + if (e1->type && e1->type->ty == Tfunction) + { + TypeFunction *tf = (TypeFunction *)e1->type; + if (tf->isref) + return this; + } + + Type *tv = type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->dtor) + { /* Type needs destruction, so declare a tmp + * which the back end will recognize and call dtor on + */ + if (e1->op == TOKdotvar) + { + DotVarExp* dve = (DotVarExp*)e1; + if (dve->e1->isTemp() != NULL) + goto Lnone; // already got a tmp + } + + Identifier *idtmp = Lexer::uniqueId("__tmpfordtor"); + VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new ExpInitializer(loc, this)); + tmp->storage_class |= STCctfe; + Expression *ae = new DeclarationExp(loc, tmp); + Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp)); + e = e->semantic(sc); + return e; + } + } +Lnone: + return this; +} + void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (e1->op == TOKtype) @@ -7779,6 +7939,8 @@ Expression *DeleteExp::semantic(Scope *sc) UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); e1 = e1->toLvalue(sc, NULL); + if (e1->op == TOKerror) + return e1; type = Type::tvoid; tb = e1->type->toBasetype(); @@ -8591,6 +8753,7 @@ Expression *CommaExp::semantic(Scope *sc) { if (!type) { BinExp::semanticp(sc); + e1 = e1->addDtorHook(sc); type = e2->type; } return this; @@ -8656,6 +8819,12 @@ int CommaExp::checkSideEffect(int flag) } } +Expression *CommaExp::addDtorHook(Scope *sc) +{ + e2 = e2->addDtorHook(sc); + return this; +} + /************************** IndexExp **********************************/ // e1 [ e2 ] @@ -8894,7 +9063,7 @@ Expression *PostExp::semantic(Scope *sc) /* Rewrite as: * auto tmp = e1; ++e1; tmp */ - Identifier *id = Lexer::uniqueId("__tmp"); + Identifier *id = Lexer::uniqueId("__pitmp"); ExpInitializer *ei = new ExpInitializer(loc, e1); VarDeclaration *tmp = new VarDeclaration(loc, e1->type, id, ei); Expression *ea = new DeclarationExp(loc, tmp); @@ -9180,16 +9349,28 @@ Expression *AssignExp::semantic(Scope *sc) sd->cpctor) { /* We have a copy constructor for this */ + // Scan past commma's + Expression *ec = NULL; + while (e2->op == TOKcomma) + { CommaExp *ecomma = (CommaExp *)e2; + e2 = ecomma->e2; + if (ec) + ec = new CommaExp(ecomma->loc, ec, ecomma->e1); + else + ec = ecomma->e1; + } if (e2->op == TOKquestion) { /* Write as: * a ? e1 = b : e1 = c; */ - CondExp *ec = (CondExp *)e2; - AssignExp *ea1 = new AssignExp(ec->e1->loc, e1, ec->e1); + CondExp *econd = (CondExp *)e2; + AssignExp *ea1 = new AssignExp(econd->e1->loc, e1, econd->e1); ea1->op = op; - AssignExp *ea2 = new AssignExp(ec->e1->loc, e1, ec->e2); + AssignExp *ea2 = new AssignExp(econd->e1->loc, e1, econd->e2); ea2->op = op; - Expression *e = new CondExp(loc, ec->econd, ea1, ea2); + Expression *e = new CondExp(loc, econd->econd, ea1, ea2); + if (ec) + e = new CommaExp(loc, ec, e); return e->semantic(sc); } else if (e2->op == TOKvar || @@ -9202,8 +9383,33 @@ Expression *AssignExp::semantic(Scope *sc) */ Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); e = new CallExp(loc, e, e2); + if (ec) + e = new CommaExp(loc, ec, e); return e->semantic(sc); } + else if (e2->op == TOKcall) + { + /* The struct value returned from the function is transferred + * so should not call the destructor on it. + * ((S _ctmp = S.init), _ctmp).this(...) + */ + CallExp *ce = (CallExp *)e2; + if (ce->e1->op == TOKdotvar) + { DotVarExp *dve = (DotVarExp *)ce->e1; + if (dve->var->isCtorDeclaration()) + { // It's a constructor call + if (dve->e1->op == TOKcomma) + { CommaExp *comma = (CommaExp *)dve->e1; + if (comma->e2->op == TOKvar) + { VarExp *ve = (VarExp *)comma->e2; + VarDeclaration *ctmp = ve->var->isVarDeclaration(); + if (ctmp) + ctmp->noscope = 1; + } + } + } + } + } } } } @@ -9560,6 +9766,7 @@ Expression *CatAssignExp::semantic(Scope *sc) } else if (tb1->ty == Tarray && (tb1next->ty == Tchar || tb1next->ty == Twchar) && + e2->type->ty != tb1next->ty && e2->implicitConvTo(Type::tdchar) ) { // Append dchar to char[] or wchar[] @@ -10448,6 +10655,35 @@ Expression *PowExp::semantic(Scope *sc) e = e->semantic(sc); return e; } + // Replace x ^^ 0 or x^^0.0 by (x, 1) + if ((e2->op == TOKint64 && e2->toInteger() == 0) || + (e2->op == TOKfloat64 && e2->toReal() == 0.0)) + { + if (e1->op == TOKint64) + e = new IntegerExp(loc, 1, e1->type); + else + e = new RealExp(loc, 1.0, e1->type); + + typeCombine(sc); + e = new CommaExp(loc, e1, e); + e = e->semantic(sc); + return e; + } + // Replace x ^^ 1 or x^^1.0 by (x) + if ((e2->op == TOKint64 && e2->toInteger() == 1) || + (e2->op == TOKfloat64 && e2->toReal() == 1.0)) + { + typeCombine(sc); + return e1; + } + // Replace x ^^ -1.0 by (1.0 / x) + if ((e2->op == TOKfloat64 && e2->toReal() == -1.0)) + { + typeCombine(sc); + e = new DivExp(loc, new RealExp(loc, 1.0, e2->type), e1); + e = e->semantic(sc); + return e; + } // All other negative integral powers are illegal if ((e1->type->isintegral()) && (e2->op == TOKint64) && (sinteger_t)e2->toInteger() < 0) { @@ -10469,7 +10705,7 @@ Expression *PowExp::semantic(Scope *sc) typeCombine(sc); // Replace x^^2 with (tmp = x, tmp*tmp) // Replace x^^3 with (tmp = x, tmp*tmp*tmp) - Identifier *idtmp = Lexer::uniqueId("__tmp"); + Identifier *idtmp = Lexer::uniqueId("__powtmp"); VarDeclaration *tmp = new VarDeclaration(loc, e1->type->toBasetype(), idtmp, new ExpInitializer(0, e1)); tmp->storage_class = STCctfe; Expression *ve = new VarExp(loc, tmp); @@ -10744,13 +10980,21 @@ Expression *OrOrExp::semantic(Scope *sc) e2 = resolveProperties(sc, e2); e2 = e2->checkToPointer(); - type = Type::tboolean; if (e2->type->ty == Tvoid) type = Type::tvoid; + else + { + e2 = e2->checkToBoolean(sc); + type = Type::tboolean; + } if (e2->op == TOKtype || e2->op == TOKimport) { error("%s is not an expression", e2->toChars()); return new ErrorExp(); } + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; return this; } @@ -10811,13 +11055,21 @@ Expression *AndAndExp::semantic(Scope *sc) e2 = resolveProperties(sc, e2); e2 = e2->checkToPointer(); - type = Type::tboolean; if (e2->type->ty == Tvoid) type = Type::tvoid; + else + { + e2 = e2->checkToBoolean(sc); + type = Type::tboolean; + } if (e2->op == TOKtype || e2->op == TOKimport) { error("%s is not an expression", e2->toChars()); return new ErrorExp(); } + if (e1->op == TOKerror) + return e1; + if (e2->op == TOKerror) + return e2; return this; } diff --git a/dmd2/expression.h b/dmd2/expression.h index 00929142..58098bf8 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -46,6 +46,7 @@ struct InterState; struct Symbol; // back end symbol #endif struct OverloadSet; +struct Initializer; #if IN_LLVM struct AssignExp; #endif @@ -88,6 +89,15 @@ FuncDeclaration *hasThis(Scope *sc); Expression *fromConstInitializer(int result, Expression *e); int arrayExpressionCanThrow(Expressions *exps, bool mustNotThrow); +/* Interpreter: what form of return value expression is required? + */ +enum CtfeGoal +{ ctfeNeedRvalue, // Must return an Rvalue + ctfeNeedLvalue, // Must return an Lvalue + ctfeNeedAnyValue, // Can return either an Rvalue or an Lvalue + ctfeNeedNothing // The return value is not required +}; + struct IntRange { uinteger_t imin; uinteger_t imax; @@ -144,10 +154,12 @@ struct Expression : Object void checkPurity(Scope *sc, FuncDeclaration *f); void checkSafety(Scope *sc, FuncDeclaration *f); virtual Expression *checkToBoolean(Scope *sc); + virtual Expression *addDtorHook(Scope *sc); Expression *checkToPointer(); Expression *addressOf(Scope *sc); Expression *deref(); Expression *integralPromotions(Scope *sc); + Expression *isTemp(); Expression *toDelegate(Scope *sc, Type *t); virtual void scanForNestedRef(Scope *sc); @@ -155,9 +167,12 @@ struct Expression : Object virtual Expression *optimize(int result); #define WANTflags 1 #define WANTvalue 2 + // A compile-time result is required. Give an error if not possible #define WANTinterpret 4 + // Same as WANTvalue, but also expand variables as far as possible + #define WANTexpand 8 - virtual Expression *interpret(InterState *istate); + virtual Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); virtual int isConst(); virtual int isBool(int result); @@ -183,6 +198,7 @@ struct Expression : Object #if IN_DMD // Back end virtual elem *toElem(IRState *irs); + elem *toElemDtor(IRState *irs); virtual dt_t **toDt(dt_t **pdt); #endif @@ -205,7 +221,7 @@ struct IntegerExp : Expression IntegerExp(dinteger_t value); int equals(Object *o); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); char *toChars(); void dump(int indent); IntRange getIntRange(); @@ -233,6 +249,7 @@ struct ErrorExp : IntegerExp ErrorExp(); Expression *implicitCastTo(Scope *sc, Type *t); + Expression *castTo(Scope *sc, Type *t); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *toLvalue(Scope *sc, Expression *e); }; @@ -244,7 +261,7 @@ struct RealExp : Expression RealExp(Loc loc, real_t value, Type *type); int equals(Object *o); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); char *toChars(); dinteger_t toInteger(); uinteger_t toUInteger(); @@ -272,7 +289,7 @@ struct ComplexExp : Expression ComplexExp(Loc loc, complex_t value, Type *type); int equals(Object *o); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); char *toChars(); dinteger_t toInteger(); uinteger_t toUInteger(); @@ -336,7 +353,7 @@ struct ThisExp : Expression ThisExp(Loc loc); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBool(int result); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int isLvalue(); @@ -380,7 +397,7 @@ struct NullExp : Expression void toMangleBuffer(OutBuffer *buf); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); #if IN_DMD elem *toElem(IRState *irs); dt_t **toDt(dt_t **pdt); @@ -405,7 +422,7 @@ struct StringExp : Expression int equals(Object *o); char *toChars(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); size_t length(); StringExp *toUTF8(Scope *sc); Expression *implicitCastTo(Scope *sc, Type *t); @@ -443,7 +460,7 @@ struct TupleExp : Expression void checkEscape(); int checkSideEffect(int flag); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *castTo(Scope *sc, Type *t); #if IN_DMD elem *toElem(IRState *irs); @@ -474,7 +491,7 @@ struct ArrayLiteralExp : Expression void toMangleBuffer(OutBuffer *buf); void scanForNestedRef(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); int canThrow(bool mustNotThrow); @@ -510,7 +527,7 @@ struct AssocArrayLiteralExp : Expression void toMangleBuffer(OutBuffer *buf); void scanForNestedRef(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); int canThrow(bool mustNotThrow); @@ -549,7 +566,7 @@ struct StructLiteralExp : Expression void toMangleBuffer(OutBuffer *buf); void scanForNestedRef(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); int canThrow(bool mustNotThrow); @@ -636,7 +653,7 @@ struct NewExp : Expression Type *newtype, Expressions *arguments); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *optimize(int result); #if IN_DMD elem *toElem(IRState *irs); @@ -700,7 +717,7 @@ struct SymOffExp : SymbolExp SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads = 0); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void checkEscape(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int isConst(); @@ -727,7 +744,7 @@ struct VarExp : SymbolExp int equals(Object *o); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void dump(int indent); char *toChars(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -774,7 +791,7 @@ struct FuncExp : Expression FuncExp(Loc loc, FuncLiteralDeclaration *fd); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void scanForNestedRef(Scope *sc); char *toChars(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -801,7 +818,7 @@ struct DeclarationExp : Expression DeclarationExp(Loc loc, Dsymbol *declaration); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD @@ -890,7 +907,8 @@ struct UnaExp : Expression Expression *optimize(int result); void dump(int indent); void scanForNestedRef(Scope *sc); - Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)); + Expression *interpretCommon(InterState *istate, CtfeGoal goal, + Expression *(*fp)(Type *, Expression *)); int canThrow(bool mustNotThrow); Expression *resolveLoc(Loc loc, Scope *sc); @@ -921,9 +939,12 @@ struct BinExp : Expression void incompatibleTypes(); void dump(int indent); void scanForNestedRef(Scope *sc); - Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)); - Expression *interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)); - Expression *interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); + Expression *interpretCommon(InterState *istate, CtfeGoal goal, + Expression *(*fp)(Type *, Expression *, Expression *)); + Expression *interpretCommon2(InterState *istate, CtfeGoal goal, + Expression *(*fp)(TOK, Type *, Expression *, Expression *)); + Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, + Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); int canThrow(bool mustNotThrow); Expression *arrayOp(Scope *sc); @@ -979,7 +1000,7 @@ struct AssertExp : UnaExp AssertExp(Loc loc, Expression *e, Expression *msg = NULL); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); int canThrow(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1027,7 +1048,7 @@ struct DotVarExp : UnaExp Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void dump(int indent); #if IN_DMD @@ -1060,7 +1081,7 @@ struct DelegateExp : UnaExp DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, int hasOverloads = 0); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1104,7 +1125,7 @@ struct CallExp : UnaExp Expression *syntaxCopy(); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void dump(int indent); @@ -1115,6 +1136,7 @@ struct CallExp : UnaExp int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); int canThrow(bool mustNotThrow); + Expression *addDtorHook(Scope *sc); int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); @@ -1143,7 +1165,7 @@ struct AddrExp : UnaExp #if IN_LLVM DValue* toElem(IRState* irs); llvm::Constant *toConstElem(IRState *irs); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal); #endif }; @@ -1161,7 +1183,7 @@ struct PtrExp : UnaExp elem *toElem(IRState *irs); #endif Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); // For operator overloading Identifier *opId(); @@ -1177,7 +1199,7 @@ struct NegExp : UnaExp NegExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1207,7 +1229,7 @@ struct ComExp : UnaExp ComExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1228,7 +1250,7 @@ struct NotExp : UnaExp NotExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBit(); #if IN_DMD elem *toElem(IRState *irs); @@ -1244,7 +1266,7 @@ struct BoolExp : UnaExp BoolExp(Loc loc, Expression *e, Type *type); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBit(); #if IN_DMD elem *toElem(IRState *irs); @@ -1284,7 +1306,7 @@ struct CastExp : UnaExp MATCH implicitConvTo(Type *t); IntRange getIntRange(); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); void checkEscape(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1322,7 +1344,7 @@ struct SliceExp : UnaExp Expression *modifiableLvalue(Scope *sc, Expression *e); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void dump(int indent); #if IN_DMD elem *toElem(IRState *irs); @@ -1346,7 +1368,7 @@ struct ArrayLengthExp : UnaExp ArrayLengthExp(Loc loc, Expression *e1); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD elem *toElem(IRState *irs); @@ -1404,9 +1426,10 @@ struct CommaExp : BinExp int isBool(int result); int checkSideEffect(int flag); MATCH implicitConvTo(Type *t); + Expression *addDtorHook(Scope *sc); Expression *castTo(Scope *sc, Type *t); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); #if IN_DMD elem *toElem(IRState *irs); #endif @@ -1429,7 +1452,7 @@ struct IndexExp : BinExp Expression *modifiableLvalue(Scope *sc, Expression *e); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *doInline(InlineDoState *ids); void scanForNestedRef(Scope *sc); @@ -1448,7 +1471,7 @@ struct PostExp : BinExp { PostExp(enum TOK op, Loc loc, Expression *e); Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Identifier *opId(); // For operator overloading #if IN_DMD @@ -1475,7 +1498,7 @@ struct AssignExp : BinExp AssignExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *checkToBoolean(Scope *sc); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Identifier *opId(); // For operator overloading void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1507,7 +1530,7 @@ struct op##AssignExp : BinAssignExp \ { \ op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ Expression *semantic(Scope *sc); \ - Expression *interpret(InterState *istate); \ + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); \ X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ X(Expression *buildArrayLoop(Parameters *fparams);) \ \ @@ -1553,7 +1576,7 @@ struct AddExp : BinExp AddExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1577,7 +1600,7 @@ struct MinExp : BinExp MinExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1600,7 +1623,7 @@ struct CatExp : BinExp CatExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); // For operator overloading Identifier *opId(); @@ -1620,7 +1643,7 @@ struct MulExp : BinExp MulExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1643,7 +1666,7 @@ struct DivExp : BinExp DivExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); IntRange getIntRange(); @@ -1666,7 +1689,7 @@ struct ModExp : BinExp ModExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); @@ -1700,7 +1723,7 @@ struct ShlExp : BinExp ShlExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); IntRange getIntRange(); // For operator overloading @@ -1721,7 +1744,7 @@ struct ShrExp : BinExp ShrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); IntRange getIntRange(); // For operator overloading @@ -1742,7 +1765,7 @@ struct UshrExp : BinExp UshrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); IntRange getIntRange(); // For operator overloading @@ -1763,7 +1786,7 @@ struct AndExp : BinExp AndExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); IntRange getIntRange(); @@ -1787,7 +1810,7 @@ struct OrExp : BinExp OrExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); MATCH implicitConvTo(Type *t); @@ -1812,7 +1835,7 @@ struct XorExp : BinExp XorExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); MATCH implicitConvTo(Type *t); @@ -1839,7 +1862,7 @@ struct OrOrExp : BinExp Expression *checkToBoolean(Scope *sc); int isBit(); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); #if IN_DMD elem *toElem(IRState *irs); @@ -1857,7 +1880,7 @@ struct AndAndExp : BinExp Expression *checkToBoolean(Scope *sc); int isBit(); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); #if IN_DMD elem *toElem(IRState *irs); @@ -1873,7 +1896,7 @@ struct CmpExp : BinExp CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBit(); // For operator overloading @@ -1929,7 +1952,7 @@ struct EqualExp : BinExp EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBit(); // For operator overloading @@ -1954,7 +1977,7 @@ struct IdentityExp : BinExp Expression *semantic(Scope *sc); int isBit(); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); #if IN_DMD elem *toElem(IRState *irs); #endif @@ -1974,7 +1997,7 @@ struct CondExp : BinExp Expression *syntaxCopy(); Expression *semantic(Scope *sc); Expression *optimize(int result); - Expression *interpret(InterState *istate); + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void checkEscape(); void checkEscapeRef(); int isLvalue(); diff --git a/dmd2/func.c b/dmd2/func.c index 80f097e3..71b046c7 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -288,6 +288,10 @@ void FuncDeclaration::semantic(Scope *sc) if (isAbstract() && !isVirtual()) error("non-virtual functions cannot be abstract"); + // https://github.com/donc/dmd/commit/9f7b2f8cfe5d7482f2de7f9678c176d54abe237f#commitcomment-321724 + //if (isOverride() && !isVirtual()) + //error("cannot override a non-virtual function"); + if ((f->isConst() || f->isImmutable()) && !isThis()) error("without 'this' cannot be const/immutable"); @@ -744,7 +748,7 @@ void FuncDeclaration::semantic(Scope *sc) FuncDeclaration *fd = new FuncDeclaration(loc, loc, Id::require, STCundefined, tf); fd->fbody = frequire; - Statement *s1 = new DeclarationStatement(loc, fd); + Statement *s1 = new ExpStatement(loc, fd); Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), (Expressions *)NULL); Statement *s2 = new ExpStatement(loc, e); frequire = new CompoundStatement(loc, s1, s2); @@ -771,7 +775,7 @@ void FuncDeclaration::semantic(Scope *sc) FuncDeclaration *fd = new FuncDeclaration(loc, loc, Id::ensure, STCundefined, tf); fd->fbody = fensure; - Statement *s1 = new DeclarationStatement(loc, fd); + Statement *s1 = new ExpStatement(loc, fd); Expression *eresult = NULL; if (outId) eresult = new IdentifierExp(loc, outId); @@ -1018,7 +1022,7 @@ void FuncDeclaration::semantic3(Scope *sc) v_arguments->parent = this; #endif } - if (f->linkage == LINKd || (parameters && parameters->dim)) + if (f->linkage == LINKd || (f->parameters && Parameter::dim(f->parameters))) { // Declare _argptr #if IN_GCC t = d_gcc_builtin_va_list_d_type; @@ -1709,7 +1713,10 @@ void FuncDeclaration::semantic3(Scope *sc) if (v->type->toBasetype()->ty == Tsarray) continue; - Expression *e = v->callScopeDtor(sc2); + if (v->noscope) + continue; + + Expression *e = v->edtor; if (e) { Statement *s = new ExpStatement(0, e); s = s->semantic(sc2); @@ -1727,7 +1734,7 @@ void FuncDeclaration::semantic3(Scope *sc) { /* Wrap the entire function body in a synchronized statement */ AggregateDeclaration *ad = isThis(); - ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL; + ClassDeclaration *cd = ad ? ad->isClassDeclaration() : parent->isClassDeclaration(); if (cd) { @@ -3395,7 +3402,7 @@ void StaticCtorDeclaration::semantic(Scope *sc) VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); v->storage_class = isSharedStaticCtorDeclaration() ? STCstatic : STCtls; Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); + Statement *s = new ExpStatement(0, v); sa->push(s); Expression *e = new IdentifierExp(0, id); e = new AddAssignExp(0, e, new IntegerExp(1)); @@ -3521,7 +3528,7 @@ void StaticDtorDeclaration::semantic(Scope *sc) VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); v->storage_class = isSharedStaticDtorDeclaration() ? STCstatic : STCtls; Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); + Statement *s = new ExpStatement(0, v); sa->push(s); Expression *e = new IdentifierExp(0, id); e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); diff --git a/dmd2/idgen.c b/dmd2/idgen.c index bbd3213e..df8230c6 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -302,6 +302,7 @@ Msgtable msgtable[] = // Builtin functions { "std" }, + { "core" }, { "math" }, { "sin" }, { "cos" }, @@ -329,6 +330,7 @@ Msgtable msgtable[] = { "isLazy" }, { "hasMember" }, { "identifier" }, + { "parent" }, { "getMember" }, { "getOverloads" }, { "getVirtualFunctions" }, diff --git a/dmd2/init.c b/dmd2/init.c index a71e7e47..3b81f27b 100644 --- a/dmd2/init.c +++ b/dmd2/init.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -34,7 +34,7 @@ Initializer *Initializer::syntaxCopy() return this; } -Initializer *Initializer::semantic(Scope *sc, Type *t) +Initializer *Initializer::semantic(Scope *sc, Type *t, int needInterpret) { return this; } @@ -87,7 +87,7 @@ Initializer *VoidInitializer::syntaxCopy() } -Initializer *VoidInitializer::semantic(Scope *sc, Type *t) +Initializer *VoidInitializer::semantic(Scope *sc, Type *t, int needInterpret) { //printf("VoidInitializer::semantic(t = %p)\n", t); type = t; @@ -141,7 +141,7 @@ void StructInitializer::addInit(Identifier *field, Initializer *value) this->value.push(value); } -Initializer *StructInitializer::semantic(Scope *sc, Type *t) +Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) { int errors = 0; @@ -168,6 +168,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) { if (fieldi >= ad->fields.dim) { error(loc, "too many initializers for %s", ad->toChars()); + errors = 1; field.remove(i); i--; continue; @@ -184,6 +185,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) if (!s) { error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); + errors = 1; continue; } @@ -192,7 +194,9 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) { if (fieldi >= ad->fields.dim) { - s->error("is not a per-instance initializable field"); + error(loc, "%s.%s is not a per-instance initializable field", + t->toChars(), s->toChars()); + errors = 1; break; } if (s == (Dsymbol *)ad->fields.data[fieldi]) @@ -201,7 +205,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) } if (s && (v = s->isVarDeclaration()) != NULL) { - val = val->semantic(sc, v->type); + val = val->semantic(sc, v->type, needInterpret); value.data[i] = (void *)val; vars.data[i] = (void *)v; } @@ -222,7 +226,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) fd->endloc = loc; Expression *e = new FuncExp(loc, fd); ExpInitializer *ie = new ExpInitializer(loc, e); - return ie->semantic(sc, t); + return ie->semantic(sc, t, needInterpret); } else { @@ -238,7 +242,6 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) return this; } - /*************************************** * This works by transforming a struct initializer into * a struct literal. In the future, the two should be the @@ -246,6 +249,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t) */ Expression *StructInitializer::toExpression() { Expression *e; + size_t offset; //printf("StructInitializer::toExpression() %s\n", toChars()); if (!ad) // if fwd referenced @@ -256,17 +260,110 @@ Expression *StructInitializer::toExpression() if (!sd) return NULL; Expressions *elements = new Expressions(); - for (size_t i = 0; i < value.dim; i++) + elements->setDim(ad->fields.dim); + for (int i = 0; i < elements->dim; i++) { - if (field.data[i]) + elements->data[i] = NULL; + } + unsigned fieldi = 0; + for (int i = 0; i < value.dim; i++) + { + Identifier *id = (Identifier *)field.data[i]; + if (id) + { + Dsymbol * s = ad->search(loc, id, 0); + if (!s) + { + error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); + goto Lno; + } + + // Find out which field index it is + for (fieldi = 0; 1; fieldi++) + { + if (fieldi >= ad->fields.dim) + { + s->error("is not a per-instance initializable field"); + goto Lno; + } + if (s == (Dsymbol *)ad->fields.data[fieldi]) + break; + } + } + else if (fieldi >= ad->fields.dim) + { error(loc, "too many initializers for '%s'", ad->toChars()); goto Lno; + } Initializer *iz = (Initializer *)value.data[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); if (!ex) goto Lno; - elements->push(ex); + if (elements->data[fieldi]) + { error(loc, "duplicate initializer for field '%s'", + ((Dsymbol *)ad->fields.data[fieldi])->toChars()); + goto Lno; + } + elements->data[fieldi] = ex; + ++fieldi; + } + // Now, fill in any missing elements with default initializers. + // We also need to validate any anonymous unions + offset = 0; + for (int i = 0; i < elements->dim; ) + { + VarDeclaration * vd = ((Dsymbol *)ad->fields.data[i])->isVarDeclaration(); + + //printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset); + if (vd->offset < offset) + { + // Only the first field of a union can have an initializer + if (elements->data[i]) + goto Lno; + } + else + { + if (!elements->data[i]) + // Default initialize + elements->data[i] = vd->type->defaultInit(); + } + offset = vd->offset + vd->type->size(); + i++; +#if 0 + int unionSize = ad->numFieldsInUnion(i); + if (unionSize == 1) + { // Not a union -- default initialize if missing + if (!elements->data[i]) + elements->data[i] = vd->type->defaultInit(); + } + else + { // anonymous union -- check for errors + int found = -1; // index of the first field with an initializer + for (int j = i; j < i + unionSize; ++j) + { + if (!elements->data[j]) + continue; + if (found >= 0) + { + VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration(); + VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration(); + error(loc, "%s cannot have initializers for fields %s and %s in same union", + ad->toChars(), + v1->toChars(), v->toChars()); + goto Lno; + } + found = j; + } + if (found == -1) + { + error(loc, "no initializer for union that contains field %s", + vd->toChars()); + goto Lno; + } + } + i += unionSize; +#endif } e = new StructLiteralExp(loc, sd, elements); e->type = sd->type; @@ -274,7 +371,6 @@ Expression *StructInitializer::toExpression() Lno: delete elements; - //error(loc, "struct initializers as expressions are not allowed"); return NULL; } @@ -340,7 +436,7 @@ void ArrayInitializer::addInit(Expression *index, Initializer *value) type = NULL; } -Initializer *ArrayInitializer::semantic(Scope *sc, Type *t) +Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) { unsigned i; unsigned length; const unsigned amax = 0x80000000; @@ -375,7 +471,7 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t) } Initializer *val = (Initializer *)value.data[i]; - val = val->semantic(sc, t->nextOf()); + val = val->semantic(sc, t->nextOf(), needInterpret); value.data[i] = (void *)val; length++; if (length == 0) @@ -630,12 +726,17 @@ Initializer *ExpInitializer::syntaxCopy() return new ExpInitializer(loc, exp->syntaxCopy()); } -Initializer *ExpInitializer::semantic(Scope *sc, Type *t) +Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); + int wantOptimize = needInterpret ? WANTinterpret|WANTvalue : WANTvalue; + + int olderrors = global.errors; + exp = exp->optimize(wantOptimize); + if (!global.gag && olderrors != global.errors) + return this; // Failed, suppress duplicate error messages Type *tb = t->toBasetype(); /* Look for case of initializing a static array with a too-short @@ -668,7 +769,7 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t) exp = exp->implicitCastTo(sc, t); L1: - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->optimize(wantOptimize); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; } diff --git a/dmd2/init.h b/dmd2/init.h index 3ccbf68a..10f8d640 100644 --- a/dmd2/init.h +++ b/dmd2/init.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -36,7 +36,8 @@ struct Initializer : Object Initializer(Loc loc); virtual Initializer *syntaxCopy(); - virtual Initializer *semantic(Scope *sc, Type *t); + // needInterpret is WANTinterpret if must be a manifest constant, 0 if not. + virtual Initializer *semantic(Scope *sc, Type *t, int needInterpret); virtual Type *inferType(Scope *sc); virtual Expression *toExpression() = 0; virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; @@ -60,7 +61,7 @@ struct VoidInitializer : Initializer VoidInitializer(Loc loc); Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t); + Initializer *semantic(Scope *sc, Type *t, int needInterpret); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -82,7 +83,7 @@ struct StructInitializer : Initializer StructInitializer(Loc loc); Initializer *syntaxCopy(); void addInit(Identifier *field, Initializer *value); - Initializer *semantic(Scope *sc, Type *t); + Initializer *semantic(Scope *sc, Type *t, int needInterpret); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -104,7 +105,7 @@ struct ArrayInitializer : Initializer ArrayInitializer(Loc loc); Initializer *syntaxCopy(); void addInit(Expression *index, Initializer *value); - Initializer *semantic(Scope *sc, Type *t); + Initializer *semantic(Scope *sc, Type *t, int needInterpret); int isAssociativeArray(); Type *inferType(Scope *sc); Expression *toExpression(); @@ -125,7 +126,7 @@ struct ExpInitializer : Initializer ExpInitializer(Loc loc, Expression *exp); Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t); + Initializer *semantic(Scope *sc, Type *t, int needInterpret); Type *inferType(Scope *sc); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); diff --git a/dmd2/inline.c b/dmd2/inline.c index 39b3e7fe..75fcac9e 100644 --- a/dmd2/inline.c +++ b/dmd2/inline.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -257,6 +257,9 @@ int DeclarationExp::inlineCost(InlineCostState *ics) return COST_MAX; cost += 1; + if (vd->edtor) // if destructor required + return COST_MAX; // needs work to make this work + // Scan initializer (vd->init) if (vd->init) { @@ -685,7 +688,7 @@ Expression *IndexExp::doInline(InlineDoState *ids) ids->from.push(vd); ids->to.push(vto); - if (vd->init) + if (vd->init && !vd->init->isVoidInitializer()) { ie = vd->init->isExpInitializer(); assert(ie); @@ -724,7 +727,7 @@ Expression *SliceExp::doInline(InlineDoState *ids) ids->from.push(vd); ids->to.push(vto); - if (vd->init) + if (vd->init && !vd->init->isVoidInitializer()) { ie = vd->init->isExpInitializer(); assert(ie); diff --git a/dmd2/interpret.c b/dmd2/interpret.c index 34375018..25035d49 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -1,5 +1,5 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -52,9 +52,8 @@ Expression *interpret_length(InterState *istate, Expression *earg); Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration *fd); Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclaration *fd); -ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, Expression *elem, size_t dim); Expression * resolveReferences(Expression *e, Expression *thisval, bool *isReference = NULL); -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d); +Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal); VarDeclaration *findParentVar(Expression *e, Expression *thisval); /************************************* @@ -100,8 +99,9 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument if (semanticRun < PASSsemantic3 && scope) { + int olderrors = global.errors; semantic3(scope); - if (global.errors) // if errors compiling this function + if (olderrors != global.errors) // if errors compiling this function return NULL; } if (semanticRun < PASSsemantic3done) @@ -187,7 +187,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument { Expression *earg = (Expression *)eargs.data[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - vsave.data[i] = v->value; + vsave.data[i] = v->getValue(); #if LOG printf("arg[%d] = %s\n", i, earg->toChars()); #endif @@ -199,7 +199,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument { cantInterpret = 1; return NULL; } - v->value = earg; + v->setValueWithoutChecking(earg); /* Don't restore the value of v2 upon function return */ assert(istate); @@ -213,7 +213,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument } else { // Value parameters and non-trivial references - v->value = earg; + v->setValueWithoutChecking(earg); } #if LOG printf("interpreted arg[%d] = %s\n", i, earg->toChars()); @@ -247,8 +247,8 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument if (v) { //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); - valueSaves.data[i] = v->value; - v->value = NULL; + valueSaves.data[i] = v->getValue(); + v->setValueNull(); } } } @@ -279,12 +279,13 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument else break; } + /* Restore the parameter values */ for (size_t i = 0; i < dim; i++) { VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - v->value = (Expression *)vsave.data[i]; + v->setValueWithoutChecking((Expression *)vsave.data[i]); } if (istate && !isNested()) @@ -295,8 +296,8 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument 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() : ""); + { v->setValueWithoutChecking((Expression *)valueSaves.data[i]); + //printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->getValue() ? v->getValue()->toChars() : ""); } } } @@ -338,7 +339,7 @@ Expression *ExpStatement::interpret(InterState *istate) START() if (exp) { - Expression *e = exp->interpret(istate); + Expression *e = exp->interpret(istate, ctfeNeedNothing); if (e == EXP_CANT_INTERPRET) { //printf("-ExpStatement::interpret(): %p\n", e); @@ -470,8 +471,8 @@ Expression * replaceReturnReference(Expression *original, InterState *istate) { VarExp *ve = (VarExp *)e; VarDeclaration *v = ve->var->isVarDeclaration(); - assert (v && v->value); - return v->value; + assert (v && v->getValue()); + return v->getValue(); } if (e->op == TOKthis) @@ -499,15 +500,18 @@ Expression * replaceReturnReference(Expression *original, InterState *istate) if (next->op == TOKcall) { + bool oldWaiting = istate->awaitingLvalueReturn; istate->awaitingLvalueReturn = true; next = next->interpret(istate); - if (next == EXP_CANT_INTERPRET) return next; + istate->awaitingLvalueReturn = oldWaiting; + if (next == EXP_CANT_INTERPRET) + return next; } if (next->op == TOKvar) { VarDeclaration * v = ((VarExp*)next)->var->isVarDeclaration(); if (v) - next = v->value; + next = v->getValue(); } else if (next->op == TOKthis) next = istate->localThis; @@ -518,14 +522,34 @@ Expression * replaceReturnReference(Expression *original, InterState *istate) old = next; } if (e->op == TOKindex) + { // The index needs to be evaluated now (it isn't part of the ref) ((IndexExp*)e)->e1 = next; + ((IndexExp*)e)->e2 = ((IndexExp*)e)->e2->interpret(istate); + if (((IndexExp*)e)->e2 == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } else if (e->op == TOKdotvar) ((DotVarExp *)e)->e1 = next; else if (e->op == TOKdotti) ((DotTemplateInstanceExp *)e)->e1 = next; else if (e->op == TOKslice) + { /* Interpret the slice bounds immediately (they are + * not part of the reference). + */ ((SliceExp*)e)->e1 = next; - + Expression *x = ((SliceExp*)e)->upr; + if (x) + x = x->interpret(istate); + if (x == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + ((SliceExp*)e)->upr = x; + x = ((SliceExp*)e)->lwr; + if (x) + x = x->interpret(istate); + if (x == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + ((SliceExp*)e)->lwr = x; + } if (old != next) break; e = next; @@ -1114,7 +1138,7 @@ Expression *AsmStatement::interpret(InterState *istate) /******************************** Expression ***************************/ -Expression *Expression::interpret(InterState *istate) +Expression *Expression::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("Expression::interpret() %s\n", toChars()); @@ -1125,7 +1149,7 @@ Expression *Expression::interpret(InterState *istate) return EXP_CANT_INTERPRET; } -Expression *ThisExp::interpret(InterState *istate) +Expression *ThisExp::interpret(InterState *istate, CtfeGoal goal) { if (istate && istate->localThis) return istate->localThis->interpret(istate); @@ -1133,12 +1157,12 @@ Expression *ThisExp::interpret(InterState *istate) return EXP_CANT_INTERPRET; } -Expression *NullExp::interpret(InterState *istate) +Expression *NullExp::interpret(InterState *istate, CtfeGoal goal) { return this; } -Expression *IntegerExp::interpret(InterState *istate) +Expression *IntegerExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("IntegerExp::interpret() %s\n", toChars()); @@ -1146,7 +1170,7 @@ Expression *IntegerExp::interpret(InterState *istate) return this; } -Expression *RealExp::interpret(InterState *istate) +Expression *RealExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("RealExp::interpret() %s\n", toChars()); @@ -1154,12 +1178,12 @@ Expression *RealExp::interpret(InterState *istate) return this; } -Expression *ComplexExp::interpret(InterState *istate) +Expression *ComplexExp::interpret(InterState *istate, CtfeGoal goal) { return this; } -Expression *StringExp::interpret(InterState *istate) +Expression *StringExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("StringExp::interpret() %s\n", toChars()); @@ -1167,7 +1191,7 @@ Expression *StringExp::interpret(InterState *istate) return this; } -Expression *FuncExp::interpret(InterState *istate) +Expression *FuncExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("FuncExp::interpret() %s\n", toChars()); @@ -1175,7 +1199,7 @@ Expression *FuncExp::interpret(InterState *istate) return this; } -Expression *SymOffExp::interpret(InterState *istate) +Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("SymOffExp::interpret() %s\n", toChars()); @@ -1188,7 +1212,7 @@ Expression *SymOffExp::interpret(InterState *istate) return EXP_CANT_INTERPRET; } -Expression *DelegateExp::interpret(InterState *istate) +Expression *DelegateExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("DelegateExp::interpret() %s\n", toChars()); @@ -1198,10 +1222,10 @@ Expression *DelegateExp::interpret(InterState *istate) #if IN_LLVM -Expression *AddrExp::interpret(InterState *istate) +Expression *AddrExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG - printf("AddrExpExp::interpret() %s\n", toChars()); + printf("AddrExp::interpret() %s\n", toChars()); #endif if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; @@ -1239,25 +1263,33 @@ Expression * resolveReferences(Expression *e, Expression *thisval, bool *isRefer // Chase down rebinding of out and ref. VarExp *ve = (VarExp *)e; VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && v->value && v->value->op == TOKvar) // it's probably a reference + if (v && v->getValue() && v->getValue()->op == TOKvar) // it's probably a reference { // Make sure it's a real reference. // It's not a reference if v is a struct initialized to // 0 using an __initZ StaticStructInitDeclaration from // TypeStruct::defaultInit() - VarExp *ve2 = (VarExp *)v->value; + VarExp *ve2 = (VarExp *)v->getValue(); if (!ve2->var->isStaticStructInitDeclaration()) { if (isReference) *isReference = true; - e = v->value; + e = v->getValue(); continue; } } - else if (v && v->value && (v->value->op==TOKindex || v->value->op == TOKdotvar - || v->value->op == TOKthis || v->value->op == TOKslice )) + else if (v && v->getValue() && (v->getValue()->op == TOKslice)) { - e = v->value; + SliceExp *se = (SliceExp *)v->getValue(); + if (se->e1->op == TOKarrayliteral || se->e1->op == TOKassocarrayliteral || se->e1->op == TOKstring) + break; + e = v->getValue(); + continue; + } + else if (v && v->getValue() && (v->getValue()->op==TOKindex || v->getValue()->op == TOKdotvar + || v->getValue()->op == TOKthis )) + { + e = v->getValue(); continue; } } @@ -1266,7 +1298,7 @@ Expression * resolveReferences(Expression *e, Expression *thisval, bool *isRefer return e; } -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) +Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal) { Expression *e = EXP_CANT_INTERPRET; VarDeclaration *v = d->isVarDeclaration(); @@ -1282,17 +1314,34 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) */ if (v->ident == Id::ctfe) return new IntegerExp(loc, 1, Type::tbool); - if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && v->init && !v->value) + if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && v->init && !v->getValue()) #else if (v->isConst() && v->init) #endif { e = v->init->toExpression(); - if (e && !e->type) + if (e && (e->op == TOKconstruct || e->op == TOKblit)) + { AssignExp *ae = (AssignExp *)e; + e = ae->e2; + v->inuse++; + e = e->interpret(istate, ctfeNeedAnyValue); + v->inuse--; + if (e == EXP_CANT_INTERPRET) + return e; e->type = v->type; + } + else + { + if (e && !e->type) + e->type = v->type; + if (e) + e = e->interpret(istate, ctfeNeedAnyValue); + } + if (e && e != EXP_CANT_INTERPRET) + v->setValueWithoutChecking(e); } - else if ((v->isCTFE() || (!v->isDataseg() && istate)) && !v->value) + else if ((v->isCTFE() || (!v->isDataseg() && istate)) && !v->getValue()) { - if (v->init) + if (v->init && v->type->size() != 0) { if (v->init->isVoidInitializer()) { @@ -1310,37 +1359,65 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) return EXP_CANT_INTERPRET; } else - { e = v->value; - if (!v->isCTFE() && v->isDataseg()) + { e = v->getValue(); + if (!e && !v->isCTFE() && v->isDataseg()) { error(loc, "static variable %s cannot be read at compile time", v->toChars()); e = EXP_CANT_INTERPRET; } else if (!e) error(loc, "variable %s is used before initialization", v->toChars()); - else if (e != EXP_CANT_INTERPRET) - e = e->interpret(istate); + else if (e == EXP_CANT_INTERPRET) + return e; + else if (goal == ctfeNeedLvalue && (e->op == TOKstring || e->op == TOKslice || + e->op == TOKstructliteral || e->op == TOKarrayliteral || + e->op == TOKassocarrayliteral)) + return e; // it's already an Lvalue + else + e = e->interpret(istate, goal); } if (!e) e = EXP_CANT_INTERPRET; } else if (s) { - Expressions *exps = new Expressions(); - e = new StructLiteralExp(0, s->dsym, exps); - e = e->semantic(NULL); +#if !IN_LLVM + // Struct static initializers, for example + if (s->dsym->toInitializer() == s->sym) + { +#endif + Expressions *exps = new Expressions(); + e = new StructLiteralExp(loc, s->dsym, exps); + e = e->semantic(NULL); + if (e->op == TOKerror) + e = EXP_CANT_INTERPRET; +#if !IN_LLVM + } + else + error(loc, "cannot interpret symbol %s at compile time", v->toChars()); +#endif } + else + error(loc, "cannot interpret variable %s at compile time", v->toChars()); return e; } -Expression *VarExp::interpret(InterState *istate) +Expression *VarExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("VarExp::interpret() %s\n", toChars()); #endif - return getVarExp(loc, istate, var); + Expression *e = getVarExp(loc, istate, var, goal); + // A VarExp may include an implicit cast. It must be done explicitly. + if (e != EXP_CANT_INTERPRET && e->type != type + && e->implicitConvTo(type) == MATCHexact) + { + e = e->implicitCastTo(0, type); + e = e->interpret(istate, goal); + } + return e; } -Expression *DeclarationExp::interpret(InterState *istate) +Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("DeclarationExp::interpret() %s\n", toChars()); @@ -1363,6 +1440,10 @@ Expression *DeclarationExp::interpret(InterState *istate) e = EXP_CANT_INTERPRET; } } + else if (s == v && !v->init && v->type->size()==0) + { // Zero-length arrays don't need an initializer + e = v->type->defaultInitLiteral(loc); + } #if DMDV2 else if (s == v && (v->isConst() || v->isImmutable()) && v->init) #else @@ -1399,7 +1480,7 @@ Expression *DeclarationExp::interpret(InterState *istate) return e; } -Expression *TupleExp::interpret(InterState *istate) +Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("TupleExp::interpret() %s\n", toChars()); @@ -1440,7 +1521,7 @@ Expression *TupleExp::interpret(InterState *istate) return this; } -Expression *ArrayLiteralExp::interpret(InterState *istate) +Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) { Expressions *expsx = NULL; #if LOG @@ -1490,7 +1571,7 @@ Lerror: return EXP_CANT_INTERPRET; } -Expression *AssocArrayLiteralExp::interpret(InterState *istate) +Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) { Expressions *keysx = keys; Expressions *valuesx = values; @@ -1577,7 +1658,7 @@ Lerr: return EXP_CANT_INTERPRET; } -Expression *StructLiteralExp::interpret(InterState *istate) +Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) { Expressions *expsx = NULL; #if LOG @@ -1586,8 +1667,8 @@ Expression *StructLiteralExp::interpret(InterState *istate) /* We don't know how to deal with overlapping fields */ if (sd->hasUnions) - { error("Unions with overlapping fields are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; + { error("Unions with overlapping fields are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; } if (elements) @@ -1633,7 +1714,47 @@ Expression *StructLiteralExp::interpret(InterState *istate) return this; } -Expression *NewExp::interpret(InterState *istate) +/****************************** + * Helper for NewExp + * Create an array literal consisting of 'elem' duplicated 'dim' times. + */ +ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, + Expression *elem, size_t dim) +{ + Expressions *elements = new Expressions(); + elements->setDim(dim); + for (size_t i = 0; i < dim; i++) + elements->data[i] = elem; + ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); + ae->type = type; + return ae; +} + +/****************************** + * Helper for NewExp + * Create a string literal consisting of 'value' duplicated 'dim' times. + */ +StringExp *createBlockDuplicatedStringLiteral(Type *type, + unsigned value, size_t dim, int sz) +{ + unsigned char *s; + s = (unsigned char *)mem.calloc(dim + 1, sz); + for (int elemi=0; elemitype = type; + return se; +} + +Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("NewExp::interpret() %s\n", toChars()); @@ -1647,11 +1768,16 @@ Expression *NewExp::interpret(InterState *istate) ((TypeArray *)newtype)->next->defaultInitLiteral(), lenExpr->toInteger()); } + if (newtype->ty == Tclass) + { + error("classes are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; + } error("Cannot interpret %s at compile time", toChars()); return EXP_CANT_INTERPRET; } -Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)) +Expression *UnaExp::interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *)) { Expression *e; Expression *e1; @@ -1672,9 +1798,9 @@ Lcant: } #define UNA_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon(istate, &op); \ +Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ +{ \ + return interpretCommon(istate, goal, &op); \ } UNA_INTERPRET(Neg) @@ -1685,7 +1811,7 @@ UNA_INTERPRET(Bool) typedef Expression *(*fp_t)(Type *, Expression *, Expression *); -Expression *BinExp::interpretCommon(InterState *istate, fp_t fp) +Expression *BinExp::interpretCommon(InterState *istate, CtfeGoal goal, fp_t fp) { Expression *e; Expression *e1; Expression *e2; @@ -1713,9 +1839,9 @@ Lcant: } #define BIN_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon(istate, &op); \ +Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ +{ \ + return interpretCommon(istate, goal, &op); \ } BIN_INTERPRET(Add) @@ -1733,7 +1859,7 @@ BIN_INTERPRET(Xor) typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); -Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) +Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp) { Expression *e; Expression *e1; Expression *e2; @@ -1749,7 +1875,10 @@ Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) e1->op != TOKstring && e1->op != TOKarrayliteral && e1->op != TOKstructliteral) + { + error("cannot compare %s at compile time", e1->toChars()); goto Lcant; + } e2 = this->e2->interpret(istate); if (e2 == EXP_CANT_INTERPRET) @@ -1759,7 +1888,10 @@ Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) e2->op != TOKstring && e2->op != TOKarrayliteral && e2->op != TOKstructliteral) + { + error("cannot compare %s at compile time", e2->toChars()); goto Lcant; + } e = (*fp)(op, type, e1, e2); return e; @@ -1769,9 +1901,9 @@ Lcant: } #define BIN_INTERPRET2(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon2(istate, &op); \ +Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ +{ \ + return interpretCommon2(istate, goal, &op); \ } BIN_INTERPRET2(Equal) @@ -1798,82 +1930,6 @@ Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, void return expsx; } -/*************************************** - * Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint+newelems.length..$] - */ -Expressions *spliceElements(Expressions *oldelems, - Expressions *newelems, size_t insertpoint) -{ - Expressions *expsx = new Expressions(); - expsx->setDim(oldelems->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j >= insertpoint && j < insertpoint + newelems->dim) - expsx->data[j] = newelems->data[j - insertpoint]; - else - expsx->data[j] = oldelems->data[j]; - } - return expsx; -} - -/*************************************** - * Returns oldstr[0..insertpoint] ~ newstr ~ oldstr[insertpoint+newlen..$] - */ -StringExp *spliceStringExp(StringExp *oldstr, StringExp *newstr, size_t insertpoint) -{ - assert(oldstr->sz==newstr->sz); - unsigned char *s; - size_t oldlen = oldstr->len; - size_t newlen = newstr->len; - size_t sz = oldstr->sz; - s = (unsigned char *)mem.calloc(oldlen + 1, sz); - memcpy(s, oldstr->string, oldlen * sz); - memcpy(s + insertpoint * sz, newstr->string, newlen * sz); - StringExp *se2 = new StringExp(oldstr->loc, s, oldlen); - se2->committed = oldstr->committed; - se2->postfix = oldstr->postfix; - se2->type = oldstr->type; - return se2; -} - -/****************************** - * Create an array literal consisting of 'elem' duplicated 'dim' times. - */ -ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, - Expression *elem, size_t dim) -{ - Expressions *elements = new Expressions(); - elements->setDim(dim); - for (size_t i = 0; i < dim; i++) - elements->data[i] = elem; - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); - ae->type = type; - return ae; -} - -/****************************** - * Create a string literal consisting of 'value' duplicated 'dim' times. - */ -StringExp *createBlockDuplicatedStringLiteral(Type *type, - unsigned value, size_t dim, int sz) -{ - unsigned char *s; - s = (unsigned char *)mem.calloc(dim + 1, sz); - for (int elemi=0; elemitype = type; - return se; -} - /******************************** * Add v to the istate list, unless it already exists there. */ @@ -1913,96 +1969,30 @@ Expression * modifyStructField(Type *type, StructLiteralExp *se, size_t offset, * set arr[index] = newval and return the new array. * */ -Expression * assignArrayElement(Loc loc, Expression *arr, Expression *index, Expression *newval) +Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae, Expression *index, Expression *newval) { - ArrayLiteralExp *ae = NULL; - AssocArrayLiteralExp *aae = NULL; - StringExp *se = NULL; - if (arr->op == TOKarrayliteral) - ae = (ArrayLiteralExp *)arr; - else if (arr->op == TOKassocarrayliteral) - aae = (AssocArrayLiteralExp *)arr; - else if (arr->op == TOKstring) - se = (StringExp *)arr; - else assert(0); - - if (ae) - { - int elemi = index->toInteger(); - if (elemi >= ae->elements->dim) - { - error(loc, "array index %d is out of bounds %s[0..%d]", elemi, - arr->toChars(), ae->elements->dim); - return EXP_CANT_INTERPRET; - } - // Create new array literal reflecting updated elem - Expressions *expsx = changeOneElement(ae->elements, elemi, newval); - Expression *ee = new ArrayLiteralExp(ae->loc, expsx); - ee->type = ae->type; - newval = ee; + /* Create new associative array literal reflecting updated key/value + */ + Expressions *keysx = aae->keys; + Expressions *valuesx = aae->values; + int updated = 0; + for (size_t j = valuesx->dim; j; ) + { j--; + Expression *ekey = (Expression *)aae->keys->data[j]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, index); + if (ex == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + if (ex->isBool(TRUE)) + { valuesx->data[j] = (void *)newval; + updated = 1; } - else if (se) - { - /* Create new string literal reflecting updated elem - */ - int elemi = index->toInteger(); - if (elemi >= se->len) - { - error(loc, "array index %d is out of bounds %s[0..%d]", elemi, - arr->toChars(), se->len); - return EXP_CANT_INTERPRET; - } - unsigned char *s; - s = (unsigned char *)mem.calloc(se->len + 1, se->sz); - memcpy(s, se->string, se->len * se->sz); - unsigned value = newval->toInteger(); - switch (se->sz) - { - case 1: s[elemi] = value; break; - case 2: ((unsigned short *)s)[elemi] = value; break; - case 4: ((unsigned *)s)[elemi] = value; break; - default: - assert(0); - break; - } - StringExp *se2 = new StringExp(se->loc, s, se->len); - se2->committed = se->committed; - se2->postfix = se->postfix; - se2->type = se->type; - newval = se2; - } - else if (aae) - { - /* Create new associative array literal reflecting updated key/value - */ - Expressions *keysx = aae->keys; - Expressions *valuesx = new Expressions(); - valuesx->setDim(aae->values->dim); - 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 *)newval; - updated = 1; - } - else - valuesx->data[j] = aae->values->data[j]; - } - if (!updated) - { // Append index/newval to keysx[]/valuesx[] - valuesx->push(newval); - keysx = (Expressions *)keysx->copy(); - keysx->push(index); - } - Expression *aae2 = new AssocArrayLiteralExp(aae->loc, keysx, valuesx); - aae2->type = aae->type; - return aae2; - } - return newval; + } + if (!updated) + { // Append index/newval to keysx[]/valuesx[] + valuesx->push(newval); + keysx->push(index); + } + return newval; } // Return true if e is derived from UnaryExp. @@ -2146,8 +2136,142 @@ Expression *assignDotVar(ExpressionReverseIterator rvs, int depth, Expression *e return NULL; } +// Given expr, which evaluates to an array/AA/string literal, +// return true if it needs to be copied +bool needToCopyLiteral(Expression *expr) +{ + for (;;) + { + switch (expr->op) + { + case TOKarrayliteral: + case TOKassocarrayliteral: + case TOKstring: + case TOKstructliteral: + return true; + case TOKthis: + case TOKvar: + return false; + case TOKassign: + return false; + case TOKindex: + case TOKdotvar: + case TOKslice: + case TOKcast: + expr = ((UnaExp *)expr)->e1; + continue; + case TOKcat: + case TOKcatass: + return false; + case TOKcall: + // TODO: Return statement should + // guarantee we never return a naked literal, but + // currently it doesn't. + return true; -Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) + // There are probably other cases which don't need + // a copy. But for now, we conservatively copy all + // other cases. + default: + return true; + } + } +} + + +// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral. +// This value will be used for in-place modification. +Expression *copyLiteral(Expression *e) +{ + if (e->op == TOKstring) // syntaxCopy doesn't make a copy for StringExp! + { + StringExp *se = (StringExp *)e; + unsigned char *s; + s = (unsigned char *)mem.calloc(se->len + 1, se->sz); + memcpy(s, se->string, se->len * se->sz); + StringExp *se2 = new StringExp(se->loc, s, se->len); + se2->committed = se->committed; + se2->postfix = se->postfix; + se2->type = se->type; + se2->sz = se->sz; + return se2; + } + else if (e->op == TOKarrayliteral) + { + ArrayLiteralExp *ae = (ArrayLiteralExp *)e; + Expressions *oldelems = ae->elements; + Expressions *newelems = new Expressions(); + newelems->setDim(oldelems->dim); + for (size_t i = 0; i < oldelems->dim; i++) + newelems->data[i] = copyLiteral((Expression *)(oldelems->data[i])); + ArrayLiteralExp *r = new ArrayLiteralExp(ae->loc, newelems); + r->type = e->type; + return r; + } + /* syntaxCopy doesn't work for struct literals, because of a nasty special + * case: block assignment is permitted inside struct literals, eg, + * an int[4] array can be initialized with a single int. + */ + else if (e->op == TOKstructliteral) + { + StructLiteralExp *se = (StructLiteralExp *)e; + Expressions *oldelems = se->elements; + Expressions * newelems = new Expressions(); + newelems->setDim(oldelems->dim); + for (size_t i = 0; i < newelems->dim; i++) + { + Expression *m = (Expression *)oldelems->data[i]; + // We need the struct definition to detect block assignment + StructDeclaration *sd = se->sd; + Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + if ((v->type->ty != m->type->ty) && v->type->ty == Tsarray) + { + // Block assignment from inside struct literals + TypeSArray *tsa = (TypeSArray *)v->type; + uinteger_t length = tsa->dim->toInteger(); + + m = createBlockDuplicatedArrayLiteral(v->type, m, length); + } else m = copyLiteral(m); + newelems->data[i] = m; + } +#if DMDV2 + StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems, se->stype); +#else + StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems); +#endif + r->type = e->type; + return r; + } + + Expression *r = e->syntaxCopy(); + r->type = e->type; + return r; +} + +void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val) +{ + assert( ae->type->ty == Tsarray || ae->type->ty == Tarray); +#if DMDV2 + Type *desttype = ((TypeArray *)ae->type)->next->castMod(0); + bool directblk = (val->type->toBasetype()->castMod(0)) == desttype; +#else + Type *desttype = ((TypeArray *)ae->type)->next; + bool directblk = (val->type->toBasetype()) == desttype; +#endif + for (size_t k = 0; k < ae->elements->dim; k++) + { + if (!directblk && ((Expression *)(ae->elements->data[k]))->op == TOKarrayliteral) + { + recursiveBlockAssign((ArrayLiteralExp *)(ae->elements->data[k]), val); + } + else ae->elements->data[k] = val; + } +} + + +Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_t fp, int post) { #if LOG printf("BinExp::interpretAssignCommon() %s\n", toChars()); @@ -2159,6 +2283,72 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) error("value of %s is not known at compile time", e1->toChars()); return e; } + /* Before we begin, we need to know if this is a reference assignment + * (dynamic array, AA, or class) or a value assignment. + * Determining this for slice assignments are tricky: we need to know + * if it is a block assignment (a[] = e) rather than a direct slice + * assignment (a[] = b[]). Note that initializers of multi-dimensional + * static arrays can have 2D block assignments (eg, int[7][7] x = 6;). + * So we need to recurse to determine if it is a block assignment. + */ + bool isBlockAssignment = false; + if (e1->op == TOKslice) + { + // a[] = e can have const e. So we compare the naked types. + Type *desttype = e1->type->toBasetype(); +#if DMDV2 + Type *srctype = e2->type->toBasetype()->castMod(0); +#else + Type *srctype = e2->type->toBasetype(); +#endif + while ( desttype->ty == Tsarray || desttype->ty == Tarray) + { + desttype = ((TypeArray *)desttype)->next; +#if DMDV2 + if (srctype == desttype->castMod(0)) +#else + if (srctype == desttype) +#endif + { + isBlockAssignment = true; + break; + } + } + } + bool wantRef = false; + if (!fp && this->e1->type->toBasetype() == this->e2->type->toBasetype() && + (e1->type->toBasetype()->ty == Tarray || e1->type->toBasetype()->ty == Taarray || + e1->type->toBasetype()->ty == Tclass) + ) + { +#if DMDV2 + wantRef = true; +#else + /* D1 doesn't have const in the type system. But there is still a + * vestigal const in the form of static const variables. + * Problematic code like: + * const int [] x = [1,2,3]; + * int [] y = x; + * can be dealt with by making this a non-ref assign (y = x.dup). + * Otherwise it's a big mess. + */ + VarDeclaration * targetVar = findParentVar(e2, istate->localThis); + if (!(targetVar && targetVar->isConst())) + wantRef = true; +#endif + } + if (isBlockAssignment && (e2->type->toBasetype()->ty == Tarray || e2->type->toBasetype()->ty == Tsarray)) + { + wantRef = true; + } + /* This happens inside compiler-generated foreach statements. + * It's another case where we need a reference + * Note that a similar case, where e2 = 'this', occurs in + * construction of a struct with an invariant(). + */ + if (op==TOKconstruct && this->e1->op==TOKvar && this->e2->op != TOKthis + && ((VarExp*)this->e1)->var->storage_class & STCref) + wantRef = true; if (fp) { @@ -2170,7 +2360,33 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) if (e1 == EXP_CANT_INTERPRET) return e1; - assert(istate); + // First, deal with this = e; and call() = e; + if (e1->op == TOKthis) + { + e1 = istate->localThis; + } + if (e1->op == TOKcall) + { + bool oldWaiting = istate->awaitingLvalueReturn; + istate->awaitingLvalueReturn = true; + e1 = e1->interpret(istate); + istate->awaitingLvalueReturn = oldWaiting; + if (e1 == EXP_CANT_INTERPRET) + return e1; + } + + if (!(e1->op == TOKarraylength || e1->op == TOKvar || e1->op == TOKdotvar + || e1->op == TOKindex || e1->op == TOKslice)) + printf("CTFE internal error: unsupported assignment %s\n", toChars()); + assert(e1->op == TOKarraylength || e1->op == TOKvar || e1->op == TOKdotvar + || e1->op == TOKindex || e1->op == TOKslice); + + Expression * newval = NULL; + + if (!wantRef) + newval = this->e2->interpret(istate); + if (newval == EXP_CANT_INTERPRET) + return newval; // ---------------------------------------------------- // Deal with read-modify-write assignments. @@ -2178,9 +2394,6 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) // Also determine the return value (except for slice // assignments, which are more complicated) // ---------------------------------------------------- - Expression * newval = this->e2->interpret(istate); - if (newval == EXP_CANT_INTERPRET) - return newval; if (fp || e1->op == TOKarraylength) { @@ -2257,7 +2470,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) } } - else if (e1->op != TOKslice) + else if (!wantRef && e1->op != TOKslice) { /* Look for special case of struct being initialized with 0. */ if (type->toBasetype()->ty == Tstruct && newval->op == TOKint64) @@ -2283,12 +2496,13 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) } // This happens inside compiler-generated foreach statements. - if (op==TOKconstruct && this->e1->op==TOKvar + if (op==TOKconstruct && this->e1->op==TOKvar && this->e2->op != TOKthis && ((VarExp*)this->e1)->var->storage_class & STCref) { //error("assignment to ref variable %s is not yet supported in CTFE", this->toChars()); VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration(); - v->value = e2; + v->setValueNull(); + v->createStackValue(e2); return e2; } bool destinationIsReference = false; @@ -2297,17 +2511,18 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) // Unless we have a simple var assignment, we're // only modifying part of the variable. So we need to make sure // that the parent variable exists. - if (e1->op != TOKvar && ultimateVar && !ultimateVar->value) - ultimateVar->value = ultimateVar->type->defaultInitLiteral(); + if (e1->op != TOKvar && ultimateVar && !ultimateVar->getValue()) + ultimateVar->createRefValue(copyLiteral(ultimateVar->type->defaultInitLiteral())); - // ---------------------------------------- - // Deal with dotvar expressions - // ---------------------------------------- + // ---------------------------------------------------------- + // Deal with dotvar expressions - non-reference types + // ---------------------------------------------------------- // Because structs are not reference types, dotvar expressions can be // collapsed into a single assignment. bool startedWithCall = false; - if (e1->op == TOKcall) startedWithCall = true; - while (e1->op == TOKdotvar || e1->op == TOKcall) + if (e1->op == TOKcall) + startedWithCall = true; + while (!wantRef && (e1->op == TOKdotvar || e1->op == TOKcall)) { ExpressionReverseIterator rvs(e1, istate->localThis); Expression *lastNonDotVar = e1; @@ -2335,7 +2550,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) { VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); - v->value = newval; + v->setRefValue(newval); return e; } assert(newval !=EXP_CANT_INTERPRET); @@ -2356,15 +2571,189 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) } if (e1->op == TOKcall) { - istate->awaitingLvalueReturn = true; - e1 = e1->interpret(istate); - istate->awaitingLvalueReturn = false; + bool oldWaiting = istate->awaitingLvalueReturn; + istate->awaitingLvalueReturn = true; + e1 = e1->interpret(istate); + istate->awaitingLvalueReturn = oldWaiting; - if (e1==EXP_CANT_INTERPRET) return e1; - assert(newval); - assert(newval !=EXP_CANT_INTERPRET); + if (e1 == EXP_CANT_INTERPRET) + return e1; + assert(newval); + assert(newval != EXP_CANT_INTERPRET); } } + // --------------------------------------- + // Deal with reference assignment + // --------------------------------------- + if (wantRef) + { + if (this->e2->op == TOKvar) + newval = this->e2; + else if (this->e2->op==TOKslice) + { + SliceExp * sexp = (SliceExp *)this->e2; + + /* Set the $ variable + */ + Expression *e1val = sexp->e1->interpret(istate); + Expression *dollar; + if (e1val->op == TOKnull) + dollar = new IntegerExp(0, 0, Type::tsize_t); + else + dollar = ArrayLength(Type::tsize_t, e1val); + + if (dollar != EXP_CANT_INTERPRET && sexp->lengthVar) + { + sexp->lengthVar->createStackValue(dollar); + } + Expression *upper = NULL; + Expression *lower = NULL; + if (sexp->upr) + upper = sexp->upr->interpret(istate); + else upper = dollar; + if (sexp->lwr) + lower = sexp->lwr->interpret(istate); + else + lower = new IntegerExp(loc, 0, Type::tsize_t); + if (sexp->lengthVar) + sexp->lengthVar->setValueNull(); // $ is defined only in [L..U] + if (upper == EXP_CANT_INTERPRET || lower == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + // We need the interpreted aggregate, except in the case where it + // was a variable. + if (sexp->e1->op == TOKvar) + e1val = sexp->e1; + newval = new SliceExp(sexp->loc, e1val, lower, upper); + newval->type = sexp->type; + } + else + newval = this->e2->interpret(istate, ctfeNeedLvalue); + if (newval == EXP_CANT_INTERPRET) + return newval; + + if (newval->op == TOKarrayliteral || (newval->op == TOKassocarrayliteral) + || newval->op == TOKstring) + { + if (needToCopyLiteral(this->e2)) + newval = copyLiteral(newval); + } + else if (newval->op == TOKnull) + { // do nothing + } + else if (newval->op == TOKvar) + { + VarExp *vv = (VarExp *)newval; + + VarDeclaration *v2 = vv->var->isVarDeclaration(); + assert(v2 && v2->getValue()); + newval = v2->getValue(); + } + else if ((e1->op == TOKdotvar || e1->op == TOKvar) && newval->op == TOKslice) + { + // This one is interesting because it could be a slice of itself + SliceExp * sexp = (SliceExp *)newval; + Expression *agg = sexp->e1; + dinteger_t newlo = sexp->lwr->toInteger(); + dinteger_t newup = sexp->upr->toInteger(); + if (agg->op == TOKvar) + { + VarExp *vv = (VarExp *)agg; + VarDeclaration *v2 = vv->var->isVarDeclaration(); + assert(v2 && v2->getValue()); + if (v2->getValue()->op == TOKarrayliteral + || v2->getValue()->op == TOKstring) + { + Expression *dollar = ArrayLength(Type::tsize_t, v2->getValue()); + if ((newup < newlo) || (newup > dollar->toInteger())) + { + error("slice [%jd..%jd] exceeds array bounds [0..%jd]", + newlo, newup, dollar->toInteger()); + return EXP_CANT_INTERPRET; + } + sexp->e1 = v2->getValue(); + newval = sexp; + } + else if (v2->getValue()->op == TOKslice) + { + SliceExp *sexpold = (SliceExp *)v2->getValue(); + sexp->e1 = sexpold->e1; + dinteger_t hi = newup + sexpold->lwr->toInteger(); + dinteger_t lo = newlo + sexpold->lwr->toInteger(); + if ((newup < newlo) || (hi > sexpold->upr->toInteger())) + { + error("slice [%jd..%jd] exceeds array bounds [0..%jd]", + newlo, newup, sexpold->upr->toInteger()-sexpold->lwr->toInteger()); + return EXP_CANT_INTERPRET; + } + sexp->lwr = new IntegerExp(loc, lo, Type::tsize_t); + sexp->upr = new IntegerExp(loc, hi, Type::tsize_t); + newval = sexp; + } + else + { + newval = newval->interpret(istate); + if (newval == EXP_CANT_INTERPRET) + return newval; + } + } + else + { + newval = newval->interpret(istate); + if (newval == EXP_CANT_INTERPRET) + return newval; + } + } + if (e1->op == TOKvar || e1->op == TOKdotvar) + { + + assert((newval->op == TOKarrayliteral || + newval->op == TOKassocarrayliteral || + newval->op == TOKstring || + newval->op == TOKslice || + newval->op == TOKnull) ); + if (newval->op == TOKslice) + { + Expression *sss = ((SliceExp *)newval)->e1; + assert(sss->op == TOKarrayliteral || sss->op == TOKstring); + } + } + + if (e1->op == TOKdotvar) + { + Expression *exx = ((DotVarExp *)e1)->e1->interpret(istate); + if (exx == EXP_CANT_INTERPRET) + return exx; + if (exx->op != TOKstructliteral) + { + error("CTFE internal error: Dotvar assignment"); + return EXP_CANT_INTERPRET; + } + StructLiteralExp *se3 = (StructLiteralExp *)exx; + VarDeclaration *vv = ((DotVarExp *)e1)->var->isVarDeclaration(); + if (!vv) + { + error("CTFE internal error: Dotvar assignment"); + return EXP_CANT_INTERPRET; + } + int se_indx = se3->getFieldIndex(e1->type, vv->offset); + se3->elements->data[se_indx] = newval; + // Mark the parent variable as modified + if (!destinationIsReference) + addVarToInterstate(istate, ultimateVar); + return newval; + } + else if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (!destinationIsReference) + addVarToInterstate(istate, v); + v->setValueNull(); + v->createRefValue(newval); + return newval; + } + e = newval; + } /* Assignment to variable of the form: * v = newval @@ -2375,19 +2764,99 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) VarDeclaration *v = ve->var->isVarDeclaration(); if (!destinationIsReference) addVarToInterstate(istate, v); - v->value = newval; + if (e1->type->toBasetype()->ty == Tstruct) + { + // This should be an in-place modification + if (newval->op == TOKstructliteral) + { + v->setValueNull(); + v->createRefValue(copyLiteral(newval)); + } + else v->setRefValue(newval); + } + else + { + if (e1->type->toBasetype()->ty == Tarray || e1->type->toBasetype()->ty == Taarray) + { // arr op= arr + if (!v->getValue()) + v->createRefValue(newval->interpret(istate)); + else v->setRefValue(newval->interpret(istate)); + } + else + { + if (!v->getValue()) // creating a new value + v->createStackValue(newval); + else + v->setStackValue(newval); + } + } } else if (e1->op == TOKindex) { - Expression *aggregate = resolveReferences(((IndexExp *)e1)->e1, istate->localThis); /* Assignment to array element of the form: * aggregate[i] = newval */ + IndexExp *ie = (IndexExp *)e1; + int destarraylen = 0; // not for AAs + + // Set the $ variable, and find the array literal to modify + if (ie->e1->type->toBasetype()->ty != Taarray) + { + Expression *oldval = ie->e1->interpret(istate); + if (oldval->op == TOKnull) + { + error("cannot index null array %s", ie->e1->toChars()); + return EXP_CANT_INTERPRET; + } + Expression *dollar = ArrayLength(Type::tsize_t, oldval); + if (dollar == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + destarraylen = dollar->toInteger(); + if (ie->lengthVar) + ie->lengthVar->createStackValue(dollar); + } + Expression *index = ie->e2->interpret(istate); + if (ie->lengthVar) + ie->lengthVar->setValueNull(); // $ is defined only inside [] + if (index == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + ArrayLiteralExp *existingAE = NULL; + StringExp *existingSE = NULL; + AssocArrayLiteralExp *existingAA = NULL; + + // Set the index to modify (for non-AAs), and check that it is in range + int indexToModify = 0; + if (ie->e1->type->toBasetype()->ty != Taarray) + { + indexToModify = index->toInteger(); + if (indexToModify > destarraylen) + { + error("array index %d is out of bounds [0..%d]", indexToModify, + destarraylen); + return EXP_CANT_INTERPRET; + } + } + + Expression *aggregate = resolveReferences(ie->e1, istate->localThis); + + /* The only possible indexable LValue aggregates are array literals, + * slices of array literals, and AA literals. + */ + + if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || + aggregate->op == TOKslice) + { + aggregate = aggregate->interpret(istate, ctfeNeedLvalue); + if (aggregate == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } if (aggregate->op == TOKvar) - { IndexExp *ie = (IndexExp *)e1; + { VarExp *ve = (VarExp *)aggregate; VarDeclaration *v = ve->var->isVarDeclaration(); - if (v->value->op == TOKnull) + aggregate = v->getValue(); + if (v->getValue()->op == TOKnull) { if (v->type->ty == Taarray) { // Assign to empty associative array @@ -2401,179 +2870,282 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) Expression *aae2 = new AssocArrayLiteralExp(loc, keysx, valuesx); aae2->type = v->type; newval = aae2; - v->value = newval; + v->setRefValue(newval); return e; } // This would be a runtime segfault - error("Cannot index null array %s", v->toChars()); + error("cannot index null array %s", v->toChars()); return EXP_CANT_INTERPRET; } - else if (v->value->op != TOKarrayliteral - && v->value->op != TOKassocarrayliteral - && v->value->op != TOKstring) + } + if (aggregate->op == TOKslice) + { + SliceExp *sexp = (SliceExp *)aggregate; + aggregate = sexp->e1; + Expression *lwr = sexp->lwr->interpret(istate); + indexToModify += lwr->toInteger(); + } + if (aggregate->op == TOKarrayliteral) + existingAE = (ArrayLiteralExp *)aggregate; + else if (aggregate->op == TOKstring) + existingSE = (StringExp *)aggregate; + else if (aggregate->op == TOKassocarrayliteral) + existingAA = (AssocArrayLiteralExp *)aggregate; + else + { + error("CTFE internal compiler error %s", aggregate->toChars()); + return EXP_CANT_INTERPRET; + } + if (existingAE) + { + existingAE->elements->data[indexToModify] = newval; + return e; + } + if (existingSE) + { + unsigned char *s = (unsigned char *)existingSE->string; + unsigned value = newval->toInteger(); + switch (existingSE->sz) { - error("CTFE internal compiler error"); - return EXP_CANT_INTERPRET; + case 1: s[indexToModify] = value; break; + case 2: ((unsigned short *)s)[indexToModify] = value; break; + case 4: ((unsigned *)s)[indexToModify] = value; break; + default: + assert(0); + break; } - // Set the $ variable - Expression *dollar = ArrayLength(Type::tsize_t, v->value); - if (dollar != EXP_CANT_INTERPRET && ie->lengthVar) - ie->lengthVar->value = dollar; - // Determine the index, and check that it's OK. - Expression *index = ie->e2->interpret(istate); - if (index == EXP_CANT_INTERPRET) + return e; + } + else if (existingAA) + { + if (assignAssocArrayElement(loc, existingAA, index, newval) == EXP_CANT_INTERPRET) return EXP_CANT_INTERPRET; - newval = assignArrayElement(loc, v->value, index, newval); - if (newval == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - v->value = newval; return e; } else + { error("Index assignment %s is not yet supported in CTFE ", toChars()); - + return EXP_CANT_INTERPRET; + } + return e; } else if (e1->op == TOKslice) { - Expression *aggregate = resolveReferences(((SliceExp *)e1)->e1, istate->localThis); // ------------------------------ // aggregate[] = newval // aggregate[low..upp] = newval // ------------------------------ - /* Slice assignment, initialization of static arrays - * a[] = e - */ - if (aggregate->op==TOKvar) + SliceExp * sexp = (SliceExp *)e1; + // Set the $ variable + Expression *oldval = sexp->e1->interpret(istate); + if (oldval->op == TOKnull) + { + error("cannot slice null array %s", sexp->e1->toChars()); + return EXP_CANT_INTERPRET; + } + Expression *arraylen = ArrayLength(Type::tsize_t, oldval); + if (arraylen == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + if (sexp->lengthVar) + { + sexp->lengthVar->createStackValue(arraylen); + } + Expression *upper = NULL; + Expression *lower = NULL; + if (sexp->upr) + upper = sexp->upr->interpret(istate); + if (sexp->lwr) + lower = sexp->lwr->interpret(istate); + if (sexp->lengthVar) + sexp->lengthVar->setValueNull(); // $ is defined only in [L..U] + if (upper == EXP_CANT_INTERPRET || lower == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + int dim = arraylen->toInteger(); + int upperbound = upper ? upper->toInteger() : dim; + int lowerbound = lower ? lower->toInteger() : 0; + + if (((int)lowerbound < 0) || (upperbound > dim)) + { + error("Array bounds [0..%d] exceeded in slice [%d..%d]", + dim, lowerbound, upperbound); + return EXP_CANT_INTERPRET; + } + + Expression *aggregate = resolveReferences(((SliceExp *)e1)->e1, istate->localThis); + int firstIndex = lowerbound; + + ArrayLiteralExp *existingAE = NULL; + StringExp *existingSE = NULL; + + /* The only possible slicable LValue aggregates are array literals, + * and slices of array literals. + */ + + if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || + aggregate->op == TOKslice) + { + aggregate = aggregate->interpret(istate, ctfeNeedLvalue); + if (aggregate == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + if (aggregate->op == TOKvar) { - SliceExp * sexp = (SliceExp *)e1; VarExp *ve = (VarExp *)(aggregate); VarDeclaration *v = ve->var->isVarDeclaration(); - /* Set the $ variable - */ - Expression *ee = v->value ? ArrayLength(Type::tsize_t, v->value) - : EXP_CANT_INTERPRET; - if (ee != EXP_CANT_INTERPRET && sexp->lengthVar) - sexp->lengthVar->value = ee; - Expression *upper = NULL; - Expression *lower = NULL; - if (sexp->upr) + aggregate = v->getValue(); + } + if (aggregate->op == TOKslice) + { // Slice of a slice --> change the bounds + SliceExp *sexpold = (SliceExp *)aggregate; + dinteger_t hi = upperbound + sexpold->lwr->toInteger(); + firstIndex = lowerbound + sexpold->lwr->toInteger(); + if (hi > sexpold->upr->toInteger()) { - upper = sexp->upr->interpret(istate); - if (upper == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - } - if (sexp->lwr) - { - lower = sexp->lwr->interpret(istate); - if (lower == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - } - Type *t = v->type->toBasetype(); - size_t dim; - if (t->ty == Tsarray) - dim = ((TypeSArray *)t)->dim->toInteger(); - else if (t->ty == Tarray) - { - if (!v->value || v->value->op == TOKnull) - { - error("cannot assign to null array %s", v->toChars()); - return EXP_CANT_INTERPRET; - } - if (v->value->op == TOKarrayliteral) - dim = ((ArrayLiteralExp *)v->value)->elements->dim; - else if (v->value->op ==TOKstring) - dim = ((StringExp *)v->value)->len; - } - else - { - error("%s cannot be evaluated at compile time", toChars()); + error("slice [%d..%d] exceeds array bounds [0..%jd]", + lowerbound, upperbound, + sexpold->upr->toInteger() - sexpold->lwr->toInteger()); return EXP_CANT_INTERPRET; } - int upperbound = upper ? upper->toInteger() : dim; - int lowerbound = lower ? lower->toInteger() : 0; + aggregate = sexpold->e1; + } + if (aggregate->op==TOKarrayliteral) + existingAE = (ArrayLiteralExp *)aggregate; + else if (aggregate->op==TOKstring) + existingSE = (StringExp *)aggregate; - if (((int)lowerbound < 0) || (upperbound > dim)) - { - error("Array bounds [0..%d] exceeded in slice [%d..%d]", - dim, lowerbound, upperbound); - return EXP_CANT_INTERPRET; - } - // Could either be slice assignment (v[] = e[]), - // or block assignment (v[] = val). - // For the former, we check that the lengths match. - bool isSliceAssignment = (newval->op == TOKarrayliteral) - || (newval->op == TOKstring); - size_t srclen = 0; - if (newval->op == TOKarrayliteral) - srclen = ((ArrayLiteralExp *)newval)->elements->dim; - else if (newval->op == TOKstring) - srclen = ((StringExp *)newval)->len; - if (isSliceAssignment && srclen != (upperbound - lowerbound)) - { - error("Array length mismatch assigning [0..%d] to [%d..%d]", srclen, lowerbound, upperbound); - return e; - } + // For slice assignment, we check that the lengths match. + size_t srclen = 0; if (newval->op == TOKarrayliteral) - { - // Static array assignment from literal - if (upperbound - lowerbound != dim) - { - ArrayLiteralExp *ae = (ArrayLiteralExp *)newval; - ArrayLiteralExp *existing = (ArrayLiteralExp *)v->value; - // value[] = value[0..lower] ~ ae ~ value[upper..$] - existing->elements = spliceElements(existing->elements, ae->elements, lowerbound); - newval = existing; - } - v->value = newval; - return newval; - } + srclen = ((ArrayLiteralExp *)newval)->elements->dim; else if (newval->op == TOKstring) + srclen = ((StringExp *)newval)->len; + if (!isBlockAssignment && srclen != (upperbound - lowerbound)) { - StringExp *se = (StringExp *)newval; - if (upperbound-lowerbound == dim) - v->value = newval; - else + error("Array length mismatch assigning [0..%d] to [%d..%d]", srclen, lowerbound, upperbound); + return EXP_CANT_INTERPRET; + } + + if (!isBlockAssignment && newval->op == TOKarrayliteral && existingAE) + { + Expressions *oldelems = existingAE->elements; + Expressions *newelems = ((ArrayLiteralExp *)newval)->elements; + for (size_t j = 0; j < newelems->dim; j++) { - if (!v->value) - v->value = createBlockDuplicatedStringLiteral(se->type, - se->type->defaultInit()->toInteger(), dim, se->sz); - if (v->value->op==TOKstring) - v->value = spliceStringExp((StringExp *)v->value, se, lowerbound); - else - error("String slice assignment is not yet supported in CTFE"); + oldelems->data[j + firstIndex] = newelems->data[j]; } return newval; } - else if (t->nextOf()->ty == newval->type->ty) + else if (newval->op == TOKstring && existingSE) { - // Static array block assignment - e = createBlockDuplicatedArrayLiteral(v->type, newval, upperbound-lowerbound); - - if (upperbound - lowerbound == dim) - newval = e; - else + StringExp * newstr = (StringExp *)newval; + unsigned char *s = (unsigned char *)existingSE->string; + size_t sz = existingSE->sz; + assert(sz == ((StringExp *)newval)->sz); + memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len); + return newval; + } + else if (newval->op == TOKstring && existingAE) + { /* Mixed slice: it was initialized as an array literal of chars. + * Now a slice of it is being set with a string. + */ + size_t newlen = ((StringExp *)newval)->len; + size_t sz = ((StringExp *)newval)->sz; + unsigned char *s = (unsigned char *)((StringExp *)newval)->string; + Type *elemType = existingAE->type->nextOf(); + for (size_t j = 0; j < newlen; j++) { - ArrayLiteralExp * newarrayval; - // Only modifying part of the array. Must create a new array literal. - // If the existing array is uninitialized (this can only happen - // with static arrays), create it. - if (v->value && v->value->op == TOKarrayliteral) - newarrayval = (ArrayLiteralExp *)v->value; - else // this can only happen with static arrays - newarrayval = createBlockDuplicatedArrayLiteral(v->type, v->type->defaultInit(), dim); - // value[] = value[0..lower] ~ e ~ value[upper..$] - newarrayval->elements = spliceElements(newarrayval->elements, - ((ArrayLiteralExp *)e)->elements, lowerbound); - newval = newarrayval; + dinteger_t val; + switch (sz) + { + case 1: val = s[j]; break; + case 2: val = ((unsigned short *)s)[j]; break; + case 4: val = ((unsigned *)s)[j]; break; + default: + assert(0); + break; } - v->value = newval; - return e; + existingAE->elements->data[j+firstIndex] + = new IntegerExp(newval->loc, val, elemType); } - else + return newval; + } + else if (newval->op == TOKarrayliteral && existingSE) + { /* Mixed slice: it was initialized as a string literal. + * Now a slice of it is being set with an array literal. + */ + unsigned char *s = (unsigned char *)existingSE->string; + ArrayLiteralExp *newae = (ArrayLiteralExp *)newval; + for (size_t j = 0; j < newae->elements->dim; j++) { - error("Slice operation %s cannot be evaluated at compile time", toChars()); - return e; + unsigned value = ((Expression *)(newae->elements->data[j]))->toInteger(); + switch (existingSE->sz) + { + case 1: s[j+firstIndex] = value; break; + case 2: ((unsigned short *)s)[j+firstIndex] = value; break; + case 4: ((unsigned *)s)[j+firstIndex] = value; break; + default: + assert(0); + break; + } } + return newval; + } + else if (existingSE) + { // String literal block slice assign + unsigned value = newval->toInteger(); + unsigned char *s = (unsigned char *)existingSE->string; + for (size_t j = 0; j < upperbound-lowerbound; j++) + { + switch (existingSE->sz) + { + case 1: s[j+firstIndex] = value; break; + case 2: ((unsigned short *)s)[j+firstIndex] = value; break; + case 4: ((unsigned *)s)[j+firstIndex] = value; break; + default: + assert(0); + break; + } + } + if (goal == ctfeNeedNothing) + return NULL; // avoid creating an unused literal + SliceExp *retslice = new SliceExp(loc, existingSE, + new IntegerExp(loc, firstIndex, Type::tsize_t), + new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); + retslice->type = this->type; + return retslice->interpret(istate); + } + else if (existingAE) + { + /* Block assignment, initialization of static arrays + * x[] = e + * x may be a multidimensional static array. (Note that this + * only happens with array literals, never with strings). + */ + Expressions * w = existingAE->elements; + assert( existingAE->type->ty == Tsarray || + existingAE->type->ty == Tarray); +#if DMDV2 + Type *desttype = ((TypeArray *)existingAE->type)->next->castMod(0); + bool directblk = (e2->type->toBasetype()->castMod(0)) == desttype; +#else + Type *desttype = ((TypeArray *)existingAE->type)->next; + bool directblk = (e2->type->toBasetype()) == desttype; +#endif + for (size_t j = 0; j < upperbound-lowerbound; j++) + { + if (!directblk) + // Multidimensional array block assign + recursiveBlockAssign((ArrayLiteralExp *)w->data[j+firstIndex], newval); + else + existingAE->elements->data[j+firstIndex] = newval; + } + if (goal == ctfeNeedNothing) + return NULL; // avoid creating an unused literal + SliceExp *retslice = new SliceExp(loc, existingAE, + new IntegerExp(loc, firstIndex, Type::tsize_t), + new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); + retslice->type = this->type; + return retslice->interpret(istate); } else error("Slice operation %s cannot be evaluated at compile time", toChars()); @@ -2591,15 +3163,15 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) error("%s cannot be modified at compile time", v->toChars()); return EXP_CANT_INTERPRET; } - if (fp && !v->value) + if (fp && !v->getValue()) { error("variable %s is used before initialization", v->toChars()); return e; } - Expression *vie = v->value; + Expression *vie = v->getValue(); if (vie->op == TOKvar) { Declaration *d = ((VarExp *)vie)->var; - vie = getVarExp(e1->loc, istate, d); + vie = getVarExp(e1->loc, istate, d, ctfeNeedRvalue); } if (vie->op != TOKstructliteral) return EXP_CANT_INTERPRET; @@ -2609,7 +3181,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) newval = modifyStructField(type, se, soe->offset, newval); addVarToInterstate(istate, v); - v->value = newval; + v->setRefValue(newval); } } else @@ -2622,15 +3194,15 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) return e; } -Expression *AssignExp::interpret(InterState *istate) +Expression *AssignExp::interpret(InterState *istate, CtfeGoal goal) { - return interpretAssignCommon(istate, NULL); + return interpretAssignCommon(istate, goal, NULL); } #define BIN_ASSIGN_INTERPRET(op) \ -Expression *op##AssignExp::interpret(InterState *istate) \ -{ \ - return interpretAssignCommon(istate, &op); \ +Expression *op##AssignExp::interpret(InterState *istate, CtfeGoal goal) \ +{ \ + return interpretAssignCommon(istate, goal, &op); \ } BIN_ASSIGN_INTERPRET(Add) @@ -2646,16 +3218,16 @@ BIN_ASSIGN_INTERPRET(And) BIN_ASSIGN_INTERPRET(Or) BIN_ASSIGN_INTERPRET(Xor) -Expression *PostExp::interpret(InterState *istate) +Expression *PostExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("PostExp::interpret() %s\n", toChars()); #endif Expression *e; if (op == TOKplusplus) - e = interpretAssignCommon(istate, &Add, 1); + e = interpretAssignCommon(istate, goal, &Add, 1); else - e = interpretAssignCommon(istate, &Min, 1); + e = interpretAssignCommon(istate, goal, &Min, 1); #if LOG if (e == EXP_CANT_INTERPRET) printf("PostExp::interpret() CANT\n"); @@ -2663,7 +3235,7 @@ Expression *PostExp::interpret(InterState *istate) return e; } -Expression *AndAndExp::interpret(InterState *istate) +Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("AndAndExp::interpret() %s\n", toChars()); @@ -2692,7 +3264,7 @@ Expression *AndAndExp::interpret(InterState *istate) return e; } -Expression *OrOrExp::interpret(InterState *istate) +Expression *OrOrExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("OrOrExp::interpret() %s\n", toChars()); @@ -2722,7 +3294,7 @@ Expression *OrOrExp::interpret(InterState *istate) } -Expression *CallExp::interpret(InterState *istate) +Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e = EXP_CANT_INTERPRET; #if LOG @@ -2743,11 +3315,11 @@ Expression *CallExp::interpret(InterState *istate) Expression * pe = ((PtrExp*)ecall)->e1; if (pe->op == TOKvar) { VarDeclaration *vd = ((VarExp *)((PtrExp*)ecall)->e1)->var->isVarDeclaration(); - if (vd && vd->value && vd->value->op == TOKsymoff) - fd = ((SymOffExp *)vd->value)->var->isFuncDeclaration(); + if (vd && vd->getValue() && vd->getValue()->op == TOKsymoff) + fd = ((SymOffExp *)vd->getValue())->var->isFuncDeclaration(); else { - ecall = getVarExp(loc, istate, vd); + ecall = getVarExp(loc, istate, vd, goal); if (ecall == EXP_CANT_INTERPRET) return ecall; @@ -2790,8 +3362,8 @@ Expression *CallExp::interpret(InterState *istate) else if (ecall->op == TOKvar) { VarDeclaration *vd = ((VarExp *)ecall)->var->isVarDeclaration(); - if (vd && vd->value) - ecall = vd->value; + if (vd && vd->getValue()) + ecall = vd->getValue(); else // Calling a function fd = ((VarExp *)e1)->var->isFuncDeclaration(); } @@ -2903,7 +3475,7 @@ Expression *CallExp::interpret(InterState *istate) return e; } -Expression *CommaExp::interpret(InterState *istate) +Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("CommaExp::interpret() %s\n", toChars()); @@ -2926,16 +3498,23 @@ Expression *CommaExp::interpret(InterState *istate) { VarExp* ve = (VarExp *)e2; VarDeclaration *v = ve->var->isVarDeclaration(); - if (!v->init && !v->value) - v->value = v->type->defaultInitLiteral(); - if (!v->value) - v->value = v->init->toExpression(); - // Bug 4027. Copy constructors are a weird case where the - // initializer is a void function (the variable is modified - // through a reference parameter instead). - Expression *newval = v->value->interpret(istate); - if (newval != EXP_VOID_INTERPRET) - v->value = newval; + if (!v->init && !v->getValue()) + { + v->createRefValue(copyLiteral(v->type->defaultInitLiteral())); + } + if (!v->getValue()) { + Expression *newval = v->init->toExpression(); +// v->setRefValue(v->init->toExpression()); + // Bug 4027. Copy constructors are a weird case where the + // initializer is a void function (the variable is modified + // through a reference parameter instead). + newval = newval->interpret(istate); + if (newval != EXP_VOID_INTERPRET) + { + // v isn't necessarily null. + v->setValueWithoutChecking(copyLiteral(newval)); + } + } return e2; } Expression *e = e1->interpret(istate); @@ -2944,7 +3523,7 @@ Expression *CommaExp::interpret(InterState *istate) return e; } -Expression *CondExp::interpret(InterState *istate) +Expression *CondExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("CondExp::interpret() %s\n", toChars()); @@ -2962,7 +3541,7 @@ Expression *CondExp::interpret(InterState *istate) return e; } -Expression *ArrayLengthExp::interpret(InterState *istate) +Expression *ArrayLengthExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; Expression *e1; @@ -2970,6 +3549,7 @@ Expression *ArrayLengthExp::interpret(InterState *istate) printf("ArrayLengthExp::interpret() %s\n", toChars()); #endif e1 = this->e1->interpret(istate); + assert(e1); if (e1 == EXP_CANT_INTERPRET) goto Lcant; if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) @@ -2988,7 +3568,7 @@ Lcant: return EXP_CANT_INTERPRET; } -Expression *IndexExp::interpret(InterState *istate) +Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; Expression *e1; Expression *e2; @@ -2996,10 +3576,16 @@ Expression *IndexExp::interpret(InterState *istate) #if LOG printf("IndexExp::interpret() %s\n", toChars()); #endif - e1 = this->e1->interpret(istate); + e1 = this->e1->interpret(istate, goal); if (e1 == EXP_CANT_INTERPRET) goto Lcant; + if (e1->op == TOKnull) + { + error("cannot index null array %s", this->e1->toChars()); + return EXP_CANT_INTERPRET; + } + if (e1->op == TOKstring || e1->op == TOKarrayliteral) { /* Set the $ variable @@ -3008,12 +3594,32 @@ Expression *IndexExp::interpret(InterState *istate) if (e == EXP_CANT_INTERPRET) goto Lcant; if (lengthVar) - lengthVar->value = e; + { + lengthVar->createStackValue(e); + } } e2 = this->e2->interpret(istate); + if (lengthVar) + lengthVar->setValueNull(); // $ is defined only inside [] if (e2 == EXP_CANT_INTERPRET) goto Lcant; + if (e1->op == TOKslice && e2->op == TOKint64) + { + // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx'] + uinteger_t indx = e2->toInteger(); + uinteger_t ilo = ((SliceExp *)e1)->lwr->toInteger(); + uinteger_t iup = ((SliceExp *)e1)->upr->toInteger(); + + if (indx > iup - ilo) + { + error("index %ju exceeds array length %ju", indx, iup - ilo); + goto Lcant; + } + indx += ilo; + e1 = ((SliceExp *)e1)->e1; + e2 = new IntegerExp(e2->loc, indx, e2->type); + } e = Index(type, e1, e2); if (e == EXP_CANT_INTERPRET) error("%s cannot be interpreted at compile time", toChars()); @@ -3024,7 +3630,7 @@ Lcant: } -Expression *SliceExp::interpret(InterState *istate) +Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; Expression *e1; Expression *lwr; @@ -3033,22 +3639,37 @@ Expression *SliceExp::interpret(InterState *istate) #if LOG printf("SliceExp::interpret() %s\n", toChars()); #endif - e1 = this->e1->interpret(istate); + e1 = this->e1->interpret(istate, goal); if (e1 == EXP_CANT_INTERPRET) goto Lcant; + if (!this->lwr) { + if (goal == ctfeNeedLvalue) + return e1; e = e1->castTo(NULL, type); return e->interpret(istate); } /* Set the $ variable */ - e = ArrayLength(Type::tsize_t, e1); + if (e1->op == TOKnull) + e = new IntegerExp(0, 0, Type::tsize_t); + else if (e1->op == TOKslice) + { + // For lvalue slices, slice ends have already been calculated + e = new IntegerExp(0, ((SliceExp *)e1)->upr->toInteger() + - ((SliceExp *)e1)->lwr->toInteger(), Type::tsize_t); + } + else + e = ArrayLength(Type::tsize_t, e1); if (e == EXP_CANT_INTERPRET) + { + error("Cannot determine length of %s at compile time\n", e1->toChars()); goto Lcant; + } if (lengthVar) - lengthVar->value = e; + lengthVar->createStackValue(e); /* Evaluate lower and upper bounds of slice */ @@ -3058,18 +3679,59 @@ Expression *SliceExp::interpret(InterState *istate) upr = this->upr->interpret(istate); if (upr == EXP_CANT_INTERPRET) goto Lcant; - + if (lengthVar) + lengthVar->setValueNull(); // $ is defined only inside [L..U] + { + uinteger_t ilwr = lwr->toInteger(); + uinteger_t iupr = upr->toInteger(); + if (e1->op == TOKnull) + { + if (ilwr== 0 && iupr == 0) + return e1; + e1->error("slice [%ju..%ju] is out of bounds", ilwr, iupr); + return EXP_CANT_INTERPRET; + } + if (goal == ctfeNeedLvalue) + { + if (e1->op == TOKslice) + { + SliceExp *se = (SliceExp *)e1; + // Simplify slice of slice: + // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr'] + uinteger_t lo1 = se->lwr->toInteger(); + uinteger_t up1 = se->upr->toInteger(); + if (ilwr > iupr || iupr > up1 - lo1) + { + error("slice[%ju..%ju] exceeds array bounds[%ju..%ju]", + ilwr, iupr, lo1, up1); + goto Lcant; + } + ilwr += lo1; + iupr += lo1; + e = new SliceExp(loc, se->e1, + new IntegerExp(loc, ilwr, lwr->type), + new IntegerExp(loc, iupr, upr->type)); + e->type = type; + return e; + } + e = new SliceExp(loc, e1, lwr, upr); + e->type = type; + return e; + } e = Slice(type, e1, lwr, upr); if (e == EXP_CANT_INTERPRET) error("%s cannot be interpreted at compile time", toChars()); + } return e; Lcant: + if (lengthVar) + lengthVar->setValueNull(); return EXP_CANT_INTERPRET; } -Expression *CatExp::interpret(InterState *istate) +Expression *CatExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; Expression *e1; Expression *e2; @@ -3098,7 +3760,7 @@ Lcant: } -Expression *CastExp::interpret(InterState *istate) +Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; Expression *e1; @@ -3121,7 +3783,7 @@ Lcant: } -Expression *AssertExp::interpret(InterState *istate) +Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; Expression *e1; @@ -3134,7 +3796,7 @@ Expression *AssertExp::interpret(InterState *istate) if (ade->e1->op == TOKthis && istate->localThis) if (istate->localThis->op == TOKdotvar && ((DotVarExp *)(istate->localThis))->e1->op == TOKthis) - return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var); + return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var, ctfeNeedRvalue); else return istate->localThis->interpret(istate); } @@ -3144,7 +3806,7 @@ Expression *AssertExp::interpret(InterState *istate) { if (istate->localThis->op == TOKdotvar && ((DotVarExp *)(istate->localThis))->e1->op == TOKthis) - return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var); + return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var, ctfeNeedRvalue); else return istate->localThis->interpret(istate); } @@ -3176,7 +3838,7 @@ Lcant: return EXP_CANT_INTERPRET; } -Expression *PtrExp::interpret(InterState *istate) +Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e = EXP_CANT_INTERPRET; #if LOG @@ -3208,7 +3870,7 @@ Expression *PtrExp::interpret(InterState *istate) { SymOffExp *soe = (SymOffExp *)e1; VarDeclaration *v = soe->var->isVarDeclaration(); if (v) - { Expression *ev = getVarExp(loc, istate, v); + { Expression *ev = getVarExp(loc, istate, v, ctfeNeedLvalue); if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral) { StructLiteralExp *se = (StructLiteralExp *)ev; e = se->getField(type, soe->offset); @@ -3235,7 +3897,7 @@ Expression *PtrExp::interpret(InterState *istate) return e; } -Expression *DotVarExp::interpret(InterState *istate) +Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e = EXP_CANT_INTERPRET; #if LOG @@ -3249,7 +3911,26 @@ Expression *DotVarExp::interpret(InterState *istate) { StructLiteralExp *se = (StructLiteralExp *)ex; VarDeclaration *v = var->isVarDeclaration(); if (v) - { e = se->getField(type, v->offset); + { + if (goal == ctfeNeedLvalue) + { + // We can't use getField, because it makes a copy + int i = se->getFieldIndex(type, v->offset); + if (i == -1) + { + error("couldn't find field %s in %s", v->toChars(), type->toChars()); + return EXP_CANT_INTERPRET; + } + e = (Expression *)se->elements->data[i]; + // If it is an lvalue literal, return it... + if (e->op == TOKstructliteral || e->op == TOKarrayliteral || + e->op == TOKassocarrayliteral || e->op == TOKstring || + e->op == TOKslice) + return e; + // ...Otherwise, just return the (simplified) dotvar expression + return new DotVarExp(loc, ex, v); + } + e = se->getField(type, v->offset); if (!e) { error("couldn't find field %s in %s", v->toChars(), type->toChars()); @@ -3299,8 +3980,10 @@ Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) earg = earg->interpret(istate); if (earg == EXP_CANT_INTERPRET) return NULL; - if (earg->op != TOKassocarrayliteral) + if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) return NULL; + if (earg->op == TOKnull) + return new NullExp(earg->loc); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); Type *elemType = ((TypeAArray *)aae->type)->index; @@ -3310,20 +3993,24 @@ Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) Expression *interpret_aaValues(InterState *istate, Expressions *arguments) { - //printf("interpret_aaValues()\n"); +#if LOG + printf("interpret_aaValues()\n"); +#endif 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) + if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) return NULL; + if (earg->op == TOKnull) + return new NullExp(earg->loc); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->values); Type *elemType = ((TypeAArray *)aae->type)->next; e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); - //printf("result is %s\n", e->toChars()); + printf("result is %s\n", e->toChars()); return e; } @@ -3352,8 +4039,11 @@ Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration earg = earg->interpret(istate); if (earg == EXP_CANT_INTERPRET) return NULL; - if (earg->op != TOKassocarrayliteral) + if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) return NULL; + if (earg->op == TOKnull) + return new NullExp(earg->loc); + assert(earg->op == TOKassocarrayliteral); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); assert(fd->type->ty == Tfunction); @@ -3365,12 +4055,17 @@ Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclaration *fd) { - //printf("interpret_values()\n"); +#if LOG + printf("interpret_values()\n"); +#endif earg = earg->interpret(istate); if (earg == EXP_CANT_INTERPRET) return NULL; - if (earg->op != TOKassocarrayliteral) + if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) return NULL; + if (earg->op == TOKnull) + return new NullExp(earg->loc); + assert(earg->op == TOKassocarrayliteral); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; Expression *e = new ArrayLiteralExp(aae->loc, aae->values); assert(fd->type->ty == Tfunction); @@ -3382,3 +4077,88 @@ Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclarati } #endif + +/* Setter functions for CTFE variable values. + * These functions exist to check for compiler CTFE bugs. + */ + +bool isStackValueValid(Expression *newval) +{ + if ((newval->op ==TOKarrayliteral) || ( newval->op==TOKstructliteral) || + (newval->op==TOKstring) || (newval->op == TOKassocarrayliteral) || + (newval->op == TOKnull) || (newval->op == TOKslice)) + { return false; + } + if (newval->op == TOKvar) return true; + if (newval->op == TOKdotvar) return true; + if (newval->op == TOKindex) return true; + if (newval->op == TOKfunction) return true; // function/delegate literal + if (newval->op == TOKdelegate) return true; + if (newval->op == TOKsymoff) // function pointer + { + if (((SymOffExp *)newval)->var->isFuncDeclaration()) + return true; + } + if (newval->op == TOKint64 || newval->op == TOKfloat64 || + newval->op == TOKchar || newval->op == TOKcomplex80) + return true; + newval->error("CTFE internal error: illegal stack value %s\n", newval->toChars()); + return false; +} +bool isRefValueValid(Expression *newval) +{ + assert(newval); + if ((newval->op ==TOKarrayliteral) || ( newval->op==TOKstructliteral) || + (newval->op==TOKstring) || (newval->op == TOKassocarrayliteral) || + (newval->op == TOKnull)) + { return true; + } + if (newval->op == TOKslice) + { + SliceExp *se = (SliceExp *)newval; + assert(se->lwr && se->lwr != EXP_CANT_INTERPRET); + assert(se->upr && se->upr != EXP_CANT_INTERPRET); + assert(se->e1->op == TOKarrayliteral || se->e1->op == TOKstring); + return true; + } + newval->error("CTFE internal error: illegal reference value %s\n", newval->toChars()); + return false; +} + +void VarDeclaration::setValueNull() +{ + literalvalue = NULL; +} + +// Don't check for validity +void VarDeclaration::setValueWithoutChecking(Expression *newval) +{ + assert(!newval || isStackValueValid(newval) || isRefValueValid(newval)); + literalvalue = newval; +} +void VarDeclaration::createRefValue(Expression *newval) +{ + assert(!literalvalue); + assert(isRefValueValid(newval)); + literalvalue = newval; +} + +void VarDeclaration::setRefValue(Expression *newval) +{ + assert(literalvalue); + assert(isRefValueValid(newval)); + literalvalue = newval; +} + +void VarDeclaration::setStackValue(Expression *newval) +{ + assert(literalvalue); + assert(isStackValueValid(newval)); + literalvalue = newval; +} +void VarDeclaration::createStackValue(Expression *newval) +{ + assert(!literalvalue); + assert(isStackValueValid(newval)); + literalvalue = newval; +} diff --git a/dmd2/irstate.c b/dmd2/irstate.c index 4ed43548..42649bb0 100644 --- a/dmd2/irstate.c +++ b/dmd2/irstate.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -32,6 +32,7 @@ IRState::IRState(IRState *irs, Statement *s) sthis = irs->sthis; blx = irs->blx; deferToObj = irs->deferToObj; + varsInScope = irs->varsInScope; } else { @@ -41,6 +42,7 @@ IRState::IRState(IRState *irs, Statement *s) sthis = NULL; blx = NULL; deferToObj = NULL; + varsInScope = NULL; } } @@ -64,6 +66,7 @@ IRState::IRState(IRState *irs, Dsymbol *s) sthis = irs->sthis; blx = irs->blx; deferToObj = irs->deferToObj; + varsInScope = irs->varsInScope; } else { @@ -73,6 +76,7 @@ IRState::IRState(IRState *irs, Dsymbol *s) sthis = NULL; blx = NULL; deferToObj = NULL; + varsInScope = NULL; } } @@ -94,6 +98,7 @@ IRState::IRState(Module *m, Dsymbol *s) blx = NULL; deferToObj = NULL; startaddress = NULL; + varsInScope = NULL; } block *IRState::getBreakBlock(Identifier *ident) diff --git a/dmd2/irstate.h b/dmd2/irstate.h index ad77db0e..fe0d0fca 100644 --- a/dmd2/irstate.h +++ b/dmd2/irstate.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -37,6 +37,7 @@ struct IRState Array *deferToObj; // array of Dsymbol's to run toObjFile(int multiobj) on later elem *ehidden; // transmit hidden pointer to CallExp::toElem() Symbol *startaddress; + Array *varsInScope; // variables that are in scope that will need destruction later block *breakBlock; block *contBlock; diff --git a/dmd2/lexer.c b/dmd2/lexer.c index fd5733d7..b3bef3f0 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -2261,6 +2261,7 @@ done: } // Parse trailing 'u', 'U', 'l' or 'L' in any combination + const unsigned char *psuffix = p; while (1) { unsigned char f; @@ -2287,6 +2288,10 @@ done: break; } + if (state == STATE_octal && n >= 8 && !global.params.useDeprecated) + error("octal literals 0%llo%.*s are deprecated, use std.conv.octal!%llo%.*s instead", + n, p - psuffix, psuffix, n, p - psuffix, psuffix); + switch (flags) { case 0: diff --git a/dmd2/mars.c b/dmd2/mars.c index acf510d1..b8471310 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -100,7 +100,7 @@ Global::Global() "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; #endif ; - version = "v2.052"; + version = "v2.053"; #if IN_LLVM ldc_version = "LDC trunk"; llvm_version = "LLVM 2.9"; @@ -182,7 +182,7 @@ void verror(Loc loc, const char *format, va_list ap) #endif fprintf(stdmsg, "\n"); fflush(stdmsg); -//halt(); +halt(); } global.errors++; } diff --git a/dmd2/mtype.c b/dmd2/mtype.c index 92781758..01bca3c5 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -1666,6 +1666,15 @@ int Type::checkBoolean() return isscalar(); } +/******************************** + * TRUE if when type goes out of scope, it needs a destructor applied. + * Only applies to value types, not ref types. + */ +int Type::needsDestruction() +{ + return FALSE; +} + /********************************* * Check type to see if it is based on a deprecated symbol. */ @@ -2067,6 +2076,7 @@ Expression *Type::toExpression() int Type::hasPointers() { + //printf("Type::hasPointers() %s, %d\n", toChars(), ty); return FALSE; } @@ -3416,7 +3426,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol sc = sc->pop(); if (d >= td->objects->dim) - { error(loc, "tuple index %ju exceeds %u", d, td->objects->dim); + { error(loc, "tuple index %ju exceeds length %u", d, td->objects->dim); goto Ldefault; } Object *o = (Object *)td->objects->data[(size_t)d]; @@ -3492,7 +3502,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) dim = semanticLength(sc, tbn, dim); - dim = dim->optimize(WANTvalue | WANTinterpret); + dim = dim->optimize(WANTvalue); if (sc && sc->parameterSpecialization && dim->op == TOKvar && ((VarExp *)dim)->var->storage_class & STCtemplateparameter) { @@ -3501,6 +3511,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) */ return this; } + dim = dim->optimize(WANTvalue | WANTinterpret); dinteger_t d1 = dim->toInteger(); dim = dim->implicitCastTo(sc, tsize_t); dim = dim->optimize(WANTvalue); @@ -3551,8 +3562,8 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) } case Tstruct: { TypeStruct *ts = (TypeStruct *)tbn; - if (ts->sym->isnested) - { error(loc, "cannot have array of inner structs %s", ts->toChars()); + if (0 && ts->sym->isnested) + { error(loc, "cannot have static array of inner struct %s", ts->toChars()); goto Lerror; } break; @@ -3717,6 +3728,11 @@ int TypeSArray::isZeroInit(Loc loc) return next->isZeroInit(loc); } +int TypeSArray::needsDestruction() +{ + return next->needsDestruction(); +} + Expression *TypeSArray::defaultInitLiteral(Loc loc) { #if LOGDEFAULTINIT @@ -3746,7 +3762,18 @@ Expression *TypeSArray::toExpression() int TypeSArray::hasPointers() { - return next->hasPointers(); + /* Don't want to do this, because: + * struct S { T* array[0]; } + * may be a variable length struct. + */ + //if (dim->toInteger() == 0) + //return FALSE; + + if (next->ty == Tvoid) + // Arrays of void contain arbitrary data, which may include pointers + return TRUE; + else + return next->hasPointers(); } /***************************** TypeDArray *****************************/ @@ -3797,8 +3824,8 @@ Type *TypeDArray::semantic(Loc loc, Scope *sc) break; case Tstruct: { TypeStruct *ts = (TypeStruct *)tbn; - if (ts->sym->isnested) - error(loc, "cannot have array of inner structs %s", ts->toChars()); + if (0 && ts->sym->isnested) + error(loc, "cannot have dynamic array of inner struct %s", ts->toChars()); break; } } @@ -4000,7 +4027,7 @@ Type *TypeNewArray::semantic(Loc loc, Scope *sc) break; case Tstruct: { TypeStruct *ts = (TypeStruct *)tbn; - if (ts->sym->isnested) + if (0 && ts->sym->isnested) error(loc, "cannot have array of inner structs %s", ts->toChars()); break; } @@ -5584,6 +5611,16 @@ Type *TypeDelegate::semantic(Loc loc, Scope *sc) return this; } next = next->semantic(loc,sc); + /* In order to deal with Bugzilla 4028, perhaps default arguments should + * be removed from next before the merge. + */ + + /* Don't return merge(), because arg identifiers and default args + * can be different + * even though the types match + */ + //deco = merge()->deco; + //return this; return merge(); } @@ -5829,8 +5866,11 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, *pe = e; } else + { Lerror: error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); + *pe = new ErrorExp(); + } return; } L2: @@ -5929,6 +5969,7 @@ L1: else error(loc, "undefined identifier %s", p); } + *pt = Type::terror; } } @@ -6657,6 +6698,11 @@ int TypeEnum::checkBoolean() return sym->memtype->checkBoolean(); } +int TypeEnum::needsDestruction() +{ + return sym->memtype->needsDestruction(); +} + MATCH TypeEnum::implicitConvTo(Type *to) { MATCH m; @@ -6860,6 +6906,11 @@ int TypeTypedef::checkBoolean() return sym->basetype->checkBoolean(); } +int TypeTypedef::needsDestruction() +{ + return sym->basetype->needsDestruction(); +} + Type *TypeTypedef::toBasetype() { if (sym->inuse) @@ -7295,7 +7346,11 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) VarDeclaration *vd = (VarDeclaration *)(sym->fields.data[j]); Expression *e; if (vd->init) - e = vd->init->toExpression(); + { if (vd->init->isVoidInitializer()) + e = NULL; + else + e = vd->init->toExpression(); + } else e = vd->type->defaultInitLiteral(); structelems->data[j] = e; @@ -7318,6 +7373,11 @@ int TypeStruct::checkBoolean() return FALSE; } +int TypeStruct::needsDestruction() +{ + return sym->dtor != NULL; +} + int TypeStruct::isAssignable() { /* If any of the fields are const or invariant, diff --git a/dmd2/mtype.h b/dmd2/mtype.h index 4a6846d1..db060aff 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.h @@ -334,6 +334,7 @@ struct Type : Object virtual TypeTuple *toArgTypes(); virtual Type *nextOf(); uinteger_t sizemask(); + virtual int needsDestruction(); static void error(Loc loc, const char *format, ...) IS_PRINTF(2); @@ -463,6 +464,7 @@ struct TypeSArray : TypeArray TypeInfoDeclaration *getTypeInfoDeclaration(); Expression *toExpression(); int hasPointers(); + int needsDestruction(); TypeTuple *toArgTypes(); #if CPP_MANGLE void toCppMangle(OutBuffer *buf, CppMangleState *cms); @@ -772,6 +774,7 @@ struct TypeStruct : Type int isZeroInit(Loc loc); int isAssignable(); int checkBoolean(); + int needsDestruction(); #if IN_DMD dt_t **toDt(dt_t **pdt); #endif @@ -820,6 +823,7 @@ struct TypeEnum : Type int isunsigned(); int checkBoolean(); int isAssignable(); + int needsDestruction(); MATCH implicitConvTo(Type *to); MATCH constConv(Type *to); Type *toBasetype(); @@ -863,6 +867,7 @@ struct TypeTypedef : Type int isunsigned(); int checkBoolean(); int isAssignable(); + int needsDestruction(); Type *toBasetype(); MATCH implicitConvTo(Type *to); MATCH constConv(Type *to); diff --git a/dmd2/optimize.c b/dmd2/optimize.c index 911992da..bae236b7 100644 --- a/dmd2/optimize.c +++ b/dmd2/optimize.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -57,11 +57,11 @@ Expression *expandVar(int result, VarDeclaration *v) //error("ICE"); return e; } - Type *tb = v->type->toBasetype(); if (result & WANTinterpret || v->storage_class & STCmanifest || - (tb->ty != Tsarray && tb->ty != Tstruct) + v->type->toBasetype()->isscalar() || + ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct)) ) { if (v->init) @@ -73,13 +73,31 @@ Expression *expandVar(int result, VarDeclaration *v) } Expression *ei = v->init->toExpression(); if (!ei) + { if (v->storage_class & STCmanifest) + v->error("enum cannot be initialized with %s", v->init->toChars()); goto L1; + } if (ei->op == TOKconstruct || ei->op == TOKblit) { AssignExp *ae = (AssignExp *)ei; ei = ae->e2; - if (ei->isConst() != 1 && ei->op != TOKstring) + if (result & WANTinterpret) + { + v->inuse++; + ei = ei->optimize(result); + v->inuse--; + } + else if (ei->isConst() != 1 && ei->op != TOKstring) goto L1; - if (ei->type != v->type) + + if (ei->type == v->type) + { // const variable initialized with const expression + } + else if (ei->implicitConvTo(v->type) >= MATCHconst) + { // const var initialized with non-const expression + ei = ei->implicitCastTo(0, v->type); + ei = ei->semantic(0); + } + else goto L1; } if (v->scope) @@ -154,7 +172,17 @@ Expression *fromConstInitializer(int result, Expression *e1) e->loc = e1->loc; } else + { e = e1; + /* If we needed to interpret, generate an error. + * Don't give an error if it's a template parameter + */ + if (v && (result & WANTinterpret) && + !(v->storage_class & STCtemplateparameter)) + { + e1->error("variable %s cannot be read at compile time", v->toChars()); + } + } } return e; } @@ -189,7 +217,7 @@ Expression *ArrayLiteralExp::optimize(int result) for (size_t i = 0; i < elements->dim; i++) { Expression *e = (Expression *)elements->data[i]; - e = e->optimize(WANTvalue | (result & WANTinterpret)); + e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); elements->data[i] = (void *)e; } } @@ -202,11 +230,11 @@ Expression *AssocArrayLiteralExp::optimize(int result) for (size_t i = 0; i < keys->dim; i++) { Expression *e = (Expression *)keys->data[i]; - e = e->optimize(WANTvalue | (result & WANTinterpret)); + e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); keys->data[i] = (void *)e; e = (Expression *)values->data[i]; - e = e->optimize(WANTvalue | (result & WANTinterpret)); + e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); values->data[i] = (void *)e; } return this; @@ -220,7 +248,7 @@ Expression *StructLiteralExp::optimize(int result) { Expression *e = (Expression *)elements->data[i]; if (!e) continue; - e = e->optimize(WANTvalue | (result & WANTinterpret)); + e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); elements->data[i] = (void *)e; } } @@ -460,6 +488,10 @@ Expression *NewExp::optimize(int result) arguments->data[i] = (void *)e; } } + if (result & WANTinterpret) + { + error("cannot evaluate %s at compile time", toChars()); + } return this; } @@ -851,7 +883,7 @@ Expression *ArrayLengthExp::optimize(int result) { Expression *e; //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e1 = e1->optimize(WANTvalue | WANTexpand | (result & WANTinterpret)); e = this; if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) { @@ -894,11 +926,36 @@ Expression *IdentityExp::optimize(int result) return e; } +/* It is possible for constant folding to change an array expression of + * unknown length, into one where the length is known. + * If the expression 'arr' is a literal, set lengthVar to be its length. + */ +void setLengthVarIfKnown(VarDeclaration *lengthVar, Expression *arr) +{ + if (!lengthVar) + return; + if (lengthVar->init && !lengthVar->init->isVoidInitializer()) + return; // we have previously calculated the length + size_t len; + if (arr->op == TOKstring) + len = ((StringExp *)arr)->len; + else if (arr->op == TOKarrayliteral) + len = ((ArrayLiteralExp *)arr)->elements->dim; + else + return; // we don't know the length yet + + Expression *dollar = new IntegerExp(0, len, Type::tsize_t); + lengthVar->init = new ExpInitializer(0, dollar); + lengthVar->storage_class |= STCstatic | STCconst; +} + + Expression *IndexExp::optimize(int result) { Expression *e; //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); - Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret)); + Expression *e1 = this->e1->optimize( + WANTvalue | (result & (WANTinterpret| WANTexpand))); e1 = fromConstInitializer(result, e1); if (this->e1->op == TOKvar) { VarExp *ve = (VarExp *)this->e1; @@ -910,6 +967,8 @@ Expression *IndexExp::optimize(int result) this->e1 = e1; } } + // We might know $ now + setLengthVarIfKnown(lengthVar, e1); e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); e = Index(type, e1, e2); if (e == EXP_CANT_INTERPRET) @@ -917,12 +976,13 @@ Expression *IndexExp::optimize(int result) return e; } + Expression *SliceExp::optimize(int result) { Expression *e; //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); e = this; - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e1 = e1->optimize(WANTvalue | (result & (WANTinterpret|WANTexpand))); if (!lwr) { if (e1->op == TOKstring) { // Convert slice of string literal into dynamic array @@ -933,6 +993,8 @@ Expression *SliceExp::optimize(int result) return e; } e1 = fromConstInitializer(result, e1); + // We might know $ now + setLengthVarIfKnown(lengthVar, e1); lwr = lwr->optimize(WANTvalue | (result & WANTinterpret)); upr = upr->optimize(WANTvalue | (result & WANTinterpret)); e = Slice(type, e1, lwr, upr); diff --git a/dmd2/parse.c b/dmd2/parse.c index 62a9a305..6c66b9bc 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -485,10 +485,10 @@ Dsymbols *Parser::parseDeclDefs(int once) if (token.value == TOKlparen) { nextToken(); - if (token.value == TOKint32v) + if (token.value == TOKint32v && token.uns64value > 0) n = (unsigned)token.uns64value; else - { error("integer expected, not %s", token.toChars()); + { error("positive integer expected, not %s", token.toChars()); n = 1; } nextToken(); @@ -3447,7 +3447,7 @@ Statement *Parser::parseStatement(int flags) nextToken(); Dsymbols *a = parseBlock(); Dsymbol *d = new StorageClassDeclaration(STCstatic, a); - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); if (flags & PSscope) s = new ScopeStatement(loc, s); break; @@ -3493,7 +3493,7 @@ Statement *Parser::parseStatement(int flags) for (int i = 0; i < a->dim; i++) { Dsymbol *d = (Dsymbol *)a->data[i]; - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); as->push(s); } s = new CompoundDeclarationStatement(loc, as); @@ -3501,7 +3501,7 @@ Statement *Parser::parseStatement(int flags) else if (a->dim == 1) { Dsymbol *d = (Dsymbol *)a->data[0]; - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); } else assert(0); @@ -3517,7 +3517,7 @@ Statement *Parser::parseStatement(int flags) { Dsymbol *d; d = parseAggregate(); - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); break; } @@ -3540,7 +3540,7 @@ Statement *Parser::parseStatement(int flags) else goto Ldeclaration; } - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); break; } @@ -3548,16 +3548,21 @@ Statement *Parser::parseStatement(int flags) { t = peek(&token); if (t->value == TOKlparen) { // mixin(string) - nextToken(); - check(TOKlparen, "mixin"); Expression *e = parseAssignExp(); - check(TOKrparen); check(TOKsemicolon); - s = new CompileStatement(loc, e); + if (e->op == TOKmixin) + { + CompileExp *cpe = (CompileExp *)e; + s = new CompileStatement(loc, cpe->e1); + } + else + { + s = new ExpStatement(loc, e); + } break; } Dsymbol *d = parseMixin(); - s = new DeclarationStatement(loc, d); + s = new ExpStatement(loc, d); break; } @@ -3596,7 +3601,7 @@ Statement *Parser::parseStatement(int flags) if (!(flags & PSsemi)) error("use '{ }' for an empty statement, not a ';'"); nextToken(); - s = new ExpStatement(loc, NULL); + s = new ExpStatement(loc, (Expression *)NULL); break; case TOKdo: @@ -5435,6 +5440,7 @@ Expression *Parser::parsePostExp(Expression *e) nextToken(); if (token.value == TOKrbracket) { // array[] + inBrackets--; e = new SliceExp(loc, e, NULL, NULL); nextToken(); } diff --git a/dmd2/scope.h b/dmd2/scope.h index 184109e8..de1f78f4 100644 --- a/dmd2/scope.h +++ b/dmd2/scope.h @@ -94,6 +94,8 @@ struct Scope #define SCOPEctor 1 // constructor type #define SCOPEstaticif 2 // inside static if #define SCOPEfree 4 // is on free list +#define SCOPEstaticassert 8 // inside static assert +#define SCOPEdebug 0x10 // inside debug conditional AnonymousAggregateDeclaration *anonAgg; // for temporary analysis diff --git a/dmd2/statement.c b/dmd2/statement.c index ed1dc110..1a0c8bba 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -188,13 +188,14 @@ int Statement::isEmpty() * *sfinally code executed in finally block */ -void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +Statement *Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) { //printf("Statement::scopeCode()\n"); //print(); *sentry = NULL; *sexception = NULL; *sfinally = NULL; + return this; } /********************************* @@ -233,6 +234,12 @@ ExpStatement::ExpStatement(Loc loc, Expression *exp) this->exp = exp; } +ExpStatement::ExpStatement(Loc loc, Dsymbol *declaration) + : Statement(loc) +{ + this->exp = new DeclarationExp(loc, declaration); +} + Statement *ExpStatement::syntaxCopy() { Expression *e = exp ? exp->syntaxCopy() : NULL; @@ -243,10 +250,19 @@ Statement *ExpStatement::syntaxCopy() void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (exp) - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); + { exp->toCBuffer(buf, hgs); + if (exp->op != TOKdeclaration) + { buf->writeByte(';'); + if (!hgs->FLinit.init) + buf->writenl(); + } + } + else + { + buf->writeByte(';'); + if (!hgs->FLinit.init) + buf->writenl(); + } } Statement *ExpStatement::semantic(Scope *sc) @@ -271,14 +287,10 @@ Statement *ExpStatement::semantic(Scope *sc) #endif exp = exp->semantic(sc); + exp = exp->addDtorHook(sc); exp = resolveProperties(sc, exp); exp->checkSideEffect(0); exp = exp->optimize(0); - if (exp->op == TOKdeclaration && !isDeclarationStatement()) - { Statement *s = new DeclarationStatement(loc, exp); - return s; - } - //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0); } return this; } @@ -307,6 +319,55 @@ int ExpStatement::isEmpty() return exp == NULL; } +Statement *ExpStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("ExpStatement::scopeCode()\n"); + //print(); + + *sentry = NULL; + *sexception = NULL; + *sfinally = NULL; + + if (exp) + { + if (exp->op == TOKdeclaration) + { + DeclarationExp *de = (DeclarationExp *)(exp); + VarDeclaration *v = de->declaration->isVarDeclaration(); + if (v && !v->noscope) + { + Expression *e = v->edtor; + if (e) + { + //printf("dtor is: "); e->print(); +#if 0 + if (v->type->toBasetype()->ty == Tstruct) + { /* Need a 'gate' to turn on/off destruction, + * in case v gets moved elsewhere. + */ + Identifier *id = Lexer::uniqueId("__runDtor"); + ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1)); + VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie); + *sentry = new ExpStatement(loc, rd); + v->rundtor = rd; + + /* Rewrite e as: + * rundtor && e + */ + Expression *ve = new VarExp(loc, v->rundtor); + e = new AndAndExp(loc, ve, e); + e->type = Type::tbool; + } +#endif + *sfinally = new ExpStatement(loc, e); + } + v->noscope = 1; // don't add in dtor again + } + } + } + return this; +} + /******************************** CompileStatement ***************************/ @@ -338,6 +399,8 @@ Statements *CompileStatement::flatten(Scope *sc) exp = exp->semantic(sc); exp = resolveProperties(sc, exp); exp = exp->optimize(WANTvalue | WANTinterpret); + if (exp->op == TOKerror) + return NULL; if (exp->op != TOKstring) { error("argument to mixin must be a string, not (%s)", exp->toChars()); return NULL; @@ -369,78 +432,6 @@ Statement *CompileStatement::semantic(Scope *sc) } -/******************************** DeclarationStatement ***************************/ - -DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration) - : ExpStatement(loc, new DeclarationExp(loc, declaration)) -{ -} - -DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp) - : ExpStatement(loc, exp) -{ -} - -Statement *DeclarationStatement::syntaxCopy() -{ - DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy()); - return ds; -} - -void DeclarationStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("DeclarationStatement::scopeCode()\n"); - //print(); - - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - - if (exp) - { - if (exp->op == TOKdeclaration) - { - DeclarationExp *de = (DeclarationExp *)(exp); - VarDeclaration *v = de->declaration->isVarDeclaration(); - if (v) - { Expression *e; - - e = v->callScopeDtor(sc); - if (e) - { - //printf("dtor is: "); e->print(); -#if 0 - if (v->type->toBasetype()->ty == Tstruct) - { /* Need a 'gate' to turn on/off destruction, - * in case v gets moved elsewhere. - */ - Identifier *id = Lexer::uniqueId("__runDtor"); - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1)); - VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new DeclarationStatement(loc, rd); - v->rundtor = rd; - - /* Rewrite e as: - * rundtor && e - */ - Expression *ve = new VarExp(loc, v->rundtor); - e = new AndAndExp(loc, ve, e); - e->type = Type::tbool; - } -#endif - *sfinally = new ExpStatement(loc, e); - } - } - } - } -} - -void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - exp->toCBuffer(buf, hgs); -} - - /******************************** CompoundStatement ***************************/ CompoundStatement::CompoundStatement(Loc loc, Statements *s) @@ -485,6 +476,15 @@ Statement *CompoundStatement::semantic(Scope *sc) //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); +#if 0 + for (size_t i = 0; i < statements->dim; i++) + { + s = (Statement *) statements->data[i]; + if (s) + printf("[%d]: %s", i, s->toChars()); + } +#endif + for (size_t i = 0; i < statements->dim; ) { s = (Statement *) statements->data[i]; @@ -505,29 +505,18 @@ Statement *CompoundStatement::semantic(Scope *sc) Statement *sexception; Statement *sfinally; - s->scopeCode(sc, &sentry, &sexception, &sfinally); + statements->data[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally); if (sentry) { sentry = sentry->semantic(sc); - if (s->isDeclarationStatement()) - { statements->insert(i, sentry); - i++; - } - else - statements->data[i] = sentry; + statements->insert(i, sentry); + i++; } if (sexception) { if (i + 1 == statements->dim && !sfinally) { -#if 1 sexception = sexception->semantic(sc); -#else - statements->push(sexception); - if (sfinally) - // Assume sexception does not throw - statements->push(sfinally); -#endif } else { @@ -724,11 +713,12 @@ void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) int nwritten = 0; for (int i = 0; i < statements->dim; i++) { Statement *s = (Statement *) statements->data[i]; - if (s) - { DeclarationStatement *ds = s->isDeclarationStatement(); - assert(ds); + ExpStatement *ds; + if (s && + (ds = s->isExpStatement()) != NULL && + ds->exp->op == TOKdeclaration) + { DeclarationExp *de = (DeclarationExp *)ds->exp; - assert(de->op == TOKdeclaration); Declaration *d = de->declaration->isDeclaration(); assert(d); VarDeclaration *v = d->isVarDeclaration(); @@ -931,7 +921,9 @@ Statement *ScopeStatement::semantic(Scope *sc) Statement *sexception; Statement *sfinally; - statement->scopeCode(sc, &sentry, &sexception, &sfinally); + statement = statement->scopeCode(sc, &sentry, &sexception, &sfinally); + assert(!sentry); + assert(!sexception); if (sfinally) { //printf("adding sfinally\n"); @@ -1228,14 +1220,15 @@ Statement *ForStatement::semantic(Scope *sc) return this; } -void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +Statement *ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) { //printf("ForStatement::scopeCode()\n"); //print(); if (init) - init->scopeCode(sc, sentry, sexception, sfinally); + init = init->scopeCode(sc, sentry, sexception, sfinally); else Statement::scopeCode(sc, sentry, sexception, sfinally); + return this; } int ForStatement::hasBreak() @@ -1592,8 +1585,8 @@ Lagain: key->init = new ExpInitializer(loc, new IntegerExp(0)); Statements *cs = new Statements(); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); + cs->push(new ExpStatement(loc, tmp)); + cs->push(new ExpStatement(loc, key)); Statement *forinit = new CompoundDeclarationStatement(loc, cs); Expression *cond; @@ -1611,7 +1604,7 @@ Lagain: // T value = tmp[key]; value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); - Statement *ds = new DeclarationStatement(loc, new DeclarationExp(loc, value)); + Statement *ds = new ExpStatement(loc, value); body = new CompoundStatement(loc, ds, body); @@ -1722,7 +1715,7 @@ Lagain: VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, rinit)); // r->semantic(sc); //printf("r: %s, init: %s\n", r->toChars(), r->init->toChars()); - Statement *init = new DeclarationStatement(loc, r); + Statement *init = new ExpStatement(loc, r); //printf("init: %s\n", init->toChars()); // !__r.empty @@ -1748,7 +1741,7 @@ Lagain: DeclarationExp *de = new DeclarationExp(loc, ve); Statement *body = new CompoundStatement(loc, - new DeclarationStatement(loc, de), this->body); + new ExpStatement(loc, de), this->body); s = new ForStatement(loc, init, condition, increment, body); #if 0 @@ -1809,7 +1802,7 @@ Lagain: id = Lexer::uniqueId("__applyArg", i); Initializer *ie = new ExpInitializer(0, new IdentifierExp(0, id)); VarDeclaration *v = new VarDeclaration(0, arg->type, arg->ident, ie); - s = new DeclarationStatement(0, v); + s = new ExpStatement(0, v); body = new CompoundStatement(loc, s, body); } a = new Parameter(STCref, arg->type, id, NULL); @@ -2051,6 +2044,9 @@ Lagain: } break; } + case Terror: + s = NULL; + break; default: error("foreach: %s is not an aggregate type", aggr->type->toChars()); @@ -2239,13 +2235,13 @@ Statement *ForeachRangeStatement::semantic(Scope *sc) // Keep order of evaluation as lwr, then upr if (op == TOKforeach) { - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs->push(new ExpStatement(loc, key)); + cs->push(new ExpStatement(loc, tmp)); } else { - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); + cs->push(new ExpStatement(loc, tmp)); + cs->push(new ExpStatement(loc, key)); } Statement *forinit = new CompoundDeclarationStatement(loc, cs); @@ -2554,7 +2550,16 @@ Statement *ConditionalStatement::semantic(Scope *sc) // This feature allows a limited form of conditional compilation. if (condition->include(sc, NULL)) { - ifbody = ifbody->semantic(sc); + DebugCondition *dc = condition->isDebugCondition(); + if (dc) + { + sc = sc->push(); + sc->flags |= SCOPEdebug; + ifbody = ifbody->semantic(sc); + sc->pop(); + } + else + ifbody = ifbody->semantic(sc); return ifbody; } else @@ -2569,8 +2574,15 @@ Statements *ConditionalStatement::flatten(Scope *sc) { Statement *s; + //printf("ConditionalStatement::flatten()\n"); if (condition->include(sc, NULL)) - s = ifbody; + { + DebugCondition *dc = condition->isDebugCondition(); + if (dc) + s = new DebugStatement(loc, ifbody); + else + s = ifbody; + } else s = elsebody; @@ -3051,7 +3063,7 @@ Statement *CaseStatement::semantic(Scope *sc) } #endif exp = exp->implicitCastTo(sc, sw->condition->type); - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->optimize(WANTvalue); /* This is where variables are allowed as case expressions. */ @@ -3069,8 +3081,10 @@ Statement *CaseStatement::semantic(Scope *sc) goto L1; } } + else + exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring && exp->op != TOKint64) + if (exp->op != TOKstring && exp->op != TOKint64 && exp->op != TOKerror) { error("case must be a string or an integral constant, not %s", exp->toChars()); exp = new IntegerExp(0); @@ -3175,13 +3189,19 @@ Statement *CaseRangeStatement::semantic(Scope *sc) first = first->semantic(sc); first = first->implicitCastTo(sc, sw->condition->type); first = first->optimize(WANTvalue | WANTinterpret); - uinteger_t fval = first->toInteger(); + last = last->semantic(sc); last = last->implicitCastTo(sc, sw->condition->type); last = last->optimize(WANTvalue | WANTinterpret); + + if (first->op == TOKerror || last->op == TOKerror) + return statement ? statement->semantic(sc) : NULL; + + uinteger_t fval = first->toInteger(); uinteger_t lval = last->toInteger(); + if ( (first->type->isunsigned() && fval > lval) || (!first->type->isunsigned() && (sinteger_t)fval > (sinteger_t)lval)) { @@ -3210,7 +3230,7 @@ Statement *CaseRangeStatement::semantic(Scope *sc) { Statement *s = statement; if (i != lval) // if not last case - s = new ExpStatement(loc, NULL); + s = new ExpStatement(loc, (Expression *)NULL); Expression *e = new IntegerExp(loc, i, first->type); Statement *cs = new CaseStatement(loc, e, s); statements->push(cs); @@ -3527,7 +3547,7 @@ Statement *ReturnStatement::semantic(Scope *sc) Type *tfret = tf->nextOf(); if (tfret) { - if (!exp->type->equals(tfret)) + if (tfret != Type::terror && !exp->type->equals(tfret)) error("mismatched function return type inference of %s and %s", exp->type->toChars(), tfret->toChars()); @@ -4003,7 +4023,7 @@ Statement *SynchronizedStatement::semantic(Scope *sc) VarDeclaration *tmp = new VarDeclaration(loc, exp->type, id, ie); Statements *cs = new Statements(); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs->push(new ExpStatement(loc, tmp)); #if IN_LLVM // LDC: Build args @@ -4045,7 +4065,7 @@ Statement *SynchronizedStatement::semantic(Scope *sc) tmp->storage_class |= STCgshared | STCstatic; Statements *cs = new Statements(); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs->push(new ExpStatement(loc, tmp)); #if IN_LLVM // LDC: Build args @@ -4148,6 +4168,8 @@ Statement *WithStatement::semantic(Scope *sc) //printf("WithStatement::semantic()\n"); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + if (exp->op == TOKerror) + return NULL; if (exp->op == TOKimport) { ScopeExp *es = (ScopeExp *)exp; @@ -4537,7 +4559,7 @@ int OnScopeStatement::usesEH() return 1; } -void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +Statement *OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) { //printf("OnScopeStatement::scopeCode()\n"); //print(); @@ -4557,17 +4579,17 @@ void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexc case TOKon_scope_success: { /* Create: - * sentry: int x = 0; - * sexception: x = 1; + * sentry: bool x = false; + * sexception: x = true; * sfinally: if (!x) statement; */ Identifier *id = Lexer::uniqueId("__os"); - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); - VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new DeclarationStatement(loc, v); + ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0, 0, Type::tbool)); + VarDeclaration *v = new VarDeclaration(loc, Type::tbool, id, ie); + *sentry = new ExpStatement(loc, v); - Expression *e = new IntegerExp(1); + Expression *e = new IntegerExp(0, 1, Type::tbool); e = new AssignExp(0, new VarExp(0, v), e); *sexception = new ExpStatement(0, e); @@ -4581,6 +4603,7 @@ void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexc default: assert(0); } + return NULL; } /******************************** ThrowStatement ***************************/ @@ -4611,6 +4634,8 @@ Statement *ThrowStatement::semantic(Scope *sc) #endif exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + if (exp->op == TOKerror) + return this; ClassDeclaration *cd = exp->type->toBasetype()->isClassHandle(); if (!cd || ((cd != ClassDeclaration::throwable) && !ClassDeclaration::throwable->isBaseOf(cd, NULL))) error("can only throw class objects derived from Throwable, not type %s", exp->type->toChars()); @@ -4697,6 +4722,57 @@ void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } +/******************************** DebugStatement **************************/ + +DebugStatement::DebugStatement(Loc loc, Statement *statement) + : Statement(loc) +{ + this->statement = statement; +} + +Statement *DebugStatement::syntaxCopy() +{ + DebugStatement *s = new DebugStatement(loc, + statement ? statement->syntaxCopy() : NULL); + return s; +} + +Statement *DebugStatement::semantic(Scope *sc) +{ + if (statement) + { + sc = sc->push(); + sc->flags |= SCOPEdebug; + statement = statement->semantic(sc); + sc->pop(); + } + return statement; +} + +Statements *DebugStatement::flatten(Scope *sc) +{ + Statements *a = statement ? statement->flatten(sc) : NULL; + if (a) + { for (size_t i = 0; i < a->dim; i++) + { Statement *s = (Statement *)a->data[i]; + + s = new DebugStatement(loc, s); + a->data[i] = s; + } + } + + return a; +} + +void DebugStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (statement) + { + statement->toCBuffer(buf, hgs); + } +} + + /******************************** GotoStatement ***************************/ GotoStatement::GotoStatement(Loc loc, Identifier *ident) @@ -4817,7 +4893,7 @@ Statements *LabelStatement::flatten(Scope *sc) { if (!a->dim) { - a->push(new ExpStatement(loc, NULL)); + a->push(new ExpStatement(loc, (Expression *)NULL)); } Statement *s = (Statement *)a->data[0]; diff --git a/dmd2/statement.h b/dmd2/statement.h index c8b7be52..d96c3f67 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -27,7 +27,7 @@ struct Expression; struct LabelDsymbol; struct Identifier; struct IfStatement; -struct DeclarationStatement; +struct ExpStatement; struct DefaultStatement; struct VarDeclaration; struct Condition; @@ -113,9 +113,6 @@ struct Statement : Object void error(const char *format, ...) IS_PRINTF(2); void warning(const char *format, ...) IS_PRINTF(2); virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual TryCatchStatement *isTryCatchStatement() { return NULL; } - virtual GotoStatement *isGotoStatement() { return NULL; } - virtual AsmStatement *isAsmStatement() { return NULL; } virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; } #if IN_LLVM virtual LabelStatement *isLabelStatement() { return NULL; } @@ -133,7 +130,7 @@ struct Statement : Object virtual int blockExit(bool mustNotThrow); virtual int comeFrom(); virtual int isEmpty(); - virtual void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + virtual Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); virtual Statements *flatten(Scope *sc); virtual Expression *interpret(InterState *istate); @@ -145,7 +142,7 @@ struct Statement : Object virtual void toIR(IRState *irs); // Avoid dynamic_cast - virtual DeclarationStatement *isDeclarationStatement() { return NULL; } + virtual ExpStatement *isExpStatement() { return NULL; } virtual CompoundStatement *isCompoundStatement() { return NULL; } virtual ReturnStatement *isReturnStatement() { return NULL; } virtual IfStatement *isIfStatement() { return NULL; } @@ -170,12 +167,14 @@ struct ExpStatement : Statement Expression *exp; ExpStatement(Loc loc, Expression *exp); + ExpStatement(Loc loc, Dsymbol *s); Statement *syntaxCopy(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *semantic(Scope *sc); Expression *interpret(InterState *istate); int blockExit(bool mustNotThrow); int isEmpty(); + Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); @@ -183,6 +182,7 @@ struct ExpStatement : Statement void toIR(IRState *irs); + ExpStatement *isExpStatement() { return this; } #if IN_LLVM void toNakedIR(IRState *irs); #endif @@ -199,20 +199,6 @@ struct CompileStatement : Statement Statement *semantic(Scope *sc); }; -struct DeclarationStatement : ExpStatement -{ - // Doing declarations as an expression, rather than a statement, - // makes inlining functions much easier. - - DeclarationStatement(Loc loc, Dsymbol *s); - DeclarationStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - - DeclarationStatement *isDeclarationStatement() { return this; } -}; - struct CompoundStatement : Statement { Statements *statements; @@ -351,7 +337,7 @@ struct ForStatement : Statement ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); Statement *syntaxCopy(); Statement *semantic(Scope *sc); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); int hasBreak(); int hasContinue(); int usesEH(); @@ -764,7 +750,6 @@ struct TryCatchStatement : Statement void toIR(IRState *irs); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - TryCatchStatement *isTryCatchStatement() { return this; } }; struct Catch : Object @@ -813,7 +798,7 @@ struct OnScopeStatement : Statement void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Statement *semantic(Scope *sc); int usesEH(); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); Expression *interpret(InterState *istate); void toIR(IRState *irs); @@ -851,6 +836,17 @@ struct VolatileStatement : Statement void toIR(IRState *irs); }; +struct DebugStatement : Statement +{ + Statement *statement; + + DebugStatement(Loc loc, Statement *statement); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Statements *flatten(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + struct GotoStatement : Statement { Identifier *ident; @@ -866,7 +862,6 @@ struct GotoStatement : Statement void toIR(IRState *irs); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - GotoStatement *isGotoStatement() { return this; } }; struct LabelStatement : Statement @@ -928,7 +923,6 @@ struct AsmStatement : Statement Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual AsmStatement *isAsmStatement() { return this; } void toIR(IRState *irs); diff --git a/dmd2/staticassert.c b/dmd2/staticassert.c index fcbe913e..88b2c70a 100644 --- a/dmd2/staticassert.c +++ b/dmd2/staticassert.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -52,10 +52,12 @@ void StaticAssert::semantic(Scope *sc) void StaticAssert::semantic2(Scope *sc) { - Expression *e; - //printf("StaticAssert::semantic2() %s\n", toChars()); - e = exp->semantic(sc); + ScopeDsymbol *sd = new ScopeDsymbol(); + sc = sc->push(sd); + sc->flags |= SCOPEstaticassert; + Expression *e = exp->semantic(sc); + sc = sc->pop(); if (e->op == TOKerror) return; e = e->optimize(WANTvalue | WANTinterpret); diff --git a/dmd2/struct.c b/dmd2/struct.c index d6a1789e..c045b279 100644 --- a/dmd2/struct.c +++ b/dmd2/struct.c @@ -254,6 +254,57 @@ int AggregateDeclaration::isNested() return isnested; } +/**************************************** + * If field[indx] is not part of a union, return indx. + * Otherwise, return the lowest field index of the union. + */ +int AggregateDeclaration::firstFieldInUnion(int indx) +{ + if (isUnionDeclaration()) + return 0; + VarDeclaration * vd = (VarDeclaration *)fields.data[indx]; + int firstNonZero = indx; // first index in the union with non-zero size + for (; ;) + { + if (indx == 0) + return firstNonZero; + VarDeclaration * v = (VarDeclaration *)fields.data[indx - 1]; + if (v->offset != vd->offset) + return firstNonZero; + --indx; + /* If it is a zero-length field, it's ambiguous: we don't know if it is + * in the union unless we find an earlier non-zero sized field with the + * same offset. + */ + if (v->size(loc) != 0) + firstNonZero = indx; + } +} + +/**************************************** + * Count the number of fields starting at firstIndex which are part of the + * same union as field[firstIndex]. If not a union, return 1. + */ +int AggregateDeclaration::numFieldsInUnion(int firstIndex) +{ + VarDeclaration * vd = (VarDeclaration *)fields.data[firstIndex]; + /* If it is a zero-length field, AND we can't find an earlier non-zero + * sized field with the same offset, we assume it's not part of a union. + */ + if (vd->size(loc) == 0 && !isUnionDeclaration() && + firstFieldInUnion(firstIndex) == firstIndex) + return 1; + int count = 1; + for (int i = firstIndex+1; i < fields.dim; ++i) + { + VarDeclaration * v = (VarDeclaration *)fields.data[i]; + // If offsets are different, they are not in the same union + if (v->offset != vd->offset) + break; + ++count; + } + return count; +} /********************************* StructDeclaration ****************************/ @@ -630,7 +681,7 @@ Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) { //printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars()); - if (scope) + if (scope && !symtab) semantic(scope); if (!members || !symtab) diff --git a/dmd2/template.c b/dmd2/template.c index d18ae75e..8a9b01c2 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -4215,7 +4215,7 @@ void TemplateInstance::semanticTiargs(Scope *sc) void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags) { // Run semantic on each argument, place results in tiargs[] - //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); + //printf("+TemplateInstance::semanticTiargs()\n"); if (!tiargs) return; for (size_t j = 0; j < tiargs->dim; j++) @@ -4239,7 +4239,9 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f * match with an 'alias' parameter. Instead, do the * const substitution in TemplateValueParameter::matchArg(). */ - if (ea->op != TOKvar || flags & 1) + if (flags & 1) // only used by __traits, must not interpret the args + ea = ea->optimize(WANTvalue); + else if (ea->op != TOKvar) ea = ea->optimize(WANTvalue | WANTinterpret); tiargs->data[j] = ea; } @@ -4288,7 +4290,9 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f } assert(ea); ea = ea->semantic(sc); - if (ea->op != TOKvar || flags & 1) + if (flags & 1) // only used by __traits, must not interpret the args + ea = ea->optimize(WANTvalue); + else if (ea->op != TOKvar) ea = ea->optimize(WANTvalue | WANTinterpret); tiargs->data[j] = ea; if (ea->op == TOKtype) @@ -4321,7 +4325,7 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f //printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]); } #if 0 - printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this); + printf("-TemplateInstance::semanticTiargs()\n"); for (size_t j = 0; j < tiargs->dim; j++) { Object *o = (Object *)tiargs->data[j]; @@ -4718,8 +4722,8 @@ Identifier *TemplateInstance::genIdent(Objects *args) Lea: sinteger_t v; real_t r; - - ea = ea->optimize(WANTvalue | WANTinterpret); + // Don't interpret it yet, it might actually be an alias + ea = ea->optimize(WANTvalue); if (ea->op == TOKvar) { sa = ((VarExp *)ea)->var; @@ -4737,6 +4741,8 @@ Identifier *TemplateInstance::genIdent(Objects *args) { ea->error("tuple is not a valid template value argument"); continue; } + // Now that we know it is not an alias, we MUST obtain a value + ea = ea->optimize(WANTvalue | WANTinterpret); #if 1 /* Use deco that matches what it would be for a function parameter */ diff --git a/dmd2/traits.c b/dmd2/traits.c index 004e770c..0753ad23 100644 --- a/dmd2/traits.c +++ b/dmd2/traits.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -196,6 +196,21 @@ Expression *TraitsExp::semantic(Scope *sc) StringExp *se = new StringExp(loc, s->ident->toChars()); return se->semantic(sc); } + else if (ident == Id::parent) + { + if (dim != 1) + goto Ldimerror; + Object *o = (Object *)args->data[0]; + Dsymbol *s = getDsymbol(o); + if (s) + s = s->toParent(); + if (!s) + { + error("argument %s has no parent", o->toChars()); + goto Lfalse; + } + return (new DsymbolExp(loc, s))->semantic(sc); + } #endif else if (ident == Id::hasMember || diff --git a/gen/asm-x86-32.h b/gen/asm-x86-32.h index 0625486a..51dd7eb1 100644 --- a/gen/asm-x86-32.h +++ b/gen/asm-x86-32.h @@ -991,8 +991,8 @@ namespace AsmParserx8632 { "pop", Op_DstW }, { "popa", Op_SizedStack }, // For intel this is always 16-bit { "popad", Op_SizedStack }, // GAS doesn't accept 'popad' -- these clobber everything, but supposedly it would be used to preserve clobbered regs - { "popf", Op_SizedStack }, // rewrite the insn with a special case - { "popfd", Op_SizedStack }, + { "popf", Op_0 }, // rewrite the insn with a special case + { "popfd", Op_0 }, { "por", Op_DstSrcMMX }, { "prefetchnta", Op_SrcMemNT }, { "prefetcht0", Op_SrcMemNT }, @@ -1033,8 +1033,8 @@ namespace AsmParserx8632 { "push", Op_push }, { "pusha", Op_SizedStack }, { "pushad", Op_SizedStack }, - { "pushf", Op_SizedStack }, - { "pushfd", Op_SizedStack }, + { "pushf", Op_0 }, + { "pushfd", Op_0 }, { "pxor", Op_DstSrcMMX }, { "rcl", Op_Shift }, // limited src operands -- change to shift { "rcpps", Op_DstSrcSSE }, diff --git a/gen/asm-x86-64.h b/gen/asm-x86-64.h index 32b783d3..aaaaa28a 100644 --- a/gen/asm-x86-64.h +++ b/gen/asm-x86-64.h @@ -1111,8 +1111,8 @@ namespace AsmParserx8664 { "pmullw", Op_DstSrcMMX }, { "pmuludq", Op_DstSrcMMX }, // also sse { "pop", Op_DstW }, - { "popf", Op_SizedStack }, // rewrite the insn with a special case - { "popfq", Op_SizedStack }, + { "popf", Op_0 }, // rewrite the insn with a special case + { "popfq", Op_0 }, { "popq", Op_push }, { "por", Op_DstSrcMMX }, { "prefetchnta", Op_SrcMemNT }, @@ -1156,8 +1156,8 @@ namespace AsmParserx8664 { "punpcklqdq",Op_DstSrcMMX }, { "punpcklwd", Op_DstSrcMMX }, { "push", Op_push }, - { "pushf", Op_SizedStack }, - { "pushfq", Op_SizedStack }, + { "pushf", Op_0 }, + { "pushfq", Op_0 }, { "pushq", Op_push }, { "pxor", Op_DstSrcMMX }, { "rcl", Op_Shift }, // limited src operands -- change to shift diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index aa03a2eb..444a4aeb 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -415,7 +415,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs, int op) DtoArrayInit(loc, lhs, rhs, op); } #if DMDV2 - else if (DtoArrayElementType(t)->equals(t2)) { + else if (stripModifiers(DtoArrayElementType(t))->equals(stripModifiers(t2))) { DtoArrayInit(loc, s, rhs, op); } else if (op != -1 && op != TOKblit && arrayNeedsPostblit(t)) {