From e74e55df89d4314b4f587acfb1e73dbd7230b200 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sun, 12 Feb 2012 14:42:37 +0400 Subject: [PATCH] Merge 2.058beta --- dmd2/access.c | 37 +- dmd2/aggregate.h | 5 +- dmd2/apply.c | 165 +++++ dmd2/argtypes.c | 5 + dmd2/arrayop.c | 2 +- dmd2/attrib.c | 18 +- dmd2/attrib.h | 8 +- dmd2/canthrow.c | 190 +++++ dmd2/cast.c | 143 +++- dmd2/class.c | 65 +- dmd2/constfold.c | 140 ++-- dmd2/cppmangle.c | 8 + dmd2/declaration.c | 95 ++- dmd2/declaration.h | 28 +- dmd2/delegatize.c | 226 ++---- dmd2/doc.c | 4 +- dmd2/dsymbol.c | 75 +- dmd2/dsymbol.h | 10 +- dmd2/enum.c | 6 +- dmd2/enum.h | 2 +- dmd2/expression.c | 1525 ++++++++++++++++++++++------------------ dmd2/expression.h | 145 ++-- dmd2/func.c | 170 ++++- dmd2/html.c | 80 ++- dmd2/html.h | 24 +- dmd2/idgen.c | 21 +- dmd2/import.c | 174 ++--- dmd2/import.h | 9 +- dmd2/init.c | 8 + dmd2/inline.c | 501 +++++++++---- dmd2/interpret.c | 1014 +++++++++++++++----------- dmd2/lexer.c | 35 +- dmd2/lexer.h | 4 +- dmd2/mars.c | 93 ++- dmd2/mars.h | 2 + dmd2/mem.c | 273 ------- dmd2/mem.h | 51 -- dmd2/module.c | 20 +- dmd2/mtype.c | 614 ++++++++++++---- dmd2/mtype.h | 33 + dmd2/objfile.h | 61 -- dmd2/opover.c | 322 ++++++--- dmd2/optimize.c | 38 +- dmd2/parse.c | 297 +++++--- dmd2/parse.h | 6 +- dmd2/root/port.c | 11 +- dmd2/root/rmem.c | 155 ++++ dmd2/sideeffect.c | 250 +++++++ dmd2/statement.c | 416 +++++------ dmd2/statement.h | 25 +- dmd2/staticassert.c | 11 +- dmd2/staticassert.h | 2 +- dmd2/struct.c | 83 ++- dmd2/template.c | 436 +++++++++--- dmd2/template.h | 19 +- dmd2/traits.c | 43 +- gen/asmstmt.cpp | 1 - gen/dvalue.h | 1 - gen/tocall.cpp | 2 +- gen/toir.cpp | 9 +- gen/typinf.cpp | 12 +- runtime/CMakeLists.txt | 3 + runtime/druntime | 2 +- runtime/phobos | 2 +- 64 files changed, 5261 insertions(+), 2974 deletions(-) create mode 100644 dmd2/apply.c create mode 100644 dmd2/canthrow.c delete mode 100644 dmd2/mem.c delete mode 100644 dmd2/mem.h delete mode 100644 dmd2/objfile.h create mode 100644 dmd2/root/rmem.c create mode 100644 dmd2/sideeffect.c diff --git a/dmd2/access.c b/dmd2/access.c index d1d1f4f2..b8b677c6 100644 --- a/dmd2/access.c +++ b/dmd2/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: @@ -265,7 +265,7 @@ int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd) // Friends if both are in the same module //if (toParent() == cd->toParent()) - if (cd && getModule() == cd->getModule()) + if (cd && getAccessModule() == cd->getAccessModule()) { #if LOG printf("\tin same module\n"); @@ -354,7 +354,7 @@ int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember) #endif return 1; } - if (!cd && getModule() == smember->getModule()) + if (!cd && getAccessModule() == smember->getAccessModule()) { #if LOG printf("\tyes 3\n"); @@ -381,39 +381,32 @@ void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) } else { - //printf("accessCheck(%s)\n", d->toChars()); + printf("accessCheck(%s)\n", d->toPrettyChars()); } #endif if (!e) { - if (d->getModule() != sc->module) - if (d->prot() == PROTprivate || - d->prot() == PROTpackage && !hasPackageAccess(sc, d)) - - error(loc, "%s %s.%s is not accessible from %s", - d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars()); + if (d->prot() == PROTprivate && d->getAccessModule() != sc->module || + d->prot() == PROTpackage && !hasPackageAccess(sc, d)) + { + error(loc, "%s %s is not accessible from module %s", + d->kind(), d->toPrettyChars(), sc->module->toChars()); + } } else if (e->type->ty == Tclass) { // Do access check - ClassDeclaration *cd; - - cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); -#if 1 + ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); if (e->op == TOKsuper) - { ClassDeclaration *cd2; - - cd2 = sc->func->toParent()->isClassDeclaration(); + { + ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration(); if (cd2) cd = cd2; } -#endif cd->accessCheck(loc, sc, d); } else if (e->type->ty == Tstruct) { // Do access check - StructDeclaration *cd; - - cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); + StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); cd->accessCheck(loc, sc, d); } } diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h index cf207b10..1d534d28 100644 --- a/dmd2/aggregate.h +++ b/dmd2/aggregate.h @@ -68,7 +68,7 @@ struct AggregateDeclaration : ScopeDsymbol // 1: size is correct // 2: cannot determine size; fwd referenced Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol - int isdeprecated; // !=0 if deprecated + bool isdeprecated; // !=0 if deprecated #if DMDV2 int isnested; // !=0 if is nested @@ -107,6 +107,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); @@ -166,6 +167,7 @@ struct StructDeclaration : AggregateDeclaration void toCBuffer(OutBuffer *buf, HdrGenState *hgs); char *mangle(); const char *kind(); + void finalizeSize(); #if DMDV1 Expression *cloneMembers(); #endif @@ -284,6 +286,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/dmd2/apply.c b/dmd2/apply.c new file mode 100644 index 00000000..f5a5ede8 --- /dev/null +++ b/dmd2/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/dmd2/argtypes.c b/dmd2/argtypes.c index 1ebf5ea7..3f1d3620 100644 --- a/dmd2/argtypes.c +++ b/dmd2/argtypes.c @@ -124,6 +124,11 @@ TypeTuple *TypeBasic::toArgTypes() return t; } +TypeTuple *TypeVector::toArgTypes() +{ + return new TypeTuple(Type::tfloat64); +} + TypeTuple *TypeSArray::toArgTypes() { #if DMDV2 diff --git a/dmd2/arrayop.c b/dmd2/arrayop.c index 0ab8ab68..ed685c18 100644 --- a/dmd2/arrayop.c +++ b/dmd2/arrayop.c @@ -578,7 +578,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/dmd2/attrib.c b/dmd2/attrib.c index c5fda17b..efd8c1d3 100644 --- a/dmd2/attrib.c +++ b/dmd2/attrib.c @@ -310,11 +310,11 @@ const char *AttribDeclaration::kind() return "attribute"; } -int AttribDeclaration::oneMember(Dsymbol **ps) +int AttribDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { Dsymbols *d = include(NULL, NULL); - return Dsymbol::oneMembers(d, ps); + return Dsymbol::oneMembers(d, ps, ident); } void AttribDeclaration::checkCtorConstInit() @@ -392,10 +392,10 @@ Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) return scd; } -int StorageClassDeclaration::oneMember(Dsymbol **ps) +int StorageClassDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { - int t = Dsymbol::oneMembers(decl, ps); + int t = Dsymbol::oneMembers(decl, ps, ident); if (t && *ps) { /* This is to deal with the following case: @@ -1150,6 +1150,7 @@ void PragmaDeclaration::semantic(Scope *sc) else error("unrecognized pragma(%s)", ident->toChars()); +Ldecl: if (decl) { for (unsigned i = 0; i < decl->dim; i++) @@ -1167,10 +1168,13 @@ 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) +int PragmaDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { *ps = NULL; return TRUE; @@ -1263,13 +1267,13 @@ Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) } -int ConditionalDeclaration::oneMember(Dsymbol **ps) +int ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); if (condition->inc) { Dsymbols *d = condition->include(NULL, NULL) ? decl : elsedecl; - return Dsymbol::oneMembers(d, ps); + return Dsymbol::oneMembers(d, ps, ident); } *ps = NULL; return TRUE; diff --git a/dmd2/attrib.h b/dmd2/attrib.h index bfe579fe..388cd55d 100644 --- a/dmd2/attrib.h +++ b/dmd2/attrib.h @@ -47,7 +47,7 @@ struct AttribDeclaration : Dsymbol void addComment(unsigned char *comment); void emitComment(Scope *sc); const char *kind(); - int oneMember(Dsymbol **ps); + int oneMember(Dsymbol **ps, Identifier *ident); int hasPointers(); bool hasStaticCtorOrDtor(); void checkCtorConstInit(); @@ -74,7 +74,7 @@ struct StorageClassDeclaration: AttribDeclaration Dsymbol *syntaxCopy(Dsymbol *s); void setScope(Scope *sc); void semantic(Scope *sc); - int oneMember(Dsymbol **ps); + int oneMember(Dsymbol **ps, Identifier *ident); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); static void stcToCBuffer(OutBuffer *buf, StorageClass stc); @@ -138,7 +138,7 @@ struct PragmaDeclaration : AttribDeclaration Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void setScope(Scope *sc); - int oneMember(Dsymbol **ps); + int oneMember(Dsymbol **ps, Identifier *ident); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); @@ -158,7 +158,7 @@ struct ConditionalDeclaration : AttribDeclaration ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); Dsymbol *syntaxCopy(Dsymbol *s); - int oneMember(Dsymbol **ps); + int oneMember(Dsymbol **ps, Identifier *ident); void emitComment(Scope *sc); Dsymbols *include(Scope *sc, ScopeDsymbol *s); void addComment(unsigned char *comment); diff --git a/dmd2/canthrow.c b/dmd2/canthrow.c new file mode 100644 index 00000000..a7280c1d --- /dev/null +++ b/dmd2/canthrow.c @@ -0,0 +1,190 @@ + +// 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 "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" + +int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow); +int lambdaCanThrow(Expression *e, void *param); + +/******************************************** + * Convert from expression to delegate that returns the expression, + * i.e. convert: + * expr + * to: + * t delegate() { return expr; } + */ + +struct CanThrow +{ + bool can; + bool mustnot; +}; + +int Expression::canThrow(bool mustNotThrow) +{ + //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars()); + CanThrow ct; + ct.can = FALSE; + ct.mustnot = mustNotThrow; + apply(&lambdaCanThrow, &ct); + return ct.can; +} + +int lambdaCanThrow(Expression *e, void *param) +{ + CanThrow *pct = (CanThrow *)param; + switch (e->op) + { + case TOKdeclaration: + { DeclarationExp *de = (DeclarationExp *)e; + pct->can = Dsymbol_canThrow(de->declaration, pct->mustnot); + break; + } + + case TOKcall: + { CallExp *ce = (CallExp *)e; + + if (global.errors && !ce->e1->type) + break; // error recovery + + /* If calling a function or delegate that is typed as nothrow, + * then this expression cannot throw. + * Note that pure functions can throw. + */ + Type *t = ce->e1->type->toBasetype(); + if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) + ; + else if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) + ; + else + { + if (pct->mustnot) + e->error("%s is not nothrow", ce->e1->toChars()); + pct->can = TRUE; + } + break; + } + + case TOKnew: + { NewExp *ne = (NewExp *)e; + if (ne->member) + { + // See if constructor call can throw + Type *t = ne->member->type->toBasetype(); + if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow) + { + if (pct->mustnot) + e->error("constructor %s is not nothrow", ne->member->toChars()); + pct->can = TRUE; + } + } + // regard storage allocation failures as not recoverable + break; + } + + case TOKnewanonclass: + assert(0); // should have been lowered by semantic() + break; + + default: + break; + } + return pct->can; // stop walking if we determine this expression can throw +} + +/************************************** + * Does symbol, when initialized, throw? + * Mirrors logic in Dsymbol_toElem(). + */ + +int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) +{ + AttribDeclaration *ad; + VarDeclaration *vd; + TemplateMixin *tm; + TupleDeclaration *td; + + //printf("Dsymbol_toElem() %s\n", s->toChars()); + ad = s->isAttribDeclaration(); + if (ad) + { + Dsymbols *decl = ad->include(NULL, NULL); + if (decl && decl->dim) + { + for (size_t i = 0; i < decl->dim; i++) + { + s = decl->tdata()[i]; + if (Dsymbol_canThrow(s, mustNotThrow)) + return 1; + } + } + } + else if ((vd = s->isVarDeclaration()) != NULL) + { + s = s->toAlias(); + if (s != vd) + return Dsymbol_canThrow(s, mustNotThrow); + if (vd->storage_class & STCmanifest) + ; + else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared)) + ; + else + { + if (vd->init) + { ExpInitializer *ie = vd->init->isExpInitializer(); + if (ie && ie->exp->canThrow(mustNotThrow)) + return 1; + } + if (vd->edtor && !vd->noscope) + return vd->edtor->canThrow(mustNotThrow); + } + } + else if ((tm = s->isTemplateMixin()) != NULL) + { + //printf("%s\n", tm->toChars()); + if (tm->members) + { + for (size_t i = 0; i < tm->members->dim; i++) + { + Dsymbol *sm = tm->members->tdata()[i]; + if (Dsymbol_canThrow(sm, mustNotThrow)) + return 1; + } + } + } + else if ((td = s->isTupleDeclaration()) != NULL) + { + for (size_t i = 0; i < td->objects->dim; i++) + { Object *o = td->objects->tdata()[i]; + if (o->dyncast() == DYNCAST_EXPRESSION) + { Expression *eo = (Expression *)o; + if (eo->op == TOKdsymbol) + { DsymbolExp *se = (DsymbolExp *)eo; + if (Dsymbol_canThrow(se->s, mustNotThrow)) + return 1; + } + } + } + } + return 0; +} diff --git a/dmd2/cast.c b/dmd2/cast.c index 90fd6380..bab1d50d 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -209,6 +209,12 @@ MATCH IntegerExp::implicitConvTo(Type *t) if (m == MATCHnomatch && t->ty == Tenum) goto Lno; + if (t->ty == Tvector) + { TypeVector *tv = (TypeVector *)t; + TypeBasic *tb = tv->elementType(); + toty = tb->ty; + } + switch (ty) { case Tbool: @@ -713,6 +719,18 @@ MATCH DelegateExp::implicitConvTo(Type *t) return result; } +MATCH FuncExp::implicitConvTo(Type *t) +{ + //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars()); + if (type && type != Type::tvoid && tok == TOKreserved && type->ty == Tpointer + && (t->ty == Tpointer || t->ty == Tdelegate)) + { // Allow implicit function to delegate conversion + if (type->nextOf()->covariant(t->nextOf()) == 1) + return t->ty == Tpointer ? MATCHconst : MATCHconvert; + } + return Expression::implicitConvTo(t); +} + MATCH OrExp::implicitConvTo(Type *t) { MATCH result = Expression::implicitConvTo(t); @@ -860,6 +878,12 @@ Expression *Expression::castTo(Scope *sc, Type *t) } L1: ; } + else if (tb->ty == Tvector && typeb->ty != Tvector) + { + e = new VectorExp(loc, e, tb); + e = e->semantic(sc); + return e; + } e = new CastExp(loc, e, tb); } } @@ -1522,6 +1546,22 @@ Expression *DelegateExp::castTo(Scope *sc, Type *t) return e; } +Expression *FuncExp::castTo(Scope *sc, Type *t) +{ + //printf("FuncExp::castTo type = %s, t = %s\n", type->toChars(), t->toChars()); + if (tok == TOKreserved) + { assert(type && type != Type::tvoid); + if (type->ty == Tpointer && t->ty == Tdelegate) + { + Expression *e = copy(); + e->type = new TypeDelegate(fd->type); + e->type = e->type->semantic(loc, sc); + return e; + } + } + return Expression::castTo(sc, t); +} + Expression *CondExp::castTo(Scope *sc, Type *t) { Expression *e = this; @@ -1738,13 +1778,16 @@ Lagain: t = t2; else if (t2n->ty == Tvoid) ; + else if (t1->implicitConvTo(t2)) + { + goto Lt2; + } + else if (t2->implicitConvTo(t1)) + { + goto Lt1; + } else if (t1n->ty == Tfunction && t2n->ty == Tfunction) { - if (t1->implicitConvTo(t2)) - goto Lt2; - if (t2->implicitConvTo(t1)) - goto Lt1; - TypeFunction *tf1 = (TypeFunction *)t1n; TypeFunction *tf2 = (TypeFunction *)t2n; TypeFunction *d = (TypeFunction *)tf1->syntaxCopy(); @@ -1782,8 +1825,11 @@ Lagain: } else if (t1n->mod != t2n->mod) { - t1 = t1n->mutableOf()->constOf()->pointerTo(); - t2 = t2n->mutableOf()->constOf()->pointerTo(); + if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared()) + goto Lincompatible; + unsigned char mod = MODmerge(t1n->mod, t2n->mod); + t1 = t1n->castMod(mod)->pointerTo(); + t2 = t2n->castMod(mod)->pointerTo(); t = t1; goto Lagain; } @@ -1807,7 +1853,19 @@ Lagain: goto Lincompatible; } else + { + t1 = t1n->constOf()->pointerTo(); + t2 = t2n->constOf()->pointerTo(); + if (t1->implicitConvTo(t2)) + { + goto Lt2; + } + else if (t2->implicitConvTo(t1)) + { + goto Lt1; + } goto Lincompatible; + } } else if ((t1->ty == Tsarray || t1->ty == Tarray) && (e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid || @@ -1840,10 +1898,14 @@ Lagain: } 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; } /* If one is mutable and the other invariant, then retry @@ -1853,30 +1915,54 @@ Lagain: (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) && t1->nextOf()->mod != t2->nextOf()->mod ) - { unsigned char mod = MODmerge(t1->nextOf()->mod, t2->nextOf()->mod); + { + Type *t1n = t1->nextOf(); + Type *t2n = t2->nextOf(); + unsigned char mod; + if (e1->op == TOKnull && e2->op != TOKnull) + mod = t2n->mod; + else if (e1->op != TOKnull && e2->op == TOKnull) + mod = t1n->mod; + else if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared()) + goto Lincompatible; + else + mod = MODmerge(t1n->mod, t2n->mod); if (t1->ty == Tpointer) - t1 = t1->nextOf()->castMod(mod)->pointerTo(); + t1 = t1n->castMod(mod)->pointerTo(); else - t1 = t1->nextOf()->castMod(mod)->arrayOf(); + t1 = t1n->castMod(mod)->arrayOf(); if (t2->ty == Tpointer) - t2 = t2->nextOf()->castMod(mod)->pointerTo(); + t2 = t2n->castMod(mod)->pointerTo(); else - t2 = t2->nextOf()->castMod(mod)->arrayOf(); + t2 = t2n->castMod(mod)->arrayOf(); t = t1; goto Lagain; } - else if (t1->ty == Tclass || t2->ty == Tclass) + else if (t1->ty == Tclass && t2->ty == Tclass) { if (t1->mod != t2->mod) - { unsigned char mod = MODmerge(t1->mod, t2->mod); + { + unsigned char mod; + if (e1->op == TOKnull && e2->op != TOKnull) + mod = t2->mod; + else if (e1->op != TOKnull && e2->op == TOKnull) + mod = t1->mod; + else if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared()) + goto Lincompatible; + else + mod = MODmerge(t1->mod, t2->mod); t1 = t1->castMod(mod); t2 = t2->castMod(mod); t = t1; goto Lagain; } - + goto Lcc; + } + else if (t1->ty == Tclass || t2->ty == Tclass) + { +Lcc: while (1) { int i1 = e2->implicitConvTo(t1); @@ -1943,6 +2029,8 @@ Lagain: { if (t1->mod != t2->mod) { + if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared()) + goto Lincompatible; unsigned char mod = MODmerge(t1->mod, t2->mod); t1 = t1->castMod(mod); t2 = t2->castMod(mod); @@ -1998,15 +2086,6 @@ Lagain: } else if (t1->ty == Tstruct || t2->ty == Tstruct) { - if (t1->mod != t2->mod) - { - unsigned char mod = MODmerge(t1->mod, t2->mod); - t1 = t1->castMod(mod); - t2 = t2->castMod(mod); - t = t1; - goto Lagain; - } - if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis) { e1 = new DotIdExp(e1->loc, e1, ((TypeStruct *)t1)->sym->aliasthis->ident); @@ -2051,9 +2130,25 @@ Lagain: e1 = e1->castTo(sc, t); e2 = e2->castTo(sc, t); } + else if (t1->ty == Tvector && t2->ty != Tvector && + e2->implicitConvTo(t1)) + { + e2 = e2->castTo(sc, t1); + t2 = t1; + goto Lagain; + } + else if (t2->ty == Tvector && t1->ty != Tvector && + e1->implicitConvTo(t2)) + { + e1 = e1->castTo(sc, t2); + t1 = t2; + goto Lagain; + } else if (t1->isintegral() && t2->isintegral()) { assert(t1->ty == t2->ty); + if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared()) + goto Lincompatible; unsigned char mod = MODmerge(t1->mod, t2->mod); t1 = t1->castMod(mod); diff --git a/dmd2/class.c b/dmd2/class.c index 8ad01e8e..238f89f8 100644 --- a/dmd2/class.c +++ b/dmd2/class.c @@ -296,9 +296,11 @@ void ClassDeclaration::semantic(Scope *sc) methods.setDim(0); #endif + int errors = global.gaggedErrors; + if (sc->stc & STCdeprecated) { - isdeprecated = 1; + isdeprecated = true; } if (sc->linkage == LINKcpp) @@ -307,9 +309,7 @@ void ClassDeclaration::semantic(Scope *sc) // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) { BaseClass *b = baseclasses->tdata()[i]; -//printf("test1 %s %s\n", toChars(), b->type->toChars()); b->type = b->type->semantic(loc, sc); -//printf("test2\n"); Type *tb = b->type->toBasetype(); if (tb->ty == Ttuple) @@ -349,7 +349,7 @@ void ClassDeclaration::semantic(Scope *sc) if (!isDeprecated()) { // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; + isdeprecated = true; tc->checkDeprecated(loc, sc); } @@ -422,7 +422,7 @@ void ClassDeclaration::semantic(Scope *sc) if (!isDeprecated()) { // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; + isdeprecated = true; tc->checkDeprecated(loc, sc); } @@ -657,9 +657,15 @@ void ClassDeclaration::semantic(Scope *sc) s->semantic(sc); } - if (sizeok == 2) - { // semantic() failed because of forward references. + if (global.gag && global.gaggedErrors != errors) + { // The type is no good, yet the error messages were gagged. + type = Type::terror; + } + + if (sizeok == 2) // failed due to forward references + { // semantic() failed due to forward references // Unwind what we did, and defer it for later + fields.setDim(0); structsize = 0; alignsize = 0; @@ -772,7 +778,7 @@ void ClassDeclaration::semantic(Scope *sc) #endif //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); - if (deferred) + if (deferred && !global.gag) { deferred->semantic2(sc); deferred->semantic3(sc); @@ -938,6 +944,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). @@ -1212,9 +1235,11 @@ void InterfaceDeclaration::semantic(Scope *sc) scope = NULL; } + int errors = global.gaggedErrors; + if (sc->stc & STCdeprecated) { - isdeprecated = 1; + isdeprecated = true; } // Expand any tuples in baseclasses[] @@ -1360,11 +1385,33 @@ void InterfaceDeclaration::semantic(Scope *sc) structalign = sc->structalign; sc->offset = PTRSIZE * 2; inuse++; + + /* Set scope so if there are forward references, we still might be able to + * resolve individual members like enums. + */ + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + /* There are problems doing this in the general case because + * Scope keeps track of things like 'offset' + */ + if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) + { + //printf("setScope %s %s\n", s->kind(), s->toChars()); + s->setScope(sc); + } + } + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = members->tdata()[i]; s->semantic(sc); } + + if (global.gag && global.gaggedErrors != errors) + { // The type is no good, yet the error messages were gagged. + type = Type::terror; + } + inuse--; //members->print(); sc->pop(); diff --git a/dmd2/constfold.c b/dmd2/constfold.c index 5581658e..38d00efd 100644 --- a/dmd2/constfold.c +++ b/dmd2/constfold.c @@ -1376,7 +1376,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; } } @@ -1394,7 +1394,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; } } @@ -1414,7 +1414,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; } @@ -1467,7 +1467,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(); @@ -1491,6 +1491,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) @@ -1600,62 +1658,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/dmd2/cppmangle.c b/dmd2/cppmangle.c index a6ef4c26..630567ef 100644 --- a/dmd2/cppmangle.c +++ b/dmd2/cppmangle.c @@ -266,6 +266,14 @@ void TypeBasic::toCppMangle(OutBuffer *buf, CppMangleState *cms) } +void TypeVector::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, this)) + { buf->writestring("U8__vector"); + basetype->toCppMangle(buf, cms); + } +} + void TypeSArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) { if (!cms->substitute(buf, this)) diff --git a/dmd2/declaration.c b/dmd2/declaration.c index 528f440c..a199369a 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -457,6 +457,7 @@ void AliasDeclaration::semantic(Scope *sc) #endif storage_class |= sc->stc & STCdeprecated; + protection = sc->protection; // Given: // alias foo.bar.abc def; @@ -1274,14 +1275,25 @@ Lnomatch: StructInitializer *si = init->isStructInitializer(); ExpInitializer *ei = init->isExpInitializer(); - // See if initializer is a NewExp that can be allocated on the stack - if (ei && isScope() && ei->exp->op == TOKnew) - { NewExp *ne = (NewExp *)ei->exp; - if (!(ne->newargs && ne->newargs->dim)) - { ne->onstack = 1; - onstack = 1; - if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) - onstack = 2; + if (ei && ei->exp->op == TOKfunction && !inferred) + ((FuncExp *)ei->exp)->setType(type); + + if (ei && isScope()) + { + // See if initializer is a NewExp that can be allocated on the stack + if (ei->exp->op == TOKnew) + { NewExp *ne = (NewExp *)ei->exp; + if (!(ne->newargs && ne->newargs->dim)) + { ne->onstack = 1; + onstack = 1; + if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) + onstack = 2; + } + } + // or a delegate that doesn't escape a reference to the function + else if (ei->exp->op == TOKfunction) + { FuncDeclaration *f = ((FuncExp *)ei->exp)->fd; + f->tookAddressOf--; } } @@ -1368,6 +1380,13 @@ Lnomatch: * variable with a bit copy of the default * initializer */ + + /* Remove ref if this declaration is ref binding. + * ref Type __self = (__ctmp = 0, __ctmp).this(...); + * -> Type __self = (__self = 0, __self.this(...)); + */ + storage_class &= ~(STCref | STCforeach | STCparameter); + Expression *e; if (sd->zeroInit == 1) { @@ -1714,25 +1733,45 @@ void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) * so it never becomes closure. */ + //printf("\tfdv = %s\n", fdv->toChars()); + //printf("\tfdthis = %s\n", fdthis->toChars()); + if (loc.filename) - fdthis->getLevel(loc, fdv); + fdthis->getLevel(loc, sc, fdv); - for (size_t i = 0; i < nestedrefs.dim; i++) - { FuncDeclaration *f = nestedrefs.tdata()[i]; - if (f == fdthis) - goto L1; + // Function literals from fdthis to fdv must be delegates + for (Dsymbol *s = fdthis; s && s != fdv; s = s->toParent2()) + { + // function literal has reference to enclosing scope is delegate + if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration()) + { + fld->tok = TOKdelegate; + } } - nestedrefs.push(fdthis); - L1: ; - - for (size_t i = 0; i < fdv->closureVars.dim; i++) - { Dsymbol *s = fdv->closureVars.tdata()[i]; - if (s == this) - goto L2; + // Add fdthis to nestedrefs[] if not already there + for (size_t i = 0; 1; i++) + { + if (i == nestedrefs.dim) + { + nestedrefs.push(fdthis); + break; + } + if (nestedrefs[i] == fdthis) + break; + } + + // Add this to fdv->closureVars[] if not already there + for (size_t i = 0; 1; i++) + { + if (i == fdv->closureVars.dim) + { + fdv->closureVars.push(this); + break; + } + if (fdv->closureVars[i] == this) + break; } - fdv->closureVars.push(this); - L2: ; //printf("fdthis is %s\n", fdthis->toChars()); //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); @@ -2205,6 +2244,18 @@ TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *t type = Type::typeinfoassociativearray->type; } +/***************************** TypeInfoVectorDeclaration ***********************/ + +TypeInfoVectorDeclaration::TypeInfoVectorDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + if (!Type::typeinfoarray) + { + ObjectNotFound(Id::TypeInfo_Vector); + } + type = Type::typeinfovector->type; +} + /***************************** TypeInfoEnumDeclaration ***********************/ TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) diff --git a/dmd2/declaration.h b/dmd2/declaration.h index c29af9ba..c887e6eb 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -294,10 +294,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 @@ -655,6 +652,15 @@ struct TypeInfoWildDeclaration : TypeInfoDeclaration void llvmDefine(); #endif }; + +struct TypeInfoVectorDeclaration : TypeInfoDeclaration +{ + TypeInfoVectorDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif +}; #endif /**************************************************************/ @@ -734,11 +740,12 @@ struct FuncDeclaration : Declaration Loc endloc; // location of closing curly bracket int vtblIndex; // for member functions, index into vtbl[] int naked; // !=0 if naked - 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 enum PASS semanticRun; + int semantic3Errors; // !=0 if errors in semantic3 // this function's frame ptr ForeachStatement *fes; // if foreach body, this is the foreach int introducing; // !=0 if 'introducing' function @@ -801,7 +808,7 @@ struct FuncDeclaration : Declaration LabelDsymbol *searchLabel(Identifier *ident); AggregateDeclaration *isThis(); AggregateDeclaration *isMember2(); - int getLevel(Loc loc, FuncDeclaration *fd); // lexical nesting level difference + int getLevel(Loc loc, Scope *sc, FuncDeclaration *fd); // lexical nesting level difference void appendExp(Expression *e); void appendState(Statement *s); char *mangle(); @@ -823,18 +830,21 @@ struct FuncDeclaration : Declaration bool setUnsafe(); 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, Expressions *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(); + void checkNestedReference(Scope *sc, Loc loc); int needsClosure(); + int hasNestedFrameRefs(); Statement *mergeFrequire(Statement *, Expressions *params = 0); Statement *mergeFensure(Statement *, Expressions *params = 0); Parameters *getParameters(int *pvarargs); diff --git a/dmd2/delegatize.c b/dmd2/delegatize.c index b805ea56..a4d37152 100644 --- a/dmd2/delegatize.c +++ b/dmd2/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,15 +38,12 @@ 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; if (t->ty == Tvoid) s = new ExpStatement(loc, e); @@ -55,164 +55,86 @@ Expression *Expression::toDelegate(Scope *sc, Type *t) 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/dmd2/doc.c b/dmd2/doc.c index 4b980056..ed405f24 100644 --- a/dmd2/doc.c +++ b/dmd2/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 @@ -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/dmd2/dsymbol.c b/dmd2/dsymbol.c index f83d4f69..0ccec83b 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.c @@ -111,7 +111,7 @@ Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) * TRUE, *ps = symbol: The one and only one symbol */ -int Dsymbol::oneMember(Dsymbol **ps) +int Dsymbol::oneMember(Dsymbol **ps, Identifier *ident) { //printf("Dsymbol::oneMember()\n"); *ps = this; @@ -122,7 +122,7 @@ int Dsymbol::oneMember(Dsymbol **ps) * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. */ -int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps) +int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) { //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); Dsymbol *s = NULL; @@ -132,7 +132,7 @@ int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps) for (size_t i = 0; i < members->dim; i++) { Dsymbol *sx = (*members)[i]; - int x = sx->oneMember(ps); + int x = sx->oneMember(ps, ident); //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); if (!x) { @@ -142,6 +142,11 @@ int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps) } if (*ps) { + if (ident) + { + if (!(*ps)->ident || !(*ps)->ident->equals(ident)) + continue; + } if (s) // more than one symbol { *ps = NULL; //printf("\tfalse 2\n"); @@ -653,19 +658,16 @@ void Dsymbol::checkDeprecated(Loc loc, Scope *sc) Module *Dsymbol::getModule() { - Module *m; - Dsymbol *s; - //printf("Dsymbol::getModule()\n"); TemplateDeclaration *td = getFuncTemplateDecl(this); if (td) return td->getModule(); - s = this; + Dsymbol *s = this; while (s) { - //printf("\ts = '%s'\n", s->toChars()); - m = s->isModule(); + //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); + Module *m = s->isModule(); if (m) return m; s = s->parent; @@ -673,30 +675,32 @@ Module *Dsymbol::getModule() return NULL; } - /********************************** - * Determine which Module a Dsymbol will be compiled in. - * This may be different from getModule for templates. + * Determine which Module a Dsymbol is in, as far as access rights go. */ -Module *Dsymbol::getCompilationModule() +Module *Dsymbol::getAccessModule() { - Module *m; - TemplateInstance *ti; - Dsymbol *s; + //printf("Dsymbol::getAccessModule()\n"); + TemplateDeclaration *td = getFuncTemplateDecl(this); + if (td) + return td->getAccessModule(); - //printf("Dsymbol::getModule()\n"); - s = this; + Dsymbol *s = this; while (s) { - //printf("\ts = '%s'\n", s->toChars()); - m = s->isModule(); - if (m) - return m; - ti = s->isTemplateInstance(); - if (ti && ti->tmodule) - return ti->tmodule; - s = s->parent; + //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); + Module *m = s->isModule(); + if (m) + return m; + TemplateInstance *ti = s->isTemplateInstance(); + if (ti && ti->isnested) + /* Because of local template instantiation, the parent isn't where the access + * rights come from - it's the template declaration + */ + s = ti->tempdecl; + else + s = s->parent; } return NULL; } @@ -832,7 +836,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 @@ -842,7 +846,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) @@ -895,7 +899,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) if (flags & 4) // if return NULL on ambiguity return NULL; if (!(flags & 2)) - ss->multiplyDefined(loc, s, s2); + ScopeDsymbol::multiplyDefined(loc, s, s2); break; } } @@ -922,7 +926,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) 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); @@ -930,11 +934,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]) @@ -1051,8 +1055,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 @@ -1102,7 +1105,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/dmd2/dsymbol.h b/dmd2/dsymbol.h index e244b6f7..197ebcd9 100644 --- a/dmd2/dsymbol.h +++ b/dmd2/dsymbol.h @@ -154,7 +154,7 @@ struct Dsymbol : Object void verror(Loc loc, const char *format, va_list ap); void checkDeprecated(Loc loc, Scope *sc); Module *getModule(); // module where declared - Module *getCompilationModule(); // possibly different for templates + Module *getAccessModule(); Dsymbol *pastMixin(); Dsymbol *toParent(); Dsymbol *toParent2(); @@ -203,8 +203,8 @@ struct Dsymbol : Object virtual int needThis(); // need a 'this' pointer? virtual enum PROT prot(); virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual int oneMember(Dsymbol **ps); - static int oneMembers(Dsymbols *members, Dsymbol **ps); + virtual int oneMember(Dsymbol **ps, Identifier *ident); + static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL); virtual int hasPointers(); virtual bool hasStaticCtorOrDtor(); virtual void addLocalClass(ClassDeclarations *) { } @@ -291,14 +291,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/dmd2/enum.c b/dmd2/enum.c index 881ba2d8..a92e9ef9 100644 --- a/dmd2/enum.c +++ b/dmd2/enum.c @@ -300,11 +300,11 @@ void EnumDeclaration::semantic(Scope *sc) //members->print(); } -int EnumDeclaration::oneMember(Dsymbol **ps) +int EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident) { if (isAnonymous()) - return Dsymbol::oneMembers(members, ps); - return Dsymbol::oneMember(ps); + return Dsymbol::oneMembers(members, ps, ident); + return Dsymbol::oneMember(ps, ident); } void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) diff --git a/dmd2/enum.h b/dmd2/enum.h index a07d80d7..b8b3290e 100644 --- a/dmd2/enum.h +++ b/dmd2/enum.h @@ -47,7 +47,7 @@ struct EnumDeclaration : ScopeDsymbol Dsymbol *syntaxCopy(Dsymbol *s); void semantic0(Scope *sc); void semantic(Scope *sc); - int oneMember(Dsymbol **ps); + int oneMember(Dsymbol **ps, Identifier *ident = NULL); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Type *getType(); const char *kind(); diff --git a/dmd2/expression.c b/dmd2/expression.c index 1fe0671a..5062f139 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -235,19 +235,63 @@ Lno: Expression *resolveProperties(Scope *sc, Expression *e) { //printf("resolveProperties(%s)\n", e->toChars()); + + TemplateDeclaration *td; + Objects *targsi; + Expression *ethis; + if (e->op == TOKdotti) + { + DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e; + td = dti->getTempdecl(sc); + dti->ti->semanticTiargs(sc); + targsi = dti->ti->tiargs; + ethis = dti->e1; + goto L1; + } + else if (e->op == TOKdottd) + { + DotTemplateExp *dte = (DotTemplateExp *)e; + td = dte->td; + targsi = NULL; + ethis = dte->e1; + goto L1; + } + else if (e->op == TOKtemplate) + { + td = ((TemplateExp *)e)->td; + targsi = NULL; + ethis = NULL; + L1: + assert(td); + unsigned errors = global.startGagging(); + FuncDeclaration *fd = td->deduceFunctionTemplate(sc, e->loc, targsi, ethis, NULL, 1); + if (global.endGagging(errors)) + fd = NULL; // eat "is not a function template" error + if (fd && fd->type) + { assert(fd->type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)fd->type; + if (!tf->isproperty && global.params.enforcePropertySyntax) + { error(e->loc, "not a property %s", e->toChars()); + return new ErrorExp(); + } + e = new CallExp(e->loc, e); + e = e->semantic(sc); + } + goto return_expr; + } + if (e->type) { Type *t = e->type->toBasetype(); if (t->ty == Tfunction || e->op == TOKoverloadset) { -#if 1 if (t->ty == Tfunction && !((TypeFunction *)t)->isproperty && global.params.enforcePropertySyntax) { - error(e->loc, "not a property %s\n", e->toChars()); + error(e->loc, "not a property %s", e->toChars()); + return new ErrorExp(); } -#endif e = new CallExp(e->loc, e); e = e->semantic(sc); } @@ -271,10 +315,12 @@ Expression *resolveProperties(Scope *sc, Expression *e) } } - else if (e->op == TOKdottd) + +return_expr: + if (!e->type) { - e = new CallExp(e->loc, e); - e = e->semantic(sc); + error(e->loc, "cannot resolve type for %s", e->toChars()); + e->type = new TypeError(); } return e; } @@ -568,16 +614,6 @@ void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) for (size_t i = 0; i < exps->dim; i++) { Expression *arg = (*exps)[i]; - if (!arg->type) - { -#ifdef DEBUG - if (!global.gag) - printf("1: \n"); -#endif - arg->error("%s is not an expression", arg->toChars()); - arg = new ErrorExp(); - } - arg = resolveProperties(sc, arg); (*exps)[i] = arg; @@ -697,7 +733,9 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, size_t nparams = Parameter::dim(tf->parameters); if (nargs > nparams && tf->varargs == 0) - error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars()); + { error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars()); + return Type::terror; + } // If inferring return type, and semantic3() needs to be run if not already run if (!tf->next && fd->inferRetType) @@ -714,6 +752,19 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, unsigned n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) unsigned wildmatch = 0; + if (ethis && tf->isWild()) + { + Type *t = ethis->type; + if (t->isWild()) + wildmatch |= MODwild; + else if (t->isConst()) + wildmatch |= MODconst; + else if (t->isImmutable()) + wildmatch |= MODimmutable; + else + wildmatch |= MODmutable; + } + int done = 0; for (size_t i = 0; i < n; i++) { @@ -723,7 +774,6 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, arg = arguments->tdata()[i]; else arg = NULL; - Type *tb; if (i < nparams) { @@ -736,7 +786,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (tf->varargs == 2 && i + 1 == nparams) goto L2; error(loc, "expected %zu function arguments, not %zu", nparams, nargs); - return tf->next; + return Type::terror; } arg = p->defaultArg; arg = arg->inlineCopy(sc); @@ -746,6 +796,15 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, arguments->push(arg); nargs++; } + else if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + Type *pt = p->type; + if (tf->varargs == 2 && i + 1 == nparams && pt->nextOf()) + pt = pt->nextOf(); + fe->setType(pt); + arg = fe->semantic(sc); + arguments->tdata()[i] = arg; + } if (tf->varargs == 2 && i + 1 == nparams) { @@ -756,7 +815,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, goto L2; else if (nargs != nparams) { error(loc, "expected %zu function arguments, not %zu", nparams, nargs); - return tf->next; + return Type::terror; } goto L1; } @@ -824,13 +883,15 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, default: if (!arg) { error(loc, "not enough arguments"); - return tf->next; + return Type::terror; } break; } arg = arg->semantic(sc); //printf("\targ = '%s'\n", arg->toChars()); arguments->setDim(i + 1); + arguments->tdata()[i] = arg; + nargs = i + 1; done = 1; } @@ -841,7 +902,42 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, if (mod) { wildmatch |= mod; - arg = arg->implicitCastTo(sc, p->type->substWildTo(mod)); + } + } + } + if (done) + break; + } + if (wildmatch) + { /* Calculate wild matching modifier + */ + if (wildmatch & MODconst || wildmatch & (wildmatch - 1)) + wildmatch = MODconst; + else if (wildmatch & MODimmutable) + wildmatch = MODimmutable; + else if (wildmatch & MODwild) + wildmatch = MODwild; + else + { assert(wildmatch & MODmutable); + wildmatch = MODmutable; + } + } + + assert(nargs >= nparams); + for (size_t i = 0; i < nargs; i++) + { + Expression *arg = arguments->tdata()[i]; + assert(arg); + + if (i < nparams) + { + Parameter *p = Parameter::getNth(tf->parameters, i); + + if (!(p->storageClass & STClazy && p->type->ty == Tvoid)) + { + if (p->type->hasWild()) + { + arg = arg->implicitCastTo(sc, p->type->substWildTo(wildmatch)); arg = arg->optimize(WANTvalue); } else if (p->type != arg->type) @@ -866,7 +962,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, arg = arg->modifiableLvalue(sc, arg); } - tb = arg->type->toBasetype(); + Type *tb = arg->type->toBasetype(); // LDC we don't want this! #if !IN_LLVM #if !SARRAYVALUE @@ -910,11 +1006,15 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, */ 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; } @@ -922,8 +1022,8 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, * 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(); @@ -961,11 +1061,13 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, // Do not allow types that need destructors if (arg->type->needsDestruction()) - arg->error("cannot pass types that need destruction as variadic arguments"); + { arg->error("cannot pass types that need destruction as variadic arguments"); + arg = new ErrorExp(); + } // Convert static arrays to dynamic arrays // BUG: I don't think this is right for D2 - tb = arg->type->toBasetype(); + Type *tb = arg->type->toBasetype(); if (tb->ty == Tsarray) { TypeSArray *ts = (TypeSArray *)tb; Type *ta = ts->next->arrayOf(); @@ -1006,7 +1108,9 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, se->hasOverloads && #endif !se->var->isFuncDeclaration()->isUnique()) - arg->error("function %s is overloaded", arg->toChars()); + { arg->error("function %s is overloaded", arg->toChars()); + arg = new ErrorExp(); + } } #endif arg->rvalue(); @@ -1014,21 +1118,6 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, arg = arg->optimize(WANTvalue); L3: arguments->tdata()[i] = arg; - if (done) - break; - } - - if (ethis && tf->isWild()) - { - Type *tthis = ethis->type; - if (tthis->isWild()) - wildmatch |= MODwild; - else if (tthis->isConst()) - wildmatch |= MODconst; - else if (tthis->isImmutable()) - wildmatch |= MODimmutable; - else - wildmatch |= MODmutable; } #if !IN_LLVM @@ -1046,16 +1135,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, { /* Adjust function return type based on wildmatch */ //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars()); - if (wildmatch & MODconst || wildmatch & (wildmatch - 1)) - tret = tret->substWildTo(MODconst); - else if (wildmatch & MODimmutable) - tret = tret->substWildTo(MODimmutable); - else if (wildmatch & MODwild) - ; - else - { assert(wildmatch & MODmutable); - tret = tret->substWildTo(MODmutable); - } + tret = tret->substWildTo(wildmatch); } return tret; } @@ -1250,7 +1330,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()); @@ -1258,8 +1338,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) @@ -1352,7 +1435,7 @@ Expression *Expression::toLvalue(Scope *sc, Expression *e) else if (!loc.filename) loc = e->loc; error("%s is not an lvalue", e->toChars()); - return this; + return new ErrorExp(); } Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) @@ -1362,11 +1445,14 @@ Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) // See if this expression is a modifiable lvalue (i.e. not const) #if DMDV2 if (type && (!type->isMutable() || !type->isAssignable())) - error("%s is not mutable", e->toChars()); + { error("%s is not mutable", e->toChars()); + return new ErrorExp(); + } #endif return toLvalue(sc, e); } + /************************************ * Detect cases where pointers to the stack can 'escape' the * lifetime of the stack frame. @@ -1400,7 +1486,8 @@ Expression *Expression::checkIntegral() error("'%s' is not of integral type, it is a %s", toChars(), type->toChars()); return new ErrorExp(); } - rvalue(); + if (!rvalue()) + return new ErrorExp(); return this; } @@ -1411,7 +1498,8 @@ Expression *Expression::checkArithmetic() error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); return new ErrorExp(); } - rvalue(); + if (!rvalue()) + return new ErrorExp(); return this; } @@ -1572,34 +1660,6 @@ void Expression::checkSafety(Scope *sc, FuncDeclaration *f) } #endif -/******************************** - * Check for expressions that have no use. - * Input: - * flag 0 not going to use the result, so issue error message if no - * side effects - * 1 the result of the expression is used, but still check - * for useless subexpressions - * 2 do not issue error messages, just return !=0 if expression - * has side effects - */ - -int Expression::checkSideEffect(int flag) -{ - if (flag == 0) - { - if (op == TOKerror) - { // Error should have already been printed - } - else if (op == TOKimport) - { - error("%s has no effect", toChars()); - } - else - error("%s has no effect in expression (%s)", - Token::toChars(op), toChars()); - } - return 0; -} /***************************** * Check that expression can be tested for true or false. @@ -1722,22 +1782,6 @@ int Expression::isBit() return FALSE; } -/******************************** - * Can this expression throw an exception? - * Valid only after semantic() pass. - * - * If 'mustNotThrow' is true, generate an error if it throws - */ - -int Expression::canThrow(bool mustNotThrow) -{ -#if DMDV2 - return FALSE; -#else - return TRUE; -#endif -} - /**************************************** * Resolve __LINE__ and __FILE__ to loc. */ @@ -1977,7 +2021,7 @@ Expression *IntegerExp::toLvalue(Scope *sc, Expression *e) else if (!loc.filename) loc = e->loc; e->error("constant %s is not an lvalue", e->toChars()); - return this; + return new ErrorExp(); } void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -2538,6 +2582,7 @@ Expression *IdentifierExp::semantic(Scope *sc) s != s2) { error("with symbol %s is shadowing local symbol %s", s->toPrettyChars(), s2->toPrettyChars()); + return new ErrorExp(); } } #endif @@ -2744,6 +2789,8 @@ Lagain: { error("cannot make expression out of initializer for %s", v->toChars()); return new ErrorExp(); } + e = e->copy(); + e->loc = loc; // for better error message e = e->semantic(sc); return e; } @@ -2861,7 +2908,11 @@ Lagain: TemplateDeclaration *td = s->isTemplateDeclaration(); if (td) { - e = new TemplateExp(loc, td); + Dsymbol *p = td->toParent2(); + if (hasThis(sc) && p && p->isAggregateDeclaration()) + e = new DotTemplateExp(loc, new ThisExp(loc), td); + else + e = new TemplateExp(loc, td); e = e->semantic(sc); return e; } @@ -3094,6 +3145,17 @@ NullExp::NullExp(Loc loc, Type *type) this->type = type; } +int NullExp::equals(Object *o) +{ + if (o && o->dyncast() == DYNCAST_EXPRESSION) + { Expression *e = (Expression *)o; + + if (e->op == TOKnull) + return TRUE; + } + return FALSE; +} + Expression *NullExp::semantic(Scope *sc) { #if LOGSEMANTIC @@ -3141,6 +3203,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) @@ -3151,6 +3214,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) @@ -3161,6 +3225,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 @@ -3409,7 +3474,10 @@ int StringExp::isBool(int result) #if DMDV2 int StringExp::isLvalue() { - return 1; + /* string literal is rvalue in default, but + * conversion to reference of static array is only allowed. + */ + return 0; } #endif @@ -3419,6 +3487,12 @@ Expression *StringExp::toLvalue(Scope *sc, Expression *e) return this; } +Expression *StringExp::modifiableLvalue(Scope *sc, Expression *e) +{ + error("Cannot modify '%s'", toChars()); + return new ErrorExp(); +} + unsigned StringExp::charAt(size_t i) { unsigned value; @@ -3547,6 +3621,7 @@ ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) { this->elements = elements; + this->ownedByCtfe = false; } ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) @@ -3585,40 +3660,19 @@ Expression *ArrayLiteralExp::semantic(Scope *sc) /* Disallow array literals of type void being used. */ if (elements->dim > 0 && t0->ty == Tvoid) - error("%s of type %s has no value", toChars(), type->toChars()); + { error("%s of type %s has no value", toChars(), type->toChars()); + return new ErrorExp(); + } return this; } -int ArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - int ArrayLiteralExp::isBool(int result) { size_t dim = elements ? elements->dim : 0; return result ? (dim != 0) : (dim == 0); } -#if DMDV2 -int ArrayLiteralExp::canThrow(bool mustNotThrow) -{ - /* Memory allocation failures throw non-recoverable exceptions, which - * we don't need to count as 'throwing'. - */ - return arrayExpressionCanThrow(elements, mustNotThrow); -} -#endif - StringExp *ArrayLiteralExp::toString() { TY telem = type->nextOf()->toBasetype()->ty; @@ -3676,6 +3730,7 @@ AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc, assert(keys->dim == values->dim); this->keys = keys; this->values = values; + this->ownedByCtfe = false; } Expression *AssocArrayLiteralExp::syntaxCopy() @@ -3714,20 +3769,6 @@ Expression *AssocArrayLiteralExp::semantic(Scope *sc) return this; } -int AssocArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = keys->tdata()[i]; - Expression *value = values->tdata()[i]; - - f |= key->checkSideEffect(2); - f |= value->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} int AssocArrayLiteralExp::isBool(int result) { @@ -3735,17 +3776,6 @@ int AssocArrayLiteralExp::isBool(int result) return result ? (dim != 0) : (dim == 0); } -#if DMDV2 -int AssocArrayLiteralExp::canThrow(bool mustNotThrow) -{ - /* Memory allocation failures throw non-recoverable exceptions, which - * we don't need to count as 'throwing'. - */ - return (arrayExpressionCanThrow(keys, mustNotThrow) || - arrayExpressionCanThrow(values, mustNotThrow)); -} -#endif - void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('['); @@ -3790,6 +3820,7 @@ StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions * #endif this->soffset = 0; this->fillHoles = 1; + this->ownedByCtfe = false; #if IN_LLVM constType = NULL; #endif @@ -3818,10 +3849,6 @@ Expression *StructLiteralExp::semantic(Scope *sc) if (!e) continue; - if (!e->type) - { error("%s has no value", e->toChars()); - return new ErrorExp(); - } e = resolveProperties(sc, e); if (i >= nfields) { error("more initializers than fields of %s", sd->toChars()); @@ -3846,6 +3873,14 @@ Expression *StructLiteralExp::semantic(Scope *sc) telem = telem->toBasetype()->nextOf(); } + if (e->op == TOKfunction) + { e = ((FuncExp *)e)->inferType(sc, telem); + if (!e) + { error("cannot infer function literal type from %s", telem->toChars()); + e = new ErrorExp(); + } + } + e = e->implicitCastTo(sc, telem); elements->tdata()[i] = e; @@ -3899,7 +3934,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) * (S tmp = S()),tmp * so that the destructor can be hung on tmp. */ - if (sd->dtor) + if (sd->dtor && sc->func) { Identifier *idtmp = Lexer::uniqueId("__sl"); VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new ExpInitializer(0, this)); @@ -4001,28 +4036,6 @@ Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) } -int StructLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; - if (!e) - continue; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -#if DMDV2 -int StructLiteralExp::canThrow(bool mustNotThrow) -{ - return arrayExpressionCanThrow(elements, mustNotThrow); -} -#endif - void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring(sd->toChars()); @@ -4083,9 +4096,10 @@ Expression *TypeExp::semantic(Scope *sc) return this; } -void TypeExp::rvalue() +int TypeExp::rvalue() { error("type %s has no value", toChars()); + return 0; } void TypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -4208,9 +4222,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 **************************************/ @@ -4304,8 +4319,9 @@ Lagain: } if (cd->noDefaultCtor && (!arguments || !arguments->dim)) - error("default construction is disabled for type %s", cd->toChars()); - + { error("default construction is disabled for type %s", cd->toChars()); + goto Lerr; + } checkDeprecated(sc, cd); if (cd->isNested()) { /* We need a 'this' pointer for the nested class. @@ -4421,8 +4437,10 @@ Lagain: if (!arguments) arguments = new Expressions(); + unsigned olderrors = global.errors; functionParameters(loc, sc, tf, NULL, arguments, f); - + if (olderrors != global.errors) + return new ErrorExp(); type = type->addMod(tf->nextOf()->mod); } else @@ -4446,7 +4464,11 @@ Lagain: assert(allocator); TypeFunction *tf = (TypeFunction *)f->type; + unsigned olderrors = global.errors; functionParameters(loc, sc, tf, NULL, newargs, f); + if (olderrors != global.errors) + return new ErrorExp(); + } else { @@ -4463,8 +4485,9 @@ Lagain: TypeFunction *tf; if (sd->noDefaultCtor && (!arguments || !arguments->dim)) - error("default construction is disabled for type %s", sd->toChars()); - + { error("default construction is disabled for type %s", sd->toChars()); + goto Lerr; + } FuncDeclaration *f = NULL; if (sd->ctor) f = resolveFuncCall(sc, loc, sd->ctor, NULL, NULL, arguments, 0); @@ -4481,7 +4504,11 @@ Lagain: if (!arguments) arguments = new Expressions(); + unsigned olderrors = global.errors; functionParameters(loc, sc, tf, NULL, arguments, f); + if (olderrors != global.errors) + return new ErrorExp(); + } else { @@ -4505,7 +4532,11 @@ Lagain: assert(allocator); tf = (TypeFunction *)f->type; + unsigned olderrors = global.errors; functionParameters(loc, sc, tf, NULL, newargs, f); + if (olderrors != global.errors) + return new ErrorExp(); + #if 0 e = new VarExp(loc, f); e = new CallExp(loc, e, newargs); @@ -4569,32 +4600,6 @@ Lerr: return new ErrorExp(); } -int NewExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int NewExp::canThrow(bool mustNotThrow) -{ - 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 void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { @@ -4657,18 +4662,6 @@ Expression *NewAnonClassExp::semantic(Scope *sc) return c->semantic(sc); } -int NewAnonClassExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int NewAnonClassExp::canThrow(bool mustNotThrow) -{ - assert(0); // should have been lowered by semantic() - return 1; -} -#endif void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { @@ -4733,6 +4726,9 @@ Expression *SymOffExp::semantic(Scope *sc) VarDeclaration *v = var->isVarDeclaration(); if (v) v->checkNestedReference(sc, loc); + FuncDeclaration *f = var->isFuncDeclaration(); + if (f) + f->checkNestedReference(sc, loc); return this; } @@ -4823,6 +4819,9 @@ Expression *VarExp::semantic(Scope *sc) checkPurity(sc, v, NULL); #endif } + FuncDeclaration *f = var->isFuncDeclaration(); + if (f) + f->checkNestedReference(sc, loc); #if 0 else if ((fd = var->isFuncLiteralDeclaration()) != NULL) { Expression *e; @@ -4851,9 +4850,9 @@ void VarExp::checkEscape() if (v) { Type *tb = v->type->toBasetype(); // if reference type - if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass) + if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass || tb->ty == Tdelegate) { - if (v->isScope() && !v->noscope) + if (v->isScope() && (!v->noscope || tb->ty == Tclass)) error("escaping reference to scope local %s", v->toChars()); else if (v->storage_class & STCvariadic) error("escaping reference to variadic parameter %s", v->toChars()); @@ -5019,7 +5018,7 @@ Expression *TupleExp::semantic(Scope *sc) e = e->semantic(sc); if (!e->type) { error("%s has no value", e->toChars()); - e = new ErrorExp(); + return new ErrorExp(); } (*exps)[i] = e; } @@ -5038,25 +5037,6 @@ void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writeByte(')'); } -int TupleExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -#if DMDV2 -int TupleExp::canThrow(bool mustNotThrow) -{ - return arrayExpressionCanThrow(exps, mustNotThrow); -} -#endif void TupleExp::checkEscape() { @@ -5068,10 +5048,14 @@ void TupleExp::checkEscape() /******************************** FuncExp *********************************/ -FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd) +FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td) : Expression(loc, TOKfunction, sizeof(FuncExp)) { this->fd = fd; + this->td = td; + tok = fd->tok; // save original kind of function/delegate/(infer) + tded = NULL; + scope = NULL; } Expression *FuncExp::syntaxCopy() @@ -5084,8 +5068,37 @@ Expression *FuncExp::semantic(Scope *sc) #if LOGSEMANTIC printf("FuncExp::semantic(%s)\n", toChars()); #endif - if (!type) + if (!type || type == Type::tvoid) { + // save for later use + scope = sc; + + //printf("td = %p, tded = %p\n", td, tded); + if (td) + { + assert(td->parameters && td->parameters->dim); + td->semantic(sc); + + if (!tded) + { // defer type determination + type = Type::tvoid; // temporary type + return this; + } + else + { + Expression *e = inferType(sc, tded); + if (e) + { e = e->castTo(sc, tded); + e = e->semantic(sc); + } + if (!e) + { error("cannot infer function literal type"); + e = new ErrorExp(); + } + return e; + } + } + unsigned olderrors = global.errors; fd->semantic(sc); //fd->parent = sc->parent; @@ -5111,7 +5124,8 @@ Expression *FuncExp::semantic(Scope *sc) ((TypeFunction *)fd->type)->next = Type::terror; // Type is a "delegate to" or "pointer to" the function literal - if (fd->isNested()) + if ((fd->isNested() && fd->tok == TOKdelegate) || + (tok == TOKreserved && tded && tded->ty == Tdelegate)) { type = new TypeDelegate(fd->type); type = type->semantic(loc, sc); @@ -5125,6 +5139,132 @@ Expression *FuncExp::semantic(Scope *sc) return this; } +// used from CallExp::semantic() +Expression *FuncExp::semantic(Scope *sc, Expressions *arguments) +{ + assert(!tded); + assert(!scope); + + if ((!type || type == Type::tvoid) && td && arguments && arguments->dim) + { + for (size_t k = 0; k < arguments->dim; k++) + { Expression *checkarg = arguments->tdata()[k]; + if (checkarg->op == TOKerror) + return checkarg; + } + + assert(td->parameters && td->parameters->dim); + td->semantic(sc); + + TypeFunction *tfl = (TypeFunction *)fd->type; + size_t dim = Parameter::dim(tfl->parameters); + + if ((!tfl->varargs && arguments->dim == dim) || + ( tfl->varargs && arguments->dim >= dim)) + { + Objects *tiargs = new Objects(); + tiargs->reserve(td->parameters->dim); + + for (size_t i = 0; i < td->parameters->dim; i++) + { + TemplateParameter *tp = (*td->parameters)[i]; + for (size_t u = 0; u < dim; u++) + { Parameter *p = Parameter::getNth(tfl->parameters, u); + if (p->type->ty == Tident && + ((TypeIdentifier *)p->type)->ident == tp->ident) + { Expression *e = (*arguments)[u]; + tiargs->push(e->type); + u = dim; // break inner loop + } + } + } + + TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); + return (new ScopeExp(loc, ti))->semantic(sc); + } + error("cannot infer function literal type"); + return new ErrorExp(); + } + return semantic(sc); +} + +Expression *FuncExp::inferType(Scope *sc, Type *to) +{ + //printf("inferType sc = %p, to = %s\n", sc, to->toChars()); + if (!sc) + { // used from TypeFunction::callMatch() + assert(scope); + sc = scope; + } + + Expression *e = NULL; + if (td) + { /// Parameter types inference from + assert(!type || type == Type::tvoid); + Type *t = to; + if (t->ty == Tdelegate || + t->ty == Tpointer && t->nextOf()->ty == Tfunction) + { t = t->nextOf(); + } + if (t->ty == Tfunction) + { + TypeFunction *tfv = (TypeFunction *)t; + TypeFunction *tfl = (TypeFunction *)fd->type; + size_t dim = Parameter::dim(tfl->parameters); + + if (Parameter::dim(tfv->parameters) == dim && + tfv->varargs == tfl->varargs) + { + Objects *tiargs = new Objects(); + tiargs->reserve(td->parameters->dim); + + for (size_t i = 0; i < td->parameters->dim; i++) + { + TemplateParameter *tp = (*td->parameters)[i]; + for (size_t u = 0; u < dim; u++) + { Parameter *p = Parameter::getNth(tfl->parameters, u); + if (p->type->ty == Tident && + ((TypeIdentifier *)p->type)->ident == tp->ident) + { p = Parameter::getNth(tfv->parameters, u); + if (p->type->ty == Tident) + return NULL; + tiargs->push(p->type); + u = dim; // break inner loop + } + } + } + + TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); + e = (new ScopeExp(loc, ti))->semantic(sc); + } + } + } + else + { + assert(type && type != Type::tvoid); // semantic is already done + e = this; + } + + if (e) + { // Check implicit function to delegate conversion + if (e->implicitConvTo(to)) + e = e->castTo(sc, to); + else + e = NULL; + } + return e; +} + +void FuncExp::setType(Type *t) +{ + assert(t); + + if (t->ty == Tdelegate || + t->ty == Tpointer && t->nextOf()->ty == Tfunction) + { tded = t; + } +} + char *FuncExp::toChars() { return fd->toChars(); @@ -5188,7 +5328,9 @@ Expression *DeclarationExp::semantic(Scope *sc) if (s->ident) { if (!sc->insert(s)) - error("declaration %s is already defined", s->toPrettyChars()); + { error("declaration %s is already defined", s->toPrettyChars()); + return new ErrorExp(); + } else if (sc->func) { VarDeclaration *v = s->isVarDeclaration(); if ( (s->isFuncDeclaration() || s->isTypedefDeclaration() || @@ -5198,6 +5340,7 @@ Expression *DeclarationExp::semantic(Scope *sc) { error("declaration %s is already defined in another scope in %s", s->toPrettyChars(), sc->func->toChars()); + return new ErrorExp(); } else if (!global.params.useDeprecated) { // Disallow shadowing @@ -5210,6 +5353,7 @@ Expression *DeclarationExp::semantic(Scope *sc) s != s2) { error("shadowing declaration %s is deprecated", s->toPrettyChars()); + return new ErrorExp(); } } } @@ -5242,95 +5386,6 @@ Expression *DeclarationExp::semantic(Scope *sc) return this; } -int DeclarationExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -/************************************** - * Does symbol, when initialized, throw? - * Mirrors logic in Dsymbol_toElem(). - */ - -int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) -{ - AttribDeclaration *ad; - VarDeclaration *vd; - TemplateMixin *tm; - TupleDeclaration *td; - - //printf("Dsymbol_toElem() %s\n", s->toChars()); - ad = s->isAttribDeclaration(); - if (ad) - { - Dsymbols *decl = ad->include(NULL, NULL); - if (decl && decl->dim) - { - for (size_t i = 0; i < decl->dim; i++) - { - s = decl->tdata()[i]; - if (Dsymbol_canThrow(s, mustNotThrow)) - return 1; - } - } - } - else if ((vd = s->isVarDeclaration()) != NULL) - { - s = s->toAlias(); - if (s != vd) - return Dsymbol_canThrow(s, mustNotThrow); - if (vd->storage_class & STCmanifest) - ; - else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared)) - ; - else - { - if (vd->init) - { ExpInitializer *ie = vd->init->isExpInitializer(); - if (ie && ie->exp->canThrow(mustNotThrow)) - return 1; - } - if (vd->edtor && !vd->noscope) - return vd->edtor->canThrow(mustNotThrow); - } - } - else if ((tm = s->isTemplateMixin()) != NULL) - { - //printf("%s\n", tm->toChars()); - if (tm->members) - { - for (size_t i = 0; i < tm->members->dim; i++) - { - Dsymbol *sm = tm->members->tdata()[i]; - if (Dsymbol_canThrow(sm, mustNotThrow)) - return 1; - } - } - } - else if ((td = s->isTupleDeclaration()) != NULL) - { - for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = td->objects->tdata()[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *eo = (Expression *)o; - if (eo->op == TOKdsymbol) - { DsymbolExp *se = (DsymbolExp *)eo; - if (Dsymbol_canThrow(se->s, mustNotThrow)) - return 1; - } - } - } - } - return 0; -} - - -int DeclarationExp::canThrow(bool mustNotThrow) -{ - return Dsymbol_canThrow(declaration, mustNotThrow); -} -#endif void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { @@ -5471,10 +5526,6 @@ Expression *HaltExp::semantic(Scope *sc) return this; } -int HaltExp::checkSideEffect(int flag) -{ - return 1; -} void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { @@ -5723,17 +5774,13 @@ Expression *IsExp::semantic(Scope *sc) /* Declare trailing parameters */ for (size_t i = 1; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[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 - Type *o = dedtypes.tdata()[i]; - Dsymbol *s = TemplateDeclaration::declareParameter(loc, sc, tp, o); -#endif if (sc->sd) s->addMember(sc, sc->sd, 1); else if (!sc->insert(s)) @@ -5776,9 +5823,17 @@ 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); - if (!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); @@ -5849,13 +5904,6 @@ Expression *UnaExp::semantic(Scope *sc) return this; } -#if DMDV2 -int UnaExp::canThrow(bool mustNotThrow) -{ - return e1->canThrow(mustNotThrow); -} -#endif - Expression *UnaExp::resolveLoc(Loc loc, Scope *sc) { e1 = e1->resolveLoc(loc, sc); @@ -5892,18 +5940,7 @@ Expression *BinExp::semantic(Scope *sc) printf("BinExp::semantic('%s')\n", toChars()); #endif e1 = e1->semantic(sc); - if (!e1->type && - !(op == TOKassign && e1->op == TOKdottd)) // a.template = e2 - { - error("%s has no value", e1->toChars()); - return new ErrorExp(); - } e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - return new ErrorExp(); - } if (e1->op == TOKerror || e2->op == TOKerror) return new ErrorExp(); return this; @@ -5917,31 +5954,6 @@ Expression *BinExp::semanticp(Scope *sc) return this; } -int BinExp::checkSideEffect(int flag) -{ - if (op == TOKplusplus || - op == TOKminusminus || - op == TOKassign || - op == TOKconstruct || - op == TOKblit || - op == TOKaddass || - op == TOKminass || - op == TOKcatass || - op == TOKmulass || - op == TOKdivass || - op == TOKmodass || - op == TOKshlass || - op == TOKshrass || - op == TOKushrass || - op == TOKandass || - op == TOKorass || - op == TOKxorass || - op == TOKpowass || - op == TOKin || - op == TOKremove) - return 1; - return Expression::checkSideEffect(flag); -} // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary void BinExp::checkComplexMulAssign() @@ -5997,21 +6009,17 @@ int BinExp::isunsigned() return e1->type->isunsigned() || e2->type->isunsigned(); } -#if DMDV2 -int BinExp::canThrow(bool mustNotThrow) -{ - return e1->canThrow(mustNotThrow) || e2->canThrow(mustNotThrow); -} -#endif - -void BinExp::incompatibleTypes() +Expression *BinExp::incompatibleTypes() { if (e1->type->toBasetype() != Type::terror && e2->type->toBasetype() != Type::terror ) - error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", + { error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", e1->toChars(), Token::toChars(op), e2->toChars(), e1->type->toChars(), e2->type->toChars()); + return new ErrorExp(); + } + return this; } /********************** BinAssignExp **************************************/ @@ -6053,9 +6061,14 @@ Expression *BinAssignExp::commonSemanticAssign(Scope *sc) e1->checkArithmetic(); e2->checkArithmetic(); - if (op == TOKmodass && e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new ErrorExp(); + if (op == TOKmodass) + { + if (e2->type->iscomplex()) + { error("cannot perform modulo complex arithmetic"); + return new ErrorExp(); + } + else if (type->toBasetype()->ty == Tvector) + return incompatibleTypes(); } } return this; @@ -6315,20 +6328,6 @@ Expression *AssertExp::semantic(Scope *sc) return this; } -int AssertExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int AssertExp::canThrow(bool mustNotThrow) -{ - /* assert()s are non-recoverable errors, so functions that - * use them can be considered "nothrow" - */ - return 0; //(global.params.useAssert != 0); -} -#endif void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { @@ -6504,6 +6503,12 @@ Expression *DotIdExp::semantic(Scope *sc, int flag) (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); @@ -6725,6 +6730,7 @@ Expression *DotVarExp::semantic(Scope *sc) * tuple(e1.a, e1.b, e1.c) */ Expressions *exps = new Expressions; + Expression *ev = e1; exps->reserve(tup->objects->dim); for (size_t i = 0; i < tup->objects->dim; i++) @@ -6734,20 +6740,29 @@ Expression *DotVarExp::semantic(Scope *sc) error("%s is not an expression", o->toChars()); goto Lerr; } - else - { - Expression *e = (Expression *)o; - if (e->op != TOKdsymbol) - { error("%s is not a member", e->toChars()); - goto Lerr; - } - else - { DsymbolExp *ve = (DsymbolExp *)e; - e = new DotVarExp(loc, e1, ve->s->isDeclaration()); - exps->push(e); - } + Expression *e = (Expression *)o; + if (e->op != TOKdsymbol) + { error("%s is not a member", e->toChars()); + goto Lerr; } + + Dsymbol *s = ((DsymbolExp *)e)->s; + if (i == 0 && sc->func && tup->objects->dim > 1 && + e1->hasSideEffect()) + { + Identifier *id = Lexer::uniqueId("__tup"); + ExpInitializer *ei = new ExpInitializer(e1->loc, e1); + VarDeclaration *v = new VarDeclaration(e1->loc, NULL, id, ei); + v->storage_class |= STCctfe | STCref | STCforeach; + + ev = new VarExp(e->loc, v); + e = new CommaExp(e1->loc, new DeclarationExp(e1->loc, v), ev); + e = new DotVarExp(loc, e, s->isDeclaration()); + } + else + e = new DotVarExp(loc, ev, s->isDeclaration()); + exps->push(e); } Expression *e = new TupleExp(loc, exps); e = e->semantic(sc); @@ -6963,8 +6978,8 @@ L1: ti->tempdecl = td; if (ti->needsTypeInference(sc)) { - e = new CallExp(loc, this); - return e->semantic(sc); + e1 = eleft; // save result of semantic() + return this; } else ti->semantic(sc); @@ -7231,7 +7246,8 @@ Lagain: Expression *key = arguments->tdata()[0]; key = key->semantic(sc); key = resolveProperties(sc, key); - key->rvalue(); + if (!key->rvalue()) + return new ErrorExp(); TypeAArray *taa = (TypeAArray *)tthis; key = key->implicitCastTo(sc, taa->index); @@ -7277,9 +7293,9 @@ Lshift: * array.foo!(tiargs)(args) into .foo!(tiargs)(array,args) */ #if DMDV2 - e1 = new DotExp(dotti->loc, + e1 = new DotTemplateInstanceExp(dotti->loc, new IdentifierExp(dotti->loc, Id::empty), - new ScopeExp(dotti->loc, dotti->ti)); + dotti->ti->name, dotti->ti->tiargs); #else e1 = new ScopeExp(dotti->loc, dotti->ti); #endif @@ -7313,6 +7329,18 @@ Expression *CallExp::semantic(Scope *sc) } #endif + if (e1->op == TOKcomma) + { /* Rewrite (a,b)(args) as (a,(b(args))) + */ + CommaExp *ce = (CommaExp *)e1; + + e1 = ce->e2; + e1->type = ce->type; + ce->e2 = this; + ce->type = NULL; + return ce->semantic(sc); + } + if (e1->op == TOKdelegate) { DelegateExp *de = (DelegateExp *)e1; @@ -7320,6 +7348,16 @@ Expression *CallExp::semantic(Scope *sc) return semantic(sc); } + if (e1->op == TOKfunction) + { FuncExp *fe = (FuncExp *)e1; + + arguments = arrayExpressionSemantic(arguments, sc); + preFunctionParameters(loc, sc, arguments); + e1 = fe->semantic(sc, arguments); + if (e1->op == TOKerror) + return e1; + } + Expression *e = resolveUFCS(sc); if (e) return e; @@ -7420,8 +7458,17 @@ 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 */ @@ -7443,6 +7490,12 @@ Lagain: e1 = new DsymbolExp(loc, se->sds); e1 = e1->semantic(sc); } + else if (e1->op == TOKsymoff && ((SymOffExp *)e1)->hasOverloads) + { + SymOffExp *se = (SymOffExp *)e1; + e1 = new VarExp(se->loc, se->var, 1); + e1 = e1->semantic(sc); + } #if 1 // patch for #540 by Oskar Linde else if (e1->op == TOKdotexp) { @@ -7469,18 +7522,6 @@ Lagain: #endif } - if (e1->op == TOKcomma) - { /* Rewrite (a,b)(args) as (a,(b(args))) - */ - CommaExp *ce = (CommaExp *)e1; - - e1 = ce->e2; - e1->type = ce->type; - ce->e2 = this; - ce->type = NULL; - return ce->semantic(sc); - } - t1 = NULL; if (e1->type) t1 = e1->type->toBasetype(); @@ -7551,7 +7592,6 @@ Lagain: } arguments = arrayExpressionSemantic(arguments, sc); - preFunctionParameters(loc, sc, arguments); // If there was an error processing any argument, or the call, @@ -7594,9 +7634,7 @@ Lagain: arguments = new Expressions(); f = td->deduceFunctionTemplate(sc, loc, targsi, ue->e1, arguments); if (!f) - { type = Type::terror; - return this; - } + return new ErrorExp(); ad = td->toParent()->isAggregateDeclaration(); } if (f->needThis()) @@ -7626,7 +7664,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 @@ -7909,6 +7950,7 @@ Lagain: checkPurity(sc, f); checkSafety(sc, f); #endif + f->checkNestedReference(sc, loc); if (f->needThis() && hasThis(sc)) { @@ -7936,7 +7978,10 @@ Lcheckargs: if (!arguments) arguments = new Expressions(); + int olderrors = global.errors; type = functionParameters(loc, sc, tf, ethis, arguments, f); + if (olderrors != global.errors) + return new ErrorExp(); if (!type) { @@ -7960,77 +8005,6 @@ Lcheckargs: return this; } -int CallExp::checkSideEffect(int flag) -{ -#if DMDV2 - int result = 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 = arguments->tdata()[i]; - - result |= e->checkSideEffect(1); - } - - return result; -#else - return 1; -#endif -} - -#if DMDV2 -int CallExp::canThrow(bool mustNotThrow) -{ - //printf("CallExp::canThrow() %s\n", toChars()); - if (e1->canThrow(mustNotThrow)) - return 1; - - /* If any of the arguments can throw, then this expression can throw - */ - if (arrayExpressionCanThrow(arguments, mustNotThrow)) - return 1; - - if (global.errors && !e1->type) - return 0; // error recovery - - /* If calling a function or delegate that is typed as nothrow, - * then this expression cannot throw. - * Note that pure functions can throw. - */ - Type *t = e1->type->toBasetype(); - if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) - return 0; - if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) - return 0; - if (mustNotThrow) - error("%s is not nothrow", e1->toChars()); - return 1; -} -#endif #if DMDV2 int CallExp::isLvalue() @@ -8283,7 +8257,8 @@ Expression *PtrExp::semantic(Scope *sc) case Terror: return new ErrorExp(); } - rvalue(); + if (!rvalue()) + return new ErrorExp(); } return this; } @@ -8570,10 +8545,6 @@ Expression *DeleteExp::semantic(Scope *sc) return this; } -int DeleteExp::checkSideEffect(int flag) -{ - return 1; -} Expression *DeleteExp::checkToBoolean(Scope *sc) { @@ -8621,8 +8592,7 @@ Expression *CastExp::syntaxCopy() Expression *CastExp::semantic(Scope *sc) -{ Expression *e; - +{ #if LOGSEMANTIC printf("CastExp::semantic('%s')\n", toChars()); #endif @@ -8647,7 +8617,14 @@ Expression *CastExp::semantic(Scope *sc) if (!to->equals(e1->type)) { - e = op_overload(sc); +#if 0 // attempt at fixing 6720 + if (e1->type->ty == Tvoid) + { + error("cannot cast from void to %s", to->toChars()); + return new ErrorExp(); + } +#endif + Expression *e = op_overload(sc); if (e) { return e->implicitCastTo(sc, to); @@ -8662,6 +8639,27 @@ Expression *CastExp::semantic(Scope *sc) Type *t1b = e1->type->toBasetype(); Type *tob = to->toBasetype(); + + if (e1->op == TOKfunction && + (tob->ty == Tdelegate || tob->ty == Tpointer && tob->nextOf()->ty == Tfunction)) + { + FuncExp *fe = (FuncExp *)e1; + Expression *e = NULL; + if (e1->type == Type::tvoid) + { + e = fe->inferType(sc, tob); + } + else if (e1->type->ty == Tpointer && e1->type->nextOf()->ty == Tfunction && + fe->tok == TOKreserved && + tob->ty == Tdelegate) + { + if (fe->implicitConvTo(tob)) + e = fe->castTo(sc, tob); + } + if (e) + e1 = e->semantic(sc); + } + if (tob->ty == Tstruct && !tob->equals(t1b) ) @@ -8673,7 +8671,7 @@ Expression *CastExp::semantic(Scope *sc) */ // Rewrite as to.call(e1) - e = new TypeExp(loc, to); + Expression *e = new TypeExp(loc, to); e = new CallExp(loc, e, e1); e = e->trySemantic(sc); if (e) @@ -8693,6 +8691,12 @@ Expression *CastExp::semantic(Scope *sc) return new ErrorExp(); } } + + // Look for casting to a vector type + if (tob->ty == Tvector && t1b->ty != Tvector) + { + return new VectorExp(loc, e1, to); + } } else if (!to) { error("cannot cast tuple"); @@ -8766,21 +8770,10 @@ Expression *CastExp::semantic(Scope *sc) } Lsafe: - e = e1->castTo(sc, to); + Expression *e = e1->castTo(sc, to); return e; } -int CastExp::checkSideEffect(int flag) -{ - /* if not: - * cast(void) - * cast(classtype)func() - */ - if (!to->equals(Type::tvoid) && - !(to->ty == Tclass && e1->op == TOKcall && e1->type->ty == Tclass)) - return Expression::checkSideEffect(flag); - return 1; -} void CastExp::checkEscape() { Type *tb = type->toBasetype(); @@ -8830,6 +8823,49 @@ void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) /************************************************************/ +VectorExp::VectorExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKvector, sizeof(VectorExp), e) +{ + assert(t->ty == Tvector); + to = t; + dim = ~0; +} + +Expression *VectorExp::syntaxCopy() +{ + return new VectorExp(loc, e1->syntaxCopy(), to->syntaxCopy()); +} + +Expression *VectorExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("VectorExp::semantic('%s')\n", toChars()); +#endif + + if (type) + return this; + e1 = e1->semantic(sc); + type = to->semantic(loc, sc); + if (e1->op == TOKerror || type->ty == Terror) + return e1; + Type *tb = type->toBasetype(); + assert(tb->ty == Tvector); + TypeVector *tv = (TypeVector *)tb; + Type *te = tv->elementType(); + dim = tv->size(loc) / te->size(loc); + return this; +} + +void VectorExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("cast("); + to->toCBuffer(buf, NULL, hgs); + buf->writeByte(')'); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + +/************************************************************/ + SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) { @@ -8993,6 +9029,12 @@ Lagain: { Expression *e = (*te->exps)[j1 + i]; (*exps)[i] = e; } + if (j1 > 0 && j2 - j1 > 0 && sc->func && (*te->exps)[0]->op == TOKdotvar) + { + Expression *einit = ((DotVarExp *)(*te->exps)[0])->e1->isTemp(); + if (einit) + ((DotVarExp *)(*exps)[0])->e1 = einit; + } e = new TupleExp(loc, exps); } else @@ -9087,13 +9129,6 @@ void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writeByte(']'); } -int SliceExp::canThrow(bool mustNotThrow) -{ - return UnaExp::canThrow(mustNotThrow) - || (lwr != NULL && lwr->canThrow(mustNotThrow)) - || (upr != NULL && upr->canThrow(mustNotThrow)); -} - /********************** ArrayLength **************************************/ ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) @@ -9342,31 +9377,6 @@ int CommaExp::isBool(int result) return e2->isBool(result); } -int CommaExp::checkSideEffect(int flag) -{ - /* Check for compiler-generated code of the form auto __tmp, e, __tmp; - * In such cases, only check e for side effect (it's OK for __tmp to have - * no side effect). - * See Bugzilla 4231 for discussion - */ - CommaExp* firstComma = this; - while (firstComma->e1->op == TOKcomma) - firstComma = (CommaExp *)firstComma->e1; - if (firstComma->e1->op == TOKdeclaration && - e2->op == TOKvar && - ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)e2)->var) - { - return e1->checkSideEffect(flag); - } - - if (flag == 2) - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - else - { - // Don't check e1 until we cast(void) the a,b code generation - return e2->checkSideEffect(flag); - } -} Expression *CommaExp::addDtorHook(Scope *sc) { @@ -9416,16 +9426,11 @@ Expression *IndexExp::semantic(Scope *sc) } e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - goto Lerr; - } - if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix - e2 = ((TupleExp *)e2)->exps->tdata()[0]; e2 = resolveProperties(sc, e2); if (e2->type == Type::terror) goto Lerr; + if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix + e2 = ((TupleExp *)e2)->exps->tdata()[0]; if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) sc = sc->pop(); @@ -9498,7 +9503,15 @@ Expression *IndexExp::semantic(Scope *sc) { if (e1->op == TOKtuple) + { e = (*te->exps)[(size_t)index]; + if (sc->func && (*te->exps)[0]->op == TOKdotvar) + { + Expression *einit = ((DotVarExp *)(*te->exps)[0])->e1->isTemp(); + if (einit) + ((DotVarExp *)e)->e1 = einit; + } + } else e = new TypeExp(e1->loc, Parameter::getNth(tup->arguments, (size_t)index)->type); } @@ -9862,18 +9875,118 @@ Expression *AssignExp::semantic(Scope *sc) } } + { Expression *e = BinExp::semantic(sc); if (e->op == TOKerror) return e; - - if (e1->op == TOKdottd) - { // Rewrite a.b=e2, when b is a template, as a.b(e2) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; } e2 = resolveProperties(sc, e2); + + /* We have f = value. + * Could mean: + * f(value) + * or: + * f() = value + */ + TemplateDeclaration *td; + Objects *targsi; + FuncDeclaration *fd; + Expression *ethis; + if (e1->op == TOKdotti) + { + DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1; + td = dti->getTempdecl(sc); + dti->ti->semanticTiargs(sc); + targsi = dti->ti->tiargs; + ethis = dti->e1; + goto L3; + } + else if (e1->op == TOKdottd) + { + DotTemplateExp *dte = (DotTemplateExp *)e1; + td = dte->td; + targsi = NULL; + ethis = dte->e1; + goto L3; + } + else if (e1->op == TOKtemplate) + { + td = ((TemplateExp *)e1)->td; + targsi = NULL; + ethis = NULL; + L3: + { + assert(td); + Expressions a; + a.push(e2); + + fd = td->deduceFunctionTemplate(sc, loc, targsi, ethis, &a, 1); + if (fd && fd->type) + goto Lsetter; + + fd = td->deduceFunctionTemplate(sc, loc, targsi, ethis, NULL, 1); + if (fd && fd->type) + goto Lgetter; + } + goto Leprop; + } + else if (e1->op == TOKdotvar && e1->type->toBasetype()->ty == Tfunction) + { + DotVarExp *dve = (DotVarExp *)e1; + fd = dve->var->isFuncDeclaration(); + ethis = dve->e1; + goto L4; + } + else if (e1->op == TOKvar && e1->type->toBasetype()->ty == Tfunction) + { + fd = ((VarExp *)e1)->var->isFuncDeclaration(); + ethis = NULL; + L4: + { + assert(fd); + FuncDeclaration *f = fd; + Expressions a; + a.push(e2); + + fd = f->overloadResolve(loc, ethis, &a, 1); + if (fd && fd->type) + goto Lsetter; + + fd = f->overloadResolve(loc, ethis, NULL, 1); + if (fd && fd->type) + goto Lgetter; + + goto Leprop; + } + + Expression *e; + TypeFunction *tf; + + Lsetter: + assert(fd->type->ty == Tfunction); + tf = (TypeFunction *)fd->type; + if (!tf->isproperty && global.params.enforcePropertySyntax) + goto Leprop; + e = new CallExp(loc, e1, e2); + return e->semantic(sc); + + Lgetter: + assert(fd->type->ty == Tfunction); + tf = (TypeFunction *)fd->type; + if (!tf->isref) + goto Leprop; + if (!tf->isproperty && global.params.enforcePropertySyntax) + goto Leprop; + e = new CallExp(loc, e1); + e = new AssignExp(loc, e, e2); + return e->semantic(sc); + + Leprop: + ::error(e1->loc, "not a property %s", e1->toChars()); + return new ErrorExp(); + } + assert(e1->type); /* Rewrite tuple assignment as a tuple of assignments. @@ -9959,25 +10072,24 @@ Ltupleassign: Type *t1 = e1->type->toBasetype(); - if (t1->ty == Tfunction) - { /* We have f=value. - * Could mean: - * f() = value - * or: - * f(value) - */ - TypeFunction *tf = (TypeFunction *)t1; - if (tf->isref) + if (t1->ty == Tdelegate || (t1->ty == Tpointer && t1->nextOf()->ty == Tfunction) + && e2->op == TOKfunction) + { + FuncExp *fe = (FuncExp *)e2; + if (e2->type == Type::tvoid) { - // Rewrite e1 = e2 to e1() = e2 - e1 = resolveProperties(sc, e1); + e2 = fe->inferType(sc, t1); } - else + else if (e2->type->ty == Tpointer && e2->type->nextOf()->ty == Tfunction && + fe->tok == TOKreserved && + t1->ty == Tdelegate) { - // Rewrite f=value to f(value) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; + if (fe->implicitConvTo(t1)) + e2 = fe->castTo(sc, t1); + } + if (!e2) + { error("cannot infer function literal type from %s", t1->toChars()); + e2 = new ErrorExp(); } } @@ -10122,7 +10234,8 @@ Ltupleassign: } } - e2->rvalue(); + if (!e2->rvalue()) + return new ErrorExp(); if (e1->op == TOKarraylength) { @@ -10149,7 +10262,17 @@ Ltupleassign: e1 = e1->modifiableLvalue(sc, e1old); } - Type *t2 = e2->type; + Type *t2 = e2->type->toBasetype(); +#if 0 + if (t1->ty == Tvector && t2->ty != Tvector && + e2->implicitConvTo(((TypeVector *)t1)->basetype->nextOf()) + ) + { // memset + ismemset = 1; // make it easy for back end to tell what this is + e2 = e2->implicitCastTo(sc, ((TypeVector *)t1)->basetype->nextOf()); + } + else +#endif if (e1->op == TOKslice && t1->nextOf() && e2->implicitConvTo(t1->nextOf()) @@ -10170,8 +10293,8 @@ Ltupleassign: } //error("cannot assign to static array %s", e1->toChars()); } - else if (e1->op == TOKslice && t2->toBasetype()->ty == Tarray && - t2->toBasetype()->nextOf()->implicitConvTo(t1->nextOf())) + else if (e1->op == TOKslice && t2->ty == Tarray && + t2->nextOf()->implicitConvTo(t1->nextOf())) { e2 = e2->implicitCastTo(sc, e1->type->constOf()); } @@ -10196,6 +10319,13 @@ Ltupleassign: 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; @@ -10422,7 +10552,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(); @@ -10510,11 +10641,9 @@ Expression *MulAssignExp::semantic(Scope *sc) e2->checkArithmetic(); checkComplexMulAssign(); if (e2->type->isfloating()) - { Type *t1; - Type *t2; - - t1 = e1->type; - t2 = e2->type; + { + Type *t1 = e1->type; + Type *t2 = e2->type; if (t1->isreal()) { if (t2->isimaginary() || t2->iscomplex()) @@ -10541,6 +10670,11 @@ Expression *MulAssignExp::semantic(Scope *sc) if (e2->type->iscomplex() && !type->iscomplex()) error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); } + else if (type->toBasetype()->ty == Tvector && + ((TypeVector *)type->toBasetype())->elementType()->size(loc) != 2) + { // Only short[8] and ushort[8] work with multiply + return incompatibleTypes(); + } return this; } @@ -10585,10 +10719,8 @@ Expression *DivAssignExp::semantic(Scope *sc) e2->checkArithmetic(); checkComplexMulAssign(); if (e2->type->isimaginary()) - { Type *t1; - Type *t2; - - t1 = e1->type; + { + Type *t1 = e1->type; if (t1->isreal()) { // x/iv = i(-x/v) // Therefore, the result is 0 @@ -10599,7 +10731,7 @@ Expression *DivAssignExp::semantic(Scope *sc) return e; } else if (t1->isimaginary()) - { Expression *e; + { Type *t2; switch (t1->ty) { @@ -10610,11 +10742,13 @@ Expression *DivAssignExp::semantic(Scope *sc) assert(0); } e2 = e2->castTo(sc, t2); - e = new AssignExp(loc, e1, e2); + Expression *e = new AssignExp(loc, e1, e2); e->type = t1; return e; } } + else if (type->toBasetype()->ty == Tvector && !e1->type->isfloating()) + return incompatibleTypes(); if (e2->type->iscomplex() && !type->iscomplex()) error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); @@ -10670,6 +10804,8 @@ Expression *ShlAssignExp::semantic(Scope *sc) e1->checkScalar(); e1->checkNoBool(); type = e1->type; + if (e1->type->toBasetype()->ty == Tvector || e2->type->toBasetype()->ty == Tvector) + return incompatibleTypes(); typeCombine(sc); e1->checkIntegral(); e2 = e2->checkIntegral(); @@ -10706,6 +10842,8 @@ Expression *ShrAssignExp::semantic(Scope *sc) e1->checkScalar(); e1->checkNoBool(); type = e1->type; + if (e1->type->toBasetype()->ty == Tvector || e2->type->toBasetype()->ty == Tvector) + return incompatibleTypes(); typeCombine(sc); e1->checkIntegral(); e2 = e2->checkIntegral(); @@ -10742,6 +10880,8 @@ Expression *UshrAssignExp::semantic(Scope *sc) e1->checkScalar(); e1->checkNoBool(); type = e1->type; + if (e1->type->toBasetype()->ty == Tvector || e2->type->toBasetype()->ty == Tvector) + return incompatibleTypes(); typeCombine(sc); e1->checkIntegral(); e2 = e2->checkIntegral(); @@ -10849,10 +10989,11 @@ Expression *PowAssignExp::semantic(Scope *sc) e = new CommaExp(loc, de, e); } e = e->semantic(sc); + if (e->type->toBasetype()->ty == Tvector) + return incompatibleTypes(); return e; } - incompatibleTypes(); - return new ErrorExp(); + return incompatibleTypes(); } @@ -10893,15 +11034,18 @@ Expression *AddExp::semantic(Scope *sc) e = scaleFactor(sc); else if (tb1->ty == Tpointer && tb2->ty == Tpointer) { - incompatibleTypes(); - type = e1->type; - e = this; + return incompatibleTypes(); } else { typeCombine(sc); - if ((e1->type->isreal() && e2->type->isimaginary()) || - (e1->type->isimaginary() && e2->type->isreal())) + Type *tb1 = e1->type->toBasetype(); + if (tb1->ty == Tvector && !tb1->isscalar()) + { + return incompatibleTypes(); + } + if ((tb1->isreal() && e2->type->isimaginary()) || + (tb1->isimaginary() && e2->type->isreal())) { switch (type->toBasetype()->ty) { @@ -10940,8 +11084,6 @@ MinExp::MinExp(Loc loc, Expression *e1, Expression *e2) Expression *MinExp::semantic(Scope *sc) { Expression *e; - Type *t1; - Type *t2; #if LOGSEMANTIC printf("MinExp::semantic('%s')\n", toChars()); @@ -10956,8 +11098,8 @@ Expression *MinExp::semantic(Scope *sc) return e; e = this; - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); if (t1->ty == Tpointer) { if (t2->ty == Tpointer) @@ -10998,6 +11140,10 @@ Expression *MinExp::semantic(Scope *sc) typeCombine(sc); t1 = e1->type->toBasetype(); t2 = e2->type->toBasetype(); + if (t1->ty == Tvector && !t1->isscalar()) + { + return incompatibleTypes(); + } if ((t1->isreal() && t2->isimaginary()) || (t1->isimaginary() && t2->isreal())) { @@ -11210,6 +11356,11 @@ Expression *MulExp::semantic(Scope *sc) type = t1; // t1 is complex } } + else if (type->toBasetype()->ty == Tvector && + ((TypeVector *)type->toBasetype())->elementType()->size(loc) != 2) + { // Only short[8] and ushort[8] work with multiply + return incompatibleTypes(); + } return this; } @@ -11277,6 +11428,10 @@ Expression *DivExp::semantic(Scope *sc) type = t1; // t1 is complex } } + else if (type->toBasetype()->ty == Tvector) + { incompatibleTypes(); + return new ErrorExp(); + } return this; } @@ -11303,6 +11458,10 @@ Expression *ModExp::semantic(Scope *sc) e1->checkArithmetic(); if (!e2->isArrayOperand()) e2->checkArithmetic(); + if (type->toBasetype()->ty == Tvector) + { incompatibleTypes(); + return new ErrorExp(); + } if (type->isfloating()) { type = e1->type; if (e2->type->iscomplex()) @@ -11313,6 +11472,8 @@ Expression *ModExp::semantic(Scope *sc) return this; } +/************************************************************/ + PowExp::PowExp(Loc loc, Expression *e1, Expression *e2) : BinExp(loc, TOKpow, sizeof(PowExp), e1, e2) { @@ -11425,8 +11586,7 @@ Expression *PowExp::semantic(Scope *sc) e = e->semantic(sc); return e; } - incompatibleTypes(); - return new ErrorExp(); + return incompatibleTypes(); } /************************************************************/ @@ -11447,6 +11607,9 @@ Expression *ShlExp::semantic(Scope *sc) return e; e1 = e1->checkIntegral(); e2 = e2->checkIntegral(); + if (e1->type->toBasetype()->ty == Tvector || + e2->type->toBasetype()->ty == Tvector) + return incompatibleTypes(); e1 = e1->integralPromotions(sc); //e2 = e2->castTo(sc, Type::tshiftcnt); e2 = e2->castTo(sc, e1->type); // LDC @@ -11472,6 +11635,9 @@ Expression *ShrExp::semantic(Scope *sc) return e; e1 = e1->checkIntegral(); e2 = e2->checkIntegral(); + if (e1->type->toBasetype()->ty == Tvector || + e2->type->toBasetype()->ty == Tvector) + return incompatibleTypes(); e1 = e1->integralPromotions(sc); //e2 = e2->castTo(sc, Type::tshiftcnt); e2 = e2->castTo(sc, e1->type); // LDC @@ -11497,6 +11663,9 @@ Expression *UshrExp::semantic(Scope *sc) return e; e1 = e1->checkIntegral(); e2 = e2->checkIntegral(); + if (e1->type->toBasetype()->ty == Tvector || + e2->type->toBasetype()->ty == Tvector) + return incompatibleTypes(); e1 = e1->integralPromotions(sc); //e2 = e2->castTo(sc, Type::tshiftcnt); e2 = e2->castTo(sc, e1->type); // LDC @@ -11668,17 +11837,6 @@ int OrOrExp::isBit() return TRUE; } -int OrOrExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - } - else - { e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} /************************************************************/ @@ -11743,18 +11901,6 @@ int AndAndExp::isBit() return TRUE; } -int AndAndExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - } - else - { - e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} /************************************************************/ @@ -11818,7 +11964,7 @@ int InExp::isBit() RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) { - type = Type::tvoid; + type = Type::tboolean; } void RemoveExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -11883,7 +12029,9 @@ Expression *CmpExp::semantic(Scope *sc) Expression *eb1 = e1; Expression *eb2 = e2; - typeCombine(sc); + e = typeCombine(sc); + if (e->op == TOKerror) + return e; #if 0 // For integer comparisons, ensure the combined type can hold both arguments. @@ -11937,9 +12085,11 @@ Expression *CmpExp::semantic(Scope *sc) e = new ErrorExp(); } #endif + else if (t1->ty == Tvector) + return incompatibleTypes(); else - { e1->rvalue(); - e2->rvalue(); + { if (!e1->rvalue() || !e2->rvalue()) + return new ErrorExp(); e = this; } //printf("CmpExp: %s, type = %s\n", e->toChars(), e->type->toChars()); @@ -12075,6 +12225,9 @@ Expression *EqualExp::semantic(Scope *sc) } e = typeCombine(sc); + if (e->op == TOKerror) + return e; + type = Type::tboolean; // Special handling for array comparisons @@ -12087,6 +12240,10 @@ Expression *EqualExp::semantic(Scope *sc) e2 = e2->castTo(sc, Type::tcomplex80); } } + + if (e1->type->toBasetype()->ty == Tvector) + return incompatibleTypes(); + return e; } @@ -12111,13 +12268,21 @@ Expression *IdentityExp::semantic(Scope *sc) BinExp::semanticp(sc); type = Type::tboolean; - typeCombine(sc); + + Expression *e = typeCombine(sc); + if (e->op == TOKerror) + return e; + if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) { // Cast both to complex e1 = e1->castTo(sc, Type::tcomplex80); e2 = e2->castTo(sc, Type::tcomplex80); } + + if (e1->type->toBasetype()->ty == Tvector) + return incompatibleTypes(); + return this; } @@ -12283,28 +12448,6 @@ Expression *CondExp::checkToBoolean(Scope *sc) return this; } -int CondExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return econd->checkSideEffect(2) || - e1->checkSideEffect(2) || - e2->checkSideEffect(2); - } - else - { - econd->checkSideEffect(1); - e1->checkSideEffect(flag); - return e2->checkSideEffect(flag); - } -} - -#if DMDV2 -int CondExp::canThrow(bool mustNotThrow) -{ - return econd->canThrow(mustNotThrow) || e1->canThrow(mustNotThrow) || e2->canThrow(mustNotThrow); -} -#endif void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { diff --git a/dmd2/expression.h b/dmd2/expression.h index 06c6447f..70c8981e 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -80,11 +80,12 @@ 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); Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Dsymbol *d); Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid); -void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module *from); void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); void expandTuples(Expressions *exps); @@ -119,6 +120,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); @@ -129,7 +131,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); @@ -169,7 +171,6 @@ struct Expression : Object Expression *isTemp(); Expression *toDelegate(Scope *sc, Type *t); - virtual void scanForNestedRef(Scope *sc); virtual Expression *optimize(int result); #define WANTflags 1 @@ -184,10 +185,12 @@ struct Expression : Object virtual int isConst(); virtual int isBool(int result); virtual int isBit(); - virtual int checkSideEffect(int flag); - virtual int canThrow(bool mustNotThrow); + bool hasSideEffect(); + void discardValue(); + void useValue(); + int canThrow(bool mustNotThrow); - virtual int inlineCost(InlineCostState *ics); + virtual int inlineCost3(InlineCostState *ics); virtual Expression *doInline(InlineDoState *ids); virtual Expression *inlineScan(InlineScanState *iss); Expression *inlineCopy(Scope *sc); @@ -364,9 +367,8 @@ struct ThisExp : Expression void toCBuffer(OutBuffer *buf, HdrGenState *hgs); int isLvalue(); 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); @@ -384,9 +386,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); }; @@ -396,6 +396,7 @@ struct NullExp : Expression unsigned char committed; // !=0 if type is committed NullExp(Loc loc, Type *t = NULL); + int equals(Object *o); Expression *semantic(Scope *sc); int isBool(int result); int isConst(); @@ -421,6 +422,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); @@ -440,6 +442,7 @@ struct StringExp : Expression int isBool(int result); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); unsigned charAt(size_t i); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toMangleBuffer(OutBuffer *buf); @@ -461,21 +464,18 @@ 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); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); Expression *castTo(Scope *sc, Type *t); #if IN_DMD elem *toElem(IRState *irs); #endif - int canThrow(bool mustNotThrow); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -487,25 +487,23 @@ 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 canThrow(bool mustNotThrow); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -522,26 +520,24 @@ 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 elem *toElem(IRState *irs); #endif - 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 canThrow(bool mustNotThrow); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -563,25 +559,24 @@ 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); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); - int canThrow(bool mustNotThrow); MATCH implicitConvTo(Type *t); - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -608,7 +603,7 @@ struct TypeExp : Expression TypeExp(Loc loc, Type *type); Expression *syntaxCopy(); Expression *semantic(Scope *sc); - void rvalue(); + int rvalue(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *optimize(int result); #if IN_DMD @@ -642,7 +637,7 @@ struct TemplateExp : Expression TemplateDeclaration *td; TemplateExp(Loc loc, TemplateDeclaration *td); - void rvalue(); + int rvalue(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); }; @@ -662,18 +657,16 @@ 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); #if IN_DMD elem *toElem(IRState *irs); #endif - int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - int canThrow(bool mustNotThrow); - //int inlineCost(InlineCostState *ics); + //int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); //Expression *inlineScan(InlineScanState *iss); @@ -694,10 +687,9 @@ 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); - int canThrow(bool mustNotThrow); }; #if DMDV2 @@ -735,7 +727,6 @@ struct SymOffExp : SymbolExp Expression *doInline(InlineDoState *ids); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); #if IN_DMD dt_t **toDt(dt_t **pdt); @@ -766,9 +757,8 @@ struct VarExp : SymbolExp #if IN_DMD dt_t **toDt(dt_t **pdt); #endif - void scanForNestedRef(Scope *sc); - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); //Expression *inlineScan(InlineScanState *iss); @@ -797,12 +787,20 @@ struct OverExp : Expression struct FuncExp : Expression { FuncLiteralDeclaration *fd; + TemplateDeclaration *td; + enum TOK tok; + Type *tded; + Scope *scope; - FuncExp(Loc loc, FuncLiteralDeclaration *fd); + FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td = NULL); Expression *syntaxCopy(); Expression *semantic(Scope *sc); + Expression *semantic(Scope *sc, Expressions *arguments); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void scanForNestedRef(Scope *sc); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + Expression *inferType(Scope *sc, Type *t); + void setType(Type *t); char *toChars(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD @@ -810,7 +808,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); @@ -830,15 +828,12 @@ struct DeclarationExp : Expression Expression *syntaxCopy(); Expression *semantic(Scope *sc); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD elem *toElem(IRState *irs); #endif - void scanForNestedRef(Scope *sc); - int canThrow(bool mustNotThrow); - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -875,7 +870,6 @@ struct HaltExp : Expression HaltExp(Loc loc); Expression *semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int checkSideEffect(int flag); #if IN_DMD elem *toElem(IRState *irs); @@ -913,17 +907,15 @@ 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 canThrow(bool mustNotThrow); Expression *resolveLoc(Loc loc, Scope *sc); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -937,9 +929,9 @@ 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); - int checkSideEffect(int flag); void checkComplexMulAssign(); void checkComplexAddAssign(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -947,19 +939,16 @@ struct BinExp : Expression Expression *typeCombine(Scope *sc); Expression *optimize(int result); int isunsigned(); - void incompatibleTypes(); + Expression *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, Expression *(*fp)(TOK, Type *, Expression *, Expression *)); Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); - int canThrow(bool mustNotThrow); Expression *arrayOp(Scope *sc); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -1010,13 +999,11 @@ 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); - int canThrow(bool mustNotThrow); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -1098,7 +1085,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 @@ -1135,24 +1122,22 @@ struct CallExp : UnaExp CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *resolveUFCS(Scope *sc); Expression *semantic(Scope *sc); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void dump(int indent); #if IN_DMD elem *toElem(IRState *irs); #endif - void scanForNestedRef(Scope *sc); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); - int canThrow(bool mustNotThrow); Expression *addDtorHook(Scope *sc); MATCH implicitConvTo(Type *t); - int inlineCost(InlineCostState *ics); + int inlineCost3(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -1297,7 +1282,6 @@ struct DeleteExp : UnaExp DeleteExp(Loc loc, Expression *e); Expression *semantic(Scope *sc); Expression *checkToBoolean(Scope *sc); - int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD elem *toElem(IRState *irs); @@ -1322,7 +1306,6 @@ struct CastExp : UnaExp IntRange getIntRange(); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); void checkEscape(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void buildArrayIdent(OutBuffer *buf, Expressions *arguments); @@ -1342,6 +1325,19 @@ struct CastExp : UnaExp #endif }; +struct VectorExp : UnaExp +{ + Type *to; + unsigned dim; // number of elements in the vector + + VectorExp(Loc loc, Expression *e, Type *t); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif +}; struct SliceExp : UnaExp { @@ -1351,6 +1347,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(); @@ -1365,12 +1362,9 @@ 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(bool mustNotThrow); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -1408,17 +1402,16 @@ struct ArrayExp : UnaExp ArrayExp(Loc loc, Expression *e1, Expressions *arguments); Expression *syntaxCopy(); + int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); // For operator overloading Identifier *opId(); Expression *op_overload(Scope *sc); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); }; @@ -1443,7 +1436,6 @@ struct CommaExp : BinExp Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); int isBool(int result); - int checkSideEffect(int flag); MATCH implicitConvTo(Type *t); Expression *addDtorHook(Scope *sc); Expression *castTo(Scope *sc, Type *t); @@ -1473,7 +1465,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); @@ -1891,7 +1882,6 @@ struct OrOrExp : BinExp int isBit(); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); #if IN_DMD elem *toElem(IRState *irs); #endif @@ -1909,7 +1899,6 @@ struct AndAndExp : BinExp int isBit(); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int checkSideEffect(int flag); #if IN_DMD elem *toElem(IRState *irs); #endif @@ -2025,6 +2014,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); @@ -2034,14 +2024,10 @@ struct CondExp : BinExp Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); Expression *checkToBoolean(Scope *sc); - int checkSideEffect(int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); - int canThrow(bool mustNotThrow); - int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -2142,4 +2128,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/dmd2/func.c b/dmd2/func.c index 2ea7121d..2671023b 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -66,11 +66,12 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla vtblIndex = -1; hasReturnExp = 0; naked = 0; - inlineStatus = ILSuninitialized; + inlineStatusExp = ILSuninitialized; + inlineStatusStmt = ILSuninitialized; inlineNest = 0; - cantInterpret = 0; isArrayOp = 0; semanticRun = PASSinit; + semantic3Errors = 0; #if DMDV1 nestedFrameRef = 0; #endif @@ -152,6 +153,7 @@ void FuncDeclaration::semantic(Scope *sc) ClassDeclaration *cd; InterfaceDeclaration *id; Dsymbol *pd; + bool doesoverride; #if 0 printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); @@ -473,6 +475,7 @@ void FuncDeclaration::semantic(Scope *sc) vi = cd->baseClass ? findVtblIndex((Dsymbols*)&cd->baseClass->vtbl, cd->baseClass->vtbl.dim) : -1; + doesoverride = FALSE; switch (vi) { case -1: @@ -495,8 +498,9 @@ void FuncDeclaration::semantic(Scope *sc) if (isFinal()) { - if (isOverride()) - error("is marked as override, but does not override any function"); + // Don't check here, as it may override an interface function + //if (isOverride()) + //error("is marked as override, but does not override any function"); cd->vtblFinal.push(this); } else @@ -516,11 +520,12 @@ void FuncDeclaration::semantic(Scope *sc) return; default: - { FuncDeclaration *fdv = (FuncDeclaration *)cd->baseClass->vtbl.tdata()[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()); + doesoverride = TRUE; #if DMDV2 if (!isOverride()) warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); @@ -530,11 +535,16 @@ 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->parent->isClassDeclaration() && fdc->parent->isClassDeclaration()) + error("multiple overrides of same function"); + + // if (this is mixin) && (fdc is not mixin) then fdc overrides + else if (!this->parent->isClassDeclaration() && fdc->parent->isClassDeclaration()) break; - if (!this->parent->isClassDeclaration() + + else if (!this->parent->isClassDeclaration() // if both are mixins then error #if !BREAKABI && !isDtorDeclaration() #endif @@ -544,7 +554,7 @@ void FuncDeclaration::semantic(Scope *sc) ) error("multiple overrides of same function"); } - cd->vtbl.tdata()[vi] = this; + cd->vtbl[vi] = this; vtblIndex = vi; /* Remember which functions this overrides @@ -602,6 +612,14 @@ void FuncDeclaration::semantic(Scope *sc) */ foverrides.push(fdv); +#if DMDV2 + /* Should we really require 'override' when implementing + * an interface function? + */ + //if (!isOverride()) + //warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); +#endif + if (fdv->tintro) ti = fdv->tintro; else if (!type->equals(fdv->type)) @@ -640,7 +658,7 @@ void FuncDeclaration::semantic(Scope *sc) } } - if (introducing && isOverride()) + if (!doesoverride && isOverride()) { error("does not override any function"); } @@ -871,6 +889,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (semanticRun >= PASSsemantic3) return; semanticRun = PASSsemantic3; + semantic3Errors = 0; // LDC if (!global.params.useAvailableExternally) @@ -976,7 +995,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 core.vararg to use variadic functions"); + return; + } else { v_argsave = new VarDeclaration(loc, t, Id::va_argsave, NULL); @@ -1798,7 +1820,10 @@ 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); } @@ -1903,7 +1928,7 @@ int FuncDeclaration::equals(Object *o) 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(); @@ -1953,6 +1978,22 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf, Expressions *params) if (!params) params = fdrequireParams; + /* If a base function and its override both have an IN contract, then + * only one of them needs to succeed. This is done by generating: + * + * void derived.in() { + * try { + * base.in(); + * } + * catch () { + * ... body of derived.in() ... + * } + * } + * + * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid. + * If base.in() throws, then derived.in()'s body is executed. + */ + /* Implementing this is done by having the overriding function call * nested functions (the fdrequire functions) nested inside the overridden * function. This requires that the stack layout of the calling function's @@ -1997,6 +2038,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf, Expressions *params) Statement *s2 = new ExpStatement(loc, e); Catch *c = new Catch(loc, NULL, NULL, sf); + c->internalCatch = true; Catches *catches = new Catches(); catches->push(c); sf = new TryCatchStatement(loc, s2, catches); @@ -2548,7 +2590,7 @@ MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) { if (tf->mod != tg->mod) { - if (tg->mod == MODconst) + if (MODimplicitConv(tf->mod, tg->mod)) match = MATCHconst; else return MATCHnomatch; @@ -2695,7 +2737,7 @@ AggregateDeclaration *FuncDeclaration::isMember2() * >0 decrease nesting by number */ -int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) +int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd) { int level; Dsymbol *s; Dsymbol *fdparent; @@ -2732,7 +2774,9 @@ int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) return level; Lerr: - error(loc, "cannot access frame of function %s", fd->toPrettyChars()); + // Don't give error if in template constraint + if (!((sc->flags & SCOPEstaticif) && parent->isTemplateDeclaration())) + error(loc, "cannot access frame of function %s", fd->toPrettyChars()); return 1; } @@ -2812,21 +2856,37 @@ int FuncDeclaration::isImportedSymbol() int FuncDeclaration::isVirtual() { + Dsymbol *p = toParent(); #if 0 printf("FuncDeclaration::isVirtual(%s)\n", toChars()); printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); printf("result is %d\n", isMember() && !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration()); + p->isClassDeclaration() && + !(p->isInterfaceDeclaration() && isFinal())); #endif - Dsymbol *p = toParent(); return isMember() && !(isStatic() || protection == PROTprivate || protection == PROTpackage) && p->isClassDeclaration() && !(p->isInterfaceDeclaration() && isFinal()); } +// 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; @@ -3042,6 +3102,38 @@ const char *FuncDeclaration::kind() return "function"; } +void FuncDeclaration::checkNestedReference(Scope *sc, Loc loc) +{ + //printf("FuncDeclaration::checkNestedReference() %s\n", toChars()); + if (parent && parent != sc->parent && this->isNested() && + this->ident != Id::require && this->ident != Id::ensure) + { + // The function that this function is in + FuncDeclaration *fdv = toParent()->isFuncDeclaration(); + // The current function + FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); + + //printf("this = %s in [%s]\n", this->toChars(), this->loc.toChars()); + //printf("fdv = %s in [%s]\n", fdv->toChars(), fdv->loc.toChars()); + //printf("fdthis = %s in [%s]\n", fdthis->toChars(), fdthis->loc.toChars()); + + if (fdv && fdthis && fdv != fdthis) + { + int lv = fdthis->getLevel(loc, sc, fdv); + if (lv == -1) + return; // OK + if (lv == 0) + return; // OK + + // BUG: may need to walk up outer scopes like Declaration::checkNestedReference() does + + // function literal has reference to enclosing scope is delegate + if (FuncLiteralDeclaration *fld = fdthis->isFuncLiteralDeclaration()) + fld->tok = TOKdelegate; + } + } +} + /******************************* * Look at all the variables in this function that are referenced * by nested functions, and determine if a closure needs to be @@ -3117,6 +3209,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. @@ -3170,6 +3299,8 @@ FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, if (fes) id = "__foreachbody"; + else if (tok == TOKreserved) + id = "__lambda"; else if (tok == TOKdelegate) id = "__dgliteral"; else @@ -3198,7 +3329,7 @@ Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) int FuncLiteralDeclaration::isNested() { //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); - return (tok == TOKdelegate); + return (tok != TOKfunction); } int FuncLiteralDeclaration::isVirtual() @@ -3209,7 +3340,7 @@ int FuncLiteralDeclaration::isVirtual() const char *FuncLiteralDeclaration::kind() { // GCC requires the (char*) casts - return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; + return (tok != TOKfunction) ? (char*)"delegate" : (char*)"function"; } void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -3806,6 +3937,7 @@ void InvariantDeclaration::semantic(Scope *sc) sc = sc->push(); sc->stc &= ~STCstatic; // not a static invariant + sc->stc |= STCconst; // invariant() is always const sc->incontract++; sc->linkage = LINKd; diff --git a/dmd2/html.c b/dmd2/html.c index 155999b9..f7ea2adb 100644 --- a/dmd2/html.c +++ b/dmd2/html.c @@ -4,7 +4,7 @@ // 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. +// in artistic.txt, or the GNU General Public License in gpl.txt. // See the included readme.txt for details. @@ -18,11 +18,49 @@ #include #include -#include "mars.h" +#define MARS 1 #include "html.h" +#if MARS #include #include "root.h" +//#include "../mars/mars.h" +#else +#include "outbuf.h" +#include "msgs2.h" + +extern void html_err(const char *, unsigned, unsigned, ...); + +static char __file__[] = __FILE__; /* for tassert.h */ +#include "tassert.h" +#endif + +#if __GNUC__ +int memicmp(const char *s1, const char *s2, int n); +#if 0 +{ + int result = 0; + + for (int i = 0; i < n; i++) + { char c1 = s1[i]; + char c2 = s2[i]; + + result = c1 - c2; + if (result) + { + if ('A' <= c1 && c1 <= 'Z') + c1 += 'a' - 'A'; + if ('A' <= c2 && c2 <= 'Z') + c2 += 'a' - 'A'; + result = c1 - c2; + if (result) + break; + } + } + return result; +} +#endif +#endif extern int HtmlNamedEntity(unsigned char *p, int length); @@ -64,20 +102,21 @@ Html::Html(const char *sourcename, unsigned char *base, unsigned length) void Html::error(const char *format, ...) { - if (!global.gag) - { - printf("%s(%d) : HTML Error: ", sourcename, linnum); + printf("%s(%d) : HTML Error: ", sourcename, linnum); - va_list ap; - va_start(ap, format); - vprintf(format, ap); - va_end(ap); + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); - printf("\n"); - fflush(stdout); - } + printf("\n"); + fflush(stdout); - global.errors++; +//#if MARS +// global.errors++; +//#else + exit(EXIT_FAILURE); +//#endif } /********************************************** @@ -85,7 +124,11 @@ void Html::error(const char *format, ...) * concatenate it all together, and store in buf. */ +#if MARS void Html::extractCode(OutBuffer *buf) +#else +void Html::extractCode(Outbuffer *buf) +#endif { //printf("Html::extractCode()\n"); dbuf = buf; // save for other routines @@ -129,7 +172,11 @@ void Html::extractCode(OutBuffer *buf) int c; c = charEntity(); +#if MARS buf->writeUTF8(c); +#else + buf->writeByte(c); +#endif } else p++; @@ -156,7 +203,12 @@ void Html::extractCode(OutBuffer *buf) break; } buf->writeByte(0); // ending sentinel +#if SCPP + //printf("Code is: '%s'\n", buf->toString() + 3); +#endif +#if MARS //printf("D code is: '%s'\n", (char *)buf->data); +#endif } /*********************************************** @@ -530,7 +582,7 @@ void Html::scanCDATA() * right. */ linnum++; - dbuf->writeUTF8('\n'); + dbuf->writeByte('\n'); p += lineSepLength; continue; } diff --git a/dmd2/html.h b/dmd2/html.h index feceab38..9b5a548f 100644 --- a/dmd2/html.h +++ b/dmd2/html.h @@ -1,16 +1,18 @@ -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2009 by Digital Mars // All Rights Reserved // written by Walter Bright -// www.digitalmars.com +// 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. +// in artistic.txt, or the GNU General Public License in gpl.txt. // See the included readme.txt for details. -#ifndef DMD_HTML_H -#define DMD_HTML_H 1 +#if MARS struct OutBuffer; +#else +struct Outbuffer; +#endif struct Html { @@ -20,14 +22,22 @@ struct Html unsigned char *end; // past end of buffer unsigned char *p; // current character unsigned linnum; // current line number +#if MARS OutBuffer *dbuf; // code source buffer +#else + Outbuffer *dbuf; // code source buffer +#endif int inCode; // !=0 if in code Html(const char *sourcename, unsigned char *base, unsigned length); - void error(const char *format, ...) IS_PRINTF(2); + void error(const char *format, ...); +#if MARS void extractCode(OutBuffer *buf); +#else + void extractCode(Outbuffer *buf); +#endif void skipTag(); void skipString(); unsigned char *skipWhite(unsigned char *q); @@ -38,5 +48,3 @@ struct Html int charEntity(); static int namedEntity(unsigned char *p, int length); }; - -#endif diff --git a/dmd2/idgen.c b/dmd2/idgen.c index 10890311..da3dc4f3 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -53,6 +53,7 @@ Msgtable msgtable[] = { "length" }, { "remove" }, { "ptr" }, + { "array" }, { "funcptr" }, { "dollar", "__dollar" }, { "ctfe", "__ctfe" }, @@ -86,6 +87,7 @@ Msgtable msgtable[] = { "TypeInfo_Enum" }, { "TypeInfo_Typedef" }, { "TypeInfo_Pointer" }, + { "TypeInfo_Vector" }, { "TypeInfo_Array" }, { "TypeInfo_StaticArray" }, { "TypeInfo_AssociativeArray" }, @@ -236,19 +238,12 @@ Msgtable msgtable[] = { "apply", "opApply" }, { "applyReverse", "opApplyReverse" }, -#if 1 + // Ranges { "Fempty", "empty" }, - { "Fhead", "front" }, - { "Ftoe", "back" }, - { "Fnext", "popFront" }, - { "Fretreat", "popBack" }, -#else - { "Fempty", "empty" }, - { "Fhead", "head" }, - { "Ftoe", "toe" }, - { "Fnext", "next" }, - { "Fretreat", "retreat" }, -#endif + { "Ffront", "front" }, + { "Fback", "back" }, + { "FpopFront", "popFront" }, + { "FpopBack", "popBack" }, { "adDup", "_adDupT" }, { "adReverse", "_adReverse" }, @@ -341,6 +336,7 @@ Msgtable msgtable[] = { "isStaticArray" }, { "isUnsigned" }, { "isVirtualFunction" }, + { "isVirtualMethod" }, { "isAbstractFunction" }, { "isFinalFunction" }, { "isStaticFunction" }, @@ -353,6 +349,7 @@ Msgtable msgtable[] = { "getMember" }, { "getOverloads" }, { "getVirtualFunctions" }, + { "getVirtualMethods" }, { "classInstanceSize" }, { "allMembers" }, { "derivedMembers" }, diff --git a/dmd2/import.c b/dmd2/import.c index e3106cd8..b19f19f4 100644 --- a/dmd2/import.c +++ b/dmd2/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; @@ -37,12 +37,6 @@ Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *alias this->isstatic = isstatic; pkg = NULL; mod = NULL; - - if (aliasId) - this->ident = aliasId; - // Kludge to change Import identifier to first package - else if (packages && packages->dim) - this->ident = packages->tdata()[0]; } void Import::addAlias(Identifier *name, Identifier *alias) @@ -50,9 +44,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); } @@ -67,13 +58,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(names.tdata()[i], aliases.tdata()[i]); + si->addAlias(names[i], aliases[i]); } return si; @@ -141,15 +130,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); } } @@ -179,20 +165,17 @@ void Import::semantic(Scope *sc) //printf("%s imports %s\n", sc->module->toChars(), mod->toChars()); sc->module->aimports.push(mod); - if (!isstatic && !aliasId && !names.dim) + /* Default to private importing + */ + enum PROT prot = sc->protection; + if (!sc->explicitProtection) + prot = PROTprivate; + for (Scope *scd = sc; scd; scd = scd->enclosing) { - /* Default to private importing - */ - enum PROT prot = sc->protection; - if (!sc->explicitProtection) - prot = PROTprivate; - for (Scope *scd = sc; scd; scd = scd->enclosing) + if (scd->scopesym) { - if (scd->scopesym) - { - scd->scopesym->importScope(mod, prot); - break; - } + scd->scopesym->importScope(this, prot); + break; } } @@ -203,17 +186,12 @@ void Import::semantic(Scope *sc) sc->module->needmoduleinfo = 1; } - sc = sc->push(mod); - for (size_t i = 0; i < aliasdecls.dim; i++) - { Dsymbol *s = aliasdecls.tdata()[i]; - - //printf("\tImport alias semantic('%s')\n", s->toChars()); - if (!mod->search(loc, names.tdata()[i], 0)) - error("%s not found", (names.tdata()[i])->toChars()); - - s->semantic(sc); + if (aliasId) + { + AliasDeclaration *ad = new AliasDeclaration(loc, aliasId, mod); + sc->insert(ad); + ad->semantic(sc); } - sc = sc->pop(); } if (global.params.moduleDeps != NULL) @@ -247,7 +225,7 @@ void Import::semantic(Scope *sc) { for (size_t i = 0; i < packages->dim; i++) { - Identifier *pid = packages->tdata()[i]; + Identifier *pid = (*packages)[i]; ob->printf("%s.", pid->toChars()); } } @@ -267,8 +245,8 @@ void Import::semantic(Scope *sc) else ob->writebyte(','); - Identifier *name = names.tdata()[i]; - Identifier *alias = aliases.tdata()[i]; + Identifier *name = names[i]; + Identifier *alias = aliases[i]; if (!alias) { @@ -280,7 +258,7 @@ void Import::semantic(Scope *sc) } if (aliasId) - ob->printf(" -> %s", aliasId->toChars()); + ob->printf(" -> %s", aliasId->toChars()); ob->writenl(); } @@ -298,48 +276,6 @@ void Import::semantic2(Scope *sc) } } -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 = names.tdata()[i]; - Identifier *alias = aliases.tdata()[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) { //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags); @@ -349,14 +285,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) @@ -374,7 +346,7 @@ void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; buf->printf("%s.", pid->toChars()); } @@ -383,3 +355,7 @@ void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); } +char *Import::toChars() +{ + return id->toChars(); +} diff --git a/dmd2/import.h b/dmd2/import.h index 40765f56..b8979923 100644 --- a/dmd2/import.h +++ b/dmd2/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,6 +28,7 @@ struct HdrGenState; struct Import : Dsymbol { + // isstatic import aliasId = packages.id; Identifiers *packages; // array of Identifier's representing packages Identifier *id; // module Identifier Identifier *aliasId; @@ -37,8 +38,6 @@ struct Import : Dsymbol Identifiers names; Identifiers aliases; - AliasDeclarations aliasdecls; // AliasDeclarations for names/aliases - Module *mod; Package *pkg; // leftmost package/module @@ -52,11 +51,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/dmd2/init.c b/dmd2/init.c index 6bf2f07a..4d9806c6 100644 --- a/dmd2/init.c +++ b/dmd2/init.c @@ -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++) @@ -287,6 +288,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++) @@ -863,6 +865,12 @@ L1: Type *ExpInitializer::inferType(Scope *sc) { //printf("ExpInitializer::inferType() %s\n", toChars()); + if (exp->op == TOKfunction && ((FuncExp *)exp)->td) + { + exp->error("cannot infer type from ambiguous function literal %s", exp->toChars()); + return Type::terror; + } + exp = exp->semantic(sc); exp = resolveProperties(sc, exp); diff --git a/dmd2/inline.c b/dmd2/inline.c index 11b9c3c5..052dc343 100644 --- a/dmd2/inline.c +++ b/dmd2/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,46 +152,93 @@ 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) +{ + //printf("expressionInlineCost()\n"); + //e->dump(0); + 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) +int VarExp::inlineCost3(InlineCostState *ics) { - //printf("VarExp::inlineCost() %s\n", toChars()); + //printf("VarExp::inlineCost3() %s\n", toChars()); + Type *tb = type->toBasetype(); + if (tb->ty == Tstruct) + { + StructDeclaration *sd = ((TypeStruct *)tb)->sym; + if (sd->isnested) + /* An inner struct will be nested inside another function hierarchy than where + * we're inlining into, so don't inline it. + * At least not until we figure out how to 'move' the struct to be nested + * locally. Example: + * struct S(alias pred) { void unused_func(); } + * void abc() { int w; S!(w) m; } + * void bar() { abc(); } + */ + return COST_MAX; + } + FuncDeclaration *fd = var->isFuncDeclaration(); + if (fd && fd->isNested()) // see Bugzilla 7199 for test case + return COST_MAX; 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; @@ -181,44 +249,19 @@ 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; - return 1 + arrayInlineCost(ics, elements); +#endif + 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. @@ -226,18 +269,19 @@ int FuncExp::inlineCost(InlineCostState *ics) return COST_MAX; } -int DelegateExp::inlineCost(InlineCostState *ics) +int DelegateExp::inlineCost3(InlineCostState *ics) { // This breaks on LDC too, since nested functions have internal linkage // and thus can't be referenced from other objects. + //printf("DelegateExp::inlineCost3()\n"); 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) { @@ -264,9 +308,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) { @@ -274,7 +319,7 @@ int DeclarationExp::inlineCost(InlineCostState *ics) if (ie) { - cost += ie->exp->inlineCost(ics); + cost += expressionInlineCost(ie->exp, ics); } } } @@ -286,62 +331,25 @@ 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) -{ - return 1 + e1->inlineCost(ics); -} - -int AssertExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + (msg ? msg->inlineCost(ics) : 0); -} - -int BinExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + e2->inlineCost(ics); -} - -int CallExp::inlineCost(InlineCostState *ics) +int CallExp::inlineCost3(InlineCostState *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 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); -} - -int SliceExp::inlineCost(InlineCostState *ics) -{ int cost; - - cost = 1 + e1->inlineCost(ics); - if (lwr) - cost += lwr->inlineCost(ics); - if (upr) - cost += upr->inlineCost(ics); - return cost; -} - -int ArrayExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); -} - - -int CondExp::inlineCost(InlineCostState *ics) -{ - return 1 + - e1->inlineCost(ics) + - e2->inlineCost(ics) + - econd->inlineCost(ics); + return 1; } @@ -359,10 +367,122 @@ struct InlineDoState Dsymbols from; // old Dsymbols Dsymbols to; // parallel array of new Dsymbols Dsymbol *parent; // new parent + FuncDeclaration *fd; // function being inlined (old parent) }; +/* -------------------------------------------------------------------- */ + +Statement *Statement::doInlineStatement(InlineDoState *ids) +{ + assert(0); + return NULL; // default is we can't inline it +} + +Statement *ExpStatement::doInlineStatement(InlineDoState *ids) +{ +#if LOG + if (exp) printf("ExpStatement::doInlineStatement() '%s'\n", exp->toChars()); +#endif + return new ExpStatement(loc, exp ? exp->doInline(ids) : NULL); +} + +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; + + /* 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); +} + +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); +} + +Statement *ScopeStatement::doInlineStatement(InlineDoState *ids) +{ + //printf("ScopeStatement::doInlineStatement() %d\n", statements->dim); + return statement ? new ScopeStatement(loc, statement->doInlineStatement(ids)) : this; +} + +Statement *IfStatement::doInlineStatement(InlineDoState *ids) +{ + assert(!arg); + + 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) +{ + //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 } @@ -425,6 +545,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; @@ -471,10 +596,12 @@ Expression *ReturnStatement::doInline(InlineDoState *ids) return exp ? exp->doInline(ids) : 0; } +#if DMDV2 Expression *ImportStatement::doInline(InlineDoState *ids) { return NULL; } +#endif /* --------------------------------------------------------------- */ @@ -536,6 +663,12 @@ Expression *VarExp::doInline(InlineDoState *ids) return ve; } } + if (ids->fd && var == ids->fd->vthis) + { VarExp *ve = new VarExp(loc, ids->vthis); + ve->type = type; + return ve; + } + return this; } @@ -838,7 +971,29 @@ 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; } @@ -1169,9 +1324,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) @@ -1179,7 +1334,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) @@ -1191,7 +1346,7 @@ Expression *CallExp::inlineScan(InlineScanState *iss) ; } else - e = fd->doInline(iss, dve->e1, arguments); + e = fd->expandInline(iss, dve->e1, arguments, NULL); } } @@ -1282,7 +1437,7 @@ void FuncDeclaration::inlineScan() #endif memset(&iss, 0, sizeof(iss)); iss.fd = this; - if (fbody) + if (fbody && !naked) { inlineNest++; fbody = fbody->inlineScan(&iss); @@ -1290,7 +1445,7 @@ void FuncDeclaration::inlineScan() } } -int FuncDeclaration::canInline(int hasthis, int hdrscan) +int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) { InlineCostState ics; int cost; @@ -1298,7 +1453,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) @@ -1312,7 +1467,8 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) return 0; } - switch (inlineStatus) +#if 1 + switch (statementsToo ? inlineStatusStmt : inlineStatusExp) { case ILSyes: #if CANINLINE_LOG @@ -1332,6 +1488,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) default: assert(0); } +#endif if (type) { assert(type->ty == Tfunction); @@ -1345,9 +1502,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; } @@ -1357,6 +1515,7 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) if ( !fbody || + ident == Id::ensure || // ensure() has magic properties the inliner loses !hdrscan && ( #if 0 @@ -1368,11 +1527,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()) )) @@ -1380,26 +1535,20 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan) goto Lno; } -#if !IN_LLVM +#if 0 /* If any parameters are Tsarray's (which are passed by reference) * or out parameters (also passed by reference), don't do inlining. */ -#if 0 if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { VarDeclaration *v = parameters->tdata()[i]; - if ( -#if DMDV1 - v->isOut() || v->isRef() || -#endif - v->type->toBasetype()->ty == Tsarray) + if (v->type->toBasetype()->ty == Tsarray) goto Lno; } } #endif -#endif // !IN_LLVM memset(&ics, 0, sizeof(ics)); ics.hasthis = hasthis; @@ -1407,18 +1556,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 !IN_LLVM - if (!hdrscan) // Don't scan recursively for header content scan - inlineScan(); + if (!hdrscan) + { + // Don't modify inlineStatus for header content scan + if (statementsToo) + inlineStatusStmt = ILSyes; + else + inlineStatusExp = ILSyes; + +#if !IN_LLVM // TODO: why was it added in the first place? + 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 @@ -1426,25 +1604,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, Expressions *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; + ids.fd = this; + + if (ps) + as = new Statements(); // Set up vthis if (ethis) @@ -1501,6 +1688,8 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, E { e = new DeclarationExp(0, ids.vthis); e->type = Type::tvoid; + if (as) + as->push(new ExpStatement(e->loc, e)); } if (arguments && arguments->dim) @@ -1540,18 +1729,31 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, E 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'. @@ -1563,7 +1765,7 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, E * 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: @@ -1593,6 +1795,9 @@ Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, E //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; } @@ -1612,7 +1817,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/dmd2/interpret.c b/dmd2/interpret.c index dffb7e36..770b29a2 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -117,6 +117,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) @@ -201,7 +202,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); @@ -210,6 +211,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)) @@ -258,8 +262,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 { @@ -276,7 +311,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() @@ -288,7 +323,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"); } }; @@ -314,25 +349,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) { @@ -346,7 +386,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) { @@ -354,6 +405,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]; @@ -401,20 +456,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) { @@ -435,10 +486,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); @@ -446,11 +497,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; @@ -462,13 +520,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; @@ -480,7 +539,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); @@ -490,12 +548,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) { @@ -511,16 +571,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; } @@ -529,23 +591,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) + 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; + error("cannot interpret %s as a ref parameter", ve->toChars()); + return EXP_CANT_INTERPRET; } - v->setValueWithoutChecking(earg); + /* 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 @@ -570,7 +640,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); @@ -579,7 +649,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 @@ -603,12 +672,22 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument ctfeStack.endFrame(istatex.framepointer); - if (e == EXP_CANT_INTERPRET || !exceptionOrCantInterpret(e)) - return e; - if (istate) - return e; - ((ThrownExceptionExp *)e)->generateUncaughtError(); - return NULL; + // 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; } /******************************** Statement ***************************/ @@ -728,7 +807,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) @@ -825,6 +905,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); @@ -846,15 +993,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); } @@ -910,19 +1064,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()); @@ -1209,7 +1357,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)) @@ -1342,7 +1493,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); } @@ -1441,7 +1592,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; @@ -1524,21 +1675,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"); @@ -1560,7 +1705,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)) @@ -1730,11 +1875,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) @@ -1744,30 +1886,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 StaticStructInitDeclaration from - // TypeStruct::defaultInit() - VarExp *ve2 = (VarExp *)v->getValue(); - 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) @@ -1815,7 +1942,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; @@ -1827,13 +1954,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()) { @@ -1864,6 +1994,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 @@ -1876,19 +2017,16 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal e = EXP_CANT_INTERPRET; } else if (s) - { + { // Struct static initializers, for example #if !IN_LLVM - // Struct static initializers, for example if (s->dsym->toInitializer() == s->sym) - { #endif - Expressions *exps = new Expressions(); - e = new StructLiteralExp(loc, s->dsym, exps); + { e = s->dsym->type->defaultInitLiteral(); e = e->semantic(NULL); if (e->op == TOKerror) e = EXP_CANT_INTERPRET; -#if !IN_LLVM } +#if !IN_LLVM else error(loc, "cannot interpret symbol %s at compile time", v->toChars()); #endif @@ -1905,10 +2043,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; @@ -2072,6 +2207,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++) @@ -2110,7 +2247,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)) @@ -2134,6 +2271,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]; @@ -2208,6 +2347,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; @@ -2232,6 +2372,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) { @@ -2272,6 +2414,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); @@ -2281,7 +2424,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(); @@ -2292,8 +2435,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; } @@ -2301,7 +2445,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; @@ -2316,16 +2460,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); @@ -2335,7 +2480,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; @@ -2344,17 +2489,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); } @@ -2365,7 +2511,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) { @@ -2385,7 +2531,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; } @@ -2409,12 +2555,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 @@ -2468,6 +2615,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; @@ -2673,10 +2835,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; @@ -2697,11 +2861,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; } @@ -2724,6 +2888,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; @@ -2759,7 +2939,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; @@ -2774,7 +2955,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; @@ -2788,15 +2970,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 */ @@ -2828,8 +3010,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; } @@ -2919,9 +3102,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: @@ -2975,6 +3160,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) @@ -2983,6 +3169,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) @@ -2991,6 +3178,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 @@ -3021,7 +3209,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); @@ -3033,6 +3221,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 @@ -3045,7 +3234,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) @@ -3104,8 +3293,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) { @@ -3116,10 +3305,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; } @@ -3136,77 +3335,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. @@ -3347,7 +3487,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 ) @@ -3382,15 +3522,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) { @@ -3453,7 +3590,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); @@ -3486,7 +3623,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); @@ -3559,26 +3698,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; @@ -3629,28 +3795,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 @@ -3673,7 +3824,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; @@ -3737,6 +3888,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); @@ -3765,8 +3917,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 @@ -3784,8 +3938,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; @@ -3813,7 +3969,7 @@ 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) { @@ -3827,23 +3983,18 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ 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); + v->setValue(newval); } else { - if (!v->getValue()) // creating a new value - v->createStackValue(newval); - else - v->setStackValue(newval); + v->setValue(newval); } } } @@ -3919,7 +4070,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); @@ -3960,7 +4111,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; } @@ -3977,10 +4128,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) @@ -4037,6 +4197,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) { @@ -4066,7 +4231,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; @@ -4086,7 +4251,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; @@ -4137,10 +4302,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) @@ -4163,7 +4337,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ } aggregate = sexpold->e1; } - if (aggregate->type->toBasetype()->ty == Tpointer && aggregate->type->toBasetype()->nextOf()->ty != Tfunction) + if ( isPointer(aggregate->type) ) { // Slicing a pointer --> change the bounds aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue); dinteger_t ofs; @@ -4177,10 +4351,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) { @@ -4321,15 +4499,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) @@ -4379,6 +4559,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)) @@ -4423,6 +4608,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)) @@ -4456,7 +4646,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; @@ -4478,10 +4668,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. @@ -4601,8 +4791,12 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) } if (pthis) { // Member function call + Expression *oldpthis; if (pthis->op == TOKthis) + { pthis = istate ? istate->localThis : NULL; + oldpthis = pthis; + } else { if (pthis->op == TOKcomma) @@ -4610,41 +4804,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); @@ -4662,8 +4861,7 @@ 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; } @@ -4674,16 +4872,12 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) 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) @@ -4719,7 +4913,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(); @@ -4762,7 +4956,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)) @@ -4838,6 +5032,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; @@ -4872,9 +5094,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; @@ -4894,7 +5118,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); @@ -4939,22 +5163,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 (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 (e == EXP_CANT_INTERPRET) - { - error("%s cannot be interpreted at compile time", toChars()); + if (exceptionOrCantInterpret(e)) return e; - } if (goal == ctfeNeedRvalue && (e->op == TOKslice || e->op == TOKdotvar)) e = e->interpret(istate); + e = paintTypeOntoLiteral(type, e); return e; } @@ -5024,7 +5247,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) @@ -5042,7 +5265,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); @@ -5050,7 +5273,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 @@ -5167,24 +5390,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; } @@ -5194,14 +5431,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; @@ -5370,19 +5611,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)) @@ -5392,6 +5625,7 @@ Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal) } else e1 = this->e1->interpret(istate); +#endif if (exceptionOrCantInterpret(e1)) return e1; if (isTrueBool(e1)) @@ -5495,7 +5729,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) @@ -5585,9 +5819,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()); @@ -5602,14 +5836,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); @@ -5625,9 +5859,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); @@ -5675,7 +5915,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); } @@ -5713,9 +5953,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) @@ -5734,10 +5975,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) @@ -6196,10 +6438,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 == Tnull || - 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) @@ -6217,16 +6462,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; @@ -6238,7 +6477,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) { @@ -6273,13 +6515,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)) @@ -6289,16 +6534,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; } @@ -6325,26 +6573,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/dmd2/lexer.c b/dmd2/lexer.c index 9b4d4f46..32a4a9ab 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -119,11 +119,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 @@ -1144,6 +1144,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; @@ -2069,7 +2075,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') { @@ -3013,6 +3025,7 @@ static Keyword keywords[] = { "__thread", TOKtls }, { "__gshared", TOKgshared }, { "__traits", TOKtraits }, + { "__vector", TOKvector }, { "__overloadset", TOKoverloadset }, { "__FILE__", TOKfile }, { "__LINE__", TOKline }, @@ -3032,25 +3045,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(6151); 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); @@ -3147,6 +3157,7 @@ void Lexer::initKeywords() Token::tochars[TOKat] = "@"; Token::tochars[TOKpow] = "^^"; Token::tochars[TOKpowass] = "^^="; + Token::tochars[TOKgoesto] = "=>"; #endif // For debugging diff --git a/dmd2/lexer.h b/dmd2/lexer.h index e7916d86..692e2c7f 100644 --- a/dmd2/lexer.h +++ b/dmd2/lexer.h @@ -34,7 +34,7 @@ struct Module; = ! ~ @ ^^ ^^= ++ -- - . -> : , + . -> : , => ? && || */ @@ -168,6 +168,8 @@ enum TOK TOKat, TOKpow, TOKpowass, + TOKgoesto, + TOKvector, #endif // LDC specific diff --git a/dmd2/mars.c b/dmd2/mars.c index b1af8a43..2d17dd29 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -1,10 +1,10 @@ // 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 -// http://www.dsource.org/projects/dmd/browser/trunk/src/mars.c +// https://github.com/D-Programming-Language/dmd/blob/master/src/mars.c // 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. @@ -96,13 +96,13 @@ Global::Global() #endif #endif - copyright = "Copyright (c) 1999-2011 by Digital Mars"; + copyright = "Copyright (c) 1999-2012 by Digital Mars"; written = "written by Walter Bright" #if TARGET_NET "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; #endif ; - version = "v2.057"; + version = "v2.058"; #if IN_LLVM ldc_version = "LDC trunk"; llvm_version = "LLVM 3.0"; @@ -162,7 +162,7 @@ bool Loc::equals(const Loc& loc) } /************************************** - * Print error message and exit. + * Print error message */ void error(Loc loc, const char *format, ...) @@ -181,6 +181,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) @@ -211,6 +223,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) @@ -258,7 +289,7 @@ void fatal() void halt() { #ifdef DEBUG - *(char*)0=0; + *(volatile char*)0=0; #endif } @@ -280,7 +311,7 @@ void usage() sizeof(size_t) == 4 ? "32" : "64", global.version, global.copyright, global.written); printf("\ -Documentation: http://www.digitalmars.com/d/2.0/index.html\n\ +Documentation: http://www.dlang.org/index.html\n\ Usage:\n\ dmd files.d ... { -switch }\n\ \n\ @@ -298,9 +329,6 @@ Usage:\n\ -debuglib=name set symbolic debug library to name\n\ -defaultlib=name set default library to name\n\ -deps=filename write module dependencies to filename\n%s" -#if TARGET_OSX -" -dylib generate dylib\n" -#endif " -g add symbolic debug info\n\ -gc add symbolic debug info, pretend to be C\n\ -gs always emit stack frame\n\ @@ -313,8 +341,12 @@ Usage:\n\ -inline do function inlining\n\ -Jpath where to look for string imports\n\ -Llinkerflag pass linkerflag to link\n\ - -lib generate library rather than object files\n\ - -man open web browser on manual page\n\ + -lib generate library rather than object files\n" +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS +" -m32 generate 32 bit code\n\ + -m64 generate 64 bit code\n" +#endif +" -man open web browser on manual page\n\ -map generate linker .map file\n\ -noboundscheck turns off array bounds checking for all functions\n\ -nofloat do not emit reference to floating point\n\ @@ -327,8 +359,11 @@ Usage:\n\ -property enforce property syntax\n\ -quiet suppress unnecessary messages\n\ -release compile release version\n\ - -run srcfile args... run resulting program, passing args\n\ - -unittest compile in unit tests\n\ + -run srcfile args... run resulting program, passing args\n" +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS +" -shared generate shared library\n" +#endif +" -unittest compile in unit tests\n\ -v verbose\n\ -version=level compile in version code >= level\n\ -version=ident compile in version code identified by ident\n\ @@ -495,12 +530,15 @@ int main(int argc, char *argv[]) else if (strcmp(p + 1, "cov") == 0) global.params.cov = 1; #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + else if (strcmp(p + 1, "shared") == 0 +#if TARGET_OSX + // backwards compatibility with old switch + || strcmp(p + 1, "dylib") == 0 +#endif + ) + global.params.dll = 1; else if (strcmp(p + 1, "fPIC") == 0) global.params.pic = 1; -#endif -#if TARGET_OSX - else if (strcmp(p + 1, "dylib") == 0) - global.params.dll = 1; #endif else if (strcmp(p + 1, "map") == 0) global.params.map = 1; @@ -764,35 +802,35 @@ int main(int argc, char *argv[]) #if DMDV1 browse("http://www.digitalmars.com/d/1.0/dmd-windows.html"); #else - browse("http://www.digitalmars.com/d/2.0/dmd-windows.html"); + browse("http://www.dlang.org/dmd-windows.html"); #endif #endif #if linux #if DMDV1 browse("http://www.digitalmars.com/d/1.0/dmd-linux.html"); #else - browse("http://www.digitalmars.com/d/2.0/dmd-linux.html"); + browse("http://www.dlang.org/dmd-linux.html"); #endif #endif #if __APPLE__ #if DMDV1 browse("http://www.digitalmars.com/d/1.0/dmd-osx.html"); #else - browse("http://www.digitalmars.com/d/2.0/dmd-osx.html"); + browse("http://www.dlang.org/dmd-osx.html"); #endif #endif #if __FreeBSD__ #if DMDV1 browse("http://www.digitalmars.com/d/1.0/dmd-freebsd.html"); #else - browse("http://www.digitalmars.com/d/2.0/dmd-freebsd.html"); + browse("http://www.dlang.org/dmd-freebsd.html"); #endif #endif #if __OpenBSD__ #if DMDV1 browse("http://www.digitalmars.com/d/1.0/dmd-openbsd.html"); #else - browse("http://www.digitalmars.com/d/2.0/dmd-openbsd.html"); + browse("http://www.dlang.org/dmd-openbsd.html"); #endif #endif exit(EXIT_SUCCESS); @@ -852,6 +890,11 @@ int main(int argc, char *argv[]) global.params.pic = 1; #endif +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS + if (global.params.lib && global.params.dll) + error("cannot mix -lib and -shared\n"); +#endif + if (global.params.release) { global.params.useInvariants = 0; global.params.useIn = 0; @@ -928,6 +971,7 @@ int main(int argc, char *argv[]) VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64"); VersionCondition::addPredefinedGlobalIdent("X86_64"); VersionCondition::addPredefinedGlobalIdent("D_LP64"); + VersionCondition::addPredefinedGlobalIdent("D_SIMD"); #if TARGET_WINDOS VersionCondition::addPredefinedGlobalIdent("Win64"); #endif @@ -937,6 +981,9 @@ int main(int argc, char *argv[]) VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); VersionCondition::addPredefinedGlobalIdent("X86"); +#if TARGET_OSX + VersionCondition::addPredefinedGlobalIdent("D_SIMD"); +#endif #if TARGET_WINDOS VersionCondition::addPredefinedGlobalIdent("Win32"); #endif diff --git a/dmd2/mars.h b/dmd2/mars.h index 9254d45c..6c9274ba 100644 --- a/dmd2/mars.h +++ b/dmd2/mars.h @@ -466,8 +466,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); void fatal(); void err_nomem(); #if IN_LLVM diff --git a/dmd2/mem.c b/dmd2/mem.c deleted file mode 100644 index 36097692..00000000 --- a/dmd2/mem.c +++ /dev/null @@ -1,273 +0,0 @@ - -/* Copyright (c) 2000 Digital Mars */ -/* All Rights Reserved */ - -#include -#include -#include -#include - -#include "rmem.h" - -#if USE_BOEHM_GC - // I needed to perfix the dir after upgrading to gc 7.0 - #include "gc/gc.h" -#endif - -/* This implementation of the storage allocator uses the standard C allocation package. - */ - -Mem mem; - -#if USE_BOEHM_GC - -static bool gc_was_init = false; - -void Mem::init() -{ - GC_init(); - gc_was_init = true; -} - -char *Mem::strdup(const char *s) -{ - char *p; - - if (s) - { - p = GC_strdup(s); - if (p) - return p; - error(); - } - return NULL; -} - -void *Mem::malloc(size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = GC_malloc(size); - if (!p) - error(); - } - return p; -} - -void *Mem::calloc(size_t size, size_t n) -{ void *p; - - if (!size || !n) - p = NULL; - else - { - p = GC_malloc(size * n); - if (!p) - error(); - memset(p, 0, size * n); - } - return p; -} - -void *Mem::realloc(void *p, size_t size) -{ - if (!size) - { if (p) - { GC_free(p); - p = NULL; - } - } - else if (!p) - { - p = GC_malloc(size); - if (!p) - error(); - } - else - { - p = GC_realloc(p, size); - if (!p) - error(); - } - return p; -} - -void Mem::free(void *p) -{ - if (p) - GC_free(p); -} - -void *Mem::mallocdup(void *o, size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = GC_malloc(size); - if (!p) - error(); - else - memcpy(p,o,size); - } - return p; -} - -void Mem::error() -{ - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); -} - -void Mem::fullcollect() -{ - GC_gcollect(); -} - -void Mem::mark(void *pointer) -{ - (void) pointer; // necessary for VC /W4 -} - -void Mem::setStackBottom(void */*bottom*/) -{ -} - -/* =================================================== */ - -void * operator new(size_t m_size) -{ - // without this we segfault with gc 7.0 - if (!gc_was_init) { - mem.init(); - } - void *p = GC_malloc(m_size); - if (p) - return p; - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); - return p; -} - -void operator delete(void *p) -{ - GC_free(p); -} - -#elif !USE_BOEHM_GC - -void Mem::init() -{ -} - -char *Mem::strdup(const char *s) -{ - char *p; - - if (s) - { - p = ::strdup(s); - if (p) - return p; - error(); - } - return NULL; -} - -void *Mem::malloc(size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = ::malloc(size); - if (!p) - error(); - } - return p; -} - -void *Mem::calloc(size_t size, size_t n) -{ void *p; - - if (!size || !n) - p = NULL; - else - { - p = ::malloc(size * n); - if (!p) - error(); - memset(p, 0, size * n); - } - return p; -} - -void *Mem::realloc(void *p, size_t size) -{ - if (!size) - { if (p) - { ::free(p); - p = NULL; - } - } - else if (!p) - { - p = ::malloc(size); - if (!p) - error(); - } - else - { - p = ::realloc(p, size); - if (!p) - error(); - } - return p; -} - -void Mem::free(void *p) -{ - if (p) - ::free(p); -} - -void *Mem::mallocdup(void *o, size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = ::malloc(size); - if (!p) - error(); - else - memcpy(p,o,size); - } - return p; -} - -void Mem::error() -{ - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); -} - -void Mem::fullcollect() -{ -} - -void Mem::mark(void *pointer) -{ -} - -void Mem::setStackBottom(void */*stackbottom*/) -{ -} - -#endif // USE_BOEHM_GC diff --git a/dmd2/mem.h b/dmd2/mem.h deleted file mode 100644 index 61930209..00000000 --- a/dmd2/mem.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2000-2001 by Chromium Communications -// All Rights Reserved - -#ifndef ROOT_MEM_H -#define ROOT_MEM_H - -#include // for size_t - -typedef void (*FINALIZERPROC)(void* pObj, void* pClientData); - -struct GC; // thread specific allocator - -struct Mem -{ - GC *gc; // pointer to our thread specific allocator - Mem() { gc = NULL; } - - void init(); - - // Derive from Mem to get these storage allocators instead of global new/delete - void * operator new(size_t m_size); - void * operator new(size_t m_size, Mem *mem); - void * operator new(size_t m_size, GC *gc); - void operator delete(void *p); - - void * operator new[](size_t m_size); - void operator delete[](void *p); - - char *strdup(const char *s); - void *malloc(size_t size); - void *malloc_uncollectable(size_t size); - void *calloc(size_t size, size_t n); - void *realloc(void *p, size_t size); - void free(void *p); - void free_uncollectable(void *p); - void *mallocdup(void *o, size_t size); - void error(); - void check(void *p); // validate pointer - void fullcollect(); // do full garbage collection - void fullcollectNoStack(); // do full garbage collection, no scan stack - void mark(void *pointer); - void addroots(char* pStart, char* pEnd); - void removeroots(char* pStart); - void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData); - void setStackBottom(void *bottom); - GC *getThreadGC(); // get apartment allocator for this thread -}; - -extern Mem mem; - -#endif /* ROOT_MEM_H */ diff --git a/dmd2/module.c b/dmd2/module.c index f6917796..c486bfc6 100644 --- a/dmd2/module.c +++ b/dmd2/module.c @@ -851,6 +851,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. @@ -858,14 +864,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/dmd2/mtype.c b/dmd2/mtype.c index b05a9b9d..abff3d40 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.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 @@ -113,6 +113,7 @@ ClassDeclaration *Type::typeinfopointer; ClassDeclaration *Type::typeinfoarray; ClassDeclaration *Type::typeinfostaticarray; ClassDeclaration *Type::typeinfoassociativearray; +ClassDeclaration *Type::typeinfovector; ClassDeclaration *Type::typeinfoenum; ClassDeclaration *Type::typeinfofunction; ClassDeclaration *Type::typeinfodelegate; @@ -198,7 +199,7 @@ void Type::init(Ir* _sir) void Type::init() #endif { - stringtable.init(); + stringtable.init(1543); #if IN_LLVM deco_stringtable.init(); #endif @@ -223,6 +224,8 @@ void Type::init() sizeTy[Ttuple] = sizeof(TypeTuple); sizeTy[Tslice] = sizeof(TypeSlice); sizeTy[Treturn] = sizeof(TypeReturn); + sizeTy[Terror] = sizeof(TypeError); + sizeTy[Tnull] = sizeof(TypeNull); mangleChar[Tarray] = 'A'; mangleChar[Tsarray] = 'G'; @@ -270,6 +273,7 @@ void Type::init() mangleChar[Ttuple] = 'B'; mangleChar[Tslice] = '@'; mangleChar[Treturn] = '@'; + mangleChar[Tvector] = '@'; mangleChar[Tnull] = 'n'; // same as TypeNone @@ -952,6 +956,9 @@ Type *Type::makeConst() t->wto = NULL; t->swto = NULL; t->vtinfo = NULL; +#if IN_DMD + t->ctype = NULL; +#endif //printf("-Type::makeConst() %p, %s\n", t, toChars()); return t; } @@ -975,6 +982,9 @@ Type *Type::makeInvariant() t->wto = NULL; t->swto = NULL; t->vtinfo = NULL; +#if IN_DMD + t->ctype = NULL; +#endif return t; } @@ -997,6 +1007,9 @@ Type *Type::makeShared() t->wto = NULL; t->swto = NULL; t->vtinfo = NULL; +#if IN_DMD + t->ctype = NULL; +#endif return t; } @@ -1019,6 +1032,9 @@ Type *Type::makeSharedConst() t->wto = NULL; t->swto = NULL; t->vtinfo = NULL; +#if IN_DMD + t->ctype = NULL; +#endif return t; } @@ -1041,6 +1057,9 @@ Type *Type::makeWild() t->wto = NULL; t->swto = NULL; t->vtinfo = NULL; +#if IN_DMD + t->ctype = NULL; +#endif return t; } @@ -1063,6 +1082,9 @@ Type *Type::makeSharedWild() t->wto = NULL; t->swto = NULL; t->vtinfo = NULL; +#if IN_DMD + t->ctype = NULL; +#endif return t; } @@ -1083,6 +1105,9 @@ Type *Type::makeMutable() t->wto = NULL; t->swto = NULL; t->vtinfo = NULL; +#if IN_DMD + t->ctype = NULL; +#endif return t; } @@ -1321,6 +1346,13 @@ Type *Type::aliasthisOf() } return t; } + EnumDeclaration *ed = ad->aliasthis->isEnumDeclaration(); + if (ed) + { + Type *t = ed->type; + return t; + } + //printf("%s\n", ad->aliasthis->kind()); } return NULL; } @@ -1366,6 +1398,31 @@ int MODimplicitConv(unsigned char modfrom, unsigned char modto) #undef X } +/*************************** + * Return !=0 if a method of type '() modfrom' can call a method of type '() modto'. + */ +int MODmethodConv(unsigned char modfrom, unsigned char modto) +{ + if (MODimplicitConv(modfrom, modto)) + return 1; + + #define X(m, n) (((m) << 4) | (n)) + switch (X(modfrom, modto)) + { + case X(0, MODwild): + case X(MODimmutable, MODwild): + case X(MODconst, MODwild): + case X(MODshared, MODshared|MODwild): + case X(MODshared|MODimmutable, MODshared|MODwild): + case X(MODshared|MODconst, MODshared|MODwild): + return 1; + + default: + return 0; + } + #undef X +} + /*************************** * Merge mod bits to form common mod. */ @@ -2103,8 +2160,9 @@ Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident) tiargs->push(se); e = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs); ((DotTemplateInstanceExp *)e)->ti->tempdecl = td; + //return e; + e = e->semantic(sc); return e; - //return e->semantic(sc); } /* See if we should forward to the alias this. @@ -2500,11 +2558,29 @@ Type *TypeNext::makeMutable() } MATCH TypeNext::constConv(Type *to) -{ MATCH m = Type::constConv(to); +{ + //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to->toChars()); + if (equals(to)) + return MATCHexact; - if (m == MATCHconst && - next->constConv(((TypeNext *)to)->next) == MATCHnomatch) - m = MATCHnomatch; + if (!(ty == to->ty && MODimplicitConv(mod, to->mod))) + return MATCHnomatch; + + Type *tn = to->nextOf(); + if (!(tn && next->ty == tn->ty)) + return MATCHnomatch; + + MATCH m; + if (to->isConst()) // whole tail const conversion + { // Recursive shared level check + m = next->constConv(tn); + if (m == MATCHexact) + m = MATCHconst; + } + else + { //printf("\tnext => %s, to->next => %s\n", next->toChars(), tn->toChars()); + m = next->equals(tn) ? MATCHconst : MATCHnomatch; + } return m; } @@ -2545,51 +2621,53 @@ TypeBasic::TypeBasic(TY ty) #define TFLAGSreal 8 #define TFLAGSimaginary 0x10 #define TFLAGScomplex 0x20 +#define TFLAGSvector 0x40 // valid for a SIMD vector type flags = 0; switch (ty) { case Tvoid: d = Token::toChars(TOKvoid); + flags |= TFLAGSvector; break; case Tint8: d = Token::toChars(TOKint8); - flags |= TFLAGSintegral; + flags |= TFLAGSintegral | TFLAGSvector; break; case Tuns8: d = Token::toChars(TOKuns8); - flags |= TFLAGSintegral | TFLAGSunsigned; + flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; break; case Tint16: d = Token::toChars(TOKint16); - flags |= TFLAGSintegral; + flags |= TFLAGSintegral | TFLAGSvector; break; case Tuns16: d = Token::toChars(TOKuns16); - flags |= TFLAGSintegral | TFLAGSunsigned; + flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; break; case Tint32: d = Token::toChars(TOKint32); - flags |= TFLAGSintegral; + flags |= TFLAGSintegral | TFLAGSvector; break; case Tuns32: d = Token::toChars(TOKuns32); - flags |= TFLAGSintegral | TFLAGSunsigned; + flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; break; case Tfloat32: d = Token::toChars(TOKfloat32); - flags |= TFLAGSfloating | TFLAGSreal; + flags |= TFLAGSfloating | TFLAGSreal | TFLAGSvector; break; case Tint64: d = Token::toChars(TOKint64); - flags |= TFLAGSintegral; + flags |= TFLAGSintegral | TFLAGSvector; break; case Tuns64: d = Token::toChars(TOKuns64); - flags |= TFLAGSintegral | TFLAGSunsigned; + flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; break; case Tfloat64: d = Token::toChars(TOKfloat64); - flags |= TFLAGSfloating | TFLAGSreal; + flags |= TFLAGSfloating | TFLAGSreal | TFLAGSvector; break; case Tfloat80: d = Token::toChars(TOKfloat80); @@ -3240,10 +3318,18 @@ MATCH TypeBasic::implicitConvTo(Type *to) return MATCHnomatch; if (to->ty == Tbool) return MATCHnomatch; - if (!to->isTypeBasic()) + + TypeBasic *tob; + if (to->ty == Tvector) + { + TypeVector *tv = (TypeVector *)to; + tob = tv->elementType(); + } + else + tob = to->isTypeBasic(); + if (!tob) return MATCHnomatch; - TypeBasic *tob = (TypeBasic *)to; if (flags & TFLAGSintegral) { // Disallow implicit conversion of integers to imaginary or complex @@ -3252,7 +3338,7 @@ MATCH TypeBasic::implicitConvTo(Type *to) #if DMDV2 // If converting from integral to integral - if (1 && tob->flags & TFLAGSintegral) + if (tob->flags & TFLAGSintegral) { d_uns64 sz = size(0); d_uns64 tosz = tob->size(0); @@ -3298,6 +3384,152 @@ TypeBasic *TypeBasic::isTypeBasic() return (TypeBasic *)this; } +/* ============================= TypeVector =========================== */ + +/* The basetype must be one of: + * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2] + */ +TypeVector::TypeVector(Loc loc, Type *basetype) + : Type(Tvector) +{ + this->basetype = basetype; +} + +Type *TypeVector::syntaxCopy() +{ + return new TypeVector(0, basetype->syntaxCopy()); +} + +Type *TypeVector::semantic(Loc loc, Scope *sc) +{ + int errors = global.errors; + basetype = basetype->semantic(loc, sc); + if (errors != global.errors) + return terror; + basetype = basetype->toBasetype()->mutableOf(); + if (basetype->ty != Tsarray || basetype->size() != 16) + { error(loc, "base type of __vector must be a 16 byte static array, not %s", basetype->toChars()); + return terror; + } + TypeSArray *t = (TypeSArray *)basetype; + TypeBasic *tb = t->nextOf()->isTypeBasic(); + if (!tb || !(tb->flags & TFLAGSvector)) + { error(loc, "base type of __vector must be a static array of an arithmetic type, not %s", t->toChars()); + return terror; + } + return merge(); +} + +TypeBasic *TypeVector::elementType() +{ + assert(basetype->ty == Tsarray); + TypeSArray *t = (TypeSArray *)basetype; + TypeBasic *tb = t->nextOf()->isTypeBasic(); + assert(tb); + return tb; +} + +int TypeVector::checkBoolean() +{ + return FALSE; +} + +char *TypeVector::toChars() +{ + return Type::toChars(); +} + +void TypeVector::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + //printf("TypeVector::toCBuffer2(mod = %d, this->mod = %d)\n", mod, this->mod); + if (mod != this->mod) + { toCBuffer3(buf, hgs, mod); + return; + } + buf->writestring("__vector("); + basetype->toCBuffer2(buf, hgs, this->mod); + buf->writestring(")"); +} + +void TypeVector::toDecoBuffer(OutBuffer *buf, int flag) +{ + if (flag != mod && flag != 0x100) + { + MODtoDecoBuffer(buf, mod); + } + buf->writestring("Nh"); + basetype->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod); +} + +d_uns64 TypeVector::size(Loc loc) +{ + return 16; +} + +unsigned TypeVector::alignsize() +{ + return 16; +} + +Expression *TypeVector::getProperty(Loc loc, Identifier *ident) +{ + return basetype->getProperty(loc, ident); +} + +Expression *TypeVector::dotExp(Scope *sc, Expression *e, Identifier *ident) +{ +#if LOGDOTEXP + printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); +#endif + if (ident == Id::array) + { + e = e->castTo(sc, basetype); + return e; + } + return basetype->dotExp(sc, e->castTo(sc, basetype), ident); +} + +Expression *TypeVector::defaultInit(Loc loc) +{ + return basetype->defaultInit(loc); +} + +int TypeVector::isZeroInit(Loc loc) +{ + return basetype->isZeroInit(loc); +} + +int TypeVector::isintegral() +{ + //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags); + return basetype->nextOf()->isintegral(); +} + +int TypeVector::isfloating() +{ + return basetype->nextOf()->isfloating(); +} + +int TypeVector::isunsigned() +{ + return basetype->nextOf()->isunsigned(); +} + +int TypeVector::isscalar() +{ + return basetype->nextOf()->isscalar(); +} + +MATCH TypeVector::implicitConvTo(Type *to) +{ + //printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars()); + if (this == to) + return MATCHexact; + if (ty == to->ty) + return MATCHconvert; + return MATCHnomatch; +} + /***************************** TypeArray *****************************/ TypeArray::TypeArray(TY ty, Type *next) @@ -3603,6 +3835,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. @@ -3846,21 +4084,27 @@ MATCH TypeSArray::implicitConvTo(Type *to) return MATCHnomatch; } if (to->ty == Tarray) - { int offset = 0; + { TypeDArray *ta = (TypeDArray *)to; if (!MODimplicitConv(next->mod, ta->next->mod)) return MATCHnomatch; - if (next->equals(ta->next) || -// next->implicitConvTo(ta->next) >= MATCHconst || - next->constConv(ta->next) != MATCHnomatch || - (ta->next->isBaseOf(next, &offset) && offset == 0 && - !ta->next->isMutable()) || - ta->next->ty == Tvoid) + /* Allow conversion to void[] + */ + if (ta->next->ty == Tvoid) + { return MATCHconvert; + } + + MATCH m = next->constConv(ta->next); + if (m != MATCHnomatch) + { + return MATCHconvert; + } return MATCHnomatch; } + if (to->ty == Tsarray) { if (this == to) @@ -3992,8 +4236,9 @@ Type *TypeDArray::semantic(Loc loc, Scope *sc) case Tnone: case Ttuple: error(loc, "can't have array of %s", tbn->toChars()); - tn = next = tint32; - break; + case Terror: + return Type::terror; + case Tstruct: { TypeStruct *ts = (TypeStruct *)tbn; if (0 && ts->sym->isnested) @@ -4089,7 +4334,7 @@ MATCH TypeDArray::implicitConvTo(Type *to) } if (to->ty == Tarray) - { int offset = 0; + { TypeDArray *ta = (TypeDArray *)to; if (!MODimplicitConv(next->mod, ta->next->mod)) @@ -4116,23 +4361,6 @@ MATCH TypeDArray::implicitConvTo(Type *to) m = MATCHconst; return m; } - -#if 0 - /* Allow conversions of T[][] to const(T)[][] - */ - if (mod == ta->mod && next->ty == Tarray && ta->next->ty == Tarray) - { - m = next->implicitConvTo(ta->next); - if (m == MATCHconst) - return m; - } -#endif - - /* Conversion of array of derived to array of const(base) - */ - if (ta->next->isBaseOf(next, &offset) && offset == 0 && - !ta->next->isMutable()) - return MATCHconvert; } return Type::implicitConvTo(to); } @@ -4251,6 +4479,7 @@ printf("index->ito->ito = x%x\n", index->ito->ito); case Tnone: case Ttuple: error(loc, "can't have associative array key of %s", index->toBasetype()->toChars()); + case Terror: return Type::terror; } next = next->semantic(loc,sc); @@ -4262,6 +4491,7 @@ printf("index->ito->ito = x%x\n", index->ito->ito); case Tvoid: case Tnone: error(loc, "can't have associative array of %s", next->toChars()); + case Terror: return Type::terror; } if (next->isscope()) @@ -4570,8 +4800,7 @@ MATCH TypeAArray::constConv(Type *to) // Pick the worst match return mkey < mindex ? mkey : mindex; } - else - return Type::constConv(to); + return Type::constConv(to); } /***************************** TypePointer *****************************/ @@ -4603,8 +4832,8 @@ Type *TypePointer::semantic(Loc loc, Scope *sc) { case Ttuple: error(loc, "can't have pointer to %s", n->toChars()); - n = tint32; - break; + case Terror: + return Type::terror; } if (n != next) { @@ -4661,7 +4890,8 @@ MATCH TypePointer::implicitConvTo(Type *to) return MATCHnomatch; } else if (to->ty == Tpointer) - { TypePointer *tp = (TypePointer *)to; + { + TypePointer *tp = (TypePointer *)to; assert(tp->next); if (!MODimplicitConv(next->mod, tp->next->mod)) @@ -4688,12 +4918,6 @@ MATCH TypePointer::implicitConvTo(Type *to) m = MATCHconst; return m; } - - /* Conversion of ptr to derived to ptr to base - */ - int offset = 0; - if (tp->next->isBaseOf(next, &offset) && offset == 0) - return MATCHconvert; } return MATCHnomatch; } @@ -4939,7 +5163,7 @@ int Type::covariant(Type *t) goto Lnotcovariant; { - // Return types + // Return types Type *t1n = t1->next; Type *t2n = t2->next; @@ -4960,6 +5184,8 @@ int Type::covariant(Type *t) // If t1n is forward referenced: ClassDeclaration *cd = ((TypeClass *)t1n)->sym; +// if (cd->scope) +// cd->semantic(NULL); #if 0 if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) #else @@ -4969,7 +5195,13 @@ int Type::covariant(Type *t) return 3; // forward references } } - if (t1n->implicitConvTo(t2n)) + if (t1n->ty == Tstruct && t2n->ty == Tstruct) + { + if (((TypeStruct *)t1n)->sym == ((TypeStruct *)t2n)->sym && + MODimplicitConv(t1n->mod, t2n->mod)) + goto Lcovariant; + } + else if (t1n->ty == t2n->ty && t1n->implicitConvTo(t2n)) goto Lcovariant; } goto Lnotcovariant; @@ -5368,6 +5600,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++) @@ -5586,7 +5819,7 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) { //printf("TypeFunction::callMatch() %s\n", toChars()); MATCH match = MATCHexact; // assume exact match - bool wildmatch = FALSE; + unsigned wildmatch = 0; if (ethis) { Type *t = ethis->type; @@ -5604,6 +5837,17 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) else return MATCHnomatch; } + if (isWild()) + { + if (t->isWild()) + wildmatch |= MODwild; + else if (t->isConst()) + wildmatch |= MODconst; + else if (t->isImmutable()) + wildmatch |= MODimmutable; + else + wildmatch |= MODmutable; + } } size_t nparams = Parameter::dim(parameters); @@ -5617,9 +5861,40 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) match = MATCHconvert; // match ... with a "conversion" match level } + for (size_t u = 0; u < nargs; u++) + { + if (u >= nparams) + break; + Parameter *p = Parameter::getNth(parameters, u); + Expression *arg = args->tdata()[u]; + assert(arg); + + if (!(p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid)) + { + unsigned mod = arg->type->wildConvTo(p->type); + if (mod) + { + wildmatch |= mod; + } + } + } + if (wildmatch) + { /* Calculate wild matching modifier + */ + if (wildmatch & MODconst || wildmatch & (wildmatch - 1)) + wildmatch = MODconst; + else if (wildmatch & MODimmutable) + wildmatch = MODimmutable; + else if (wildmatch & MODwild) + wildmatch = MODwild; + else + { assert(wildmatch & MODmutable); + wildmatch = MODmutable; + } + } + for (size_t u = 0; u < nparams; u++) { MATCH m; - Expression *arg; // BUG: what about out and ref? @@ -5629,51 +5904,70 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) { if (p->defaultArg) continue; - if (varargs == 2 && u + 1 == nparams) - goto L1; - goto Nomatch; // not enough arguments + goto L1; // try typesafe variadics } - arg = args->tdata()[u]; + { + Expression *arg = args->tdata()[u]; assert(arg); + + if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + Type *pt = p->type; + arg = ((FuncExp *)arg)->inferType(NULL, pt); + if (!arg) + goto L1; // try typesafe variadics + } + //printf("arg: %s, type: %s\n", arg->toChars(), arg->type->toChars()); + Type *targ = arg->type; + Type *tprm = wildmatch ? p->type->substWildTo(wildmatch) : p->type; + // Non-lvalues do not match ref or out parameters - if (p->storageClass & (STCref | STCout)) + if (p->storageClass & STCref) + { if (!arg->isLvalue()) + { if (arg->op == TOKstring && tprm->ty == Tsarray) + { if (targ->ty != Tsarray) + targ = new TypeSArray(targ->nextOf(), + new IntegerExp(0, ((StringExp *)arg)->len, + Type::tindex)); + } + else + goto Nomatch; + } + + /* Don't allow static arrays to be passed to mutable references + * to static arrays if the argument cannot be modified. + */ + Type *targb = targ->toBasetype(); + Type *tprmb = tprm->toBasetype(); + //printf("%s\n", targb->toChars()); + //printf("%s\n", tprmb->toChars()); + if (targb->nextOf() && tprmb->ty == Tsarray && + !MODimplicitConv(targb->nextOf()->mod, tprmb->nextOf()->mod)) + goto Nomatch; + + // ref variable behaves like head-const reference + if (!targb->constConv(tprmb)) + goto Nomatch; + } + else if (p->storageClass & STCout) { if (!arg->isLvalue()) goto Nomatch; } - if (p->storageClass & STCref) - { - /* Don't allow static arrays to be passed to mutable references - * to static arrays if the argument cannot be modified. - */ - Type *targb = arg->type->toBasetype(); - Type *tparb = p->type->toBasetype(); - //printf("%s\n", targb->toChars()); - //printf("%s\n", tparb->toChars()); - if (targb->nextOf() && tparb->ty == Tsarray && - !MODimplicitConv(targb->nextOf()->mod, tparb->nextOf()->mod)) - goto Nomatch; - } - - if (p->storageClass & STClazy && p->type->ty == Tvoid && - arg->type->ty != Tvoid) + if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid) m = MATCHconvert; else { - //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), arg->type->toChars(), p->type->toChars()); + //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars()); if (flag) // for partial ordering, value is an irrelevant mockup, just look at the type - m = arg->type->implicitConvTo(p->type); + m = targ->implicitConvTo(tprm); else - m = arg->implicitConvTo(p->type); + m = arg->implicitConvTo(tprm); //printf("match %d\n", m); - if (m == MATCHnomatch && arg->type->wildConvTo(p->type)) - { - wildmatch = TRUE; // mod matched to wild - m = MATCHconst; - } + } } /* prefer matching the element type rather than the array @@ -5702,9 +5996,17 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) { TypeArray *ta = (TypeArray *)tb; for (; u < nargs; u++) { - arg = args->tdata()[u]; + Expression *arg = args->tdata()[u]; assert(arg); #if 1 + if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + Type *pt = tb->nextOf(); + arg = ((FuncExp *)arg)->inferType(NULL, pt); + if (!arg) + goto Nomatch; + } + /* If lazy array of delegates, * convert arg(s) to delegate(s) */ @@ -6102,13 +6404,9 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, for (; i < idents.dim; i++) { id = idents.tdata()[i]; - //printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type); - if (id == Id::offsetof || !e->type) - { e = new DotIdExp(e->loc, e, id); - e = e->semantic(sc); - } - else - e = e->type->dotExp(sc, e, id); + //printf("e: '%s', id: '%s', type = %s\n", e->toChars(), id->toChars(), e->type->toChars()); + e = new DotIdExp(e->loc, e, id); + e = e->semantic(sc); } if (e->op == TOKtype) *pt = e->type; @@ -6440,7 +6738,9 @@ void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymb //printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars()); s = tempinst; if (s) + { //printf("s = %s\n", s->toChars()); s->semantic(sc); + } resolveHelper(loc, sc, s, NULL, pe, pt, ps); if (*pt) *pt = (*pt)->addMod(mod); @@ -6607,6 +6907,7 @@ Type *TypeTypeof::semantic(Loc loc, Scope *sc) { Scope *sc2 = sc->push(); sc2->intypeof++; + sc2->flags |= sc->flags & SCOPEstaticif; exp = exp->semantic(sc2); #if DMDV2 if (exp->type && exp->type->ty == Tfunction && @@ -7395,11 +7696,28 @@ 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); + + Expression *ev = e; for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *v = sym->fields.tdata()[i]; - Expression *fe = new DotVarExp(e->loc, e, v); + Expression *fe; + if (i == 0 && sc->func && sym->fields.dim > 1 && + e->hasSideEffect()) + { + Identifier *id = Lexer::uniqueId("__tup"); + ExpInitializer *ei = new ExpInitializer(e->loc, e); + VarDeclaration *vd = new VarDeclaration(e->loc, NULL, id, ei); + vd->storage_class |= STCctfe | STCref | STCforeach; + + ev = new VarExp(e->loc, vd); + fe = new CommaExp(e->loc, new DeclarationExp(e->loc, vd), ev); + fe = new DotVarExp(e->loc, fe, v); + } + else + fe = new DotVarExp(ev->loc, ev, v); exps->push(fe); } e = new TupleExp(e->loc, exps); @@ -7471,7 +7789,7 @@ L1: if (td) { e = new DotTemplateExp(e->loc, e, td); - e->semantic(sc); + e = e->semantic(sc); return e; } @@ -7491,8 +7809,7 @@ L1: return de; } - Import *timp = s->isImport(); - if (timp) + if (s->isImport() || s->isModule() || s->isPackage()) { e = new DsymbolExp(e->loc, s, 0); e = e->semantic(sc); @@ -7754,7 +8071,10 @@ unsigned TypeStruct::wildConvTo(Type *tprm) return Type::wildConvTo(tprm); if (sym->aliasthis) - return aliasthisOf()->wildConvTo(tprm); + { Type *t = aliasthisOf(); + assert(t); + return t->wildConvTo(tprm); + } return 0; } @@ -7848,14 +8168,42 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) /* Create a TupleExp */ e = e->semantic(sc); // do this before turning on noaccesscheck + + /* If this is called in the middle of a class declaration, + * class Inner { + * int x; + * alias typeof(Inner.tupleof) T; + * int y; + * } + * then Inner.y will be omitted from the tuple. + */ + // Detect that error, and at least try to run semantic() on it if we can + sym->size(e->loc); + Expressions *exps = new Expressions; exps->reserve(sym->fields.dim); + + Expression *ev = e; for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *v = sym->fields.tdata()[i]; // Don't include hidden 'this' pointer if (v->isThisDeclaration()) continue; - Expression *fe = new DotVarExp(e->loc, e, v); + Expression *fe; + if (i == 0 && sc->func && sym->fields.dim > 1 && + e->hasSideEffect()) + { + Identifier *id = Lexer::uniqueId("__tup"); + ExpInitializer *ei = new ExpInitializer(e->loc, e); + VarDeclaration *vd = new VarDeclaration(e->loc, NULL, id, ei); + vd->storage_class |= STCctfe | STCref | STCforeach; + + ev = new VarExp(e->loc, vd); + fe = new CommaExp(e->loc, new DeclarationExp(e->loc, vd), ev); + fe = new DotVarExp(e->loc, fe, v); + } + else + fe = new DotVarExp(e->loc, ev, v); exps->push(fe); } e = new TupleExp(e->loc, exps); @@ -7871,14 +8219,10 @@ 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) @@ -8051,7 +8395,7 @@ L1: if (td) { e = new DotTemplateExp(e->loc, e, td); - e->semantic(sc); + e = e->semantic(sc); return e; } @@ -8071,6 +8415,15 @@ L1: return de; } +#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 + OverloadSet *o = s->isOverloadSet(); if (o) { @@ -8152,7 +8505,6 @@ L1: if (d->parent && d->toParent()->isModule()) { // (e, d) - VarExp *ve = new VarExp(e->loc, d, 1); e = new CommaExp(e->loc, e, ve); e->type = d->type; @@ -8193,9 +8545,14 @@ MATCH TypeClass::implicitConvTo(Type *to) return m; ClassDeclaration *cdto = to->isClassHandle(); - if (cdto && cdto->isBaseOf(sym, NULL)) - { //printf("'to' is base\n"); - return MATCHconvert; + if (cdto) + { + if (cdto->scope) + cdto->semantic(NULL); + if (cdto->isBaseOf(sym, NULL)) + { //printf("'to' is base\n"); + return MATCHconvert; + } } if (global.params.Dversion == 1) @@ -8219,6 +8576,13 @@ MATCH TypeClass::constConv(Type *to) if (ty == to->ty && sym == ((TypeClass *)to)->sym && MODimplicitConv(mod, to->mod)) return MATCHconst; + + /* Conversion derived to const(base) + */ + int offset = 0; + if (to->isBaseOf(this, &offset) && offset == 0 && !to->isMutable()) + return MATCHconvert; + return MATCHnomatch; } @@ -8775,8 +9139,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, 0, mangle ? mangleFlag : 0); } /**************************************** @@ -8794,9 +9157,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); } /**************************************************** @@ -8847,7 +9208,7 @@ void Parameter::toDecoBuffer(OutBuffer *buf, bool mangle) break; default: #ifdef DEBUG - printf("storageClass = x%lx\n", storageClass & (STCin | STCout | STCref | STClazy)); + printf("storageClass = x%llx\n", storageClass & (STCin | STCout | STCref | STClazy)); halt(); #endif assert(0); @@ -8876,8 +9237,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; } @@ -8922,7 +9282,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/dmd2/mtype.h b/dmd2/mtype.h index de57ad2e..fe58c7df 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.h @@ -107,6 +107,7 @@ enum ENUMTY Treturn, Tnull, + Tvector, TMAX }; typedef unsigned char TY; // ENUMTY @@ -203,6 +204,7 @@ struct Type : Object static ClassDeclaration *typeinfoarray; static ClassDeclaration *typeinfostaticarray; static ClassDeclaration *typeinfoassociativearray; + static ClassDeclaration *typeinfovector; static ClassDeclaration *typeinfoenum; static ClassDeclaration *typeinfofunction; static ClassDeclaration *typeinfodelegate; @@ -432,6 +434,36 @@ struct TypeBasic : Type TypeBasic *isTypeBasic(); }; +struct TypeVector : Type +{ + Type *basetype; + + TypeVector(Loc loc, Type *basetype); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + d_uns64 size(Loc loc); + unsigned alignsize(); + Expression *getProperty(Loc loc, Identifier *ident); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + char *toChars(); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toDecoBuffer(OutBuffer *buf, int flag); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + int isintegral(); + int isfloating(); + int isscalar(); + int isunsigned(); + int checkBoolean(); + MATCH implicitConvTo(Type *to); + Expression *defaultInit(Loc loc); + TypeBasic *elementType(); + int isZeroInit(Loc loc); + TypeInfoDeclaration *getTypeInfoDeclaration(); + TypeTuple *toArgTypes(); +}; + struct TypeArray : TypeNext { TypeArray(TY ty, Type *next); @@ -1029,6 +1061,7 @@ int arrayTypeCompatible(Loc loc, Type *t1, Type *t2); int arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2); void MODtoBuffer(OutBuffer *buf, unsigned char mod); int MODimplicitConv(unsigned char modfrom, unsigned char modto); +int MODmethodConv(unsigned char modfrom, unsigned char modto); int MODmerge(unsigned char mod1, unsigned char mod2); #endif /* DMD_MTYPE_H */ diff --git a/dmd2/objfile.h b/dmd2/objfile.h deleted file mode 100644 index a872f4d0..00000000 --- a/dmd2/objfile.h +++ /dev/null @@ -1,61 +0,0 @@ - - -#ifndef OBJFILE_H -#define OBJFILE_H - -#include "root.h" - -typedef void *SymHandle; -typedef unsigned SegOffset; - -enum ObjFormat -{ - NTCOFF, - ELF -}; - -struct ObjFile : File -{ - ObjFile(FileName *); - ~ObjFile(); - - ObjFile *init(ObjFormat); - - void comment(const char *); // insert comment into object file - void modulename(const char *); // set module name - void library(const char *); // add default library - void startaddress(SegHandle seg, SegOffset offset); // set start address - - // Segments - enum SegHandle - { code = 1, - data, bss - }; - - SymHandle defineSym(const char *name, SegHandle seg, SegOffset offset); - SymHandle externSym(const char *name); - - SegOffset write(SegHandle seg, const void *data, unsigned nbytes); - SegOffset writestring(SegHandle seg, char *string); - SegOffset write8(SegHandle seg, unsigned b); - SegOffset write16(SegHandle seg, unsigned w); - SegOffset write32(SegHandle seg, unsigned long v); - SegOffset write64(SegHandle seg, unsigned long long v); - SegOffset fill0(SegHandle seg, unsigned nbytes); - SegOffset align(SegHandle seg, unsigned size); - SegOffset writefixup(SegHandle seg, SymHandle sym, unsigned value, int selfrelative); - - // Non-binding hint as to how big seg will grow - void reserve(SegHandle seg, SegOffset size); - - // Set actual size - void setSize(SegHandle seg, SegOffset size); - - // Get/set offset for subsequent writes - void setOffset(SegHandle seg, SegOffset offset); - SegOffset getOffset(SegHandle seg); - - SegHandle createSeg(const char *name); -}; - -#endif diff --git a/dmd2/opover.c b/dmd2/opover.c index b4e61247..27e2c7d1 100644 --- a/dmd2/opover.c +++ b/dmd2/opover.c @@ -28,6 +28,7 @@ #include "mtype.h" #include "init.h" #include "expression.h" +#include "statement.h" #include "scope.h" #include "id.h" #include "declaration.h" @@ -35,9 +36,9 @@ #include "template.h" #include "scope.h" -static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Parameters *arguments); +static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *arguments); static void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments); -static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments); +static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments, int flags = 0); static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments); /******************************** Expression **************************/ @@ -385,6 +386,7 @@ Expression *ArrayExp::op_overload(Scope *sc) currentDimension = i; // Dimension for $, if required x = x->semantic(sc); + x = resolveProperties(sc, x); if (!x->type) error("%s has no value", x->toChars()); if (lengthVar) @@ -922,21 +924,26 @@ Expression *EqualExp::op_overload(Scope *sc) Type *t1 = e1->type->toBasetype(); Type *t2 = e2->type->toBasetype(); if (t1->ty == Tclass && t2->ty == Tclass) - { - /* Rewrite as: - * .object.opEquals(cast(Object)e1, cast(Object)e2) - * The explicit cast is necessary for interfaces, - * see http://d.puremagic.com/issues/show_bug.cgi?id=4088 - */ - Expression *e1x = e1; //new CastExp(loc, e1, ClassDeclaration::object->getType()); - Expression *e2x = e2; //new CastExp(loc, e2, ClassDeclaration::object->getType()); + { ClassDeclaration *cd1 = t1->isClassHandle(); + ClassDeclaration *cd2 = t2->isClassHandle(); - Expression *e = new IdentifierExp(loc, Id::empty); - e = new DotIdExp(loc, e, Id::object); - e = new DotIdExp(loc, e, Id::eq); - e = new CallExp(loc, e, e1x, e2x); - e = e->semantic(sc); - return e; + if (!(cd1->isCPPinterface() || cd2->isCPPinterface())) + { + /* Rewrite as: + * .object.opEquals(cast(Object)e1, cast(Object)e2) + * The explicit cast is necessary for interfaces, + * see http://d.puremagic.com/issues/show_bug.cgi?id=4088 + */ + Expression *e1x = new CastExp(loc, e1, ClassDeclaration::object->getType()); + Expression *e2x = new CastExp(loc, e2, ClassDeclaration::object->getType()); + + Expression *e = new IdentifierExp(loc, Id::empty); + e = new DotIdExp(loc, e, Id::object); + e = new DotIdExp(loc, e, Id::eq); + e = new CallExp(loc, e, e1x, e2x); + e = e->semantic(sc); + return e; + } } return compare_overload(sc, Id::eq); @@ -1212,34 +1219,161 @@ Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid) } +int ForeachStatement::inferAggregate(Scope *sc, Dsymbol *&sapply) +{ + Identifier *idapply = (op == TOKforeach) ? Id::apply : Id::applyReverse; +#if DMDV2 + Identifier *idhead = (op == TOKforeach) ? Id::Ffront : Id::Fback; + int sliced = 0; +#endif + Type *tab; + AggregateDeclaration *ad; + + while (1) + { + aggr = aggr->semantic(sc); + aggr = resolveProperties(sc, aggr); + aggr = aggr->optimize(WANTvalue); + if (!aggr->type) + goto Lerr; + + tab = aggr->type->toBasetype(); + switch (tab->ty) + { + case Tarray: + case Tsarray: + case Ttuple: + case Taarray: + break; + + case Tclass: + ad = ((TypeClass *)tab)->sym; + goto Laggr; + + case Tstruct: + ad = ((TypeStruct *)tab)->sym; + goto Laggr; + + Laggr: +#if DMDV2 + if (!sliced) + { + sapply = search_function(ad, idapply); + if (sapply) + { // opApply aggregate + break; + } + + Dsymbol *s = search_function(ad, Id::slice); + if (s) + { Expression *rinit = new SliceExp(aggr->loc, aggr, NULL, NULL); + rinit = rinit->trySemantic(sc); + if (rinit) // if application of [] succeeded + { aggr = rinit; + sliced = 1; + continue; + } + } + } + + if (Dsymbol *shead = search_function(ad, idhead)) + { // range aggregate + break; + } + + if (ad->aliasthis) + { + aggr = new DotIdExp(aggr->loc, aggr, ad->aliasthis->ident); + continue; + } +#else + sapply = search_function(ad, idapply); + if (sapply) + { // opApply aggregate + break; + } +#endif + goto Lerr; + + case Tdelegate: + if (aggr->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)aggr; + sapply = de->func->isFuncDeclaration(); + } + break; + + case Terror: + break; + + default: + goto Lerr; + } + break; + } + return 1; + +Lerr: + return 0; +} + /***************************************** * Given array of arguments and an aggregate type, * if any of the argument types are missing, attempt to infer * them from the aggregate type. */ -void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module* from) +int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) { if (!arguments || !arguments->dim) - return; + return 0; + + if (sapply) // prefer opApply + { + for (size_t u = 0; u < arguments->dim; u++) + { Parameter *arg = arguments->tdata()[u]; + if (arg->type) + arg->type = arg->type->semantic(loc, sc); + } + + Expression *ethis; + Type *tab = aggr->type->toBasetype(); + if (tab->ty == Tclass || tab->ty == Tstruct) + ethis = aggr; + else + { assert(tab->ty == Tdelegate && aggr->op == TOKdelegate); + ethis = ((DelegateExp *)aggr)->e1; + } + + /* Look for like an + * int opApply(int delegate(ref Type [, ...]) dg); + * overload + */ + FuncDeclaration *fd = sapply->isFuncDeclaration(); + if (fd) + { sapply = inferApplyArgTypesX(ethis, fd, arguments); + } +#if 0 + TemplateDeclaration *td = sapply->isTemplateDeclaration(); + if (td) + { inferApplyArgTypesZ(td, arguments); + } +#endif + return sapply ? 1 : 0; + } /* Return if no arguments need types. */ - for (size_t u = 0; 1; u++) - { if (u == arguments->dim) - return; - Parameter *arg = arguments->tdata()[u]; + for (size_t u = 0; u < arguments->dim; u++) + { Parameter *arg = arguments->tdata()[u]; if (!arg->type) break; } - Dsymbol *s; AggregateDeclaration *ad; Parameter *arg = arguments->tdata()[0]; Type *taggr = aggr->type; - if (!taggr) - return; + assert(taggr); Type *tab = taggr->toBasetype(); switch (tab->ty) { @@ -1279,25 +1413,19 @@ void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Mo goto Laggr; Laggr: - s = search_function(ad, - (op == TOKforeach_reverse) ? Id::applyReverse - : Id::apply); - if (s) - goto Lapply; // prefer opApply - if (arguments->dim == 1) { if (!arg->type) { /* Look for a head() or rear() overload */ - Identifier *id = (op == TOKforeach) ? Id::Fhead : Id::Ftoe; + Identifier *id = (op == TOKforeach) ? Id::Ffront : Id::Fback; Dsymbol *s = search_function(ad, id); FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; if (!fd) { if (s && s->isTemplateDeclaration()) break; - goto Lapply; + break; } // Resolve inout qualifier of front type arg->type = fd->type->nextOf(); @@ -1306,80 +1434,86 @@ void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Mo } break; } - - Lapply: - { /* Look for an - * int opApply(int delegate(ref Type [, ...]) dg); - * overload - */ - if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { inferApplyArgTypesX(from, fd, arguments); - break; - } -#if 0 - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { inferApplyArgTypesZ(td, arguments); - break; - } -#endif - } break; - } case Tdelegate: { - if (0 && aggr->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)aggr; - - FuncDeclaration *fd = de->func->isFuncDeclaration(); - if (fd) - inferApplyArgTypesX(from, fd, arguments); - } - else - { - inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments); - } + if (!inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments)) + return 0; break; } default: break; // ignore error, caught later } + return 1; } -/******************************** - * Recursive helper function, - * analogous to func.overloadResolveX(). - */ - -int fp3(void *param, FuncDeclaration *f) +static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *arguments) { - Parameters *arguments = (Parameters *)param; - TypeFunction *tf = (TypeFunction *)f->type; - if (inferApplyArgTypesY(tf, arguments) == 1) - return 0; - if (arguments->dim == 0) - return 1; - return 0; -} + struct Param3 + { + Parameters *arguments; + int mod; + MATCH match; + FuncDeclaration *fd_best; + FuncDeclaration *fd_ambig; -static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Parameters *arguments) -{ - overloadApply(fstart, &fp3, arguments); + static int fp(void *param, FuncDeclaration *f) + { + Param3 *p = (Param3 *)param; + TypeFunction *tf = (TypeFunction *)f->type; + MATCH m = MATCHexact; + + if (f->isThis()) + { if (!MODimplicitConv(p->mod, tf->mod)) + m = MATCHnomatch; + else if (p->mod != tf->mod) + m = MATCHconst; + } + if (!inferApplyArgTypesY(tf, p->arguments, 1)) + m = MATCHnomatch; + + if (m > p->match) + { p->fd_best = f; + p->fd_ambig = NULL; + p->match = m; + } + else if (m == p->match) + p->fd_ambig = f; + return 0; + } + }; + + Param3 p; + p.arguments = arguments; + p.mod = ethis->type->mod; + p.match = MATCHnomatch; + p.fd_best = NULL; + p.fd_ambig = NULL; + overloadApply(fstart, &Param3::fp, &p); + if (p.fd_best) + { + inferApplyArgTypesY((TypeFunction *)p.fd_best->type, arguments); + if (p.fd_ambig) + { ::error(ethis->loc, "%s.%s matches more than one declaration:\n\t%s(%d):%s\nand:\n\t%s(%d):%s", + ethis->toChars(), fstart->ident->toChars(), + p.fd_best ->loc.filename, p.fd_best ->loc.linnum, p.fd_best ->type->toChars(), + p.fd_ambig->loc.filename, p.fd_ambig->loc.linnum, p.fd_ambig->type->toChars()); + p.fd_best = NULL; + } + } + return p.fd_best; } /****************************** * Infer arguments from type of function. * Returns: - * 0 match for this function - * 1 no match for this function + * 1 match for this function + * 0 no match for this function */ -static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments) +static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments, int flags) { size_t nparams; Parameter *p; @@ -1406,22 +1540,16 @@ static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments) Parameter *param = Parameter::getNth(tf->parameters, u); if (arg->type) { if (!arg->type->equals(param->type)) - { - /* Cannot resolve argument types. Indicate an - * error by setting the number of arguments to 0. - */ - arguments->dim = 0; - goto Lmatch; - } - continue; + goto Lnomatch; } - arg->type = param->type; + else if (!flags) + arg->type = param->type; } Lmatch: - return 0; + return 1; Lnomatch: - return 1; + return 0; } /******************************************* diff --git a/dmd2/optimize.c b/dmd2/optimize.c index c540557b..82bfe9c1 100644 --- a/dmd2/optimize.c +++ b/dmd2/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 @@ -262,6 +262,7 @@ Expression *TypeExp::optimize(int result) Expression *UnaExp::optimize(int result) { + //printf("UnaExp::optimize() %s\n", toChars()); e1 = e1->optimize(result); return this; } @@ -670,7 +671,6 @@ Expression *CastExp::optimize(int result) // We can convert 'head const' to mutable if (to->constOf()->equals(e1->type->constOf())) -// if (to->constConv(e1->type) >= MATCHconst) { e1->type = type; if (X) printf(" returning5 %s\n", e1->toChars()); @@ -715,8 +715,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); } } @@ -810,8 +810,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) @@ -955,13 +955,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) @@ -1106,8 +1103,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 @@ -1124,7 +1125,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; @@ -1155,7 +1160,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/dmd2/parse.c b/dmd2/parse.c index 99519b72..17ae1df5 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -231,6 +231,7 @@ Dsymbols *Parser::parseDeclDefs(int once) case TOKsuper: case TOKtypeof: case TOKdot: + case TOKvector: Ldeclaration: a = parseDeclarations(STCundefined, NULL); decldefs->append(a); @@ -820,6 +821,23 @@ TypeQualified *Parser::parseTypeof() } #endif +/*********************************** + * Parse __vector(type). + * Current token is on the '__vector'. + */ + +#if DMDV2 +Type *Parser::parseVector() +{ + Loc loc = this->loc; + nextToken(); + check(TOKlparen); + Type *tb = parseType(); + check(TOKrparen); + return new TypeVector(loc, tb); +} +#endif + /*********************************** * Parse extern (linkage) * The parser is on the 'extern' token. @@ -1247,7 +1265,7 @@ DeleteDeclaration *Parser::parseDelete() * Parse parameter list. */ -Parameters *Parser::parseParameters(int *pvarargs) +Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) { Parameters *arguments = new Parameters(); int varargs = 0; @@ -1351,17 +1369,32 @@ Parameters *Parser::parseParameters(int *pvarargs) default: Ldefault: - stc = storageClass & (STCin | STCout | STCref | STClazy); + { stc = storageClass & (STCin | STCout | STCref | STClazy); if (stc & (stc - 1)) // if stc is not a power of 2 error("incompatible parameter storage classes"); if ((storageClass & (STCconst | STCout)) == (STCconst | STCout)) error("out cannot be const"); if ((storageClass & (STCimmutable | STCout)) == (STCimmutable | STCout)) error("out cannot be immutable"); - if ((storageClass & STCscope) && - (storageClass & (STCref | STCout))) + if ((storageClass & STCscope) && (storageClass & (STCref | STCout))) error("scope cannot be ref or out"); - at = parseType(&ai); + + Token *t; + if (tpl && !stc && token.value == TOKidentifier && + (t = peek(&token), (t->value == TOKcomma || t->value == TOKrparen))) + { Identifier *id = Lexer::uniqueId("__T"); + at = new TypeIdentifier(loc, id); + if (!*tpl) + *tpl = new TemplateParameters(); + TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL); + (*tpl)->push(tp); + + ai = token.ident; + nextToken(); + } + else + at = parseType(&ai); + ae = NULL; if (token.value == TOKassign) // = defaultArg { nextToken(); @@ -1394,6 +1427,7 @@ Parameters *Parser::parseParameters(int *pvarargs) goto L1; } break; + } } break; } @@ -1494,6 +1528,11 @@ EnumDeclaration *Parser::parseEnum() } addComment(em, comment); comment = token.blockComment; + + if (token.value == TOKeof) + { error("premature end of file"); + break; + } } nextToken(); } @@ -1627,26 +1666,33 @@ BaseClasses *Parser::parseBaseClasses() for (; 1; nextToken()) { + bool prot = false; enum PROT protection = PROTpublic; switch (token.value) { case TOKprivate: + prot = true; protection = PROTprivate; nextToken(); break; case TOKpackage: + prot = true; protection = PROTpackage; nextToken(); break; case TOKprotected: + prot = true; protection = PROTprotected; nextToken(); break; case TOKpublic: + prot = true; protection = PROTpublic; 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); @@ -1920,6 +1966,11 @@ Dsymbol *Parser::parseMixin() tqual = parseTypeof(); check(TOKdot); } + else if (token.value == TOKvector) + { + tqual = parseVector(); + check(TOKdot); + } if (token.value != TOKidentifier) { error("identifier expected, not %s", token.toChars()); @@ -2018,56 +2069,11 @@ Objects *Parser::parseTemplateArgumentList2() { // Template argument is an expression Expression *ea = parseAssignExp(); - if (ea->op == TOKfunction) - { FuncLiteralDeclaration *fd = ((FuncExp *)ea)->fd; - if (fd->type->ty == Tfunction) - { - TypeFunction *tf = (TypeFunction *)fd->type; - /* If there are parameters that consist of only an identifier, - * rather than assuming the identifier is a type, as we would - * for regular function declarations, assume the identifier - * is the parameter name, and we're building a template with - * a deduced type. - */ - TemplateParameters *tpl = NULL; - for (size_t i = 0; i < tf->parameters->dim; i++) - { Parameter *param = tf->parameters->tdata()[i]; - if (param->ident == NULL && - param->type && - param->type->ty == Tident && - ((TypeIdentifier *)param->type)->idents.dim == 0 - ) - { - /* Switch parameter type to parameter identifier, - * parameterize with template type parameter _T - */ - TypeIdentifier *pt = (TypeIdentifier *)param->type; - param->ident = pt->ident; - Identifier *id = Lexer::uniqueId("__T"); - param->type = new TypeIdentifier(pt->loc, id); - TemplateParameter *tp = new TemplateTypeParameter(fd->loc, id, NULL, NULL); - if (!tpl) - tpl = new TemplateParameters(); - tpl->push(tp); - } - } - - if (tpl) - { // Wrap a template around function fd - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(fd); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, 0); - tempdecl->literal = 1; // it's a template 'literal' - tiargs->push(tempdecl); - goto L1; - } - } - } - - tiargs->push(ea); + if (ea->op == TOKfunction && ((FuncExp *)ea)->td) + tiargs->push(((FuncExp *)ea)->td); + else + tiargs->push(ea); } - L1: if (token.value != TOKcomma) break; nextToken(); @@ -2094,6 +2100,10 @@ Objects *Parser::parseTemplateArgument() ta = new TypeIdentifier(loc, token.ident); goto LabelX; + case TOKvector: + ta = parseVector(); + goto LabelX; + case BASIC_TYPES_X(ta): tiargs->push(ta); nextToken(); @@ -2369,6 +2379,10 @@ Type *Parser::parseBasicType() tid = parseTypeof(); goto Lident2; + case TOKvector: + t = parseVector(); + break; + case TOKconst: // const(type) nextToken(); @@ -2875,6 +2889,13 @@ L2: { Declaration *v; Initializer *init = NULL; + /* Aliases can no longer have multiple declarators, storage classes, + * linkages, or auto declarations. + * These never made any sense, anyway. + * The code below needs to be fixed to reject them. + * The grammar has already been fixed to preclude them. + */ + if (token.value == TOKassign) { nextToken(); @@ -3434,13 +3455,14 @@ Statement *Parser::parseStatement(int flags) Identifier *ident = token.ident; nextToken(); nextToken(); - s = parseStatement(PSsemi); + s = parseStatement(PSsemi_ok); s = new LabelStatement(loc, ident, s); break; } // fallthrough to TOKdot case TOKdot: case TOKtypeof: + case TOKvector: if (isDeclaration(&token, 2, TOKreserved, NULL)) goto Ldeclaration; else @@ -3559,7 +3581,6 @@ Statement *Parser::parseStatement(int flags) case TOKgshared: case TOKat: #endif -// case TOKtypeof: Ldeclaration: { Dsymbols *a; @@ -3680,8 +3701,15 @@ Statement *Parser::parseStatement(int flags) } case TOKsemicolon: - if (!(flags & PSsemi)) - error("use '{ }' for an empty statement, not a ';'"); + if (!(flags & PSsemi_ok)) + { + if (flags & PSsemi) + { if (global.params.warnings) + warning(loc, "use '{ }' for an empty statement, not a ';'"); + } + else + error("use '{ }' for an empty statement, not a ';'"); + } nextToken(); s = new ExpStatement(loc, (Expression *)NULL); break; @@ -3865,13 +3893,13 @@ Statement *Parser::parseStatement(int flags) else if (token.value == TOKidentifier) { Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) + if (t->value == TOKsemicolon) { arg = new Parameter(0, NULL, token.ident, NULL); nextToken(); nextToken(); - if (1 || !global.params.useDeprecated) - error("if (v; e) is deprecated, use if (auto v = e)"); + if (!global.params.useDeprecated) + error("if (v%s e) is deprecated, use if (auto v = e)", t->toChars()); } } @@ -4255,7 +4283,7 @@ Statement *Parser::parseStatement(int flags) s = parseStatement(PSsemi | PScurlyscope); #if DMDV2 if (!global.params.useDeprecated) - error("volatile statements deprecated; used synchronized statements instead"); + error("volatile statements deprecated; use synchronized statements instead"); #endif s = new VolatileStatement(loc, s); break; @@ -4531,6 +4559,7 @@ int Parser::isBasicType(Token **pt) goto Ldot; case TOKtypeof: + case TOKvector: /* typeof(exp).identifier... */ t = peek(t); @@ -4721,9 +4750,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; @@ -5092,6 +5124,9 @@ Expression *Parser::parsePrimaryExp() switch (token.value) { case TOKidentifier: + if (peekNext() == TOKgoesto) + goto case_delegate; + id = token.ident; nextToken(); if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin) @@ -5284,6 +5319,13 @@ Expression *Parser::parsePrimaryExp() break; } + case TOKvector: + { + t = parseVector(); + e = new TypeExp(loc, t); + break; + } + case TOKtypeid: { nextToken(); @@ -5433,9 +5475,14 @@ Expression *Parser::parsePrimaryExp() } case TOKlparen: - if (peekPastParen(&token)->value == TOKlcurly) + { enum TOK past = peekPastParen(&token)->value; + + if (past == TOKgoesto) + { // (arguments) => expression + goto case_delegate; + } + else if (past == TOKlcurly) { // (arguments) { statements... } - save = TOKdelegate; goto case_delegate; } // ( expression ) @@ -5444,6 +5491,7 @@ Expression *Parser::parsePrimaryExp() e->parens = 1; check(loc, TOKrparen); break; + } case TOKlbracket: { /* Parse array literals and associative array literals: @@ -5484,53 +5532,102 @@ Expression *Parser::parsePrimaryExp() } case TOKlcurly: - // { statements... } - save = TOKdelegate; - goto case_delegate; - case TOKfunction: case TOKdelegate: - save = token.value; - nextToken(); case_delegate: { - /* function type(parameters) { body } pure nothrow - * delegate type(parameters) { body } pure nothrow - * (parameters) { body } - * { body } - */ - Parameters *arguments; - int varargs; - FuncLiteralDeclaration *fd; - Type *t; + TemplateParameters *tpl = NULL; + Parameters *parameters = NULL; + int varargs = 0; + Type *tret = NULL; StorageClass stc = 0; + enum TOK save = TOKreserved; + Loc loc = this->loc; - if (token.value == TOKlcurly) + switch (token.value) { - t = NULL; - varargs = 0; - arguments = new Parameters(); + case TOKfunction: + case TOKdelegate: + save = token.value; + nextToken(); + if (token.value != TOKlparen && token.value != TOKlcurly) + { // function type (parameters) { statements... } + // delegate type (parameters) { statements... } + tret = parseBasicType(); + tret = parseBasicType2(tret); // function return type + } + + if (token.value == TOKlparen) + { // function (parameters) { statements... } + // delegate (parameters) { statements... } + } + else + { // function { statements... } + // delegate { statements... } + break; + } + /* fall through to TOKlparen */ + + case TOKlparen: + Lparen: + { // (parameters) => expression + // (parameters) { statements... } + parameters = parseParameters(&varargs, &tpl); + stc = parsePostfix(); + if (stc & (STCconst | STCimmutable | STCshared | STCwild)) + error("const/immutable/shared/inout attributes are only valid for non-static member functions"); + break; + } + case TOKlcurly: + // { statements... } + break; + + case TOKidentifier: + { // identifier => expression + parameters = new Parameters(); + Identifier *id = Lexer::uniqueId("__T"); + Type *t = new TypeIdentifier(loc, id); + parameters->push(new Parameter(0, t, token.ident, NULL)); + + tpl = new TemplateParameters(); + TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL); + tpl->push(tp); + + nextToken(); + break; + } + default: + assert(0); + } + + if (!parameters) + parameters = new Parameters(); + TypeFunction *tf = new TypeFunction(parameters, tret, varargs, linkage, stc); + FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL); + + if (token.value == TOKgoesto) + { + check(TOKgoesto); + Loc loc = this->loc; + Expression *ae = parseAssignExp(); + fd->fbody = new ReturnStatement(loc, ae); + fd->endloc = this->loc; } else { - if (token.value == TOKlparen) - t = NULL; - else - { - t = parseBasicType(); - t = parseBasicType2(t); // function return type - } - arguments = parseParameters(&varargs); - stc = parsePostfix(); - if (stc & (STCconst | STCimmutable | STCshared | STCwild)) - error("const/immutable/shared/inout attributes are only valid for non-static member functions"); + parseContracts(fd); } - TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage, stc); + TemplateDeclaration *td = NULL; + if (tpl) + { // Wrap a template around function fd + Dsymbols *decldefs = new Dsymbols(); + decldefs->push(fd); + td = new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, 0); + td->literal = 1; // it's a template 'literal' + } - fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL); - parseContracts(fd); - e = new FuncExp(loc, fd); + e = new FuncExp(loc, fd, td); break; } @@ -5853,6 +5950,7 @@ Expression *Parser::parseUnaryExp() case TOKfunction: case TOKdelegate: case TOKtypeof: + case TOKvector: #if DMDV2 case TOKfile: case TOKline: @@ -6336,7 +6434,7 @@ Expressions *Parser::parseArguments() { nextToken(); - while (token.value != endtok) + while (token.value != endtok && token.value != TOKeof) { arg = parseAssignExp(); arguments->push(arg); @@ -6528,6 +6626,7 @@ void initPrecedence() precedence[TOKcast] = PREC_unary; #if DMDV2 + precedence[TOKvector] = PREC_unary; precedence[TOKpow] = PREC_pow; #endif diff --git a/dmd2/parse.h b/dmd2/parse.h index 0e43cc25..716e775a 100644 --- a/dmd2/parse.h +++ b/dmd2/parse.h @@ -52,10 +52,11 @@ struct StaticAssert; enum ParseStatementFlags { - PSsemi = 1, // empty ';' statements are allowed + PSsemi = 1, // empty ';' statements are allowed, but deprecated PSscope = 2, // start a new scope PScurly = 4, // { } statement is required PScurlyscope = 8, // { } starts a new scope + PSsemi_ok = 0x10, // empty ';' are really ok }; @@ -85,6 +86,7 @@ struct Parser : Lexer Objects *parseTemplateArgument(); StaticAssert *parseStaticAssert(); TypeQualified *parseTypeof(); + Type *parseVector(); enum LINK parseLinkage(); Condition *parseDebugCondition(); Condition *parseVersionCondition(); @@ -100,7 +102,7 @@ struct Parser : Lexer UnitTestDeclaration *parseUnitTest(); NewDeclaration *parseNew(); DeleteDeclaration *parseDelete(); - Parameters *parseParameters(int *pvarargs); + Parameters *parseParameters(int *pvarargs, TemplateParameters **tpl = NULL); EnumDeclaration *parseEnum(); Dsymbol *parseAggregate(); BaseClasses *parseBaseClasses(); diff --git a/dmd2/root/port.c b/dmd2/root/port.c index 9718c3fe..232faefc 100644 --- a/dmd2/root/port.c +++ b/dmd2/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/dmd2/root/rmem.c b/dmd2/root/rmem.c new file mode 100644 index 00000000..2504ab93 --- /dev/null +++ b/dmd2/root/rmem.c @@ -0,0 +1,155 @@ + +/* Copyright (c) 2000 Digital Mars */ +/* All Rights Reserved */ + +#include +#include +#include + +#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 +#include "../root/rmem.h" +#else +#include "rmem.h" +#endif + +/* This implementation of the storage allocator uses the standard C allocation package. + */ + +Mem mem; + +void Mem::init() +{ +} + +char *Mem::strdup(const char *s) +{ + char *p; + + if (s) + { + p = ::strdup(s); + if (p) + return p; + error(); + } + return NULL; +} + +void *Mem::malloc(size_t size) +{ void *p; + + if (!size) + p = NULL; + else + { + p = ::malloc(size); + if (!p) + error(); + } + return p; +} + +void *Mem::calloc(size_t size, size_t n) +{ void *p; + + if (!size || !n) + p = NULL; + else + { + p = ::calloc(size, n); + if (!p) + error(); + } + return p; +} + +void *Mem::realloc(void *p, size_t size) +{ + if (!size) + { if (p) + { ::free(p); + p = NULL; + } + } + else if (!p) + { + p = ::malloc(size); + if (!p) + error(); + } + else + { + void *psave = p; + p = ::realloc(psave, size); + if (!p) + { free(psave); + error(); + } + } + return p; +} + +void Mem::free(void *p) +{ + if (p) + ::free(p); +} + +void *Mem::mallocdup(void *o, size_t size) +{ void *p; + + if (!size) + p = NULL; + else + { + p = ::malloc(size); + if (!p) + error(); + else + memcpy(p,o,size); + } + return p; +} + +void Mem::error() +{ + printf("Error: out of memory\n"); + exit(EXIT_FAILURE); +} + +void Mem::fullcollect() +{ +} + +void Mem::mark(void *pointer) +{ + (void) pointer; // necessary for VC /W4 +} + +void Mem::setStackBottom(void *bottom) +{ +} + +void Mem::addroots(char* pStart, char* pEnd) +{ +} + + +/* =================================================== */ + +void * operator new(size_t m_size) +{ + void *p = malloc(m_size); + if (p) + return p; + printf("Error: out of memory\n"); + exit(EXIT_FAILURE); + return p; +} + +void operator delete(void *p) +{ + free(p); +} + + diff --git a/dmd2/sideeffect.c b/dmd2/sideeffect.c new file mode 100644 index 00000000..a80f874e --- /dev/null +++ b/dmd2/sideeffect.c @@ -0,0 +1,250 @@ + +// 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" + +int lambdaHasSideEffect(Expression *e, void *param); + +/******************************************** + * Determine if Expression has any side effects. + */ + +bool Expression::hasSideEffect() +{ + bool has = FALSE; + apply(&lambdaHasSideEffect, &has); + return has; +} + +int lambdaHasSideEffect(Expression *e, void *param) +{ + bool *phas = (bool *)param; + switch (e->op) + { + // Sort the cases by most frequently used first + case TOKassign: + case TOKplusplus: + case TOKminusminus: + case TOKdeclaration: + case TOKconstruct: + case TOKblit: + case TOKaddass: + case TOKminass: + case TOKcatass: + case TOKmulass: + case TOKdivass: + case TOKmodass: + case TOKshlass: + case TOKshrass: + case TOKushrass: + case TOKandass: + case TOKorass: + case TOKxorass: + case TOKpowass: + case TOKin: + case TOKremove: + case TOKassert: + case TOKhalt: + case TOKdelete: + case TOKnew: + case TOKnewanonclass: + *phas = TRUE; + break; + + case TOKcall: + { CallExp *ce = (CallExp *)e; + + /* Calling a function or delegate that is pure nothrow + * has no side effects. + */ + if (ce->e1->type) + { + Type *t = ce->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) + ) + { + } + else + *phas = TRUE; + } + break; + } + + case TOKcast: + { CastExp *ce = (CastExp *)e; + + /* if: + * cast(classtype)func() // because it may throw + */ + if (ce->to->ty == Tclass && ce->e1->op == TOKcall && ce->e1->type->ty == Tclass) + *phas = TRUE; + break; + } + + default: + break; + } + return *phas; // stop walking if we determine this expression has side effects +} + + +/*********************************** + * The result of this expression will be discarded. + * Complain if the operation has no side effects (and hence is meaningless). + */ +void Expression::discardValue() +{ + bool has = FALSE; + lambdaHasSideEffect(this, &has); + if (!has) + { + switch (op) + { + case TOKcast: + { CastExp *ce = (CastExp *)this; + if (ce->to->equals(Type::tvoid)) + { /* + * Don't complain about an expression with no effect if it was cast to void + */ + ce->e1->useValue(); + break; + } + goto Ldefault; // complain + } + + case TOKerror: + break; + + case TOKcall: + /* Don't complain about calling functions with no effect, + * because purity and nothrow are inferred, and because some of the + * runtime library depends on it. Needs more investigation. + */ + break; + + case TOKimport: + error("%s has no effect", toChars()); + break; + + case TOKandand: + { AndAndExp *aae = (AndAndExp *)this; + aae->e1->useValue(); + aae->e2->discardValue(); + break; + } + + case TOKoror: + { OrOrExp *ooe = (OrOrExp *)this; + ooe->e1->useValue(); + ooe->e2->discardValue(); + break; + } + + case TOKquestion: + { CondExp *ce = (CondExp *)this; + ce->econd->useValue(); + ce->e1->discardValue(); + ce->e2->discardValue(); + break; + } + + case TOKcomma: + { CommaExp *ce = (CommaExp *)this; + + /* Check for compiler-generated code of the form auto __tmp, e, __tmp; + * In such cases, only check e for side effect (it's OK for __tmp to have + * no side effect). + * See Bugzilla 4231 for discussion + */ + CommaExp* firstComma = ce; + while (firstComma->e1->op == TOKcomma) + firstComma = (CommaExp *)firstComma->e1; + if (firstComma->e1->op == TOKdeclaration && + ce->e2->op == TOKvar && + ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)ce->e2)->var) + { + ce->e1->useValue(); + break; + } + // Don't check e1 until we cast(void) the a,b code generation + //ce->e1->discardValue(); + ce->e2->discardValue(); + break; + } + + case TOKtuple: + /* Pass without complaint if any of the tuple elements have side effects. + * Ideally any tuple elements with no side effects should raise an error, + * this needs more investigation as to what is the right thing to do. + */ + if (!hasSideEffect()) + goto Ldefault; + break; + + default: + Ldefault: + error("%s has no effect in expression (%s)", + Token::toChars(op), toChars()); + break; + } + } + else + { + useValue(); + } +} + +/* This isn't used yet because the only way an expression has an unused sub-expression + * is with the CommaExp, and that currently generates messages from rewrites into comma + * expressions. Needs more investigation. + */ +void Expression::useValue() +{ +#if 0 + // Disabled because need to cast(void) the a,b code generation + void *p; + apply(&lambdaUseValue, &p); +#endif +} + +#if 0 +int lambdaUseValue(Expression *e, void *param) +{ + switch (e->op) + { + case TOKcomma: + { CommaExp *ce = (CommaExp *)e; + discardValue(ce->E1); + break; + } + + default: + break; + } + return 0; +} +#endif diff --git a/dmd2/statement.c b/dmd2/statement.c index 60ea2c89..4dd913a7 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -292,7 +292,7 @@ Statement *ExpStatement::semantic(Scope *sc) exp = exp->semantic(sc); exp = exp->addDtorHook(sc); exp = resolveProperties(sc, exp); - exp->checkSideEffect(0); + exp->discardValue(); exp = exp->optimize(0); } return this; @@ -337,7 +337,7 @@ Statement *ExpStatement::scopeCode(Scope *sc, Statement **sentry, Statement **se { DeclarationExp *de = (DeclarationExp *)(exp); VarDeclaration *v = de->declaration->isVarDeclaration(); - if (v && !v->noscope) + if (v && !v->noscope && !v->isDataseg()) { Expression *e = v->edtor; if (e) @@ -485,10 +485,10 @@ Statement *CompoundStatement::syntaxCopy() Statements *a = new Statements(); a->setDim(statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s) s = s->syntaxCopy(); - a->tdata()[i] = s; + (*a)[i] = s; } CompoundStatement *cs = new CompoundStatement(loc, a); return cs; @@ -503,7 +503,7 @@ Statement *CompoundStatement::semantic(Scope *sc) #if 0 for (size_t i = 0; i < statements->dim; i++) { - s = statements->tdata()[i]; + s = (*statements)[i]; if (s) printf("[%d]: %s", i, s->toChars()); } @@ -511,7 +511,7 @@ Statement *CompoundStatement::semantic(Scope *sc) for (size_t i = 0; i < statements->dim; ) { - s = statements->tdata()[i]; + s = (*statements)[i]; if (s) { Statements *a = s->flatten(sc); @@ -522,25 +522,26 @@ Statement *CompoundStatement::semantic(Scope *sc) continue; } s = s->semantic(sc); - statements->tdata()[i] = s; + (*statements)[i] = s; if (s) { Statement *sentry; Statement *sexception; Statement *sfinally; - statements->tdata()[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally); + (*statements)[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally); if (sentry) { sentry = sentry->semantic(sc); statements->insert(i, sentry); i++; } + if (sexception) + sexception = sexception->semantic(sc); if (sexception) { if (i + 1 == statements->dim && !sfinally) { - sexception = sexception->semantic(sc); } else { @@ -555,15 +556,18 @@ Statement *CompoundStatement::semantic(Scope *sc) Statements *a = new Statements(); for (size_t j = i + 1; j < statements->dim; j++) { - a->push(statements->tdata()[j]); + a->push((*statements)[j]); } 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); + } Catches *catches = new Catches(); Catch *ctch = new Catch(0, NULL, id, handler); @@ -594,7 +598,7 @@ Statement *CompoundStatement::semantic(Scope *sc) Statements *a = new Statements(); for (size_t j = i + 1; j < statements->dim; j++) { - a->push(statements->tdata()[j]); + a->push((*statements)[j]); } Statement *body = new CompoundStatement(0, a); s = new TryFinallyStatement(0, body, sfinally); @@ -610,7 +614,7 @@ Statement *CompoundStatement::semantic(Scope *sc) } if (statements->dim == 1 && !isAsmBlockStatement()) { - return statements->tdata()[0]; + return (*statements)[0]; } return this; } @@ -625,7 +629,7 @@ ReturnStatement *CompoundStatement::isReturnStatement() ReturnStatement *rs = NULL; for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s) { rs = s->isReturnStatement(); @@ -641,7 +645,7 @@ Statement *CompoundStatement::last() Statement *s = NULL; for (size_t i = statements->dim; i; --i) - { s = statements->tdata()[i - 1]; + { s = (*statements)[i - 1]; if (s) { s = s->last(); @@ -655,7 +659,7 @@ Statement *CompoundStatement::last() void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s) s->toCBuffer(buf, hgs); } @@ -664,7 +668,7 @@ void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) int CompoundStatement::usesEH() { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s && s->usesEH()) return TRUE; } @@ -677,7 +681,7 @@ int CompoundStatement::blockExit(bool mustNotThrow) int result = BEfallthru; Statement *slast = NULL; for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s) { //printf("result = x%x\n", result); @@ -722,7 +726,7 @@ int CompoundStatement::comeFrom() //printf("CompoundStatement::comeFrom()\n"); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (!s) continue; @@ -735,7 +739,7 @@ int CompoundStatement::comeFrom() int CompoundStatement::isEmpty() { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s && !s->isEmpty()) return FALSE; } @@ -756,10 +760,10 @@ Statement *CompoundDeclarationStatement::syntaxCopy() Statements *a = new Statements(); a->setDim(statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s) s = s->syntaxCopy(); - a->tdata()[i] = s; + (*a)[i] = s; } CompoundDeclarationStatement *cs = new CompoundDeclarationStatement(loc, a); return cs; @@ -769,7 +773,7 @@ void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { int nwritten = 0; for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; ExpStatement *ds; if (s && (ds = s->isExpStatement()) != NULL && @@ -833,10 +837,10 @@ Statement *UnrolledLoopStatement::syntaxCopy() Statements *a = new Statements(); a->setDim(statements->dim); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s) s = s->syntaxCopy(); - a->tdata()[i] = s; + (*a)[i] = s; } UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); return cs; @@ -854,12 +858,12 @@ Statement *UnrolledLoopStatement::semantic(Scope *sc) for (size_t i = 0; i < statements->dim; i++) { - Statement *s = statements->tdata()[i]; + Statement *s = (*statements)[i]; if (s) { //printf("[%d]: %s\n", i, s->toChars()); s = s->semantic(scd); - statements->tdata()[i] = s; + (*statements)[i] = s; } } @@ -876,7 +880,7 @@ void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (size_t i = 0; i < statements->dim; i++) { Statement *s; - s = statements->tdata()[i]; + s = (*statements)[i]; if (s) s->toCBuffer(buf, hgs); } @@ -898,7 +902,7 @@ int UnrolledLoopStatement::hasContinue() int UnrolledLoopStatement::usesEH() { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s && s->usesEH()) return TRUE; } @@ -909,7 +913,7 @@ int UnrolledLoopStatement::blockExit(bool mustNotThrow) { int result = BEfallthru; for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s) { int r = s->blockExit(mustNotThrow); @@ -925,7 +929,7 @@ int UnrolledLoopStatement::comeFrom() //printf("UnrolledLoopStatement::comeFrom()\n"); for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (!s) continue; @@ -1419,46 +1423,21 @@ Statement *ForeachStatement::semantic(Scope *sc) if (func->fes) func = func->fes->func; -Lretry: - aggr = aggr->semantic(sc); - aggr = resolveProperties(sc, aggr); - aggr = aggr->optimize(WANTvalue); - if (!aggr->type) + if (!inferAggregate(sc, sapply)) { error("invalid foreach aggregate %s", aggr->toChars()); return this; } - inferApplyArgTypes(op, arguments, aggr, sc->module); - /* Check for inference errors */ - if (dim != arguments->dim) + if (!inferApplyArgTypes(sc, sapply)) { //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); error("cannot uniquely infer foreach argument types"); return this; } - Expression *prelude = NULL; - if (aggr->op == TOKcomma) - { - Expression **pe = &aggr; - while (((CommaExp *)(*pe))->e2->op == TOKcomma) - pe = &((CommaExp *)(*pe))->e2; - if (pe == &aggr) - { - prelude = ((CommaExp *)(*pe))->e1; - aggr = ((CommaExp *)(*pe))->e2; - } - else - { - prelude = aggr; - aggr = ((CommaExp *)(*pe))->e2; - *pe = ((CommaExp *)(*pe))->e1; - } - } - Type *tab = aggr->type->toBasetype(); if (tab->ty == Ttuple) // don't generate new scope for tuple loops @@ -1474,9 +1453,19 @@ Lretry: //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); size_t n; TupleExp *te = NULL; + Expression *prelude = NULL; if (aggr->op == TOKtuple) // expression tuple { te = (TupleExp *)aggr; n = te->exps->dim; + + if (te->exps->dim > 0 && (*te->exps)[0]->op == TOKdotvar && + ((DotVarExp *)(*te->exps)[0])->e1->isTemp()) + { + CommaExp *ce = (CommaExp *)((DotVarExp *)(*te->exps)[0])->e1; + + prelude = ce->e1; + ((DotVarExp *)(*te->exps)[0])->e1 = ce->e2; + } } else if (aggr->op == TOKtype) // type tuple { @@ -1489,10 +1478,10 @@ Lretry: 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) @@ -1516,10 +1505,11 @@ Lretry: var->storage_class |= STCmanifest; DeclarationExp *de = new DeclarationExp(loc, var); st->push(new ExpStatement(loc, de)); - arg = arguments->tdata()[1]; // value + arg = (*arguments)[1]; // value } // Declare value - if (arg->storageClass & (STCout | STCref | STClazy)) + if (arg->storageClass & (STCout | STClazy) || + arg->storageClass & STCref && !te) error("no storage class for value %s", arg->ident->toChars()); Dsymbol *var; if (te) @@ -1533,14 +1523,24 @@ Lretry: s =((ScopeExp *)e)->sds; if (s) + { var = new AliasDeclaration(loc, arg->ident, s); + if (arg->storageClass & STCref) + error("symbol %s cannot be ref", s->toChars()); + } else { arg->type = e->type; Initializer *ie = new ExpInitializer(0, e); VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); + if (arg->storageClass & STCref) + v->storage_class |= STCref | STCforeach; if (e->isConst() || e->op == TOKstring) - v->storage_class |= STCmanifest; + { if (v->storage_class & STCref) + error("constant value %s cannot be ref", ie->toChars()); + else + v->storage_class |= STCmanifest; + } var = v; } } @@ -1572,9 +1572,6 @@ Lretry: sc->noctor++; Lagain: - Identifier *idapply = (op == TOKforeach_reverse) - ? Id::applyReverse : Id::apply; - sapply = NULL; switch (tab->ty) { case Tarray: @@ -1596,7 +1593,7 @@ Lagain: { Parameter *arg; int i = (dim == 1) ? 0 : 1; // index of value - arg = arguments->tdata()[i]; + arg = (*arguments)[i]; arg->type = arg->type->semantic(loc, sc); tnv = arg->type->toBasetype(); if (tnv->ty != tn->ty && @@ -1605,7 +1602,7 @@ Lagain: if (arg->storageClass & STCref) error("foreach: value of UTF conversion cannot be ref"); if (dim == 2) - { arg = arguments->tdata()[0]; + { arg = (*arguments)[0]; if (arg->storageClass & STCref) error("foreach: key cannot be ref"); } @@ -1615,7 +1612,7 @@ Lagain: for (size_t i = 0; i < dim; i++) { // Declare args - Parameter *arg = arguments->tdata()[i]; + Parameter *arg = (*arguments)[i]; Type *argtype = arg->type->semantic(loc, sc); VarDeclaration *var; @@ -1696,9 +1693,6 @@ Lagain: body = new CompoundStatement(loc, ds, body); s = new ForStatement(loc, forinit, cond, increment, body); - if (prelude) - s = new CompoundStatement(loc, - new ExpStatement(prelude->loc, prelude), s); s = s->semantic(sc); break; } @@ -1762,7 +1756,6 @@ Lagain: #if DMDV2 /* Prefer using opApply, if it exists */ - sapply = search_function((AggregateDeclaration *)tab->toDsymbol(sc), idapply); if (sapply) goto Lapply; @@ -1781,42 +1774,21 @@ Lagain: Identifier *idhead; Identifier *idnext; if (op == TOKforeach) - { idhead = Id::Fhead; - idnext = Id::Fnext; + { idhead = Id::Ffront; + idnext = Id::FpopFront; } else - { idhead = Id::Ftoe; - idnext = Id::Fretreat; + { idhead = Id::Fback; + idnext = Id::FpopBack; } Dsymbol *shead = search_function(ad, idhead); if (!shead) - { - if (ad->aliasthis) - { - Identifier *id = Lexer::uniqueId("__tup"); - ExpInitializer *ei = new ExpInitializer(aggr->loc, aggr); - VarDeclaration *vd = new VarDeclaration(loc, NULL, id, ei); - vd->storage_class |= STCctfe | STCref | STCforeach; - - aggr = new CommaExp(aggr->loc, - new DeclarationExp(loc, vd), - new DotIdExp(aggr->loc, - new VarExp(loc, vd), - ad->aliasthis->ident)); - - goto Lretry; - } goto Lapply; - } /* Generate a temporary __r and initialize it with the aggregate. */ Identifier *id = Identifier::generateId("__r"); - Expression *rinit = new SliceExp(loc, aggr, NULL, NULL); - rinit = rinit->trySemantic(sc); - if (!rinit) // if application of [] failed - rinit = aggr; - VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, rinit)); + VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, aggr)); Statement *init = new ExpStatement(loc, r); // !__r.empty @@ -1836,7 +1808,7 @@ Lagain: Statement *makeargs, *forbody; if (dim == 1) { - Parameter *arg = arguments->tdata()[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); @@ -1878,8 +1850,8 @@ Lagain: for (size_t i = 0; i < dim; i++) { - Parameter *arg = arguments->tdata()[i]; - Expression *exp = exps->tdata()[i]; + Parameter *arg = (*arguments)[i]; + Expression *exp = (*exps)[i]; #if 0 printf("[%d] arg = %s %s, exp = %s %s\n", i, arg->type ? arg->type->toChars() : "?", arg->ident->toChars(), @@ -1908,9 +1880,6 @@ Lagain: printf("increment: %s\n", increment->toChars()); printf("body: %s\n", forbody->toChars()); #endif - if (prelude) - s = new CompoundStatement(loc, - new ExpStatement(prelude->loc, prelude), s); s = s->semantic(sc); break; @@ -1925,7 +1894,6 @@ Lagain: FuncDeclaration *fdapply; Expression *ec; Expression *e; - Parameter *a; TypeDelegate* dgty; TypeDelegate* dgty2; TypeDelegate* fldeTy; @@ -1949,34 +1917,74 @@ Lagain: sc->func->vresult = v; } + TypeFunction *tfld = NULL; + if (sapply) + { FuncDeclaration *fdapply = sapply->isFuncDeclaration(); + if (fdapply) + { assert(fdapply->type && fdapply->type->ty == Tfunction); + tfld = (TypeFunction *)fdapply->type->semantic(loc, sc); + goto Lget; + } + else if (tab->ty == Tdelegate) + { + tfld = (TypeFunction *)tab->nextOf(); + Lget: + //printf("tfld = %s\n", tfld->toChars()); + if (tfld->parameters->dim == 1) + { + Parameter *p = Parameter::getNth(tfld->parameters, 0); + if (p->type && p->type->ty == Tdelegate) + { Type *t = p->type->semantic(loc, sc); + assert(t->ty == Tdelegate); + tfld = (TypeFunction *)t->nextOf(); + } + } + } + } + /* Turn body into the function literal: * int delegate(ref T arg) { body } */ Parameters *args = new Parameters(); for (size_t i = 0; i < dim; i++) - { Parameter *arg = arguments->tdata()[i]; + { Parameter *arg = (*arguments)[i]; + StorageClass stc = STCref; Identifier *id; arg->type = arg->type->semantic(loc, sc); - if (arg->storageClass & STCref) + if (tfld) + { Parameter *prm = Parameter::getNth(tfld->parameters, i); + //printf("\tprm = %s%s\n", (prm->storageClass&STCref?"ref ":""), prm->ident->toChars()); + stc = prm->storageClass & STCref; + id = arg->ident; // argument copy is not need. + if ((arg->storageClass & STCref) != stc) + { if (!stc) + error("foreach: cannot make %s ref", arg->ident->toChars()); + goto LcopyArg; + } + } + else if (arg->storageClass & STCref) + { // default delegate parameters are marked as ref, then + // argument copy is not need. id = arg->ident; + } else { // Make a copy of the ref argument so it isn't // a reference. - + LcopyArg: id = Lexer::uniqueId("__applyArg", i); + Initializer *ie = new ExpInitializer(0, new IdentifierExp(0, id)); VarDeclaration *v = new VarDeclaration(0, arg->type, arg->ident, ie); s = new ExpStatement(0, v); body = new CompoundStatement(loc, s, body); } - a = new Parameter(STCref, arg->type, id, NULL); - args->push(a); + args->push(new Parameter(stc, arg->type, id, NULL)); } - Type *t = new TypeFunction(args, Type::tint32, 0, LINKd); + tfld = new TypeFunction(args, Type::tint32, 0, LINKd); cases = new Statements(); gotos = new CompoundStatements(); - FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); + FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, 0, tfld, TOKdelegate, this); fld->fbody = body; Expression *flde = new FuncExp(loc, fld); flde = flde->semantic(sc); @@ -1984,28 +1992,28 @@ Lagain: // Resolve any forward referenced goto's for (size_t i = 0; i < gotos->dim; i++) - { CompoundStatement *cs = gotos->tdata()[i]; - GotoStatement *gs = (GotoStatement *)cs->statements->tdata()[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->tdata()[0] = s; + (*cs->statements)[0] = s; } } if (taa) { // Check types - Parameter *arg = arguments->tdata()[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 = arguments->tdata()[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()); @@ -2154,8 +2162,7 @@ Lagain: { assert(tab->ty == Tstruct || tab->ty == Tclass); Expressions *exps = new Expressions(); - if (!sapply) - sapply = search_function((AggregateDeclaration *)tab->toDsymbol(sc), idapply); + assert(sapply); #if 0 TemplateDeclaration *td; if (sapply && @@ -2165,7 +2172,7 @@ Lagain: */ Objects *tiargs = new Objects(); tiargs->push(fld); - ec = new DotTemplateInstanceExp(loc, aggr, idapply, tiargs); + ec = new DotTemplateInstanceExp(loc, aggr, sapply->ident, tiargs); } else #endif @@ -2173,7 +2180,7 @@ Lagain: /* Call: * aggr.apply(flde) */ - ec = new DotIdExp(loc, aggr, idapply); + ec = new DotIdExp(loc, aggr, sapply->ident); exps->push(flde); } e = new CallExp(loc, ec, exps); @@ -2198,7 +2205,7 @@ Lagain: // cases 2... for (size_t i = 0; i < cases->dim; i++) { - s = cases->tdata()[i]; + s = (*cases)[i]; s = new CaseStatement(0, new IntegerExp(i + 2), s); a->push(s); } @@ -2206,9 +2213,6 @@ Lagain: s = new CompoundStatement(loc, a); s = new SwitchStatement(loc, e, s, FALSE); } - if (prelude) - s = new CompoundStatement(loc, - new ExpStatement(prelude->loc, prelude), s); s = s->semantic(sc); break; } @@ -2230,7 +2234,7 @@ bool ForeachStatement::checkForArgTypes() { bool result = TRUE; for (size_t i = 0; i < arguments->dim; i++) - { Parameter *arg = arguments->tdata()[i]; + { Parameter *arg = (*arguments)[i]; if (!arg->type) { error("cannot infer type for %s", arg->ident->toChars()); @@ -2283,7 +2287,7 @@ void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(" ("); for (size_t i = 0; i < arguments->dim; i++) { - Parameter *a = arguments->tdata()[i]; + Parameter *a = (*arguments)[i]; if (i) buf->writestring(", "); if (a->storageClass & STCref) @@ -2827,7 +2831,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); @@ -2853,11 +2857,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()); @@ -2885,10 +2889,10 @@ Statement *PragmaStatement::semantic(Scope *sc) error("function name expected for start address"); 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; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) error("function name expected for start address, not '%s'", e->toChars()); @@ -3050,7 +3054,7 @@ Statement *SwitchStatement::semantic(Scope *sc) // Resolve any goto case's with exp for (size_t i = 0; i < gotoCases.dim; i++) { - GotoCaseStatement *gcs = gotoCases.tdata()[i]; + GotoCaseStatement *gcs = gotoCases[i]; if (!gcs->exp) { @@ -3064,7 +3068,7 @@ Statement *SwitchStatement::semantic(Scope *sc) continue; for (size_t j = 0; j < scx->sw->cases->dim; j++) { - CaseStatement *cs = scx->sw->cases->tdata()[j]; + CaseStatement *cs = (*scx->sw->cases)[j]; if (cs->exp->equals(gcs->exp)) { @@ -3079,38 +3083,7 @@ Statement *SwitchStatement::semantic(Scope *sc) ; } - if (!sc->sw->sdefault && !isFinal) - { hasNoDefault = 1; - - if (!global.params.useDeprecated) - error("non-final switch statement without a default is deprecated"); - - // Generate runtime error if the default is hit - Statements *a = new Statements(); - CompoundStatement *cs; - Statement *s; - - if (global.params.useSwitchError) - s = new SwitchErrorStatement(loc); - else - { Expression *e = new HaltExp(loc); - s = new ExpStatement(loc, e); - } - - a->reserve(4); - a->push(body); - - // LDC needs semantic to be run on break - Statement *breakstmt = new BreakStatement(loc, NULL); - breakstmt->semantic(sc); - a->push(breakstmt); - - sc->sw->sdefault = new DefaultStatement(loc, s); - a->push(sc->sw->sdefault); - cs = new CompoundStatement(loc, a); - body = cs; - } - + bool needswitcherror = FALSE; #if DMDV2 if (isFinal) { Type *t = condition->type; @@ -3125,11 +3098,11 @@ Statement *SwitchStatement::semantic(Scope *sc) size_t dim = ed->members->dim; for (size_t i = 0; i < dim; i++) { - EnumMember *em = ed->members->tdata()[i]->isEnumMember(); + EnumMember *em = (*ed->members)[i]->isEnumMember(); if (em) { for (size_t j = 0; j < cases->dim; j++) - { CaseStatement *cs = cases->tdata()[j]; + { CaseStatement *cs = (*cases)[j]; if (cs->exp->equals(em->value)) goto L1; } @@ -3139,9 +3112,37 @@ Statement *SwitchStatement::semantic(Scope *sc) ; } } + else + needswitcherror = TRUE; } #endif + if (!sc->sw->sdefault && (!isFinal || needswitcherror)) + { hasNoDefault = 1; + + if (!global.params.useDeprecated && !isFinal) + error("non-final switch statement without a default is deprecated"); + + // Generate runtime error if the default is hit + Statements *a = new Statements(); + CompoundStatement *cs; + Statement *s; + + if (global.params.useSwitchError) + s = new SwitchErrorStatement(loc); + else + { Expression *e = new HaltExp(loc); + s = new ExpStatement(loc, e); + } + + a->reserve(2); + sc->sw->sdefault = new DefaultStatement(loc, s); + a->push(sc->sw->sdefault); + a->push(body); + cs = new CompoundStatement(loc, a); + body = cs; + } + sc->pop(); return this; } @@ -3263,7 +3264,7 @@ Statement *CaseStatement::semantic(Scope *sc) L1: for (size_t i = 0; i < sw->cases->dim; i++) { - CaseStatement *cs = sw->cases->tdata()[i]; + CaseStatement *cs = (*sw->cases)[i]; //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); if (cs->exp->equals(exp)) @@ -3277,7 +3278,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 = sw->gotoCases.tdata()[i]; + GotoCaseStatement *gcs = sw->gotoCases[i]; if (!gcs->exp) { @@ -3622,19 +3623,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) @@ -3674,6 +3666,9 @@ Statement *ReturnStatement::semantic(Scope *sc) { fd->hasReturnExp |= 1; + if (exp->op == TOKfunction && tbret) + ((FuncExp *)exp)->setType(tbret); + exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (!((TypeFunction *)fd->type)->isref) @@ -3705,10 +3700,7 @@ Statement *ReturnStatement::semantic(Scope *sc) else fd->nrvo_can = 0; - if (fd->returnLabel && tbret->ty != Tvoid) - { - } - else if (fd->inferRetType) + if (fd->inferRetType) { TypeFunction *tf = (TypeFunction *)fd->type; assert(tf->ty == Tfunction); Type *tfret = tf->nextOf(); @@ -3769,6 +3761,8 @@ Statement *ReturnStatement::semantic(Scope *sc) tbret = tret->toBasetype(); } } + if (fd->returnLabel) + eorg = exp; } else if (tbret->ty != Tvoid) { @@ -3778,10 +3772,14 @@ Statement *ReturnStatement::semantic(Scope *sc) { exp = exp->castTo(sc, exp->type->invariantOf()); } - 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); + if (!((TypeFunction *)fd->type)->isref) exp = exp->optimize(WANTvalue); } @@ -3797,7 +3795,7 @@ Statement *ReturnStatement::semantic(Scope *sc) else { ((TypeFunction *)fd->type)->next = Type::tvoid; - fd->type = fd->type->semantic(loc, sc); + //fd->type = fd->type->semantic(loc, sc); // Remove with7321, same as 6902 if (!fd->tintro) { tret = Type::tvoid; tbret = tret; @@ -3885,7 +3883,8 @@ Statement *ReturnStatement::semantic(Scope *sc) assert(fd->vresult); VarExp *v = new VarExp(0, fd->vresult); - exp = new ConstructExp(loc, v, exp); + assert(eorg); + exp = new ConstructExp(loc, v, eorg); exp = exp->semantic(sc); } } @@ -4472,9 +4471,9 @@ Statement *TryCatchStatement::syntaxCopy() for (size_t i = 0; i < a->dim; i++) { Catch *c; - c = catches->tdata()[i]; + c = (*catches)[i]; c = c->syntaxCopy(); - a->tdata()[i] = c; + (*a)[i] = c; } TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); return s; @@ -4487,12 +4486,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 = catches->tdata()[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 = catches->tdata()[j]; + { Catch *cj = (*catches)[j]; char *si = c->loc.toChars(); char *sj = cj->loc.toChars(); @@ -4526,7 +4525,7 @@ int TryCatchStatement::blockExit(bool mustNotThrow) int catchresult = 0; for (size_t i = 0; i < catches->dim; i++) { - Catch *c = catches->tdata()[i]; + Catch *c = (*catches)[i]; if (c->type == Type::terror) continue; @@ -4556,7 +4555,7 @@ void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) body->toCBuffer(buf, hgs); for (size_t i = 0; i < catches->dim; i++) { - Catch *c = catches->tdata()[i]; + Catch *c = (*catches)[i]; c->toCBuffer(buf, hgs); } } @@ -4571,6 +4570,7 @@ Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) this->ident = id; this->handler = handler; var = NULL; + internalCatch = false; } Catch *Catch::syntaxCopy() @@ -4579,6 +4579,7 @@ Catch *Catch::syntaxCopy() (type ? type->syntaxCopy() : NULL), ident, (handler ? handler->syntaxCopy() : NULL)); + c->internalCatch = internalCatch; return c; } @@ -4617,6 +4618,7 @@ void Catch::semantic(Scope *sc) } else if (sc->func && !sc->intypeof && + !internalCatch && cd != ClassDeclaration::exception && !ClassDeclaration::exception->isBaseOf(cd, NULL) && sc->func->setUnsafe()) @@ -4905,10 +4907,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 = a->tdata()[i]; + { Statement *s = (*a)[i]; s = new VolatileStatement(loc, s); - a->tdata()[i] = s; + (*a)[i] = s; } } @@ -4966,10 +4968,10 @@ Statements *DebugStatement::flatten(Scope *sc) Statements *a = statement ? statement->flatten(sc) : NULL; if (a) { for (size_t i = 0; i < a->dim; i++) - { Statement *s = a->tdata()[i]; + { Statement *s = (*a)[i]; s = new DebugStatement(loc, s); - a->tdata()[i] = s; + (*a)[i] = s; } } @@ -5107,10 +5109,10 @@ Statements *LabelStatement::flatten(Scope *sc) { a->push(new ExpStatement(loc, (Expression *)NULL)); } - Statement *s = a->tdata()[0]; + Statement *s = (*a)[0]; s = new LabelStatement(loc, ident, s); - a->tdata()[0] = s; + (*a)[0] = s; } } @@ -5240,8 +5242,8 @@ Statement *ImportStatement::syntaxCopy() Dsymbols *m = new Dsymbols(); m->setDim(imports->dim); for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *s = imports->tdata()[i]; - m->tdata()[i] = s->syntaxCopy(NULL); + { Dsymbol *s = (*imports)[i]; + (*m)[i] = s->syntaxCopy(NULL); } return new ImportStatement(loc, m); } @@ -5249,7 +5251,7 @@ Statement *ImportStatement::syntaxCopy() Statement *ImportStatement::semantic(Scope *sc) { for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *s = imports->tdata()[i]; + { Dsymbol *s = (*imports)[i]; s->semantic(sc); sc->insert(s); } @@ -5269,7 +5271,7 @@ int ImportStatement::isEmpty() void ImportStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *s = imports->tdata()[i]; + { Dsymbol *s = (*imports)[i]; s->toCBuffer(buf, hgs); } } diff --git a/dmd2/statement.h b/dmd2/statement.h index c96c5b40..06fbe750 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -136,6 +136,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 @@ -180,6 +181,7 @@ struct ExpStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); @@ -235,6 +237,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); @@ -274,6 +277,7 @@ struct UnrolledLoopStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); @@ -296,6 +300,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); @@ -362,7 +369,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); }; @@ -386,6 +395,8 @@ struct ForeachStatement : Statement Statement *syntaxCopy(); Statement *semantic(Scope *sc); bool checkForArgTypes(); + int inferAggregate(Scope *sc, Dsymbol *&sapply); + int inferApplyArgTypes(Scope *sc, Dsymbol *&sapply); int hasBreak(); int hasContinue(); int usesEH(); @@ -448,6 +459,7 @@ struct IfStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); @@ -660,6 +672,7 @@ struct ReturnStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); Statement *inlineScan(InlineScanState *iss); void toIR(IRState *irs); @@ -775,6 +788,7 @@ struct Catch : Object Identifier *ident; VarDeclaration *var; Statement *handler; + bool internalCatch; Catch(Loc loc, Type *t, Identifier *id, Statement *handler); Catch *syntaxCopy(); @@ -927,9 +941,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 + 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(); @@ -940,6 +954,10 @@ struct AsmStatement : Statement void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + //int inlineCost(InlineCostState *ics); + //Expression *doInline(InlineDoState *ids); + //Statement *inlineScan(InlineScanState *iss); + void toIR(IRState *irs); #if IN_LLVM @@ -965,6 +983,7 @@ struct ImportStatement : Statement int inlineCost(InlineCostState *ics); Expression *doInline(InlineDoState *ids); + Statement *doInlineStatement(InlineDoState *ids); void toIR(IRState *irs); }; diff --git a/dmd2/staticassert.c b/dmd2/staticassert.c index 88b2c70a..4d8bfa42 100644 --- a/dmd2/staticassert.c +++ b/dmd2/staticassert.c @@ -58,10 +58,15 @@ void StaticAssert::semantic2(Scope *sc) sc->flags |= SCOPEstaticassert; Expression *e = exp->semantic(sc); sc = sc->pop(); - 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; @@ -86,7 +91,7 @@ void StaticAssert::semantic2(Scope *sc) } } -int StaticAssert::oneMember(Dsymbol **ps) +int StaticAssert::oneMember(Dsymbol **ps, Identifier *ident) { //printf("StaticAssert::oneMember())\n"); *ps = NULL; diff --git a/dmd2/staticassert.h b/dmd2/staticassert.h index 2f7e0906..8d64416c 100644 --- a/dmd2/staticassert.h +++ b/dmd2/staticassert.h @@ -32,7 +32,7 @@ struct StaticAssert : Dsymbol void semantic(Scope *sc); void semantic2(Scope *sc); void inlineScan(); - int oneMember(Dsymbol **ps); + int oneMember(Dsymbol **ps, Identifier *ident); void toObjFile(int multiobj); const char *kind(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); diff --git a/dmd2/struct.c b/dmd2/struct.c index 352c21ed..4d6d2d33 100644 --- a/dmd2/struct.c +++ b/dmd2/struct.c @@ -41,7 +41,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) hasUnions = 0; sizeok = 0; // size not determined yet deferred = NULL; - isdeprecated = 0; + isdeprecated = false; inv = NULL; aggNew = NULL; aggDelete = NULL; @@ -126,7 +126,7 @@ void AggregateDeclaration::inlineScan() unsigned AggregateDeclaration::size(Loc loc) { - //printf("AggregateDeclaration::size() = %d\n", structsize); + //printf("AggregateDeclaration::size() %s, scope = %p\n", toChars(), scope); if (!members) error(loc, "unknown size"); if (sizeok != 1 && scope) @@ -148,6 +148,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. @@ -377,6 +382,8 @@ void StructDeclaration::semantic(Scope *sc) scope = NULL; } + int errors = global.gaggedErrors; + unsigned dprogress_save = Module::dprogress; parent = sc->parent; @@ -390,7 +397,7 @@ void StructDeclaration::semantic(Scope *sc) protection = sc->protection; storage_class |= sc->stc; if (sc->stc & STCdeprecated) - isdeprecated = 1; + isdeprecated = true; assert(!isAnonymous()); if (sc->stc & STCabstract) error("structs, unions cannot be abstract"); @@ -464,7 +471,7 @@ void StructDeclaration::semantic(Scope *sc) * resolve individual members like enums. */ for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; /* There are problems doing this in the general case because * Scope keeps track of things like 'offset' */ @@ -477,28 +484,19 @@ void StructDeclaration::semantic(Scope *sc) for (size_t i = 0; i < members_dim; i++) { - Dsymbol *s = members->tdata()[i]; - s->semantic(sc2); -#if 0 - if (sizeok == 2) - { //printf("forward reference\n"); - break; - } -#endif + Dsymbol *s = (*members)[i]; -#if 0 /* Decided to allow this because if the field is initialized by copying it from - * a correctly initialized struct, it will work. + /* If this is the last member, see if we can finish setting the size. + * This could be much better - finish setting the size after the last + * field was processed. The problem is the chicken-and-egg determination + * of when that is. See Bugzilla 7426 for more info. */ - Type *t; - if (s->isDeclaration() && - (t = s->isDeclaration()->type) != NULL && - t->toBasetype()->ty == Tstruct) - { StructDeclaration *sd = (StructDeclaration *)t->toDsymbol(sc); - if (sd->isnested) - error("inner struct %s cannot be the type for field %s as it must embed a reference to its enclosing %s", - sd->toChars(), s->toChars(), sd->toParent2()->toPrettyChars()); + if (i + 1 == members_dim) + { + if (sizeok == 0 && s->isAliasDeclaration()) + finalizeSize(); } -#endif + s->semantic(sc2); } if (sizeok == 2) @@ -518,19 +516,7 @@ void StructDeclaration::semantic(Scope *sc) return; } - // 0 sized struct's are set to 1 byte - if (structsize == 0) - { - structsize = 1; - alignsize = 1; - } - - // Round struct size up to next alignsize boundary. - // This will ensure that arrays of structs will get their internals - // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - - sizeok = 1; + finalizeSize(); Module::dprogress++; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); @@ -649,7 +635,13 @@ void StructDeclaration::semantic(Scope *sc) semantic2(sc); semantic3(sc); } - if (deferred) + + if (global.gag && global.gaggedErrors != errors) + { // The type is no good, yet the error messages were gagged. + type = Type::terror; + } + + if (deferred && !global.gag) { deferred->semantic2(sc); deferred->semantic3(sc); @@ -672,6 +664,23 @@ Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) return ScopeDsymbol::search(loc, ident, flags); } +void StructDeclaration::finalizeSize() +{ + // 0 sized struct's are set to 1 byte + if (structsize == 0) + { + structsize = 1; + alignsize = 1; + } + + // Round struct size up to next alignsize boundary. + // This will ensure that arrays of structs will get their internals + // aligned properly. + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + + sizeok = 1; +} + void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->printf("%s ", kind()); diff --git a/dmd2/template.c b/dmd2/template.c index 36103e7c..e4e2e158 100644 --- a/dmd2/template.c +++ b/dmd2/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 @@ -14,6 +14,7 @@ #include #include "root.h" +#include "aav.h" #include "rmem.h" #include "stringtable.h" #include "mars.h" @@ -278,6 +279,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) @@ -287,12 +290,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(); @@ -305,7 +317,7 @@ void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) { if (i) buf->writeByte(','); - Object *o = args->tdata()[i]; + Object *o = (*args)[i]; ObjectToCBuffer(buf, hgs, o); } } @@ -377,13 +389,10 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, if (members) { Dsymbol *s; - if (Dsymbol::oneMembers(members, &s)) + if (Dsymbol::oneMembers(members, &s, ident) && s) { - if (s && s->ident && s->ident->equals(ident)) - { - onemember = s; - s->parent = this; - } + onemember = s; + s->parent = this; } } } @@ -515,13 +524,10 @@ void TemplateDeclaration::semantic(Scope *sc) if (members) { Dsymbol *s; - if (Dsymbol::oneMembers(members, &s)) + if (Dsymbol::oneMembers(members, &s, ident) && s) { - if (s && s->ident && s->ident->equals(ident)) - { - onemember = s; - s->parent = this; - } + onemember = s; + s->parent = this; } } @@ -719,12 +725,7 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); #endif -#if DMDV1 m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); -#else - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0); - -#endif //printf("\tm2 = %d\n", m2); if (m2 == MATCHnomatch) @@ -759,12 +760,19 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, } #if DMDV2 - if (m && !(m == MATCHexact && flag == 2) && constraint && !(flag & 1)) + if (m && constraint && !flag) { /* Check to see if constraint is satisfied. */ makeParamNamesVisibleInConstraint(paramscope, fargs); Expression *e = constraint->syntaxCopy(); Scope *sc = paramscope->push(); + + /* There's a chicken-and-egg problem here. We don't know yet if this template + * instantiation will be a local one (isnested is set), and we won't know until + * after selecting the correct template. Thus, function we're nesting inside + * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). + * Workaround the problem by setting a flag to relax the checking on frame errors. + */ sc->flags |= SCOPEstaticif; FuncDeclaration *fd = onemember && onemember->toAlias() ? @@ -1165,7 +1173,7 @@ L2: mod &= ~STCwild; if (tthis->mod != mod) { - if (!MODimplicitConv(tthis->mod, mod)) + if (!MODmethodConv(tthis->mod, mod)) goto Lnomatch; if (MATCHconst < match) match = MATCHconst; @@ -1215,6 +1223,9 @@ Lretry: #endif Type *argtype = farg->type; + // Apply function parameter storage classes to parameter types + fparam->type = fparam->type->addStorageClass(fparam->storageClass); + #if DMDV2 /* Allow string literals which are type [] to match with [dim] */ @@ -1229,15 +1240,41 @@ Lretry: } } + /* Allow implicit function literals to delegate conversion + */ + if (farg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)farg; + Type *tp = fparam->type; + if (tp->ty == Tdelegate && + fe->type->ty == Tpointer && fe->type->nextOf()->ty == Tfunction && + fe->tok == TOKreserved) + { Type *tdg = new TypeDelegate(fe->type->nextOf()); + tdg = tdg->semantic(loc, sc); + farg = fe->inferType(sc, tdg); + } + else if (fe->type == Type::tvoid) + { + farg = fe->inferType(sc, tp); + if (!farg) + goto Lvarargs; + } + argtype = farg->type; + } + /* Remove top const for dynamic array types and pointer types */ if ((argtype->ty == Tarray || argtype->ty == Tpointer) && - !argtype->isMutable()) + !argtype->isMutable() && + (!(fparam->storageClass & STCref) || + (fparam->storageClass & STCauto) && !farg->isLvalue())) { argtype = argtype->mutableOf(); } #endif + if (fvarargs == 2 && i + 1 == nfparams && i + 1 < nfargs) + goto Lvarargs; + MATCH m; m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes, tf->hasWild() ? &wildmatch : NULL); @@ -1274,16 +1311,33 @@ Lretry: ad = ((TypeStruct *)tba)->sym; Lad: if (ad->aliasthis) - { + { /* If a semantic error occurs while doing alias this, + * eg purity(bug 7295), just regard it as not a match. + */ + unsigned olderrors = global.startGagging(); Expression *e = new DotIdExp(farg->loc, farg, ad->aliasthis->ident); e = e->semantic(sc); e = resolveProperties(sc, e); - farg = e; - goto Lretry; + if (!global.endGagging(olderrors)) + { farg = e; + goto Lretry; + } } } } + if (m && (fparam->storageClass & (STCref | STCauto)) == STCref) + { if (!farg->isLvalue()) + goto Lnomatch; + } + if (m && (fparam->storageClass & STCout)) + { if (!farg->isLvalue()) + goto Lnomatch; + } + if (!m && (fparam->storageClass & STClazy) && fparam->type->ty == Tvoid && + farg->type->ty != Tvoid) + m = MATCHconvert; + if (m) { if (m < match) match = m; // pick worst match @@ -1291,6 +1345,7 @@ Lretry: } } + Lvarargs: /* The following code for variadic arguments closely * matches TypeFunction::callMatch() */ @@ -1315,6 +1370,25 @@ Lretry: { Expression *arg = fargs->tdata()[i]; assert(arg); + + if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + Type *tp = tb->nextOf(); + if (tp->ty == Tdelegate && + fe->type->ty == Tpointer && fe->type->nextOf()->ty == Tfunction && + fe->tok == TOKreserved) + { tp = new TypeDelegate(fe->type->nextOf()); + tp = tp->semantic(loc, sc); + arg = fe->inferType(sc, tp); + } + else if (arg->type == Type::tvoid) + { + arg = fe->inferType(sc, tp); + if (!arg) + goto Lnomatch; + } + } + MATCH m; /* If lazy array of delegates, * convert arg(s) to delegate(s) @@ -1380,7 +1454,7 @@ Lmatch: */ Declaration *sparam; dedargs->tdata()[i] = oded; - MATCH m2 = tparam->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam, 0); + MATCH m2 = tparam->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); //printf("m2 = %d\n", m2); if (!m2) goto Lnomatch; @@ -1412,6 +1486,7 @@ Lmatch: #if DMDV2 if (constraint) { /* Check to see if constraint is satisfied. + * Most of this code appears twice; this is a good candidate for refactoring. */ makeParamNamesVisibleInConstraint(paramscope, fargs); Expression *e = constraint->syntaxCopy(); @@ -1620,7 +1695,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, TemplateDeclaration *td_best = NULL; Objects *tdargs = new Objects(); TemplateInstance *ti; - FuncDeclaration *fd; + FuncDeclaration *fd_best; #if 0 printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); @@ -1655,6 +1730,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, MATCH m; Objects dedargs; + FuncDeclaration *fd = NULL; m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); //printf("deduceFunctionTemplateMatch = %d\n", m); @@ -1670,14 +1746,53 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, // Disambiguate by picking the most specialized TemplateDeclaration MATCH c1 = td->leastAsSpecialized(td_best, fargs); MATCH c2 = td_best->leastAsSpecialized(td, fargs); - //printf("c1 = %d, c2 = %d\n", c1, c2); + //printf("1: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; else if (c1 < c2) goto Ltd_best; - else - goto Lambig; + } + + if (!fd_best) + { + fd_best = td_best->doHeaderInstantiation(sc, tdargs, fargs); + if (!fd_best) + goto Lerror; + } + { + tdargs->setDim(dedargs.dim); + memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *)); + fd = td->doHeaderInstantiation(sc, tdargs, fargs); + if (!fd) + goto Lerror; + } + assert(fd && fd_best); + + { + // Disambiguate by tf->callMatch + TypeFunction *tf1 = (TypeFunction *)fd->type; + TypeFunction *tf2 = (TypeFunction *)fd_best->type; + MATCH c1 = (MATCH) tf1->callMatch(fd->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); + MATCH c2 = (MATCH) tf2->callMatch(fd_best->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); + //printf("2: c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + if (c1 < c2) + goto Ltd_best; + } + + { + // Disambiguate by picking the most specialized FunctionDeclaration + MATCH c1 = fd->leastAsSpecialized(fd_best); + MATCH c2 = fd_best->leastAsSpecialized(fd); + //printf("3: c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + if (c1 < c2) + goto Ltd_best; } Lambig: // td_best and td are ambiguous @@ -1692,6 +1807,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, td_ambig = NULL; assert((size_t)td->scope > 0x10000); td_best = td; + fd_best = fd; m_best = m; tdargs->setDim(dedargs.dim); memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); @@ -1717,10 +1833,10 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, assert((size_t)td_best->scope > 0x10000); ti = new TemplateInstance(loc, td_best, tdargs); ti->semantic(sc, fargs); - fd = ti->toAlias()->isFuncDeclaration(); - if (!fd) + fd_best = ti->toAlias()->isFuncDeclaration(); + if (!fd_best || !((TypeFunction*)fd_best->type)->callMatch(ethis, fargs, flags)) goto Lerror; - return fd; + return fd_best; Lerror: #if DMDV2 @@ -1749,6 +1865,78 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, return NULL; } +/************************************************* + * Limited function template instantiation for using fd->leastAsSpecialized() + */ +FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(Scope *sc, + Objects *tdargs, Expressions *fargs) +{ + FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); + if (!fd) + return NULL; + +#if 0 + printf("doHeaderInstantiation this = %s\n", toChars()); + for (size_t i = 0; i < tdargs->dim; ++i) + printf("\ttdargs[%d] = %s\n", i, ((Object *)tdargs->data[i])->toChars()); +#endif + + assert((size_t)scope > 0x10000); + TemplateInstance *ti = new TemplateInstance(loc, this, tdargs); + ti->tinst = sc->tinst; + { + ti->tdtypes.setDim(ti->tempdecl->parameters->dim); + if (!ti->tempdecl->matchWithInstance(ti, &ti->tdtypes, fargs, 2)) + return NULL; + } + + ti->parent = parent; + + // function body and contracts are not need + //fd = fd->syntaxCopy(NULL)->isFuncDeclaration(); + fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy()); + fd->parent = ti; + + Scope *scope = this->scope; + + ti->argsym = new ScopeDsymbol(); + ti->argsym->parent = scope->parent; + scope = scope->push(ti->argsym); + + Scope *paramscope = scope->push(); + paramscope->stc = 0; + ti->declareParameters(paramscope); + paramscope->pop(); + + { + TypeFunction *tf = (TypeFunction *)fd->type; + if (tf && tf->ty == Tfunction) + tf->fargs = fargs; + } + + Scope *sc2; + sc2 = scope->push(ti); + sc2->parent = /*isnested ? sc->parent :*/ ti; + sc2->tinst = ti; + + { + Scope *sc = sc2; + sc = sc->push(); + + if (fd->isCtorDeclaration()) + sc->flags |= SCOPEctor; + fd->type = fd->type->semantic(fd->loc, sc); + sc = sc->pop(); + } + //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod); + //printf("fd->needThis() = %d\n", fd->needThis()); + + sc2->pop(); + scope->pop(); + + return fd; +} + bool TemplateDeclaration::hasStaticCtorOrDtor() { return FALSE; // don't scan uninstantiated templates @@ -2128,6 +2316,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) { @@ -2135,8 +2336,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()) @@ -2655,8 +2866,8 @@ MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame { TypeStruct *tp = (TypeStruct *)tparam; - if (sym != tp->sym) - return MATCHnomatch; + //printf("\t%d\n", (MATCH) implicitConvTo(tp)); + return implicitConvTo(tp); } return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); } @@ -2880,6 +3091,8 @@ TemplateThisParameter *TemplateParameter::isTemplateThisParameter() // type-parameter +Type *TemplateTypeParameter::tdummy = NULL; + TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType) : TemplateParameter(loc, ident) @@ -2963,15 +3176,13 @@ Lnomatch: * parameters[] template parameters * dedtypes[] deduced arguments to template instance * *psparam set to symbol declared and initialized to dedtypes[i] - * flags 1: don't do 'toHeadMutable()' */ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam, int flags) + Declaration **psparam) { //printf("TemplateTypeParameter::matchArg()\n"); - Type *t; Object *oarg; MATCH m = MATCHexact; Type *ta; @@ -2989,7 +3200,6 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, { goto Lnomatch; } - flags |= 1; // already deduced, so don't to toHeadMutable() } } @@ -3001,10 +3211,11 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, } //printf("ta is %s\n", ta->toChars()); - t = (Type *)dedtypes->tdata()[i]; - if (specType) { + if (!ta || ta == tdummy) + goto Lnomatch; + //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); if (m2 == MATCHnomatch) @@ -3014,37 +3225,29 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, if (m2 < m) m = m2; - t = (Type *)dedtypes->tdata()[i]; + if (dedtypes->tdata()[i]) + ta = (Type *)dedtypes->tdata()[i]; } else { - // So that matches with specializations are better - if (!(flags & 1)) - m = MATCHconvert; - - /* This is so that: - * template Foo(T), Foo!(const int), => ta == int - */ -// if (!(flags & 1)) -// ta = ta->toHeadMutable(); - - if (t) + if (dedtypes->tdata()[i]) { // Must match already deduced type + Type *t = (Type *)dedtypes->tdata()[i]; - m = MATCHexact; if (!t->equals(ta)) { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); goto Lnomatch; } } + else + { + // So that matches with specializations are better + m = MATCHconvert; + } } + dedtypes->tdata()[i] = ta; - if (!t) - { - dedtypes->tdata()[i] = ta; - t = ta; - } - *psparam = new AliasDeclaration(loc, ident, t); + *psparam = new AliasDeclaration(loc, ident, ta); //printf("\tm = %d\n", m); return m; @@ -3096,7 +3299,9 @@ void *TemplateTypeParameter::dummyArg() t = specType; else { // Use this for alias-parameter's too (?) - t = new TypeIdentifier(loc, ident); + if (!tdummy) + tdummy = new TypeIdentifier(loc, ident); + t = tdummy; } return (void *)t; } @@ -3245,10 +3450,9 @@ Lnomatch: return 0; } -MATCH TemplateAliasParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, - Objects *dedtypes, - Declaration **psparam, int flags) +MATCH TemplateAliasParameter::matchArg(Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) { Object *sa; Object *oarg; @@ -3412,7 +3616,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) @@ -3510,9 +3714,9 @@ Lnomatch: } -MATCH TemplateValueParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam, int flags) +MATCH TemplateValueParameter::matchArg(Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) { //printf("TemplateValueParameter::matchArg()\n"); @@ -3562,7 +3766,7 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, if (specValue) { - if (!ei || ei == edummy) + if (!ei || _aaGetRvalue(edummies, ei->type) == ei) goto Lnomatch; Expression *e = specValue; @@ -3570,13 +3774,11 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, e = e->semantic(sc); e = e->implicitCastTo(sc, valType); e = e->optimize(WANTvalue | WANTinterpret); - //e->type = e->type->toHeadMutable(); ei = ei->syntaxCopy(); ei = ei->semantic(sc); ei = ei->implicitCastTo(sc, vt); ei = ei->optimize(WANTvalue | WANTinterpret); - //ei->type = ei->type->toHeadMutable(); //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); if (!ei->equals(e)) @@ -3647,9 +3849,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; } @@ -3720,10 +3923,9 @@ int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) return 0; } -MATCH TemplateTupleParameter::matchArg(Scope *sc, - Objects *tiargs, size_t i, TemplateParameters *parameters, - Objects *dedtypes, - Declaration **psparam, int flags) +MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, + size_t i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) { //printf("TemplateTupleParameter::matchArg()\n"); @@ -4232,15 +4434,13 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) if (members->dim) { Dsymbol *s; - if (Dsymbol::oneMembers(members, &s) && s) + if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) { //printf("s->kind = '%s'\n", s->kind()); //s->print(); //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - if (s->ident && s->ident->equals(tempdecl->ident)) - { - //printf("setting aliasdecl\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); + //printf("setting aliasdecl\n"); + aliasdecl = new AliasDeclaration(loc, s->ident, s); #if IN_LLVM // LDC propagate internal information @@ -4251,7 +4451,6 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) } } #endif - } } } @@ -4293,6 +4492,12 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) error("recursive expansion"); fatal(); } + + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->setScope(sc2); + } + for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = members->tdata()[i]; @@ -4333,6 +4538,27 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) } } + /* ConditionalDeclaration may introduce eponymous declaration, + * so we should find it once again after semantic. + */ + if (members->dim) + { + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) + { + if (!aliasdecl || aliasdecl->toAlias() != s) + { + //printf("s->kind = '%s'\n", s->kind()); + //s->print(); + //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); + //printf("setting aliasdecl 2\n"); + aliasdecl = new AliasDeclaration(loc, s->ident, s); + } + } + else if (aliasdecl) + aliasdecl = NULL; + } + /* The problem is when to parse the initializer for a variable. * Perhaps VarDeclaration::semantic() should do it like it does * for initializers inside a function. @@ -4962,6 +5188,8 @@ Identifier *TemplateInstance::genIdent(Objects *args) } // Now that we know it is not an alias, we MUST obtain a value ea = ea->optimize(WANTvalue | WANTinterpret); + if (ea->op == TOKerror) + continue; #if 1 /* Use deco that matches what it would be for a function parameter */ @@ -5180,7 +5408,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; @@ -5203,7 +5431,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) @@ -5221,9 +5449,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; } } @@ -5236,11 +5464,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; } } @@ -5342,7 +5570,7 @@ const char *TemplateInstance::kind() return "template instance"; } -int TemplateInstance::oneMember(Dsymbol **ps) +int TemplateInstance::oneMember(Dsymbol **ps, Identifier *ident) { *ps = NULL; return TRUE; @@ -5561,7 +5789,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, NULL); @@ -5789,23 +6017,25 @@ const char *TemplateMixin::kind() return "mixin"; } -int TemplateMixin::oneMember(Dsymbol **ps) +int TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident) { - return Dsymbol::oneMember(ps); + return Dsymbol::oneMember(ps, ident); } int TemplateMixin::hasPointers() { //printf("TemplateMixin::hasPointers() %s\n", toChars()); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - //printf(" s = %s %s\n", s->kind(), s->toChars()); - if (s->hasPointers()) + + if (members) + for (size_t i = 0; i < members->dim; i++) { - return 1; + Dsymbol *s = (*members)[i]; + //printf(" s = %s %s\n", s->kind(), s->toChars()); + if (s->hasPointers()) + { + return 1; + } } - } return 0; } diff --git a/dmd2/template.h b/dmd2/template.h index 18117e43..d4920b68 100644 --- a/dmd2/template.h +++ b/dmd2/template.h @@ -95,6 +95,7 @@ struct TemplateDeclaration : ScopeDsymbol MATCH deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, Objects *dedargs); FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, int flags = 0); void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); + FuncDeclaration *doHeaderInstantiation(Scope *sc, Objects *tdargs, Expressions *fargs); TemplateDeclaration *isTemplateDeclaration() { return this; } @@ -151,7 +152,7 @@ struct TemplateParameter /* Match actual argument against parameter. */ - virtual MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags = 0) = 0; + virtual MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0; /* Create dummy argument based on parameter. */ @@ -166,6 +167,8 @@ struct TemplateTypeParameter : TemplateParameter Type *specType; // type parameter: if !=NULL, this is the type specialization Type *defaultType; + static Type *tdummy; + TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); TemplateTypeParameter *isTemplateTypeParameter(); @@ -177,7 +180,7 @@ struct TemplateTypeParameter : TemplateParameter Object *specialization(); Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; @@ -208,7 +211,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); @@ -221,7 +224,7 @@ struct TemplateValueParameter : TemplateParameter Object *specialization(); Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; @@ -248,7 +251,7 @@ struct TemplateAliasParameter : TemplateParameter Object *specialization(); Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; @@ -269,7 +272,7 @@ struct TemplateTupleParameter : TemplateParameter Object *specialization(); Object *defaultArg(Loc loc, Scope *sc); int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); void *dummyArg(); }; @@ -322,7 +325,7 @@ struct TemplateInstance : ScopeDsymbol void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Dsymbol *toAlias(); // resolve real symbol const char *kind(); - int oneMember(Dsymbol **ps); + int oneMember(Dsymbol **ps, Identifier *ident); int needsTypeInference(Scope *sc); char *toChars(); char *mangle(); @@ -365,7 +368,7 @@ struct TemplateMixin : TemplateInstance void semantic3(Scope *sc); void inlineScan(); const char *kind(); - int oneMember(Dsymbol **ps); + int oneMember(Dsymbol **ps, Identifier *ident); int hasPointers(); char *toChars(); char *mangle(); diff --git a/dmd2/traits.c b/dmd2/traits.c index 849b0434..ee3fa3ff 100644 --- a/dmd2/traits.c +++ b/dmd2/traits.c @@ -57,6 +57,9 @@ static int fptraits(void *param, FuncDeclaration *f) if (p->ident == Id::getVirtualFunctions && !f->isVirtual()) return 0; + if (p->ident == Id::getVirtualMethods && !f->isVirtualMethod()) + return 0; + Expression *e; if (p->e1->op == TOKdotvar) @@ -156,6 +159,11 @@ Expression *TraitsExp::semantic(Scope *sc) FuncDeclaration *f; ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtual()) } + else if (ident == Id::isVirtualMethod) + { + FuncDeclaration *f; + ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtualMethod()) + } else if (ident == Id::isFinalFunction) { FuncDeclaration *f; @@ -218,6 +226,7 @@ Expression *TraitsExp::semantic(Scope *sc) else if (ident == Id::hasMember || ident == Id::getMember || ident == Id::getOverloads || + ident == Id::getVirtualMethods || ident == Id::getVirtualFunctions) { if (dim != 2) @@ -262,9 +271,12 @@ Expression *TraitsExp::semantic(Scope *sc) if (t) { Dsymbol *sym = t->toDsymbol(sc); - Dsymbol *sm = sym->search(loc, id, 0); - if (sm) - goto Ltrue; + if (sym) + { + Dsymbol *sm = sym->search(loc, id, 0); + if (sm) + goto Ltrue; + } } /* Take any errors as meaning it wasn't found @@ -274,13 +286,7 @@ Expression *TraitsExp::semantic(Scope *sc) e = e->trySemantic(sc2); sc2->pop(); if (!e) - { if (global.gag) - { - global.errors++; - global.gaggedErrors++; - } goto Lfalse; - } else goto Ltrue; } @@ -290,6 +296,7 @@ Expression *TraitsExp::semantic(Scope *sc) return e; } else if (ident == Id::getVirtualFunctions || + ident == Id::getVirtualMethods || ident == Id::getOverloads) { unsigned errors = global.errors; @@ -392,9 +399,21 @@ Expression *TraitsExp::semantic(Scope *sc) ScopeDsymbol::foreach(sd->members, &PushIdentsDg::dg, idents); ClassDeclaration *cd = sd->isClassDeclaration(); - if (cd && cd->baseClass && ident == Id::allMembers) - { sd = cd->baseClass; // do again with base class - ScopeDsymbol::foreach(sd->members, &PushIdentsDg::dg, idents); + if (cd && ident == Id::allMembers) + { + struct PushBaseMembers + { + static void dg(ClassDeclaration *cd, Identifiers *idents) + { + for (size_t i = 0; i < cd->baseclasses->dim; i++) + { ClassDeclaration *cb = (*cd->baseclasses)[i]->base; + ScopeDsymbol::foreach(cb->members, &PushIdentsDg::dg, idents); + if (cb->baseclasses->dim) + dg(cb, idents); + } + } + }; + PushBaseMembers::dg(cd, idents); } // Turn Identifiers into StringExps reusing the allocated array diff --git a/gen/asmstmt.cpp b/gen/asmstmt.cpp index 601dd54a..aa59f7db 100644 --- a/gen/asmstmt.cpp +++ b/gen/asmstmt.cpp @@ -166,7 +166,6 @@ Statement *AsmStatement::semantic(Scope *sc) sc->func->inlineAsm = true; #endif sc->func->hasReturnExp |= 8; - sc->func->inlineStatus = ILSno; // %% not sure // empty statement -- still do the above things because they might be expected? if (! tokens) diff --git a/gen/dvalue.h b/gen/dvalue.h index 8c431e4e..55255a5f 100644 --- a/gen/dvalue.h +++ b/gen/dvalue.h @@ -9,7 +9,6 @@ handling is necessary, they hold enough information to do-the-right-thing (TM) #include #include "root.h" -#include "mem.h" struct Type; struct Dsymbol; diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 9b089b2d..1e3029d9 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -458,7 +458,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* // handle the rest of the arguments based on param passing style - // variadic instrinsics need some custom casts + // variadic intrinsics need some custom casts if (va_intrinsic) { for (int i=0; icodegen(Type::sir); assert(fd->ir.irFunc->func); - if(fd->tok == TOKdelegate) { + if (fd->tok == TOKreserved && type->ty == Tpointer && fd->vthis) + fd->tok = TOKfunction; + + if(fd->isNested()) { LLType* dgty = DtoType(type); LLValue* cval; @@ -2673,11 +2676,9 @@ DValue* FuncExp::toElem(IRState* p) return new DImValue(type, DtoAggrPair(cval, castfptr, ".func")); - } else if(fd->tok == TOKfunction) { + } else { return new DImValue(type, fd->ir.irFunc->func); } - - assert(0 && "fd->tok must be TOKfunction or TOKdelegate"); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gen/typinf.cpp b/gen/typinf.cpp index 3933c656..0de0c26e 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -208,11 +208,18 @@ TypeInfoDeclaration *TypeStruct::getTypeInfoDeclaration() TypeInfoDeclaration *TypeClass::getTypeInfoDeclaration() { if (sym->isInterfaceDeclaration()) - return new TypeInfoInterfaceDeclaration(this); + return new TypeInfoInterfaceDeclaration(this); else - return new TypeInfoClassDeclaration(this); + return new TypeInfoClassDeclaration(this); } +#if DMDV2 +TypeInfoDeclaration *TypeVector::getTypeInfoDeclaration() +{ + return new TypeInfoVectorDeclaration(this); +} +#endif + TypeInfoDeclaration *TypeEnum::getTypeInfoDeclaration() { return new TypeInfoEnumDeclaration(this); @@ -233,7 +240,6 @@ TypeInfoDeclaration *TypeTuple::getTypeInfoDeclaration() return new TypeInfoTupleDeclaration(this); } - /* ========================================================================= */ /* These decide if there's an instance for them already in std.typeinfo, diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 730bca4b..94bae5d5 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -64,6 +64,9 @@ list(REMOVE_ITEM DCRT_D ${RUNTIME_DC_DIR}/qsort2.d ${RUNTIME_DC_DIR}/trace.d ) +list(REMOVE_ITEM CORE_D + ${RUNTIME_DIR}/src/core/simd.d +) file(GLOB DCRT_C ${RUNTIME_DC_DIR}/*.c) list(REMOVE_ITEM DCRT_C ${RUNTIME_DC_DIR}/deh.c ${RUNTIME_DC_DIR}/dylib_fixes.c) if(UNIX) diff --git a/runtime/druntime b/runtime/druntime index 33925006..f2ce5491 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 33925006113cb894a46c8ffcb13ddc4fd29f4c54 +Subproject commit f2ce54913beaa90f59721bb3c5eb68f9b3938404 diff --git a/runtime/phobos b/runtime/phobos index 1f6264e9..2cc90b12 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 1f6264e94236e5cd20d211e136f05a88cb536b00 +Subproject commit 2cc90b12a6d21e1d9c674aae3b6475498315f126