diff --git a/dmd/access.c b/dmd/access.c index 8e9282a9..91f09e5c 100644 --- a/dmd/access.c +++ b/dmd/access.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -91,7 +91,7 @@ enum PROT ClassDeclaration::getAccess(Dsymbol *smember) break; case PROTprivate: - access = PROTnone; // private members of base class not accessible + access_ret = PROTnone; // private members of base class not accessible break; case PROTpackage: diff --git a/dmd/aggregate.h b/dmd/aggregate.h index b7dc8f2d..32d6a3ec 100644 --- a/dmd/aggregate.h +++ b/dmd/aggregate.h @@ -105,6 +105,7 @@ struct AggregateDeclaration : ScopeDsymbol int isDeprecated(); // is aggregate deprecated? FuncDeclaration *buildDtor(Scope *sc); int isNested(); + int isExport(); void emitComment(Scope *sc); void toJsonBuffer(OutBuffer *buf); @@ -275,6 +276,7 @@ struct ClassDeclaration : AggregateDeclaration virtual int isBaseInfoComplete(); Dsymbol *search(Loc, Identifier *ident, int flags); + Dsymbol *searchBase(Loc, Identifier *ident); #if DMDV2 int isFuncHidden(FuncDeclaration *fd); #endif diff --git a/dmd/apply.c b/dmd/apply.c new file mode 100644 index 00000000..f5a5ede8 --- /dev/null +++ b/dmd/apply.c @@ -0,0 +1,165 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2011 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include + +#include "mars.h" +#include "expression.h" + + +/************************************** + * An Expression tree walker that will visit each Expression e in the tree, + * in depth-first evaluation order, and call fp(e,param) on it. + * fp() signals whether the walking continues with its return value: + * Returns: + * 0 continue + * 1 done + * It's a bit slower than using virtual functions, but more encapsulated and less brittle. + * Creating an iterator for this would be much more complex. + */ + +typedef int (*fp_t)(Expression *, void *); + +int Expression::apply(fp_t fp, void *param) +{ + return (*fp)(this, param); +} + +/****************************** + * Perform apply() on an array of Expressions. + */ + +int arrayExpressionApply(Expressions *a, fp_t fp, void *param) +{ + //printf("arrayExpressionApply(%p)\n", a); + if (a) + { + for (size_t i = 0; i < a->dim; i++) + { Expression *e = (*a)[i]; + + if (e) + { + if (e->apply(fp, param)) + return 1; + } + } + } + return 0; +} + +int NewExp::apply(int (*fp)(Expression *, void *), void *param) +{ + //printf("NewExp::apply(): %s\n", toChars()); + + return ((thisexp ? thisexp->apply(fp, param) : 0) || + arrayExpressionApply(newargs, fp, param) || + arrayExpressionApply(arguments, fp, param) || + (*fp)(this, param)); +} + +int NewAnonClassExp::apply(int (*fp)(Expression *, void *), void *param) +{ + //printf("NewAnonClassExp::apply(): %s\n", toChars()); + + return ((thisexp ? thisexp->apply(fp, param) : 0) || + arrayExpressionApply(newargs, fp, param) || + arrayExpressionApply(arguments, fp, param) || + (*fp)(this, param)); +} + +int UnaExp::apply(fp_t fp, void *param) +{ + return e1->apply(fp, param) || + (*fp)(this, param); +} + +int BinExp::apply(fp_t fp, void *param) +{ + return e1->apply(fp, param) || + e2->apply(fp, param) || + (*fp)(this, param); +} + +int AssertExp::apply(fp_t fp, void *param) +{ + //printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars()); + return e1->apply(fp, param) || + (msg ? msg->apply(fp, param) : 0) || + (*fp)(this, param); +} + + +int CallExp::apply(fp_t fp, void *param) +{ + //printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars()); + return e1->apply(fp, param) || + arrayExpressionApply(arguments, fp, param) || + (*fp)(this, param); +} + + +int ArrayExp::apply(fp_t fp, void *param) +{ + //printf("ArrayExp::apply(fp_t fp, void *param): %s\n", toChars()); + return e1->apply(fp, param) || + arrayExpressionApply(arguments, fp, param) || + (*fp)(this, param); +} + + +int SliceExp::apply(fp_t fp, void *param) +{ + return e1->apply(fp, param) || + (lwr ? lwr->apply(fp, param) : 0) || + (upr ? upr->apply(fp, param) : 0) || + (*fp)(this, param); +} + + +int ArrayLiteralExp::apply(fp_t fp, void *param) +{ + return arrayExpressionApply(elements, fp, param) || + (*fp)(this, param); +} + + +int AssocArrayLiteralExp::apply(fp_t fp, void *param) +{ + return arrayExpressionApply(keys, fp, param) || + arrayExpressionApply(values, fp, param) || + (*fp)(this, param); +} + + +int StructLiteralExp::apply(fp_t fp, void *param) +{ + return arrayExpressionApply(elements, fp, param) || + (*fp)(this, param); +} + + +int TupleExp::apply(fp_t fp, void *param) +{ + return arrayExpressionApply(exps, fp, param) || + (*fp)(this, param); +} + + +int CondExp::apply(fp_t fp, void *param) +{ + return econd->apply(fp, param) || + e1->apply(fp, param) || + e2->apply(fp, param) || + (*fp)(this, param); +} + + + diff --git a/dmd/arrayop.c b/dmd/arrayop.c index 87046a64..e043d779 100644 --- a/dmd/arrayop.c +++ b/dmd/arrayop.c @@ -551,7 +551,7 @@ Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \ Expression *ex1 = e1->buildArrayLoop(fparams); \ Parameter *param = (*fparams)[0]; \ param->storageClass = 0; \ - Expression *e = new Str##AssignExp(0, ex1, ex2); \ + Expression *e = new Str##AssignExp(loc, ex1, ex2); \ return e; \ } diff --git a/dmd/arraytypes.h b/dmd/arraytypes.h index dc86bcff..45458ce1 100644 --- a/dmd/arraytypes.h +++ b/dmd/arraytypes.h @@ -53,12 +53,21 @@ typedef ArrayBase VarDeclarations; typedef ArrayBase Types; typedef ArrayBase ScopeDsymbols; + +typedef ArrayBase Catches; + typedef ArrayBase StaticDtorDeclarations; typedef ArrayBase SharedStaticDtorDeclarations; typedef ArrayBase Modules; typedef ArrayBase CaseStatements; + +typedef ArrayBase CompoundStatements; + +typedef ArrayBase GotoCaseStatements; + typedef ArrayBase TemplateInstances; +typedef ArrayBase Blocks; typedef ArrayBase Symbols; diff --git a/dmd/attrib.c b/dmd/attrib.c index c7f08770..aff21495 100644 --- a/dmd/attrib.c +++ b/dmd/attrib.c @@ -1142,6 +1142,7 @@ void PragmaDeclaration::semantic(Scope *sc) else error("unrecognized pragma(%s)", ident->toChars()); +Ldecl: if (decl) { for (unsigned i = 0; i < decl->dim; i++) @@ -1159,7 +1160,10 @@ void PragmaDeclaration::semantic(Scope *sc) Lnodecl: if (decl) + { error("pragma is missing closing ';'"); + goto Ldecl; // do them anyway, to avoid segfaults. + } } int PragmaDeclaration::oneMember(Dsymbol **ps) diff --git a/dmd/cast.c b/dmd/cast.c index 8a5a6622..3176f846 100644 --- a/dmd/cast.c +++ b/dmd/cast.c @@ -1451,10 +1451,14 @@ Expression *BinExp::typeCombine(Scope *sc) } else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) { + if (t1->ty == Tsarray && e2->op == TOKarrayliteral) + goto Lt1; goto Lt2; } else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) { + if (t2->ty == Tsarray && e1->op == TOKarrayliteral) + goto Lt2; goto Lt1; } else if (t1->ty == Tclass || t2->ty == Tclass) diff --git a/dmd/class.c b/dmd/class.c index 988dccd1..24554f91 100644 --- a/dmd/class.c +++ b/dmd/class.c @@ -898,6 +898,23 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) return s; } +Dsymbol *ClassDeclaration::searchBase(Loc loc, Identifier *ident) +{ + // Search bases classes in depth-first, left to right order + + for (size_t i = 0; i < baseclasses->dim; i++) + { + BaseClass *b = (*baseclasses)[i]; + Dsymbol *cdb = b->type->isClassHandle(); + if (cdb->ident->equals(ident)) + return cdb; + cdb = ((ClassDeclaration *)cdb)->searchBase(loc, ident); + if (cdb) + return cdb; + } + return NULL; +} + /********************************************************** * fd is in the vtbl[] for this class. * Return 1 if function is hidden (not findable through search). diff --git a/dmd/constfold.c b/dmd/constfold.c index 85ee51f9..6baf73be 100644 --- a/dmd/constfold.c +++ b/dmd/constfold.c @@ -1244,7 +1244,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; e = ale->elements->tdata()[i]; e->type = type; - if (e->checkSideEffect(2)) + if (e->hasSideEffect()) e = EXP_CANT_INTERPRET; } } @@ -1262,7 +1262,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) else { e = ale->elements->tdata()[i]; e->type = type; - if (e->checkSideEffect(2)) + if (e->hasSideEffect()) e = EXP_CANT_INTERPRET; } } @@ -1282,7 +1282,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) if (ex->isBool(TRUE)) { e = ae->values->tdata()[i]; e->type = type; - if (e->checkSideEffect(2)) + if (e->hasSideEffect()) e = EXP_CANT_INTERPRET; break; } @@ -1335,7 +1335,7 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) } else if (e1->op == TOKarrayliteral && lwr->op == TOKint64 && upr->op == TOKint64 && - !e1->checkSideEffect(2)) + !e1->hasSideEffect()) { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; uinteger_t ilwr = lwr->toInteger(); uinteger_t iupr = upr->toInteger(); @@ -1359,6 +1359,64 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) return e; } +/* Set a slice of char array literal 'existingAE' from a string 'newval'. + * existingAE[firstIndex..firstIndex+newval.length] = newval. + */ +void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex) +{ + size_t newlen = newval->len; + size_t sz = newval->sz; + unsigned char *s = (unsigned char *)newval->string; + Type *elemType = existingAE->type->nextOf(); + for (size_t j = 0; j < newlen; j++) + { + 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; + } + existingAE->elements->tdata()[j+firstIndex] + = new IntegerExp(newval->loc, val, elemType); + } +} + +/* Set a slice of string 'existingSE' from a char array literal 'newae'. + * existingSE[firstIndex..firstIndex+newae.length] = newae. + */ +void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex) +{ + unsigned char *s = (unsigned char *)existingSE->string; + for (size_t j = 0; j < newae->elements->dim; j++) + { + unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger()); + switch (existingSE->sz) + { + case 1: s[j+firstIndex] = value; break; + case 2: ((unsigned short *)s)[j+firstIndex] = value; break; + case 4: ((unsigned *)s)[j+firstIndex] = value; break; + default: + assert(0); + break; + } + } +} + +/* Set a slice of string 'existingSE' from a string 'newstr'. + * existingSE[firstIndex..firstIndex+newstr.length] = newstr. + */ +void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex) +{ + unsigned char *s = (unsigned char *)existingSE->string; + size_t sz = existingSE->sz; + assert(sz == newstr->sz); + memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len); +} + /* Also return EXP_CANT_INTERPRET if this fails */ Expression *Cat(Type *type, Expression *e1, Expression *e2) @@ -1468,62 +1526,42 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) else if (e2->op == TOKstring && e1->op == TOKarrayliteral && t1->nextOf()->isintegral()) { - // Concatenate the strings - StringExp *es1 = (StringExp *)e2; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1; - size_t len = es1->len + es2->elements->dim; - int sz = es1->sz; - - void *s = mem.malloc((len + 1) * sz); - memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz); - for (size_t i = 0; i < es2->elements->dim; i++) - { Expression *es2e = es2->elements->tdata()[i]; - if (es2e->op != TOKint64) - return EXP_CANT_INTERPRET; - dinteger_t v = es2e->toInteger(); - memcpy((unsigned char *)s + i * sz, &v, sz); + // [chars] ~ string --> [chars] + StringExp *es = (StringExp *)e2; + ArrayLiteralExp *ea = (ArrayLiteralExp *)e1; + size_t len = es->len + ea->elements->dim; + Expressions * elems = new Expressions; + elems->setDim(len); + for (size_t i= 0; i < ea->elements->dim; ++i) + { + elems->tdata()[i] = ea->elements->tdata()[i]; } - - // 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; + ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); + dest->type = type; + sliceAssignArrayLiteralFromString(dest, es, ea->elements->dim); + return dest; } else if (e1->op == TOKstring && e2->op == TOKarrayliteral && t2->nextOf()->isintegral()) { - // Concatenate the strings - StringExp *es1 = (StringExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - size_t len = es1->len + es2->elements->dim; - int sz = es1->sz; - - void *s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - for (size_t i = 0; i < es2->elements->dim; i++) - { Expression *es2e = es2->elements->tdata()[i]; - if (es2e->op != TOKint64) - return EXP_CANT_INTERPRET; - dinteger_t v = es2e->toInteger(); - memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz); + // string ~ [chars] --> [chars] + StringExp *es = (StringExp *)e1; + ArrayLiteralExp *ea = (ArrayLiteralExp *)e2; + size_t len = es->len + ea->elements->dim; + Expressions * elems = new Expressions; + elems->setDim(len); + for (size_t i= 0; i < ea->elements->dim; ++i) + { + elems->tdata()[es->len + i] = ea->elements->tdata()[i]; } - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - StringExp *es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = 0; //es1->committed; - es->type = type; - e = es; + ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); + dest->type = type; + sliceAssignArrayLiteralFromString(dest, es, 0); + return dest; } else if (e1->op == TOKstring && e2->op == TOKint64) { - // Concatenate the strings + // string ~ char --> string void *s; StringExp *es1 = (StringExp *)e1; StringExp *es; diff --git a/dmd/declaration.c b/dmd/declaration.c index 313f03f3..a9335756 100644 --- a/dmd/declaration.c +++ b/dmd/declaration.c @@ -470,6 +470,7 @@ void AliasDeclaration::semantic(Scope *sc) #endif storage_class |= sc->stc & STCdeprecated; + protection = sc->protection; // Given: // alias foo.bar.abc def; diff --git a/dmd/declaration.h b/dmd/declaration.h index 98bf0fac..c6edf0ef 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -291,10 +291,7 @@ struct VarDeclaration : Declaration bool hasValue(); void setValueNull(); void setValueWithoutChecking(Expression *newval); - void createRefValue(Expression *newval); - void setRefValue(Expression *newval); - void setStackValue(Expression *newval); - void createStackValue(Expression *newval); + void setValue(Expression *newval); #if DMDV2 VarDeclaration *rundtor; // if !NULL, rundtor is tested at runtime to see @@ -717,15 +714,17 @@ struct FuncDeclaration : Declaration int vtblIndex; // for member functions, index into vtbl[] int naked; // !=0 if naked int inlineAsm; // !=0 if has inline assembler - ILS inlineStatus; + ILS inlineStatusStmt; + ILS inlineStatusExp; int inlineNest; // !=0 if nested inline - int cantInterpret; // !=0 if cannot interpret function + int isArrayOp; // !=0 if array operation int semanticRun; // 1 semantic() run // 2 semantic2() run // 3 semantic3() started // 4 semantic3() done // 5 toObjFile() run // this function's frame ptr + int semantic3Errors; // !=0 if errors in semantic3 ForeachStatement *fes; // if foreach body, this is the foreach int introducing; // !=0 if 'introducing' function Type *tintro; // if !=NULL, then this is the type @@ -803,18 +802,20 @@ struct FuncDeclaration : Declaration int isTrusted(); virtual int isNested(); int needThis(); + int isVirtualMethod(); virtual int isVirtual(); virtual int isFinal(); virtual int addPreInvariant(); virtual int addPostInvariant(); Expression *interpret(InterState *istate, Expressions *arguments, Expression *thisexp = NULL); void inlineScan(); - int canInline(int hasthis, int hdrscan = 0); - Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); + int canInline(int hasthis, int hdrscan = false, int statementsToo = true); + Expression *expandInline(InlineScanState *iss, Expression *ethis, Expressions *arguments, Statement **ps); const char *kind(); void toDocBuffer(OutBuffer *buf); FuncDeclaration *isUnique(); int needsClosure(); + int hasNestedFrameRefs(); Statement *mergeFrequire(Statement *); Statement *mergeFensure(Statement *); Parameters *getParameters(int *pvarargs); @@ -854,9 +855,6 @@ struct FuncDeclaration : Declaration typedef std::map LabelMap; LabelMap labmap; - // if this is an array operation it gets a little special attention - bool isArrayOp; - // Functions that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. bool availableExternally; diff --git a/dmd/delegatize.c b/dmd/delegatize.c index 72fe66b5..617ece35 100644 --- a/dmd/delegatize.c +++ b/dmd/delegatize.c @@ -28,6 +28,9 @@ * t delegate() { return expr; } */ +int lambdaSetParent(Expression *e, void *param); +int lambdaCheckForNestedRef(Expression *e, void *param); + Expression *Expression::toDelegate(Scope *sc, Type *t) { //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars()); @@ -35,180 +38,103 @@ Expression *Expression::toDelegate(Scope *sc, Type *t) FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL); Expression *e; -#if 1 sc = sc->push(); sc->parent = fld; // set current function to be the delegate e = this; - e->scanForNestedRef(sc); + e->apply(&lambdaSetParent, sc); + e->apply(&lambdaCheckForNestedRef, sc); sc = sc->pop(); -#else - e = this->syntaxCopy(); -#endif - Statement *s = new ReturnStatement(loc, e); + Statement *s; + if (t->ty == Tvoid) + s = new ExpStatement(loc, e); + else + s = new ReturnStatement(loc, e); fld->fbody = s; e = new FuncExp(loc, fld); e = e->semantic(sc); return e; } -/****************************** - * Perform scanForNestedRef() on an array of Expressions. +/****************************************** + * Patch the parent of declarations to be the new function literal. */ - -void arrayExpressionScanForNestedRef(Scope *sc, Expressions *a) +int lambdaSetParent(Expression *e, void *param) { - //printf("arrayExpressionScanForNestedRef(%p)\n", a); - if (a) + Scope *sc = (Scope *)param; + /* We could use virtual functions instead of a switch, + * but it doesn't seem worth the bother. + */ + switch (e->op) { - for (size_t i = 0; i < a->dim; i++) - { Expression *e = (*a)[i]; - - if (e) - { - e->scanForNestedRef(sc); - } + case TOKdeclaration: + { DeclarationExp *de = (DeclarationExp *)e; + de->declaration->parent = sc->parent; + break; } + + case TOKindex: + { IndexExp *de = (IndexExp *)e; + if (de->lengthVar) + { //printf("lengthVar\n"); + de->lengthVar->parent = sc->parent; + } + break; + } + + case TOKslice: + { SliceExp *se = (SliceExp *)e; + if (se->lengthVar) + { //printf("lengthVar\n"); + se->lengthVar->parent = sc->parent; + } + break; + } + + default: + break; } + return 0; } -void Expression::scanForNestedRef(Scope *sc) +/******************************************* + * Look for references to variables in a scope enclosing the new function literal. + */ +int lambdaCheckForNestedRef(Expression *e, void *param) { - //printf("Expression::scanForNestedRef(%s)\n", toChars()); -} + Scope *sc = (Scope *)param; + /* We could use virtual functions instead of a switch, + * but it doesn't seem worth the bother. + */ + switch (e->op) + { + case TOKsymoff: + { SymOffExp *se = (SymOffExp *)e; + VarDeclaration *v = se->var->isVarDeclaration(); + if (v) + v->checkNestedReference(sc, 0); + break; + } -void SymOffExp::scanForNestedRef(Scope *sc) -{ - //printf("SymOffExp::scanForNestedRef(%s)\n", toChars()); - VarDeclaration *v = var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); -} + case TOKvar: + { VarExp *ve = (VarExp *)e; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v) + v->checkNestedReference(sc, 0); + break; + } -void VarExp::scanForNestedRef(Scope *sc) -{ - //printf("VarExp::scanForNestedRef(%s)\n", toChars()); - VarDeclaration *v = var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); -} + case TOKthis: + case TOKsuper: + { ThisExp *te = (ThisExp *)e; + VarDeclaration *v = te->var->isVarDeclaration(); + if (v) + v->checkNestedReference(sc, 0); + break; + } -void ThisExp::scanForNestedRef(Scope *sc) -{ - assert(var); - var->isVarDeclaration()->checkNestedReference(sc, 0); -} - -void SuperExp::scanForNestedRef(Scope *sc) -{ - ThisExp::scanForNestedRef(sc); -} - -void FuncExp::scanForNestedRef(Scope *sc) -{ - //printf("FuncExp::scanForNestedRef(%s)\n", toChars()); - //fd->parent = sc->parent; -} - -void DeclarationExp::scanForNestedRef(Scope *sc) -{ - //printf("DeclarationExp::scanForNestedRef() %s\n", toChars()); - declaration->parent = sc->parent; -} - -void NewExp::scanForNestedRef(Scope *sc) -{ - //printf("NewExp::scanForNestedRef(Scope *sc): %s\n", toChars()); - - if (thisexp) - thisexp->scanForNestedRef(sc); - arrayExpressionScanForNestedRef(sc, newargs); - arrayExpressionScanForNestedRef(sc, arguments); -} - -void UnaExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); -} - -void BinExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); - e2->scanForNestedRef(sc); -} - -void CallExp::scanForNestedRef(Scope *sc) -{ - //printf("CallExp::scanForNestedRef(Scope *sc): %s\n", toChars()); - e1->scanForNestedRef(sc); - arrayExpressionScanForNestedRef(sc, arguments); -} - - -void IndexExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); - - if (lengthVar) - { //printf("lengthVar\n"); - lengthVar->parent = sc->parent; + default: + break; } - e2->scanForNestedRef(sc); + return 0; } - -void SliceExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); - - if (lengthVar) - { //printf("lengthVar\n"); - lengthVar->parent = sc->parent; - } - if (lwr) - lwr->scanForNestedRef(sc); - if (upr) - upr->scanForNestedRef(sc); -} - - -void ArrayLiteralExp::scanForNestedRef(Scope *sc) -{ - arrayExpressionScanForNestedRef(sc, elements); -} - - -void AssocArrayLiteralExp::scanForNestedRef(Scope *sc) -{ - arrayExpressionScanForNestedRef(sc, keys); - arrayExpressionScanForNestedRef(sc, values); -} - - -void StructLiteralExp::scanForNestedRef(Scope *sc) -{ - arrayExpressionScanForNestedRef(sc, elements); -} - - -void TupleExp::scanForNestedRef(Scope *sc) -{ - arrayExpressionScanForNestedRef(sc, exps); -} - - -void ArrayExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); - arrayExpressionScanForNestedRef(sc, arguments); -} - - -void CondExp::scanForNestedRef(Scope *sc) -{ - econd->scanForNestedRef(sc); - e1->scanForNestedRef(sc); - e2->scanForNestedRef(sc); -} - - - diff --git a/dmd/doc.c b/dmd/doc.c index 7b7ab95e..5595c9c4 100644 --- a/dmd/doc.c +++ b/dmd/doc.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -227,7 +227,7 @@ void Module::gendocfile() // Override with the ddoc macro files from the command line for (size_t i = 0; i < global.params.ddocfiles->dim; i++) { - FileName f((char *)global.params.ddocfiles->data[i], 0); + FileName f(global.params.ddocfiles->tdata()[i], 0); File file(&f); file.readv(); // BUG: convert file contents to UTF-8 before use @@ -532,7 +532,7 @@ void ScopeDsymbol::emitMemberComments(Scope *sc) sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = (*members)[i]; //printf("\ts = '%s'\n", s->toChars()); s->emitComment(sc); } @@ -704,7 +704,7 @@ void EnumDeclaration::emitComment(Scope *sc) { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = (*members)[i]; s->emitComment(sc); } return; @@ -962,7 +962,7 @@ void ClassDeclaration::toDocBuffer(OutBuffer *buf) } int any = 0; for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *bc = (BaseClass *)baseclasses->data[i]; + { BaseClass *bc = (*baseclasses)[i]; if (bc->protection == PROTprivate) continue; @@ -1116,7 +1116,7 @@ void DocComment::parseSections(unsigned char *comment) goto L1; if (*p == '\n') { p++; - if (*p == '\n' && !summary && !namelen) + if (*p == '\n' && !summary && !namelen && !inCode) { pend = p; p++; diff --git a/dmd/dsymbol.c b/dmd/dsymbol.c index 2e4cc726..1fbf08a2 100644 --- a/dmd/dsymbol.c +++ b/dmd/dsymbol.c @@ -794,6 +794,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) // Look in symbols declared in this module Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; + //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); // hide the aliases generated by selective or renamed private imports if (s && flags & 1) @@ -811,7 +812,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) { // Look in imported modules for (size_t i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss = (*imports)[i]; + { Dsymbol *ss = (*imports)[i]; Dsymbol *s2; // If private import, don't search it @@ -821,7 +822,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); /* Don't find private members if ss is a module */ - s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); + s2 = ss->search(loc, ident, ss->isImport() ? 1 : 0); if (!s) s = s2; else if (s2 && s != s2) @@ -850,7 +851,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) ) ) { - ss->multiplyDefined(loc, s, s2); + ScopeDsymbol::multiplyDefined(loc, s, s2); break; } } @@ -859,14 +860,15 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) if (s) { Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && !d->parent->isTemplateMixin()) + if (d && d->protection == PROTprivate && + !d->parent->isTemplateMixin()) error(loc, "%s is private", d->toPrettyChars()); } } return s; } -void ScopeDsymbol::importScope(ScopeDsymbol *s, enum PROT protection) +void ScopeDsymbol::importScope(Dsymbol *s, enum PROT protection) { //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); @@ -874,11 +876,11 @@ void ScopeDsymbol::importScope(ScopeDsymbol *s, enum PROT protection) if (s != this) { if (!imports) - imports = new ScopeDsymbols(); + imports = new Dsymbols(); else { for (size_t i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss = (*imports)[i]; + { Dsymbol *ss = (*imports)[i]; if (ss == s) // if already imported { if (protection > prots[i]) @@ -995,8 +997,7 @@ static int dimDg(void *ctx, size_t n, Dsymbol *) size_t ScopeDsymbol::dim(Dsymbols *members) { size_t n = 0; - if (members) - foreach(members, &dimDg, &n); + foreach(members, &dimDg, &n); return n; } #endif @@ -1046,7 +1047,9 @@ Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *pn) #if DMDV2 int ScopeDsymbol::foreach(Dsymbols *members, ScopeDsymbol::ForeachDg dg, void *ctx, size_t *pn) { - assert(members); + assert(dg); + if (!members) + return 0; size_t n = pn ? *pn : 0; // take over index int result = 0; diff --git a/dmd/dsymbol.h b/dmd/dsymbol.h index 6ec7e880..c3e8905e 100644 --- a/dmd/dsymbol.h +++ b/dmd/dsymbol.h @@ -285,14 +285,14 @@ struct ScopeDsymbol : Dsymbol Dsymbols *members; // all Dsymbol's in this scope DsymbolTable *symtab; // members[] sorted into table - ScopeDsymbols *imports; // imported ScopeDsymbol's + Dsymbols *imports; // imported Dsymbol's unsigned char *prots; // array of PROT, one for each import ScopeDsymbol(); ScopeDsymbol(Identifier *id); Dsymbol *syntaxCopy(Dsymbol *s); Dsymbol *search(Loc loc, Identifier *ident, int flags); - void importScope(ScopeDsymbol *s, enum PROT protection); + void importScope(Dsymbol *s, enum PROT protection); int isforwardRef(); void defineRef(Dsymbol *s); static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); diff --git a/dmd/expression.c b/dmd/expression.c index 51ea2d9c..980b2258 100644 --- a/dmd/expression.c +++ b/dmd/expression.c @@ -746,11 +746,15 @@ void functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *argum */ if (!tf->parameterEscapes(p)) { + Expression *a = arg; + if (a->op == TOKcast) + a = ((CastExp *)a)->e1; + /* Function literals can only appear once, so if this * appearance was scoped, there cannot be any others. */ - if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; + if (a->op == TOKfunction) + { FuncExp *fe = (FuncExp *)a; fe->fd->tookAddressOf = 0; } @@ -758,8 +762,8 @@ void functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *argum * this doesn't count as taking the address of it. * We only worry about 'escaping' references to the function. */ - else if (arg->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)arg; + else if (a->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)a; if (de->e1->op == TOKvar) { VarExp *ve = (VarExp *)de->e1; FuncDeclaration *f = ve->var->isFuncDeclaration(); @@ -1029,7 +1033,7 @@ void Expression::warning(const char *format, ...) } } -void Expression::rvalue() +int Expression::rvalue() { if (type && type->toBasetype()->ty == Tvoid) { error("expression %s is void and has no value", toChars()); @@ -1037,8 +1041,11 @@ void Expression::rvalue() dump(0); halt(); #endif - type = Type::terror; + if (!global.gag) + type = Type::terror; + return 0; } + return 1; } Expression *Expression::combine(Expression *e1, Expression *e2) @@ -1183,7 +1190,8 @@ Expression *Expression::checkIntegral() Expression *Expression::checkArithmetic() { if (!type->isintegral() && !type->isfloating()) - { error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); + { if (type->toBasetype() != Type::terror) + error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); return new ErrorExp(); } return this; @@ -2644,6 +2652,7 @@ StringExp::StringExp(Loc loc, char *string) this->sz = 1; this->committed = 0; this->postfix = 0; + this->ownedByCtfe = false; } StringExp::StringExp(Loc loc, void *string, size_t len) @@ -2654,6 +2663,7 @@ StringExp::StringExp(Loc loc, void *string, size_t len) this->sz = 1; this->committed = 0; this->postfix = 0; + this->ownedByCtfe = false; } StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix) @@ -2664,6 +2674,7 @@ StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix) this->sz = 1; this->committed = 0; this->postfix = postfix; + this->ownedByCtfe = false; } #if 0 @@ -2676,7 +2687,7 @@ Expression *StringExp::syntaxCopy() int StringExp::equals(Object *o) { - //printf("StringExp::equals('%s')\n", o->toChars()); + //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars()); if (o && o->dyncast() == DYNCAST_EXPRESSION) { Expression *e = (Expression *)o; @@ -2722,7 +2733,7 @@ Expression *StringExp::semantic(Scope *sc) p = utf_decodeChar((unsigned char *)string, len, &u, &c); if (p) { error("%s", p); - break; + return new ErrorExp(); } else { buffer.write4(c); @@ -2743,7 +2754,7 @@ Expression *StringExp::semantic(Scope *sc) p = utf_decodeChar((unsigned char *)string, len, &u, &c); if (p) { error("%s", p); - break; + return new ErrorExp(); } else { buffer.writeUTF16(c); @@ -3038,6 +3049,7 @@ ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) { this->elements = elements; + this->ownedByCtfe = false; } ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) @@ -3116,9 +3128,9 @@ int ArrayLiteralExp::checkSideEffect(int flag) { int f = 0; for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; + { Expression *e = elements->tdata()[i]; - f |= e->checkSideEffect(2); + f |= e->hasSideEffect(); } if (flag == 0 && f == 0) Expression::checkSideEffect(0); @@ -3179,7 +3191,7 @@ void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = elements ? elements->dim : 0; buf->printf("A%zu", dim); for (size_t i = 0; i < dim; i++) - { Expression *e = (Expression *)elements->data[i]; + { Expression *e = elements->tdata()[i]; e->toMangleBuffer(buf); } } @@ -3195,6 +3207,7 @@ AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc, assert(keys->dim == values->dim); this->keys = keys; this->values = values; + this->ownedByCtfe = false; } Expression *AssocArrayLiteralExp::syntaxCopy() @@ -3238,8 +3251,8 @@ int AssocArrayLiteralExp::checkSideEffect(int flag) { Expression *key = (Expression *)keys->data[i]; Expression *value = (Expression *)values->data[i]; - f |= key->checkSideEffect(2); - f |= value->checkSideEffect(2); + f |= key->hasSideEffect(); + f |= value->hasSideEffect(); } if (flag == 0 && f == 0) Expression::checkSideEffect(0); @@ -3507,7 +3520,7 @@ int StructLiteralExp::checkSideEffect(int flag) if (!e) continue; - f |= e->checkSideEffect(2); + f |= e->hasSideEffect(); } if (flag == 0 && f == 0) Expression::checkSideEffect(0); @@ -3701,9 +3714,10 @@ void TemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(td->toChars()); } -void TemplateExp::rvalue() +int TemplateExp::rvalue() { error("template %s has no value", toChars()); + return 0; } /********************** NewExp **************************************/ @@ -3759,7 +3773,7 @@ Lagain: else { error("'this' for nested class must be a class type, not %s", thisexp->type->toChars()); - type = newtype->semantic(loc, sc); + goto Lerr; } } else @@ -3774,7 +3788,9 @@ Lagain: preFunctionParameters(loc, sc, arguments); if (thisexp && tb->ty != Tclass) - error("e.new is only for allocating nested classes, not %s", tb->toChars()); + { error("e.new is only for allocating nested classes, not %s", tb->toChars()); + goto Lerr; + } if (tb->ty == Tclass) { TypeFunction *tf; @@ -3782,14 +3798,17 @@ Lagain: TypeClass *tc = (TypeClass *)(tb); ClassDeclaration *cd = tc->sym->isClassDeclaration(); if (cd->isInterfaceDeclaration()) - error("cannot create instance of interface %s", cd->toChars()); + { error("cannot create instance of interface %s", cd->toChars()); + goto Lerr; + } else if (cd->isAbstract()) { error("cannot create instance of abstract class %s", cd->toChars()); for (size_t i = 0; i < cd->vtbl.dim; i++) - { FuncDeclaration *fd = ((Dsymbol *)cd->vtbl.data[i])->isFuncDeclaration(); + { FuncDeclaration *fd = cd->vtbl.tdata()[i]->isFuncDeclaration(); if (fd && fd->isAbstract()) error("function %s is abstract", fd->toChars()); } + goto Lerr; } checkDeprecated(sc, cd); if (cd->isNested()) @@ -3811,7 +3830,7 @@ Lagain: { if (!sp) { error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - break; + goto Lerr; } ClassDeclaration *cdp = sp->isClassDeclaration(); if (!cdp) @@ -3828,7 +3847,9 @@ Lagain: { //printf("cdthis = %s\n", cdthis->toChars()); if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL)) - error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars()); + { error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars()); + goto Lerr; + } } #if 0 else @@ -3838,7 +3859,7 @@ Lagain: if (!sf) { error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - break; + goto Lerr; } printf("sf = %s\n", sf->toChars()); AggregateDeclaration *ad = sf->isThis(); @@ -3849,7 +3870,9 @@ Lagain: #endif } else if (thisexp) - error("e.new is only for allocating nested classes"); + { error("e.new is only for allocating nested classes"); + goto Lerr; + } else if (fdn) { // make sure the parent context fdn of cd is reachable from sc @@ -3861,13 +3884,15 @@ Lagain: if (!sp || (fsp && fsp->isStatic())) { error("outer function context of %s is needed to 'new' nested class %s", fdn->toPrettyChars(), cd->toPrettyChars()); - break; + goto Lerr; } } } } else if (thisexp) - error("e.new is only for allocating nested classes"); + { error("e.new is only for allocating nested classes"); + goto Lerr; + } FuncDeclaration *f = cd->ctor; if (f) @@ -3885,12 +3910,18 @@ Lagain: if (!arguments) arguments = new Expressions(); + unsigned olderrors = global.errors; functionParameters(loc, sc, tf, arguments); + if (olderrors != global.errors) + return new ErrorExp(); + } else { if (arguments && arguments->dim) - error("no constructor for %s", cd->toChars()); + { error("no constructor for %s", cd->toChars()); + goto Lerr; + } } if (cd->aggNew) @@ -3906,12 +3937,18 @@ Lagain: assert(allocator); tf = (TypeFunction *)f->type; + unsigned olderrors = global.errors; functionParameters(loc, sc, tf, newargs); + if (olderrors != global.errors) + return new ErrorExp(); + } else { if (newargs && newargs->dim) - error("no allocator for %s", cd->toChars()); + { error("no allocator for %s", cd->toChars()); + goto Lerr; + } } } else if (tb->ty == Tstruct) @@ -3939,7 +3976,10 @@ Lagain: assert(allocator); tf = (TypeFunction *)f->type; + unsigned olderrors = global.errors; functionParameters(loc, sc, tf, newargs); + if (olderrors != global.errors) + return new ErrorExp(); e = new VarExp(loc, f); e = new CallExp(loc, e, newargs); @@ -3956,36 +3996,42 @@ Lagain: { if (tb->ty != Tarray) { error("too many arguments for array"); - arguments->dim = i; - break; + goto Lerr; } - Expression *arg = (Expression *)arguments->data[i]; + Expression *arg = arguments->tdata()[i]; arg = resolveProperties(sc, arg); arg = arg->implicitCastTo(sc, Type::tsize_t); if (arg->op == TOKint64 && (long long)arg->toInteger() < 0) - error("negative array index %s", arg->toChars()); - arguments->data[i] = (void *) arg; + { error("negative array index %s", arg->toChars()); + goto Lerr; + } + arguments->tdata()[i] = arg; tb = ((TypeDArray *)tb)->next->toBasetype(); } } else if (tb->isscalar()) { if (arguments && arguments->dim) - error("no constructor for %s", type->toChars()); + { error("no constructor for %s", type->toChars()); + goto Lerr; + } type = type->pointerTo(); } else { error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars()); - type = type->pointerTo(); + goto Lerr; } //printf("NewExp: '%s'\n", toChars()); //printf("NewExp:type '%s'\n", type->toChars()); return this; + +Lerr: + return new ErrorExp(); } int NewExp::checkSideEffect(int flag) @@ -3994,9 +4040,24 @@ int NewExp::checkSideEffect(int flag) } #if DMDV2 -int NewExp::canThrow() +int NewExp::canThrow(bool mustNotThrow) { - return 1; + if (arrayExpressionCanThrow(newargs, mustNotThrow) || + arrayExpressionCanThrow(arguments, mustNotThrow)) + return 1; + if (member) + { + // See if constructor call can throw + Type *t = member->type->toBasetype(); + if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow) + { + if (mustNotThrow) + error("constructor %s is not nothrow", member->toChars()); + return 1; + } + } + // regard storage allocation failures as not recoverable + return 0; } #endif @@ -4499,7 +4560,7 @@ int TupleExp::checkSideEffect(int flag) for (size_t i = 0; i < exps->dim; i++) { Expression *e = (*exps)[i]; - f |= e->checkSideEffect(2); + f |= e->hasSideEffect(); } if (flag == 0 && f == 0) Expression::checkSideEffect(0); @@ -5027,17 +5088,13 @@ Expression *IsExp::semantic(Scope *sc) /* Declare trailing parameters */ for (size_t i = 1; i < parameters->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + { TemplateParameter *tp = (*parameters)[i]; Declaration *s = NULL; m = tp->matchArg(sc, &tiargs, i, parameters, &dedtypes, &s); if (m == MATCHnomatch) goto Lno; s->semantic(sc); -#if 0 - Object *o = (Object *)dedtypes.data[i]; - Dsymbol *s = TemplateDeclaration::declareParameter(loc, sc, tp, o); -#endif if (sc->sd) s->addMember(sc, sc->sd, 1); else if (!sc->insert(s)) @@ -5080,9 +5137,18 @@ Expression *IsExp::semantic(Scope *sc) Lyes: if (id) { - Dsymbol *s = new AliasDeclaration(loc, id, tded); + Dsymbol *s; + Tuple *tup = isTuple(tded); + if (tup) + s = new TupleDeclaration(loc, id, &(tup->objects)); + else + s = new AliasDeclaration(loc, id, tded); s->semantic(sc); - sc->insert(s); + /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there. + * More investigation is needed. + */ + if (!tup && !sc->insert(s)) + error("declaration %s is already defined", s->toChars()); if (sc->sd) s->addMember(sc, sc->sd, 1); } @@ -5732,6 +5798,12 @@ Expression *DotIdExp::semantic(Scope *sc) (ie->sds->isModule() && ie->sds != sc->module) ? 1 : 0); if (s) { + /* Check for access before resolving aliases because public + * aliases to private symbols are public. + */ + if (Declaration *d = s->isDeclaration()) + accessCheck(loc, sc, 0, d); + s = s->toAlias(); checkDeprecated(sc, s); @@ -6606,7 +6678,15 @@ Lagain: } else { + static int nest; + if (++nest > 500) + { + error("recursive evaluation of %s", toChars()); + --nest; + return new ErrorExp(); + } UnaExp::semantic(sc); + --nest; /* Look for e1 being a lazy parameter */ @@ -6627,6 +6707,14 @@ Lagain: e1 = new DsymbolExp(loc, se->sds); e1 = e1->semantic(sc); } +#if DMDV2 + else if (e1->op == TOKsymoff && ((SymOffExp *)e1)->hasOverloads) + { + SymOffExp *se = (SymOffExp *)e1; + e1 = new VarExp(se->loc, se->var, 1); + e1 = e1->semantic(sc); + } +#endif #if 1 // patch for #540 by Oskar Linde else if (e1->op == TOKdotexp) { @@ -6754,9 +6842,7 @@ Lagain: arguments = new Expressions(); f = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); if (!f) - { type = Type::terror; - return this; - } + return new ErrorExp(); ad = td->toParent()->isAggregateDeclaration(); } if (f->needThis()) @@ -6785,7 +6871,10 @@ Lagain: if (!f->needThis()) { VarExp *ve = new VarExp(loc, f); - e1 = new CommaExp(loc, ue->e1, ve); + if ((ue->e1)->op == TOKtype) // just a FQN + e1 = ve; + else // things like (new Foo).bar() + e1 = new CommaExp(loc, ue->e1, ve); e1->type = f->type; } else @@ -6823,16 +6912,14 @@ Lagain: if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) { error("super class constructor call must be in a constructor"); - type = Type::terror; - return this; + return new ErrorExp(); } else { f = cd->baseClass->ctor; if (!f) { error("no super class constructor for %s", cd->baseClass->toChars()); - type = Type::terror; - return this; + return new ErrorExp(); } else { @@ -6854,6 +6941,7 @@ Lagain: checkDeprecated(sc, f); #if DMDV2 checkPurity(sc, f); + checkSafety(sc, f); #endif e1 = new DotVarExp(e1->loc, e1, f); e1 = e1->semantic(sc); @@ -6871,8 +6959,7 @@ Lagain: if (!cd || !sc->func->isCtorDeclaration()) { error("class constructor call must be in a constructor"); - type = Type::terror; - return this; + return new ErrorExp(); } else { @@ -6894,6 +6981,7 @@ Lagain: checkDeprecated(sc, f); #if DMDV2 checkPurity(sc, f); + checkSafety(sc, f); #endif e1 = new DotVarExp(e1->loc, e1, f); e1 = e1->semantic(sc); @@ -6902,14 +6990,15 @@ Lagain: // BUG: this should really be done by checking the static // call graph if (f == sc->func) - error("cyclic constructor call"); + { error("cyclic constructor call"); + return new ErrorExp(); + } } } else if (!t1) { error("function expected before (), not '%s'", e1->toChars()); - type = Type::terror; - return this; + return new ErrorExp(); } else if (t1->ty != Tfunction) { @@ -6920,9 +7009,8 @@ Lagain: goto Lcheckargs; } else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction) - { Expression *e; - - e = new PtrExp(loc, e1); + { + Expression *e = new PtrExp(loc, e1); t1 = ((TypePointer *)t1)->next; e->type = t1; e1 = e; @@ -6932,8 +7020,8 @@ Lagain: TemplateExp *te = (TemplateExp *)e1; f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); if (!f) - { type = Type::terror; - return this; + { + return new ErrorExp(); } if (f->needThis() && hasThis(sc)) { @@ -6949,8 +7037,7 @@ Lagain: } else { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); - type = Type::terror; - return this; + return new ErrorExp(); } } else if (e1->op == TOKvar) @@ -6988,6 +7075,7 @@ Lagain: checkDeprecated(sc, f); #if DMDV2 checkPurity(sc, f); + checkSafety(sc, f); #endif if (f->needThis() && hasThis(sc)) @@ -7014,9 +7102,16 @@ Lcheckargs: if (!arguments) arguments = new Expressions(); + int olderrors = global.errors; functionParameters(loc, sc, tf, arguments); + if (olderrors != global.errors) + return new ErrorExp(); - assert(type); + if (!type) + { + error("forward reference to inferred return type of function call %s", toChars()); + return new ErrorExp(); + } if (f && f->tintro) { @@ -7037,31 +7132,43 @@ Lcheckargs: int CallExp::checkSideEffect(int flag) { #if DMDV2 - if (flag != 2) - return 1; + int result = 1; - if (e1->checkSideEffect(2)) - return 1; + /* Calling a function or delegate that is pure nothrow + * has no side effects. + */ + if (e1->type) + { + Type *t = e1->type->toBasetype(); + if ((t->ty == Tfunction && ((TypeFunction *)t)->purity > PUREweak && + ((TypeFunction *)t)->isnothrow) + || + (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->purity > PUREweak && + ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) + ) + { + result = 0; + //if (flag == 0) + //warning("pure nothrow function %s has no effect", e1->toChars()); + } + else + result = 1; + } + + result |= e1->checkSideEffect(1); /* If any of the arguments have side effects, this expression does */ for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; + { Expression *e = arguments->tdata()[i]; - if (e->checkSideEffect(2)) - return 1; + result |= e->checkSideEffect(1); } - /* If calling a function or delegate that is typed as pure, - * then this expression has no side effects. - */ - Type *t = e1->type->toBasetype(); - if (t->ty == Tfunction && ((TypeFunction *)t)->ispure) - return 0; - if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->ispure) - return 0; -#endif + return result; +#else return 1; +#endif } #if DMDV2 @@ -7284,7 +7391,8 @@ Expression *PtrExp::semantic(Scope *sc) case Terror: return new ErrorExp(); } - rvalue(); + if (!rvalue()) + return new ErrorExp(); } return this; } @@ -8166,7 +8274,7 @@ int CommaExp::isBool(int result) int CommaExp::checkSideEffect(int flag) { if (flag == 2) - return e1->checkSideEffect(2) || e2->checkSideEffect(2); + return e1->hasSideEffect() || e2->hasSideEffect(); else { // Don't check e1 until we cast(void) the a,b code generation @@ -8585,7 +8693,8 @@ Expression *AssignExp::semantic(Scope *sc) } } - e2->rvalue(); + if (!e2->rvalue()) + return new ErrorExp(); if (e1->op == TOKarraylength) { @@ -8628,12 +8737,22 @@ Expression *AssignExp::semantic(Scope *sc) e2->op == TOKmul || e2->op == TOKdiv || e2->op == TOKmod || e2->op == TOKxor || e2->op == TOKand || e2->op == TOKor || +#if DMDV2 + e2->op == TOKpow || +#endif e2->op == TOKtilde || e2->op == TOKneg)) { type = e1->type; return arrayOp(sc); } + if (e1->op == TOKvar && + (((VarExp *)e1)->var->storage_class & STCscope) && + op == TOKassign) + { + error("cannot rebind scope variables"); + } + type = e1->type; assert(type); return this; @@ -8646,7 +8765,7 @@ Expression *AssignExp::checkToBoolean() // are usually mistakes. error("assignment cannot be used as a condition, perhaps == was meant?"); - return this; + return new ErrorExp(); } /************************************************************/ @@ -8853,7 +8972,8 @@ Expression *CatAssignExp::semantic(Scope *sc) Type *tb1 = e1->type->toBasetype(); Type *tb2 = e2->type->toBasetype(); - e2->rvalue(); + if (!e2->rvalue()) + return new ErrorExp(); Type *tb1next = tb1->nextOf(); @@ -9889,7 +10009,7 @@ int OrOrExp::checkSideEffect(int flag) { if (flag == 2) { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); + return e1->hasSideEffect() || e2->hasSideEffect(); } else { e1->checkSideEffect(1); @@ -9964,7 +10084,7 @@ int AndAndExp::checkSideEffect(int flag) { if (flag == 2) { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); + return e1->hasSideEffect() || e2->hasSideEffect(); } else { @@ -10422,9 +10542,9 @@ int CondExp::checkSideEffect(int flag) { if (flag == 2) { - return econd->checkSideEffect(2) || - e1->checkSideEffect(2) || - e2->checkSideEffect(2); + return econd->hasSideEffect() || + e1->hasSideEffect() || + e2->hasSideEffect(); } else { diff --git a/dmd/expression.h b/dmd/expression.h index 53d4ccc3..74933f1e 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -74,6 +74,8 @@ namespace llvm { void initPrecedence(); +typedef int (*apply_fp_t)(Expression *, void *); + Expression *resolveProperties(Scope *sc, Expression *e); void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); Dsymbol *search_function(AggregateDeclaration *ad, Identifier *funcid); @@ -111,6 +113,7 @@ struct Expression : Object Expression(Loc loc, enum TOK op, int size); Expression *copy(); virtual Expression *syntaxCopy(); + virtual int apply(apply_fp_t fp, void *param); virtual Expression *semantic(Scope *sc); Expression *trySemantic(Scope *sc); @@ -121,7 +124,7 @@ struct Expression : Object virtual void dump(int indent); void error(const char *format, ...) IS_PRINTF(2); void warning(const char *format, ...) IS_PRINTF(2); - virtual void rvalue(); + virtual int rvalue(); static Expression *combine(Expression *e1, Expression *e2); static Expressions *arraySyntaxCopy(Expressions *exps); @@ -153,7 +156,6 @@ struct Expression : Object Expression *integralPromotions(Scope *sc); Expression *toDelegate(Scope *sc, Type *t); - virtual void scanForNestedRef(Scope *sc); virtual Expression *optimize(int result); #define WANTflags 1 @@ -168,10 +170,11 @@ struct Expression : Object virtual int isConst(); virtual int isBool(int result); virtual int isBit(); + bool hasSideEffect(); virtual int checkSideEffect(int flag); virtual int canThrow(); - virtual int inlineCost(InlineCostState *ics); + virtual int inlineCost3(InlineCostState *ics); virtual Expression *doInline(InlineDoState *ids); virtual Expression *inlineScan(InlineScanState *iss); Expression *inlineCopy(Scope *sc); @@ -342,9 +345,8 @@ struct ThisExp : Expression int isBool(int result); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *toLvalue(Scope *sc, Expression *e); - void scanForNestedRef(Scope *sc); - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); //Expression *inlineScan(InlineScanState *iss); @@ -362,9 +364,7 @@ struct SuperExp : ThisExp SuperExp(Loc loc); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); //Expression *inlineScan(InlineScanState *iss); }; @@ -399,6 +399,7 @@ struct StringExp : Expression unsigned char sz; // 1: char, 2: wchar, 4: dchar unsigned char committed; // !=0 if type is committed unsigned char postfix; // 'c', 'w', 'd' + bool ownedByCtfe; // true = created in CTFE StringExp(Loc loc, char *s); StringExp(Loc loc, void *s, size_t len); @@ -436,10 +437,10 @@ struct TupleExp : Expression TupleExp(Loc loc, Expressions *exps); TupleExp(Loc loc, TupleDeclaration *tup); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); int equals(Object *o); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); void checkEscape(); int checkSideEffect(int flag); Expression *optimize(int result); @@ -449,7 +450,6 @@ struct TupleExp : Expression elem *toElem(IRState *irs); #endif - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -461,24 +461,24 @@ struct TupleExp : Expression struct ArrayLiteralExp : Expression { Expressions *elements; + bool ownedByCtfe; // true = created in CTFE ArrayLiteralExp(Loc loc, Expressions *elements); ArrayLiteralExp(Loc loc, Expression *e); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); int isBool(int result); int checkSideEffect(int flag); StringExp *toString(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -495,10 +495,12 @@ struct AssocArrayLiteralExp : Expression { Expressions *keys; Expressions *values; + bool ownedByCtfe; // true = created in CTFE AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); int isBool(int result); #if IN_DMD @@ -507,13 +509,11 @@ struct AssocArrayLiteralExp : Expression int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -535,22 +535,23 @@ struct StructLiteralExp : Expression #endif size_t soffset; // offset from start of s int fillHoles; // fill alignment 'holes' with zero + bool ownedByCtfe; // true = created in CTFE StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); Expression *getField(Type *type, unsigned offset); int getFieldIndex(Type *type, unsigned offset); int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *toLvalue(Scope *sc, Expression *e); - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -610,7 +611,7 @@ struct TemplateExp : Expression TemplateDeclaration *td; TemplateExp(Loc loc, TemplateDeclaration *td); - void rvalue(); + int rvalue(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; @@ -630,6 +631,7 @@ struct NewExp : Expression NewExp(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *optimize(int result); @@ -638,9 +640,8 @@ struct NewExp : Expression #endif int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - //int inlineCost(InlineCostState *ics); + //int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); //Expression *inlineScan(InlineScanState *iss); @@ -661,6 +662,7 @@ struct NewAnonClassExp : Expression NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs, ClassDeclaration *cd, Expressions *arguments); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -696,7 +698,6 @@ struct SymOffExp : Expression Expression *doInline(InlineDoState *ids); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); #if IN_DMD elem *toElem(IRState *irs); @@ -731,9 +732,7 @@ struct VarExp : Expression elem *toElem(IRState *irs); dt_t **toDt(dt_t **pdt); #endif - void scanForNestedRef(Scope *sc); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); //Expression *inlineScan(InlineScanState *iss); @@ -767,7 +766,6 @@ struct FuncExp : Expression Expression *syntaxCopy(); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void scanForNestedRef(Scope *sc); char *toChars(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD @@ -775,7 +773,7 @@ struct FuncExp : Expression dt_t **toDt(dt_t **pdt); #endif - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); //Expression *doInline(InlineDoState *ids); //Expression *inlineScan(InlineScanState *iss); @@ -800,9 +798,8 @@ struct DeclarationExp : Expression #if IN_DMD elem *toElem(IRState *irs); #endif - void scanForNestedRef(Scope *sc); - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -875,14 +872,13 @@ struct UnaExp : Expression UnaExp(Loc loc, enum TOK op, int size, Expression *e1); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *optimize(int result); void dump(int indent); - void scanForNestedRef(Scope *sc); Expression *interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *)); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -896,6 +892,7 @@ struct BinExp : Expression BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); Expression *semanticp(Scope *sc); Expression *commonSemanticAssign(Scope *sc); @@ -910,7 +907,6 @@ struct BinExp : Expression int isunsigned(); void incompatibleTypes(); void dump(int indent); - void scanForNestedRef(Scope *sc); Expression *interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *, Expression *)); Expression *interpretCommon2(InterState *istate, CtfeGoal goal, @@ -919,7 +915,6 @@ struct BinExp : Expression Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); Expression *arrayOp(Scope *sc); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -958,12 +953,12 @@ struct AssertExp : UnaExp AssertExp(Loc loc, Expression *e, Expression *msg = NULL); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -1040,7 +1035,7 @@ struct DelegateExp : UnaExp void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void dump(int indent); - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); #if IN_DMD elem *toElem(IRState *irs); #endif @@ -1076,6 +1071,7 @@ struct CallExp : UnaExp CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); @@ -1085,11 +1081,10 @@ struct CallExp : UnaExp #if IN_DMD elem *toElem(IRState *irs); #endif - void scanForNestedRef(Scope *sc); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -1276,6 +1271,7 @@ struct SliceExp : UnaExp SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); void checkEscape(); void checkEscapeRef(); @@ -1289,12 +1285,10 @@ struct SliceExp : UnaExp #if IN_DMD elem *toElem(IRState *irs); #endif - void scanForNestedRef(Scope *sc); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); Expression *buildArrayLoop(Parameters *fparams); int canThrow(); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -1328,15 +1322,14 @@ struct ArrayExp : UnaExp ArrayExp(Loc loc, Expression *e1, Expressions *arguments); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); Expression *toLvalue(Scope *sc, Expression *e); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); // For operator overloading Identifier *opId(); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); }; @@ -1385,7 +1378,6 @@ struct IndexExp : BinExp Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *doInline(InlineDoState *ids); - void scanForNestedRef(Scope *sc); #if IN_DMD elem *toElem(IRState *irs); @@ -1899,6 +1891,7 @@ struct CondExp : BinExp CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); @@ -1911,9 +1904,7 @@ struct CondExp : BinExp void toCBuffer(OutBuffer *buf, HdrGenState *hgs); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -2015,4 +2006,11 @@ Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); +// Const-folding functions used by CTFE + +void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex); +void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex); +void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex); + + #endif /* DMD_EXPRESSION_H */ diff --git a/dmd/func.c b/dmd/func.c index 2a9d2386..29f45e58 100644 --- a/dmd/func.c +++ b/dmd/func.c @@ -61,11 +61,13 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla vtblIndex = -1; hasReturnExp = 0; naked = 0; - inlineStatus = ILSuninitialized; + inlineStatusExp = ILSuninitialized; + inlineStatusStmt = ILSuninitialized; inlineNest = 0; inlineAsm = 0; - cantInterpret = 0; + isArrayOp = 0; semanticRun = PASSinit; + semantic3Errors = 0; #if DMDV1 nestedFrameRef = 0; #endif @@ -86,6 +88,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla #if DMDV2 builtin = BUILTINunknown; tookAddressOf = 0; + flags = 0; #endif #if IN_LLVM @@ -408,7 +411,7 @@ void FuncDeclaration::semantic(Scope *sc) return; default: - { FuncDeclaration *fdv = (FuncDeclaration *)cd->baseClass->vtbl.data[vi]; + { FuncDeclaration *fdv = (FuncDeclaration *)cd->baseClass->vtbl[vi]; // This function is covariant with fdv if (fdv->isFinal()) error("cannot override final function %s", fdv->toPrettyChars()); @@ -422,11 +425,13 @@ void FuncDeclaration::semantic(Scope *sc) if (fdc->toParent() == parent) { // If both are mixins, then error. - // If either is not, the one that is not overrides - // the other. - if (fdc->parent->isClassDeclaration()) + // If either is not, the one that is not overrides the other. + + // if (this is mixin) && (fdc is not mixin) then fdc overrides + if (!this->parent->isClassDeclaration() && fdc->parent->isClassDeclaration()) break; - if (!this->parent->isClassDeclaration() + + if (!this->parent->isClassDeclaration() // if both are mixins then error #if !BREAKABI && !isDtorDeclaration() #endif @@ -726,6 +731,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (semanticRun >= PASSsemantic3) return; semanticRun = PASSsemantic3; + semantic3Errors = 0; #if IN_LLVM if (!global.params.useAvailableExternally) @@ -847,7 +853,10 @@ void FuncDeclaration::semantic3(Scope *sc) Type *t = new TypeIdentifier(loc, Id::va_argsave_t); t = t->semantic(loc, sc); if (t == Type::terror) + { error("must import std.c.stdarg to use variadic functions"); + return; + } else { v_argsave = new VarDeclaration(loc, t, Id::va_argsave, NULL); @@ -1560,7 +1569,12 @@ void FuncDeclaration::semantic3(Scope *sc) if (global.gag && global.errors != nerrors) semanticRun = PASSsemanticdone; // Ensure errors get reported again else + { semanticRun = PASSsemantic3done; + semantic3Errors = global.errors - nerrors; + } + //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); + //fflush(stdout); } void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -1575,7 +1589,7 @@ void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (fbody && - (!hgs->hdrgen || hgs->tpltMember || canInline(1,1)) + (!hgs->hdrgen || hgs->tpltMember || canInline(1,1,1)) ) { buf->writenl(); @@ -1667,11 +1681,11 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf) Statement *s2 = new ExpStatement(loc, e); Catch *c = new Catch(loc, NULL, NULL, sf); - Array *catches = new Array(); - catches->push(c); - sf = new TryCatchStatement(loc, s2, catches); - } - else + Catches *catches = new Catches(); + catches->push(c); + sf = new TryCatchStatement(loc, s2, catches); + } + else return NULL; } return sf; @@ -2448,6 +2462,21 @@ int FuncDeclaration::isVirtual() toParent()->isClassDeclaration(); } +// Determine if a function is pedantically virtual + +int FuncDeclaration::isVirtualMethod() +{ + //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars()); + if (!isVirtual()) + return 0; + // If it's a final method, and does not override anything, then it is not virtual + if (isFinal() && foverrides.dim == 0) + { + return 0; + } + return 1; +} + int FuncDeclaration::isFinal() { ClassDeclaration *cd; @@ -2622,6 +2651,43 @@ Lyes: } #endif +/*********************************************** + * Determine if function's variables are referenced by a function + * nested within it. + */ + +int FuncDeclaration::hasNestedFrameRefs() +{ +#if DMDV2 + if (closureVars.dim) +#else + if (nestedFrameRef) +#endif + return 1; + + /* If a virtual method has contracts, assume its variables are referenced + * by those contracts, even if they aren't. Because they might be referenced + * by the overridden or overriding function's contracts. + * This can happen because frequire and fensure are implemented as nested functions, + * and they can be called directly by an overriding function and the overriding function's + * context had better match, or Bugzilla 7337 will bite. + */ + if ((fdrequire || fdensure) && isVirtualMethod()) + return 1; + + if (foverrides.dim && isVirtualMethod()) + { + for (size_t i = 0; i < foverrides.dim; i++) + { + FuncDeclaration *fdv = foverrides.tdata()[i]; + if (fdv->hasNestedFrameRefs()) + return 1; + } + } + + return 0; +} + /********************************************* * Return the function's parameter list, and whether * it is variadic or not. diff --git a/dmd/import.c b/dmd/import.c index 0f78d9c1..add1f094 100644 --- a/dmd/import.c +++ b/dmd/import.c @@ -27,7 +27,7 @@ Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId, int isstatic) - : Dsymbol(id) + : Dsymbol() { assert(id); this->loc = loc; @@ -38,12 +38,6 @@ Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *alias protection = PROTundefined; pkg = NULL; mod = NULL; - - if (aliasId) - this->ident = aliasId; - // Kludge to change Import identifier to first package - else if (packages && packages->dim) - this->ident = (Identifier *)packages->data[0]; } void Import::addAlias(Identifier *name, Identifier *alias) @@ -51,9 +45,6 @@ void Import::addAlias(Identifier *name, Identifier *alias) if (isstatic) error("cannot have an import bind list"); - if (!aliasId) - this->ident = NULL; // make it an anonymous import - names.push(name); aliases.push(alias); } @@ -72,13 +63,11 @@ Dsymbol *Import::syntaxCopy(Dsymbol *s) { assert(!s); - Import *si; - - si = new Import(loc, packages, id, aliasId, isstatic); + Import *si = new Import(loc, packages, id, aliasId, isstatic); for (size_t i = 0; i < names.dim; i++) { - si->addAlias((Identifier *)names.data[i], (Identifier *)aliases.data[i]); + si->addAlias(names[i], aliases[i]); } return si; @@ -146,15 +135,12 @@ void Import::importAll(Scope *sc) load(sc); mod->importAll(0); - if (!isstatic && !aliasId && !names.dim) - { - /* Default to private importing - */ - enum PROT prot = sc->protection; - if (!sc->explicitProtection) - prot = PROTprivate; - sc->scopesym->importScope(mod, prot); - } + /* Default to private importing + */ + enum PROT prot = sc->protection; + if (!sc->explicitProtection) + prot = PROTprivate; + sc->scopesym->importScope(this, prot); } } @@ -186,32 +172,31 @@ void Import::semantic(Scope *sc) /* Default to private importing */ - protection = sc->protection; + enum PROT prot = sc->protection; if (!sc->explicitProtection) - protection = PROTprivate; - - if (!isstatic && !aliasId && !names.dim) + prot = PROTprivate; + for (Scope *scd = sc; scd; scd = scd->enclosing) { - sc->scopesym->importScope(mod, protection); + if (scd->scopesym) + { + scd->scopesym->importScope(this, prot); + break; + } } mod->semantic(); if (mod->needmoduleinfo) + { //printf("module4 %s because of %s\n", sc->module->toChars(), mod->toChars()); sc->module->needmoduleinfo = 1; + } - sc = sc->push(mod); - for (size_t i = 0; i < aliasdecls.dim; i++) - { AliasDeclaration *ad = (AliasDeclaration *)aliasdecls.data[i]; - - //printf("\tImport alias semantic('%s')\n", s->toChars()); - if (!mod->search(loc, (Identifier *)names.data[i], 0)) - error("%s not found", ((Identifier *)names.data[i])->toChars()); - - ad->importprot = protection; + if (aliasId) + { + AliasDeclaration *ad = new AliasDeclaration(loc, aliasId, mod); + sc->insert(ad); ad->semantic(sc); } - sc = sc->pop(); } //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); @@ -246,7 +231,7 @@ void Import::semantic(Scope *sc) { for (size_t i = 0; i < packages->dim; i++) { - Identifier *pid = (Identifier *)packages->data[i]; + Identifier *pid = (*packages)[i]; ob->printf("%s.", pid->toChars()); } } @@ -266,8 +251,8 @@ void Import::semantic(Scope *sc) else ob->writebyte(','); - Identifier *name = (Identifier *)names.data[i]; - Identifier *alias = (Identifier *)aliases.data[i]; + Identifier *name = names[i]; + Identifier *alias = aliases[i]; if (!alias) { @@ -292,49 +277,9 @@ void Import::semantic2(Scope *sc) //printf("Import::semantic2('%s')\n", toChars()); mod->semantic2(); if (mod->needmoduleinfo) + { //printf("module5 %s because of %s\n", sc->module->toChars(), mod->toChars()); sc->module->needmoduleinfo = 1; -} - -Dsymbol *Import::toAlias() -{ - if (aliasId) - return mod; - return this; -} - -/***************************** - * Add import to sd's symbol table. - */ - -int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - int result = 0; - - if (names.dim == 0) - return Dsymbol::addMember(sc, sd, memnum); - - if (aliasId) - result = Dsymbol::addMember(sc, sd, memnum); - - /* Instead of adding the import to sd's symbol table, - * add each of the alias=name pairs - */ - for (size_t i = 0; i < names.dim; i++) - { - Identifier *name = (Identifier *)names.data[i]; - Identifier *alias = (Identifier *)aliases.data[i]; - - if (!alias) - alias = name; - - TypeIdentifier *tname = new TypeIdentifier(loc, name); - AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname); - result |= ad->addMember(sc, sd, memnum); - - aliasdecls.push(ad); } - - return result; } Dsymbol *Import::search(Loc loc, Identifier *ident, int flags) @@ -346,14 +291,50 @@ Dsymbol *Import::search(Loc loc, Identifier *ident, int flags) mod->semantic(); } - // Forward it to the package/module - return pkg->search(loc, ident, flags); -} + if (names.dim) // selective import + { + for (size_t i = 0; i < names.dim; i++) + { + Identifier *name = (Identifier *)names[i]; + Identifier *alias = (Identifier *)aliases[i]; -int Import::overloadInsert(Dsymbol *s) -{ - // Allow multiple imports of the same name - return s->isImport() != NULL; + if (!alias) + alias = name; + + if (alias->equals(ident)) + return mod->search(loc, name, flags); + } + + // What should happen when renamed and selective imports are mixed? + // This makes the whole module available with the renamed id. + if (aliasId && aliasId->equals(ident)) + return mod; + } + else // non-selective import + { + // For renamed imports, only the alias name is visible. + if (aliasId) + { + if (aliasId->equals(ident)) + return mod; + return 0; + } + + // For non-static imports, prefer symbols in the module over the module name. + if (!isstatic) + { + Dsymbol *s = mod->search(loc, ident, flags); + if (s) + return s; + } + + // Make the start of the package name available. + if (pkg->ident->equals(ident)) + { + return pkg; + } + } + return 0; } void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -371,7 +352,7 @@ void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; + { Identifier *pid = (*packages)[i]; buf->printf("%s.", pid->toChars()); } @@ -400,3 +381,7 @@ void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); } +char *Import::toChars() +{ + return id->toChars(); +} diff --git a/dmd/import.h b/dmd/import.h index 65f5e6bf..872e1301 100644 --- a/dmd/import.h +++ b/dmd/import.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -28,17 +28,16 @@ struct HdrGenState; struct Import : Dsymbol { - Identifiers *packages; // array of Identifier's representing packages + // isstatic import aliasId = packages.id; + Identifiers *packages; // array of Identifier's representing packages Identifier *id; // module Identifier Identifier *aliasId; int isstatic; // !=0 if static import enum PROT protection; // Pairs of alias=name to bind into current namespace - Array names; - Array aliases; - - Array aliasdecls; // AliasDeclarations for names/aliases + Identifiers names; + Identifiers aliases; Module *mod; Package *pkg; // leftmost package/module @@ -54,11 +53,9 @@ struct Import : Dsymbol void importAll(Scope *sc); void semantic(Scope *sc); void semantic2(Scope *sc); - Dsymbol *toAlias(); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); Dsymbol *search(Loc loc, Identifier *ident, int flags); - int overloadInsert(Dsymbol *s); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *toChars(); Import *isImport() { return this; } }; diff --git a/dmd/init.c b/dmd/init.c index 46ad5697..9fdda975 100644 --- a/dmd/init.c +++ b/dmd/init.c @@ -164,8 +164,8 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) #endif for (size_t i = 0; i < field.dim; i++) { - Identifier *id = (Identifier *)field.data[i]; - Initializer *val = (Initializer *)value.data[i]; + Identifier *id = field[i]; + Initializer *val = value[i]; Dsymbol *s; VarDeclaration *v; @@ -180,7 +180,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) } else { - s = (Dsymbol *)ad->fields.data[fieldi]; + s = ad->fields[fieldi]; } } else @@ -193,6 +193,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) errors = 1; continue; } + s = s->toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) @@ -204,7 +205,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) errors = 1; break; } - if (s == (Dsymbol *)ad->fields.data[fieldi]) + if (s == ad->fields[fieldi]) break; } } @@ -277,7 +278,7 @@ Expression *StructInitializer::toExpression() unsigned fieldi = 0; for (size_t i = 0; i < value.dim; i++) { - Identifier *id = (Identifier *)field.data[i]; + Identifier *id = field[i]; if (id) { Dsymbol * s = ad->search(loc, id, 0); @@ -286,6 +287,7 @@ Expression *StructInitializer::toExpression() error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); goto Lno; } + s = s->toAlias(); // Find out which field index it is for (fieldi = 0; 1; fieldi++) @@ -295,7 +297,7 @@ Expression *StructInitializer::toExpression() s->error("is not a per-instance initializable field"); goto Lno; } - if (s == (Dsymbol *)ad->fields.data[fieldi]) + if (s == ad->fields[fieldi]) break; } } diff --git a/dmd/inline.c b/dmd/inline.c index bd7ddc8c..93b65b05 100644 --- a/dmd/inline.c +++ b/dmd/inline.c @@ -39,15 +39,29 @@ struct InlineCostState }; const int COST_MAX = 250; +const int STATEMENT_COST = 0x1000; +const int STATEMENT_COST_MAX = 250 * 0x1000; + +// STATEMENT_COST be power of 2 and greater than COST_MAX +//static assert((STATEMENT_COST & (STATEMENT_COST - 1)) == 0); +//static assert(STATEMENT_COST > COST_MAX); + +bool tooCostly(int cost) { return ((cost & (STATEMENT_COST - 1)) >= COST_MAX); } + +int expressionInlineCost(Expression *e, InlineCostState *ics); int Statement::inlineCost(InlineCostState *ics) { + //printf("Statement::inlineCost = %d\n", COST_MAX); + //printf("%p\n", isScopeStatement()); + //printf("%s\n", toChars()); return COST_MAX; // default is we can't inline it } int ExpStatement::inlineCost(InlineCostState *ics) { - return exp ? exp->inlineCost(ics) : 0; + return expressionInlineCost(exp, ics); + //return exp ? exp->inlineCost(ics) : 0; } int CompoundStatement::inlineCost(InlineCostState *ics) @@ -58,10 +72,11 @@ int CompoundStatement::inlineCost(InlineCostState *ics) if (s) { cost += s->inlineCost(ics); - if (cost >= COST_MAX) + if (tooCostly(cost)) break; } } + //printf("CompoundStatement::inlineCost = %d\n", cost); return cost; } @@ -73,13 +88,18 @@ int UnrolledLoopStatement::inlineCost(InlineCostState *ics) if (s) { cost += s->inlineCost(ics); - if (cost >= COST_MAX) + if (tooCostly(cost)) break; } } return cost; } +int ScopeStatement::inlineCost(InlineCostState *ics) +{ + return statement ? 1 + statement->inlineCost(ics) : 1; +} + int IfStatement::inlineCost(InlineCostState *ics) { int cost; @@ -92,7 +112,7 @@ int IfStatement::inlineCost(InlineCostState *ics) return COST_MAX; #endif - cost = condition->inlineCost(ics); + cost = expressionInlineCost(condition, ics); #if !IN_LLVM /* Specifically allow: @@ -121,6 +141,7 @@ int IfStatement::inlineCost(InlineCostState *ics) cost += elsebody->inlineCost(ics); ics->nested -= 1; } + //printf("IfStatement::inlineCost = %d\n", cost); return cost; } @@ -131,41 +152,67 @@ int ReturnStatement::inlineCost(InlineCostState *ics) if (ics->nested) return COST_MAX; #endif - return exp ? exp->inlineCost(ics) : 0; + return expressionInlineCost(exp, ics); } -/* -------------------------- */ +#if DMDV2 +int ImportStatement::inlineCost(InlineCostState *ics) +{ + return 0; +} +#endif -int arrayInlineCost(InlineCostState *ics, Expressions *arguments) -{ int cost = 0; - - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (*arguments)[i]; - - if (e) - cost += e->inlineCost(ics); - } - } +int ForStatement::inlineCost(InlineCostState *ics) +{ + //return COST_MAX; + int cost = STATEMENT_COST; + if (init) + cost += init->inlineCost(ics); + if (condition) + cost += expressionInlineCost(condition, ics); + if (increment) + cost += expressionInlineCost(increment, ics); + if (body) + cost += body->inlineCost(ics); + //printf("ForStatement: inlineCost = %d\n", cost); return cost; } -int Expression::inlineCost(InlineCostState *ics) + +/* -------------------------- */ + +struct ICS2 +{ + int cost; + InlineCostState *ics; +}; + +int lambdaInlineCost(Expression *e, void *param) +{ + ICS2 *ics2 = (ICS2 *)param; + ics2->cost += e->inlineCost3(ics2->ics); + return (ics2->cost >= COST_MAX); +} + +int expressionInlineCost(Expression *e, InlineCostState *ics) +{ + ICS2 ics2; + ics2.cost = 0; + ics2.ics = ics; + if (e) + e->apply(&lambdaInlineCost, &ics2); + return ics2.cost; +} + +int Expression::inlineCost3(InlineCostState *ics) { return 1; } -int VarExp::inlineCost(InlineCostState *ics) -{ - //printf("VarExp::inlineCost() %s\n", toChars()); - return 1; -} - -int ThisExp::inlineCost(InlineCostState *ics) +int ThisExp::inlineCost3(InlineCostState *ics) { #if !IN_LLVM - //printf("ThisExp::inlineCost() %s\n", toChars()); + //printf("ThisExp::inlineCost3() %s\n", toChars()); FuncDeclaration *fd = ics->fd; if (!fd) return COST_MAX; @@ -176,64 +223,38 @@ int ThisExp::inlineCost(InlineCostState *ics) return 1; } -int SuperExp::inlineCost(InlineCostState *ics) -{ -#if !IN_LLVM - FuncDeclaration *fd = ics->fd; - if (!fd) - return COST_MAX; - if (!ics->hdrscan) - if (fd->isNested() || !ics->hasthis) - return COST_MAX; -#endif - return 1; -} - -int TupleExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, exps); -} - -int ArrayLiteralExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, elements); -} - -int AssocArrayLiteralExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, keys) + arrayInlineCost(ics, values); -} - -int StructLiteralExp::inlineCost(InlineCostState *ics) +int StructLiteralExp::inlineCost3(InlineCostState *ics) { + //printf("StructLiteralExp::inlineCost3() %s\n", toChars()); #if DMDV2 if (sd->isnested) return COST_MAX; #endif - return 1 + arrayInlineCost(ics, elements); + return 1; } -int FuncExp::inlineCost(InlineCostState *ics) +int FuncExp::inlineCost3(InlineCostState *ics) { - //printf("FuncExp::inlineCost()\n"); + //printf("FuncExp::inlineCost3()\n"); // This breaks on LDC too, since nested functions have internal linkage // and thus can't be referenced from other objects. // Right now, this makes the function be output to the .obj file twice. return COST_MAX; } -int DelegateExp::inlineCost(InlineCostState *ics) +int DelegateExp::inlineCost3(InlineCostState *ics) { + //printf("DelegateExp::inlineCost3()\n"); // This breaks on LDC too, since nested functions have internal linkage // and thus can't be referenced from other objects. return COST_MAX; } -int DeclarationExp::inlineCost(InlineCostState *ics) +int DeclarationExp::inlineCost3(InlineCostState *ics) { int cost = 0; VarDeclaration *vd; - //printf("DeclarationExp::inlineCost()\n"); + //printf("DeclarationExp::inlineCost3()\n"); vd = declaration->isVarDeclaration(); if (vd) { @@ -260,6 +281,10 @@ int DeclarationExp::inlineCost(InlineCostState *ics) return COST_MAX; cost += 1; +#if DMDV2 + if (vd->edtor) // if destructor required + return COST_MAX; // needs work to make this work +#endif // Scan initializer (vd->init) if (vd->init) { @@ -267,7 +292,7 @@ int DeclarationExp::inlineCost(InlineCostState *ics) if (ie) { - cost += ie->exp->inlineCost(ics); + cost += expressionInlineCost(ie->exp, ics); } } } @@ -279,82 +304,157 @@ int DeclarationExp::inlineCost(InlineCostState *ics) declaration->isClassDeclaration() || declaration->isFuncDeclaration() || declaration->isTypedefDeclaration() || +#if DMDV2 + declaration->isAttribDeclaration() || +#endif declaration->isTemplateMixin()) return COST_MAX; - //printf("DeclarationExp::inlineCost('%s')\n", toChars()); + //printf("DeclarationExp::inlineCost3('%s')\n", toChars()); return cost; } -int UnaExp::inlineCost(InlineCostState *ics) +int CallExp::inlineCost3(InlineCostState *ics) { - return 1 + e1->inlineCost(ics); + //printf("CallExp::inlineCost3() %s\n", toChars()); + // Bugzilla 3500: super.func() calls must be devirtualized, and the inliner + // can't handle that at present. + if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKsuper) + return COST_MAX; + + return 1; } -int AssertExp::inlineCost(InlineCostState *ics) + +/* ======================== Perform the inlining ============================== */ + +/* Inlining is done by: + * o Converting to an Expression + * o Copying the trees of the function to be inlined + * o Renaming the variables + */ + +struct InlineDoState { - return 1 + e1->inlineCost(ics) + (msg ? msg->inlineCost(ics) : 0); + VarDeclaration *vthis; + Dsymbols from; // old Dsymbols + Dsymbols to; // parallel array of new Dsymbols + Dsymbol *parent; // new parent +}; + +/* -------------------------------------------------------------------- */ + +Statement *Statement::doInlineStatement(InlineDoState *ids) +{ + assert(0); + return NULL; // default is we can't inline it } -int BinExp::inlineCost(InlineCostState *ics) +Statement *ExpStatement::doInlineStatement(InlineDoState *ids) { - return 1 + e1->inlineCost(ics) + e2->inlineCost(ics); +#if LOG + if (exp) printf("ExpStatement::doInlineStatement() '%s'\n", exp->toChars()); +#endif + return new ExpStatement(loc, exp ? exp->doInline(ids) : NULL); } -int CallExp::inlineCost(InlineCostState *ics) -{ - // Bugzilla 3500: super.func() calls must be devirtualized, and the inliner - // can't handle that at present. - if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKsuper) - return COST_MAX; +Statement *CompoundStatement::doInlineStatement(InlineDoState *ids) +{ + //printf("CompoundStatement::doInlineStatement() %d\n", statements->dim); + Statements *as = new Statements(); + as->reserve(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (*statements)[i]; + if (s) + { + as->push(s->doInlineStatement(ids)); + if (s->isReturnStatement()) + break; - return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); + /* Check for: + * if (condition) + * return exp1; + * else + * return exp2; + */ + IfStatement *ifs = s->isIfStatement(); + if (ifs && ifs->elsebody && ifs->ifbody && + ifs->ifbody->isReturnStatement() && + ifs->elsebody->isReturnStatement() + ) + break; + } + else + as->push(NULL); + } + return new CompoundStatement(loc, as); } -int SliceExp::inlineCost(InlineCostState *ics) -{ int cost; - - cost = 1 + e1->inlineCost(ics); - if (lwr) - cost += lwr->inlineCost(ics); - if (upr) - cost += upr->inlineCost(ics); - return cost; +Statement *UnrolledLoopStatement::doInlineStatement(InlineDoState *ids) +{ + //printf("UnrolledLoopStatement::doInlineStatement() %d\n", statements->dim); + Statements *as = new Statements(); + as->reserve(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (*statements)[i]; + if (s) + { + as->push(s->doInlineStatement(ids)); + if (s->isReturnStatement()) + break; + } + else + as->push(NULL); + } + return new UnrolledLoopStatement(loc, as); } -int ArrayExp::inlineCost(InlineCostState *ics) +Statement *ScopeStatement::doInlineStatement(InlineDoState *ids) { - return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); + //printf("ScopeStatement::doInlineStatement() %d\n", statements->dim); + return statement ? new ScopeStatement(loc, statement->doInlineStatement(ids)) : this; } +Statement *IfStatement::doInlineStatement(InlineDoState *ids) +{ + assert(!arg); -int CondExp::inlineCost(InlineCostState *ics) + Expression *condition = this->condition ? this->condition->doInline(ids) : NULL; + Statement *ifbody = this->ifbody ? this->ifbody->doInlineStatement(ids) : NULL; + Statement *elsebody = this->elsebody ? this->elsebody->doInlineStatement(ids) : NULL; + + return new IfStatement(loc, arg, condition, ifbody, elsebody); +} + +Statement *ReturnStatement::doInlineStatement(InlineDoState *ids) { - return 1 + - e1->inlineCost(ics) + - e2->inlineCost(ics) + - econd->inlineCost(ics); -} - - -/* ======================== Perform the inlining ============================== */ - -/* Inlining is done by: - * o Converting to an Expression - * o Copying the trees of the function to be inlined - * o Renaming the variables - */ - -struct InlineDoState -{ - VarDeclaration *vthis; - Array from; // old Dsymbols - Array to; // parallel array of new Dsymbols - Dsymbol *parent; // new parent -}; + //printf("ReturnStatement::doInlineStatement() '%s'\n", exp ? exp->toChars() : ""); + return new ReturnStatement(loc, exp ? exp->doInline(ids) : NULL); +} + +#if DMDV2 +Statement *ImportStatement::doInlineStatement(InlineDoState *ids) +{ + return NULL; +} +#endif + +Statement *ForStatement::doInlineStatement(InlineDoState *ids) +{ + //printf("ForStatement::doInlineStatement()\n"); + Statement *init = this->init ? this->init->doInlineStatement(ids) : NULL; + Expression *condition = this->condition ? this->condition->doInline(ids) : NULL; + Expression *increment = this->increment ? this->increment->doInline(ids) : NULL; + Statement *body = this->body ? this->body->doInlineStatement(ids) : NULL; + return new ForStatement(loc, init, condition, increment, body); +} + +/* -------------------------------------------------------------------- */ Expression *Statement::doInline(InlineDoState *ids) { + printf("Statement::doInline()\n%s\n", toChars()); + fflush(stdout); assert(0); return NULL; // default is we can't inline it } @@ -417,6 +517,11 @@ Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) return e; } +Expression *ScopeStatement::doInline(InlineDoState *ids) +{ + return statement ? statement->doInline(ids) : NULL; +} + Expression *IfStatement::doInline(InlineDoState *ids) { Expression *econd; @@ -463,6 +568,13 @@ Expression *ReturnStatement::doInline(InlineDoState *ids) return exp ? exp->doInline(ids) : 0; } +#if DMDV2 +Expression *ImportStatement::doInline(InlineDoState *ids) +{ + return NULL; +} +#endif + /* --------------------------------------------------------------- */ /****************************** @@ -478,11 +590,11 @@ Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) newa->setDim(a->dim); for (size_t i = 0; i < a->dim; i++) - { Expression *e = (Expression *)a->data[i]; + { Expression *e = a->tdata()[i]; if (e) e = e->doInline(ids); - newa->data[i] = (void *)e; + newa->tdata()[i] = e; } } return newa; @@ -499,11 +611,11 @@ Expression *SymOffExp::doInline(InlineDoState *ids) //printf("SymOffExp::doInline(%s)\n", toChars()); for (size_t i = 0; i < ids->from.dim; i++) { - if (var == (Declaration *)ids->from.data[i]) + if (var == ids->from.tdata()[i]) { SymOffExp *se = (SymOffExp *)copy(); - se->var = (Declaration *)ids->to.data[i]; + se->var = (Declaration *)ids->to.tdata()[i]; return se; } } @@ -515,11 +627,11 @@ Expression *VarExp::doInline(InlineDoState *ids) //printf("VarExp::doInline(%s)\n", toChars()); for (size_t i = 0; i < ids->from.dim; i++) { - if (var == (Declaration *)ids->from.data[i]) + if (var == ids->from.tdata()[i]) { VarExp *ve = (VarExp *)copy(); - ve->var = (Declaration *)ids->to.data[i]; + ve->var = (Declaration *)ids->to.tdata()[i]; return ve; } } @@ -563,7 +675,7 @@ Expression *DeclarationExp::doInline(InlineDoState *ids) if (td) { for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; + { DsymbolExp *se = td->objects->tdata()[i]; assert(se->op == TOKdsymbol); se->s; } @@ -825,16 +937,38 @@ Statement *ExpStatement::inlineScan(InlineScanState *iss) printf("ExpStatement::inlineScan(%s)\n", toChars()); #endif if (exp) + { exp = exp->inlineScan(iss); + + /* See if we can inline as a statement rather than as + * an Expression. + */ + if (exp && exp->op == TOKcall) + { + CallExp *ce = (CallExp *)exp; + if (ce->e1->op == TOKvar) + { + VarExp *ve = (VarExp *)ce->e1; + FuncDeclaration *fd = ve->var->isFuncDeclaration(); + + if (fd && fd != iss->fd && fd->canInline(0, 0, 1)) + { + Statement *s; + fd->expandInline(iss, NULL, ce->arguments, &s); + return s; + } + } + } + } return this; } Statement *CompoundStatement::inlineScan(InlineScanState *iss) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s) - statements->data[i] = (void *)s->inlineScan(iss); + (*statements)[i] = s->inlineScan(iss); } return this; } @@ -842,9 +976,9 @@ Statement *CompoundStatement::inlineScan(InlineScanState *iss) Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s) - statements->data[i] = (void *)s->inlineScan(iss); + (*statements)[i] = s->inlineScan(iss); } return this; } @@ -928,10 +1062,10 @@ Statement *SwitchStatement::inlineScan(InlineScanState *iss) if (cases) { for (size_t i = 0; i < cases->dim; i++) - { Statement *s; + { CaseStatement *s; - s = (Statement *) cases->data[i]; - cases->data[i] = (void *)s->inlineScan(iss); + s = cases->tdata()[i]; + cases->tdata()[i] = (CaseStatement *)s->inlineScan(iss); } } return this; @@ -994,7 +1128,7 @@ Statement *TryCatchStatement::inlineScan(InlineScanState *iss) if (catches) { for (size_t i = 0; i < catches->dim; i++) - { Catch *c = (Catch *)catches->data[i]; + { Catch *c = catches->tdata()[i]; if (c->handler) c->handler = c->handler->inlineScan(iss); @@ -1039,17 +1173,17 @@ Statement *LabelStatement::inlineScan(InlineScanState *iss) /* -------------------------- */ -void arrayInlineScan(InlineScanState *iss, Array *arguments) +void arrayInlineScan(InlineScanState *iss, Expressions *arguments) { if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; + { Expression *e = arguments->tdata()[i]; if (e) { e = e->inlineScan(iss); - arguments->data[i] = (void *)e; + arguments->tdata()[i] = e; } } } @@ -1069,7 +1203,7 @@ void scanVar(Dsymbol *s, InlineScanState *iss) if (td) { for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; + { DsymbolExp *se = (DsymbolExp *)td->objects->tdata()[i]; assert(se->op == TOKdsymbol); scanVar(se->s, iss); } @@ -1156,9 +1290,9 @@ Expression *CallExp::inlineScan(InlineScanState *iss) VarExp *ve = (VarExp *)e1; FuncDeclaration *fd = ve->var->isFuncDeclaration(); - if (fd && fd != iss->fd && fd->canInline(0)) + if (fd && fd != iss->fd && fd->canInline(0, 0, 0)) { - e = fd->doInline(iss, NULL, arguments); + e = fd->expandInline(iss, NULL, arguments, NULL); } } else if (e1->op == TOKdotvar) @@ -1166,7 +1300,7 @@ Expression *CallExp::inlineScan(InlineScanState *iss) DotVarExp *dve = (DotVarExp *)e1; FuncDeclaration *fd = dve->var->isFuncDeclaration(); - if (fd && fd != iss->fd && fd->canInline(1)) + if (fd && fd != iss->fd && fd->canInline(1, 0, 0)) { if (dve->e1->op == TOKcall && dve->e1->type->toBasetype()->ty == Tstruct) @@ -1178,7 +1312,7 @@ Expression *CallExp::inlineScan(InlineScanState *iss) ; } else - e = fd->doInline(iss, dve->e1, arguments); + e = fd->expandInline(iss, dve->e1, arguments, NULL); } } @@ -1269,7 +1403,7 @@ void FuncDeclaration::inlineScan() #endif memset(&iss, 0, sizeof(iss)); iss.fd = this; - if (fbody) + if (fbody && !naked) { inlineNest++; fbody = fbody->inlineScan(&iss); @@ -1277,7 +1411,7 @@ void FuncDeclaration::inlineScan() } } -int FuncDeclaration::canInline(int hasthis, int hdrscan) +int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) { InlineCostState ics; int cost; @@ -1285,7 +1419,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) #define CANINLINE_LOG 0 #if CANINLINE_LOG - printf("FuncDeclaration::canInline(hasthis = %d, '%s')\n", hasthis, toChars()); + printf("FuncDeclaration::canInline(hasthis = %d, statementsToo = %d, '%s')\n", hasthis, statementsToo, toChars()); #endif if (needThis() && !hasthis) @@ -1299,7 +1433,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) return 0; } - switch (inlineStatus) + switch (statementsToo ? inlineStatusStmt : inlineStatusExp) { case ILSyes: #if CANINLINE_LOG @@ -1332,9 +1466,10 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) /* Don't inline a function that returns non-void, but has * no return expression. + * No statement inlining for non-voids. */ if (tf->next && tf->next->ty != Tvoid && - !(hasReturnExp & 1) && + (!(hasReturnExp & 1) || statementsToo) && !hdrscan) goto Lno; } @@ -1350,6 +1485,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) if ( !fbody || + ident == Id::ensure || // ensure() has magic properties the inliner loses !hdrscan && ( #if 0 @@ -1361,11 +1497,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) isSynchronized() || isImportedSymbol() || #if !IN_LLVM -#if DMDV2 - closureVars.dim || // no nested references to this frame -#else - nestedFrameRef || // no nested references to this frame -#endif + hasNestedFrameRefs() || // no nested references to this frame #endif // !IN_LLVM (isVirtual() && !isFinal()) )) @@ -1382,8 +1514,8 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) { for (size_t i = 0; i < parameters->dim; i++) { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - if (/*v->isOut() || v->isRef() ||*/ v->type->toBasetype()->ty == Tsarray) + VarDeclaration *v = parameters->tdata()[i]; + if (v->type->toBasetype()->ty == Tsarray) goto Lno; } } @@ -1396,18 +1528,47 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) ics.hdrscan = hdrscan; cost = fbody->inlineCost(&ics); #if CANINLINE_LOG - printf("cost = %d\n", cost); + printf("cost = %d for %s\n", cost, toChars()); #endif - if (cost >= COST_MAX) + if (tooCostly(cost)) + goto Lno; + if (!statementsToo && cost > COST_MAX) goto Lno; + if (!hdrscan) + { + // Don't modify inlineStatus for header content scan + if (statementsToo) + inlineStatusStmt = ILSyes; + else + inlineStatusExp = ILSyes; + #if !IN_LLVM - if (!hdrscan) // Don't scan recursively for header content scan - inlineScan(); + inlineScan(); // Don't scan recursively for header content scan #endif - if (!hdrscan) // Don't modify inlineStatus for header content scan - inlineStatus = ILSyes; + if (inlineStatusExp == ILSuninitialized) + { + // Need to redo cost computation, as some statements or expressions have been inlined + memset(&ics, 0, sizeof(ics)); + ics.hasthis = hasthis; + ics.fd = this; + ics.hdrscan = hdrscan; + cost = fbody->inlineCost(&ics); + #if CANINLINE_LOG + printf("recomputed cost = %d for %s\n", cost, toChars()); + #endif + if (tooCostly(cost)) + goto Lno; + if (!statementsToo && cost > COST_MAX) + goto Lno; + + if (statementsToo) + inlineStatusStmt = ILSyes; + else + inlineStatusExp = ILSyes; + } + } #if CANINLINE_LOG printf("\t2: yes %s\n", toChars()); #endif @@ -1415,26 +1576,34 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) Lno: if (!hdrscan) // Don't modify inlineStatus for header content scan - inlineStatus = ILSno; + { if (statementsToo) + inlineStatusStmt = ILSno; + else + inlineStatusExp = ILSno; + } #if CANINLINE_LOG printf("\t2: no %s\n", toChars()); #endif return 0; } -Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, Array *arguments) +Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethis, Expressions *arguments, Statement **ps) { InlineDoState ids; DeclarationExp *de; Expression *e = NULL; + Statements *as = NULL; -#if LOG - printf("FuncDeclaration::doInline('%s')\n", toChars()); +#if LOG || CANINLINE_LOG + printf("FuncDeclaration::expandInline('%s')\n", toChars()); #endif memset(&ids, 0, sizeof(ids)); ids.parent = iss->fd; + if (ps) + as = new Statements(); + // Set up vthis if (ethis) { @@ -1490,6 +1659,8 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, A { e = new DeclarationExp(0, ids.vthis); e->type = Type::tvoid; + if (as) + as->push(new ExpStatement(e->loc, e)); } if (arguments && arguments->dim) @@ -1498,9 +1669,9 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, A for (size_t i = 0; i < arguments->dim; i++) { - VarDeclaration *vfrom = (VarDeclaration *)parameters->data[i]; + VarDeclaration *vfrom = parameters->tdata()[i]; VarDeclaration *vto; - Expression *arg = (Expression *)arguments->data[i]; + Expression *arg = arguments->tdata()[i]; ExpInitializer *ei; VarExp *ve; @@ -1530,18 +1701,31 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, A de = new DeclarationExp(0, vto); de->type = Type::tvoid; - e = Expression::combine(e, de); + if (as) + as->push(new ExpStatement(0, de)); + else + e = Expression::combine(e, de); } } - inlineNest++; - Expression *eb = fbody->doInline(&ids); - inlineNest--; -//eb->type->print(); -//eb->print(); -//eb->dump(0); - - e = Expression::combine(e, eb); + if (ps) + { + inlineNest++; + Statement *s = fbody->doInlineStatement(&ids); + as->push(s); + *ps = new ScopeStatement(0, new CompoundStatement(0, as)); + inlineNest--; + } + else + { + inlineNest++; + Expression *eb = fbody->doInline(&ids); + e = Expression::combine(e, eb); + inlineNest--; + //eb->type->print(); + //eb->print(); + //eb->dump(0); + } /* There's a problem if what the function returns is used subsequently as an * lvalue, as in a struct return that is then used as a 'this'. @@ -1553,7 +1737,7 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, A * See Bugzilla 2127 for an example. */ TypeFunction *tf = (TypeFunction*)type; - if (tf->next->ty == Tstruct) + if (!ps && tf->next->ty == Tstruct) { /* Generate a new variable to hold the result and initialize it with the * inlined body of the function: @@ -1584,6 +1768,9 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, A //fprintf(stderr, "CallExp::inlineScan: e = "); e->print(); } + // Need to reevaluate whether parent can now be inlined + // in expressions, as we might have inlined statements + iss->fd->inlineStatusExp = ILSuninitialized; return e; } @@ -1603,7 +1790,7 @@ Expression *Expression::inlineCopy(Scope *sc) memset(&ics, 0, sizeof(ics)); ics.hdrscan = 1; // so DeclarationExp:: will work on 'statics' which are not - int cost = inlineCost(&ics); + int cost = expressionInlineCost(this, &ics); if (cost >= COST_MAX) { error("cannot inline default argument %s", toChars()); return new ErrorExp(); diff --git a/dmd/interpret.c b/dmd/interpret.c index 0cd938f6..3536542a 100644 --- a/dmd/interpret.c +++ b/dmd/interpret.c @@ -118,6 +118,7 @@ public: void pop(VarDeclaration *v) { assert(!v->isDataseg() || v->isCTFE()); + assert(!(v->storage_class & (STCref | STCout))); int oldid = v->ctfeAdrOnStack; v->ctfeAdrOnStack = (size_t)(savedId.tdata()[oldid]); if (v->ctfeAdrOnStack == values.dim - 1) @@ -202,7 +203,7 @@ void printCtfePerformanceStats() } -Expression * resolveReferences(Expression *e, Expression *thisval, bool *isReference = NULL); +Expression * resolveReferences(Expression *e, Expression *thisval); Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal); VarDeclaration *findParentVar(Expression *e, Expression *thisval); bool needToCopyLiteral(Expression *expr); @@ -211,6 +212,9 @@ Expression *paintTypeOntoLiteral(Type *type, Expression *lit); Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2); Expression *evaluateIfBuiltin(InterState *istate, Loc loc, FuncDeclaration *fd, Expressions *arguments, Expression *pthis); +Expression *scrubReturnValue(Loc loc, Expression *e); +bool isAssocArray(Type *t); +bool isPointer(Type *t); // CTFE only expressions #define TOKclassreference ((TOK)(TOKMAX+1)) @@ -259,8 +263,39 @@ struct ClassReferenceExp : Expression } return -1; } + // Return index of the field, or -1 if not found + // Same as getFieldIndex, but checks for a direct match with the VarDeclaration + int findFieldIndexByName(VarDeclaration *v) + { + ClassDeclaration *cd = originalClass(); + size_t fieldsSoFar = 0; + for (size_t j = 0; j < value->elements->dim; j++) + { while (j - fieldsSoFar >= cd->fields.dim) + { fieldsSoFar += cd->fields.dim; + cd = cd->baseClass; + } + Dsymbol *s = cd->fields.tdata()[j - fieldsSoFar]; + VarDeclaration *v2 = s->isVarDeclaration(); + if (v == v2) + { return value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar); + } + } + return -1; + } }; +// Return index of the field, or -1 if not found +// Same as getFieldIndex, but checks for a direct match with the VarDeclaration +int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v) +{ + for (int i = 0; i < sd->fields.dim; ++i) + { + if (sd->fields.tdata()[i] == v) + return i; + } + return -1; +} + // Fake class which holds the thrown exception. Used for implementing exception handling. struct ThrownExceptionExp : Expression { @@ -277,7 +312,7 @@ struct ThrownExceptionExp : Expression } char *toChars() { - return "CTFE ThrownException"; + return (char *)"CTFE ThrownException"; } // Generate an error message when this exception is not caught void generateUncaughtError() @@ -289,7 +324,7 @@ struct ThrownExceptionExp : Expression * (eg, in ScopeStatement) */ if (loc.filename && !loc.equals(thrown->loc)) - fprintf(stdmsg, "%s: thrown from here\n", loc.toChars()); + errorSupplemental(loc, "thrown from here"); } }; @@ -315,25 +350,30 @@ void showCtfeExpr(Expression *e, int level = 0) if (e->op == TOKstructliteral) { elements = ((StructLiteralExp *)e)->elements; sd = ((StructLiteralExp *)e)->sd; - printf("STRUCT type = %s %p :\n", e->type->toChars(), e); + printf("STRUCT type = %s %p:\n", e->type->toChars(), + e); } else if (e->op == TOKclassreference) { elements = ((ClassReferenceExp *)e)->value->elements; cd = ((ClassReferenceExp *)e)->originalClass(); - printf("CLASS type = %s %p :\n", e->type->toChars(), ((ClassReferenceExp *)e)->value->toChars()); + printf("CLASS type = %s %p:\n", e->type->toChars(), + ((ClassReferenceExp *)e)->value); } else if (e->op == TOKarrayliteral) { elements = ((ArrayLiteralExp *)e)->elements; - printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(), e); + printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(), + e); } else if (e->op == TOKassocarrayliteral) { - printf("AA LITERAL type=%s %p:\n", e->type->toChars(), e); + printf("AA LITERAL type=%s %p:\n", e->type->toChars(), + e); } else if (e->op == TOKstring) { - printf("STRING %s %p\n", e->toChars(), ((StringExp *)e)->string); + printf("STRING %s %p\n", e->toChars(), + ((StringExp *)e)->string); } else if (e->op == TOKslice) { @@ -347,7 +387,18 @@ void showCtfeExpr(Expression *e, int level = 0) if (v && v->getValue()) showCtfeExpr(v->getValue(), level + 1); } - else printf("VALUE %p: %s\n", e, e->toChars()); + else if (isPointer(e->type)) + { + // This is potentially recursive. We mustn't try to print the thing we're pointing to. + if (e->op == TOKindex) + printf("POINTER %p into %p [%s]\n", e, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2->toChars()); + else if (e->op == TOKdotvar) + printf("POINTER %p to %p .%s\n", e, ((DotVarExp *)e)->e1, ((DotVarExp *)e)->var->toChars()); + else + printf("POINTER %p: %s\n", e, e->toChars()); + } + else + printf("VALUE %p: %s\n", e, e->toChars()); if (elements) { @@ -355,6 +406,10 @@ void showCtfeExpr(Expression *e, int level = 0) for (size_t i = 0; i < elements->dim; i++) { Expression *z = NULL; Dsymbol *s = NULL; + if (i > 15) { + printf("...(total %d elements)\n", elements->dim); + return; + } if (sd) { s = sd->fields.tdata()[i]; z = elements->tdata()[i]; @@ -402,20 +457,16 @@ void showCtfeExpr(Expression *e, int level = 0) * arguments function arguments * thisarg 'this', if a needThis() function, NULL if not. * - * Return result expression if successful, NULL if not. + * Return result expression if successful, EXP_CANT_INTERPRET if not. */ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg) { #if LOG printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); - printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun); #endif - if (global.errors) - return NULL; - - if (cantInterpret || semanticRun == PASSsemantic3) - return NULL; + if (semanticRun == PASSsemantic3) + return EXP_CANT_INTERPRET; if (semanticRun < PASSsemantic3 && scope) { @@ -436,10 +487,10 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument if (spec && global.errors != olderrors) spec->errors = global.errors - olderrors; if (olderrors != global.errors) // if errors compiling this function - return NULL; + return EXP_CANT_INTERPRET; } if (semanticRun < PASSsemantic3done) - return NULL; + return EXP_CANT_INTERPRET; Type *tb = type->toBasetype(); assert(tb->ty == Tfunction); @@ -447,11 +498,18 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument Type *tret = tf->next->toBasetype(); if (tf->varargs && arguments && ((parameters && arguments->dim != parameters->dim) || (!parameters && arguments->dim))) - { cantInterpret = 1; + { error("C-style variadic functions are not yet implemented in CTFE"); - return NULL; + return EXP_CANT_INTERPRET; } + // Nested functions always inherit the 'this' pointer from the parent, + // except for delegates. (Note that the 'this' pointer may be null). + // Func literals report isNested() even if they are in global scope, + // so we need to check that the parent is a function. + if (isNested() && toParent2()->isFuncDeclaration() && !thisarg && istate) + thisarg = istate->localThis; + InterState istatex; istatex.caller = istate; istatex.fd = this; @@ -463,13 +521,14 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument if (needThis() && !thisarg) { // error, no this. Prevent segfault. error("need 'this' to access member %s", toChars()); - return NULL; + return EXP_CANT_INTERPRET; } if (thisarg && !istate) { // Check that 'this' aleady has a value if (thisarg->interpret(istate) == EXP_CANT_INTERPRET) - return NULL; + return EXP_CANT_INTERPRET; } + static int evaluatingArgs = 0; if (arguments) { dim = arguments->dim; @@ -481,7 +540,6 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument */ Expressions eargs; eargs.setDim(dim); - for (size_t i = 0; i < dim; i++) { Expression *earg = arguments->tdata()[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); @@ -491,12 +549,14 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument if (!istate && (arg->storageClass & STCout)) { // initializing an out parameter involves writing to it. earg->error("global %s cannot be passed as an 'out' parameter at compile time", earg->toChars()); - return NULL; + return EXP_CANT_INTERPRET; } // Convert all reference arguments into lvalue references + ++evaluatingArgs; earg = earg->interpret(istate, ctfeNeedLvalueRef); + --evaluatingArgs; if (earg == EXP_CANT_INTERPRET) - return NULL; + return earg; } else if (arg->storageClass & STClazy) { @@ -512,16 +572,18 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument */ earg = ((AddrExp *)earg)->e1; } + ++evaluatingArgs; earg = earg->interpret(istate); + --evaluatingArgs; if (earg == EXP_CANT_INTERPRET) - return NULL; - } + return earg; + } if (earg->op == TOKthrownexception) { if (istate) return earg; ((ThrownExceptionExp *)earg)->generateUncaughtError(); - return NULL; + return EXP_CANT_INTERPRET; } eargs.tdata()[i] = earg; } @@ -530,23 +592,31 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument { Expression *earg = eargs.tdata()[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); VarDeclaration *v = parameters->tdata()[i]; - ctfeStack.push(v); #if LOG printf("arg[%d] = %s\n", i, earg->toChars()); #endif - if (arg->storageClass & (STCout | STCref) && earg->op==TOKvar) - { - VarExp *ve = (VarExp *)earg; - VarDeclaration *v2 = ve->var->isVarDeclaration(); - if (!v2) + if (arg->storageClass & (STCout | STCref) && earg->op == TOKvar) + { + VarExp *ve = (VarExp *)earg; + VarDeclaration *v2 = ve->var->isVarDeclaration(); + if (!v2) { - error("cannot interpret %s as a ref parameter", ve->toChars()); - return NULL; - } - v->setValueWithoutChecking(earg); + error("cannot interpret %s as a ref parameter", ve->toChars()); + return EXP_CANT_INTERPRET; } + /* The push() isn't a variable we'll use, it's just a place + * to save the old value of v. + * Note that v might be v2! So we need to save v2's index + * before pushing. + */ + size_t oldadr = v2->ctfeAdrOnStack; + ctfeStack.push(v); + v->ctfeAdrOnStack = oldadr; + assert(v2->hasValue()); + } else { // Value parameters and non-trivial references + ctfeStack.push(v); v->setValueWithoutChecking(earg); } #if LOG || LOGASSIGN @@ -571,7 +641,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument { // This is a compiler error. It must not be suppressed. global.gag = 0; error("CTFE recursion limit exceeded"); - e = NULL; + e = EXP_CANT_INTERPRET; break; } e = fbody->interpret(&istatex); @@ -580,7 +650,6 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument #if LOG printf("function body failed to interpret\n"); #endif - e = NULL; } /* This is how we deal with a recursive statement AST @@ -604,12 +673,22 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument ctfeStack.endFrame(istatex.framepointer); - if (e == EXP_CANT_INTERPRET || !exceptionOrCantInterpret(e)) + // If fell off the end of a void function, return void + if (!e && type->toBasetype()->nextOf()->ty == Tvoid) + return EXP_VOID_INTERPRET; + // If it generated an exception, return it + if (exceptionOrCantInterpret(e)) + { + if (istate || e == EXP_CANT_INTERPRET) + return e; + ((ThrownExceptionExp *)e)->generateUncaughtError(); + return EXP_CANT_INTERPRET; + } + if (!istate && !evaluatingArgs) + { + e = scrubReturnValue(loc, e); + } return e; - if (istate) - return e; - ((ThrownExceptionExp *)e)->generateUncaughtError(); - return NULL; } /******************************** Statement ***************************/ @@ -729,7 +808,8 @@ Expression *UnrolledLoopStatement::interpret(InterState *istate) // For CTFE only. Returns true if 'e' is TRUE or a non-null pointer. int isTrueBool(Expression *e) { - return e->isBool(TRUE) || (e->type->ty == Tpointer && e->op != TOKnull); + return e->isBool(TRUE) || ((e->type->ty == Tpointer || e->type->ty == Tclass) + && e->op != TOKnull); } Expression *IfStatement::interpret(InterState *istate) @@ -826,6 +906,73 @@ Expression *ctfeEqual(enum TOK op, Type *type, Expression *e1, Expression *e2) return Equal(op, type, e1, e2); } +Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) +{ + Loc loc = e1->loc; + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + Expression *e; + if (e2->op == TOKstring && e1->op == TOKarrayliteral && + t1->nextOf()->isintegral()) + { + // [chars] ~ string => string (only valid for CTFE) + StringExp *es1 = (StringExp *)e2; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1; + size_t len = es1->len + es2->elements->dim; + int sz = es1->sz; + + void *s = mem.malloc((len + 1) * sz); + memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz); + for (size_t i = 0; i < es2->elements->dim; i++) + { Expression *es2e = es2->elements->tdata()[i]; + if (es2e->op != TOKint64) + return EXP_CANT_INTERPRET; + dinteger_t v = es2e->toInteger(); + memcpy((unsigned char *)s + i * sz, &v, sz); + } + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + StringExp *es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = 0; + es->type = type; + e = es; + return e; + } + else if (e1->op == TOKstring && e2->op == TOKarrayliteral && + t2->nextOf()->isintegral()) + { + // string ~ [chars] => string (only valid for CTFE) + // Concatenate the strings + StringExp *es1 = (StringExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + size_t len = es1->len + es2->elements->dim; + int sz = es1->sz; + + void *s = mem.malloc((len + 1) * sz); + memcpy(s, es1->string, es1->len * sz); + for (size_t i = 0; i < es2->elements->dim; i++) + { Expression *es2e = es2->elements->tdata()[i]; + if (es2e->op != TOKint64) + return EXP_CANT_INTERPRET; + dinteger_t v = es2e->toInteger(); + memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz); + } + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + StringExp *es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = 0; //es1->committed; + es->type = type; + e = es; + return e; + } + return Cat(type, e1, e2); +} void scrubArray(Loc loc, Expressions *elems); @@ -847,15 +994,22 @@ Expression *scrubReturnValue(Loc loc, Expression *e) if (e->op == TOKstructliteral) { StructLiteralExp *se = (StructLiteralExp *)e; + se->ownedByCtfe = false; scrubArray(loc, se->elements); - } + } + if (e->op == TOKstring) + { + ((StringExp *)e)->ownedByCtfe = false; + } if (e->op == TOKarrayliteral) { + ((ArrayLiteralExp *)e)->ownedByCtfe = false; scrubArray(loc, ((ArrayLiteralExp *)e)->elements); } if (e->op == TOKassocarrayliteral) { AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; + aae->ownedByCtfe = false; scrubArray(loc, aae->keys); scrubArray(loc, aae->values); } @@ -911,19 +1065,13 @@ Expression *ReturnStatement::interpret(InterState *istate) // We need to treat pointers specially, because TOKsymoff can be used to // return a value OR a pointer Expression *e; - if ((exp->type->ty == Tpointer && exp->type->nextOf()->ty != Tfunction)) + if ( isPointer(exp->type) ) e = exp->interpret(istate, ctfeNeedLvalue); else e = exp->interpret(istate); if (exceptionOrCantInterpret(e)) return e; - if (!istate->caller) - { - e = scrubReturnValue(loc, e); - if (e == EXP_CANT_INTERPRET) - return e; - } - else if (needToCopyLiteral(exp)) + if (needToCopyLiteral(e)) e = copyLiteral(e); #if LOGASSIGN printf("RETURN %s\n", loc.toChars()); @@ -1210,7 +1358,10 @@ Expression *SwitchStatement::interpret(InterState *istate) for (size_t i = 0; i < cases->dim; i++) { CaseStatement *cs = cases->tdata()[i]; - e = ctfeEqual(TOKequal, Type::tint32, econdition, cs->exp); + Expression * caseExp = cs->exp->interpret(istate); + if (exceptionOrCantInterpret(caseExp)) + return caseExp; + e = ctfeEqual(TOKequal, Type::tint32, econdition, caseExp); if (exceptionOrCantInterpret(e)) return e; if (e->isBool(TRUE)) @@ -1339,7 +1490,7 @@ Expression *TryCatchStatement::interpret(InterState *istate) if (ca->var) { ctfeStack.push(ca->var); - ca->var->createStackValue(ex->thrown); + ca->var->setValue(ex->thrown); } return ca->handler->interpret(istate); } @@ -1438,7 +1589,7 @@ Expression *WithStatement::interpret(InterState *istate) e->type = wthis->type; } ctfeStack.push(wthis); - wthis->createStackValue(e); + wthis->setValue(e); e = body ? body->interpret(istate) : EXP_VOID_INTERPRET; ctfeStack.pop(wthis); return e; @@ -1521,21 +1672,15 @@ Expression *StringExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("StringExp::interpret() %s\n", toChars()); #endif - /* Since we are using StringExps as reference types for char[] arrays, - * we need to dup them if there's any chance they'll be modified. - * For efficiency, we try to only dup when necessary. + /* In both D1 and D2, attempts to modify string literals are prevented + * in BinExp::interpretAssignCommon. + * In D2, we also disallow casts of read-only literals to mutable, + * though it isn't strictly necessary. */ +#if DMDV2 // Fixed-length char arrays always get duped later anyway. if (type->ty == Tsarray) return this; - /* String literals are normally immutable, so we don't need to dup them - * In D2, we can detect attempts to write to read-only literals. - * For D1, we could be pessimistic, and always dup. - * But since it fails only when there has been an explicit cast, and any - * such function would give different results at runtime anyway (eg, it - * may crash), it hardly seems worth the massive performance hit. - */ -#if DMDV2 if (!(((TypeNext *)type)->next->mod & (MODconst | MODimmutable))) { // It seems this happens only when there has been an explicit cast error("cannot cast a read-only string literal to mutable in CTFE"); @@ -1557,7 +1702,7 @@ Expression *FuncExp::interpret(InterState *istate, CtfeGoal goal) * srcPointee is the genuine type (never void). * destPointee may be void. */ -bool isSafePointerCast(Type *srcPointee, Type*destPointee) +bool isSafePointerCast(Type *srcPointee, Type *destPointee) { // It's OK if both are the same (modulo const) #if DMDV2 if (srcPointee->castMod(0) == destPointee->castMod(0)) @@ -1679,11 +1824,8 @@ Expression *DelegateExp::interpret(InterState *istate, CtfeGoal goal) // ------------------------------------------------------------- // The variable used in a dotvar, index, or slice expression, // after 'out', 'ref', and 'this' have been removed. -// *isReference will be set to true if a reference was removed. -Expression * resolveReferences(Expression *e, Expression *thisval, bool *isReference /*=NULL */) +Expression * resolveReferences(Expression *e, Expression *thisval) { - if (isReference) - *isReference = false; for(;;) { if (e->op == TOKthis) @@ -1693,31 +1835,15 @@ Expression * resolveReferences(Expression *e, Expression *thisval, bool *isRefer e = thisval; continue; } - if (e->op == TOKvar) { - // Chase down rebinding of out and ref. + if (e->op == TOKvar) + { VarExp *ve = (VarExp *)e; VarDeclaration *v = ve->var->isVarDeclaration(); if (v->type->ty == Tpointer) break; if (v->ctfeAdrOnStack == (size_t)-1) // If not on the stack, can't possibly be a ref. break; - if (v && v->getValue() && v->getValue()->op == TOKvar) // it's probably a reference - { - // Make sure it's a real reference. - // It's not a reference if v is a struct initialized to - // 0 using an __initZ SymbolDeclaration from - // TypeStruct::defaultInit() - VarExp *ve2 = (VarExp *)v->getValue(); - //if (!ve2->var->isSymbolDeclaration()) - if (!ve2->var->isStaticStructInitDeclaration()) - { - if (isReference) - *isReference = true; - e = v->getValue(); - continue; - } - } - else if (v && v->getValue() && (v->getValue()->op == TOKslice)) + if (v && v->getValue() && (v->getValue()->op == TOKslice)) { SliceExp *se = (SliceExp *)v->getValue(); if (se->e1->op == TOKarrayliteral || se->e1->op == TOKassocarrayliteral || se->e1->op == TOKstring) @@ -1765,7 +1891,7 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal e = e->interpret(istate, ctfeNeedAnyValue); v->inuse--; if (e == EXP_CANT_INTERPRET && !global.gag && !CtfeStatus::stackTraceCallsToSuppress) - fprintf(stdmsg, "%s: while evaluating %s.init\n", loc.toChars(), v->toChars()); + errorSupplemental(loc, "while evaluating %s.init", v->toChars()); if (exceptionOrCantInterpret(e)) return e; e->type = v->type; @@ -1777,13 +1903,16 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal if (e) e = e->interpret(istate, ctfeNeedAnyValue); if (e == EXP_CANT_INTERPRET && !global.gag && !CtfeStatus::stackTraceCallsToSuppress) - fprintf(stdmsg, "%s: while evaluating %s.init\n", loc.toChars(), v->toChars()); - } + errorSupplemental(loc, "while evaluating %s.init", v->toChars()); + } if (e && e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) + { + e = copyLiteral(e); if (v->isDataseg()) ctfeStack.saveGlobalConstant(v, e); else v->setValueWithoutChecking(e); + } } else if (v->isCTFE() && !v->hasValue()) { @@ -1814,6 +1943,17 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal error(loc, "variable %s is used before initialization", v->toChars()); else if (exceptionOrCantInterpret(e)) return e; + else if (goal == ctfeNeedLvalue && v->isRef() && e->op == TOKindex) + { // If it is a foreach ref, resolve the index into a constant + IndexExp *ie = (IndexExp *)e; + Expression *w = ie->e2->interpret(istate); + if (w != ie->e2) + { + e = new IndexExp(ie->loc, ie->e1, w); + e->type = ie->type; + } + return e; + } else if ((goal == ctfeNeedLvalue) || e->op == TOKstring || e->op == TOKstructliteral || e->op == TOKarrayliteral || e->op == TOKassocarrayliteral || e->op == TOKslice @@ -1832,13 +1972,12 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal if (s->dsym->toInitializer() == s->sym) { #endif - Expressions *exps = new Expressions(); - e = new StructLiteralExp(loc, s->dsym, exps); - e = e->semantic(NULL); + e = s->dsym->type->defaultInitLiteral(); + 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 @@ -1855,10 +1994,7 @@ Expression *VarExp::interpret(InterState *istate, CtfeGoal goal) #endif if (goal == ctfeNeedLvalueRef) { - // If it is a reference, return the thing it's pointing to. VarDeclaration *v = var->isVarDeclaration(); - if (v && v->hasValue() && (v->storage_class & (STCref | STCout))) - return v->getValue(); if (v && !v->isDataseg() && !v->isCTFE() && !istate) { error("variable %s cannot be referenced at compile time", v->toChars()); return EXP_CANT_INTERPRET; @@ -2022,6 +2158,8 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("ArrayLiteralExp::interpret() %s\n", toChars()); #endif + if (ownedByCtfe) // We've already interpreted all the elements + return copyLiteral(this); if (elements) { for (size_t i = 0; i < elements->dim; i++) @@ -2060,7 +2198,7 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) goto Lerror; ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); ae->type = type; - return ae; + return copyLiteral(ae); } #if DMDV2 if (((TypeNext *)type)->next->mod & (MODconst | MODimmutable)) @@ -2084,6 +2222,8 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); #endif + if (ownedByCtfe) // We've already interpreted all the elements + return copyLiteral(this); for (size_t i = 0; i < keys->dim; i++) { Expression *ekey = keys->tdata()[i]; Expression *evalue = values->tdata()[i]; @@ -2158,6 +2298,7 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) AssocArrayLiteralExp *ae; ae = new AssocArrayLiteralExp(loc, keysx, valuesx); ae->type = type; + ae->ownedByCtfe = true; return ae; } return this; @@ -2182,6 +2323,8 @@ Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) { error("Unions with overlapping fields are not yet supported in CTFE"); return EXP_CANT_INTERPRET; } + if (ownedByCtfe) + return copyLiteral(this); if (elements) { @@ -2222,6 +2365,7 @@ Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) } StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); se->type = type; + se->ownedByCtfe = true; return se; } return copyLiteral(this); @@ -2231,7 +2375,7 @@ Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) * Helper for NewExp * Create an array literal consisting of 'elem' duplicated 'dim' times. */ -ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, +ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type, Expression *elem, size_t dim) { Expressions *elements = new Expressions(); @@ -2242,8 +2386,9 @@ ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, elem = copyLiteral(elem); elements->tdata()[i] = elem; } - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); + ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); ae->type = type; + ae->ownedByCtfe = true; return ae; } @@ -2251,7 +2396,7 @@ ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, * Helper for NewExp * Create a string literal consisting of 'value' duplicated 'dim' times. */ -StringExp *createBlockDuplicatedStringLiteral(Type *type, +StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type, unsigned value, size_t dim, int sz) { unsigned char *s; @@ -2266,16 +2411,17 @@ StringExp *createBlockDuplicatedStringLiteral(Type *type, default: assert(0); } } - StringExp *se = new StringExp(0, s, dim); + StringExp *se = new StringExp(loc, s, dim); se->type = type; se->sz = sz; se->committed = true; + se->ownedByCtfe = true; return se; } // Create an array literal of type 'newtype' with dimensions given by // 'arguments'[argnum..$] -Expression *recursivelyCreateArrayLiteral(Type *newtype, InterState *istate, +Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *istate, Expressions *arguments, int argnum) { Expression *lenExpr = ((arguments->tdata()[argnum]))->interpret(istate); @@ -2285,7 +2431,7 @@ Expression *recursivelyCreateArrayLiteral(Type *newtype, InterState *istate, Type *elemType = ((TypeArray *)newtype)->next; if (elemType->ty == Tarray && argnum < arguments->dim - 1) { - Expression *elem = recursivelyCreateArrayLiteral(elemType, istate, + Expression *elem = recursivelyCreateArrayLiteral(loc, elemType, istate, arguments, argnum + 1); if (exceptionOrCantInterpret(elem)) return elem; @@ -2294,17 +2440,18 @@ Expression *recursivelyCreateArrayLiteral(Type *newtype, InterState *istate, elements->setDim(len); for (size_t i = 0; i < len; i++) elements->tdata()[i] = copyLiteral(elem); - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); + ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); ae->type = newtype; + ae->ownedByCtfe = true; return ae; } assert(argnum == arguments->dim - 1); if (elemType->ty == Tchar || elemType->ty == Twchar || elemType->ty == Tdchar) - return createBlockDuplicatedStringLiteral(newtype, + return createBlockDuplicatedStringLiteral(loc, newtype, (unsigned)(elemType->defaultInitLiteral()->toInteger()), len, elemType->size()); - return createBlockDuplicatedArrayLiteral(newtype, + return createBlockDuplicatedArrayLiteral(loc, newtype, elemType->defaultInitLiteral(), len); } @@ -2315,7 +2462,7 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) printf("NewExp::interpret() %s\n", toChars()); #endif if (newtype->ty == Tarray && arguments) - return recursivelyCreateArrayLiteral(newtype, istate, arguments, 0); + return recursivelyCreateArrayLiteral(loc, newtype, istate, arguments, 0); if (newtype->toBasetype()->ty == Tstruct) { @@ -2335,7 +2482,7 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) // but that's OK because D1 doesn't have struct constructors anyway. assert(!member); #endif - Expression *e = new AddrExp(loc, se); + Expression *e = new AddrExp(loc, copyLiteral(se)); e->type = type; return e; } @@ -2359,12 +2506,13 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(); if (exceptionOrCantInterpret(m)) return m; - elems->tdata()[fieldsSoFar+i] = m; + elems->tdata()[fieldsSoFar+i] = copyLiteral(m); } } // Hack: we store a ClassDeclaration instead of a StructDeclaration. // We probably won't get away with this. StructLiteralExp *se = new StructLiteralExp(loc, (StructDeclaration *)cd, elems, newtype); + se->ownedByCtfe = true; Expression *e = new ClassReferenceExp(loc, se, type); if (member) { // Call constructor @@ -2418,6 +2566,21 @@ Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs) *ofs = 0; if (e->op == TOKaddress) e = ((AddrExp *)e)->e1; + if (e->op == TOKdotvar) + { + Expression *ex = ((DotVarExp *)e)->e1; + VarDeclaration *v = ((DotVarExp *)e)->var->isVarDeclaration(); + assert(v); + StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex; + // We can't use getField, because it makes a copy + int i = -1; + if (ex->op == TOKclassreference) + i = ((ClassReferenceExp *)ex)->getFieldIndex(e->type, v->offset); + else + i = se->getFieldIndex(e->type, v->offset); + assert(i != -1); + e = se->elements->tdata()[i]; + } if (e->op == TOKindex) { IndexExp *ie = (IndexExp *)e; @@ -2616,10 +2779,12 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex dinteger_t ofs1, ofs2; Expression *agg1 = getAggregateFromPointer(e1, &ofs1); Expression *agg2 = getAggregateFromPointer(e2, &ofs2); + // Note that type painting can occur with VarExp, so we + // must compare the variables being pointed to. if (agg1 == agg2 || - (agg1->op == TOKstring && agg2->op == TOKstring && - ((StringExp *)agg1)->string == ((StringExp *)agg2)->string)) - + (agg1->op == TOKvar && agg2->op == TOKvar && + ((VarExp *)agg1)->var == ((VarExp *)agg2)->var) + ) { dinteger_t cm = ofs1 - ofs2; dinteger_t n; @@ -2640,11 +2805,11 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex return new IntegerExp(loc, n, type); } int cmp; - if (e1->op == TOKnull) + if (agg1->op == TOKnull) { - cmp = (e2->op == TOKnull); + cmp = (agg2->op == TOKnull); } - else if (e2->op == TOKnull) + else if (agg2->op == TOKnull) { cmp = 0; } @@ -2667,6 +2832,22 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex return new IntegerExp(loc, cmp, type); } +Expression *ctfeIdentity(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ + if (e1->op == TOKclassreference || e2->op == TOKclassreference) + { + int cmp = 0; + if (e1->op == TOKclassreference && e2->op == TOKclassreference && + ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value) + cmp = 1; + if (op == TOKnotidentity || op == TOKnotequal) + cmp ^= 1; + return new IntegerExp(e1->loc, cmp, type); + } + return Identity(op, type, e1, e2); +} + + Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp) { Expression *e; Expression *e1; @@ -2702,7 +2883,8 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp e1->op != TOKnull && e1->op != TOKstring && e1->op != TOKarrayliteral && - e1->op != TOKstructliteral) + e1->op != TOKstructliteral && + e1->op != TOKclassreference) { error("cannot compare %s at compile time", e1->toChars()); goto Lcant; @@ -2717,7 +2899,8 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp e2->op != TOKnull && e2->op != TOKstring && e2->op != TOKarrayliteral && - e2->op != TOKstructliteral) + e2->op != TOKstructliteral && + e2->op != TOKclassreference) { error("cannot compare %s at compile time", e2->toChars()); goto Lcant; @@ -2731,15 +2914,15 @@ Lcant: return EXP_CANT_INTERPRET; } -#define BIN_INTERPRET2(op) \ +#define BIN_INTERPRET2(op, opfunc) \ Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretCommon2(istate, goal, &op); \ +{ \ + return interpretCommon2(istate, goal, &opfunc); \ } -BIN_INTERPRET2(Equal) -BIN_INTERPRET2(Identity) -BIN_INTERPRET2(Cmp) +BIN_INTERPRET2(Equal, Equal) +BIN_INTERPRET2(Identity, ctfeIdentity) +BIN_INTERPRET2(Cmp, Cmp) /* Helper functions for BinExp::interpretAssignCommon */ @@ -2771,8 +2954,9 @@ Expression * modifyStructField(Type *type, StructLiteralExp *se, size_t offset, /* Create new struct literal reflecting updated fieldi */ Expressions *expsx = changeOneElement(se->elements, fieldi, newval); - Expression * ee = new StructLiteralExp(se->loc, se->sd, expsx); + StructLiteralExp * ee = new StructLiteralExp(se->loc, se->sd, expsx); ee->type = se->type; + ee->ownedByCtfe = 1; return ee; } @@ -2862,9 +3046,11 @@ bool needToCopyLiteral(Expression *expr) switch (expr->op) { case TOKarrayliteral: + return !((ArrayLiteralExp *)expr)->ownedByCtfe; case TOKassocarrayliteral: + return !((AssocArrayLiteralExp *)expr)->ownedByCtfe; case TOKstructliteral: - return true; + return !((StructLiteralExp *)expr)->ownedByCtfe; case TOKstring: case TOKthis: case TOKvar: @@ -2918,6 +3104,7 @@ Expression *copyLiteral(Expression *e) se2->postfix = se->postfix; se2->type = se->type; se2->sz = se->sz; + se2->ownedByCtfe = true; return se2; } else if (e->op == TOKarrayliteral) @@ -2926,6 +3113,7 @@ Expression *copyLiteral(Expression *e) ArrayLiteralExp *r = new ArrayLiteralExp(e->loc, copyLiteralArray(ae->elements)); r->type = e->type; + r->ownedByCtfe = true; return r; } else if (e->op == TOKassocarrayliteral) @@ -2934,6 +3122,7 @@ Expression *copyLiteral(Expression *e) AssocArrayLiteralExp *r = new AssocArrayLiteralExp(e->loc, copyLiteralArray(aae->keys), copyLiteralArray(aae->values)); r->type = e->type; + r->ownedByCtfe = true; return r; } /* syntaxCopy doesn't work for struct literals, because of a nasty special @@ -2964,7 +3153,7 @@ Expression *copyLiteral(Expression *e) // Block assignment from inside struct literals TypeSArray *tsa = (TypeSArray *)v->type; uinteger_t length = tsa->dim->toInteger(); - m = createBlockDuplicatedArrayLiteral(v->type, m, (size_t)length); + m = createBlockDuplicatedArrayLiteral(e->loc, v->type, m, (size_t)length); } else if (v->type->ty != Tarray && v->type->ty!=Taarray) // NOTE: do not copy array references m = copyLiteral(m); @@ -2976,6 +3165,7 @@ Expression *copyLiteral(Expression *e) StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems); #endif r->type = e->type; + r->ownedByCtfe = true; return r; } else if (e->op == TOKfunction || e->op == TOKdelegate @@ -2988,7 +3178,7 @@ Expression *copyLiteral(Expression *e) r->type = e->type; return r; } - else if (e->type->ty == Tpointer && e->type->nextOf()->ty != Tfunction) + else if ( isPointer(e->type) ) { // For pointers, we only do a shallow copy. Expression *r; if (e->op == TOKaddress) @@ -3047,8 +3237,8 @@ Expression *paintTypeOntoLiteral(Type *type, Expression *lit) } else if (lit->op == TOKarrayliteral) { - ArrayLiteralExp *ae = (ArrayLiteralExp *)lit; - e = new ArrayLiteralExp(lit->loc, ae->elements); + e = new SliceExp(lit->loc, lit, + new IntegerExp(0, 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit)); } else if (lit->op == TOKstring) { @@ -3059,10 +3249,20 @@ Expression *paintTypeOntoLiteral(Type *type, Expression *lit) else if (lit->op == TOKassocarrayliteral) { AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)lit; - e = new AssocArrayLiteralExp(lit->loc, aae->keys, aae->values); + // TODO: we should be creating a reference to this AAExp, not + // just a ref to the keys and values. + bool wasOwned = aae->ownedByCtfe; + aae = new AssocArrayLiteralExp(lit->loc, aae->keys, aae->values); + aae->ownedByCtfe = wasOwned; + e = aae; } else + { // Can't type paint from struct to struct*; this needs another + // level of indirection + if (lit->op == TOKstructliteral && isPointer(type) ) + lit->error("CTFE internal error painting %s", type->toChars()); e = copyLiteral(lit); + } e->type = type; return e; } @@ -3079,77 +3279,18 @@ Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e) if (originalClass->type->implicitConvTo(to)) return paintTypeOntoLiteral(to, e); else - { - error(loc, "cannot reinterpret class from %s to %s at compile time", originalClass->toChars(), to->toChars()); - return EXP_CANT_INTERPRET; - } + return new NullExp(loc, to); } Expression *r = Cast(type, to, e); if (r == EXP_CANT_INTERPRET) - error(loc, "cannot cast %s to %s at compile time", r->toChars(), to->toChars()); + error(loc, "cannot cast %s to %s at compile time", e->toChars(), to->toChars()); + if (e->op == TOKarrayliteral) + ((ArrayLiteralExp *)e)->ownedByCtfe = true; + if (e->op == TOKstring) + ((StringExp *)e)->ownedByCtfe = true; return r; } - -/* Set a slice of char array literal 'existingAE' from a string 'newval'. - * existingAE[firstIndex..firstIndex+newval.length] = newval. - */ -void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex) -{ - size_t newlen = newval->len; - size_t sz = newval->sz; - unsigned char *s = (unsigned char *)newval->string; - Type *elemType = existingAE->type->nextOf(); - for (size_t j = 0; j < newlen; j++) - { - 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; - } - existingAE->elements->tdata()[j+firstIndex] - = new IntegerExp(newval->loc, val, elemType); - } -} - -/* Set a slice of string 'existingSE' from a char array literal 'newae'. - * existingSE[firstIndex..firstIndex+newae.length] = newae. - */ -void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex) -{ - unsigned char *s = (unsigned char *)existingSE->string; - for (size_t j = 0; j < newae->elements->dim; j++) - { - unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger()); - switch (existingSE->sz) - { - case 1: s[j+firstIndex] = value; break; - case 2: ((unsigned short *)s)[j+firstIndex] = value; break; - case 4: ((unsigned *)s)[j+firstIndex] = value; break; - default: - assert(0); - break; - } - } -} - -/* Set a slice of string 'existingSE' from a string 'newstr'. - * existingSE[firstIndex..firstIndex+newstr.length] = newstr. - */ -void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex) -{ - unsigned char *s = (unsigned char *)existingSE->string; - size_t sz = existingSE->sz; - assert(sz == newstr->sz); - memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len); -} - - /* Set dest = src, where both dest and src are container value literals * (ie, struct literals, or static arrays (can be an array literal or a string) * Assignment is recursively in-place. @@ -3290,7 +3431,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ } 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 == Tarray || isAssocArray(e1->type)) // e = *x is never a reference, because *x is always a value && this->e2->op != TOKstar ) @@ -3325,15 +3466,12 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ { wantRef = true; } - /* This happens inside compiler-generated foreach statements. - * It's another case where we need a reference - * Note that a similar case, where e2 = 'this', occurs in - * construction of a struct with an invariant(). - */ - if (op==TOKconstruct && this->e1->op==TOKvar && this->e2->op != TOKthis - && this->e2->op != TOKcomma + // If it is a construction of a ref variable, it is a ref assignment + if (op == TOKconstruct && this->e1->op==TOKvar && ((VarExp*)this->e1)->var->storage_class & STCref) - wantRef = true; + { + wantRef = true; + } if (fp) { @@ -3396,7 +3534,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ // return a value OR a pointer assert(e1); assert(e1->type); - if ((e1->type->ty == Tpointer && e1->type->nextOf()->ty != Tfunction) && (e2->op == TOKsymoff || e2->op==TOKaddress || e2->op==TOKvar)) + if ( isPointer(e1->type) && (e2->op == TOKsymoff || e2->op==TOKaddress || e2->op==TOKvar)) newval = this->e2->interpret(istate, ctfeNeedLvalue); else newval = this->e2->interpret(istate); @@ -3429,7 +3567,9 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ // ~= can create new values (see bug 6052) if (op == TOKcatass) { - if (needToCopyLiteral(newval)) + // We need to dup it. We can skip this if it's a dynamic array, + // because it gets copied later anyway + if (newval->type->ty != Tarray) newval = copyLiteral(newval); if (newval->op == TOKslice) newval = resolveSlice(newval); @@ -3502,26 +3642,53 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ Expressions *elements = new Expressions(); elements->setDim(newlen); size_t copylen = oldlen < newlen ? oldlen : newlen; - if (oldlen !=0) - assert(oldval->op == TOKarrayliteral); - ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval; - for (size_t i = 0; i < copylen; i++) - elements->tdata()[i] = ae->elements->tdata()[i]; - if (elemType->ty == Tstruct || elemType->ty == Tsarray) - { /* If it is an aggregate literal representing a value type, - * we need to create a unique copy for each element - */ - for (size_t i = copylen; i < newlen; i++) - elements->tdata()[i] = copyLiteral(defaultElem); + if (oldval->op == TOKstring) + { + StringExp *oldse = (StringExp *)oldval; + unsigned char *s = (unsigned char *)mem.calloc(newlen + 1, oldse->sz); + memcpy(s, oldse->string, copylen * oldse->sz); + unsigned defaultValue = (unsigned)(defaultElem->toInteger()); + for (size_t elemi = copylen; elemi < newlen; ++elemi) + { + switch (oldse->sz) + { + case 1: s[elemi] = defaultValue; break; + case 2: ((unsigned short *)s)[elemi] = defaultValue; break; + case 4: ((unsigned *)s)[elemi] = defaultValue; break; + default: assert(0); + } + } + StringExp *se = new StringExp(loc, s, newlen); + se->type = t; + se->sz = oldse->sz; + se->committed = oldse->committed; + se->ownedByCtfe = true; + newval = se; } else { - for (size_t i = copylen; i < newlen; i++) - elements->tdata()[i] = defaultElem; + if (oldlen !=0) + assert(oldval->op == TOKarrayliteral); + ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval; + for (size_t i = 0; i < copylen; i++) + elements->tdata()[i] = ae->elements->tdata()[i]; + if (elemType->ty == Tstruct || elemType->ty == Tsarray) + { /* If it is an aggregate literal representing a value type, + * we need to create a unique copy for each element + */ + for (size_t i = copylen; i < newlen; i++) + elements->tdata()[i] = copyLiteral(defaultElem); + } + else + { + for (size_t i = copylen; i < newlen; i++) + elements->tdata()[i] = defaultElem; + } + ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements); + aae->type = t; + newval = aae; + aae->ownedByCtfe = true; } - ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements); - aae->type = t; - newval = aae; // We have changed it into a reference assignment // Note that returnValue is still the new length. wantRef = true; @@ -3572,28 +3739,13 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ return EXP_CANT_INTERPRET; } - // This happens inside compiler-generated foreach statements. - if (op==TOKconstruct && this->e1->op==TOKvar && - this->e2->op == TOKindex - && ((VarExp*)this->e1)->var->storage_class & STCref) - { - VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration(); -#if (LOGASSIGN) - printf("FOREACH ASSIGN %s=%s\n", v->toChars(), e2->toChars()); -#endif - v->setValueNull(); - v->createStackValue(e2); - return e2; - } - - bool destinationIsReference = false; - e1 = resolveReferences(e1, istate->localThis, &destinationIsReference); + e1 = resolveReferences(e1, istate->localThis); // 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->getValue()) - ultimateVar->createRefValue(copyLiteral(ultimateVar->type->defaultInitLiteral())); + ultimateVar->setValue(copyLiteral(ultimateVar->type->defaultInitLiteral())); // --------------------------------------- // Deal with reference assignment @@ -3616,7 +3768,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ if (newval->op == TOKassocarrayliteral || newval->op == TOKstring || newval->op==TOKarrayliteral) { - if (needToCopyLiteral(this->e2)) + if (needToCopyLiteral(newval)) newval = copyLiteral(newval); } returnValue = newval; @@ -3680,6 +3832,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ Expressions *keysx = new Expressions(); newAA = new AssocArrayLiteralExp(loc, keysx, valuesx); newAA->type = xe->type; + newAA->ownedByCtfe = true; //... and insert it into the existing AA. existingAA->keys->push(indx); existingAA->values->push(newAA); @@ -3708,8 +3861,10 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ Expressions *keysx = new Expressions(); valuesx->push(newval); keysx->push(index); - newval = new AssocArrayLiteralExp(loc, keysx, valuesx); - newval->type = e1->type; + AssocArrayLiteralExp *newaae = new AssocArrayLiteralExp(loc, keysx, valuesx); + newaae->ownedByCtfe = true; + newaae->type = e1->type; + newval = newaae; e1 = ((IndexExp *)e1)->e1; } // We must return to the original aggregate, in case it was a reference @@ -3727,8 +3882,10 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ if (!wantRef && e1->op == TOKdotvar) { // Strip of all of the leading dotvars, unless we started with a call + // or a ref parameter // (in which case, we already have the lvalue). - if (this->e1->op != TOKcall) + if (this->e1->op != TOKcall && !(this->e1->op==TOKvar + && ((VarExp*)this->e1)->var->storage_class & (STCref | STCout))) e1 = e1->interpret(istate, ctfeNeedLvalue); if (exceptionOrCantInterpret(e1)) return e1; @@ -3756,37 +3913,32 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ if (wantRef) { v->setValueNull(); - v->createRefValue(newval); - } + v->setValue(newval); + } else if (e1->type->toBasetype()->ty == Tstruct) - { + { // In-place modification if (newval->op != TOKstructliteral) { error("CTFE internal error assigning struct"); - return EXP_CANT_INTERPRET; - } + return EXP_CANT_INTERPRET; + } newval = copyLiteral(newval); if (v->getValue()) assignInPlace(v->getValue(), newval); else - v->createRefValue(newval); - } + v->setValue(newval); + } else - { + { TY tyE1 = e1->type->toBasetype()->ty; if (tyE1 == Tarray || tyE1 == Taarray) { // arr op= arr - if (!v->getValue()) - v->createRefValue(newval); - else v->setRefValue(newval); - } - else + v->setValue(newval); + } + else { - if (!v->getValue()) // creating a new value - v->createStackValue(newval); - else - v->setStackValue(newval); + v->setValue(newval); } } } @@ -3862,7 +4014,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ { IntegerExp *dollarExp = new IntegerExp(loc, destarraylen, Type::tsize_t); ctfeStack.push(ie->lengthVar); - ie->lengthVar->createStackValue(dollarExp); + ie->lengthVar->setValue(dollarExp); } } Expression *index = ie->e2->interpret(istate); @@ -3903,7 +4055,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ } if (indexToModify >= destarraylen) { - error("array index %d is out of bounds [0..%d]", indexToModify, + error("array index %lld is out of bounds [0..%lld]", indexToModify, destarraylen); return EXP_CANT_INTERPRET; } @@ -3920,10 +4072,19 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ if (exceptionOrCantInterpret(aggregate)) return aggregate; // The array could be an index of an AA. Resolve it if so. - if (aggregate->op == TOKindex) + if (aggregate->op == TOKindex && + ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) { IndexExp *ix = (IndexExp *)aggregate; - aggregate = Index(ix->type, ix->e1, ix->e2); + aggregate = findKeyInAA((AssocArrayLiteralExp *)ix->e1, ix->e2); + if (!aggregate) + { + error("key %s not found in associative array %s", + ix->e2->toChars(), ix->e1->toChars()); + return EXP_CANT_INTERPRET; + } + if (exceptionOrCantInterpret(aggregate)) + return aggregate; } } if (aggregate->op == TOKvar) @@ -3980,6 +4141,11 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ if (existingSE) { unsigned char *s = (unsigned char *)existingSE->string; + if (!existingSE->ownedByCtfe) + { + error("cannot modify read-only string literal %s", ie->e1->toChars()); + return EXP_CANT_INTERPRET; + } unsigned value = newval->toInteger(); switch (existingSE->sz) { @@ -4009,7 +4175,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ // Set the $ variable Expression *oldval = sexp->e1; bool assignmentToSlicedPointer = false; - if (oldval->type->toBasetype()->ty == Tpointer && oldval->type->toBasetype()->nextOf()->ty != Tfunction) + if (isPointer(oldval->type)) { // Slicing a pointer oldval = oldval->interpret(istate, ctfeNeedLvalue); dinteger_t ofs; @@ -4029,7 +4195,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ { Expression *arraylen = new IntegerExp(loc, dollar, Type::tsize_t); ctfeStack.push(sexp->lengthVar); - sexp->lengthVar->createStackValue(arraylen); + sexp->lengthVar->setValue(arraylen); } Expression *upper = NULL; @@ -4080,10 +4246,19 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ if (exceptionOrCantInterpret(aggregate)) return aggregate; // The array could be an index of an AA. Resolve it if so. - if (aggregate->op == TOKindex) + if (aggregate->op == TOKindex && + ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) { - IndexExp *ie = (IndexExp *)aggregate; - aggregate = Index(ie->type, ie->e1, ie->e2); + IndexExp *ix = (IndexExp *)aggregate; + aggregate = findKeyInAA((AssocArrayLiteralExp *)ix->e1, ix->e2); + if (!aggregate) + { + error("key %s not found in associative array %s", + ix->e2->toChars(), ix->e1->toChars()); + return EXP_CANT_INTERPRET; + } + if (exceptionOrCantInterpret(aggregate)) + return aggregate; } } if (aggregate->op == TOKvar) @@ -4102,11 +4277,11 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ error("slice [%d..%d] exceeds array bounds [0..%jd]", lowerbound, upperbound, sexpold->upr->toInteger() - sexpold->lwr->toInteger()); - return EXP_CANT_INTERPRET; - } - aggregate = sexpold->e1; + return EXP_CANT_INTERPRET; } - if (aggregate->type->toBasetype()->ty == Tpointer && aggregate->type->toBasetype()->nextOf()->ty != Tfunction) + aggregate = sexpold->e1; + } + if ( isPointer(aggregate->type) ) { // Slicing a pointer --> change the bounds aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue); dinteger_t ofs; @@ -4120,10 +4295,14 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ return EXP_CANT_INTERPRET; } } - if (aggregate->op==TOKarrayliteral) + if (aggregate->op == TOKarrayliteral) existingAE = (ArrayLiteralExp *)aggregate; - else if (aggregate->op==TOKstring) + else if (aggregate->op == TOKstring) existingSE = (StringExp *)aggregate; + if (existingSE && !existingSE->ownedByCtfe) + { error("cannot modify read-only string literal %s", sexp->e1->toChars()); + return EXP_CANT_INTERPRET; + } if (!wantRef && newval->op == TOKslice) { @@ -4264,15 +4443,17 @@ Expression *AssignExp::interpret(InterState *istate, CtfeGoal goal) return interpretAssignCommon(istate, goal, NULL); } -#define BIN_ASSIGN_INTERPRET(op) \ +#define BIN_ASSIGN_INTERPRET_CTFE(op, ctfeOp) \ Expression *op##AssignExp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretAssignCommon(istate, goal, &op); \ +{ \ + return interpretAssignCommon(istate, goal, &ctfeOp); \ } +#define BIN_ASSIGN_INTERPRET(op) BIN_ASSIGN_INTERPRET_CTFE(op, op) + BIN_ASSIGN_INTERPRET(Add) BIN_ASSIGN_INTERPRET(Min) -BIN_ASSIGN_INTERPRET(Cat) +BIN_ASSIGN_INTERPRET_CTFE(Cat, ctfeCat) BIN_ASSIGN_INTERPRET(Mul) BIN_ASSIGN_INTERPRET(Div) BIN_ASSIGN_INTERPRET(Mod) @@ -4322,6 +4503,11 @@ Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) e = e2->interpret(istate); if (exceptionOrCantInterpret(e)) return e; + if (e == EXP_VOID_INTERPRET) + { + assert(type->ty == Tvoid); + return NULL; + } if (e != EXP_CANT_INTERPRET) { if (e->isBool(FALSE)) @@ -4366,6 +4552,11 @@ Expression *OrOrExp::interpret(InterState *istate, CtfeGoal goal) if (exceptionOrCantInterpret(e)) return e; + if (e == EXP_VOID_INTERPRET) + { + assert(type->ty == Tvoid); + return NULL; + } if (e != EXP_CANT_INTERPRET) { if (e->isBool(FALSE)) @@ -4399,7 +4590,7 @@ void showCtfeBackTrace(InterState *istate, CallExp * callingExp, FuncDeclaration --CtfeStatus::stackTraceCallsToSuppress; return; } - fprintf(stdmsg, "%s: called from here: %s\n", callingExp->loc.toChars(), callingExp->toChars()); + errorSupplemental(callingExp->loc, "called from here: %s", callingExp->toChars()); // Quit if it's not worth trying to compress the stack trace if (CtfeStatus::callDepth < 6 || global.params.verbose) return; @@ -4421,10 +4612,10 @@ void showCtfeBackTrace(InterState *istate, CallExp * callingExp, FuncDeclaration if (recurseCount < 2) return; // We found a useful recursion. Print all the calls involved in the recursion - fprintf(stdmsg, "%s: %d recursive calls to function %s\n", fd->loc.toChars(), recurseCount, fd->toChars()); + errorSupplemental(fd->loc, "%d recursive calls to function %s", recurseCount, fd->toChars()); for (InterState *cur = istate; cur->fd != fd; cur = cur->caller) { - fprintf(stdmsg, "%s: recursively called from function %s\n", cur->fd->loc.toChars(), cur->fd->toChars()); + errorSupplemental(cur->fd->loc, "recursively called from function %s", cur->fd->toChars()); } // We probably didn't enter the recursion in this function. // Go deeper to find the real beginning. @@ -4536,8 +4727,12 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) } if (pthis) { // Member function call + Expression *oldpthis; if (pthis->op == TOKthis) - pthis = istate ? istate->localThis : NULL; + { + pthis = istate ? istate->localThis : NULL; + oldpthis = pthis; + } else { if (pthis->op == TOKcomma) @@ -4545,41 +4740,46 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) if (exceptionOrCantInterpret(pthis)) return pthis; // Evaluate 'this' - Expression *oldpthis = pthis; + oldpthis = pthis; if (pthis->op != TOKvar) pthis = pthis->interpret(istate, ctfeNeedLvalue); if (exceptionOrCantInterpret(pthis)) return pthis; - if (fd->isVirtual()) - { // Make a virtual function call. - Expression *thisval = pthis; - if (pthis->op == TOKvar) - { assert(((VarExp*)thisval)->var->isVarDeclaration()); - thisval = ((VarExp*)thisval)->var->isVarDeclaration()->getValue(); - } - // Get the function from the vtable of the original class - ClassDeclaration *cd; - if (thisval && thisval->op == TOKnull) - { - error("function call through null class reference %s", pthis->toChars()); - return EXP_CANT_INTERPRET; - } - if (oldpthis->op == TOKsuper) - { assert(oldpthis->type->ty == Tclass); - cd = ((TypeClass *)oldpthis->type)->sym; - } - else - { - assert(thisval && thisval->op == TOKclassreference); - cd = ((ClassReferenceExp *)thisval)->originalClass(); - } - // We can't just use the vtable index to look it up, because - // vtables for interfaces don't get populated until the glue layer. - fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type); - - assert(fd); - } } + if (fd->isVirtual()) + { // Make a virtual function call. + Expression *thisval = pthis; + if (pthis->op == TOKvar) + { assert(((VarExp*)thisval)->var->isVarDeclaration()); + thisval = ((VarExp*)thisval)->var->isVarDeclaration()->getValue(); + } + // Get the function from the vtable of the original class + ClassDeclaration *cd; + if (thisval && thisval->op == TOKnull) + { + error("function call through null class reference %s", pthis->toChars()); + return EXP_CANT_INTERPRET; + } + if (oldpthis->op == TOKsuper) + { assert(oldpthis->type->ty == Tclass); + cd = ((TypeClass *)oldpthis->type)->sym; + } + else + { + assert(thisval && thisval->op == TOKclassreference); + cd = ((ClassReferenceExp *)thisval)->originalClass(); + } + // We can't just use the vtable index to look it up, because + // vtables for interfaces don't get populated until the glue layer. + fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type); + + assert(fd); + } + } + if (fd && fd->semanticRun >= PASSsemantic3done && fd->semantic3Errors) + { + error("CTFE failed because of previous errors in %s", fd->toChars()); + return EXP_CANT_INTERPRET; } // Check for built-in functions Expression *eresult = evaluateIfBuiltin(istate, loc, fd, arguments, pthis); @@ -4597,28 +4797,23 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) { if (e->op == TOKslice) e= resolveSlice(e); - e = expType(type, e); - e = copyLiteral(e); + e = paintTypeOntoLiteral(type, copyLiteral(e)); } return e; } - if (!fd->fbody) - { - error("%s cannot be interpreted at compile time," - " because it has no available source code", fd->toChars()); - return EXP_CANT_INTERPRET; - } + if (!fd->fbody) + { + error("%s cannot be interpreted at compile time," + " because it has no available source code", fd->toChars()); + return EXP_CANT_INTERPRET; + } eresult = fd->interpret(istate, arguments, pthis); - if (eresult) - e = eresult; - else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) - e = EXP_VOID_INTERPRET; - else + if (eresult == EXP_CANT_INTERPRET) { // Print a stack trace. if (!global.gag) showCtfeBackTrace(istate, this, fd); } - return e; + return eresult; } Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal) @@ -4654,7 +4849,7 @@ Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal) ctfeStack.push(v); if (!v->init && !v->getValue()) { - v->createRefValue(copyLiteral(v->type->defaultInitLiteral())); + v->setValue(copyLiteral(v->type->defaultInitLiteral())); } if (!v->getValue()) { Expression *newval = v->init->toExpression(); @@ -4697,7 +4892,7 @@ Expression *CondExp::interpret(InterState *istate, CtfeGoal goal) printf("CondExp::interpret() %s\n", toChars()); #endif Expression *e; - if (econd->type->ty == Tpointer && econd->type->nextOf()->ty != Tfunction) + if ( isPointer(econd->type) ) { e = econd->interpret(istate, ctfeNeedLvalue); if (exceptionOrCantInterpret(e)) @@ -4773,6 +4968,34 @@ Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2) return NULL; } +/* Same as for constfold.Index, except that it only works for static arrays, + * dynamic arrays, and strings. We know that e1 is an + * interpreted CTFE expression, so it cannot have side-effects. + */ +Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx) +{ //printf("ctfeIndex(e1 = %s)\n", e1->toChars()); + assert(e1->type); + if (e1->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + if (indx >= es1->len) + { + error(loc, "string index %ju is out of bounds [0 .. %zu]", indx, es1->len); + return EXP_CANT_INTERPRET; + } + else + return new IntegerExp(loc, es1->charAt(indx), type); + } + assert(e1->op == TOKarrayliteral); + ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + if (indx >= ale->elements->dim) + { + error(loc, "array index %ju is out of bounds %s[0 .. %u]", indx, e1->toChars(), ale->elements->dim); + return EXP_CANT_INTERPRET; + } + Expression *e = ale->elements->tdata()[indx]; + return paintTypeOntoLiteral(type, e); +} + Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e1 = NULL; @@ -4807,9 +5030,11 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) indx+ofs, len); return EXP_CANT_INTERPRET; } - return Index(type, agg, new IntegerExp(loc, indx+ofs, Type::tsize_t)); + return ctfeIndex(loc, type, agg, indx+ofs); } - e1 = this->e1->interpret(istate); + e1 = this->e1; + if (!(e1->op == TOKarrayliteral && ((ArrayLiteralExp *)e1)->ownedByCtfe)) + e1 = e1->interpret(istate); if (exceptionOrCantInterpret(e1)) return e1; @@ -4829,7 +5054,7 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) uinteger_t dollar = resolveArrayLength(e1); Expression *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t); ctfeStack.push(lengthVar); - lengthVar->createStackValue(dollarExp); + lengthVar->setValue(dollarExp); } e2 = this->e2->interpret(istate); @@ -4874,22 +5099,21 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) e2->toChars(), this->e1->toChars()); return EXP_CANT_INTERPRET; } - if (exceptionOrCantInterpret(e)) - return e; - assert(!e->checkSideEffect(2)); - e = paintTypeOntoLiteral(type, e); } else { - e = Index(type, e1, e2); - } - if (e == EXP_CANT_INTERPRET) - { - error("%s cannot be interpreted at compile time", toChars()); - return e; + if (e2->op != TOKint64) + { + e1->error("CTFE internal error: non-integral index [%s]", this->e2->toChars()); + return EXP_CANT_INTERPRET; + } + e = ctfeIndex(loc, type, e1, e2->toInteger()); } + if (exceptionOrCantInterpret(e)) + return e; if (goal == ctfeNeedRvalue && (e->op == TOKslice || e->op == TOKdotvar)) e = e->interpret(istate); + e = paintTypeOntoLiteral(type, e); return e; } @@ -4959,7 +5183,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) if (goal == ctfeNeedRvalue && this->e1->op == TOKstring) e1 = this->e1; // Will get duplicated anyway else - e1 = this->e1->interpret(istate, goal); + e1 = this->e1->interpret(istate); if (exceptionOrCantInterpret(e1)) return e1; if (e1->op == TOKvar) @@ -4977,7 +5201,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) if (e1->op != TOKarrayliteral && e1->op != TOKstring && e1->op != TOKnull && e1->op != TOKslice) { - error("Cannot determine length of %s at compile time\n", e1->toChars()); + error("Cannot determine length of %s at compile time", e1->toChars()); return EXP_CANT_INTERPRET; } uinteger_t dollar = resolveArrayLength(e1); @@ -4985,7 +5209,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) { IntegerExp *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t); ctfeStack.push(lengthVar); - lengthVar->createStackValue(dollarExp); + lengthVar->setValue(dollarExp); } /* Evaluate lower and upper bounds of slice @@ -5102,24 +5326,38 @@ Expression *CatExp::interpret(InterState *istate, CtfeGoal goal) return e2; if (e2->op == TOKslice) e2 = resolveSlice(e2); - e = Cat(type, e1, e2); + e = ctfeCat(type, e1, e2); if (e == EXP_CANT_INTERPRET) error("%s cannot be interpreted at compile time", toChars()); + // We know we still own it, because we interpreted both e1 and e2 + if (e->op == TOKarrayliteral) + ((ArrayLiteralExp *)e)->ownedByCtfe = true; + if (e->op == TOKstring) + ((StringExp *)e)->ownedByCtfe = true; return e; } -#if DMDV2 + +// Return true if t is a pointer (not a function pointer) +bool isPointer(Type *t) +{ + Type * tb = t->toBasetype(); + return tb->ty == Tpointer && tb->nextOf()->ty != Tfunction; +} + // Return true if t is an AA, or AssociativeArray!(key, value) bool isAssocArray(Type *t) { t = t->toBasetype(); if (t->ty == Taarray) return true; +#if DMDV2 if (t->ty != Tstruct) return false; StructDeclaration *sym = ((TypeStruct *)t)->sym; if (sym->ident == Id::AssociativeArray) return true; +#endif return false; } @@ -5129,14 +5367,18 @@ TypeAArray *toBuiltinAAType(Type *t) t = t->toBasetype(); if (t->ty == Taarray) return (TypeAArray *)t; +#if DMDV2 assert(t->ty == Tstruct); StructDeclaration *sym = ((TypeStruct *)t)->sym; assert(sym->ident == Id::AssociativeArray); TemplateInstance *tinst = sym->parent->isTemplateInstance(); assert(tinst); return new TypeAArray((Type *)(tinst->tiargs->tdata()[1]), (Type *)(tinst->tiargs->tdata()[0])); -} +#else + assert(0); + return NULL; #endif +} Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) { Expression *e; @@ -5305,19 +5547,11 @@ Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("AssertExp::interpret() %s\n", toChars()); #endif - if (this->e1->op == TOKthis) - { - if (istate->localThis) - { - if (istate->localThis->op == TOKdotvar - && ((DotVarExp *)(istate->localThis))->e1->op == TOKthis) - return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var, ctfeNeedRvalue); - else - return istate->localThis->interpret(istate); - } - } +#if DMDV2 + e1 = this->e1->interpret(istate); +#else // Deal with pointers (including compiler-inserted assert(&this, "null this")) - if (this->e1->type->ty == Tpointer && this->e1->type->nextOf()->ty != Tfunction) + if ( isPointer(this->e1->type) ) { e1 = this->e1->interpret(istate, ctfeNeedLvalue); if (exceptionOrCantInterpret(e1)) @@ -5326,7 +5560,8 @@ Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal) return new IntegerExp(loc, 1, Type::tbool); } else - e1 = this->e1->interpret(istate); + e1 = this->e1->interpret(istate); +#endif if (exceptionOrCantInterpret(e1)) return e1; if (isTrueBool(e1)) @@ -5430,7 +5665,7 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) toChars(), len); return EXP_CANT_INTERPRET; } - e = Index(type, ie->e1, ie->e2); + e = ctfeIndex(loc, type, ie->e1, indx); if (isGenuineIndex) { if (e->op == TOKindex) @@ -5520,9 +5755,9 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) // We can't use getField, because it makes a copy int i = -1; if (ex->op == TOKclassreference) - i = ((ClassReferenceExp *)ex)->getFieldIndex(type, v->offset); + i = ((ClassReferenceExp *)ex)->findFieldIndexByName(v); else - i = se->getFieldIndex(type, v->offset); + i = findFieldIndexByName(se->sd, v); if (i == -1) { error("couldn't find field %s of type %s in %s", v->toChars(), type->toChars(), se->toChars()); @@ -5537,14 +5772,14 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) if ((type->ty == Tsarray || goal == ctfeNeedLvalue) && ( e->op == TOKarrayliteral || e->op == TOKassocarrayliteral || e->op == TOKstring || - e->op == TOKslice)) + e->op == TOKclassreference || e->op == TOKslice)) return e; /* Element is an allocated pointer, which was created in * CastExp. */ if (goal == ctfeNeedLvalue && e->op == TOKindex && e->type == type && - (type->ty == Tpointer && type->nextOf()->ty != Tfunction)) + isPointer(type) ) return e; // ...Otherwise, just return the (simplified) dotvar expression e = new DotVarExp(loc, ex, v); @@ -5560,9 +5795,15 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) if (e->op == TOKstructliteral || e->op == TOKarrayliteral || e->op == TOKassocarrayliteral || e->op == TOKstring) return e; - if (type->ty == Tpointer && type->nextOf()->ty != Tfunction) + if ( isPointer(type) ) { - assert(e->type == type); + return paintTypeOntoLiteral(type, e); + } + if (e->op == TOKvar) + { // Don't typepaint twice, since that might cause an erroneous copy + e = getVarExp(loc, istate, ((VarExp *)e)->var, goal); + if (e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) + e = paintTypeOntoLiteral(type, e); return e; } return e->interpret(istate, goal); @@ -5610,7 +5851,7 @@ Expression *RemoveExp::interpret(InterState *istate, CtfeGoal goal) } valuesx->dim = valuesx->dim - removed; keysx->dim = keysx->dim - removed; - return EXP_VOID_INTERPRET; + return new IntegerExp(loc, removed?1:0, Type::tbool); } @@ -5648,9 +5889,10 @@ Expression *interpret_keys(InterState *istate, Expression *earg, Type *elemType) return NULL; assert(earg->op == TOKassocarrayliteral); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); - e->type = new TypeSArray(elemType, new IntegerExp(aae->keys->dim)); - return copyLiteral(e); + ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->keys); + ae->ownedByCtfe = aae->ownedByCtfe; + ae->type = new TypeSArray(elemType, new IntegerExp(aae->keys->dim)); + return copyLiteral(ae); } Expression *interpret_values(InterState *istate, Expression *earg, Type *elemType) @@ -5669,10 +5911,11 @@ Expression *interpret_values(InterState *istate, Expression *earg, Type *elemTyp return NULL; assert(earg->op == TOKassocarrayliteral); AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->values); - e->type = new TypeSArray(elemType, new IntegerExp(aae->values->dim)); + ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->values); + ae->ownedByCtfe = aae->ownedByCtfe; + ae->type = new TypeSArray(elemType, new IntegerExp(aae->values->dim)); //printf("result is %s\n", e->toChars()); - return copyLiteral(e); + return copyLiteral(ae); } // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value) @@ -6131,9 +6374,13 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, * These functions exist to check for compiler CTFE bugs. */ -bool IsStackValueValid(Expression *newval) +bool isCtfeValueValid(Expression *newval) { - if (newval->type->ty == Tpointer && newval->type->nextOf()->ty != Tfunction) + if ( +#if DMDV2 + newval->type->ty == Tnull || +#endif + isPointer(newval->type) ) { if (newval->op == TOKaddress || newval->op == TOKnull || newval->op == TOKstring) @@ -6151,16 +6398,10 @@ bool IsStackValueValid(Expression *newval) return true; if (newval->op == TOKint64) return true; // Result of a cast, but cannot be dereferenced - newval->error("CTFE internal error: illegal pointer value %s\n", newval->toChars()); - return false; + // else it must be a reference } if (newval->op == TOKclassreference || (newval->op == TOKnull && newval->type->ty == Tclass)) return true; - if ((newval->op == TOKarrayliteral) || ( newval->op == TOKstructliteral) || - (newval->op == TOKstring) || (newval->op == TOKassocarrayliteral) || - (newval->op == TOKnull) || (newval->op == TOKslice)) - { return false; - } if (newval->op == TOKvar) { VarExp *ve = (VarExp *)newval; @@ -6172,7 +6413,10 @@ bool IsStackValueValid(Expression *newval) if (newval->op == TOKdotvar) { if (((DotVarExp *)newval)->e1->op == TOKstructliteral) + { + assert(((StructLiteralExp *)((DotVarExp *)newval)->e1)->ownedByCtfe); return true; + } } if (newval->op == TOKindex) { @@ -6198,13 +6442,16 @@ bool IsStackValueValid(Expression *newval) 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); + // References + + if (newval->op == TOKstructliteral) + assert(((StructLiteralExp *)newval)->ownedByCtfe); + if (newval->op == TOKarrayliteral) + assert(((ArrayLiteralExp *)newval)->ownedByCtfe); + if (newval->op == TOKassocarrayliteral) + assert(((AssocArrayLiteralExp *)newval)->ownedByCtfe); + if ((newval->op ==TOKarrayliteral) || ( newval->op==TOKstructliteral) || (newval->op==TOKstring) || (newval->op == TOKassocarrayliteral) || (newval->op == TOKnull)) @@ -6214,16 +6461,19 @@ bool IsRefValueValid(Expression *newval) // they may originate from an index or dotvar expression. if (newval->type->ty == Tarray || newval->type->ty == Taarray) if (newval->op == TOKdotvar || newval->op == TOKindex) - return IsStackValueValid(newval); // actually must be null + return true; // actually must be null + if (newval->op == TOKslice) { SliceExp *se = (SliceExp *)newval; assert(se->lwr && se->lwr != EXP_CANT_INTERPRET && se->lwr->op == TOKint64); assert(se->upr && se->upr != EXP_CANT_INTERPRET && se->upr->op == TOKint64); assert(se->e1->op == TOKarrayliteral || se->e1->op == TOKstring); + if (se->e1->op == TOKarrayliteral) + assert(((ArrayLiteralExp *)se->e1)->ownedByCtfe); return true; } - newval->error("CTFE internal error: illegal reference value %s\n", newval->toChars()); + newval->error("CTFE internal error: illegal value %s\n", newval->toChars()); return false; } @@ -6250,26 +6500,8 @@ void VarDeclaration::setValueWithoutChecking(Expression *newval) ctfeStack.setValue(this, newval); } -void VarDeclaration::createRefValue(Expression *newval) +void VarDeclaration::setValue(Expression *newval) { - assert(IsRefValueValid(newval)); - ctfeStack.setValue(this, newval); -} - -void VarDeclaration::setRefValue(Expression *newval) -{ - assert(IsRefValueValid(newval)); - ctfeStack.setValue(this, newval); -} - -void VarDeclaration::setStackValue(Expression *newval) -{ - assert(IsStackValueValid(newval)); - ctfeStack.setValue(this, newval); -} - -void VarDeclaration::createStackValue(Expression *newval) -{ - assert(IsStackValueValid(newval)); + assert(isCtfeValueValid(newval)); ctfeStack.setValue(this, newval); } diff --git a/dmd/lexer.c b/dmd/lexer.c index acfa45a1..1ba4d15b 100644 --- a/dmd/lexer.c +++ b/dmd/lexer.c @@ -123,11 +123,11 @@ const char *Token::toChars() break; case TOKint64v: - sprintf(buffer,"%jdL",int64value); + sprintf(buffer,"%jdL",(intmax_t)int64value); break; case TOKuns64v: - sprintf(buffer,"%juUL",uns64value); + sprintf(buffer,"%juUL",(uintmax_t)uns64value); break; #if IN_GCC @@ -1148,6 +1148,12 @@ void Lexer::scan(Token *t) else t->value = TOKequal; // == } +#if DMDV2 + else if (*p == '>') + { p++; + t->value = TOKgoesto; // => + } +#endif else t->value = TOKassign; // = return; @@ -2073,7 +2079,13 @@ TOK Lexer::number(Token *t) continue; } if (c == '.' && p[1] != '.') + { +#if DMDV2 + if (isalpha(p[1]) || p[1] == '_') + goto done; +#endif goto real; + } else if (c == 'i' || c == 'f' || c == 'F' || c == 'e' || c == 'E') { @@ -3016,6 +3028,7 @@ static Keyword keywords[] = { "__thread", TOKtls }, { "__gshared", TOKgshared }, { "__traits", TOKtraits }, + { "__vector", TOKvector }, { "__overloadset", TOKoverloadset }, { "__FILE__", TOKfile }, { "__LINE__", TOKline }, @@ -3035,25 +3048,22 @@ int Token::isKeyword() } void Lexer::initKeywords() -{ StringValue *sv; - unsigned u; - enum TOK v; +{ unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]); - stringtable.init(); + stringtable.init(1543); if (global.params.Dversion == 1) nkeywords -= 2; cmtable_init(); - for (u = 0; u < nkeywords; u++) - { const char *s; - + for (unsigned u = 0; u < nkeywords; u++) + { //printf("keyword[%d] = '%s'\n",u, keywords[u].name); - s = keywords[u].name; - v = keywords[u].value; - sv = stringtable.insert(s, strlen(s)); + const char *s = keywords[u].name; + enum TOK v = keywords[u].value; + StringValue *sv = stringtable.insert(s, strlen(s)); sv->ptrvalue = (void *) new Identifier(sv->lstring.string,v); //printf("tochars[%d] = '%s'\n",v, s); @@ -3150,6 +3160,7 @@ void Lexer::initKeywords() Token::tochars[TOKat] = "@"; Token::tochars[TOKpow] = "^^"; Token::tochars[TOKpowass] = "^^="; + Token::tochars[TOKgoesto] = "=>"; #endif // For debugging diff --git a/dmd/mars.c b/dmd/mars.c index 564dc331..1faab5e8 100644 --- a/dmd/mars.c +++ b/dmd/mars.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -72,9 +72,9 @@ Global::Global() obj_ext_alt = "obj"; #endif - copyright = "Copyright (c) 1999-2011 by Digital Mars and Tomas Lindquist Olsen"; + copyright = "Copyright (c) 1999-2012 by Digital Mars and Tomas Lindquist Olsen"; written = "written by Walter Bright and Tomas Lindquist Olsen"; - version = "v1.072"; + version = "v1.073"; ldc_version = "LDC trunk"; llvm_version = "LLVM 3.0"; global.structalign = 8; @@ -132,7 +132,7 @@ bool Loc::equals(const Loc& loc) } /************************************** - * Print error message and exit. + * Print error message */ void error(Loc loc, const char *format, ...) @@ -151,6 +151,18 @@ void warning(Loc loc, const char *format, ...) va_end( ap ); } +/************************************** + * Print supplementary message about the last error + * Used for backtraces, etc + */ +void errorSupplemental(Loc loc, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + verrorSupplemental(loc, format, ap); + va_end( ap ); +} + void verror(Loc loc, const char *format, va_list ap) { if (!global.gag) @@ -174,6 +186,25 @@ void verror(Loc loc, const char *format, va_list ap) global.errors++; } +// Doesn't increase error count, doesn't print "Error:". +void verrorSupplemental(Loc loc, const char *format, va_list ap) +{ + if (!global.gag) + { + fprintf(stdmsg, "%s: ", loc.toChars()); +#if _MSC_VER + // MS doesn't recognize %zu format + OutBuffer tmp; + tmp.vprintf(format, ap); + fprintf(stdmsg, "%s", tmp.toChars()); +#else + vfprintf(stdmsg, format, ap); +#endif + fprintf(stdmsg, "\n"); + fflush(stdmsg); + } +} + void vwarning(Loc loc, const char *format, va_list ap) { if (global.params.warnings && !global.gag) @@ -221,7 +252,7 @@ void fatal() void halt() { #ifdef DEBUG - *(char*)0=0; + *(volatile char*)0=0; #endif } diff --git a/dmd/mars.h b/dmd/mars.h index 2f2bd4f3..efe25de9 100644 --- a/dmd/mars.h +++ b/dmd/mars.h @@ -496,8 +496,10 @@ typedef uint64_t StorageClass; void warning(Loc loc, const char *format, ...) IS_PRINTF(2); void error(Loc loc, const char *format, ...) IS_PRINTF(2); +void errorSupplemental(Loc loc, const char *format, ...); void verror(Loc loc, const char *format, va_list); void vwarning(Loc loc, const char *format, va_list); +void verrorSupplemental(Loc loc, const char *format, va_list); #ifdef __GNUC__ __attribute__((noreturn)) #endif diff --git a/dmd/module.c b/dmd/module.c index 7cf14a6b..8bc37da4 100644 --- a/dmd/module.c +++ b/dmd/module.c @@ -726,6 +726,12 @@ void Module::importAll(Scope *prevsc) if (scope) return; // already done + if (isDocFile) + { + error("is a Ddoc file, cannot import it"); + return; + } + /* Note that modules get their own scope, from scratch. * This is so regardless of where in the syntax a module * gets imported, it is unaffected by context. @@ -733,14 +739,14 @@ void Module::importAll(Scope *prevsc) */ Scope *sc = Scope::createGlobal(this); // create root scope - // Add import of "object" if this module isn't "object" - if (ident != Id::object) + // Add import of "object", even for the "object" module. + // If it isn't there, some compiler rewrites, like + // classinst == classinst -> .object.opEquals(classinst, classinst) + // would fail inside object.d. + if (members->dim == 0 || ((*members)[0])->ident != Id::object) { - if (members->dim == 0 || ((*members)[0])->ident != Id::object) - { - Import *im = new Import(0, NULL, Id::object, NULL, 0); - members->shift(im); - } + Import *im = new Import(0, NULL, Id::object, NULL, 0); + members->shift(im); } if (!symtab) diff --git a/dmd/mtype.c b/dmd/mtype.c index 76228a85..3ba7dbb8 100644 --- a/dmd/mtype.c +++ b/dmd/mtype.c @@ -190,7 +190,7 @@ void Type::init(Ir* _sir) void Type::init() #endif { - stringtable.init(); + stringtable.init(1543); deco_stringtable.init(); Lexer::initKeywords(); @@ -1950,6 +1950,12 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol *pe = (Expression *)o; return; } + if (o->dyncast() == DYNCAST_TYPE) + { + *ps = NULL; + *pt = (Type *)o; + return; + } /* Create a new TupleDeclaration which * is a slice [d..d+1] out of the old one. @@ -1992,7 +1998,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) { error(loc, "tuple index %ju exceeds %u", d, sd->objects->dim); return Type::terror; } - Object *o = (Object *)sd->objects->data[(size_t)d]; + Object *o = (*sd->objects)[(size_t)d]; if (o->dyncast() != DYNCAST_TYPE) { error(loc, "%s is not a type", toChars()); return Type::terror; @@ -3154,6 +3160,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) Scope *argsc = sc->push(); argsc->stc = 0; // don't inherit storage class argsc->protection = PROTpublic; + argsc->func = NULL; size_t dim = Parameter::dim(tf->parameters); for (size_t i = 0; i < dim; i++) @@ -4744,7 +4751,7 @@ Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) if (!sym->members) { error(e->loc, "struct %s is forward referenced", sym->toChars()); - return new IntegerExp(e->loc, 0, Type::tint32); + return new ErrorExp(); } /* If e.tupleof @@ -4755,10 +4762,11 @@ Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) * (e.field0, e.field1, e.field2, ...) */ e = e->semantic(sc); // do this before turning on noaccesscheck + e->type->size(); // do semantic of type Expressions *exps = new Expressions; exps->reserve(sym->fields.dim); for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; + { VarDeclaration *v = sym->fields[i]; Expression *fe = new DotVarExp(e->loc, e, v); exps->push(fe); } @@ -4820,9 +4828,8 @@ L1: TemplateMixin *tm = s->isTemplateMixin(); if (tm) - { Expression *de; - - de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); + { + Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); de->type = e->type; return de; } @@ -4851,8 +4858,7 @@ L1: return de; } - Import *timp = s->isImport(); - if (timp) + if (s->isImport() || s->isModule() || s->isPackage()) { e = new DsymbolExp(e->loc, s); e = e->semantic(sc); @@ -4949,7 +4955,7 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) structelems->setDim(sym->fields.dim); for (size_t j = 0; j < structelems->dim; j++) { - VarDeclaration *vd = (VarDeclaration *)(sym->fields.data[j]); + VarDeclaration *vd = sym->fields[j]; Expression *e; if (vd->init) { if (vd->init->isVoidInitializer()) @@ -4959,7 +4965,7 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) } else e = vd->type->defaultInitLiteral(); - structelems->data[j] = e; + structelems->tdata()[j] = e; } StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems); // Why doesn't the StructLiteralExp constructor do this, when @@ -5020,6 +5026,7 @@ Type *TypeClass::semantic(Loc loc, Scope *sc) //printf("TypeClass::semantic(%s)\n", sym->toChars()); if (deco) return this; + //printf("\t%s\n", merge()->deco); return merge(); } @@ -5060,7 +5067,6 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) VarDeclaration *v; Dsymbol *s; DotVarExp *de; - Declaration *d; #if LOGDOTEXP printf("TypeClass::dotExp(e='%s', ident='%s')\n", e->toChars(), ident->toChars()); @@ -5084,10 +5090,11 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) /* Create a TupleExp */ e = e->semantic(sc); // do this before turning on noaccesscheck + e->type->size(); // do semantic of type Expressions *exps = new Expressions; exps->reserve(sym->fields.dim); for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; + { VarDeclaration *v = sym->fields[i]; // Don't include hidden 'this' pointer if (v->isThisDeclaration()) continue; @@ -5107,22 +5114,16 @@ L1: if (!s) { // See if it's a base class - ClassDeclaration *cbase; - for (cbase = sym->baseClass; cbase; cbase = cbase->baseClass) + if (Dsymbol *cbase = sym->searchBase(e->loc, ident)) { - if (cbase->ident->equals(ident)) - { - e = new DotTypeExp(0, e, cbase); - return e; - } + e = new DotTypeExp(0, e, cbase); + return e; } if (ident == Id::classinfo) { - Type *t; - assert(ClassDeclaration::classinfo); - t = ClassDeclaration::classinfo->type; + Type *t = ClassDeclaration::classinfo->type; if (e->op == TOKtype || e->op == TOKdottype) { /* For type.classinfo, we know the classinfo @@ -5271,9 +5272,8 @@ L1: TemplateMixin *tm = s->isTemplateMixin(); if (tm) - { Expression *de; - - de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); + { + Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); de->type = e->type; return de; } @@ -5302,11 +5302,20 @@ L1: return de; } - d = s->isDeclaration(); +#if 0 // shouldn't this be here? + if (s->isImport() || s->isModule() || s->isPackage()) + { + e = new DsymbolExp(e->loc, s, 0); + e = e->semantic(sc); + return e; + } +#endif + + Declaration *d = s->isDeclaration(); if (!d) { e->error("%s.%s is not a declaration", e->toChars(), ident->toChars()); - return new IntegerExp(e->loc, 1, Type::tint32); + return new ErrorExp(); } if (e->op == TOKtype) @@ -5335,7 +5344,7 @@ L1: { e = new ThisExp(e->loc); e = new DotTypeExp(e->loc, e, cd); - de = new DotVarExp(e->loc, e, d); + DotVarExp *de = new DotVarExp(e->loc, e, d); e = de->semantic(sc); return e; } @@ -5345,7 +5354,10 @@ L1: } } - de = new DotVarExp(e->loc, new ThisExp(e->loc), d); + /* Rewrite as: + * this.d + */ + DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d); e = de->semantic(sc); return e; } @@ -5371,9 +5383,7 @@ L1: if (d->parent && d->toParent()->isModule()) { // (e, d) - VarExp *ve; - - ve = new VarExp(e->loc, d); + VarExp *ve = new VarExp(e->loc, d); e = new CommaExp(e->loc, e, ve); e->type = d->type; return e; @@ -5413,7 +5423,7 @@ MATCH TypeClass::implicitConvTo(Type *to) ClassDeclaration *cdto = to->isClassHandle(); if (cdto && cdto->isBaseOf(sym, NULL)) - { //printf("is base\n"); + { //printf("'to' is base\n"); return MATCHconvert; } @@ -5745,19 +5755,18 @@ Parameters *Parameter::arraySyntaxCopy(Parameters *args) a = new Parameters(); a->setDim(args->dim); for (size_t i = 0; i < a->dim; i++) - { Parameter *arg = (Parameter *)args->data[i]; + { Parameter *arg = (*args)[i]; arg = arg->syntaxCopy(); - a->data[i] = (void *)arg; + (*a)[i] = arg; } } return a; } char *Parameter::argsTypesToChars(Parameters *args, int varargs) -{ OutBuffer *buf; - - buf = new OutBuffer(); +{ + OutBuffer *buf = new OutBuffer(); buf->writeByte('('); if (args) @@ -5767,7 +5776,7 @@ char *Parameter::argsTypesToChars(Parameters *args, int varargs) for (size_t i = 0; i < args->dim; i++) { if (i) buf->writeByte(','); - Parameter *arg = (Parameter *)args->data[i]; + Parameter *arg = args->tdata()[i]; argbuf.reset(); arg->type->toCBuffer2(&argbuf, &hgs, 0); buf->write(&argbuf); @@ -5834,8 +5843,7 @@ void Parameter::argsToDecoBuffer(OutBuffer *buf, Parameters *arguments, bool man { //printf("Parameter::argsToDecoBuffer()\n"); // Write argument types - if (arguments) - foreach(arguments, &argsToDecoBufferDg, buf, 0, mangle ? mangleFlag : 0); + foreach(arguments, &argsToDecoBufferDg, buf); } /**************************************** @@ -5853,9 +5861,7 @@ static int isTPLDg(void *ctx, size_t n, Parameter *arg, int) int Parameter::isTPL(Parameters *arguments) { //printf("Parameter::isTPL()\n"); - if (arguments) - return foreach(arguments, &isTPLDg, NULL); - return 0; + return foreach(arguments, &isTPLDg, NULL); } /**************************************************** @@ -5904,6 +5910,7 @@ void Parameter::toDecoBuffer(OutBuffer *buf, bool mangle) break; default: #ifdef DEBUG + printf("storageClass = x%llx\n", storageClass & (STCin | STCout | STCref | STClazy)); halt(); #endif assert(0); @@ -5924,8 +5931,7 @@ static int dimDg(void *ctx, size_t n, Parameter *, int) size_t Parameter::dim(Parameters *args) { size_t n = 0; - if (args) - foreach(args, &dimDg, &n); + foreach(args, &dimDg, &n); return n; } @@ -5970,7 +5976,9 @@ Parameter *Parameter::getNth(Parameters *args, size_t nth, size_t *pn) int Parameter::foreach(Parameters *args, Parameter::ForeachDg dg, void *ctx, size_t *pn, int flags) { - assert(args && dg); + assert(dg); + if (!args) + return 0; size_t n = pn ? *pn : 0; // take over index int result = 0; diff --git a/dmd/optimize.c b/dmd/optimize.c index 1d179674..17ecf074 100644 --- a/dmd/optimize.c +++ b/dmd/optimize.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -122,11 +122,11 @@ Expression *StructLiteralExp::optimize(int result) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; + { Expression *e = (*elements)[i]; if (!e) continue; e = e->optimize(WANTvalue | (result & WANTinterpret)); - elements->data[i] = (void *)e; + (*elements)[i] = e; } } return this; @@ -329,20 +329,20 @@ Expression *NewExp::optimize(int result) if (newargs) { for (size_t i = 0; i < newargs->dim; i++) - { Expression *e = (Expression *)newargs->data[i]; + { Expression *e = newargs->tdata()[i]; e = e->optimize(WANTvalue); - newargs->data[i] = (void *)e; + newargs->tdata()[i] = e; } } if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; + { Expression *e = arguments->tdata()[i]; e = e->optimize(WANTvalue); - arguments->data[i] = (void *)e; + arguments->tdata()[i] = e; } } return this; @@ -357,10 +357,10 @@ Expression *CallExp::optimize(int result) if (arguments) { for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; + { Expression *e = arguments->tdata()[i]; e = e->optimize(WANTvalue); - arguments->data[i] = (void *)e; + arguments->tdata()[i] = e; } } @@ -466,8 +466,8 @@ Expression *BinExp::optimize(int result) { dinteger_t i2 = e2->toInteger(); d_uns64 sz = e1->type->size() * 8; - if (i2 < 0 || i2 > sz) - { error("shift assign by %jd is outside the range 0..%zu", i2, sz); + if (i2 < 0 || i2 >= sz) + { error("shift assign by %jd is outside the range 0..%zu", i2, sz - 1); e2 = new IntegerExp(0); } } @@ -561,8 +561,8 @@ Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, E { dinteger_t i2 = e->e2->toInteger(); d_uns64 sz = e->e1->type->size() * 8; - if (i2 < 0 || i2 > sz) - { e->error("shift by %jd is outside the range 0..%zu", i2, sz); + if (i2 < 0 || i2 >= sz) + { e->error("shift by %jd is outside the range 0..%zu", i2, sz - 1); e->e2 = new IntegerExp(0); } if (e->e1->isConst() == 1) @@ -641,13 +641,10 @@ Expression *CommaExp::optimize(int result) e = interpret(NULL); return (e == EXP_CANT_INTERPRET) ? this : e; } - // Don't constant fold if it is a compiler-generated temporary. - if (e1->op == TOKdeclaration) - return this; e1 = e1->optimize(result & WANTinterpret); e2 = e2->optimize(result); - if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2)) + if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->hasSideEffect()) { e = e2; if (e) @@ -784,8 +781,12 @@ Expression *AndAndExp::optimize(int result) e = this; if (e1->isBool(FALSE)) { - e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); - e->type = type; + if (type->toBasetype()->ty == Tvoid) + e = e2; + else + { e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); + e->type = type; + } e = e->optimize(result); } else @@ -802,7 +803,11 @@ Expression *AndAndExp::optimize(int result) e = new IntegerExp(loc, n1 && n2, type); } else if (e1->isBool(TRUE)) - e = new BoolExp(loc, e2, type); + { + if (type->toBasetype()->ty == Tvoid) + e = e2; + else e = new BoolExp(loc, e2, type); + } } } return e; @@ -833,7 +838,12 @@ Expression *OrOrExp::optimize(int result) e = new IntegerExp(loc, n1 || n2, type); } else if (e1->isBool(FALSE)) - e = new BoolExp(loc, e2, type); + { + if (type->toBasetype()->ty == Tvoid) + e = e2; + else + e = new BoolExp(loc, e2, type); + } } } return e; diff --git a/dmd/parse.c b/dmd/parse.c index f0646205..3a0d73dd 100644 --- a/dmd/parse.c +++ b/dmd/parse.c @@ -1301,36 +1301,49 @@ Dsymbol *Parser::parseAggregate() BaseClasses *Parser::parseBaseClasses() { - enum PROT protection = PROTpublic; BaseClasses *baseclasses = new BaseClasses(); for (; 1; nextToken()) { + bool prot = false; + enum PROT protection = PROTpublic; switch (token.value) { - case TOKidentifier: - break; case TOKprivate: + prot = true; protection = PROTprivate; - continue; + nextToken(); + break; case TOKpackage: + prot = true; protection = PROTpackage; - continue; + nextToken(); + break; case TOKprotected: + prot = true; protection = PROTprotected; - continue; + nextToken(); + break; case TOKpublic: + prot = true; protection = PROTpublic; - continue; - default: - error("base classes expected instead of %s", token.toChars()); - return NULL; + nextToken(); + break; + } + //if (prot && !global.params.useDeprecated) + //error("use of base class protection is deprecated"); + if (token.value == TOKidentifier) + { + BaseClass *b = new BaseClass(parseBasicType(), protection); + baseclasses->push(b); + if (token.value != TOKcomma) + break; + } + else + { + error("base classes expected instead of %s", token.toChars()); + return NULL; } - BaseClass *b = new BaseClass(parseBasicType(), protection); - baseclasses->push(b); - if (token.value != TOKcomma) - break; - protection = PROTpublic; } return baseclasses; } @@ -3493,7 +3506,7 @@ Statement *Parser::parseStatement(int flags) case TOKtry: { Statement *body; - Array *catches = NULL; + Catches *catches = NULL; Statement *finalbody = NULL; nextToken(); @@ -3523,7 +3536,7 @@ Statement *Parser::parseStatement(int flags) handler = parseStatement(0); c = new Catch(loc, t, id, handler); if (!catches) - catches = new Array(); + catches = new Catches(); catches->push(c); } @@ -3962,9 +3975,12 @@ int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) case TOKrbracket: case TOKassign: case TOKcomma: + case TOKdotdotdot: case TOKsemicolon: case TOKlcurly: case TOKin: + case TOKout: + case TOKbody: // The !parens is to disallow unnecessary parentheses if (!parens && (endtok == TOKreserved || endtok == t->value)) { *pt = t; @@ -4731,9 +4747,8 @@ Expression *Parser::parsePostExp(Expression *e) { nextToken(); while (1) - { Expression *arg; - - arg = parseAssignExp(); + { + Expression *arg = parseAssignExp(); arguments->push(arg); if (token.value == TOKrbracket) break; @@ -5369,7 +5384,7 @@ Expressions *Parser::parseArguments() nextToken(); if (token.value != endtok) { - while (1) + while (token.value != TOKeof) { arg = parseAssignExp(); arguments->push(arg); diff --git a/dmd/root/port.c b/dmd/root/port.c index 1ca30c8d..bc82f7fc 100644 --- a/dmd/root/port.c +++ b/dmd/root/port.c @@ -347,7 +347,7 @@ char *Port::strupr(char *s) #include static double zero = 0; -double Port::nan = NAN; +double Port::nan = copysign(NAN, 1.0); double Port::infinity = 1 / zero; double Port::dbl_max = 1.7976931348623157e308; double Port::dbl_min = 5e-324; @@ -362,14 +362,7 @@ static PortInitializer portinitializer; PortInitializer::PortInitializer() { - // gcc nan's have the sign bit set by default, so turn it off - // Need the volatile to prevent gcc from doing incorrect - // constant folding. - volatile long double foo; - foo = NAN; - if (signbit(foo)) // signbit sometimes, not always, set - foo = -foo; // turn off sign bit - Port::nan = foo; + assert(!signbit(Port::nan)); #if __FreeBSD__ && __i386__ // LDBL_MAX comes out as infinity. Fix. diff --git a/dmd/sideeffect.c b/dmd/sideeffect.c new file mode 100644 index 00000000..9cc43b70 --- /dev/null +++ b/dmd/sideeffect.c @@ -0,0 +1,34 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2012 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include +#include + +#include "mars.h" +#include "init.h" +#include "expression.h" +#include "template.h" +#include "statement.h" +#include "mtype.h" +#include "utf.h" +#include "declaration.h" +#include "aggregate.h" +#include "scope.h" +#include "attrib.h" + +/******************************************** + * Determine if Expression has any side effects. + */ + +bool Expression::hasSideEffect() +{ + return checkSideEffect(2); +} + diff --git a/dmd/statement.c b/dmd/statement.c index d6ae39bd..7e637e98 100644 --- a/dmd/statement.c +++ b/dmd/statement.c @@ -327,9 +327,8 @@ void ExpStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexcepti DeclarationExp *de = (DeclarationExp *)(exp); VarDeclaration *v = de->declaration->isVarDeclaration(); if (v) - { Expression *e; - - e = v->callScopeDtor(sc); + { + Expression *e = v->callScopeDtor(sc); if (e) { //printf("dtor is: "); e->print(); @@ -451,7 +450,7 @@ Statement *CompoundStatement::syntaxCopy() Statements *a = new Statements(); a->setDim(statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; + { Statement *s = (*statements)[i]; if (s) s = s->syntaxCopy(); a->data[i] = s; @@ -468,7 +467,7 @@ Statement *CompoundStatement::semantic(Scope *sc) for (size_t i = 0; i < statements->dim; ) { - s = (Statement *) statements->data[i]; + s = (*statements)[i]; if (s) { Statements *a = s->flatten(sc); @@ -479,7 +478,7 @@ Statement *CompoundStatement::semantic(Scope *sc) continue; } s = s->semantic(sc); - statements->data[i] = s; + (*statements)[i] = s; if (s) { Statement *sentry; @@ -493,17 +492,11 @@ Statement *CompoundStatement::semantic(Scope *sc) statements->data[i] = sentry; } if (sexception) + sexception = sexception->semantic(sc); + 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 { @@ -515,22 +508,23 @@ Statement *CompoundStatement::semantic(Scope *sc) * catch (Object __o) * { sexception; throw __o; } */ - Statement *body; Statements *a = new Statements(); - for (size_t j = i + 1; j < statements->dim; j++) { a->push((*statements)[j]); } - body = new CompoundStatement(0, a); + Statement *body = new CompoundStatement(0, a); body = new ScopeStatement(0, body); Identifier *id = Lexer::uniqueId("__o"); - Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id)); - handler = new CompoundStatement(0, sexception, handler); + Statement *handler = sexception; + if (sexception->blockExit(FALSE) & BEfallthru) + { handler = new ThrowStatement(0, new IdentifierExp(0, id)); + handler = new CompoundStatement(0, sexception, handler); + } - Array *catches = new Array(); + Catches *catches = new Catches(); Catch *ctch = new Catch(0, NULL, id, handler); catches->push(ctch); s = new TryCatchStatement(0, body, catches); @@ -556,14 +550,12 @@ Statement *CompoundStatement::semantic(Scope *sc) * As: * s; try { s1; s2; } finally { sfinally; } */ - Statement *body; Statements *a = new Statements(); - for (size_t j = i + 1; j < statements->dim; j++) { a->push((*statements)[j]); } - body = new CompoundStatement(0, a); + Statement *body = new CompoundStatement(0, a); s = new TryFinallyStatement(0, body, sfinally); s = s->semantic(sc); statements->setDim(i + 1); @@ -606,7 +598,7 @@ ReturnStatement *CompoundStatement::isReturnStatement() void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s) s->toCBuffer(buf, hgs); } @@ -615,7 +607,7 @@ void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) int CompoundStatement::usesEH() { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s && s->usesEH()) return TRUE; } @@ -627,7 +619,7 @@ int CompoundStatement::blockExit(bool mustNotThrow) //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); int result = BEfallthru; for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s) { //printf("result = x%x\n", result); @@ -652,7 +644,7 @@ int CompoundStatement::comeFrom() //printf("CompoundStatement::comeFrom()\n"); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; + { Statement *s = (*statements)[i]; if (!s) continue; @@ -665,7 +657,7 @@ int CompoundStatement::comeFrom() int CompoundStatement::isEmpty() { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s && !s->isEmpty()) return FALSE; } @@ -686,7 +678,7 @@ Statement *CompoundDeclarationStatement::syntaxCopy() Statements *a = new Statements(); a->setDim(statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; + { Statement *s = (*statements)[i]; if (s) s = s->syntaxCopy(); a->data[i] = s; @@ -699,7 +691,7 @@ void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { int nwritten = 0; for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; ExpStatement *ds; if (s && (ds = s->isExpStatement()) != NULL && @@ -764,7 +756,7 @@ Statement *UnrolledLoopStatement::syntaxCopy() Statements *a = new Statements(); a->setDim(statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; + { Statement *s = (*statements)[i]; if (s) s = s->syntaxCopy(); a->data[i] = s; @@ -785,7 +777,7 @@ Statement *UnrolledLoopStatement::semantic(Scope *sc) for (size_t i = 0; i < statements->dim; i++) { - Statement *s = (Statement *) statements->data[i]; + Statement *s = (*statements)[i]; if (s) { //printf("[%d]: %s\n", i, s->toChars()); @@ -807,7 +799,7 @@ void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (size_t i = 0; i < statements->dim; i++) { Statement *s; - s = (Statement *) statements->data[i]; + s = (*statements)[i]; if (s) s->toCBuffer(buf, hgs); } @@ -829,7 +821,7 @@ int UnrolledLoopStatement::hasContinue() int UnrolledLoopStatement::usesEH() { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s && s->usesEH()) return TRUE; } @@ -840,7 +832,7 @@ int UnrolledLoopStatement::blockExit(bool mustNotThrow) { int result = BEfallthru; for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; + { Statement *s = (*statements)[i]; if (s) { int r = s->blockExit(mustNotThrow); @@ -856,7 +848,7 @@ int UnrolledLoopStatement::comeFrom() //printf("UnrolledLoopStatement::comeFrom()\n"); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; + { Statement *s = (*statements)[i]; if (!s) continue; @@ -1360,6 +1352,8 @@ Statement *ForeachStatement::semantic(Scope *sc) error("invalid foreach aggregate %s", aggr->toChars()); return this; } + if (aggr->type->toBasetype()->ty == Terror) + return NULL; inferApplyArgTypes(op, arguments, aggr, sc->module); @@ -1402,10 +1396,10 @@ Statement *ForeachStatement::semantic(Scope *sc) Expression *e; Type *t; if (te) - e = te->exps->tdata()[k]; + e = (*te->exps)[k]; else t = Parameter::getNth(tuple->arguments, k)->type; - Parameter *arg = arguments->tdata()[0]; + Parameter *arg = (*arguments)[0]; Statements *st = new Statements(); if (dim == 2) @@ -1508,7 +1502,7 @@ Statement *ForeachStatement::semantic(Scope *sc) { Parameter *arg; int i = (dim == 1) ? 0 : 1; // index of value - arg = (Parameter *)arguments->data[i]; + arg = (*arguments)[i]; arg->type = arg->type->semantic(loc, sc); tnv = arg->type->toBasetype(); if (tnv->ty != tn->ty && @@ -1517,7 +1511,7 @@ Statement *ForeachStatement::semantic(Scope *sc) if (arg->storageClass & STCref) error("foreach: value of UTF conversion cannot be ref"); if (dim == 2) - { arg = (Parameter *)arguments->data[0]; + { arg = (*arguments)[0]; if (arg->storageClass & STCref) error("foreach: key cannot be ref"); } @@ -1527,7 +1521,7 @@ Statement *ForeachStatement::semantic(Scope *sc) for (size_t i = 0; i < dim; i++) { // Declare args - Parameter *arg = (Parameter *)arguments->data[i]; + Parameter *arg = (*arguments)[i]; Type *argtype = arg->type->semantic(loc, sc); VarDeclaration *var; @@ -1705,7 +1699,7 @@ Statement *ForeachStatement::semantic(Scope *sc) e = new VarExp(loc, r); Expression *einit = new DotIdExp(loc, e, idhead); // einit = einit->semantic(sc); - Parameter *arg = (Parameter *)arguments->data[0]; + Parameter *arg = (*arguments)[0]; VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); ve->storage_class |= STCforeach; ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); @@ -1755,7 +1749,8 @@ Statement *ForeachStatement::semantic(Scope *sc) */ Parameters *args = new Parameters(); for (size_t i = 0; i < dim; i++) - { Parameter *arg = (Parameter *)arguments->data[i]; + { Parameter *arg = (*arguments)[i]; + StorageClass stc = STCref; Identifier *id; arg->type = arg->type->semantic(loc, sc); @@ -1776,7 +1771,7 @@ Statement *ForeachStatement::semantic(Scope *sc) } Type *t = new TypeFunction(args, Type::tint32, 0, LINKd); cases = new Statements(); - gotos = new Array(); + gotos = new CompoundStatements(); FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); fld->fbody = body; Expression *flde = new FuncExp(loc, fld); @@ -1784,28 +1779,28 @@ Statement *ForeachStatement::semantic(Scope *sc) // Resolve any forward referenced goto's for (size_t i = 0; i < gotos->dim; i++) - { CompoundStatement *cs = (CompoundStatement *)gotos->data[i]; - GotoStatement *gs = (GotoStatement *)cs->statements->data[0]; + { CompoundStatement *cs = (*gotos)[i]; + GotoStatement *gs = (GotoStatement *)(*cs->statements)[0]; if (!gs->label->statement) { // 'Promote' it to this scope, and replace with a return cases->push(gs); s = new ReturnStatement(0, new IntegerExp(cases->dim + 1)); - cs->statements->data[0] = (void *)s; + (*cs->statements)[0] = s; } } if (taa) { // Check types - Parameter *arg = (Parameter *)arguments->data[0]; + Parameter *arg = (*arguments)[0]; if (dim == 2) { if (arg->storageClass & STCref) error("foreach: index cannot be ref"); if (!arg->type->equals(taa->index)) error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); - arg = (Parameter *)arguments->data[1]; + arg = (*arguments)[1]; } if (!arg->type->equals(taa->nextOf())) error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); @@ -1985,7 +1980,7 @@ Statement *ForeachStatement::semantic(Scope *sc) // cases 2... for (size_t i = 0; i < cases->dim; i++) { - s = (Statement *)cases->data[i]; + s = (*cases)[i]; s = new CaseStatement(0, new IntegerExp(i + 2), s); a->push(s); } @@ -2052,7 +2047,7 @@ void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(" ("); for (size_t i = 0; i < arguments->dim; i++) { - Parameter *a = (Parameter *)arguments->data[i]; + Parameter *a = (*arguments)[i]; if (i) buf->writestring(", "); if (a->storageClass & STCref) @@ -2553,7 +2548,7 @@ Statement *PragmaStatement::semantic(Scope *sc) { for (size_t i = 0; i < args->dim; i++) { - Expression *e = args->tdata()[i]; + Expression *e = (*args)[i]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); @@ -2579,11 +2574,11 @@ Statement *PragmaStatement::semantic(Scope *sc) error("string expected for library name"); else { - Expression *e = args->tdata()[0]; + Expression *e = (*args)[0]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); - args->tdata()[0] = e; + (*args)[0] = e; StringExp *se = e->toString(); if (!se) error("string expected for library name, not '%s'", e->toChars()); @@ -2611,10 +2606,10 @@ Statement *PragmaStatement::semantic(Scope *sc) error("function name expected for start address"); else { - Expression *e = (Expression *)args->data[0]; + Expression *e = (*args)[0]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; + (*args)[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) error("function name expected for start address, not '%s'", e->toChars()); @@ -2771,7 +2766,7 @@ Statement *SwitchStatement::semantic(Scope *sc) // Resolve any goto case's with exp for (size_t i = 0; i < gotoCases.dim; i++) { - GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i]; + GotoCaseStatement *gcs = gotoCases[i]; if (!gcs->exp) { @@ -2785,7 +2780,7 @@ Statement *SwitchStatement::semantic(Scope *sc) continue; for (size_t j = 0; j < scx->sw->cases->dim; j++) { - CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j]; + CaseStatement *cs = (*scx->sw->cases)[j]; if (cs->exp->equals(gcs->exp)) { @@ -2845,11 +2840,11 @@ Statement *SwitchStatement::semantic(Scope *sc) size_t dim = ed->members->dim; for (size_t i = 0; i < dim; i++) { - EnumMember *em = ((Dsymbol *)ed->members->data[i])->isEnumMember(); + EnumMember *em = (*ed->members)[i]->isEnumMember(); if (em) { for (size_t j = 0; j < cases->dim; j++) - { CaseStatement *cs = (CaseStatement *)cases->data[j]; + { CaseStatement *cs = (*cases)[j]; if (cs->exp->equals(em->value)) goto L1; } @@ -2962,7 +2957,7 @@ Statement *CaseStatement::semantic(Scope *sc) for (size_t i = 0; i < sw->cases->dim; i++) { - CaseStatement *cs = (CaseStatement *)sw->cases->data[i]; + CaseStatement *cs = (*sw->cases)[i]; //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); if (cs->exp->equals(exp)) @@ -2976,7 +2971,7 @@ Statement *CaseStatement::semantic(Scope *sc) // Resolve any goto case's with no exp to this case statement for (size_t i = 0; i < sw->gotoCases.dim; i++) { - GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i]; + GotoCaseStatement *gcs = sw->gotoCases[i]; if (!gcs->exp) { @@ -3304,19 +3299,10 @@ Statement *ReturnStatement::semantic(Scope *sc) FuncDeclaration *fd = sc->parent->isFuncDeclaration(); Scope *scx = sc; int implicit0 = 0; + Expression *eorg = NULL; - if (sc->fes) - { - // Find scope of function foreach is in - for (; 1; scx = scx->enclosing) - { - assert(scx); - if (scx->func != fd) - { fd = scx->func; // fd is now function enclosing foreach - break; - } - } - } + if (fd->fes) + fd = fd->fes->func; // fd is now function enclosing foreach Type *tret = fd->type->nextOf(); if (fd->tintro) @@ -3379,10 +3365,7 @@ Statement *ReturnStatement::semantic(Scope *sc) else fd->nrvo_can = 0; - if (fd->returnLabel && tbret->ty != Tvoid) - { - } - else if (fd->inferRetType) + if (fd->inferRetType) { Type *tfret = fd->type->nextOf(); if (tfret) @@ -3400,11 +3383,17 @@ Statement *ReturnStatement::semantic(Scope *sc) tbret = tret->toBasetype(); } } + if (fd->returnLabel) + eorg = exp; } else if (tbret->ty != Tvoid) { if (fd->tintro) exp = exp->implicitCastTo(sc, fd->type->nextOf()); + + // eorg isn't casted to tret (== fd->tintro->nextOf()) + if (fd->returnLabel) + eorg = exp->copy(); exp = exp->implicitCastTo(sc, tret); } } @@ -3419,7 +3408,7 @@ Statement *ReturnStatement::semantic(Scope *sc) else { fd->type->next = Type::tvoid; - fd->type = fd->type->semantic(loc, sc); + //fd->type = fd->type->semantic(loc, sc); if (!fd->tintro) { tret = Type::tvoid; tbret = tret; @@ -3490,7 +3479,8 @@ Statement *ReturnStatement::semantic(Scope *sc) assert(fd->vresult); VarExp *v = new VarExp(0, fd->vresult); - exp = new AssignExp(loc, v, exp); + assert(eorg); + exp = new AssignExp(loc, v, eorg); exp->op = TOKconstruct; exp = exp->semantic(sc); } @@ -4027,7 +4017,7 @@ int WithStatement::blockExit(bool mustNotThrow) /******************************** TryCatchStatement ***************************/ -TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) +TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Catches *catches) : Statement(loc) { this->body = body; @@ -4036,14 +4026,14 @@ TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) Statement *TryCatchStatement::syntaxCopy() { - Array *a = new Array(); + Catches *a = new Catches(); a->setDim(catches->dim); for (size_t i = 0; i < a->dim; i++) { Catch *c; - c = (Catch *)catches->data[i]; + c = (*catches)[i]; c = c->syntaxCopy(); - a->data[i] = c; + (*a)[i] = c; } TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); return s; @@ -4056,12 +4046,12 @@ Statement *TryCatchStatement::semantic(Scope *sc) /* Even if body is NULL, still do semantic analysis on catches */ for (size_t i = 0; i < catches->dim; i++) - { Catch *c = (Catch *)catches->data[i]; + { Catch *c = (*catches)[i]; c->semantic(sc); // Determine if current catch 'hides' any previous catches for (size_t j = 0; j < i; j++) - { Catch *cj = (Catch *)catches->data[j]; + { Catch *cj = (*catches)[j]; char *si = c->loc.toChars(); char *sj = cj->loc.toChars(); @@ -4095,7 +4085,7 @@ int TryCatchStatement::blockExit(bool mustNotThrow) int catchresult = 0; for (size_t i = 0; i < catches->dim; i++) { - Catch *c = (Catch *)catches->data[i]; + Catch *c =(* catches)[i]; if (c->type == Type::terror) continue; @@ -4125,7 +4115,7 @@ void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) body->toCBuffer(buf, hgs); for (size_t i = 0; i < catches->dim; i++) { - Catch *c = (Catch *)catches->data[i]; + Catch *c = (*catches)[i]; c->toCBuffer(buf, hgs); } } @@ -4448,10 +4438,10 @@ Statements *VolatileStatement::flatten(Scope *sc) a = statement ? statement->flatten(sc) : NULL; if (a) { for (size_t i = 0; i < a->dim; i++) - { Statement *s = (Statement *)a->data[i]; + { Statement *s = (*a)[i]; s = new VolatileStatement(loc, s); - a->data[i] = s; + (*a)[i] = s; } } @@ -4511,7 +4501,7 @@ Statement *GotoStatement::semantic(Scope *sc) * list. */ Statements *a = new Statements(); - Statement *s; + CompoundStatement *s; a->push(this); s = new CompoundStatement(loc, a); @@ -4599,10 +4589,10 @@ Statements *LabelStatement::flatten(Scope *sc) { a->push(new ExpStatement(loc, (Expression *)NULL)); } - Statement *s = (Statement *)a->data[0]; + Statement *s = (*a)[0]; s = new LabelStatement(loc, ident, s); - a->data[0] = s; + (*a)[0] = s; } } diff --git a/dmd/statement.h b/dmd/statement.h index d8327d4b..6ffb84f4 100644 --- a/dmd/statement.h +++ b/dmd/statement.h @@ -132,6 +132,7 @@ struct Statement : Object virtual int inlineCost(InlineCostState *ics); virtual Expression *doInline(InlineDoState *ids); + virtual Statement *doInlineStatement(InlineDoState *ids); virtual Statement *inlineScan(InlineScanState *iss); // Back end @@ -176,6 +177,7 @@ struct ExpStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); @@ -218,6 +220,7 @@ struct CompoundStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); virtual void toIR(IRState *irs); @@ -256,6 +259,7 @@ struct UnrolledLoopStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); @@ -278,6 +282,9 @@ struct ScopeStatement : Statement int isEmpty(); Expression *interpret(InterState *istate); + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); @@ -344,7 +351,9 @@ struct ForStatement : Statement Expression *interpret(InterState *istate); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int inlineCost(InlineCostState *ics); Statement *inlineScan(InlineScanState *iss); + Statement *doInlineStatement(InlineDoState *ids); void toIR(IRState *irs); }; @@ -362,7 +371,7 @@ struct ForeachStatement : Statement FuncDeclaration *func; // function we're lexically in Statements *cases; // put breaks, continues, gotos and returns here - Array *gotos; // forward referenced goto's go here + CompoundStatements *gotos; // forward referenced goto's go here ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, Expression *aggr, Statement *body); Statement *syntaxCopy(); @@ -430,6 +439,7 @@ struct IfStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); @@ -485,8 +495,8 @@ struct SwitchStatement : Statement DefaultStatement *sdefault; - Array gotoCases; // array of unresolved GotoCaseStatement's - CaseStatements *cases; // array of CaseStatement's + GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's + CaseStatements *cases; // array of CaseStatement's int hasNoDefault; // !=0 if no default statement // LDC @@ -634,6 +644,7 @@ struct ReturnStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); @@ -720,9 +731,9 @@ struct WithStatement : Statement struct TryCatchStatement : Statement { Statement *body; - Array *catches; + Catches *catches; - TryCatchStatement(Loc loc, Statement *body, Array *catches); + TryCatchStatement(Loc loc, Statement *body, Catches *catches); Statement *syntaxCopy(); Statement *semantic(Scope *sc); int hasBreak(); @@ -847,7 +858,7 @@ struct LabelStatement : Statement Statement* enclosingScopeExit; block *lblock; // back end - Array *fwdrefs; // forward references to this LabelStatement + Blocks *fwdrefs; // forward references to this LabelStatement LabelStatement(Loc loc, Identifier *ident, Statement *statement); Statement *syntaxCopy(); @@ -882,8 +893,9 @@ struct AsmStatement : Statement Token *tokens; code *asmcode; unsigned asmalign; // alignment of this statement - unsigned refparam; // !=0 if function parameter is referenced - unsigned naked; // !=0 if function is to be naked + unsigned regs; // mask of registers modified (must match regm_t in back end) + unsigned char refparam; // !=0 if function parameter is referenced + unsigned char naked; // !=0 if function is to be naked AsmStatement(Loc loc, Token *tokens); Statement *syntaxCopy(); diff --git a/dmd/staticassert.c b/dmd/staticassert.c index 33db1aa4..07adb737 100644 --- a/dmd/staticassert.c +++ b/dmd/staticassert.c @@ -54,10 +54,15 @@ void StaticAssert::semantic2(Scope *sc) { //printf("StaticAssert::semantic2() %s\n", toChars()); Expression *e = exp->semantic(sc); - if (e->op == TOKerror) + if (e->type == Type::terror) return; + unsigned olderrs = global.errors; e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(FALSE)) + if (global.errors != olderrs) + { + errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars()); + } + else if (e->isBool(FALSE)) { if (msg) { HdrGenState hgs; diff --git a/dmd/struct.c b/dmd/struct.c index 20c18f60..b542b180 100644 --- a/dmd/struct.c +++ b/dmd/struct.c @@ -54,6 +54,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) aliasthis = NULL; noDefaultCtor = FALSE; #endif + dtor = NULL; #if IN_LLVM availableExternally = true; // assume this unless proven otherwise @@ -77,7 +78,7 @@ void AggregateDeclaration::semantic2(Scope *sc) sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; s->semantic2(sc); } sc->pop(); @@ -96,7 +97,7 @@ void AggregateDeclaration::semantic3(Scope *sc) sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; s->semantic3(sc); } sc->pop(); @@ -110,7 +111,7 @@ void AggregateDeclaration::inlineScan() { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; //printf("inline scan aggregate symbol '%s'\n", s->toChars()); s->inlineScan(); } @@ -141,6 +142,11 @@ int AggregateDeclaration::isDeprecated() return isdeprecated; } +int AggregateDeclaration::isExport() +{ + return protection == PROTexport; +} + /**************************** * Do byte or word alignment as necessary. * Align sizes of 0, as we may not know array sizes yet. @@ -238,13 +244,13 @@ int AggregateDeclaration::firstFieldInUnion(int indx) { if (isUnionDeclaration()) return 0; - VarDeclaration * vd = (VarDeclaration *)fields.data[indx]; + VarDeclaration * vd = fields.tdata()[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]; + VarDeclaration * v = fields.tdata()[indx - 1]; if (v->offset != vd->offset) return firstNonZero; --indx; @@ -263,7 +269,7 @@ int AggregateDeclaration::firstFieldInUnion(int indx) */ int AggregateDeclaration::numFieldsInUnion(int firstIndex) { - VarDeclaration * vd = (VarDeclaration *)fields.data[firstIndex]; + VarDeclaration * vd = fields.tdata()[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. */ @@ -273,7 +279,7 @@ int AggregateDeclaration::numFieldsInUnion(int firstIndex) int count = 1; for (size_t i = firstIndex+1; i < fields.dim; ++i) { - VarDeclaration * v = (VarDeclaration *)fields.data[i]; + VarDeclaration * v = fields.tdata()[i]; // If offsets are different, they are not in the same union if (v->offset != vd->offset) break; @@ -366,7 +372,7 @@ void StructDeclaration::semantic(Scope *sc) { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); s->addMember(sc, this, 1); } @@ -387,7 +393,7 @@ void StructDeclaration::semantic(Scope *sc) * resolve individual members like enums. */ for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; + { Dsymbol *s = members->tdata()[i]; /* There are problems doing this in the general case because * Scope keeps track of things like 'offset' */ @@ -400,7 +406,7 @@ void StructDeclaration::semantic(Scope *sc) for (size_t i = 0; i < members_dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; s->semantic(sc2); #if 0 if (sizeok == 2) @@ -588,7 +594,7 @@ void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = members->tdata()[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); diff --git a/dmd/template.c b/dmd/template.c index 67180be5..9d9c6a78 100644 --- a/dmd/template.c +++ b/dmd/template.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -16,6 +16,7 @@ #if !IN_LLVM #endif #include "root.h" +#include "aav.h" #include "rmem.h" #include "stringtable.h" #include "mars.h" @@ -280,6 +281,8 @@ int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, } /**************************************** + * This makes a 'pretty' version of the template arguments. + * It's analogous to genIdent() which makes a mangled version. */ void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) @@ -289,12 +292,21 @@ void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) Expression *e = isExpression(oarg); Dsymbol *s = isDsymbol(oarg); Tuple *v = isTuple(oarg); + /* The logic of this should match what genIdent() does. The _dynamic_cast() + * function relies on all the pretty strings to be unique for different classes + * (see Bugzilla 7375). + * Perhaps it would be better to demangle what genIdent() does. + */ if (t) { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); t->toCBuffer(buf, NULL, hgs); } else if (e) + { + if (e->op == TOKvar) + e = e->optimize(WANTvalue); // added to fix Bugzilla 7375 e->toCBuffer(buf, hgs); + } else if (s) { char *p = s->ident ? s->ident->toChars() : s->toChars(); @@ -307,7 +319,7 @@ void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) { if (i) buf->writeByte(','); - Object *o = (Object *)args->data[i]; + Object *o = (*args)[i]; ObjectToCBuffer(buf, hgs, o); } } @@ -1721,6 +1733,19 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, else goto Lnomatch; } + else if (tparam->ty == Ttypeof) + { + /* Need a loc to go with the semantic routine. + */ + Loc loc; + if (parameters->dim) + { + TemplateParameter *tp = parameters->tdata()[0]; + loc = tp->loc; + } + + tparam = tparam->semantic(loc, sc); + } if (ty != tparam->ty) { @@ -1728,8 +1753,18 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, // Can't instantiate AssociativeArray!() without a scope if (tparam->ty == Taarray && !((TypeAArray*)tparam)->sc) ((TypeAArray*)tparam)->sc = sc; + + MATCH m = implicitConvTo(tparam); + if (m == MATCHnomatch) + { + Type *at = aliasthisOf(); + if (at) + m = at->deduceType(sc, tparam, parameters, dedtypes, wildmatch); + } + return m; +#else + return implicitConvTo(tparam); #endif - return implicitConvTo(tparam); } if (nextOf()) @@ -1749,14 +1784,14 @@ Lconst: #if DMDV2 MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) + Objects *dedtypes, unsigned *wildmatch) { #if 0 printf("TypeDArray::deduceType()\n"); printf("\tthis = %d, ", ty); print(); printf("\ttparam = %d, ", tparam->ty); tparam->print(); #endif - return Type::deduceType(sc, tparam, parameters, dedtypes); + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); } #endif @@ -2911,7 +2946,7 @@ Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) // value-parameter -Expression *TemplateValueParameter::edummy = NULL; +AA *TemplateValueParameter::edummies = NULL; TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue) @@ -3022,14 +3057,14 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, Object *oarg; if (i < tiargs->dim) - oarg = (Object *)tiargs->data[i]; + oarg = tiargs->tdata()[i]; else { // Get default argument instead oarg = defaultArg(loc, sc); if (!oarg) { assert(i < dedtypes->dim); // It might have already been deduced - oarg = (Object *)dedtypes->data[i]; + oarg = dedtypes->tdata()[i]; if (!oarg) goto Lnomatch; } @@ -3043,7 +3078,7 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, if (specValue) { - if (!ei || ei == edummy) + if (!ei || _aaGetRvalue(edummies, ei->type) == ei) goto Lnomatch; Expression *e = specValue; @@ -3128,9 +3163,10 @@ void *TemplateValueParameter::dummyArg() if (!e) { // Create a dummy value - if (!edummy) - edummy = valType->defaultInit(); - e = edummy; + Expression **pe = (Expression **)_aaGet(&edummies, valType); + if (!*pe) + *pe = valType->defaultInit(); + e = *pe; } return (void *)e; } @@ -3469,6 +3505,11 @@ void TemplateInstance::semantic(Scope *sc) * (if we havetempdecl, then tiargs is already evaluated) */ semanticTiargs(sc); + if (arrayObjectIsError(tiargs)) + { inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + return; // error recovery + } tempdecl = findTemplateDeclaration(sc); if (tempdecl) @@ -4367,6 +4408,8 @@ Identifier *TemplateInstance::genIdent() { ea->error("tuple is not a valid template value argument"); continue; } + if (ea->op == TOKerror) + continue; #if 1 /* Use deco that matches what it would be for a function parameter */ @@ -4572,7 +4615,7 @@ void TemplateInstance::printInstantiationTrace() return; const unsigned max_shown = 6; - const char format[] = "%s: instantiated from here: %s\n"; + const char format[] = "instantiated from here: %s"; // determine instantiation depth and number of recursive instantiations int n_instantiations = 1; @@ -4595,7 +4638,7 @@ void TemplateInstance::printInstantiationTrace() { for (TemplateInstance *cur = this; cur; cur = cur->tinst) { - fprintf(stdmsg, format, cur->loc.toChars(), cur->toChars()); + errorSupplemental(cur->loc, format, cur->toChars()); } } else if (n_instantiations - n_totalrecursions <= max_shown) @@ -4613,9 +4656,9 @@ void TemplateInstance::printInstantiationTrace() else { if (recursionDepth) - fprintf(stdmsg, "%s: %d recursive instantiations from here: %s\n", cur->loc.toChars(), recursionDepth+2, cur->toChars()); + errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars()); else - fprintf(stdmsg,format, cur->loc.toChars(), cur->toChars()); + errorSupplemental(cur->loc, format, cur->toChars()); recursionDepth = 0; } } @@ -4628,11 +4671,11 @@ void TemplateInstance::printInstantiationTrace() for (TemplateInstance *cur = this; cur; cur = cur->tinst) { if (i == max_shown / 2) - fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); + errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2) - fprintf(stdmsg, format, cur->loc.toChars(), cur->toChars()); + errorSupplemental(cur->loc, format, cur->toChars()); ++i; } } @@ -4653,7 +4696,7 @@ void TemplateInstance::toObjFile(int multiobj) { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = (*members)[i]; s->toObjFile(multiobj); } } @@ -4671,7 +4714,7 @@ void TemplateInstance::inlineScan() { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = (*members)[i]; s->inlineScan(); } } @@ -4694,7 +4737,7 @@ void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (i) buf->writeByte(','); - Object *oarg = (Object *)args->data[i]; + Object *oarg = (*args)[i]; ObjectToCBuffer(buf, hgs, oarg); } nest--; @@ -4798,7 +4841,7 @@ void TemplateInstance::printInstantiationTrace() TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Identifiers *idents, Objects *tiargs) - : TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1]) + : TemplateInstance(loc, idents->tdata()[idents->dim - 1]) { //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); this->ident = ident; @@ -4814,7 +4857,7 @@ Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) ids->setDim(idents->dim); for (size_t i = 0; i < idents->dim; i++) { // Matches TypeQualified::syntaxCopyHelper() - Identifier *id = (Identifier *)idents->data[i]; + Identifier *id = idents->tdata()[i]; if (id->dyncast() == DYNCAST_DSYMBOL) { TemplateInstance *ti = (TemplateInstance *)id; @@ -4883,7 +4926,7 @@ void TemplateMixin::semantic(Scope *sc) else { i = 1; - id = (Identifier *)idents->data[0]; + id = idents->tdata()[0]; switch (id->dyncast()) { case DYNCAST_IDENTIFIER: @@ -4906,7 +4949,7 @@ void TemplateMixin::semantic(Scope *sc) { if (!s) break; - id = (Identifier *)idents->data[i]; + id = idents->tdata()[i]; s = s->searchX(loc, sc, id); } if (!s) @@ -4954,7 +4997,7 @@ void TemplateMixin::semantic(Scope *sc) // Run semantic on each argument, place results in tiargs[] semanticTiargs(sc); - if (errors) + if (errors || arrayObjectIsError(tiargs)) return; tempdecl = findBestMatch(sc); @@ -5190,9 +5233,11 @@ int TemplateMixin::oneMember(Dsymbol **ps) int TemplateMixin::hasPointers() { //printf("TemplateMixin::hasPointers() %s\n", toChars()); + + if (members) for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = (*members)[i]; //printf(" s = %s %s\n", s->kind(), s->toChars()); if (s->hasPointers()) { diff --git a/dmd/template.h b/dmd/template.h index 2ef2646d..8904719a 100644 --- a/dmd/template.h +++ b/dmd/template.h @@ -198,7 +198,7 @@ struct TemplateValueParameter : TemplateParameter Expression *specValue; Expression *defaultValue; - static Expression *edummy; + static AA *edummies; TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue);