diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h index 1d534d28..46af2b3d 100644 --- a/dmd2/aggregate.h +++ b/dmd2/aggregate.h @@ -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 @@ -40,6 +40,13 @@ struct TypeInfoClassDeclaration; struct VarDeclaration; struct dt_t; +enum Sizeok +{ + SIZEOKnone, // size of aggregate is not computed yet + SIZEOKdone, // size of aggregate is set correctly + SIZEOKfwd, // error in computing size of aggregate +}; + #if IN_LLVM struct ClassInfoDeclaration; namespace llvm @@ -63,10 +70,7 @@ struct AggregateDeclaration : ScopeDsymbol unsigned structalign; // struct member alignment in effect int hasUnions; // set if aggregate has overlapping fields VarDeclarations fields; // VarDeclaration fields - unsigned sizeok; // set when structsize contains valid data - // 0: no size - // 1: size is correct - // 2: cannot determine size; fwd referenced + enum Sizeok sizeok; // set when structsize contains valid data Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol bool isdeprecated; // !=0 if deprecated @@ -91,7 +95,8 @@ struct AggregateDeclaration : ScopeDsymbol FuncDeclaration *dtor; // aggregate destructor #ifdef IN_GCC - Array methods; // flat list of all methods for debug information + Expressions *attributes; // GCC decl/type attributes + FuncDeclarations methods; // flat list of all methods for debug information #endif AggregateDeclaration(Loc loc, Identifier *id); @@ -100,8 +105,10 @@ struct AggregateDeclaration : ScopeDsymbol void inlineScan(); unsigned size(Loc loc); static void alignmember(unsigned salign, unsigned size, unsigned *poffset); + static unsigned placeField(unsigned *nextoffset, + unsigned memsize, unsigned memalignsize, unsigned memalign, + unsigned *paggsize, unsigned *paggalignsize, bool isunion); Type *getType(); - void addField(Scope *sc, VarDeclaration *v); int firstFieldInUnion(int indx); // first field in union that includes indx int numFieldsInUnion(int firstIndex); // #fields in union starting at index int isDeprecated(); // is aggregate deprecated? @@ -167,7 +174,7 @@ struct StructDeclaration : AggregateDeclaration void toCBuffer(OutBuffer *buf, HdrGenState *hgs); char *mangle(); const char *kind(); - void finalizeSize(); + void finalizeSize(Scope *sc); #if DMDV1 Expression *cloneMembers(); #endif @@ -235,6 +242,7 @@ struct BaseClass #define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size #else #define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size +#define CLASSINFO_SIZE_64 (0x98) // value of ClassInfo.size #endif struct ClassDeclaration : AggregateDeclaration diff --git a/dmd2/aliasthis.c b/dmd2/aliasthis.c index f8a74b48..0f6ff452 100644 --- a/dmd2/aliasthis.c +++ b/dmd2/aliasthis.c @@ -17,9 +17,32 @@ #include "scope.h" #include "aggregate.h" #include "dsymbol.h" +#include "mtype.h" #if DMDV2 +Expression *resolveAliasThis(Scope *sc, Expression *e) +{ + Type *t = e->type->toBasetype(); + AggregateDeclaration *ad; + + if (t->ty == Tclass) + { ad = ((TypeClass *)t)->sym; + goto L1; + } + else if (t->ty == Tstruct) + { ad = ((TypeStruct *)t)->sym; + L1: + if (ad && ad->aliasthis) + { + e = new DotIdExp(e->loc, e, ad->aliasthis->ident); + e = e->semantic(sc); + e = resolveProperties(sc, e); + } + } + + return e; +} AliasThis::AliasThis(Loc loc, Identifier *ident) : Dsymbol(NULL) // it's anonymous (no identifier) diff --git a/dmd2/attrib.c b/dmd2/attrib.c index 5d55cd20..245cb084 100644 --- a/dmd2/attrib.c +++ b/dmd2/attrib.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 @@ -54,6 +54,24 @@ Dsymbols *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) return decl; } +int AttribDeclaration::apply(Dsymbol_apply_ft_t fp, void *param) +{ + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; + if (s) + { + if (s->apply(fp, param)) + return 1; + } + } + } + return 0; +} + int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { int m = 0; @@ -61,8 +79,8 @@ int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; //printf("\taddMember %s to %s\n", s->toChars(), sd->toChars()); m |= s->addMember(sc, sd, m | memnum); } @@ -92,8 +110,8 @@ void AttribDeclaration::setScopeNewSc(Scope *sc, newsc->explicitProtection = explicitProtection; newsc->structalign = structalign; } - for (unsigned i = 0; i < decl->dim; i++) - { Dsymbol *s = decl->tdata()[i]; + for (size_t i = 0; i < decl->dim; i++) + { Dsymbol *s = (*decl)[i]; s->setScope(newsc); // yes, the only difference from semanticNewSc() } @@ -127,8 +145,8 @@ void AttribDeclaration::semanticNewSc(Scope *sc, newsc->explicitProtection = explicitProtection; newsc->structalign = structalign; } - for (unsigned i = 0; i < decl->dim; i++) - { Dsymbol *s = decl->tdata()[i]; + for (size_t i = 0; i < decl->dim; i++) + { Dsymbol *s = (*decl)[i]; s->semantic(newsc); } @@ -149,7 +167,7 @@ void AttribDeclaration::semantic(Scope *sc) { for (size_t i = 0; i < d->dim; i++) { - Dsymbol *s = d->tdata()[i]; + Dsymbol *s = (*d)[i]; s->semantic(sc); } @@ -163,7 +181,7 @@ void AttribDeclaration::semantic2(Scope *sc) if (d) { for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + { Dsymbol *s = (*d)[i]; s->semantic2(sc); } } @@ -176,7 +194,7 @@ void AttribDeclaration::semantic3(Scope *sc) if (d) { for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + { Dsymbol *s = (*d)[i]; s->semantic3(sc); } } @@ -188,8 +206,8 @@ void AttribDeclaration::inlineScan() if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); s->inlineScan(); } @@ -205,8 +223,8 @@ void AttribDeclaration::addComment(unsigned char *comment) if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; //printf("AttribDeclaration::addComment %s\n", s->toChars()); s->addComment(comment); } @@ -230,8 +248,8 @@ void AttribDeclaration::emitComment(Scope *sc) if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; //printf("AttribDeclaration::emitComment %s\n", s->toChars()); s->emitComment(sc); } @@ -246,32 +264,26 @@ void AttribDeclaration::toObjFile(int multiobj) if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; s->toObjFile(multiobj); } } } +#endif -int AttribDeclaration::cvMember(unsigned char *p) +void AttribDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) { - int nwritten = 0; - int n; Dsymbols *d = include(NULL, NULL); if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - n = s->cvMember(p); - if (p) - p += n; - nwritten += n; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; + s->setFieldOffset(ad, poffset, isunion); } } - return nwritten; } -#endif int AttribDeclaration::hasPointers() { @@ -281,7 +293,7 @@ int AttribDeclaration::hasPointers() { for (size_t i = 0; i < d->dim; i++) { - Dsymbol *s = d->tdata()[i]; + Dsymbol *s = (*d)[i]; if (s->hasPointers()) return 1; } @@ -323,8 +335,8 @@ void AttribDeclaration::checkCtorConstInit() if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; s->checkCtorConstInit(); } } @@ -339,8 +351,8 @@ void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; s->addLocalClass(aclasses); } } @@ -354,15 +366,15 @@ void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) if (decl->dim == 0) buf->writestring("{}"); else if (decl->dim == 1) - (decl->tdata()[0])->toCBuffer(buf, hgs); + ((*decl)[0])->toCBuffer(buf, hgs); else { buf->writenl(); buf->writeByte('{'); buf->writenl(); - for (unsigned i = 0; i < decl->dim; i++) + for (size_t i = 0; i < decl->dim; i++) { - Dsymbol *s = decl->tdata()[i]; + Dsymbol *s = (*decl)[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -581,9 +593,9 @@ void LinkDeclaration::semantic3(Scope *sc) { enum LINK linkage_save = sc->linkage; sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) + for (size_t i = 0; i < decl->dim; i++) { - Dsymbol *s = decl->tdata()[i]; + Dsymbol *s = (*decl)[i]; s->semantic3(sc); } @@ -757,6 +769,7 @@ AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Dsymbols *decl) : AttribDeclaration(decl) { this->loc = loc; + this->alignment = 0; this->isunion = isunion; this->sem = 0; } @@ -774,21 +787,6 @@ void AnonDeclaration::semantic(Scope *sc) { //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); - if (sem == 1) - { //printf("already completed\n"); - scope = NULL; - return; // semantic() already completed - } - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; - scope = NULL; - } - - unsigned dprogress_save = Module::dprogress; - assert(sc->parent); Dsymbol *parent = sc->parent->pastMixin(); @@ -800,106 +798,85 @@ void AnonDeclaration::semantic(Scope *sc) return; } + alignment = sc->structalign; if (decl) { - AnonymousAggregateDeclaration aad; - int adisunion; - - if (sc->anonAgg) - { ad = sc->anonAgg; - adisunion = sc->inunion; - } - else - adisunion = ad->isUnionDeclaration() != NULL; - -// printf("\tsc->anonAgg = %p\n", sc->anonAgg); -// printf("\tad = %p\n", ad); -// printf("\taad = %p\n", &aad); - sc = sc->push(); - sc->anonAgg = &aad; sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); sc->inunion = isunion; sc->offset = 0; sc->flags = 0; - aad.structalign = sc->structalign; - aad.parent = ad; - for (unsigned i = 0; i < decl->dim; i++) + for (size_t i = 0; i < decl->dim; i++) { - Dsymbol *s = decl->tdata()[i]; - + Dsymbol *s = (*decl)[i]; s->semantic(sc); - if (isunion) - sc->offset = 0; - if (aad.sizeok == 2) - { - break; - } } sc = sc->pop(); + } +} - // If failed due to forward references, unwind and try again later - if (aad.sizeok == 2) + +void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) +{ + //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); + + if (decl) + { + /* This works by treating an AnonDeclaration as an aggregate 'member', + * so in order to place that member we need to compute the member's + * size and alignment. + */ + + size_t fieldstart = ad->fields.dim; + + /* Hackishly hijack ad's structsize and alignsize fields + * for use in our fake anon aggregate member. + */ + unsigned savestructsize = ad->structsize; + unsigned savealignsize = ad->alignsize; + ad->structsize = 0; + ad->alignsize = 0; + + unsigned offset = 0; + for (size_t i = 0; i < decl->dim; i++) { - ad->sizeok = 2; - //printf("\tsetting ad->sizeok %p to 2\n", ad); - if (!sc->anonAgg) - { - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - Module::dprogress = dprogress_save; - //printf("\tforward reference %p\n", this); - return; + Dsymbol *s = (*decl)[i]; + + s->setFieldOffset(ad, &offset, this->isunion); + if (this->isunion) + offset = 0; } - if (sem == 0) - { Module::dprogress++; - sem = 1; - //printf("\tcompleted %p\n", this); - } - else - ;//printf("\talready completed %p\n", this); + + unsigned anonstructsize = ad->structsize; + unsigned anonalignsize = ad->alignsize; + ad->structsize = savestructsize; + ad->alignsize = savealignsize; // 0 sized structs are set to 1 byte - if (aad.structsize == 0) + if (anonstructsize == 0) { - aad.structsize = 1; - aad.alignsize = 1; + anonstructsize = 1; + anonalignsize = 1; } - // Align size of anonymous aggregate -//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); - ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); - //ad->structsize = sc->offset; -//printf("sc->offset = %d\n", sc->offset); + /* Given the anon 'member's size and alignment, + * go ahead and place it. + */ + unsigned anonoffset = AggregateDeclaration::placeField( + poffset, + anonstructsize, anonalignsize, alignment, + &ad->structsize, &ad->alignsize, + isunion); - // Add members of aad to ad - //printf("\tadding members of aad to '%s'\n", ad->toChars()); - for (unsigned i = 0; i < aad.fields.dim; i++) + // Add to the anon fields the base offset of this anonymous aggregate + //printf("anon fields, anonoffset = %d\n", anonoffset); + for (size_t i = fieldstart; i < ad->fields.dim; i++) { - VarDeclaration *v = aad.fields.tdata()[i]; - - v->offset += sc->offset; - ad->fields.push(v); + VarDeclaration *v = ad->fields[i]; + //printf("\t[%d] %s %d\n", i, v->toChars(), v->offset); + v->offset += anonoffset; } - - // Add size of aad to ad - if (adisunion) - { - if (aad.structsize > ad->structsize) - ad->structsize = aad.structsize; - sc->offset = 0; - } - else - { - ad->structsize = sc->offset + aad.structsize; - sc->offset = ad->structsize; - } - - if (ad->alignsize < aad.alignsize) - ad->alignsize = aad.alignsize; } } @@ -910,9 +887,9 @@ void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring("\n{\n"); if (decl) { - for (unsigned i = 0; i < decl->dim; i++) + for (size_t i = 0; i < decl->dim; i++) { - Dsymbol *s = decl->tdata()[i]; + Dsymbol *s = (*decl)[i]; //buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -958,10 +935,10 @@ void PragmaDeclaration::setScope(Scope *sc) } 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) { @@ -996,10 +973,15 @@ void PragmaDeclaration::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); + if (e->op != TOKerror) + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKerror) + { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); + return; + } StringExp *se = e->toString(); if (se) { @@ -1018,11 +1000,11 @@ void PragmaDeclaration::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; if (e->op == TOKerror) goto Lnodecl; StringExp *se = e->toString(); @@ -1050,7 +1032,7 @@ void PragmaDeclaration::semantic(Scope *sc) Declaration *d = NULL; StringExp *s = NULL; - e = args->tdata()[0]; + e = (*args)[0]; e = e->semantic(sc); if (e->op == TOKvar) { @@ -1061,14 +1043,14 @@ void PragmaDeclaration::semantic(Scope *sc) if (!d) error("first argument of GNU_asm must be a function or variable declaration"); - e = args->tdata()[1]; + e = (*args)[1]; e = e->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); e = e->toString(); if (e && ((StringExp *)e)->sz == 1) s = ((StringExp *)e); else - error("second argument of GNU_asm must be a char string"); + error("second argument of GNU_asm must be a character string"); if (d && s) d->c_ident = Lexer::idPool((char*) s->string); @@ -1083,10 +1065,10 @@ void PragmaDeclaration::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()); @@ -1116,7 +1098,7 @@ void PragmaDeclaration::semantic(Scope *sc) { for (size_t i = 0; i < args->dim; i++) { - Expression *e = args->tdata()[i]; + Expression *e = (*args)[i]; // ignore errors in ignored pragmas. global.gag++; unsigned errors_save = global.errors; @@ -1145,9 +1127,9 @@ void PragmaDeclaration::semantic(Scope *sc) Ldecl: if (decl) { - for (unsigned i = 0; i < decl->dim; i++) + for (size_t i = 0; i < decl->dim; i++) { - Dsymbol *s = decl->tdata()[i]; + Dsymbol *s = (*decl)[i]; s->semantic(sc); @@ -1184,7 +1166,7 @@ void PragmaDeclaration::toObjFile(int multiobj) { assert(args && args->dim == 1); - Expression *e = args->tdata()[0]; + Expression *e = (*args)[0]; assert(e->op == TOKstring); @@ -1212,7 +1194,7 @@ void PragmaDeclaration::toObjFile(int multiobj) else if (ident == Id::startaddress) { assert(args && args->dim == 1); - Expression *e = args->tdata()[0]; + Expression *e = (*args)[0]; Dsymbol *sa = getDsymbol(e); FuncDeclaration *f = sa->isFuncDeclaration(); assert(f); @@ -1284,8 +1266,8 @@ void ConditionalDeclaration::emitComment(Scope *sc) * a template, then include(NULL, NULL) will fail. */ Dsymbols *d = decl ? decl : elsedecl; - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; s->emitComment(sc); } } @@ -1307,9 +1289,9 @@ void ConditionalDeclaration::setScope(Scope *sc) //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d); if (d) { - for (unsigned i = 0; i < d->dim; i++) + for (size_t i = 0; i < d->dim; i++) { - Dsymbol *s = d->tdata()[i]; + Dsymbol *s = (*d)[i]; s->setScope(sc); } @@ -1323,9 +1305,9 @@ void ConditionalDeclaration::importAll(Scope *sc) //printf("\tConditionalDeclaration::importAll '%s', d = %p\n",toChars(), d); if (d) { - for (unsigned i = 0; i < d->dim; i++) + for (size_t i = 0; i < d->dim; i++) { - Dsymbol *s = d->tdata()[i]; + Dsymbol *s = (*d)[i]; s->importAll(sc); } @@ -1348,10 +1330,8 @@ void ConditionalDeclaration::addComment(unsigned char *comment) { if (d) { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = d->tdata()[i]; + for (size_t i = 0; i < d->dim; i++) + { Dsymbol *s = (*d)[i]; //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); s->addComment(comment); } @@ -1371,9 +1351,9 @@ void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); if (decl) { - for (unsigned i = 0; i < decl->dim; i++) + for (size_t i = 0; i < decl->dim; i++) { - Dsymbol *s = decl->tdata()[i]; + Dsymbol *s = (*decl)[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -1387,9 +1367,9 @@ void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); buf->writeByte('{'); buf->writenl(); - for (unsigned i = 0; i < elsedecl->dim; i++) + for (size_t i = 0; i < elsedecl->dim; i++) { - Dsymbol *s = elsedecl->tdata()[i]; + Dsymbol *s = (*elsedecl)[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -1473,9 +1453,9 @@ void StaticIfDeclaration::semantic(Scope *sc) addisdone = 1; } - for (unsigned i = 0; i < d->dim; i++) + for (size_t i = 0; i < d->dim; i++) { - Dsymbol *s = d->tdata()[i]; + Dsymbol *s = (*d)[i]; s->semantic(sc); } diff --git a/dmd2/attrib.h b/dmd2/attrib.h index 388cd55d..e296677a 100644 --- a/dmd2/attrib.h +++ b/dmd2/attrib.h @@ -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 @@ -33,6 +33,7 @@ struct AttribDeclaration : Dsymbol AttribDeclaration(Dsymbols *decl); virtual Dsymbols *include(Scope *sc, ScopeDsymbol *s); + int apply(Dsymbol_apply_ft_t fp, void *param); int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void setScopeNewSc(Scope *sc, StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, @@ -48,6 +49,7 @@ struct AttribDeclaration : Dsymbol void emitComment(Scope *sc); const char *kind(); int oneMember(Dsymbol **ps, Identifier *ident); + void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); int hasPointers(); bool hasStaticCtorOrDtor(); void checkCtorConstInit(); @@ -58,7 +60,6 @@ struct AttribDeclaration : Dsymbol #if IN_DMD void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); #endif #if IN_LLVM @@ -120,12 +121,14 @@ struct AlignDeclaration : AttribDeclaration struct AnonDeclaration : AttribDeclaration { - int isunion; + bool isunion; + unsigned alignment; int sem; // 1 if successful semantic() AnonDeclaration(Loc loc, int isunion, Dsymbols *decl); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); + void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); }; diff --git a/dmd2/builtin.c b/dmd2/builtin.c index 4cfee71f..0c8a780a 100644 --- a/dmd2/builtin.c +++ b/dmd2/builtin.c @@ -12,15 +12,6 @@ #include #include -#if __FreeBSD__ -extern "C" -{ - long double sinl(long double); - long double cosl(long double); - long double tanl(long double); - long double sqrtl(long double); -} -#endif #include "mars.h" #include "declaration.h" @@ -33,6 +24,16 @@ extern "C" #include "id.h" #include "module.h" +#if __FreeBSD__ +extern "C" +{ + longdouble sinl(longdouble); + longdouble cosl(longdouble); + longdouble tanl(longdouble); + longdouble sqrtl(longdouble); +} +#endif + #if DMDV2 /********************************** diff --git a/dmd2/cast.c b/dmd2/cast.c index bab1d50d..fded2ecc 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -17,6 +17,7 @@ #include "utf.h" #include "declaration.h" #include "aggregate.h" +#include "template.h" #include "scope.h" //#define DUMP .dump(__PRETTY_FUNCTION__, this) @@ -107,6 +108,9 @@ fflush(stdout); else if (t->reliesOnTident()) error("forward reference to type %s", t->reliesOnTident()->toChars()); +//printf("type %p ty %d deco %p\n", type, type->ty, type->deco); +//type = type->semantic(loc, sc); +//printf("type %s t %s\n", type->deco, t->deco); error("cannot implicitly convert expression (%s) of type %s to %s", toChars(), type->toChars(), t->toChars()); } @@ -131,6 +135,12 @@ Expression *ErrorExp::implicitCastTo(Scope *sc, Type *t) return this; } +Expression *FuncExp::implicitCastTo(Scope *sc, Type *t) +{ + //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars()); + return inferType(t); +} + /******************************************* * Return !=0 if we can implicitly convert this to type t. * Don't do the actual cast. @@ -352,16 +362,16 @@ MATCH IntegerExp::implicitConvTo(Type *t) case Tfloat80: { - volatile long double f; + volatile_longdouble f; if (type->isunsigned()) { - f = (long double)value; - if (f != value) + f = ldouble(value); + if (f != value) // isn't this a noop, because the compiler prefers ld goto Lno; } else { - f = (long double)(long long)value; + f = ldouble((long long)value); if (f != (long long)value) goto Lno; } @@ -490,14 +500,17 @@ MATCH StringExp::implicitConvTo(Type *t) return MATCHnomatch; m = MATCHconst; } - switch (tn->ty) + if (!committed) { - case Tchar: - case Twchar: - case Tdchar: - if (!committed) - return m; - break; + switch (tn->ty) + { + case Tchar: + return (postfix != 'w' && postfix != 'd' ? m : MATCHconvert); + case Twchar: + return (postfix == 'w' ? m : MATCHconvert); + case Tdchar: + return (postfix == 'd' ? m : MATCHconvert); + } } break; } @@ -721,12 +734,24 @@ MATCH DelegateExp::implicitConvTo(Type *t) 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; + //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars()); + Expression *e = inferType(t, 1); + if (e) + { + if (e != this) + return e->implicitConvTo(t); + + /* MATCHconst: Conversion from implicit to explicit function pointer + * MATCHconvert: Conversion from impliict funciton pointer to delegate + */ + if (tok == TOKreserved && type->ty == Tpointer && + (t->ty == Tpointer || t->ty == Tdelegate)) + { + if (type == t) + return MATCHexact; + if (type->nextOf()->covariant(t->nextOf()) == 1) + return t->ty == Tpointer ? MATCHconst : MATCHconvert; + } } return Expression::implicitConvTo(t); } @@ -850,7 +875,7 @@ Expression *Expression::castTo(Scope *sc, Type *t) { /* Forward the cast to our alias this member, rewrite to: * cast(to)e1.aliasthis */ - Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); + Expression *e1 = resolveAliasThis(sc, this); Expression *e2 = new CastExp(loc, e1, tb); e2 = e2->semantic(sc); return e2; @@ -871,7 +896,7 @@ Expression *Expression::castTo(Scope *sc, Type *t) /* Forward the cast to our alias this member, rewrite to: * cast(to)e1.aliasthis */ - Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); + Expression *e1 = resolveAliasThis(sc, this); Expression *e2 = new CastExp(loc, e1, tb); e2 = e2->semantic(sc); return e2; @@ -1508,7 +1533,7 @@ Expression *DelegateExp::castTo(Scope *sc, Type *t) Expression *e = this; Type *tb = t->toBasetype(); Type *typeb = type->toBasetype(); - if (tb != typeb) + if (tb != typeb || hasOverloads) { // Look for delegates to functions where the functions are overloaded. FuncDeclaration *f; @@ -1549,15 +1574,11 @@ Expression *DelegateExp::castTo(Scope *sc, Type *t) 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; - } + Expression *e = inferType(t, 1); + if (e) + { if (e != this) + e = e->castTo(sc, t); + return e; } return Expression::castTo(sc, t); } @@ -1595,6 +1616,180 @@ Expression *CommaExp::castTo(Scope *sc, Type *t) return e; } +/* ==================== inferType ====================== */ + +/**************************************** + * Set type inference target + * flag 1: don't put an error when inference fails + */ + +Expression *Expression::inferType(Type *t, int flag, TemplateParameters *tparams) +{ + return this; +} + +Expression *ArrayLiteralExp::inferType(Type *t, int flag, TemplateParameters *tparams) +{ + if (t) + { + t = t->toBasetype(); + if (t->ty == Tarray || t->ty == Tsarray) + { + Type *tn = t->nextOf(); + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (*elements)[i]; + if (e) + { e = e->inferType(tn, flag, tparams); + (*elements)[i] = e; + } + } + } + } + return this; +} + +Expression *AssocArrayLiteralExp::inferType(Type *t, int flag, TemplateParameters *tparams) +{ + if (t) + { + t = t->toBasetype(); + if (t->ty == Taarray) + { TypeAArray *taa = (TypeAArray *)t; + Type *ti = taa->index; + Type *tv = taa->nextOf(); + for (size_t i = 0; i < keys->dim; i++) + { Expression *e = (*keys)[i]; + if (e) + { e = e->inferType(ti, flag, tparams); + (*keys)[i] = e; + } + } + for (size_t i = 0; i < values->dim; i++) + { Expression *e = (*values)[i]; + if (e) + { e = e->inferType(tv, flag, tparams); + (*values)[i] = e; + } + } + } + } + return this; +} + +Expression *FuncExp::inferType(Type *to, int flag, TemplateParameters *tparams) +{ + if (!to) + return this; + + //printf("FuncExp::interType('%s'), to=%s\n", type?type->toChars():"null", to->toChars()); + + if (!type) // semantic is not yet done + { + if (to->ty == Tdelegate || + to->ty == Tpointer && to->nextOf()->ty == Tfunction) + { treq = to; + } + return this; + } + + Expression *e = NULL; + + Type *t = to; + if (t->ty == Tdelegate) + { if (tok == TOKfunction) + goto L1; + t = t->nextOf(); + } + else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) + { if (tok == TOKdelegate) + goto L1; + t = t->nextOf(); + } + + if (td) + { /// Parameter types inference from + assert(td->scope); + 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); + Type *tprm = p->type; + if (tprm->reliesOnTident(tparams)) + goto L1; + tprm = tprm->semantic(loc, td->scope); + tiargs->push(tprm); + u = dim; // break inner loop + } + } + } + + TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); + e = (new ScopeExp(loc, ti))->semantic(td->scope); + if (e->op == TOKfunction) + { FuncExp *fe = (FuncExp *)e; + assert(fe->td == NULL); + e = fe->inferType(to, flag); + } + } + } + } + else if (type) + { + assert(type != Type::tvoid); // semantic is already done + + // Allow conversion from implicit function pointer to delegate + if (tok == TOKreserved && type->ty == Tpointer && + to->ty == Tdelegate) + { + Type *typen = type->nextOf(); + assert(typen->deco); + //if (typen->covariant(to->nextOf()) == 1) + { + FuncExp *fe = (FuncExp *)copy(); + fe->tok = TOKdelegate; + fe->type = (new TypeDelegate(typen))->merge(); + e = fe; + //e = fe->Expression::implicitCastTo(sc, to); + } + } + else + e = this; + } +L1: + if (!flag && !e) + { error("cannot infer function literal type from %s", to->toChars()); + e = new ErrorExp(); + } + return e; +} + +Expression *CondExp::inferType(Type *t, int flag, TemplateParameters *tparams) +{ + if (t) + { + t = t->toBasetype(); + e1 = e1->inferType(t, flag, tparams); + e2 = e2->inferType(t, flag, tparams); + } + return this; +} + /* ==================== ====================== */ /**************************************** @@ -1718,6 +1913,7 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression #endif assert(t2); +Lagain: Type *t1b = t1->toBasetype(); Type *t2b = t2->toBasetype(); @@ -1757,7 +1953,6 @@ int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression t1 = t1b; t2 = t2b; -Lagain: if (t1 == t2) { } @@ -2007,17 +2202,13 @@ Lcc: } else if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis) { - e1 = new DotIdExp(e1->loc, e1, ((TypeStruct *)t1)->sym->aliasthis->ident); - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); + e1 = resolveAliasThis(sc, e1); t1 = e1->type; continue; } else if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis) { - e2 = new DotIdExp(e2->loc, e2, ((TypeStruct *)t2)->sym->aliasthis->ident); - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); + e2 = resolveAliasThis(sc, e2); t2 = e2->type; continue; } @@ -2052,16 +2243,12 @@ Lcc: Expression *e2b = NULL; if (ts2->sym->aliasthis) { - e2b = new DotIdExp(e2->loc, e2, ts2->sym->aliasthis->ident); - e2b = e2b->semantic(sc); - e2b = resolveProperties(sc, e2b); + e2b = resolveAliasThis(sc, e2); i1 = e2b->implicitConvTo(t1); } if (ts1->sym->aliasthis) { - e1b = new DotIdExp(e1->loc, e1, ts1->sym->aliasthis->ident); - e1b = e1b->semantic(sc); - e1b = resolveProperties(sc, e1b); + e1b = resolveAliasThis(sc, e1); i2 = e1b->implicitConvTo(t2); } if (i1 && i2) @@ -2088,18 +2275,14 @@ Lcc: { if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis) { - e1 = new DotIdExp(e1->loc, e1, ((TypeStruct *)t1)->sym->aliasthis->ident); - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); + e1 = resolveAliasThis(sc, e1); t1 = e1->type; t = t1; goto Lagain; } if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis) { - e2 = new DotIdExp(e2->loc, e2, ((TypeStruct *)t2)->sym->aliasthis->ident); - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); + e2 = resolveAliasThis(sc, e2); t2 = e2->type; t = t2; goto Lagain; diff --git a/dmd2/class.c b/dmd2/class.c index 238f89f8..25644248 100644 --- a/dmd2/class.c +++ b/dmd2/class.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 @@ -277,7 +277,7 @@ void ClassDeclaration::semantic(Scope *sc) return; } if (symtab) - { if (sizeok == 1 || !scope) + { if (sizeok == SIZEOKdone || !scope) { //printf("\tsemantic for '%s' is already completed\n", toChars()); return; // semantic() already completed } @@ -337,7 +337,8 @@ void ClassDeclaration::semantic(Scope *sc) //b->type = b->type->semantic(loc, sc); tb = b->type->toBasetype(); if (tb->ty != Tclass) - { error("base type must be class or interface, not %s", b->type->toChars()); + { if (b->type != Type::terror) + error("base type must be class or interface, not %s", b->type->toChars()); baseclasses->remove(0); } else @@ -368,12 +369,12 @@ void ClassDeclaration::semantic(Scope *sc) goto L7; } } - if (!tc->sym->symtab || tc->sym->sizeok == 0) + if (!tc->sym->symtab || tc->sym->sizeok == SIZEOKnone) { // Try to resolve forward reference if (/*sc->mustsemantic &&*/ tc->sym->scope) tc->sym->semantic(NULL); } - if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) + if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == SIZEOKnone) { //printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars()); //error("forward reference of base class %s", baseClass->toChars()); @@ -410,8 +411,8 @@ void ClassDeclaration::semantic(Scope *sc) else tc = NULL; if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); + { if (b->type != Type::terror) + error("base type must be interface, not %s", b->type->toChars()); baseclasses->remove(i); continue; } @@ -516,13 +517,13 @@ void ClassDeclaration::semantic(Scope *sc) protection = sc->protection; storage_class |= sc->stc; - if (sizeok == 0) + if (sizeok == SIZEOKnone) { interfaceSemantic(sc); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->addMember(sc, this, 1); } @@ -593,13 +594,6 @@ void ClassDeclaration::semantic(Scope *sc) if (storage_class & STCabstract) isabstract = 1; - if (storage_class & STCimmutable) - type = type->addMod(MODimmutable); - if (storage_class & STCconst) - type = type->addMod(MODconst); - if (storage_class & STCshared) - type = type->addMod(MODshared); - sc = sc->push(this); //sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); //sc->stc |= storage_class & STC_TYPECTOR; @@ -635,17 +629,20 @@ void ClassDeclaration::semantic(Scope *sc) structsize = sc->offset; Scope scsave = *sc; size_t members_dim = members->dim; - sizeok = 0; + sizeok = SIZEOKnone; /* 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->tdata()[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)) + if (s->isEnumDeclaration() || + (s->isAggregateDeclaration() && s->ident) || + s->isTemplateMixin() || + s->isAliasDeclaration()) { //printf("setScope %s %s\n", s->kind(), s->toChars()); s->setScope(sc); @@ -653,19 +650,35 @@ void ClassDeclaration::semantic(Scope *sc) } for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; s->semantic(sc); } + // Set the offsets of the fields and determine the size of the class + + unsigned offset = structsize; + bool isunion = isUnionDeclaration() != NULL; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->setFieldOffset(this, &offset, false); + } + sc->offset = structsize; + 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 + if (sizeok == SIZEOKfwd) // failed due to forward references { // semantic() failed due to forward references // Unwind what we did, and defer it for later + for (size_t i = 0; i < fields.dim; i++) + { Dsymbol *s = fields[i]; + VarDeclaration *vd = s->isVarDeclaration(); + if (vd) + vd->offset = 0; + } fields.setDim(0); structsize = 0; alignsize = 0; @@ -685,15 +698,19 @@ void ClassDeclaration::semantic(Scope *sc) //printf("\tsemantic('%s') successful\n", toChars()); - structsize = sc->offset; //members->print(); /* Look for special member functions. * They must be in this class, not in a base class. */ - ctor = (CtorDeclaration *)search(0, Id::ctor, 0); + ctor = search(0, Id::ctor, 0); +#if DMDV1 if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) ctor = NULL; +#else + if (ctor && (ctor->toParent() != this || !(ctor->isCtorDeclaration() || ctor->isTemplateDeclaration()))) + ctor = NULL; // search() looks through ancestor classes +#endif // dtor = (DtorDeclaration *)search(Id::dtor, 0); // if (dtor && dtor->toParent() != this) @@ -719,7 +736,6 @@ void ClassDeclaration::semantic(Scope *sc) members->push(ctor); ctor->addMember(sc, this, 1); *sc = scsave; // why? What about sc->nofree? - sc->offset = structsize; ctor->semantic(sc); this->ctor = ctor; defaultCtor = ctor; @@ -735,9 +751,10 @@ void ClassDeclaration::semantic(Scope *sc) #endif // Allocate instance of each new interface + sc->offset = structsize; for (size_t i = 0; i < vtblInterfaces->dim; i++) { - BaseClass *b = vtblInterfaces->tdata()[i]; + BaseClass *b = (*vtblInterfaces)[i]; unsigned thissize = PTRSIZE; alignmember(structalign, thissize, &sc->offset); @@ -760,7 +777,7 @@ void ClassDeclaration::semantic(Scope *sc) if (global.params.is64bit) structsize = (structsize + structalign - 1) & ~(structalign - 1); #endif - sizeok = 1; + sizeok = SIZEOKdone; Module::dprogress++; dtor = buildDtor(sc); @@ -906,7 +923,12 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) if (scope && !symtab) { Scope *sc = scope; sc->mustsemantic++; + // If speculatively gagged, ungag now. + unsigned oldgag = global.gag; + if (global.isSpeculativeGagging()) + global.gag = 0; semantic(sc); + global.gag = oldgag; sc->mustsemantic--; } @@ -1025,7 +1047,7 @@ FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) { for (size_t i = 0; i < vtbl->dim; i++) { - FuncDeclaration *fd = vtbl->tdata()[i]->isFuncDeclaration(); + FuncDeclaration *fd = (*vtbl)[i]->isFuncDeclaration(); if (!fd) continue; // the first entry might be a ClassInfo @@ -1244,7 +1266,7 @@ void InterfaceDeclaration::semantic(Scope *sc) // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = baseclasses->tdata()[0]; + { BaseClass *b = (*baseclasses)[0]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); @@ -1280,8 +1302,8 @@ void InterfaceDeclaration::semantic(Scope *sc) else tc = NULL; if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); + { if (b->type != Type::terror) + error("base type must be interface, not %s", b->type->toChars()); baseclasses->remove(i); continue; } @@ -1338,7 +1360,7 @@ void InterfaceDeclaration::semantic(Scope *sc) { BaseClass *b = interfaces[i]; // Skip if b has already appeared - for (int k = 0; k < i; k++) + for (size_t k = 0; k < i; k++) { if (b == interfaces[k]) goto Lcontinue; @@ -1346,11 +1368,11 @@ void InterfaceDeclaration::semantic(Scope *sc) // Copy vtbl[] from base class if (b->base->vtblOffset()) - { int d = b->base->vtbl.dim; + { size_t d = b->base->vtbl.dim; if (d > 1) { vtbl.reserve(d - 1); - for (int j = 1; j < d; j++) + for (size_t j = 1; j < d; j++) vtbl.push(b->base->vtbl.tdata()[j]); } } @@ -1368,7 +1390,7 @@ void InterfaceDeclaration::semantic(Scope *sc) for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->addMember(sc, this, 1); } @@ -1384,6 +1406,7 @@ void InterfaceDeclaration::semantic(Scope *sc) sc->explicitProtection = 0; structalign = sc->structalign; sc->offset = PTRSIZE * 2; + structsize = sc->offset; inuse++; /* Set scope so if there are forward references, we still might be able to diff --git a/dmd2/clone.c b/dmd2/clone.c index 2664f864..d0b22c40 100644 --- a/dmd2/clone.c +++ b/dmd2/clone.c @@ -204,6 +204,11 @@ int StructDeclaration::needOpEquals() if (hasIdentityEquals) goto Lneed; +#if 0 + if (isUnionDeclaration()) + goto Ldontneed; +#endif + /* If any of the fields has an opEquals, then we * need it too. */ @@ -215,6 +220,14 @@ int StructDeclaration::needOpEquals() if (v->storage_class & STCref) continue; Type *tv = v->type->toBasetype(); +#if 0 + if (tv->isfloating()) + goto Lneed; + if (tv->ty == Tarray) + goto Lneed; + if (tv->ty == Tclass) + goto Lneed; +#endif while (tv->ty == Tsarray) { TypeSArray *ta = (TypeSArray *)tv; tv = tv->nextOf()->toBasetype(); @@ -226,6 +239,7 @@ int StructDeclaration::needOpEquals() goto Lneed; } } +Ldontneed: if (X) printf("\tdontneed\n"); return 0; diff --git a/dmd2/complex_t.h b/dmd2/complex_t.h index a1b4f4ed..fa39271e 100644 --- a/dmd2/complex_t.h +++ b/dmd2/complex_t.h @@ -16,12 +16,14 @@ struct complex_t { - long double re; - long double im; + longdouble re; + longdouble im; complex_t() { this->re = 0; this->im = 0; } - complex_t(long double re) { this->re = re; this->im = 0; } - complex_t(long double re, long double im) { this->re = re; this->im = im; } + complex_t(longdouble re) { this->re = re; this->im = 0; } + complex_t(double re) { this->re = re; this->im = 0; } + complex_t(longdouble re, longdouble im) { this->re = re; this->im = im; } + complex_t(double re, double im) { this->re = re; this->im = im; } complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; } complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; } @@ -30,9 +32,9 @@ struct complex_t complex_t operator / (complex_t y) { - long double abs_y_re = y.re < 0 ? -y.re : y.re; - long double abs_y_im = y.im < 0 ? -y.im : y.im; - long double r, den; + longdouble abs_y_re = y.re < 0 ? -y.re : y.re; + longdouble abs_y_im = y.im < 0 ? -y.im : y.im; + longdouble r, den; if (abs_y_re < abs_y_im) { @@ -56,17 +58,17 @@ struct complex_t int operator != (complex_t y) { return re != y.re || im != y.im; } }; -inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; } -inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); } -inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); } +inline complex_t operator * (longdouble x, complex_t y) { return complex_t(x) * y; } +inline complex_t operator * (complex_t x, longdouble y) { return x * complex_t(y); } +inline complex_t operator / (complex_t x, longdouble y) { return x / complex_t(y); } -inline long double creall(complex_t x) +inline longdouble creall(complex_t x) { return x.re; } -inline long double cimagl(complex_t x) +inline longdouble cimagl(complex_t x) { return x.im; } diff --git a/dmd2/constfold.c b/dmd2/constfold.c index 38d00efd..0be4cb82 100644 --- a/dmd2/constfold.c +++ b/dmd2/constfold.c @@ -585,12 +585,12 @@ Expression *Pow(Type *type, Expression *e1, Expression *e2) if (e1->type->isfloating()) { r = new RealExp(loc, e1->toReal(), e1->type); - v = new RealExp(loc, 1.0, e1->type); + v = new RealExp(loc, ldouble(1.0), e1->type); } else { r = new RealExp(loc, e1->toReal(), Type::tfloat64); - v = new RealExp(loc, 1.0, Type::tfloat64); + v = new RealExp(loc, ldouble(1.0), Type::tfloat64); } while (n != 0) @@ -602,7 +602,7 @@ Expression *Pow(Type *type, Expression *e1, Expression *e2) } if (neg) - v = Div(v->type, new RealExp(loc, 1.0, v->type), v); + v = Div(v->type, new RealExp(loc, ldouble(1.0), v->type), v); if (type->isintegral()) e = new IntegerExp(loc, v->toInteger(), type); @@ -614,7 +614,7 @@ Expression *Pow(Type *type, Expression *e1, Expression *e2) // x ^^ y for x < 0 and y not an integer is not defined if (e1->toReal() < 0.0) { - e = new RealExp(loc, Port::nan, type); + e = new RealExp(loc, ldouble(Port::nan), type); } else if (e2->toReal() == 0.5) { @@ -1354,7 +1354,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) if (i >= es1->len) { - e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len); + e1->error("string index %llu is out of bounds [0 .. %llu]", i, (ulonglong)es1->len); e = new ErrorExp(); } else @@ -1369,7 +1369,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) if (i >= length) { - e1->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length); + e1->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length); e = new ErrorExp(); } else if (e1->op == TOKarrayliteral) @@ -1388,7 +1388,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; if (i >= ale->elements->dim) { - e1->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); + e1->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); e = new ErrorExp(); } else @@ -1444,7 +1444,7 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) if (iupr > es1->len || ilwr > iupr) { - e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr); + e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr); e = new ErrorExp(); } else @@ -1474,7 +1474,7 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) if (iupr > es1->elements->dim || ilwr > iupr) { - e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr); + e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr); e = new ErrorExp(); } else diff --git a/dmd2/cppmangle.c b/dmd2/cppmangle.c index 630567ef..915bb23c 100644 --- a/dmd2/cppmangle.c +++ b/dmd2/cppmangle.c @@ -277,7 +277,7 @@ void TypeVector::toCppMangle(OutBuffer *buf, CppMangleState *cms) void TypeSArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) { if (!cms->substitute(buf, this)) - { buf->printf("A%ju_", dim ? dim->toInteger() : 0); + { buf->printf("A%llu_", dim ? dim->toInteger() : 0); next->toCppMangle(buf, cms); } } diff --git a/dmd2/declaration.c b/dmd2/declaration.c index 6f7c3558..2d284b09 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.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 @@ -512,7 +512,8 @@ void AliasDeclaration::semantic(Scope *sc) if (s) goto L2; - error("cannot alias an expression %s", e->toChars()); + if (e->op != TOKerror) + error("cannot alias an expression %s", e->toChars()); t = e->type; } else if (t) @@ -524,7 +525,7 @@ void AliasDeclaration::semantic(Scope *sc) ScopeDsymbol::multiplyDefined(0, this, overnext); this->inSemantic = 0; - if (errors != global.errors) + if (global.gag && errors != global.errors) type = savedtype; return; @@ -563,7 +564,7 @@ void AliasDeclaration::semantic(Scope *sc) assert(global.errors); s = NULL; } - if (errors != global.errors) + if (global.gag && errors != global.errors) { type = savedtype; overnext = savedovernext; @@ -698,6 +699,7 @@ VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer #if DMDV1 nestedref = 0; #endif + alignment = 0; ctorinit = 0; aliassym = NULL; onstack = 0; @@ -1012,7 +1014,7 @@ Lnomatch: { Parameter *arg = Parameter::getNth(tt->arguments, i); OutBuffer buf; - buf.printf("_%s_field_%zu", ident->toChars(), i); + buf.printf("_%s_field_%llu", ident->toChars(), (ulonglong)i); buf.writeByte(0); const char *name = (const char *)buf.extractData(); Identifier *id = Lexer::idPool(name); @@ -1090,9 +1092,7 @@ Lnomatch: } else { - AggregateDeclaration *aad = sc->anonAgg; - if (!aad) - aad = parent->isAggregateDeclaration(); + AggregateDeclaration *aad = parent->isAggregateDeclaration(); if (aad) { #if DMDV2 @@ -1104,15 +1104,16 @@ Lnomatch: storage_class |= STCstatic; } else +#endif { - aad->addField(sc, this); + storage_class |= STCfield; + alignment = sc->structalign; +#if DMDV2 if (tb->ty == Tstruct && ((TypeStruct *)tb)->sym->noDefaultCtor || tb->ty == Tclass && ((TypeClass *)tb)->sym->noDefaultCtor) aad->noDefaultCtor = TRUE; - } -#else - aad->addField(sc, this); #endif + } } InterfaceDeclaration *id = parent->isInterfaceDeclaration(); @@ -1165,7 +1166,7 @@ Lnomatch: { if (func->fes) func = func->fes->func; - if (!func->type->hasWild()) + if (!((TypeFunction *)func->type)->iswild) { error("inout variables can only be declared inside inout functions"); } @@ -1271,9 +1272,6 @@ Lnomatch: StructInitializer *si = init->isStructInitializer(); ExpInitializer *ei = init->isExpInitializer(); - 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 @@ -1322,6 +1320,8 @@ Lnomatch: Expression *e1 = new VarExp(loc, this); Type *t = type->toBasetype(); + if (ei && !inferred) + ei->exp = ei->exp->inferType(t); Linit2: if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) @@ -1597,6 +1597,31 @@ Ldtor: void VarDeclaration::semantic2(Scope *sc) { //printf("VarDeclaration::semantic2('%s')\n", toChars()); + // Inside unions, default to void initializers + if (!init && sc->inunion && !toParent()->isFuncDeclaration()) + { + AggregateDeclaration *aad = parent->isAggregateDeclaration(); + if (aad) + { + if (aad->fields[0] == this) + { + int hasinit = 0; + for (size_t i = 1; i < aad->fields.dim; i++) + { + if (aad->fields[i]->init && + !aad->fields[i]->init->isVoidInitializer()) + { + hasinit = 1; + break; + } + } + if (!hasinit) + init = new ExpInitializer(loc, type->defaultInitLiteral(loc)); + } + else + init = new VoidInitializer(loc); + } + } if (init && !toParent()->isFuncDeclaration()) { inuse++; #if 0 @@ -1613,6 +1638,82 @@ void VarDeclaration::semantic2(Scope *sc) sem = Semantic2Done; } +void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) +{ + //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars()); + + if (aliassym) + { // If this variable was really a tuple, set the offsets for the tuple fields + TupleDeclaration *v2 = aliassym->isTupleDeclaration(); + assert(v2); + for (size_t i = 0; i < v2->objects->dim; i++) + { Object *o = (*v2->objects)[i]; + assert(o->dyncast() == DYNCAST_EXPRESSION); + Expression *e = (Expression *)o; + assert(e->op == TOKdsymbol); + DsymbolExp *se = (DsymbolExp *)e; + se->s->setFieldOffset(ad, poffset, isunion); + } + return; + } + + if (!(storage_class & STCfield)) + return; + assert(!(storage_class & (STCstatic | STCextern | STCparameter | STCtls))); + + /* Fields that are tuples appear both as part of TupleDeclarations and + * as members. That means ignore them if they are already a field. + */ + if (offset) + return; // already a field + for (size_t i = 0; i < ad->fields.dim; i++) + { + if (ad->fields[i] == this) + return; // already a field + } + + // Check for forward referenced types which will fail the size() call + Type *t = type->toBasetype(); + if (storage_class & STCref) + { // References are the size of a pointer + t = Type::tvoidptr; + } + if (t->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)t; +#if DMDV2 + if (ts->sym == ad) + { + ad->error("cannot have field %s with same struct type", toChars()); + } +#endif + + if (ts->sym->sizeok != SIZEOKdone && ts->sym->scope) + ts->sym->semantic(NULL); + if (ts->sym->sizeok != SIZEOKdone) + { + ad->sizeok = SIZEOKfwd; // cannot finish; flag as forward referenced + return; + } + } + if (t->ty == Tident) + { + ad->sizeok = SIZEOKfwd; // cannot finish; flag as forward referenced + return; + } + + unsigned memsize = t->size(loc); // size of member + unsigned memalignsize = t->alignsize(); // size of member for alignment purposes + unsigned memalign = t->memalign(alignment); // alignment boundaries + + offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, memalign, + &ad->structsize, &ad->alignsize, isunion); + + //printf("\t%s: alignsize = %d\n", toChars(), alignsize); + + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad->toChars(), offset, memsize); + ad->fields.push(this); +} + void VarDeclaration::semantic3(Scope *sc) { // LDC diff --git a/dmd2/declaration.h b/dmd2/declaration.h index 079adfdf..b9429f6a 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -132,6 +132,10 @@ struct Declaration : Dsymbol enum LINK linkage; int inuse; // used to detect cycles +#if IN_GCC + Expressions *attributes; // GCC decl/type attributes +#endif + enum Semantic sem; Declaration(Identifier *id); @@ -280,6 +284,7 @@ struct VarDeclaration : Declaration #else int nestedref; // referenced by a lexically nested function #endif + unsigned short alignment; int ctorinit; // it has been initialized in a ctor int onstack; // 1: it has been allocated on the stack // 2: on stack, run destructor anyway @@ -306,6 +311,7 @@ struct VarDeclaration : Declaration VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); + void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); void semantic2(Scope *sc); const char *kind(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -700,6 +706,9 @@ enum BUILTIN BUILTINbsr, // core.bitop.bsr BUILTINbsf, // core.bitop.bsf BUILTINbswap, // core.bitop.bswap +#if IN_GCC + BUILTINgcc, // GCC builtin +#endif }; Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments); @@ -778,6 +787,7 @@ struct FuncDeclaration : Declaration VarDeclarations closureVars; // local variables in this function // which are referenced by nested // functions + FuncDeclarations deferred; // toObjFile() these functions after this one unsigned flags; #define FUNCFLAGpurityInprocess 1 // working on determining purity @@ -822,10 +832,12 @@ struct FuncDeclaration : Declaration int isAbstract(); int isCodeseg(); int isOverloadable(); + int hasOverloads(); enum PURE isPure(); enum PURE isPureBypassingInference(); bool setImpure(); int isSafe(); + bool isSafeBypassingInference(); int isTrusted(); bool setUnsafe(); virtual int isNested(); @@ -862,6 +874,8 @@ struct FuncDeclaration : Declaration #endif FuncDeclaration *isFuncDeclaration() { return this; } + virtual FuncDeclaration *toAliasFunc() { return this; } + #if IN_LLVM // LDC stuff @@ -905,15 +919,19 @@ FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, struct FuncAliasDeclaration : FuncDeclaration { FuncDeclaration *funcalias; + int hasOverloads; PROT importprot; // if generated by import, store its protection - FuncAliasDeclaration(FuncDeclaration *funcalias); + FuncAliasDeclaration(FuncDeclaration *funcalias, int hasOverloads = 1); FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } const char *kind(); #if IN_DMD Symbol *toSymbol(); + char *mangle() { return toAliasFunc()->mangle(); } #endif + + FuncDeclaration *toAliasFunc(); }; struct FuncLiteralDeclaration : FuncDeclaration diff --git a/dmd2/delegatize.c b/dmd2/delegatize.c index a4d37152..b08892f1 100644 --- a/dmd2/delegatize.c +++ b/dmd2/delegatize.c @@ -34,7 +34,10 @@ int lambdaCheckForNestedRef(Expression *e, void *param); Expression *Expression::toDelegate(Scope *sc, Type *t) { //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars()); - TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd); + Type *tw = t->semantic(loc, sc); + Type *tc = t->substWildTo(MODconst)->semantic(loc, sc); + TypeFunction *tf = new TypeFunction(NULL, tc, 0, LINKd); + (tf = (TypeFunction *)tf->semantic(loc, sc))->next = tw; // hack for bug7757 FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL); Expression *e; diff --git a/dmd2/dmd_msc.vcproj b/dmd2/dmd_msc.vcproj new file mode 100644 index 00000000..94a9e4f9 --- /dev/null +++ b/dmd2/dmd_msc.vcproj @@ -0,0 +1,2088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dmd2/doc.c b/dmd2/doc.c index ed405f24..094d5947 100644 --- a/dmd2/doc.c +++ b/dmd2/doc.c @@ -261,6 +261,9 @@ void Module::gendocfile() Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); } + char *srcfilename = srcfile->toChars(); + Macro::define(¯otable, (unsigned char *)"SRCFILENAME", 11, (unsigned char *)srcfilename, strlen(srcfilename)); + char *docfilename = docfile->toChars(); Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c index 45c2641c..f6563ccb 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.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 @@ -50,6 +50,7 @@ Dsymbol::Dsymbol() this->loc = 0; this->comment = NULL; this->scope = NULL; + this->errors = false; #if IN_LLVM this->llvmInternal = LLVMnone; @@ -70,6 +71,7 @@ Dsymbol::Dsymbol(Identifier *ident) this->loc = 0; this->comment = NULL; this->scope = NULL; + this->errors = false; #if IN_LLVM this->llvmInternal = LLVMnone; @@ -147,12 +149,15 @@ int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) if (!(*ps)->ident || !(*ps)->ident->equals(ident)) continue; } - if (s) // more than one symbol + if (!s) + s = *ps; + else if (s->isOverloadable() && (*ps)->isOverloadable()) + ; // keep head of overload set + else // more than one symbol { *ps = NULL; //printf("\tfalse 2\n"); return FALSE; } - s = *ps; } } } @@ -177,6 +182,10 @@ bool Dsymbol::hasStaticCtorOrDtor() return FALSE; } +void Dsymbol::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) +{ +} + char *Dsymbol::toChars() { return ident ? ident->toChars() : (char *)"__anonymous"; @@ -291,6 +300,23 @@ TemplateInstance *Dsymbol::inTemplateInstance() return NULL; } +// Check if this function is a member of a template which has only been +// instantiated speculatively, eg from inside is(typeof()). +// Return the speculative template instance it is part of, +// or NULL if not speculative. +TemplateInstance *Dsymbol::isSpeculative() +{ + Dsymbol * par = parent; + while (par) + { + TemplateInstance *ti = par->isTemplateInstance(); + if (ti && ti->speculative) + return ti; + par = par->toParent(); + } + return NULL; +} + int Dsymbol::isAnonymous() { return ident ? 0 : 1; @@ -375,11 +401,21 @@ Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) void *symbol_search_fp(void *arg, const char *seed) { + /* If not in the lexer's string table, it certainly isn't in the symbol table. + * Doing this first is a lot faster. + */ + size_t len = strlen(seed); + if (!len) + return NULL; + StringValue *sv = Lexer::stringtable.lookup(seed, len); + if (!sv) + return NULL; + Identifier *id = (Identifier *)sv->ptrvalue; + assert(id); + Dsymbol *s = (Dsymbol *)arg; - Identifier id(seed, 0); Module::clearCache(); - s = s->search(0, &id, 4|2); - return s; + return s->search(0, id, 4|2); } Dsymbol *Dsymbol::search_correct(Identifier *ident) @@ -417,8 +453,14 @@ Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) id = ti->name; sm = s->search(loc, id, 0); if (!sm) - { error("template identifier %s is not a member of %s %s", - id->toChars(), s->kind(), s->toChars()); + { + sm = s->search_correct(id); + if (sm) + error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", + id->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); + else + error("template identifier '%s' is not a member of '%s %s'", + id->toChars(), s->kind(), s->toChars()); return NULL; } sm = sm->toAlias(); @@ -507,6 +549,11 @@ int Dsymbol::isOverloadable() { return 0; } + +int Dsymbol::hasOverloads() +{ + return 0; +} #endif LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? @@ -532,6 +579,11 @@ int Dsymbol::needThis() return FALSE; } +int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param) +{ + return (*fp)(this, param); +} + int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { //printf("Dsymbol::addMember('%s')\n", toChars()); @@ -1118,7 +1170,7 @@ int ScopeDsymbol::foreach(Dsymbols *members, ScopeDsymbol::ForeachDg dg, void *c { Dsymbol *s = (*members)[i]; if (AttribDeclaration *a = s->isAttribDeclaration()) - result = foreach(a->decl, dg, ctx, &n); + result = foreach(a->include(NULL, NULL), dg, ctx, &n); else if (TemplateMixin *tm = s->isTemplateMixin()) result = foreach(tm->members, dg, ctx, &n); else if (s->isTemplateInstance()) diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h index 2b16eecb..c905ebf9 100644 --- a/dmd2/dsymbol.h +++ b/dmd2/dsymbol.h @@ -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 @@ -134,6 +134,8 @@ enum PASS PASSobj, // toObjFile() run }; +typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *); + struct Dsymbol : Object { Identifier *ident; @@ -146,6 +148,7 @@ struct Dsymbol : Object unsigned char *comment; // documentation comment for this Dsymbol Loc loc; // where defined Scope *scope; // !=NULL means context to use for semantic() + bool errors; // this symbol failed to pass semantic() Dsymbol(); Dsymbol(Identifier *); @@ -163,6 +166,7 @@ struct Dsymbol : Object Dsymbol *toParent(); Dsymbol *toParent2(); TemplateInstance *inTemplateInstance(); + TemplateInstance *isSpeculative(); int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() @@ -171,6 +175,7 @@ struct Dsymbol : Object virtual const char *toPrettyChars(); virtual const char *kind(); virtual Dsymbol *toAlias(); // resolve real symbol + virtual int apply(Dsymbol_apply_ft_t fp, void *param); virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); virtual void setScope(Scope *sc); virtual void importAll(Scope *sc); @@ -199,6 +204,7 @@ struct Dsymbol : Object virtual int isDeprecated(); // is Dsymbol deprecated? #if DMDV2 virtual int isOverloadable(); + virtual int hasOverloads(); #endif virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? @@ -209,6 +215,7 @@ struct Dsymbol : Object virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees virtual int oneMember(Dsymbol **ps, Identifier *ident); static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL); + virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); virtual int hasPointers(); virtual bool hasStaticCtorOrDtor(); virtual void addLocalClass(ClassDeclarations *) { } diff --git a/dmd2/dump.c b/dmd2/dump.c index 4fd0d04e..c9e4f5ff 100644 --- a/dmd2/dump.c +++ b/dmd2/dump.c @@ -55,7 +55,7 @@ void Expression::dump(int i) void IntegerExp::dump(int i) { indent(i); - printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type)); + printf("%p %lld type=%s\n", this, (ulonglong)value, type_print(type)); } void IdentifierExp::dump(int i) diff --git a/dmd2/enum.c b/dmd2/enum.c index a92e9ef9..a09a7e93 100644 --- a/dmd2/enum.c +++ b/dmd2/enum.c @@ -169,6 +169,7 @@ void EnumDeclaration::semantic(Scope *sc) { EnumMember *em = (*members)[i]->isEnumMember(); Expression *e; + Expression *emax = NULL; if (!em) /* The e->semantic(sce) can insert other symbols, such as @@ -219,10 +220,18 @@ void EnumDeclaration::semantic(Scope *sc) } else { + // Lazily evaluate enum.max + if (!emax) + { + emax = t->getProperty(0, Id::max); + emax = emax->semantic(sce); + emax = emax->optimize(WANTvalue | WANTinterpret); + } + // Set value to (elast + 1). // But first check that (elast != t.max) assert(elast); - e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max)); + e = new EqualExp(TOKequal, em->loc, elast, emax); e = e->semantic(sce); e = e->optimize(WANTvalue | WANTinterpret); if (e->toInteger()) @@ -233,6 +242,16 @@ void EnumDeclaration::semantic(Scope *sc) e = e->semantic(sce); e = e->castTo(sce, elast->type); e = e->optimize(WANTvalue | WANTinterpret); + + if (t->isfloating()) + { + // Check that e != elast (not always true for floats) + Expression *etest = new EqualExp(TOKequal, em->loc, e, elast); + etest = etest->semantic(sce); + etest = etest->optimize(WANTvalue | WANTinterpret); + if (etest->toInteger()) + error("enum member %s has inexact value, due to loss of precision", em->toChars()); + } } elast = e; em->value = e; diff --git a/dmd2/enum.h b/dmd2/enum.h index b8b3290e..c13d90ca 100644 --- a/dmd2/enum.h +++ b/dmd2/enum.h @@ -42,6 +42,9 @@ struct EnumDeclaration : ScopeDsymbol int isdeprecated; int isdone; // 0: not done // 1: semantic() successfully completed +#if IN_GCC + Expressions *attributes; // GCC decl/type attributes +#endif EnumDeclaration(Loc loc, Identifier *id, Type *memtype); Dsymbol *syntaxCopy(Dsymbol *s); diff --git a/dmd2/expression.c b/dmd2/expression.c index e2daf426..5fdf13ec 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.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 @@ -325,6 +325,113 @@ return_expr: return e; } +/****************************** + * Check the tail CallExp is really property function call. + */ + +void checkPropertyCall(Expression *e, Expression *emsg) +{ + while (e->op == TOKcomma) + e = ((CommaExp *)e)->e2; + + if (e->op == TOKcall) + { CallExp *ce = (CallExp *)e; + TypeFunction *tf; + if (ce->f) + tf = (TypeFunction *)ce->f->type; + else if (ce->e1->type->ty == Tfunction) + tf = (TypeFunction *)ce->e1->type; + else if (ce->e1->type->ty == Tdelegate) + tf = (TypeFunction *)ce->e1->type->nextOf(); + else if (ce->e1->type->ty == Tpointer && ce->e1->type->nextOf()->ty == Tfunction) + tf = (TypeFunction *)ce->e1->type->nextOf(); + else + assert(0); + + if (!tf->isproperty && global.params.enforcePropertySyntax) + ce->e1->error("not a property %s", emsg->toChars()); + } +} + +/****************************** + * Pull out property with UFCS. + */ + +Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL) +{ + Expression *e = NULL; + Expression *eleft; + Identifier *ident; + Objects* tiargs; + Loc loc = e1->loc; + + if (e1->op == TOKdot) + { + DotIdExp *die = (DotIdExp *)e1; + eleft = die->e1; + ident = die->ident; + tiargs = NULL; + goto L1; + } + else if (e1->op == TOKdotti) + { + DotTemplateInstanceExp *dti; + dti = (DotTemplateInstanceExp *)e1; + eleft = dti->e1; + ident = dti->ti->name; + tiargs = dti->ti->tiargs; + L1: + /* .ident + * .ident!tiargs + */ + e = new IdentifierExp(loc, Id::empty); + if (tiargs) + e = new DotTemplateInstanceExp(loc, e, ident, tiargs); + else + e = new DotIdExp(loc, e, ident); + + Expressions *arguments = new Expressions(); + /* .f(e1, e2) + */ + if (e2) + { + arguments->setDim(2); + (*arguments)[0] = eleft; + (*arguments)[1] = e2; + + Expression *ex = e->syntaxCopy(); + e = new CallExp(loc, e, arguments); + e = e->trySemantic(sc); + if (e) + { checkPropertyCall(e, e1); + return e->semantic(sc); + } + e = ex; + } + + /* .f(e1) + * .f(e1) = e2 + */ + { + arguments->setDim(1); + (*arguments)[0] = eleft; + e = new CallExp(loc, e, arguments); + e = e->trySemantic(sc); + if (!e) + goto Leprop; + checkPropertyCall(e, e1); + if (e2) + e = new AssignExp(loc, e, e2); + return e->semantic(sc); + } + } + return e; + +Leprop: + e1->error("not a property %s", e1->toChars()); + return new ErrorExp(); +} + /****************************** * Perform semantic() on an array of Expressions. */ @@ -530,7 +637,7 @@ Expressions *arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt e = resolveProperties(sc, e); if (!e->type) - { error("%s has no value", e->toChars()); + { e->error("%s has no value", e->toChars()); e = new ErrorExp(); } @@ -694,23 +801,6 @@ Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope) } #endif -// Check if this function is a member of a template which has only been -// instantiated speculatively, eg from inside is(typeof()). -// Return the speculative template instance it is part of, -// or NULL if not speculative. -TemplateInstance *isSpeculativeFunction(FuncDeclaration *fd) -{ - Dsymbol * par = fd->parent; - while (par) - { - TemplateInstance *ti = par->isTemplateInstance(); - if (ti && ti->speculative) - return ti; - par = par->toParent(); - } - return NULL; -} - /**************************************** * Now that we know the exact type of the function we're calling, * the arguments[] need to be adjusted: @@ -733,14 +823,14 @@ 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 %llu for non-variadic function type %s", nparams, (ulonglong)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) { - TemplateInstance *spec = isSpeculativeFunction(fd); + TemplateInstance *spec = fd->isSpeculative(); int olderrs = global.errors; fd->semantic3(fd->scope); // Update the template instantiation with the number @@ -785,7 +875,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); + error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs); return Type::terror; } arg = p->defaultArg; @@ -796,25 +886,25 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, arguments->push(arg); nargs++; } - else if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; + else + { 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; + arg = arg->inferType(pt); + arguments->tdata()[i] = arg; } if (tf->varargs == 2 && i + 1 == nparams) { //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); - if (arg->implicitConvTo(p->type)) + MATCH m; + if ((m = arg->implicitConvTo(p->type)) != MATCHnomatch) { - if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf())) + if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m) goto L2; else if (nargs != nparams) - { error(loc, "expected %zu function arguments, not %zu", nparams, nargs); + { error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs); return Type::terror; } goto L1; @@ -1175,18 +1265,17 @@ void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) * Write out argument list to buf. */ -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) +void argsToCBuffer(OutBuffer *buf, Expressions *expressions, HdrGenState *hgs) { - if (arguments) + if (expressions) { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = arguments->tdata()[i]; + for (size_t i = 0; i < expressions->dim; i++) + { Expression *e = (*expressions)[i]; - if (arg) - { if (i) - buf->writeByte(','); - expToCBuffer(buf, hgs, arg, PREC_assign); - } + if (i) + buf->writeByte(','); + if (e) + expToCBuffer(buf, hgs, e, PREC_assign); } } } @@ -1201,12 +1290,12 @@ void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *h { OutBuffer argbuf; for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = arguments->tdata()[i]; + { Expression *e = (*arguments)[i]; if (i) buf->writeByte(','); argbuf.reset(); - arg->type->toCBuffer2(&argbuf, hgs, 0); + e->type->toCBuffer2(&argbuf, hgs, 0); buf->write(&argbuf); } } @@ -1376,13 +1465,13 @@ uinteger_t Expression::toUInteger() real_t Expression::toReal() { error("Floating point constant expression expected instead of %s", toChars()); - return 0; + return ldouble(0); } real_t Expression::toImaginary() { error("Floating point constant expression expected instead of %s", toChars()); - return 0; + return ldouble(0); } complex_t Expression::toComplex() @@ -1391,7 +1480,7 @@ complex_t Expression::toComplex() #ifdef IN_GCC return complex_t(real_t(0)); // %% nicer #else - return 0; + return 0.0; #endif } @@ -1408,9 +1497,6 @@ void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs) void Expression::toMangleBuffer(OutBuffer *buf) { error("expression %s is not a valid template value argument", toChars()); -#ifdef DEBUG -dump(0); -#endif } /*************************************** @@ -1600,7 +1686,7 @@ void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis) break; if (ff->setImpure() && !msg) { error("pure function '%s' cannot access mutable static data '%s'", - sc->func->toChars(), v->toChars()); + sc->func->toPrettyChars(), v->toChars()); msg = TRUE; // only need the innermost message } } @@ -1672,6 +1758,7 @@ Expression *Expression::checkToBoolean(Scope *sc) #ifdef DEBUG if (!type) dump(0); + assert(type); #endif // Structs can be converted to bool using opCast(bool)() @@ -1692,9 +1779,7 @@ Expression *Expression::checkToBoolean(Scope *sc) // Forward to aliasthis. if (ad->aliasthis) { - Expression *e = new DotIdExp(loc, this, ad->aliasthis->ident); - e = e->semantic(sc); - e = resolveProperties(sc, e); + Expression *e = resolveAliasThis(sc, this); e = e->checkToBoolean(sc); return e; } @@ -1900,7 +1985,7 @@ char *IntegerExp::toChars() #else static char buffer[sizeof(value) * 3 + 1]; - sprintf(buffer, "%jd", value); + sprintf(buffer, "%lld", value); return buffer; #endif } @@ -1972,14 +2057,14 @@ real_t IntegerExp::toReal() toInteger(); t = type->toBasetype(); if (t->ty == Tuns64) - return (real_t)(d_uns64)value; + return ldouble((d_uns64)value); else - return (real_t)(d_int64)value; + return ldouble((d_int64)value); } real_t IntegerExp::toImaginary() { - return (real_t) 0; + return ldouble(0); } complex_t IntegerExp::toComplex() @@ -2096,12 +2181,12 @@ void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) break; case Tint64: - buf->printf("%jdL", v); + buf->printf("%lldL", v); break; case Tuns64: L4: - buf->printf("%juLU", v); + buf->printf("%lluLU", v); break; case Tbool: @@ -2134,15 +2219,15 @@ void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } } else if (v & 0x8000000000000000LL) - buf->printf("0x%jx", v); + buf->printf("0x%llx", v); else - buf->printf("%jd", v); + buf->printf("%lld", v); } void IntegerExp::toMangleBuffer(OutBuffer *buf) { if ((sinteger_t)value < 0) - buf->printf("N%jd", -value); + buf->printf("N%lld", -value); else { /* This is an awful hack to maintain backwards compatibility. @@ -2154,7 +2239,7 @@ void IntegerExp::toMangleBuffer(OutBuffer *buf) if (buf->offset > 0 && isdigit(buf->data[buf->offset - 1])) buf->writeByte('i'); - buf->printf("%jd", value); + buf->printf("%lld", value); } } @@ -2196,11 +2281,12 @@ char *RealExp::toChars() #ifdef IN_GCC value.format(buffer, sizeof(buffer)); +#else + ld_sprint(buffer, 'g', value); +#endif if (type->isimaginary()) strcat(buffer, "i"); -#else - sprintf(buffer, type->isimaginary() ? "%Lgi" : "%Lg", value); -#endif + assert(strlen(buffer) < sizeof(buffer)); return mem.strdup(buffer); } @@ -2208,7 +2294,7 @@ char *RealExp::toChars() dinteger_t RealExp::toInteger() { #ifdef IN_GCC - return toReal().toInt(); + return (sinteger_t) toReal().toInt(); #else return (sinteger_t) toReal(); #endif @@ -2225,12 +2311,12 @@ uinteger_t RealExp::toUInteger() real_t RealExp::toReal() { - return type->isreal() ? value : 0; + return type->isreal() ? value : ldouble(0); } real_t RealExp::toImaginary() { - return type->isreal() ? 0 : value; + return type->isreal() ? ldouble(0) : value; } complex_t RealExp::toComplex() @@ -2303,7 +2389,7 @@ void floatToBuffer(OutBuffer *buf, Type *type, real_t value) * always exact. */ char buffer[25]; - sprintf(buffer, "%Lg", value); + ld_sprint(buffer, 'g', value); assert(strlen(buffer) < sizeof(buffer)); #if _WIN32 && __DMC__ char *save = __locale_decpoint; @@ -2313,21 +2399,9 @@ void floatToBuffer(OutBuffer *buf, Type *type, real_t value) #else real_t r = strtold(buffer, NULL); #endif - if (r == value) // if exact duplication - buf->writestring(buffer); - else - { -#ifdef __HAIKU__ // broken printf workaround - char buffer2[25]; - char *ptr = (char *)&value; - for(int i = 0; i < sizeof(value); i++) - snprintf(buffer2, sizeof(char), "%x", ptr[i]); - - buf->writestring(buffer2); -#else - buf->printf("%La", value); // ensure exact duplication -#endif - } + if (r != value) // if exact duplication + ld_sprint(buffer, 'a', value); + buf->writestring(buffer); if (type) { @@ -2382,7 +2456,7 @@ void realToMangleBuffer(OutBuffer *buf, real_t value) else { char buffer[32]; - int n = sprintf(buffer, "%LA", value); + int n = ld_sprint(buffer, 'A', value); assert(n > 0 && n < sizeof(buffer)); for (int i = 0; i < n; i++) { char c = buffer[i]; @@ -2430,16 +2504,17 @@ char *ComplexExp::toChars() { char buffer[sizeof(value) * 3 + 8 + 1]; -#ifdef IN_GCC char buf1[sizeof(value) * 3 + 8 + 1]; char buf2[sizeof(value) * 3 + 8 + 1]; +#ifdef IN_GCC creall(value).format(buf1, sizeof(buf1)); cimagl(value).format(buf2, sizeof(buf2)); - sprintf(buffer, "(%s+%si)", buf1, buf2); #else - sprintf(buffer, "(%Lg+%Lgi)", creall(value), cimagl(value)); - assert(strlen(buffer) < sizeof(buffer)); + ld_sprint(buffer, 'g', creall(value)); + ld_sprint(buffer, 'g', cimagl(value)); #endif + sprintf(buffer, "(%s+%si)", buf1, buf2); + assert(strlen(buffer) < sizeof(buffer)); return mem.strdup(buffer); } @@ -2708,6 +2783,8 @@ DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads) this->hasOverloads = hasOverloads; } +AggregateDeclaration *isAggregate(Type *t); + Expression *DsymbolExp::semantic(Scope *sc) { #if LOGSEMANTIC @@ -2765,6 +2842,7 @@ Lagain: if (em) { e = em->value; + e->loc = loc; e = e->semantic(sc); return e; } @@ -2811,12 +2889,18 @@ Lagain: { //printf("'%s' is a function\n", f->toChars()); if (!f->originalType && f->scope) // semantic not yet run + { + unsigned oldgag = global.gag; + if (global.isSpeculativeGagging() && !f->isSpeculative()) + global.gag = 0; f->semantic(f->scope); + global.gag = oldgag; + } // if inferring return type, sematic3 needs to be run if (f->inferRetType && f->scope && f->type && !f->type->nextOf()) { - TemplateInstance *spec = isSpeculativeFunction(f); + TemplateInstance *spec = f->isSpeculative(); int olderrs = global.errors; f->semantic3(f->scope); // Update the template instantiation with the number @@ -2894,7 +2978,7 @@ Lagain: } TemplateInstance *ti = s->isTemplateInstance(); - if (ti && !global.errors) + if (ti) { if (!ti->semanticRun) ti->semantic(sc); s = ti->inst->toAlias(); @@ -2908,12 +2992,14 @@ Lagain: TemplateDeclaration *td = s->isTemplateDeclaration(); if (td) { -#if 0 // This was the fix for Bugzilla 6738, but it breaks 7498 Dsymbol *p = td->toParent2(); - if (hasThis(sc) && p && p->isAggregateDeclaration()) + FuncDeclaration *fdthis = hasThis(sc); + AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL; + if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad) + { e = new DotTemplateExp(loc, new ThisExp(loc), td); + } else -#endif e = new TemplateExp(loc, td); e = e->semantic(sc); return e; @@ -3766,6 +3852,9 @@ Expression *AssocArrayLiteralExp::semantic(Scope *sc) keys = arrayExpressionToCommonType(sc, keys, &tkey); values = arrayExpressionToCommonType(sc, values, &tvalue); + if (tkey == Type::terror || tvalue == Type::terror) + return new ErrorExp; + type = new TypeAArray(tvalue, tkey); type = type->semantic(loc, sc); return this; @@ -3818,6 +3907,7 @@ StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions * this->elements = elements; this->stype = stype; #if IN_DMD + this->sinit = NULL; this->sym = NULL; #endif this->soffset = 0; @@ -3825,7 +3915,8 @@ StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions * this->ownedByCtfe = false; #if IN_LLVM constType = NULL; -#endif +#endif + //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars()); } Expression *StructLiteralExp::syntaxCopy() @@ -3835,7 +3926,6 @@ Expression *StructLiteralExp::syntaxCopy() Expression *StructLiteralExp::semantic(Scope *sc) { Expression *e; - size_t nfields = sd->fields.dim - sd->isnested; #if LOGSEMANTIC printf("StructLiteralExp::semantic('%s')\n", toChars()); @@ -3843,6 +3933,11 @@ Expression *StructLiteralExp::semantic(Scope *sc) if (type) return this; + sd->size(loc); + if (sd->sizeok != SIZEOKdone) + return new ErrorExp(); + size_t nfields = sd->fields.dim - sd->isnested; + elements = arrayExpressionSemantic(elements, sc); // run semantic() on each element expandTuples(elements); size_t offset = 0; @@ -3853,7 +3948,12 @@ Expression *StructLiteralExp::semantic(Scope *sc) e = resolveProperties(sc, e); if (i >= nfields) - { error("more initializers than fields of %s", sd->toChars()); + { +#if 0 + for (size_t i = 0; i < sd->fields.dim; i++) + printf("[%d] = %s\n", i, sd->fields[i]->toChars()); +#endif + error("more initializers than fields (%d) of %s", nfields, sd->toChars()); return new ErrorExp(); } Dsymbol *s = sd->fields.tdata()[i]; @@ -3875,14 +3975,6 @@ 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; @@ -4025,19 +4117,6 @@ int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) return -1; } -#if DMDV2 -int StructLiteralExp::isLvalue() -{ - return 1; -} -#endif - -Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - - void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring(sd->toChars()); @@ -4137,8 +4216,9 @@ Expression *ScopeExp::semantic(Scope *sc) #endif Lagain: ti = sds->isTemplateInstance(); - if (ti && !global.errors) + if (ti && !ti->errors) { + unsigned olderrs = global.errors; if (!ti->semanticRun) ti->semantic(sc); if (ti->inst) @@ -4168,7 +4248,7 @@ Lagain: } //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); } - if (global.errors) + if (olderrs != global.errors) return new ErrorExp(); } else @@ -5056,49 +5136,49 @@ FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td) this->fd = fd; this->td = td; tok = fd->tok; // save original kind of function/delegate/(infer) - tded = NULL; - scope = NULL; + treq = NULL; } Expression *FuncExp::syntaxCopy() { - return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); + TemplateDeclaration *td2 = td ? (TemplateDeclaration *)td->syntaxCopy(NULL) : NULL; + return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL), td2); } Expression *FuncExp::semantic(Scope *sc) { #if LOGSEMANTIC printf("FuncExp::semantic(%s)\n", toChars()); + if (treq) printf(" treq = %s\n", treq->toChars()); #endif if (!type || type == Type::tvoid) { - // save for later use - scope = sc; + if (treq) + treq = treq->semantic(loc, sc); - //printf("td = %p, tded = %p\n", td, tded); + // Set target of return type inference + if (treq && !fd->type->nextOf()) + { TypeFunction *tfv = NULL; + if (treq->ty == Tdelegate || + (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction)) + tfv = (TypeFunction *)treq->nextOf(); + if (tfv) + { TypeFunction *tfl = (TypeFunction *)fd->type; + tfl->next = tfv->nextOf(); + } + } + + //printf("td = %p, treq = %p\n", td, treq); if (td) { assert(td->parameters && td->parameters->dim); td->semantic(sc); + type = Type::tvoid; // temporary type - if (!tded) - { // defer type determination - type = Type::tvoid; // temporary type + if (!treq) // defer type determination 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; - } + + return inferType(treq); } unsigned olderrors = global.errors; @@ -5127,7 +5207,7 @@ Expression *FuncExp::semantic(Scope *sc) // Type is a "delegate to" or "pointer to" the function literal if ((fd->isNested() && fd->tok == TOKdelegate) || - (tok == TOKreserved && tded && tded->ty == Tdelegate)) + (tok == TOKreserved && treq && treq->ty == Tdelegate)) { type = new TypeDelegate(fd->type); type = type->semantic(loc, sc); @@ -5144,9 +5224,6 @@ Expression *FuncExp::semantic(Scope *sc) // 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++) @@ -5190,88 +5267,6 @@ Expression *FuncExp::semantic(Scope *sc, Expressions *arguments) 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; - } - -#if IN_LLVM - if (fd->tok == TOKreserved && to->ty == Tpointer && to->nextOf()->ty == Tfunction) - fd->tok = TOKfunction; -#endif - - 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(); @@ -5962,44 +5957,122 @@ Expression *BinExp::semanticp(Scope *sc) } -// generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary -void BinExp::checkComplexMulAssign() +Expression *BinExp::checkComplexOpAssign(Scope *sc) { - // Any multiplication by an imaginary or complex number yields a complex result. - // r *= c, i*=c, r*=i, i*=i are all forbidden operations. - const char *opstr = Token::toChars(op); - if ( e1->type->isreal() && e2->type->iscomplex()) + // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary + if (op == TOKmulass || op == TOKdivass || op == TOKmodass) { - error("%s %s %s is undefined. Did you mean %s %s %s.re ?", - e1->type->toChars(), opstr, e2->type->toChars(), - e1->type->toChars(), opstr, e2->type->toChars()); + // Any multiplication by an imaginary or complex number yields a complex result. + // r *= c, i*=c, r*=i, i*=i are all forbidden operations. + const char *opstr = Token::toChars(op); + if ( e1->type->isreal() && e2->type->iscomplex()) + { + error("%s %s %s is undefined. Did you mean %s %s %s.re ?", + e1->type->toChars(), opstr, e2->type->toChars(), + e1->type->toChars(), opstr, e2->type->toChars()); + } + else if (e1->type->isimaginary() && e2->type->iscomplex()) + { + error("%s %s %s is undefined. Did you mean %s %s %s.im ?", + e1->type->toChars(), opstr, e2->type->toChars(), + e1->type->toChars(), opstr, e2->type->toChars()); + } + else if ((e1->type->isreal() || e1->type->isimaginary()) && + e2->type->isimaginary()) + { + error("%s %s %s is an undefined operation", e1->type->toChars(), + opstr, e2->type->toChars()); + } } - else if (e1->type->isimaginary() && e2->type->iscomplex()) - { - error("%s %s %s is undefined. Did you mean %s %s %s.im ?", - e1->type->toChars(), opstr, e2->type->toChars(), - e1->type->toChars(), opstr, e2->type->toChars()); - } - else if ((e1->type->isreal() || e1->type->isimaginary()) && - e2->type->isimaginary()) - { - error("%s %s %s is an undefined operation", e1->type->toChars(), - opstr, e2->type->toChars()); - } -} -// generate an error if this is a nonsensical += or -=, eg real += imaginary -void BinExp::checkComplexAddAssign() -{ - // Addition or subtraction of a real and an imaginary is a complex result. - // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. - if ( (e1->type->isreal() && (e2->type->isimaginary() || e2->type->iscomplex())) || - (e1->type->isimaginary() && (e2->type->isreal() || e2->type->iscomplex())) - ) + // generate an error if this is a nonsensical += or -=, eg real += imaginary + if (op == TOKaddass || op == TOKminass) { - error("%s %s %s is undefined (result is complex)", - e1->type->toChars(), Token::toChars(op), e2->type->toChars()); + // Addition or subtraction of a real and an imaginary is a complex result. + // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. + if ( (e1->type->isreal() && (e2->type->isimaginary() || e2->type->iscomplex())) || + (e1->type->isimaginary() && (e2->type->isreal() || e2->type->iscomplex())) + ) + { + error("%s %s %s is undefined (result is complex)", + e1->type->toChars(), Token::toChars(op), e2->type->toChars()); + } + if (type->isreal() || type->isimaginary()) + { + assert(global.errors || e2->type->isfloating()); + e2 = e2->castTo(sc, e1->type); + } } + + if (op == TOKmulass) + { + if (e2->type->isfloating()) + { + Type *t1 = e1->type; + Type *t2 = e2->type; + if (t1->isreal()) + { + if (t2->isimaginary() || t2->iscomplex()) + { + e2 = e2->castTo(sc, t1); + } + } + else if (t1->isimaginary()) + { + if (t2->isimaginary() || t2->iscomplex()) + { + switch (t1->ty) + { + case Timaginary32: t2 = Type::tfloat32; break; + case Timaginary64: t2 = Type::tfloat64; break; + case Timaginary80: t2 = Type::tfloat80; break; + default: + assert(0); + } + e2 = e2->castTo(sc, t2); + } + } + } + } else if (op == TOKdivass) + { + if (e2->type->isimaginary()) + { + Type *t1 = e1->type; + if (t1->isreal()) + { // x/iv = i(-x/v) + // Therefore, the result is 0 + e2 = new CommaExp(loc, e2, new RealExp(loc, ldouble(0.0), t1)); + e2->type = t1; + Expression *e = new AssignExp(loc, e1, e2); + e->type = t1; + return e; + } + else if (t1->isimaginary()) + { Type *t2; + + switch (t1->ty) + { + case Timaginary32: t2 = Type::tfloat32; break; + case Timaginary64: t2 = Type::tfloat64; break; + case Timaginary80: t2 = Type::tfloat80; break; + default: + assert(0); + } + e2 = e2->castTo(sc, t2); + Expression *e = new AssignExp(loc, e1, e2); + e->type = t1; + return e; + } + } + } else if (op == TOKmodass) + { + if (e2->type->iscomplex()) + { + error("cannot perform modulo complex arithmetic"); + return new ErrorExp(); + } + } + return this; } void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -6021,9 +6094,18 @@ Expression *BinExp::incompatibleTypes() if (e1->type->toBasetype() != Type::terror && e2->type->toBasetype() != Type::terror ) - { error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", + { + if (e1->op == TOKtype || e2->op == TOKtype) + { + error("incompatible types for ((%s) %s (%s)): cannot use '%s' with types", + e1->toChars(), Token::toChars(op), e2->toChars(), Token::toChars(op)); + } + else + { + 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; @@ -6031,94 +6113,95 @@ Expression *BinExp::incompatibleTypes() /********************** BinAssignExp **************************************/ -/*************************** - * Common semantic routine for some xxxAssignExp's. - */ +Expression *BinAssignExp::semantic(Scope *sc) +{ + Expression *e; -Expression *BinAssignExp::commonSemanticAssign(Scope *sc) -{ Expression *e; + if (type) + return this; - if (!type) + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKarraylength) { - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - if (e1->op == TOKslice) - { // T[] op= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - error("operator not allowed on bool expression %s", toChars()); - return new ErrorExp(); - } - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - - if (op == TOKmodass) - { - if (e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new ErrorExp(); - } - else if (type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - } + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; } - return this; -} -Expression *BinAssignExp::commonSemanticAssignIntegral(Scope *sc) -{ Expression *e; - - if (!type) + if (e1->op == TOKslice) { - e = op_overload(sc); - if (e) + // T[] op= ... + e = typeCombine(sc); + if (e->op == TOKerror) return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - if (e1->op == TOKslice) - { // T[] op= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - e2 = e2->implicitCastTo(sc, type); - } - - typeCombine(sc); - e1->checkIntegral(); - e2->checkIntegral(); + return arrayOp(sc); } - return this; + + e1 = e1->modifiableLvalue(sc, e1); + e1 = e1->semantic(sc); + type = e1->type; + checkScalar(); + + int arith = (op == TOKaddass || op == TOKminass || op == TOKmulass || + op == TOKdivass || op == TOKmodass || op == TOKpowass); + int bitwise = (op == TOKandass || op == TOKorass || op == TOKxorass); + int shift = (op == TOKshlass || op == TOKshrass || op == TOKushrass); + + if (bitwise && type->toBasetype()->ty == Tbool) + e2 = e2->implicitCastTo(sc, type); + else + checkNoBool(); + + if ((op == TOKaddass || op == TOKminass) && + e1->type->toBasetype()->ty == Tpointer && + e2->type->toBasetype()->isintegral()) + return scaleFactor(sc); + + typeCombine(sc); + if (arith) + { + e1 = e1->checkArithmetic(); + e2 = e2->checkArithmetic(); + } + if (bitwise || shift) + { + e1 = e1->checkIntegral(); + e2 = e2->checkIntegral(); + } + if (shift) + { +#if IN_DMD + e2 = e2->castTo(sc, Type::tshiftcnt); +#elif IN_LLVM + e2 = e2->castTo(sc, e1->type); +#endif + } + + // vectors + if (shift && (e1->type->toBasetype()->ty == Tvector || + e2->type->toBasetype()->ty == Tvector)) + return incompatibleTypes(); + + int isvector = type->toBasetype()->ty == Tvector; + + if (op == TOKmulass && isvector && !e2->type->isfloating() && + ((TypeVector *)type->toBasetype())->elementType()->size(loc) != 2) + return incompatibleTypes(); // Only short[8] and ushort[8] work with multiply + + if (op == TOKdivass && isvector && !e1->type->isfloating()) + return incompatibleTypes(); + + if (op == TOKmodass && isvector) + return incompatibleTypes(); + + if (e1->op == TOKerror || e2->op == TOKerror) + return new ErrorExp(); + + return checkComplexOpAssign(sc); } #if DMDV2 @@ -6358,7 +6441,7 @@ DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident) Expression *DotIdExp::semantic(Scope *sc) { - // Indicate we didn't come from CallExp::semantic() + // Indicate we need to resolve by UFCS. return semantic(sc, 0); } @@ -6635,7 +6718,12 @@ Expression *DotIdExp::semantic(Scope *sc, int flag) e = e->semantic(sc); return e; } - error("undefined identifier %s", toChars()); + s = ie->sds->search_correct(ident); + if (s) + error("undefined identifier '%s', did you mean '%s %s'?", + ident->toChars(), s->kind(), s->toChars()); + else + error("undefined identifier '%s'", ident->toChars()); return new ErrorExp(); } else if (t1b->ty == Tpointer && @@ -6652,23 +6740,26 @@ Expression *DotIdExp::semantic(Scope *sc, int flag) return e->type->dotExp(sc, e, ident); } #if DMDV2 - else if ((t1b->ty == Tarray || t1b->ty == Tsarray || - t1b->ty == Taarray) && - ident != Id::sort && ident != Id::reverse && - ident != Id::dup && ident != Id::idup) + else if (!flag) { /* If ident is not a valid property, rewrite: * e1.ident * as: * .ident(e1) */ + if (e1->op == TOKtype || + t1b->ty == Tvoid || + (t1b->ty == Tarray || t1b->ty == Tsarray || t1b->ty == Taarray) && + (ident == Id::sort || ident == Id::reverse || ident == Id::dup || ident == Id::idup)) + { goto L2; + } + unsigned errors = global.startGagging(); Type *t1 = e1->type; e = e1->type->dotExp(sc, e1, ident); - if (global.endGagging(errors)) // if failed to find the property + if (global.endGagging(errors)) // if failed to find the property { e1->type = t1; // kludge to restore type - e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); - e = new CallExp(loc, e, e1); + e = resolveUFCSProperties(sc, this); } e = e->semantic(sc); return e; @@ -6676,9 +6767,9 @@ Expression *DotIdExp::semantic(Scope *sc, int flag) #endif else { + L2: e = e1->type->dotExp(sc, e1, ident); - if (!(flag && e->op == TOKdotti)) // let CallExp::semantic() handle this - e = e->semantic(sc); + e = e->semantic(sc); return e; } } @@ -6965,23 +7056,41 @@ TemplateDeclaration *DotTemplateInstanceExp::getTempdecl(Scope *sc) } Expression *DotTemplateInstanceExp::semantic(Scope *sc) +{ + // Indicate we need to resolve by UFCS. + return semantic(sc, 0); +} +Expression *DotTemplateInstanceExp::semantic(Scope *sc, int flag) { #if LOGSEMANTIC printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); #endif - Expression *eleft; + + UnaExp::semantic(sc); Expression *e = new DotIdExp(loc, e1, ti->name); + + if (e1->op == TOKimport && ((ScopeExp *)e1)->sds->isModule()) + e = ((DotIdExp *)e)->semantic(sc, 1); + else + { + unsigned errors = global.startGagging(); + e = ((DotIdExp *)e)->semantic(sc, 1); + if (global.endGagging(errors) && !flag) + { + return resolveUFCSProperties(sc, this); + } + } + L1: - e = e->semantic(sc); if (e->op == TOKerror) return e; if (e->op == TOKdottd) { - if (global.errors) - return new ErrorExp(); // TemplateInstance::semantic() will fail anyway + if (ti->errors) + return new ErrorExp(); DotTemplateExp *dte = (DotTemplateExp *)e; TemplateDeclaration *td = dte->td; - eleft = dte->e1; + Expression *eleft = dte->e1; ti->tempdecl = td; if (ti->needsTypeInference(sc)) { @@ -7055,8 +7164,15 @@ L1: { TemplateExp *te = (TemplateExp *) de->e2; e = new DotTemplateExp(loc,de->e1,te->td); } + else + goto Lerr; + + e = e->semantic(sc); + if (e == de) + goto Lerr; goto L1; } +Lerr: error("%s isn't a template", e->toChars()); return new ErrorExp(); } @@ -7189,7 +7305,7 @@ Expression *CallExp::syntaxCopy() Expression *CallExp::resolveUFCS(Scope *sc) { - Expression *ethis = NULL; + Expression *e = NULL; DotIdExp *dotid; DotTemplateInstanceExp *dotti; Identifier *ident; @@ -7198,48 +7314,73 @@ Expression *CallExp::resolveUFCS(Scope *sc) { dotid = (DotIdExp *)e1; ident = dotid->ident; - ethis = dotid->e1 = dotid->e1->semantic(sc); - if (ethis->op == TOKdotexp) + e = dotid->e1 = dotid->e1->semantic(sc); + if (e->op == TOKdotexp) return NULL; - ethis = resolveProperties(sc, ethis); + e = resolveProperties(sc, e); } else if (e1->op == TOKdotti) { dotti = (DotTemplateInstanceExp *)e1; ident = dotti->ti->name; - ethis = dotti->e1 = dotti->e1->semantic(sc); - if (ethis->op == TOKdotexp) + e = dotti->e1 = dotti->e1->semantic(sc); + if (e->op == TOKdotexp) return NULL; - ethis = resolveProperties(sc, ethis); + e = resolveProperties(sc, e); } - if (ethis && ethis->type) + if (e && e->type) { + if (e->op == TOKtype || e->op == TOKimport) + return NULL; + //printf("resolveUCSS %s, e->op = %s\n", toChars(), Token::toChars(e->op)); AggregateDeclaration *ad; + Expression *esave = e; Lagain: - Type *tthis = ethis->type->toBasetype(); - if (tthis->ty == Tclass) - { - ad = ((TypeClass *)tthis)->sym; - if (search_function(ad, ident)) - return NULL; - goto L1; - } - else if (tthis->ty == Tstruct) - { - ad = ((TypeStruct *)tthis)->sym; - if (search_function(ad, ident)) - return NULL; - L1: - if (ad->aliasthis) + Type *t = e->type->toBasetype(); + if (t->ty == Tpointer) + { Type *tn = t->nextOf(); + if (tn->ty == Tclass || tn->ty == Tstruct) { - ethis = new DotIdExp(ethis->loc, ethis, ad->aliasthis->ident); - ethis = ethis->semantic(sc); - ethis = resolveProperties(sc, ethis); - goto Lagain; + e = new PtrExp(e->loc, e); + e = e->semantic(sc); + t = e->type->toBasetype(); } } - else if (tthis->ty == Taarray && e1->op == TOKdot) + if (t->ty == Tclass) + { + ad = ((TypeClass *)t)->sym; + goto L1; + } + else if (t->ty == Tstruct) + { + ad = ((TypeStruct *)t)->sym; + L1: + if (ad->search(loc, ident, 0)) + return NULL; + if (ad->aliasthis) + { + e = resolveAliasThis(sc, e); + goto Lagain; + } + if (ad->search(loc, Id::opDot, 0)) + { + e = new DotIdExp(e->loc, e, Id::opDot); + e = e->semantic(sc); + e = resolveProperties(sc, e); + goto Lagain; + } + if (ad->search(loc, Id::opDispatch, 0)) + return NULL; + e = esave; + goto Lshift; + } + else if ((t->isTypeBasic() && t->ty != Tvoid) || + t->ty == Tenum || t->ty == Tnull) + { + goto Lshift; + } + else if (t->ty == Taarray && e1->op == TOKdot) { if (ident == Id::remove) { @@ -7250,23 +7391,35 @@ Lagain: { error("expected key as argument to aa.remove()"); return new ErrorExp(); } + if (!e->type->isMutable()) + { const char *p = NULL; + if (e->type->isConst()) + p = "const"; + else if (e->type->isImmutable()) + p = "immutable"; + else + p = "inout"; + error("cannot remove key from %s associative array %s", p, e->toChars()); + return new ErrorExp(); + } Expression *key = arguments->tdata()[0]; key = key->semantic(sc); key = resolveProperties(sc, key); + + TypeAArray *taa = (TypeAArray *)t; + key = key->implicitCastTo(sc, taa->index); + if (!key->rvalue()) return new ErrorExp(); - TypeAArray *taa = (TypeAArray *)tthis; - key = key->implicitCastTo(sc, taa->index); - - return new RemoveExp(loc, ethis, key); + return new RemoveExp(loc, e, key); } else if (ident == Id::apply || ident == Id::applyReverse) { return NULL; } else - { TypeAArray *taa = (TypeAArray *)tthis; + { TypeAArray *taa = (TypeAArray *)t; assert(taa->ty == Taarray); StructDeclaration *sd = taa->getImpl(); Dsymbol *s = sd->search(0, ident, 2); @@ -7275,12 +7428,12 @@ Lagain: goto Lshift; } } - else if (tthis->ty == Tarray || tthis->ty == Tsarray) + else if (t->ty == Tarray || t->ty == Tsarray) { Lshift: if (!arguments) arguments = new Expressions(); - arguments->shift(ethis); + arguments->shift(e); if (e1->op == TOKdot) { /* Transform: @@ -7315,7 +7468,6 @@ Lshift: Expression *CallExp::semantic(Scope *sc) { - TypeFunction *tf; Type *t1; int istemp; Objects *targsi = NULL; // initial list of template arguments @@ -7381,7 +7533,10 @@ Expression *CallExp::semantic(Scope *sc) /* Attempt to instantiate ti. If that works, go with it. * If not, go with partial explicit specialization. */ + unsigned olderrors = global.errors; ti->semanticTiargs(sc); + if (olderrors != global.errors) + return new ErrorExp(); if (ti->needsTypeInference(sc)) { /* Go with partial explicit specialization @@ -7454,7 +7609,7 @@ Lagain: { if (e1->op == TOKdot) { DotIdExp *die = (DotIdExp *)e1; - e1 = die->semantic(sc, 1); + e1 = die->semantic(sc); /* Look for e1 having been rewritten to expr.opDispatch!(string) * We handle such earlier, so go back. * Note that in the rewrite, we carefully did not run semantic() on e1 @@ -7485,7 +7640,10 @@ Lagain: if (ve->var->storage_class & STClazy) { // lazy paramaters can be called without violating purity and safety - TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd, STCsafe | STCpure); + Type *tw = ve->var->type; + Type *tc = ve->var->type->substWildTo(MODconst); + TypeFunction *tf = new TypeFunction(NULL, tc, 0, LINKd, STCsafe | STCpure); + (tf = (TypeFunction *)tf->semantic(loc, sc))->next = tw; // hack for bug7757 TypeDelegate *t = new TypeDelegate(tf); ve->type = t->semantic(loc, sc); } @@ -7631,6 +7789,17 @@ Lagain: if (e1->op == TOKerror) return e1; + // If there was an error processing any template argument, + // return an error without trying to resolve the template. + if (targsi && targsi->dim) + { + for (size_t k = 0; k < targsi->dim; k++) + { Object *o = targsi->tdata()[k]; + if (isError(o)) + return new ErrorExp(); + } + } + if (e1->op == TOKdotvar && t1->ty == Tfunction || e1->op == TOKdottd) { @@ -7768,8 +7937,8 @@ Lagain: // Base class constructor call ClassDeclaration *cd = NULL; - if (sc->func) - cd = sc->func->toParent()->isClassDeclaration(); + if (sc->func && sc->func->isThis()) + cd = sc->func->isThis()->isClassDeclaration(); if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) { error("super class constructor call must be in a constructor"); @@ -7814,8 +7983,8 @@ Lagain: // same class constructor call AggregateDeclaration *cd = NULL; - if (sc->func) - cd = sc->func->toParent()->isAggregateDeclaration(); + if (sc->func && sc->func->isThis()) + cd = sc->func->isThis()->isAggregateDeclaration(); if (!cd || !sc->func->isCtorDeclaration()) { error("constructor call must be in a constructor"); @@ -7900,38 +8069,18 @@ Lagain: } else if (t1->ty != Tfunction) { + TypeFunction *tf; + const char *p; if (t1->ty == Tdelegate) { TypeDelegate *td = (TypeDelegate *)t1; assert(td->next->ty == Tfunction); tf = (TypeFunction *)(td->next); - if (sc->func && !tf->purity && !(sc->flags & SCOPEdebug)) - { - if (sc->func->setImpure()) - error("pure function '%s' cannot call impure delegate '%s'", sc->func->toChars(), e1->toChars()); - } - if (sc->func && tf->trust <= TRUSTsystem) - { - if (sc->func->setUnsafe()) - error("safe function '%s' cannot call system delegate '%s'", sc->func->toChars(), e1->toChars()); - } - goto Lcheckargs; + p = "delegate"; } else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction) { - Expression *e = new PtrExp(loc, e1); - t1 = ((TypePointer *)t1)->next; - if (sc->func && !((TypeFunction *)t1)->purity && !(sc->flags & SCOPEdebug)) - { - if (sc->func->setImpure()) - error("pure function '%s' cannot call impure function pointer '%s'", sc->func->toChars(), e1->toChars()); - } - if (sc->func && ((TypeFunction *)t1)->trust <= TRUSTsystem) - { - if (sc->func->setUnsafe()) - error("safe function '%s' cannot call system function pointer '%s'", sc->func->toChars(), e1->toChars()); - } - e->type = t1; - e1 = e; + tf = (TypeFunction *)(((TypePointer *)t1)->next); + p = "function pointer"; } else if (e1->op == TOKtemplate) { @@ -7958,6 +8107,50 @@ Lagain: { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); return new ErrorExp(); } + + if (sc->func && !tf->purity && !(sc->flags & SCOPEdebug)) + { + if (sc->func->setImpure()) + error("pure function '%s' cannot call impure %s '%s'", sc->func->toChars(), p, e1->toChars()); + } + if (sc->func && tf->trust <= TRUSTsystem) + { + if (sc->func->setUnsafe()) + error("safe function '%s' cannot call system %s '%s'", sc->func->toChars(), p, e1->toChars()); + } + + if (!tf->callMatch(NULL, arguments)) + { + OutBuffer buf; + + buf.writeByte('('); + if (arguments) + { + HdrGenState hgs; + + argExpTypesToCBuffer(&buf, arguments, &hgs); + buf.writeByte(')'); + if (ethis) + ethis->type->modToBuffer(&buf); + } + else + buf.writeByte(')'); + + //printf("tf = %s, args = %s\n", tf->deco, arguments->tdata()[0]->type->deco); + ::error(loc, "%s %s %s is not callable using argument types %s", + p, e1->toChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), + buf.toChars()); + + return new ErrorExp(); + } + + if (t1->ty == Tpointer) + { + Expression *e = new PtrExp(loc, e1); + e->type = tf; + e1 = e; + } + t1 = tf; } else if (e1->op == TOKvar) { @@ -7995,10 +8188,7 @@ Lagain: t1 = f->type; } assert(t1->ty == Tfunction); - tf = (TypeFunction *)(t1); - -Lcheckargs: - assert(tf->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)(t1); if (!arguments) arguments = new Expressions(); @@ -8033,11 +8223,14 @@ Lcheckargs: #if DMDV2 int CallExp::isLvalue() { -// if (type->toBasetype()->ty == Tstruct) -// return 1; Type *tb = e1->type->toBasetype(); if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) + { + if (e1->op == TOKdotvar) + if (((DotVarExp *)e1)->var->isCtorDeclaration()) + return 0; return 1; // function returns a reference + } return 0; } #endif @@ -8206,10 +8399,20 @@ Expression *AddrExp::semantic(Scope *sc) * mark here that we took its address because castTo() * may not be called with an exact match. */ - f->toParent2()->isFuncDeclaration()) + f->isNested()) f->tookAddressOf++; if (f->isNested()) { + if (f->isFuncLiteralDeclaration()) + { + if (!f->FuncDeclaration::isNested()) + { /* Supply a 'null' for a this pointer if no this is available + */ + Expression *e = new DelegateExp(loc, new NullExp(loc, Type::tnull), f, ve->hasOverloads); + e = e->semantic(sc); + return e; + } + } Expression *e = new DelegateExp(loc, e1, f, ve->hasOverloads); e = e->semantic(sc); return e; @@ -8664,26 +8867,6 @@ 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) ) @@ -8972,7 +9155,7 @@ Lagain: } if (ad->aliasthis) { - e1 = new DotIdExp(e1->loc, e1, ad->aliasthis->ident); + e1 = resolveAliasThis(sc, e1); goto Lagain; } goto Lerror; @@ -9074,7 +9257,7 @@ Lagain: } else { - error("string slice [%ju .. %ju] is out of bounds", i1, i2); + error("string slice [%llu .. %llu] is out of bounds", i1, i2); goto Lerr; } return e; @@ -9541,8 +9724,8 @@ Expression *IndexExp::semantic(Scope *sc) } else { - error("array index [%ju] is outside array bounds [0 .. %zu]", - index, length); + error("array index [%llu] is outside array bounds [0 .. %llu]", + index, (ulonglong)length); e = e1; } break; @@ -9624,10 +9807,18 @@ Expression *PostExp::semantic(Scope *sc) if (e) return e; - e1 = e1->modifiableLvalue(sc, e1); + if (e1->op == TOKslice) + { + const char *s = op == TOKplusplus ? "increment" : "decrement"; + error("cannot post-%s array slice '%s', use pre-%s instead", s, e1->toChars(), s); + return new ErrorExp(); + } + + if (e1->op != TOKarraylength) + e1 = e1->modifiableLvalue(sc, e1); Type *t1 = e1->type->toBasetype(); - if (t1->ty == Tclass || t1->ty == Tstruct) + if (t1->ty == Tclass || t1->ty == Tstruct || e1->op == TOKarraylength) { /* Check for operator overloading, * but rewrite in terms of ++e instead of e++ */ @@ -9635,7 +9826,7 @@ Expression *PostExp::semantic(Scope *sc) /* If e1 is not trivial, take a reference to it */ Expression *de = NULL; - if (e1->op != TOKvar) + if (e1->op != TOKvar && e1->op != TOKarraylength) { // ref v = e1; Identifier *id = Lexer::uniqueId("__postref"); @@ -9758,6 +9949,7 @@ Expression *AssignExp::semantic(Scope *sc) Identifier *id = Id::index; ae->e1 = ae->e1->semantic(sc); + ae->e1 = resolveProperties(sc, ae->e1); Type *t1 = ae->e1->type->toBasetype(); if (t1->ty == Tstruct) { @@ -9823,18 +10015,17 @@ Expression *AssignExp::semantic(Scope *sc) // No opIndexAssign found yet, but there might be an alias this to try. if (ad && ad->aliasthis) - { Expression *at = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); - at = at->semantic(sc); - Type *attype = at->type->toBasetype(); + { Expression *e = resolveAliasThis(sc, ae->e1); + Type *t = e->type->toBasetype(); - if (attype->ty == Tstruct) + if (t->ty == Tstruct) { - ad = ((TypeStruct *)attype)->sym; + ad = ((TypeStruct *)t)->sym; goto L1; } - else if (attype->ty == Tclass) + else if (t->ty == Tclass) { - ad = ((TypeClass *)attype)->sym; + ad = ((TypeClass *)t)->sym; goto L1; } } @@ -9882,31 +10073,66 @@ Expression *AssignExp::semantic(Scope *sc) // No opSliceAssign found yet, but there might be an alias this to try. if (ad && ad->aliasthis) - { Expression *at = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); - at = at->semantic(sc); - Type *attype = at->type->toBasetype(); + { Expression *e = resolveAliasThis(sc, ae->e1); + Type *t = e->type->toBasetype(); - if (attype->ty == Tstruct) + if (t->ty == Tstruct) { - ad = ((TypeStruct *)attype)->sym; + ad = ((TypeStruct *)t)->sym; goto L2; } - else if (attype->ty == Tclass) + else if (t->ty == Tclass) { - ad = ((TypeClass *)attype)->sym; + ad = ((TypeClass *)t)->sym; goto L2; } } } - { - Expression *e = BinExp::semantic(sc); - if (e->op == TOKerror) - return e; - } - + e2 = e2->semantic(sc); + if (e2->op == TOKerror) + return new ErrorExp(); e2 = resolveProperties(sc, e2); + /* With UFCS, e.f = value + * Could mean: + * .f(e, value) + * or: + * .f(e) = value + */ + if (e1->op == TOKdotti) + { + DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)e1; + dti->e1 = dti->e1->semantic(sc); + if (!global.errors && dti->e1->type) + { + unsigned errors = global.startGagging(); + e1 = dti->semantic(sc, 1); + if (global.endGagging(errors) || e1->op == TOKerror) + { + return resolveUFCSProperties(sc, dti, e2); + } + } + } + else if (e1->op == TOKdot) + { + DotIdExp *die = (DotIdExp *)e1; + die->e1 = die->e1->semantic(sc); + if (!global.errors && die->e1->type) + { + unsigned errors = global.startGagging(); + e1 = die->semantic(sc, 1); + if (global.endGagging(errors) || e1->op == TOKerror) + { + return resolveUFCSProperties(sc, die, e2); + } + } + } +Le1: + e1 = e1->semantic(sc); + if (e1->op == TOKerror) + return new ErrorExp(); + /* We have f = value. * Could mean: * f(value) @@ -10048,7 +10274,8 @@ Ltupleassign: TypeTuple *tt = (TypeTuple *)e1->type; Identifier *id = Lexer::uniqueId("__tup"); - VarDeclaration *v = new VarDeclaration(e2->loc, NULL, id, new ExpInitializer(e2->loc, e2)); + ExpInitializer *ei = new ExpInitializer(e2->loc, e2); + VarDeclaration *v = new VarDeclaration(e2->loc, NULL, id, ei); v->storage_class = STCctfe | STCref | STCforeach; Expression *ve = new VarExp(e2->loc, v); ve->type = e2->type; @@ -10096,27 +10323,6 @@ Ltupleassign: Type *t1 = e1->type->toBasetype(); - if (t1->ty == Tdelegate || (t1->ty == Tpointer && t1->nextOf()->ty == Tfunction) - && e2->op == TOKfunction) - { - FuncExp *fe = (FuncExp *)e2; - if (e2->type == Type::tvoid) - { - e2 = fe->inferType(sc, t1); - } - else if (e2->type->ty == Tpointer && e2->type->nextOf()->ty == Tfunction && - fe->tok == TOKreserved && - t1->ty == Tdelegate) - { - if (fe->implicitConvTo(t1)) - e2 = fe->castTo(sc, t1); - } - if (!e2) - { error("cannot infer function literal type from %s", t1->toChars()); - e2 = new ErrorExp(); - } - } - /* If it is an assignment from a 'foreign' type, * check for operator overloading. */ @@ -10222,7 +10428,7 @@ Ltupleassign: } else if (t1->ty == Tclass) { // Disallow assignment operator overloads for same type - if (!e2->implicitConvTo(e1->type)) + if (op == TOKassign && !e2->implicitConvTo(e1->type)) { Expression *e = op_overload(sc); if (e) @@ -10258,6 +10464,7 @@ Ltupleassign: } } + e2 = e2->inferType(t1); if (!e2->rvalue()) return new ErrorExp(); @@ -10297,8 +10504,16 @@ Ltupleassign: } else #endif + // If it is a array, get the element type. Note that it may be + // multi-dimensional. + Type *telem = t1; + while (telem->ty == Tarray) + telem = telem->nextOf(); + + // Check for block assignment. If it is of type void[], void[][], etc, + // '= null' is the only allowable block assignment (Bug 7493) if (e1->op == TOKslice && - t1->nextOf() && + t1->nextOf() && (telem->ty != Tvoid || e2->op == TOKnull) && e2->implicitConvTo(t1->nextOf()) ) { // memset @@ -10380,115 +10595,6 @@ AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *AddAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - if (e1->op == TOKslice) - { - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - else - { - e1 = e1->modifiableLvalue(sc, e1); - } - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - typeCombine(sc); - e = this; - } - else - { - e1->checkScalar(); - e1->checkNoBool(); - if (tb1->ty == Tpointer && tb2->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tbool) - { -#if 0 - // Need to rethink this - if (e1->op != TOKvar) - { // Rewrite e1+=e2 to (v=&e1),*v=*v+e2 - VarDeclaration *v; - Expression *ea; - Expression *ex; - - Identifier *id = Lexer::uniqueId("__name"); - - v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - - ea = new AddrExp(loc, e1); - ea = new AssignExp(loc, new VarExp(loc, v), ea); - - ex = new VarExp(loc, v); - ex = new PtrExp(loc, ex); - e = new AddExp(loc, ex, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, ex->syntaxCopy(), e); - - e = new CommaExp(loc, ea, e); - } - else -#endif - { // Rewrite e1+=e2 to e1=e1+e2 - // BUG: doesn't account for side effects in e1 - // BUG: other assignment operators for bits aren't handled at all - e = new AddExp(loc, e1, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, e1->syntaxCopy(), e); - } - e = e->semantic(sc); - } - else - { - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexAddAssign(); - if (type->isreal() || type->isimaginary()) - { - assert(global.errors || e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - } - return e; -} - /************************************************************/ MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10496,57 +10602,6 @@ MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *MinAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - if (e1->op == TOKslice) - { // T[] -= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer && e2->type->isintegral()) - e = scaleFactor(sc); - else - { - e1 = e1->checkArithmetic(); - e2 = e2->checkArithmetic(); - checkComplexAddAssign(); - type = e1->type; - typeCombine(sc); - if (type->isreal() || type->isimaginary()) - { - assert(e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - return e; -} - /************************************************************/ CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10555,10 +10610,9 @@ CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) } Expression *CatAssignExp::semantic(Scope *sc) -{ Expression *e; - +{ //printf("CatAssignExp::semantic() %s\n", toChars()); - e = op_overload(sc); + Expression *e = op_overload(sc); if (e) return e; @@ -10572,14 +10626,17 @@ Expression *CatAssignExp::semantic(Scope *sc) } e1 = e1->modifiableLvalue(sc, e1); + if (e1->op == TOKerror) + return e1; Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); + Type *tb1next = tb1->nextOf(); + e2 = e2->inferType(tb1next); if (!e2->rvalue()) return new ErrorExp(); - Type *tb1next = tb1->nextOf(); + Type *tb2 = e2->type->toBasetype(); if ((tb1->ty == Tarray) && (tb2->ty == Tarray || tb2->ty == Tsarray) && @@ -10632,76 +10689,6 @@ MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *MulAssignExp::semantic(Scope *sc) -{ Expression *e; - - e = op_overload(sc); - if (e) - return e; - -#if DMDV2 - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKslice) - { // T[] *= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexMulAssign(); - if (e2->type->isfloating()) - { - Type *t1 = e1->type; - Type *t2 = e2->type; - if (t1->isreal()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - e2 = e2->castTo(sc, t1); - } - } - else if (t1->isimaginary()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - } - } - - 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; -} - /************************************************************/ DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10709,77 +10696,6 @@ DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *DivAssignExp::semantic(Scope *sc) -{ Expression *e; - - e = op_overload(sc); - if (e) - return e; - -#if DMDV2 - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKslice) - { // T[] /= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexMulAssign(); - if (e2->type->isimaginary()) - { - Type *t1 = e1->type; - if (t1->isreal()) - { // x/iv = i(-x/v) - // Therefore, the result is 0 - e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1)); - e2->type = t1; - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - else if (t1->isimaginary()) - { Type *t2; - - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - 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()); - - return this; -} - /************************************************************/ ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10787,20 +10703,6 @@ ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *ModAssignExp::semantic(Scope *sc) -{ - if (!type) - { - Expression *e = op_overload(sc); - if (e) - return e; - - checkComplexMulAssign(); - return commonSemanticAssign(sc); - } - return this; -} - /************************************************************/ ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10808,39 +10710,6 @@ ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *ShlAssignExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlAssignExp::semantic()\n"); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - e1 = e1->modifiableLvalue(sc, e1); - 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(); -#if IN_DMD - e2 = e2->castTo(sc, Type::tshiftcnt); -#elif IN_LLVM - e2 = e2->castTo(sc, e1->type); -#endif - return this; -} - /************************************************************/ ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10848,37 +10717,6 @@ ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *ShrAssignExp::semantic(Scope *sc) -{ Expression *e; - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - e1 = e1->modifiableLvalue(sc, e1); - 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(); -#if IN_DMD - e2 = e2->castTo(sc, Type::tshiftcnt); -#elif IN_LLVM - e2 = e2->castTo(sc, e1->type); -#endif - return this; -} - /************************************************************/ UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10886,34 +10724,6 @@ UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *UshrAssignExp::semantic(Scope *sc) -{ Expression *e; - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - e1 = e1->modifiableLvalue(sc, e1); - 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(); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - return this; -} - /************************************************************/ AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10921,11 +10731,6 @@ AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *AndAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - /************************************************************/ OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10933,11 +10738,6 @@ OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *OrAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - /************************************************************/ XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) @@ -10945,11 +10745,6 @@ XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) { } -Expression *XorAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - /***************** PowAssignExp *******************************************/ PowAssignExp::PowAssignExp(Loc loc, Expression *e1, Expression *e2) diff --git a/dmd2/expression.h b/dmd2/expression.h index b2fbb4a6..14f3f235 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -97,7 +97,9 @@ int arrayExpressionCanThrow(Expressions *exps, bool mustNotThrow); TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s); void valueNoDtor(Expression *e); void modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1); - +#if DMDV2 +Expression *resolveAliasThis(Scope *sc, Expression *e); +#endif /* Interpreter: what form of return value expression is required? */ @@ -151,6 +153,7 @@ struct Expression : Object virtual MATCH implicitConvTo(Type *t); virtual IntRange getIntRange(); virtual Expression *castTo(Scope *sc, Type *t); + virtual Expression *inferType(Type *t, int flag = 0, TemplateParameters *tparams = NULL); virtual void checkEscape(); virtual void checkEscapeRef(); virtual Expression *resolveLoc(Loc loc, Scope *sc); @@ -503,6 +506,7 @@ struct ArrayLiteralExp : Expression Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); + Expression *inferType(Type *t, int flag = 0, TemplateParameters *tparams = NULL); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -537,6 +541,7 @@ struct AssocArrayLiteralExp : Expression Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); + Expression *inferType(Type *t, int flag = 0, TemplateParameters *tparams = NULL); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); @@ -555,6 +560,7 @@ struct StructLiteralExp : Expression Type *stype; // final type of result (can be different from sd's type) #if IN_DMD + Symbol *sinit; // if this is a defaultInitLiteral, this symbol contains the default initializer Symbol *sym; // back end symbol to initialize with literal #endif size_t soffset; // offset from start of s @@ -572,8 +578,6 @@ struct StructLiteralExp : Expression void toMangleBuffer(OutBuffer *buf); Expression *optimize(int result); Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); MATCH implicitConvTo(Type *t); int inlineCost3(InlineCostState *ics); @@ -789,18 +793,17 @@ struct FuncExp : Expression FuncLiteralDeclaration *fd; TemplateDeclaration *td; enum TOK tok; - Type *tded; - Scope *scope; + Type *treq; 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); + Expression *implicitCastTo(Scope *sc, Type *t); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); - Expression *inferType(Scope *sc, Type *t); - void setType(Type *t); + Expression *inferType(Type *t, int flag = 0, TemplateParameters *tparams = NULL); char *toChars(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #if IN_DMD @@ -932,8 +935,7 @@ struct BinExp : Expression int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); Expression *semanticp(Scope *sc); - void checkComplexMulAssign(); - void checkComplexAddAssign(); + Expression *checkComplexOpAssign(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Expression *scaleFactor(Scope *sc); Expression *typeCombine(Scope *sc); @@ -941,6 +943,7 @@ struct BinExp : Expression int isunsigned(); Expression *incompatibleTypes(); void dump(int indent); + Expression *interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *, Expression *)); Expression *interpretCommon2(InterState *istate, CtfeGoal goal, @@ -967,8 +970,7 @@ struct BinAssignExp : BinExp { } - Expression *commonSemanticAssign(Scope *sc); - Expression *commonSemanticAssignIntegral(Scope *sc); + Expression *semantic(Scope *sc); Expression *op_overload(Scope *sc); @@ -1067,6 +1069,7 @@ struct DotTemplateInstanceExp : UnaExp Expression *syntaxCopy(); TemplateDeclaration *getTempdecl(Scope *sc); Expression *semantic(Scope *sc); + Expression *semantic(Scope *sc, int flag); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void dump(int indent); }; @@ -1542,7 +1545,7 @@ struct ConstructExp : AssignExp struct op##AssignExp : BinAssignExp \ { \ op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ - Expression *semantic(Scope *sc); \ + S(Expression *semantic(Scope *sc);) \ Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); \ X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ X(Expression *buildArrayLoop(Parameters *fparams);) \ @@ -1553,6 +1556,7 @@ struct op##AssignExp : BinAssignExp \ }; #define X(a) a +#define S(a) ASSIGNEXP(Add) ASSIGNEXP(Min) ASSIGNEXP(Mul) @@ -1561,17 +1565,28 @@ ASSIGNEXP(Mod) ASSIGNEXP(And) ASSIGNEXP(Or) ASSIGNEXP(Xor) +#undef S + #if DMDV2 +#define S(a) a ASSIGNEXP(Pow) +#undef S #endif + +#undef S #undef X #define X(a) +#define S(a) ASSIGNEXP(Shl) ASSIGNEXP(Shr) ASSIGNEXP(Ushr) +#undef S + +#define S(a) a ASSIGNEXP(Cat) +#undef S #undef X #undef ASSIGNEXP @@ -1991,7 +2006,7 @@ struct EqualExp : BinExp #endif }; -// === and !=== +// is and !is struct IdentityExp : BinExp { @@ -2030,6 +2045,7 @@ struct CondExp : BinExp void toCBuffer(OutBuffer *buf, HdrGenState *hgs); MATCH implicitConvTo(Type *t); Expression *castTo(Scope *sc, Type *t); + Expression *inferType(Type *t, int flag = 0, TemplateParameters *tparams = NULL); Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); diff --git a/dmd2/func.c b/dmd2/func.c index 2671023b..81f2ace2 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -1,5 +1,5 @@ // 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 @@ -341,13 +341,6 @@ void FuncDeclaration::semantic(Scope *sc) } #endif -#ifdef IN_GCC - { - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (ad) - ad->methods.push(this); - } -#endif sd = parent->isStructDeclaration(); if (sd) { @@ -468,6 +461,9 @@ void FuncDeclaration::semantic(Scope *sc) //printf("\tnot virtual\n"); goto Ldone; } + // Suppress further errors if the return type is an error + if (type->nextOf() == Type::terror) + goto Ldone; /* Find index of existing function in base class's vtbl[] to override * (the index will be the same as in cd's current vtbl[]) @@ -479,6 +475,7 @@ void FuncDeclaration::semantic(Scope *sc) switch (vi) { case -1: + Lintro: /* Didn't find one, so * This is an 'introducing' function which gets a new * slot in the vtbl[]. @@ -515,7 +512,7 @@ void FuncDeclaration::semantic(Scope *sc) break; case -2: // can't determine because of fwd refs - cd->sizeok = 2; // can't finish due to forward reference + cd->sizeok = SIZEOKfwd; // can't finish due to forward reference Module::dprogress = dprogress_save; return; @@ -534,9 +531,12 @@ void FuncDeclaration::semantic(Scope *sc) FuncDeclaration *fdc = ((Dsymbol *)cd->vtbl.data[vi])->isFuncDeclaration(); if (fdc->toParent() == parent) { + // fdc overrides fdv exactly, then this introduces new function. + if (fdc->type->mod == fdv->type->mod && this->type->mod != fdv->type->mod) + goto Lintro; + // If both are mixins, then error. // 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"); @@ -600,7 +600,7 @@ void FuncDeclaration::semantic(Scope *sc) break; case -2: - cd->sizeok = 2; // can't finish due to forward reference + cd->sizeok = SIZEOKfwd; // can't finish due to forward reference Module::dprogress = dprogress_save; return; @@ -636,7 +636,7 @@ void FuncDeclaration::semantic(Scope *sc) { // any error in isBaseOf() is a forward reference error, so we bail out global.errors = errors; - cd->sizeok = 2; // can't finish due to forward reference + cd->sizeok = SIZEOKfwd; // can't finish due to forward reference Module::dprogress = dprogress_save; return; } @@ -647,9 +647,14 @@ void FuncDeclaration::semantic(Scope *sc) } if (ti) { - if (tintro && !tintro->equals(ti)) + if (tintro) { - error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); + if (!tintro->nextOf()->equals(ti->nextOf()) && + !tintro->nextOf()->isBaseOf(ti->nextOf(), NULL) && + !ti->nextOf()->isBaseOf(tintro->nextOf(), NULL)) + { + error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); + } } tintro = ti; } @@ -660,7 +665,11 @@ void FuncDeclaration::semantic(Scope *sc) if (!doesoverride && isOverride()) { - error("does not override any function"); + Dsymbol *s = cd->search_correct(ident); + if (s) + error("does not override any function, did you mean '%s'", s->toPrettyChars()); + else + error("does not override any function"); } L2: ; @@ -879,7 +888,7 @@ void FuncDeclaration::semantic3(Scope *sc) //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); assert(0); } - //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); + //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", parent->toChars(), toChars(), this, sc, loc.toChars()); //fflush(stdout); //printf("storage class = x%x %x\n", sc->stc, storage_class); //{ static int x; if (++x == 2) *(char*)0=0; } @@ -978,6 +987,9 @@ void FuncDeclaration::semantic3(Scope *sc) } else assert(!isNested() || sc->intypeof); // can't be both member and nested +#if IN_GCC + ad->methods.push(this); +#endif } vthis = declareThis(sc2, ad); @@ -989,7 +1001,7 @@ void FuncDeclaration::semantic3(Scope *sc) #else Type *t; -#if !IN_LLVM +#if !IN_GCC && !IN_LLVM if (global.params.is64bit) { // Declare save area for varargs registers Type *t = new TypeIdentifier(loc, Id::va_argsave_t); @@ -1327,7 +1339,7 @@ void FuncDeclaration::semantic3(Scope *sc) } } - if (inferRetType || f->retStyle() != RETstack) + if (!inferRetType && f->retStyle() != RETstack) nrvo_can = 0; fbody = fbody->semantic(sc2); @@ -1915,11 +1927,13 @@ int FuncDeclaration::equals(Object *o) Dsymbol *s = isDsymbol(o); if (s) { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) + FuncDeclaration *fd1 = this->toAliasFunc(); + FuncDeclaration *fd2 = s->isFuncDeclaration(); + if (fd2) { - return toParent()->equals(fd->toParent()) && - ident->equals(fd->ident) && type->equals(fd->type); + fd2 = fd2->toAliasFunc(); + return fd1->toParent()->equals(fd2->toParent()) && + fd1->ident->equals(fd2->ident) && fd1->type->equals(fd2->type); } } return FALSE; @@ -2137,6 +2151,8 @@ int FuncDeclaration::overrides(FuncDeclaration *fd) int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) { FuncDeclaration *mismatch = NULL; + StorageClass mismatchstc = 0; + int mismatchvi = -1; int bestvi = -1; for (int vi = 0; vi < dim; vi++) { @@ -2146,7 +2162,8 @@ int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) if (type->equals(fdv->type)) // if exact match return vi; // no need to look further - int cov = type->covariant(fdv->type); + StorageClass stc = 0; + int cov = type->covariant(fdv->type, &stc); //printf("\tbaseclass cov = %d\n", cov); switch (cov) { @@ -2158,6 +2175,8 @@ int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) break; // keep looking for an exact match case 2: + mismatchvi = vi; + mismatchstc = stc; mismatch = fdv; // overrides, but is not covariant break; // keep looking for an exact match @@ -2174,8 +2193,15 @@ int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) //type->print(); //mismatch->type->print(); //printf("%s %s\n", type->deco, mismatch->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), mismatch->toPrettyChars(), mismatch->type->toChars()); + //printf("stc = %llx\n", mismatchstc); + if (mismatchstc) + { // Fix it by modifying the type to add the storage classes + type = type->addStorageClass(mismatchstc); + bestvi = mismatchvi; + } + else + error("of type %s overrides but is not covariant with %s of type %s", + type->toChars(), mismatch->toPrettyChars(), mismatch->type->toChars()); } return bestvi; } @@ -2262,8 +2288,21 @@ int overloadApply(FuncDeclaration *fstart, if (fa) { - if (overloadApply(fa->funcalias, fp, param)) - return 1; + if (fa->hasOverloads) + { + if (overloadApply(fa->funcalias, fp, param)) + return 1; + } + else + { + f = fa->toAliasFunc(); + if (!f) + { d->error("is aliased to a function"); + break; + } + if ((*fp)(param, f)) + return 1; + } next = fa->overnext; } else @@ -2611,7 +2650,7 @@ MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) e->type = p->type; } else - e = p->type->defaultInit(); + e = p->type->defaultInitLiteral(0); args.tdata()[u] = e; } @@ -2925,6 +2964,11 @@ int FuncDeclaration::isOverloadable() return 1; // functions can be overloaded } +int FuncDeclaration::hasOverloads() +{ + return overnext != NULL; +} + enum PURE FuncDeclaration::isPure() { //printf("FuncDeclaration::isPure() '%s'\n", toChars()); @@ -2982,6 +3026,14 @@ int FuncDeclaration::isSafe() return ((TypeFunction *)type)->trust == TRUSTsafe; } +bool FuncDeclaration::isSafeBypassingInference() +{ + if (flags & FUNCFLAGsafetyInprocess) + return false; + else + return isSafe(); +} + int FuncDeclaration::isTrusted() { assert(type->ty == Tfunction); @@ -3012,21 +3064,16 @@ bool FuncDeclaration::setUnsafe() int FuncDeclaration::isNested() { - //if (!toParent()) - //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); - //printf("\ttoParent2() = '%s'\n", toParent2()->toChars()); - return ((storage_class & STCstatic) == 0) && toParent2() && - (toParent2()->isFuncDeclaration() != NULL); + FuncDeclaration *f = toAliasFunc(); + //printf("\ttoParent2() = '%s'\n", f->toParent2()->toChars()); + return ((f->storage_class & STCstatic) == 0) && + (f->toParent2()->isFuncDeclaration() != NULL); } int FuncDeclaration::needThis() { //printf("FuncDeclaration::needThis() '%s'\n", toChars()); - int i = isThis() != NULL; - //printf("\t%d\n", i); - if (!i && isFuncAliasDeclaration()) - i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); - return i; + return toAliasFunc()->isThis() != NULL; } int FuncDeclaration::addPreInvariant() @@ -3272,7 +3319,7 @@ Parameters *FuncDeclaration::getParameters(int *pvarargs) // Used as a way to import a set of functions from another scope into this one. -FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) +FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias, int hasOverloads) : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, funcalias->storage_class, funcalias->type) { @@ -3281,6 +3328,18 @@ FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) #if IN_LLVM importprot = PROTundefined; #endif + + this->hasOverloads = hasOverloads; + if (hasOverloads) + { + if (FuncAliasDeclaration *fad = funcalias->isFuncAliasDeclaration()) + this->hasOverloads = fad->hasOverloads; + } + else + { // for internal use + assert(!funcalias->isFuncAliasDeclaration()); + this->hasOverloads = 0; + } } const char *FuncAliasDeclaration::kind() @@ -3288,6 +3347,11 @@ const char *FuncAliasDeclaration::kind() return "function alias"; } +FuncDeclaration *FuncAliasDeclaration::toAliasFunc() +{ + return funcalias->toAliasFunc(); +} + /****************************** FuncLiteralDeclaration ************************/ @@ -3737,7 +3801,7 @@ int StaticCtorDeclaration::addPostInvariant() void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { - if (hgs->hdrgen) + if (hgs->hdrgen && !hgs->tpltMember) { buf->writestring("static this();"); buf->writenl(); return; diff --git a/dmd2/html.c b/dmd2/html.c index f7ea2adb..81d15458 100644 --- a/dmd2/html.c +++ b/dmd2/html.c @@ -18,7 +18,6 @@ #include #include -#define MARS 1 #include "html.h" #if MARS @@ -102,15 +101,15 @@ Html::Html(const char *sourcename, unsigned char *base, unsigned length) void Html::error(const char *format, ...) { - printf("%s(%d) : HTML Error: ", sourcename, linnum); + fprintf(stderr, "%s(%d) : HTML Error: ", sourcename, linnum); va_list ap; va_start(ap, format); - vprintf(format, ap); + vfprintf(stderr, format, ap); va_end(ap); - printf("\n"); - fflush(stdout); + fprintf(stderr, "\n"); + fflush(stderr); //#if MARS // global.errors++; diff --git a/dmd2/html.h b/dmd2/html.h index 9b5a548f..90e43260 100644 --- a/dmd2/html.h +++ b/dmd2/html.h @@ -7,6 +7,7 @@ // in artistic.txt, or the GNU General Public License in gpl.txt. // See the included readme.txt for details. +#define MARS 1 #if MARS struct OutBuffer; diff --git a/dmd2/identifier.c b/dmd2/identifier.c index 178ae12b..825d78b6 100644 --- a/dmd2/identifier.c +++ b/dmd2/identifier.c @@ -94,7 +94,7 @@ Identifier *Identifier::generateId(const char *prefix, size_t i) { OutBuffer buf; buf.writestring(prefix); - buf.printf("%zu", i); + buf.printf("%llu", (ulonglong)i); char *id = buf.toChars(); buf.data = NULL; diff --git a/dmd2/idgen.c b/dmd2/idgen.c index da3dc4f3..2e40fbce 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -293,7 +293,7 @@ Msgtable msgtable[] = // Special functions #if IN_DMD - { "alloca" }, + { "__alloca", "alloca" }, // has to be mapped because alloca is #defined if _MSC_VER #endif { "main" }, { "WinMain" }, diff --git a/dmd2/import.c b/dmd2/import.c index bd43af90..f4582c23 100644 --- a/dmd2/import.c +++ b/dmd2/import.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -77,13 +77,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; @@ -95,7 +93,16 @@ void Import::load(Scope *sc) // See if existing module DsymbolTable *dst = Package::resolve(packages, NULL, &pkg); - +#if TARGET_NET //dot net needs modules and packages with same name +#else + if (pkg && pkg->isModule()) + { + ::error(loc, "can only import from a module, not from a member of module %s. Did you mean `import %s : %s`?", + pkg->toChars(), pkg->toPrettyChars(), id->toChars()); + mod = pkg->isModule(); // Error recovery - treat as import of that module + return; + } +#endif Dsymbol *s = dst->lookup(id); if (s) { @@ -105,7 +112,8 @@ void Import::load(Scope *sc) if (s->isModule()) mod = (Module *)s; else - error("package and module have the same name"); + ::error(loc, "can only import from a module, not from package %s.%s", + pkg->toPrettyChars(), id->toChars()); #endif } @@ -113,10 +121,13 @@ void Import::load(Scope *sc) { // Load module mod = Module::load(loc, packages, id); - dst->insert(id, mod); // id may be different from mod->ident, - // if so then insert alias - if (!mod->importedFrom) - mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; + if (mod) + { + dst->insert(id, mod); // id may be different from mod->ident, + // if so then insert alias + if (!mod->importedFrom) + mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; + } } if (!pkg) pkg = mod; @@ -167,7 +178,8 @@ void Import::semantic(Scope *sc) // Load if not already done so if (!mod) { load(sc); - mod->importAll(0); + if (mod) + mod->importAll(0); } if (mod) @@ -217,18 +229,26 @@ void Import::semantic(Scope *sc) sc->protection = PROTpublic; #endif for (size_t i = 0; i < aliasdecls.dim; i++) - { Dsymbol *s = aliasdecls.tdata()[i]; + { Dsymbol *s = aliasdecls[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 (mod->search(loc, names[i], 0)) + s->semantic(sc); + else + { + s = mod->search_correct(names[i]); + if (s) + mod->error(loc, "import '%s' not found, did you mean '%s %s'?", names[i]->toChars(), s->kind(), s->toChars()); + else + mod->error(loc, "import '%s' not found", names[i]->toChars()); + } } sc = sc->pop(); } - if (global.params.moduleDeps != NULL) + if (global.params.moduleDeps != NULL && + // object self-imports itself, so skip that (Bugzilla 7547) + !(id == Id::object && sc->module->ident == Id::object)) { /* The grammar of the file is: * ImportDeclaration @@ -259,7 +279,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()); } } @@ -279,8 +299,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) { @@ -367,8 +387,15 @@ Dsymbol *Import::search(Loc loc, Identifier *ident, int flags) int Import::overloadInsert(Dsymbol *s) { - // Allow multiple imports of the same name - return s->isImport() != NULL; + /* Allow multiple imports with the same package base, but disallow + * alias collisions (Bugzilla 5412). + */ + assert(ident && ident == s->ident); + Import *imp; + if (!aliasId && (imp = s->isImport()) != NULL && !imp->aliasId) + return TRUE; + else + return FALSE; } void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) diff --git a/dmd2/init.c b/dmd2/init.c index 4d9806c6..c5a834b7 100644 --- a/dmd2/init.c +++ b/dmd2/init.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 @@ -53,10 +53,10 @@ Initializers *Initializer::arraySyntaxCopy(Initializers *ai) a = new Initializers(); a->setDim(ai->dim); for (size_t i = 0; i < a->dim; i++) - { Initializer *e = ai->tdata()[i]; + { Initializer *e = (*ai)[i]; e = e->syntaxCopy(); - a->tdata()[i] = e; + (*a)[i] = e; } } return a; @@ -128,11 +128,11 @@ Initializer *StructInitializer::syntaxCopy() ai->value.setDim(value.dim); for (size_t i = 0; i < field.dim; i++) { - ai->field.tdata()[i] = field.tdata()[i]; + ai->field[i] = field[i]; - Initializer *init = value.tdata()[i]; + Initializer *init = value[i]; init = init->syntaxCopy(); - ai->value.tdata()[i] = init; + ai->value[i] = init; } return ai; } @@ -164,8 +164,8 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) if (((StructDeclaration *)ad)->isnested) nfields--; for (size_t i = 0; i < field.dim; i++) { - Identifier *id = field.tdata()[i]; - Initializer *val = value.tdata()[i]; + Identifier *id = field[i]; + Initializer *val = value[i]; Dsymbol *s; VarDeclaration *v; @@ -180,7 +180,7 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) } else { - s = ad->fields.tdata()[fieldi]; + s = ad->fields[fieldi]; } } else @@ -189,7 +189,12 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) s = ad->search(loc, id, 0); if (!s) { - error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); + s = ad->search_correct(id); + if (s) + error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?", + id->toChars(), t->toChars(), s->kind(), s->toChars()); + else + error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); errors = 1; continue; } @@ -205,15 +210,15 @@ Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) errors = 1; break; } - if (s == ad->fields.tdata()[fieldi]) + if (s == ad->fields[fieldi]) break; } } if (s && (v = s->isVarDeclaration()) != NULL) { val = val->semantic(sc, v->type, needInterpret); - value.tdata()[i] = val; - vars.tdata()[i] = v; + value[i] = val; + vars[i] = v; } else { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); @@ -274,12 +279,12 @@ Expression *StructInitializer::toExpression() elements->setDim(nfields); for (size_t i = 0; i < elements->dim; i++) { - elements->tdata()[i] = NULL; + (*elements)[i] = NULL; } unsigned fieldi = 0; for (size_t i = 0; i < value.dim; i++) { - Identifier *id = field.tdata()[i]; + Identifier *id = field[i]; if (id) { Dsymbol * s = ad->search(loc, id, 0); @@ -298,7 +303,7 @@ Expression *StructInitializer::toExpression() s->error("is not a per-instance initializable field"); goto Lno; } - if (s == ad->fields.tdata()[fieldi]) + if (s == ad->fields[fieldi]) break; } } @@ -306,18 +311,18 @@ Expression *StructInitializer::toExpression() { error(loc, "too many initializers for '%s'", ad->toChars()); goto Lno; } - Initializer *iz = value.tdata()[i]; + Initializer *iz = value[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); if (!ex) goto Lno; - if (elements->tdata()[fieldi]) + if ((*elements)[fieldi]) { error(loc, "duplicate initializer for field '%s'", - ad->fields.tdata()[fieldi]->toChars()); + ad->fields[fieldi]->toChars()); goto Lno; } - elements->tdata()[fieldi] = ex; + (*elements)[fieldi] = ex; ++fieldi; } // Now, fill in any missing elements with default initializers. @@ -325,20 +330,20 @@ Expression *StructInitializer::toExpression() offset = 0; for (size_t i = 0; i < elements->dim; ) { - VarDeclaration * vd = ad->fields.tdata()[i]->isVarDeclaration(); + VarDeclaration * vd = ad->fields[i]->isVarDeclaration(); //printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset); if (vd->offset < offset) { // Only the first field of a union can have an initializer - if (elements->tdata()[i]) + if ((*elements)[i]) goto Lno; } else { - if (!elements->tdata()[i]) + if (!(*elements)[i]) // Default initialize - elements->tdata()[i] = vd->type->defaultInit(); + (*elements)[i] = vd->type->defaultInit(); } offset = vd->offset + vd->type->size(); i++; @@ -346,15 +351,15 @@ Expression *StructInitializer::toExpression() int unionSize = ad->numFieldsInUnion(i); if (unionSize == 1) { // Not a union -- default initialize if missing - if (!elements->tdata()[i]) - elements->tdata()[i] = vd->type->defaultInit(); + if (!(*elements)[i]) + (*elements)[i] = vd->type->defaultInit(); } else { // anonymous union -- check for errors int found = -1; // index of the first field with an initializer - for (int j = i; j < i + unionSize; ++j) + for (size_t j = i; j < i + unionSize; ++j) { - if (!elements->tdata()[j]) + if (!(*elements)[j]) continue; if (found >= 0) { @@ -395,13 +400,13 @@ void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (i > 0) buf->writebyte(','); - Identifier *id = field.tdata()[i]; + Identifier *id = field[i]; if (id) { buf->writestring(id->toChars()); buf->writebyte(':'); } - Initializer *iz = value.tdata()[i]; + Initializer *iz = value[i]; if (iz) iz->toCBuffer(buf, hgs); } @@ -428,14 +433,14 @@ Initializer *ArrayInitializer::syntaxCopy() ai->index.setDim(index.dim); ai->value.setDim(value.dim); for (size_t i = 0; i < ai->value.dim; i++) - { Expression *e = index.tdata()[i]; + { Expression *e = index[i]; if (e) e = e->syntaxCopy(); - ai->index.tdata()[i] = e; + ai->index[i] = e; - Initializer *init = value.tdata()[i]; + Initializer *init = value[i]; init = init->syntaxCopy(); - ai->value.tdata()[i] = init; + ai->value[i] = init; } return ai; } @@ -474,17 +479,17 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) length = 0; for (i = 0; i < index.dim; i++) { - Expression *idx = index.tdata()[i]; + Expression *idx = index[i]; if (idx) { idx = idx->semantic(sc); idx = idx->optimize(WANTvalue | WANTinterpret); - index.tdata()[i] = idx; + index[i] = idx; length = idx->toInteger(); } - Initializer *val = value.tdata()[i]; + Initializer *val = value[i]; val = val->semantic(sc, t->nextOf(), needInterpret); - value.tdata()[i] = val; + value[i] = val; length++; if (length == 0) { error(loc, "array dimension overflow"); @@ -498,7 +503,7 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) dinteger_t edim = ((TypeSArray *)t)->dim->toInteger(); if (dim > edim) { - error(loc, "array initializer has %u elements, but array length is %jd", dim, edim); + error(loc, "array initializer has %u elements, but array length is %lld", dim, edim); goto Lerr; } } @@ -552,8 +557,8 @@ Expression *ArrayInitializer::toExpression() edim = value.dim; for (size_t i = 0, j = 0; i < value.dim; i++, j++) { - if (index.tdata()[i]) - j = index.tdata()[i]->toInteger(); + if (index[i]) + j = index[i]->toInteger(); if (j >= edim) edim = j + 1; } @@ -564,10 +569,10 @@ Expression *ArrayInitializer::toExpression() elements->zero(); for (size_t i = 0, j = 0; i < value.dim; i++, j++) { - if (index.tdata()[i]) - j = (index.tdata()[i])->toInteger(); + if (index[i]) + j = (index[i])->toInteger(); assert(j < edim); - Initializer *iz = value.tdata()[i]; + Initializer *iz = value[i]; if (!iz) goto Lno; Expression *ex = iz->toExpression(); @@ -575,7 +580,7 @@ Expression *ArrayInitializer::toExpression() { goto Lno; } - elements->tdata()[j] = ex; + (*elements)[j] = ex; } /* Fill in any missing elements with the default initializer @@ -584,13 +589,13 @@ Expression *ArrayInitializer::toExpression() Expression *init = NULL; for (size_t i = 0; i < edim; i++) { - if (!elements->tdata()[i]) + if (!(*elements)[i]) { if (!type) goto Lno; if (!init) init = ((TypeNext *)t)->next->defaultInit(); - elements->tdata()[i] = init; + (*elements)[i] = init; } } @@ -621,18 +626,18 @@ Expression *ArrayInitializer::toAssocArrayLiteral() for (size_t i = 0; i < value.dim; i++) { - e = index.tdata()[i]; + e = index[i]; if (!e) goto Lno; - keys->tdata()[i] = e; + (*keys)[i] = e; - Initializer *iz = value.tdata()[i]; + Initializer *iz = value[i]; if (!iz) goto Lno; e = iz->toExpression(); if (!e) goto Lno; - values->tdata()[i] = e; + (*values)[i] = e; } e = new AssocArrayLiteralExp(loc, keys, values); return e; @@ -648,7 +653,7 @@ int ArrayInitializer::isAssociativeArray() { for (size_t i = 0; i < value.dim; i++) { - if (index.tdata()[i]) + if (index[i]) return 1; } return 0; @@ -710,13 +715,13 @@ void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (i > 0) buf->writebyte(','); - Expression *ex = index.tdata()[i]; + Expression *ex = index[i]; if (ex) { ex->toCBuffer(buf, hgs); buf->writebyte(':'); } - Initializer *iz = value.tdata()[i]; + Initializer *iz = value[i]; if (iz) iz->toCBuffer(buf, hgs); } @@ -792,10 +797,8 @@ bool hasNonConstPointers(Expression *e) bool arrayHasNonConstPointers(Expressions *elems) { for (size_t i = 0; i < elems->dim; i++) - { - if (!elems->tdata()[i]) - continue; - if (hasNonConstPointers(elems->tdata()[i])) + { Expression *e = (*elems)[i]; + if (e && hasNonConstPointers(e)) return true; } return false; @@ -816,7 +819,7 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) return this; // Failed, suppress duplicate error messages if (exp->op == TOKtype) - error("initializer must be an expression, not '%s'", exp->toChars()); + exp->error("initializer must be an expression, not '%s'", exp->toChars()); // Make sure all pointers are constants if (needInterpret && hasNonConstPointers(exp)) @@ -865,12 +868,6 @@ 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); @@ -884,7 +881,7 @@ Type *ExpInitializer::inferType(Scope *sc) // Give error for overloaded function addresses if (exp->op == TOKdelegate) { DelegateExp *se = (DelegateExp *)exp; - if ( + if (se->hasOverloads && se->func->isFuncDeclaration() && !se->func->isFuncDeclaration()->isUnique()) exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); diff --git a/dmd2/inline.c b/dmd2/inline.c index 052dc343..47eebe6d 100644 --- a/dmd2/inline.c +++ b/dmd2/inline.c @@ -1516,6 +1516,9 @@ int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) if ( !fbody || ident == Id::ensure || // ensure() has magic properties the inliner loses + (ident == Id::require && // require() has magic properties too + toParent()->isFuncDeclaration() && // see bug 7699 + toParent()->isFuncDeclaration()->needThis()) || !hdrscan && ( #if 0 @@ -1813,6 +1816,18 @@ Expression *Expression::inlineCopy(Scope *sc) */ return copy(); #else + if (op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)this; + + if (de->func->isNested()) + { /* See Bugzilla 4820 + * Defer checking until later if we actually need the 'this' pointer + */ + Expression *e = de->copy(); + return e; + } + } + InlineCostState ics; memset(&ics, 0, sizeof(ics)); @@ -1829,3 +1844,4 @@ Expression *Expression::inlineCopy(Scope *sc) return e; #endif } + diff --git a/dmd2/interpret.c b/dmd2/interpret.c index 3d82d385..1dcecd02 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -27,7 +27,6 @@ #include "attrib.h" // for AttribDeclaration #include "template.h" -TemplateInstance *isSpeculativeFunction(FuncDeclaration *fd); #define LOG 0 @@ -45,6 +44,10 @@ private: together with the VarDeclaration, and the previous stack address of that variable, so that we can restore it when we leave the stack frame. + Note that when a function is forward referenced, the interpreter must + run semantic3, and that may start CTFE again with a NULL istate. Thus + the stack might not be empty when CTFE begins. + Ctfe Stack addresses are just 0-based integers, but we save them as 'void *' because ArrayBase can only do pointers. */ @@ -143,7 +146,11 @@ public: } void saveGlobalConstant(VarDeclaration *v, Expression *e) { - assert(v->isDataseg() && !v->isCTFE()); +#if DMDV2 + assert( v->init && (v->isConst() || v->isImmutable()) && !v->isCTFE()); +#else + assert( v->init && v->isConst() && !v->isCTFE()); +#endif v->ctfeAdrOnStack = globalValues.dim; globalValues.push(e); } @@ -208,7 +215,7 @@ VarDeclaration *findParentVar(Expression *e, Expression *thisval); bool needToCopyLiteral(Expression *expr); Expression *copyLiteral(Expression *e); Expression *paintTypeOntoLiteral(Type *type, Expression *lit); -Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2); +Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2); Expression *evaluateIfBuiltin(InterState *istate, Loc loc, FuncDeclaration *fd, Expressions *arguments, Expression *pthis); Expression *scrubReturnValue(Loc loc, Expression *e); @@ -243,6 +250,16 @@ struct ClassReferenceExp : Expression { return value->sd->isClassDeclaration(); } + VarDeclaration *getFieldAt(int index) + { + ClassDeclaration *cd = originalClass(); + size_t fieldsSoFar = 0; + while (index - fieldsSoFar >= cd->fields.dim) + { fieldsSoFar += cd->fields.dim; + cd = cd->baseClass; + } + return cd->fields.tdata()[index - fieldsSoFar]; + } // Return index of the field, or -1 if not found int getFieldIndex(Type *fieldtype, size_t fieldoffset) { @@ -283,6 +300,28 @@ struct ClassReferenceExp : Expression } }; +struct VoidInitExp : Expression +{ + VarDeclaration *var; + + VoidInitExp(VarDeclaration *var, Type *type) + : Expression(var->loc, TOKvoid, sizeof(VoidInitExp)) + { + this->var = var; + this->type = var->type; + } + char *toChars() + { + return (char *)"void"; + } + Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue) + { + error("CTFE internal error: trying to read uninitialized variable"); + assert(0); + return EXP_CANT_INTERPRET; + } +}; + // 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) @@ -456,7 +495,8 @@ void showCtfeExpr(Expression *e, int level = 0) * arguments function arguments * thisarg 'this', if a needThis() function, NULL if not. * - * Return result expression if successful, EXP_CANT_INTERPRET if not. + * Return result expression if successful, EXP_CANT_INTERPRET if not, + * or EXP_VOID_INTERPRET if function returned void. */ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg) @@ -475,7 +515,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument */ int olderrors = global.errors; int oldgag = global.gag; - TemplateInstance *spec = isSpeculativeFunction(this); + TemplateInstance *spec = isSpeculative(); if (global.gag && !spec) global.gag = 0; ++scope->ignoreTemplates; @@ -578,6 +618,15 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument --evaluatingArgs; if (earg == EXP_CANT_INTERPRET) return earg; + /* Struct literals are passed by value, but we don't need to + * copy them if they are passed as const + */ + if (earg->op == TOKstructliteral +#if DMDV2 + && !(arg->storageClass & (STCconst | STCimmutable)) +#endif + ) + earg = copyLiteral(earg); } if (earg->op == TOKthrownexception) { @@ -677,6 +726,11 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument // If fell off the end of a void function, return void if (!e && type->toBasetype()->nextOf()->ty == Tvoid) return EXP_VOID_INTERPRET; + + // If result is void, return void + if (e == EXP_VOID_INTERPRET) + return e; + // If it generated an exception, return it if (exceptionOrCantInterpret(e)) { @@ -685,6 +739,9 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument ((ThrownExceptionExp *)e)->generateUncaughtError(); return EXP_CANT_INTERPRET; } + + // If we're about to leave CTFE, make sure we don't crash the + // compiler by returning a CTFE-internal expression. if (!istate && !evaluatingArgs) { e = scrubReturnValue(loc, e); @@ -898,13 +955,16 @@ uinteger_t resolveArrayLength(Expression *e) } // As Equal, but resolves slices before comparing -Expression *ctfeEqual(enum TOK op, Type *type, Expression *e1, Expression *e2) +Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) { if (e1->op == TOKslice) e1 = resolveSlice(e1); if (e2->op == TOKslice) e2 = resolveSlice(e2); - return Equal(op, type, e1, e2); + Expression *e = Equal(op, type, e1, e2); + if (e == EXP_CANT_INTERPRET) + error(loc, "cannot evaluate %s==%s at compile time", e1->toChars(), e2->toChars()); + return e; } Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) @@ -975,7 +1035,7 @@ Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) return Cat(type, e1, e2); } -void scrubArray(Loc loc, Expressions *elems); +bool scrubArray(Loc loc, Expressions *elems, bool structlit = false); /* All results destined for use outside of CTFE need to have their CTFE-specific * features removed. @@ -988,6 +1048,11 @@ Expression *scrubReturnValue(Loc loc, Expression *e) error(loc, "%s class literals cannot be returned from CTFE", ((ClassReferenceExp*)e)->originalClass()->toChars()); return EXP_CANT_INTERPRET; } + if (e->op == TOKvoid) + { + error(loc, "uninitialized variable '%s' cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars()); + e = new ErrorExp(); + } if (e->op == TOKslice) { e = resolveSlice(e); @@ -996,7 +1061,8 @@ Expression *scrubReturnValue(Loc loc, Expression *e) { StructLiteralExp *se = (StructLiteralExp *)e; se->ownedByCtfe = false; - scrubArray(loc, se->elements); + if (!scrubArray(loc, se->elements, true)) + return EXP_CANT_INTERPRET; } if (e->op == TOKstring) { @@ -1005,29 +1071,38 @@ Expression *scrubReturnValue(Loc loc, Expression *e) if (e->op == TOKarrayliteral) { ((ArrayLiteralExp *)e)->ownedByCtfe = false; - scrubArray(loc, ((ArrayLiteralExp *)e)->elements); + if (!scrubArray(loc, ((ArrayLiteralExp *)e)->elements)) + return EXP_CANT_INTERPRET; } if (e->op == TOKassocarrayliteral) { AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; aae->ownedByCtfe = false; - scrubArray(loc, aae->keys); - scrubArray(loc, aae->values); + if (!scrubArray(loc, aae->keys)) + return EXP_CANT_INTERPRET; + if (!scrubArray(loc, aae->values)) + return EXP_CANT_INTERPRET; } return e; } -// Scrub all members of an array -void scrubArray(Loc loc, Expressions *elems) +// Scrub all members of an array. Return false if error +bool scrubArray(Loc loc, Expressions *elems, bool structlit) { for (size_t i = 0; i < elems->dim; i++) { Expression *m = elems->tdata()[i]; if (!m) continue; - m = scrubReturnValue(loc, m); + if (m && m->op == TOKvoid && structlit) + m = NULL; + if (m) + m = scrubReturnValue(loc, m); + if (m == EXP_CANT_INTERPRET) + return false; elems->tdata()[i] = m; } + return true; } @@ -1362,7 +1437,7 @@ Expression *SwitchStatement::interpret(InterState *istate) Expression * caseExp = cs->exp->interpret(istate); if (exceptionOrCantInterpret(caseExp)) return caseExp; - e = ctfeEqual(TOKequal, Type::tint32, econdition, caseExp); + e = ctfeEqual(caseExp->loc, TOKequal, Type::tint32, econdition, caseExp); if (exceptionOrCantInterpret(e)) return e; if (e->isBool(TRUE)) @@ -1481,25 +1556,25 @@ Expression *TryCatchStatement::interpret(InterState *istate) ThrownExceptionExp *ex = (ThrownExceptionExp *)e; Type *extype = ex->thrown->originalClass()->type; // Search for an appropriate catch clause. - for (size_t i = 0; i < catches->dim; i++) - { + for (size_t i = 0; i < catches->dim; i++) + { #if DMDV1 - Catch *ca = (Catch *)catches->data[i]; + Catch *ca = (Catch *)catches->data[i]; #else - Catch *ca = catches->tdata()[i]; + Catch *ca = catches->tdata()[i]; #endif - Type *catype = ca->type; + Type *catype = ca->type; - if (catype->equals(extype) || catype->isBaseOf(extype, NULL)) - { // Execute the handler + if (catype->equals(extype) || catype->isBaseOf(extype, NULL)) + { // Execute the handler if (ca->var) { ctfeStack.push(ca->var); ca->var->setValue(ex->thrown); } - return ca->handler->interpret(istate); - } + return ca->handler ? ca->handler->interpret(istate) : NULL; } + } return e; } @@ -1740,6 +1815,8 @@ Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) } Type *pointee = ((TypePointer *)type)->next; Expression *val = getVarExp(loc, istate, var, goal); + if (val == EXP_CANT_INTERPRET) + return val; if (val->type->ty == Tarray || val->type->ty == Tsarray) { // Check for unsupported type painting operations @@ -1965,10 +2042,7 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal if (e && e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) { e = copyLiteral(e); - if (v->isDataseg()) - ctfeStack.saveGlobalConstant(v, e); - else - v->setValueWithoutChecking(e); + ctfeStack.saveGlobalConstant(v, e); } } else if (v->isCTFE() && !v->hasValue()) @@ -1977,11 +2051,16 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal { if (v->init->isVoidInitializer()) { - error(loc, "variable %s is used before initialization", v->toChars()); - return EXP_CANT_INTERPRET; + // var should have been initialized when it was created + error(loc, "CTFE internal error - trying to access uninitialized var"); + assert(0); + e = EXP_CANT_INTERPRET; + } + else + { + e = v->init->toExpression(); + e = e->interpret(istate); } - e = v->init->toExpression(); - e = e->interpret(istate); } else e = v->type->defaultInitLiteral(loc); @@ -1997,7 +2076,11 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal e = EXP_CANT_INTERPRET; } else if (!e) - error(loc, "variable %s is used before initialization", v->toChars()); + { + assert(0); + assert(v->init && v->init->isVoidInitializer()); + e = v->type->voidInitLiteral(v); + } else if (exceptionOrCantInterpret(e)) return e; else if (goal == ctfeNeedLvalue && v->isRef() && e->op == TOKindex) @@ -2016,6 +2099,13 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal || e->op == TOKassocarrayliteral || e->op == TOKslice || e->type->toBasetype()->ty == Tpointer) return e; // it's already an Lvalue + else if (e->op == TOKvoid) + { + VoidInitExp *ve = (VoidInitExp *)e; + error(loc, "cannot read uninitialized variable %s in ctfe", v->toPrettyChars()); + errorSupplemental(ve->var->loc, "%s was uninitialized and used before set", ve->var->toChars()); + e = EXP_CANT_INTERPRET; + } else e = e->interpret(istate, goal); } @@ -2027,10 +2117,12 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal #if !IN_LLVM if (s->dsym->toInitializer() == s->sym) #endif - { e = s->dsym->type->defaultInitLiteral(); + { e = s->dsym->type->defaultInitLiteral(loc); e = e->semantic(NULL); if (e->op == TOKerror) e = EXP_CANT_INTERPRET; + else // Convert NULL to VoidExp + e = e->interpret(istate, goal); } #if !IN_LLVM else @@ -2101,7 +2193,12 @@ Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal) if (ie) e = ie->exp->interpret(istate); else if (v->init->isVoidInitializer()) - e = NULL; + { + e = v->type->voidInitLiteral(v); + // There is no AssignExp for void initializers, + // so set it here. + v->setValue(e); + } else { error("Declaration %s is not yet implemented in CTFE", toChars()); @@ -2330,7 +2427,7 @@ Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) ekey = resolveSlice(ekey); for (size_t j = i; j < keysx->dim; j++) { Expression *ekey2 = keysx->tdata()[j]; - Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, ekey2); + Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, ekey2); if (ex == EXP_CANT_INTERPRET) goto Lerr; if (ex->isBool(TRUE)) // if a match @@ -2504,10 +2601,10 @@ Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *is if (elemType->ty == Tchar || elemType->ty == Twchar || elemType->ty == Tdchar) return createBlockDuplicatedStringLiteral(loc, newtype, - (unsigned)(elemType->defaultInitLiteral()->toInteger()), + (unsigned)(elemType->defaultInitLiteral(loc)->toInteger()), len, elemType->size()); return createBlockDuplicatedArrayLiteral(loc, newtype, - elemType->defaultInitLiteral(), + elemType->defaultInitLiteral(loc), len); } @@ -2521,7 +2618,7 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) if (newtype->toBasetype()->ty == Tstruct) { - Expression *se = newtype->defaultInitLiteral(); + Expression *se = newtype->defaultInitLiteral(loc); #if DMDV2 if (member) { @@ -2558,7 +2655,7 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) Dsymbol *s = c->fields.tdata()[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); - Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(); + Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(loc); if (exceptionOrCantInterpret(m)) return m; elems->tdata()[fieldsSoFar+i] = copyLiteral(m); @@ -2735,7 +2832,7 @@ Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type, } if (indx < 0 || indx > len) { - error(loc, "cannot assign pointer to index %jd inside memory block [0..%jd]", indx, len); + error(loc, "cannot assign pointer to index %lld inside memory block [0..%lld]", indx, len); return EXP_CANT_INTERPRET; } @@ -3037,7 +3134,7 @@ Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae, Expressi for (size_t j = valuesx->dim; j; ) { j--; Expression *ekey = aae->keys->tdata()[j]; - Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, index); + Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, index); if (exceptionOrCantInterpret(ex)) return ex; if (ex->isBool(TRUE)) @@ -3207,7 +3304,7 @@ Expression *copyLiteral(Expression *e) assert(v); // If it is a void assignment, use the default initializer if (!m) - m = v->type->defaultInitLiteral(e->loc); + m = v->type->voidInitLiteral(v); if (m->op == TOKslice) m = resolveSlice(m); if ((v->type->ty != m->type->ty) && v->type->ty == Tsarray) @@ -3234,7 +3331,8 @@ Expression *copyLiteral(Expression *e) || e->op == TOKsymoff || e->op == TOKnull || e->op == TOKvar || e->op == TOKint64 || e->op == TOKfloat64 - || e->op == TOKchar || e->op == TOKcomplex80) + || e->op == TOKchar || e->op == TOKcomplex80 + || e->op == TOKvoid) { // Simple value types Expression *r = e->syntaxCopy(); r->type = e->type; @@ -3404,7 +3502,7 @@ void assignInPlace(Expression *dest, Expression *src) assert(o->op == e->op); assignInPlace(o, e); } - else if (e->type->ty == Tsarray && o->type->ty == Tsarray) + else if (e->type->ty == Tsarray && o->type->ty == Tsarray && e->op != TOKvoid) { assignInPlace(o, e); } @@ -3699,7 +3797,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ Type *elemType= NULL; elemType = ((TypeArray *)t)->next; assert(elemType); - Expression *defaultElem = elemType->defaultInitLiteral(); + Expression *defaultElem = elemType->defaultInitLiteral(loc); Expressions *elements = new Expressions(); elements->setDim(newlen); @@ -3807,7 +3905,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ // 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->setValue(copyLiteral(ultimateVar->type->defaultInitLiteral())); + ultimateVar->setValue(copyLiteral(ultimateVar->type->defaultInitLiteral(loc))); // --------------------------------------- // Deal with reference assignment @@ -3885,7 +3983,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ indx = resolveSlice(indx); // Look up this index in it up in the existing AA, to get the next level of AA. - AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(existingAA, indx); + AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(loc, existingAA, indx); if (exceptionOrCantInterpret(newAA)) return newAA; if (!newAA) @@ -4031,14 +4129,29 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ ? (StructLiteralExp *)exx : ((ClassReferenceExp *)exx)->value; int fieldi = exx->op == TOKstructliteral - ? se->getFieldIndex(member->type, member->offset) - : ((ClassReferenceExp *)exx)->getFieldIndex(member->type, member->offset); + ? findFieldIndexByName(se->sd, member) + : ((ClassReferenceExp *)exx)->findFieldIndexByName(member); if (fieldi == -1) { error("CTFE internal error: cannot find field %s in %s", member->toChars(), exx->toChars()); return EXP_CANT_INTERPRET; } - assert(fieldi>=0 && fieldi < se->elements->dim); + assert(fieldi >= 0 && fieldi < se->elements->dim); + // If it's a union, set all other members of this union to void + if (exx->op == TOKstructliteral) + { + assert(se->sd); + int unionStart = se->sd->firstFieldInUnion(fieldi); + int unionSize = se->sd->numFieldsInUnion(fieldi); + for(int i = unionStart; i < unionStart + unionSize; ++i) + { if (i == fieldi) + continue; + Expression **el = &se->elements->tdata()[i]; + if ((*el)->op != TOKvoid) + *el = (*el)->type->voidInitLiteral(member); + } + } + if (newval->op == TOKstructliteral) assignInPlace(se->elements->tdata()[fieldi], newval); else @@ -4113,6 +4226,21 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ } aggregate = getAggregateFromPointer(aggregate, &ofs); indexToModify += ofs; + if (aggregate->op != TOKslice && aggregate->op != TOKstring && + aggregate->op != TOKarrayliteral && aggregate->op != TOKassocarrayliteral) + { + if (indexToModify != 0) + { + error("pointer index [%lld] lies outside memory block [0..1]", indexToModify); + return EXP_CANT_INTERPRET; + } + // It is equivalent to *aggregate = newval. + // Aggregate could be varexp, a dotvar, ... + // TODO: we could support this + error("indexed assignment of non-array pointers is not yet supported at compile time; use *%s = %s instead", + ie->e1->toChars(), e2->toChars()); + return EXP_CANT_INTERPRET; + } destarraylen = resolveArrayLength(aggregate); } if (indexToModify >= destarraylen) @@ -4138,7 +4266,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) { IndexExp *ix = (IndexExp *)aggregate; - aggregate = findKeyInAA((AssocArrayLiteralExp *)ix->e1, ix->e2); + aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2); if (!aggregate) { error("key %s not found in associative array %s", @@ -4240,6 +4368,8 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ if (isPointer(oldval->type)) { // Slicing a pointer oldval = oldval->interpret(istate, ctfeNeedLvalue); + if (exceptionOrCantInterpret(oldval)) + return oldval; dinteger_t ofs; oldval = getAggregateFromPointer(oldval, &ofs); assignmentToSlicedPointer = true; @@ -4249,7 +4379,13 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ if (oldval->op != TOKarrayliteral && oldval->op != TOKstring && oldval->op != TOKslice && oldval->op != TOKnull) { - error("CTFE ICE: cannot resolve array length"); + if (assignmentToSlicedPointer) + { + error("pointer %s cannot be sliced at compile time (it does not point to an array)", + sexp->e1->toChars()); + } + else + error("CTFE ICE: cannot resolve array length"); return EXP_CANT_INTERPRET; } uinteger_t dollar = resolveArrayLength(oldval); @@ -4312,7 +4448,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) { IndexExp *ix = (IndexExp *)aggregate; - aggregate = findKeyInAA((AssocArrayLiteralExp *)ix->e1, ix->e2); + aggregate = findKeyInAA(loc, (AssocArrayLiteralExp *)ix->e1, ix->e2); if (!aggregate) { error("key %s not found in associative array %s", @@ -4336,7 +4472,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ firstIndex = lowerbound + sexpold->lwr->toInteger(); if (hi > sexpold->upr->toInteger()) { - error("slice [%d..%d] exceeds array bounds [0..%jd]", + error("slice [%d..%d] exceeds array bounds [0..%lld]", lowerbound, upperbound, sexpold->upr->toInteger() - sexpold->lwr->toInteger()); return EXP_CANT_INTERPRET; @@ -4348,11 +4484,16 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue); dinteger_t ofs; aggregate = getAggregateFromPointer(aggregate, &ofs); + if (aggregate->op == TOKnull) + { + error("cannot slice null pointer %s", sexp->e1->toChars()); + return EXP_CANT_INTERPRET; + } dinteger_t hi = upperbound + ofs; firstIndex = lowerbound + ofs; if (firstIndex < 0 || hi > dim) { - error("slice [%d..%jd] exceeds memory block bounds [0..%jd]", + error("slice [lld..%lld] exceeds memory block bounds [0..%lld]", firstIndex, hi, dim); return EXP_CANT_INTERPRET; } @@ -4493,9 +4634,6 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ else { error("%s cannot be evaluated at compile time", toChars()); -#ifdef DEBUG - dump(0); -#endif } return returnValue; } @@ -4883,6 +5021,10 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) if (!global.gag) showCtfeBackTrace(istate, this, fd); } + else if (eresult == EXP_VOID_INTERPRET) + ; + else + eresult->loc = loc; return eresult; } @@ -4901,7 +5043,6 @@ Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal) InterState istateComma; if (!istate && firstComma->e1->op == TOKdeclaration) { - assert(ctfeStack.stackPointer() == 0); ctfeStack.startFrame(); istate = &istateComma; } @@ -4919,7 +5060,7 @@ Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal) ctfeStack.push(v); if (!v->init && !v->getValue()) { - v->setValue(copyLiteral(v->type->defaultInitLiteral())); + v->setValue(copyLiteral(v->type->defaultInitLiteral(loc))); } if (!v->getValue()) { Expression *newval = v->init->toExpression(); @@ -5015,7 +5156,7 @@ Expression *ArrayLengthExp::interpret(InterState *istate, CtfeGoal goal) * Return ae[e2] if present, or NULL if not found. * Return EXP_CANT_INTERPRET on error. */ -Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2) +Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2) { /* Search the keys backwards, in case there are duplicate keys */ @@ -5023,13 +5164,9 @@ Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2) { i--; Expression *ekey = ae->keys->tdata()[i]; - Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, e2); + Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, e2); if (ex == EXP_CANT_INTERPRET) - { - error("cannot evaluate %s==%s at compile time", - ekey->toChars(), e2->toChars()); return ex; - } if (ex->isBool(TRUE)) { return ae->values->tdata()[i]; @@ -5084,23 +5221,37 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) if (exceptionOrCantInterpret(e2)) return e2; dinteger_t indx = e2->toInteger(); + dinteger_t ofs; Expression *agg = getAggregateFromPointer(e1, &ofs); + if (agg->op == TOKnull) { error("cannot index null pointer %s", this->e1->toChars()); return EXP_CANT_INTERPRET; } - assert(agg->op == TOKarrayliteral || agg->op == TOKstring); - dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); - Type *pointee = ((TypePointer *)agg->type)->next; - if ((indx + ofs) < 0 || (indx+ofs) > len) + if ( agg->op == TOKarrayliteral || agg->op == TOKstring) { - error("pointer index [%jd] exceeds allocated memory block [0..%jd]", - indx+ofs, len); - return EXP_CANT_INTERPRET; + dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); + Type *pointee = ((TypePointer *)agg->type)->next; + if ((indx + ofs) < 0 || (indx+ofs) > len) + { + error("pointer index [%lld] exceeds allocated memory block [0..%lld]", + indx+ofs, len); + return EXP_CANT_INTERPRET; + } + return ctfeIndex(loc, type, agg, indx+ofs); + } + else + { // Pointer to a non-array variable + if ((indx + ofs) != 0) + { + error("pointer index [%lld] lies outside memory block [0..1]", + indx+ofs); + return EXP_CANT_INTERPRET; + } + return agg->interpret(istate); } - return ctfeIndex(loc, type, agg, indx+ofs); } e1 = this->e1; if (!(e1->op == TOKarrayliteral && ((ArrayLiteralExp *)e1)->ownedByCtfe)) @@ -5141,7 +5292,7 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) if (indx > iup - ilo) { - error("index %ju exceeds array length %ju", indx, iup - ilo); + error("index %llu exceeds array length %llu", indx, iup - ilo); return EXP_CANT_INTERPRET; } indx += ilo; @@ -5162,7 +5313,7 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) { if (e2->op == TOKslice) e2 = resolveSlice(e2); - e = findKeyInAA((AssocArrayLiteralExp *)e1, e2); + e = findKeyInAA(loc, (AssocArrayLiteralExp *)e1, e2); if (!e) { error("key %s not found in associative array %s", @@ -5183,6 +5334,12 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) return e; if (goal == ctfeNeedRvalue && (e->op == TOKslice || e->op == TOKdotvar)) e = e->interpret(istate); + if (goal == ctfeNeedRvalue && e->op == TOKvoid) + { + error("%s is used before initialized", toChars()); + errorSupplemental(e->loc, "originally uninitialized here"); + return EXP_CANT_INTERPRET; + } e = paintTypeOntoLiteral(type, e); return e; } @@ -5237,12 +5394,18 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) error("cannot slice null pointer %s", this->e1->toChars()); return EXP_CANT_INTERPRET; } + if (agg->op != TOKarrayliteral && agg->op != TOKstring) + { + error("pointer %s cannot be sliced at compile time (it does not point to an array)", + this->e1->toChars()); + return EXP_CANT_INTERPRET; + } assert(agg->op == TOKarrayliteral || agg->op == TOKstring); dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); Type *pointee = ((TypePointer *)agg->type)->next; if ((ilwr + ofs) < 0 || (iupr+ofs) > (len + 1) || iupr < ilwr) { - error("pointer slice [%jd..%jd] exceeds allocated memory block [0..%jd]", + error("pointer slice [%lld..%lld] exceeds allocated memory block [0..%lld]", ilwr+ofs, iupr+ofs, len); return EXP_CANT_INTERPRET; } @@ -5306,7 +5469,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) { if (ilwr== 0 && iupr == 0) return e1; - e1->error("slice [%ju..%ju] is out of bounds", ilwr, iupr); + e1->error("slice [%llu..%llu] is out of bounds", ilwr, iupr); return EXP_CANT_INTERPRET; } if (e1->op == TOKslice) @@ -5318,7 +5481,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) uinteger_t up1 = se->upr->toInteger(); if (ilwr > iupr || iupr > up1 - lo1) { - error("slice[%ju..%ju] exceeds array bounds[%ju..%ju]", + error("slice[%llu..%llu] exceeds array bounds[%llu..%llu]", ilwr, iupr, lo1, up1); return EXP_CANT_INTERPRET; } @@ -5335,7 +5498,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) { if (iupr < ilwr || ilwr < 0 || iupr > dollar) { - error("slice [%jd..%jd] exceeds array bounds [0..%jd]", + error("slice [%lld..%lld] exceeds array bounds [0..%lld]", ilwr, iupr, dollar); return EXP_CANT_INTERPRET; } @@ -5366,7 +5529,7 @@ Expression *InExp::interpret(InterState *istate, CtfeGoal goal) } if (e1->op == TOKslice) e1 = resolveSlice(e1); - e = findKeyInAA((AssocArrayLiteralExp *)e2, e1); + e = findKeyInAA(loc, (AssocArrayLiteralExp *)e2, e1); if (exceptionOrCantInterpret(e)) return e; if (!e) @@ -5425,8 +5588,12 @@ bool isAssocArray(Type *t) if (t->ty != Tstruct) return false; StructDeclaration *sym = ((TypeStruct *)t)->sym; - if (sym->ident == Id::AssociativeArray) + if (sym->ident == Id::AssociativeArray && sym->parent && + sym->parent->parent && + sym->parent->parent->ident == Id::object) + { return true; + } #endif return false; } @@ -5581,9 +5748,15 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) e->type = type; return e; } - error("pointer cast from %s to %s is not supported at compile time", + + // Check if we have a null pointer (eg, inside a struct) + e1 = e1->interpret(istate); + if (e1->op != TOKnull) + { + error("pointer cast from %s to %s is not supported at compile time", e1->type->toChars(), to->toChars()); - return EXP_CANT_INTERPRET; + return EXP_CANT_INTERPRET; + } } if (to->ty == Tarray && e1->op == TOKslice) { @@ -5731,7 +5904,7 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) assert(indx >=0 && indx <= len); // invalid pointer if (indx == len) { - error("dereference of pointer %s one past end of memory block limits [0..%jd]", + error("dereference of pointer %s one past end of memory block limits [0..%lld]", toChars(), len); return EXP_CANT_INTERPRET; } @@ -5776,7 +5949,7 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) } else if (e->op == TOKaddress) e = ((AddrExp*)e)->e1; // *(&x) ==> x - if (e->op == TOKnull) + else if (e->op == TOKnull) { error("dereference of null pointer '%s'", e1->toChars()); return EXP_CANT_INTERPRET; @@ -5865,6 +6038,13 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) if (e->op == TOKstructliteral || e->op == TOKarrayliteral || e->op == TOKassocarrayliteral || e->op == TOKstring) return e; + if (e->op == TOKvoid) + { + VoidInitExp *ve = (VoidInitExp *)e; + error("cannot read uninitialized variable %s in ctfe", toChars()); + ve->var->error("was uninitialized and used before set"); + return EXP_CANT_INTERPRET; + } if ( isPointer(type) ) { return paintTypeOntoLiteral(type, e); @@ -5909,7 +6089,7 @@ Expression *RemoveExp::interpret(InterState *istate, CtfeGoal goal) size_t removed = 0; for (size_t j = 0; j < valuesx->dim; ++j) { Expression *ekey = keysx->tdata()[j]; - Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, index); + Expression *ex = ctfeEqual(loc, TOKequal, Type::tbool, ekey, index); if (exceptionOrCantInterpret(ex)) return ex; if (ex->isBool(TRUE)) @@ -6088,7 +6268,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del else if (str->op == TOKarrayliteral) ale = (ArrayLiteralExp *)str; else - { error("CTFE internal error: cannot foreach %s", str->toChars()); + { str->error("CTFE internal error: cannot foreach %s", str->toChars()); return EXP_CANT_INTERPRET; } Expressions args; @@ -6552,6 +6732,10 @@ bool isCtfeValueValid(Expression *newval) assert(((ArrayLiteralExp *)se->e1)->ownedByCtfe); return true; } + if (newval->op == TOKvoid) + { + return true; + } newval->error("CTFE internal error: illegal value %s\n", newval->toChars()); return false; } @@ -6584,3 +6768,28 @@ void VarDeclaration::setValue(Expression *newval) assert(isCtfeValueValid(newval)); ctfeStack.setValue(this, newval); } + + +Expression *Type::voidInitLiteral(VarDeclaration *var) +{ + return new VoidInitExp(var, this); +} + +Expression *TypeSArray::voidInitLiteral(VarDeclaration *var) +{ + return createBlockDuplicatedArrayLiteral(var->loc, this, next->voidInitLiteral(var), dim->toInteger()); +} + +Expression *TypeStruct::voidInitLiteral(VarDeclaration *var) +{ + Expressions *exps = new Expressions(); + exps->setDim(sym->fields.dim); + for (size_t i = 0; i < sym->fields.dim; i++) + { + (*exps)[i] = new VoidInitExp(var, sym->fields[i]->type); + } + StructLiteralExp *se = new StructLiteralExp(var->loc, sym, exps); + se->type = this; + se->ownedByCtfe = true; + return se; +} diff --git a/dmd2/lexer.c b/dmd2/lexer.c index 7b53f212..ed3dfae0 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -119,11 +119,11 @@ const char *Token::toChars() break; case TOKint64v: - sprintf(buffer,"%jdL",(intmax_t)int64value); + sprintf(buffer,"%lldL",(intmax_t)int64value); break; case TOKuns64v: - sprintf(buffer,"%juUL",(uintmax_t)uns64value); + sprintf(buffer,"%lluUL",(uintmax_t)uns64value); break; #if IN_GCC @@ -141,27 +141,32 @@ const char *Token::toChars() break; #else case TOKfloat32v: - sprintf(buffer,"%Lgf", float80value); + ld_sprint(buffer, 'g', float80value); + strcat(buffer, "f"); break; case TOKfloat64v: - sprintf(buffer,"%Lg", float80value); + ld_sprint(buffer, 'g', float80value); break; case TOKfloat80v: - sprintf(buffer,"%LgL", float80value); + ld_sprint(buffer, 'g', float80value); + strcat(buffer, "L"); break; case TOKimaginary32v: - sprintf(buffer,"%Lgfi", float80value); + ld_sprint(buffer, 'g', float80value); + strcat(buffer, "fi"); break; case TOKimaginary64v: - sprintf(buffer,"%Lgi", float80value); + ld_sprint(buffer, 'g', float80value); + strcat(buffer, "i"); break; case TOKimaginary80v: - sprintf(buffer,"%LgLi", float80value); + ld_sprint(buffer, 'g', float80value); + strcat(buffer, "Li"); break; #endif @@ -300,7 +305,7 @@ void Lexer::error(const char *format, ...) { va_list ap; va_start(ap, format); - verror(loc, format, ap); + verror(tokenLoc(), format, ap); va_end(ap); } @@ -363,7 +368,6 @@ Token *Lexer::peek(Token *ct) { t = new Token(); scan(t); - t->next = NULL; ct->next = t; } return t; @@ -1222,9 +1226,21 @@ void Lexer::scan(Token *t) #undef DOUBLE case '#': + { p++; - pragma(); - continue; + Token *n = peek(t); + if (n->value == TOKidentifier && n->ident == Id::line) + { + nextToken(); + poundLine(); + continue; + } + else + { + t->value = TOKpound; + return; + } + } default: { unsigned c = *p; @@ -2567,22 +2583,17 @@ done: } /********************************************* - * Do pragma. - * Currently, the only pragma supported is: + * parse: * #line linnum [filespec] */ -void Lexer::pragma() +void Lexer::poundLine() { Token tok; int linnum; char *filespec = NULL; Loc loc = this->loc; - scan(&tok); - if (tok.value != TOKidentifier || tok.ident != Id::line) - goto Lerr; - scan(&tok); if (tok.value == TOKint32v || tok.value == TOKint64v) { linnum = tok.uns64value - 1; @@ -2866,6 +2877,38 @@ unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2) return c; } +/******************************************* + * Search actual location of current token + * even when infinite look-ahead was done. + */ +Loc Lexer::tokenLoc() +{ + Loc result = this->loc; + Token* last = &token; + while (last->next) + last = last->next; + + unsigned char* start = token.ptr; + unsigned char* stop = last->ptr; + + for (unsigned char* p = start; p < stop; ++p) + { + switch (*p) + { + case '\n': + result.linnum--; + break; + case '\r': + if (p[1] != '\n') + result.linnum--; + break; + default: + break; + } + } + return result; +} + /******************************************** * Create an identifier in the string table. */ @@ -3165,6 +3208,7 @@ void Lexer::initKeywords() Token::tochars[TOKpow] = "^^"; Token::tochars[TOKpowass] = "^^="; Token::tochars[TOKgoesto] = "=>"; + Token::tochars[TOKpound] = "#"; #endif // For debugging diff --git a/dmd2/lexer.h b/dmd2/lexer.h index 692e2c7f..848d7123 100644 --- a/dmd2/lexer.h +++ b/dmd2/lexer.h @@ -170,6 +170,7 @@ enum TOK TOKpowass, TOKgoesto, TOKvector, + TOKpound, #endif // LDC specific @@ -256,6 +257,7 @@ struct Token static const char *tochars[TOKMAX]; static void *operator new(size_t sz); + Token() : next(NULL) {} int isKeyword(); void print(); const char *toChars(); @@ -310,12 +312,14 @@ struct Lexer void error(const char *format, ...) IS_PRINTF(2); void error(Loc loc, const char *format, ...) IS_PRINTF(3); void verror(Loc loc, const char *format, va_list ap); - void pragma(); + void poundLine(); unsigned decodeUTF(); void getDocComment(Token *t, unsigned lineComment); static int isValidIdentifier(char *p); static unsigned char *combineComments(unsigned char *c1, unsigned char *c2); + + Loc tokenLoc(); }; #endif /* DMD_LEXER_H */ diff --git a/dmd2/lib.h b/dmd2/lib.h index abd31cb2..3a67ed30 100644 --- a/dmd2/lib.h +++ b/dmd2/lib.h @@ -48,6 +48,20 @@ struct Library unsigned short numDictPages(unsigned padding); int FillDict(unsigned char *bucketsP, unsigned short uNumPages); void WriteLibToBuffer(OutBuffer *libbuf); + + void error(const char *format, ...) + { + Loc loc; + if (libfile) + { + loc.filename = libfile->name->toChars(); + loc.linnum = 0; + } + va_list ap; + va_start(ap, format); + ::verror(loc, format, ap); + va_end(ap); + } }; #endif /* DMD_LIB_H */ diff --git a/dmd2/mangle.c b/dmd2/mangle.c index 0c19040c..fc97aa51 100644 --- a/dmd2/mangle.c +++ b/dmd2/mangle.c @@ -239,7 +239,7 @@ char *TemplateInstance::mangle() buf.writestring(p); } } - buf.printf("%zu%s", strlen(id), id); + buf.printf("%llu%s", (ulonglong)strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); @@ -293,7 +293,7 @@ char *Dsymbol::mangle() p += 2; buf.writestring(p); } - buf.printf("%zu%s", strlen(id), id); + buf.printf("%llu%s", (ulonglong)strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); diff --git a/dmd2/mars.c b/dmd2/mars.c index f80250e6..f809295e 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -100,7 +100,7 @@ Global::Global() "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; #endif ; - version = "v2.058"; + version = "v2.059"; #if IN_LLVM ldc_version = "LDC trunk"; llvm_version = "LLVM 3.0"; @@ -132,6 +132,11 @@ bool Global::endGagging(unsigned oldGagged) return anyErrs; } +bool Global::isSpeculativeGagging() +{ + return gag && gag == speculativeGag; +} + char *Loc::toChars() { @@ -375,7 +380,7 @@ Usage:\n\ extern signed char tyalignsize[]; -#if _WIN32 +#if _WIN32 && __DMC__ extern "C" { extern int _xi_a; @@ -383,11 +388,11 @@ extern "C" } #endif -int main(int argc, char *argv[]) +int tryMain(int argc, char *argv[]) { mem.init(); // initialize storage allocator mem.setStackBottom(&argv); -#if _WIN32 +#if _WIN32 && __DMC__ mem.addroots((char *)&_xi_a, (char *)&_end); #endif @@ -411,7 +416,7 @@ int main(int argc, char *argv[]) if (argc < 1 || !argv) { Largs: - error("missing or null command line arguments"); + error(0, "missing or null command line arguments"); fatal(); } for (size_t i = 0; i < argc; i++) @@ -421,7 +426,7 @@ int main(int argc, char *argv[]) } if (response_expand(&argc,&argv)) // expand response files - error("can't open response file"); + error(0, "can't open response file"); files.reserve(argc - 1); @@ -448,6 +453,7 @@ int main(int argc, char *argv[]) global.params.is64bit = (sizeof(size_t) == 8); #if TARGET_WINDOS + global.params.is64bit = 0; global.params.defaultlibname = "phobos"; #elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS global.params.defaultlibname = "phobos2"; @@ -549,7 +555,7 @@ int main(int argc, char *argv[]) else if (strcmp(p + 1, "gs") == 0) global.params.alwaysframe = 1; else if (strcmp(p + 1, "gt") == 0) - { error("use -profile instead of -gt\n"); + { error(0, "use -profile instead of -gt\n"); global.params.trace = 1; } else if (strcmp(p + 1, "m32") == 0) @@ -569,7 +575,7 @@ int main(int argc, char *argv[]) #if DMDV1 global.params.Dversion = 1; #else - error("use DMD 1.0 series compilers for -v1 switch"); + error(0, "use DMD 1.0 series compilers for -v1 switch"); break; #endif } @@ -606,7 +612,7 @@ int main(int argc, char *argv[]) break; case 0: - error("-o no longer supported, use -of or -od"); + error(0, "-o no longer supported, use -of or -od"); break; default: @@ -851,11 +857,11 @@ int main(int argc, char *argv[]) else { Lerror: - error("unrecognized switch '%s'", argv[i]); + error(0, "unrecognized switch '%s'", argv[i]); continue; Lnoarg: - error("argument expected for switch '%s'", argv[i]); + error(0, "argument expected for switch '%s'", argv[i]); continue; } } @@ -890,7 +896,7 @@ int main(int argc, char *argv[]) #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"); + error(0, "cannot mix -lib and -shared\n"); #endif if (global.params.release) @@ -952,7 +958,7 @@ int main(int argc, char *argv[]) } else if (global.params.run) { - error("flags conflict with -run"); + error(0, "flags conflict with -run"); fatal(); } else @@ -1058,10 +1064,10 @@ int main(int argc, char *argv[]) #if _WIN32 // Convert / to \ so linker will work - for (size_t i = 0; p[i]; i++) + for (size_t j = 0; p[j]; j++) { - if (p[i] == '/') - p[i] = '\\'; + if (p[j] == '/') + p[j] = '\\'; } #endif @@ -1143,12 +1149,12 @@ int main(int argc, char *argv[]) strcmp(name, ".") == 0) { Linvalid: - error("invalid file name '%s'", files.tdata()[i]); + error(0, "invalid file name '%s'", files.tdata()[i]); fatal(); } } else - { error("unrecognized file extension %s\n", ext); + { error(0, "unrecognized file extension %s\n", ext); fatal(); } } @@ -1172,10 +1178,6 @@ int main(int argc, char *argv[]) } } -#if WINDOWS_SEH - __try - { -#endif // Read files #define ASYNCREAD 1 #if ASYNCREAD @@ -1212,7 +1214,8 @@ int main(int argc, char *argv[]) #if ASYNCREAD if (aw->read(filei)) { - error("cannot read file %s", m->srcfile->name->toChars()); + error(0, "cannot read file %s", m->srcfile->name->toChars()); + fatal(); } #endif m->parse(); @@ -1246,7 +1249,7 @@ int main(int argc, char *argv[]) if (anydocfiles && modules.dim && (global.params.oneobj || global.params.objname)) { - error("conflicting Ddoc and obj generation options"); + error(0, "conflicting Ddoc and obj generation options"); fatal(); } if (global.errors) @@ -1433,14 +1436,6 @@ int main(int argc, char *argv[]) if (global.params.lib && !global.errors) library->write(); -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - printf("Stack overflow\n"); - fatal(); - } -#endif backend_term(); if (global.errors) fatal(); @@ -1448,7 +1443,7 @@ int main(int argc, char *argv[]) if (!global.params.objfiles->dim) { if (global.params.link) - error("no object files to link"); + error(0, "no object files to link"); } else { @@ -1478,6 +1473,25 @@ int main(int argc, char *argv[]) return status; } +int main(int argc, char *argv[]) +{ + int status = -1; +#if WINDOWS_SEH + __try + { +#endif + status = tryMain(argc, argv); +#if WINDOWS_SEH + } + __except (__ehfilter(GetExceptionInformation())) + { + printf("Stack overflow\n"); + fatal(); + } +#endif + return status; +} + #endif // !IN_LLVM /*********************************** diff --git a/dmd2/mars.h b/dmd2/mars.h index dc640308..1263ca4c 100644 --- a/dmd2/mars.h +++ b/dmd2/mars.h @@ -312,6 +312,12 @@ struct Global unsigned gag; // !=0 means gag reporting of errors & warnings unsigned gaggedErrors; // number of errors reported while gagged + /* Gagging can either be speculative (is(typeof()), etc) + * or because of forward references + */ + unsigned speculativeGag; // == gag means gagging is for is(typeof); + bool isSpeculativeGagging(); + // Start gagging. Return the current number of gagged errors unsigned startGagging(); @@ -328,10 +334,12 @@ extern Global global; /* Set if Windows Structured Exception Handling C extensions are supported. * Apparently, VC has dropped support for these? */ -#define WINDOWS_SEH (_WIN32 && __DMC__) +#define WINDOWS_SEH _WIN32 +#include "longdouble.h" #ifdef __DMC__ + #include typedef _Complex long double complex_t; #else #ifndef IN_GCC @@ -362,7 +370,7 @@ typedef uint64_t d_uns64; typedef float d_float32; typedef double d_float64; -typedef long double d_float80; +typedef longdouble d_float80; typedef d_uns8 d_char; typedef d_uns16 d_wchar; @@ -371,7 +379,7 @@ typedef d_uns32 d_dchar; #ifdef IN_GCC #include "d-gcc-real.h" #else -typedef long double real_t; +typedef longdouble real_t; #endif // Modify OutBuffer::writewchar to write the correct size of wchar @@ -470,6 +478,7 @@ void fatal(); void err_nomem(); #if IN_LLVM void inifile(char *argv0, const char *inifile); +void error(const char *format, ...) IS_PRINTF(1); #else int runLINK(); void deleteExeFile(); diff --git a/dmd2/module.c b/dmd2/module.c index c486bfc6..75aa88a8 100644 --- a/dmd2/module.c +++ b/dmd2/module.c @@ -37,7 +37,6 @@ #include "hdrgen.h" #include "lexer.h" -#define MARS 1 #include "html.h" #ifdef IN_GCC @@ -342,7 +341,7 @@ static void check_and_add_output_file(Module* NewMod, const std::string& str) if (i != files.end()) { Module* ThisMod = i->second; - error("Output file '%s' for module '%s' collides with previous module '%s'. See the -oq option", + error(Loc(), "Output file '%s' for module '%s' collides with previous module '%s'. See the -oq option", str.c_str(), NewMod->toPrettyChars(), ThisMod->toPrettyChars()); fatal(); } @@ -507,7 +506,9 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); } - m->read(loc); + if (!m->read(loc)) + return NULL; + m->parse(); #ifdef IN_GCC @@ -517,7 +518,7 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) return m; } -void Module::read(Loc loc) +bool Module::read(Loc loc) { //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars()); if (srcfile->read()) @@ -530,14 +531,16 @@ void Module::read(Loc loc) for (size_t i = 0; i < global.path->dim; i++) { char *p = global.path->tdata()[i]; - fprintf(stdmsg, "import path[%zd] = %s\n", i, p); + fprintf(stdmsg, "import path[%llu] = %s\n", (ulonglong)i, p); } } else fprintf(stdmsg, "Specify path to file '%s' with -I switch\n", srcfile->toChars()); + fatal(); } - fatal(); + return false; } + return true; } inline unsigned readwordLE(unsigned short *p) @@ -1342,19 +1345,23 @@ DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package else { assert(p->isPackage()); -#if TARGET_NET //dot net needs modules and packages with same name -#else - if (p->isModule()) - { p->error("module and package have the same name"); - fatal(); - break; - } -#endif + // It might already be a module, not a package, but that needs + // to be checked at a higher level, where a nice error message + // can be generated. + // dot net needs modules and packages with same name } parent = p; dst = ((Package *)p)->symtab; if (ppkg && !*ppkg) *ppkg = (Package *)p; +#if TARGET_NET +#else + if (p->isModule()) + { // Return the module so that a nice error message can be generated + *ppkg = (Package *)p; + break; + } +#endif } if (pparent) { diff --git a/dmd2/module.h b/dmd2/module.h index 22c8de2e..609017ea 100644 --- a/dmd2/module.h +++ b/dmd2/module.h @@ -138,7 +138,7 @@ struct Module : Package #if !IN_LLVM void setDocfile(); // set docfile member #endif - void read(Loc loc); // read file + bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise. #if IN_LLVM void parse(bool gen_docs = false); // syntactic parse #elif IN_GCC diff --git a/dmd2/mtype.c b/dmd2/mtype.c index c08c650b..7502dc17 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -87,6 +87,10 @@ int REALALIGNSIZE = 16; int REALSIZE = 12; int REALPAD = 2; int REALALIGNSIZE = 4; +#elif IN_GCC +int REALSIZE = 0; +int REALPAD = 0; +int REALALIGNSIZE = 0; #else int REALSIZE = 10; int REALPAD = 0; @@ -279,7 +283,7 @@ void Type::init() for (size_t i = 0; i < TMAX; i++) { if (!mangleChar[i]) - fprintf(stdmsg, "ty = %zd\n", i); + fprintf(stdmsg, "ty = %llu\n", (ulonglong)i); assert(mangleChar[i]); } @@ -461,6 +465,8 @@ Type *Type::mutableOf() t = t->merge(); t->fixTo(this); } + else + t = t->merge(); assert(t->isMutable()); return t; } @@ -552,6 +558,8 @@ Type *Type::unSharedOf() t->fixTo(this); } + else + t = t->merge(); assert(!t->isShared()); return t; } @@ -1342,7 +1350,19 @@ Type *Type::aliasthisOf() Expression *ethis = this->defaultInit(0); fd = fd->overloadResolve(0, ethis, NULL); if (fd) + { TypeFunction *tf = (TypeFunction *)fd->type; + if (!tf->next && fd->inferRetType) + { + TemplateInstance *spec = fd->isSpeculative(); + int olderrs = global.errors; + fd->semantic3(fd->scope); + // Update the template instantiation with the number + // of errors which occured. + if (spec && global.errors != olderrs) + spec->errors = global.errors - olderrs; + } t = ((TypeFunction *)fd->type)->next; + } } return t; } @@ -1352,6 +1372,32 @@ Type *Type::aliasthisOf() Type *t = ed->type; return t; } + TemplateDeclaration *td = ad->aliasthis->isTemplateDeclaration(); + if (td) + { assert(td->scope); + Expression *ethis = defaultInit(0); + FuncDeclaration *fd = td->deduceFunctionTemplate(td->scope, 0, NULL, ethis, NULL, 1); + if (fd) + { + //if (!fd->type->nextOf() && fd->inferRetType) + { + TemplateInstance *spec = fd->isSpeculative(); + int olderrs = global.errors; + fd->semantic3(fd->scope); + // Update the template instantiation with the number + // of errors which occured. + if (spec && global.errors != olderrs) + spec->errors = global.errors - olderrs; + } + if (!global.errors) + { + Type *t = fd->type->nextOf(); + t = t->substWildTo(mod == 0 ? MODmutable : mod); + return t; + } + } + return Type::terror; + } //printf("%s\n", ad->aliasthis->kind()); } return NULL; @@ -1642,6 +1688,8 @@ Type *Type::merge() if (ty == Ttypeof) return this; if (ty == Tident) return this; if (ty == Tinstance) return this; + if (ty == Taarray && !((TypeAArray *)this)->index->merge()->deco) + return this; if (nextOf() && !nextOf()->merge()->deco) return this; @@ -1918,12 +1966,12 @@ Type *Type::substWildTo(unsigned mod) else if (ty == Taarray) { t = new TypeAArray(t, ((TypeAArray *)this)->index->syntaxCopy()); - t = t->merge(); + ((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc; // duplicate scope } else assert(0); - t = t->addMod(this->mod); + t = t->merge(); } } else @@ -2060,35 +2108,6 @@ Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident) } else if (ident == Id::init) { -#if 0 - if (v->init) - { - if (v->init->isVoidInitializer()) - error(e->loc, "%s.init is void", v->toChars()); - else - { Loc loc = e->loc; - e = v->init->toExpression(); - if (e->op == TOKassign || e->op == TOKconstruct || e->op == TOKblit) - { - e = ((AssignExp *)e)->e2; - - /* Take care of case where we used a 0 - * to initialize the struct. - */ - if (e->type == Type::tint32 && - e->isBool(0) && - v->type->toBasetype()->ty == Tstruct) - { - e = v->type->defaultInit(e->loc); - } - } - e = e->optimize(WANTvalue | WANTinterpret); -// if (!e->isConst()) -// error(loc, ".init cannot be evaluated at compile time"); - } - goto Lreturn; - } -#endif e = defaultInitLiteral(e->loc); goto Lreturn; } @@ -2164,7 +2183,6 @@ 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; } @@ -2175,7 +2193,7 @@ Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident) { /* Rewrite e.ident as: * e.aliasthis.ident */ - e = new DotIdExp(e->loc, e, sym->aliasthis->ident); + e = resolveAliasThis(sc, e); e = new DotIdExp(e->loc, e, ident); return e->semantic(sc); } @@ -2254,11 +2272,15 @@ void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) } /******************************* - * If one of the subtypes of this type is a TypeIdentifier, - * i.e. it's an unresolved type, return that type. + * tparams == NULL: + * If one of the subtypes of this type is a TypeIdentifier, + * i.e. it's an unresolved type, return that type. + * tparams != NULL: + * Only when the TypeIdentifier is one of template parameters, + * return that type. */ -Type *Type::reliesOnTident() +Type *Type::reliesOnTident(TemplateParameters *tparams) { return NULL; } @@ -2378,9 +2400,9 @@ void TypeNext::checkDeprecated(Loc loc, Scope *sc) } -Type *TypeNext::reliesOnTident() +Type *TypeNext::reliesOnTident(TemplateParameters *tparams) { - return next->reliesOnTident(); + return next->reliesOnTident(tparams); } int TypeNext::hasWild() @@ -2547,9 +2569,7 @@ Type *TypeNext::makeMutable() { //printf("TypeNext::makeMutable() %p, %s\n", this, toChars()); TypeNext *t = (TypeNext *)Type::makeMutable(); - if ((ty != Tfunction && next->ty != Tfunction && - //(next->deco || next->ty == Tfunction) && - next->isWild()) || ty == Tsarray) + if (ty == Tsarray) { t->next = next->mutableOf(); } @@ -3124,7 +3144,7 @@ Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident) case Timaginary64: t = tfloat64; goto L2; case Timaginary80: t = tfloat80; goto L2; L2: - e = new RealExp(0, 0.0, t); + e = new RealExp(e->loc, ldouble(0.0), t); break; default: @@ -3156,7 +3176,7 @@ Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident) case Tfloat32: case Tfloat64: case Tfloat80: - e = new RealExp(0, 0.0, this); + e = new RealExp(e->loc, ldouble(0.0), this); break; default: @@ -3183,7 +3203,7 @@ Expression *TypeBasic::defaultInit(Loc loc) */ union { unsigned short us[8]; - long double ld; + longdouble ld; } snan = {{ 0, 0, 0, 0xA000, 0x7FFF }}; /* * Although long doubles are 10 bytes long, some @@ -3411,11 +3431,25 @@ Type *TypeVector::semantic(Loc loc, Scope *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()); + if (basetype->ty != Tsarray) + { error(loc, "T in __vector(T) must be a static array, not %s", basetype->toChars()); return terror; } TypeSArray *t = (TypeSArray *)basetype; + + if (sc && sc->parameterSpecialization && t->dim->op == TOKvar && + ((VarExp *)t->dim)->var->storage_class & STCtemplateparameter) + { + /* It could be a template parameter N which has no value yet: + * template Foo(T : __vector(T[N]), size_t N); + */ + return this; + } + + if (t->size(loc) != 16) + { error(loc, "base type of __vector must be a 16 byte static array, not %s", t->toChars()); + return terror; + } 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()); @@ -3757,7 +3791,7 @@ d_uns64 TypeSArray::size(Loc loc) return sz; Loverflow: - error(loc, "index %jd overflow for static array", sz); + error(loc, "index %lld overflow for static array", sz); return 1; } @@ -3805,7 +3839,10 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt); if (*pe) { // It's really an index expression - Expression *e = new IndexExp(loc, *pe, dim); + Expressions *exps = new Expressions(); + exps->setDim(1); + (*exps)[0] = dim; + Expression *e = new ArrayExp(loc, *pe, exps); *pe = e; } else if (*ps) @@ -3824,7 +3861,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol sc = sc->pop(); if (d >= td->objects->dim) - { error(loc, "tuple index %ju exceeds length %u", d, td->objects->dim); + { error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim); goto Ldefault; } Object *o = td->objects->tdata()[(size_t)d]; @@ -3884,7 +3921,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) uinteger_t d = dim->toUInteger(); if (d >= sd->objects->dim) - { error(loc, "tuple index %ju exceeds %u", d, sd->objects->dim); + { error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim); return Type::terror; } Object *o = sd->objects->tdata()[(size_t)d]; @@ -3951,7 +3988,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) if (n && n2 / n != d2) { Loverflow: - error(loc, "index %jd overflow for static array", d1); + error(loc, "index %lld overflow for static array", d1); goto Lerror; } } @@ -3965,7 +4002,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) uinteger_t d = dim->toUInteger(); if (d >= tt->arguments->dim) - { error(loc, "tuple index %ju exceeds %u", d, tt->arguments->dim); + { error(loc, "tuple index %llu exceeds %u", d, tt->arguments->dim); goto Lerror; } Parameter *arg = tt->arguments->tdata()[(size_t)d]; @@ -4006,7 +4043,7 @@ void TypeSArray::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) { Type::toDecoBuffer(buf, flag, mangle); if (dim) - buf->printf("%ju", dim->toInteger()); + buf->printf("%llu", dim->toInteger()); if (next) /* Note that static arrays are value types, so * for a parameter, propagate the 0x100 to the next @@ -4258,6 +4295,31 @@ Type *TypeDArray::semantic(Loc loc, Scope *sc) return merge(); } +void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +{ + //printf("TypeDArray::resolve() %s\n", toChars()); + next->resolve(loc, sc, pe, pt, ps); + //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt); + if (*pe) + { // It's really a slice expression + Expression *e = new SliceExp(loc, *pe, NULL, NULL); + *pe = e; + } + else if (*ps) + { + TupleDeclaration *td = (*ps)->isTupleDeclaration(); + if (td) + ; // keep *ps + else + goto Ldefault; + } + else + { + Ldefault: + Type::resolve(loc, sc, pe, pt, ps); + } +} + void TypeDArray::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) { Type::toDecoBuffer(buf, flag, mangle); @@ -4529,8 +4591,8 @@ StructDeclaration *TypeAArray::getImpl() * which has Tident's instead of real types. */ Objects *tiargs = new Objects(); - tiargs->push(index); - tiargs->push(next); + tiargs->push(index->substWildTo(MODconst)); // hack for bug7757 + tiargs->push(next ->substWildTo(MODconst)); // hack for bug7757 // Create AssociativeArray!(index, next) #if 1 @@ -4698,8 +4760,12 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) ident != Id::stringof && ident != Id::offsetof) { - e->type = getImpl()->type; - e = e->type->dotExp(sc, e, ident); +//printf("test1: %s, %s\n", e->toChars(), e->type->toChars()); + Type *t = getImpl()->type; +//printf("test2: %s, %s\n", e->toChars(), e->type->toChars()); + e->type = t; + e = t->dotExp(sc, e, ident); +//printf("test3: %s, %s\n", e->toChars(), e->type->toChars()); } else e = Type::dotExp(sc, e, ident); @@ -4743,6 +4809,22 @@ int TypeAArray::checkBoolean() return TRUE; } +Expression *TypeAArray::toExpression() +{ + Expression *e = next->toExpression(); + if (e) + { + Expression *ei = index->toExpression(); + if (ei) + { + Expressions *arguments = new Expressions(); + arguments->push(ei); + return new ArrayExp(loc, e, arguments); + } + } + return NULL; +} + int TypeAArray::hasPointers() { return TRUE; @@ -4774,11 +4856,7 @@ MATCH TypeAArray::implicitConvTo(Type *to) MATCH mi = index->constConv(ta->index); if (m != MATCHnomatch && mi != MATCHnomatch) { - if (m == MATCHexact && mod != to->mod) - m = MATCHconst; - if (mi < m) - m = mi; - return m; + return MODimplicitConv(mod, to->mod) ? MATCHconst : MATCHnomatch; } } else if (to->ty == Tstruct && ((TypeStruct *)to)->sym->ident == Id::AssociativeArray) @@ -4844,7 +4922,8 @@ Type *TypePointer::semantic(Loc loc, Scope *sc) deco = NULL; } next = n; - transitive(); + if (next->ty != Tfunction) + transitive(); return merge(); } @@ -5049,6 +5128,7 @@ TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, e this->purity = PUREimpure; this->isproperty = false; this->isref = false; + this->iswild = false; this->fargs = NULL; #if IN_LLVM @@ -5097,9 +5177,10 @@ Type *TypeFunction::syntaxCopy() * 2 arguments match as far as overloading goes, * but types are not covariant * 3 cannot determine covariance because of forward references + * *pstc STCxxxx which would make it covariant */ -int Type::covariant(Type *t) +int Type::covariant(Type *t, StorageClass *pstc) { #if 0 printf("Type::covariant(t = %s) %s\n", t->toChars(), toChars()); @@ -5108,6 +5189,10 @@ int Type::covariant(Type *t) printf("mod = %x, %x\n", mod, t->mod); #endif + if (pstc) + *pstc = 0; + StorageClass stc = 0; + int inoutmismatch = 0; TypeFunction *t1; @@ -5211,35 +5296,39 @@ int Type::covariant(Type *t) goto Lnotcovariant; Lcovariant: + if (t1->isref != t2->isref) + goto Lnotcovariant; + /* Can convert mutable to const */ if (!MODimplicitConv(t2->mod, t1->mod)) - goto Lnotcovariant; -#if 0 - if (t1->mod != t2->mod) { - if (!(t1->mod & MODconst) && (t2->mod & MODconst)) - goto Lnotcovariant; - if (!(t1->mod & MODshared) && (t2->mod & MODshared)) + // If adding 'const' will make it covariant + if (MODimplicitConv(t2->mod, MODmerge(t1->mod, MODconst))) + stc |= STCconst; + else goto Lnotcovariant; } -#endif /* Can convert pure to impure, and nothrow to throw */ if (!t1->purity && t2->purity) - goto Lnotcovariant; + stc |= STCpure; if (!t1->isnothrow && t2->isnothrow) - goto Lnotcovariant; - - if (t1->isref != t2->isref) - goto Lnotcovariant; + stc |= STCnothrow; /* Can convert safe/trusted to system */ if (t1->trust <= TRUSTsystem && t2->trust >= TRUSTtrusted) + // Should we infer trusted or safe? Go with safe. + stc |= STCsafe; + + if (stc) + { if (pstc) + *pstc = stc; goto Lnotcovariant; + } //printf("\tcovaraint: 1\n"); return 1; @@ -5551,10 +5640,14 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) tf->isnothrow = TRUE; if (sc->stc & STCref) tf->isref = TRUE; + if (sc->stc & STCsafe) tf->trust = TRUSTsafe; + if (sc->stc & STCsystem) + tf->trust = TRUSTsystem; if (sc->stc & STCtrusted) tf->trust = TRUSTtrusted; + if (sc->stc & STCproperty) tf->isproperty = TRUE; @@ -5562,13 +5655,15 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) /* If the parent is @safe, then this function defaults to safe * too. + * If the parent's @safe-ty is inferred, then this function's @safe-ty needs + * to be inferred first. */ if (tf->trust == TRUSTdefault) for (Dsymbol *p = sc->func; p; p = p->toParent2()) { FuncDeclaration *fd = p->isFuncDeclaration(); if (fd) { - if (fd->isSafe()) + if (fd->isSafeBypassingInference()) tf->trust = TRUSTsafe; // default to @safe break; } @@ -5605,7 +5700,6 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) } bool wildparams = FALSE; - bool wildsubparams = FALSE; if (tf->parameters) { /* Create a scope for evaluating the default arguments for the parameters @@ -5647,17 +5741,38 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) !(t->ty == Tpointer && t->nextOf()->ty == Tfunction || t->ty == Tdelegate)) { wildparams = TRUE; - if (tf->next && !wildreturn) - error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')"); + //if (tf->next && !wildreturn) + // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')"); } - else if (!wildsubparams && t->hasWild()) - wildsubparams = TRUE; if (fparam->defaultArg) - { - fparam->defaultArg = fparam->defaultArg->semantic(argsc); - fparam->defaultArg = resolveProperties(argsc, fparam->defaultArg); - fparam->defaultArg = fparam->defaultArg->implicitCastTo(argsc, fparam->type); + { Expression *e = fparam->defaultArg; + e = e->inferType(fparam->type); + e = e->semantic(argsc); + e = resolveProperties(argsc, e); + if (e->op == TOKfunction) // see Bugzilla 4820 + { FuncExp *fe = (FuncExp *)e; + if (fe->fd) + { if (fe->fd->tok == TOKreserved) + { + if (fe->type->ty == Tpointer) + { + fe->fd->vthis = NULL; + fe->fd->tok = TOKfunction; + } + else + fe->fd->tok = TOKdelegate; + } + // Replace function literal with a function symbol, + // since default arg expression must be copied when used + // and copying the literal itself is wrong. + e = new VarExp(e->loc, fe->fd, 0); + e = new AddrExp(e->loc, e); + e = e->semantic(argsc); + } + } + e = e->implicitCastTo(argsc, fparam->type); + fparam->defaultArg = e; } /* If fparam after semantic() turns out to be a tuple, the number of parameters may @@ -5718,8 +5833,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) if (wildreturn && !wildparams) error(loc, "inout on return means inout must be on a parameter as well for %s", toChars()); - if (wildsubparams && wildparams) - error(loc, "inout must be all or none on top level for %s", toChars()); + tf->iswild = wildparams; if (tf->next) tf->deco = tf->merge()->deco; @@ -5730,8 +5844,8 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) return terror; } - if (tf->isproperty && (tf->varargs || Parameter::dim(tf->parameters) > 1)) - error(loc, "properties can only have zero or one parameter"); + if (tf->isproperty && (tf->varargs || Parameter::dim(tf->parameters) > 2)) + error(loc, "properties can only have zero, one, or two parameter"); if (tf->varargs == 1 && tf->linkage != LINKd && Parameter::dim(tf->parameters) == 0) error(loc, "variadic functions with non-D linkage must have at least one parameter"); @@ -5924,9 +6038,8 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) assert(arg); if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - Type *pt = p->type; - arg = ((FuncExp *)arg)->inferType(NULL, pt); + { + arg = ((FuncExp *)arg)->inferType(p->type, 1); if (!arg) goto L1; // try typesafe variadics } @@ -6013,9 +6126,8 @@ int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) assert(arg); #if 1 if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - Type *pt = tb->nextOf(); - arg = ((FuncExp *)arg)->inferType(NULL, pt); + { + arg = ((FuncExp *)arg)->inferType(tb->nextOf(), 1); if (!arg) goto Nomatch; } @@ -6075,16 +6187,16 @@ Nomatch: return MATCHnomatch; } -Type *TypeFunction::reliesOnTident() +Type *TypeFunction::reliesOnTident(TemplateParameters *tparams) { size_t dim = Parameter::dim(parameters); for (size_t i = 0; i < dim; i++) { Parameter *fparam = Parameter::getNth(parameters, i); - Type *t = fparam->type->reliesOnTident(); + Type *t = fparam->type->reliesOnTident(tparams); if (t) return t; } - return next ? next->reliesOnTident() : NULL; + return next ? next->reliesOnTident(tparams) : NULL; } /******************************************** @@ -6142,6 +6254,40 @@ Expression *TypeFunction::defaultInit(Loc loc) return new ErrorExp(); } +Type *TypeFunction::addStorageClass(StorageClass stc) +{ + TypeFunction *t = (TypeFunction *)Type::addStorageClass(stc); + if ((stc & STCpure && !t->purity) || + (stc & STCnothrow && !t->isnothrow) || + (stc & STCsafe && t->trust < TRUSTtrusted)) + { + // Klunky to change these + TypeFunction *tf = new TypeFunction(t->parameters, t->next, t->varargs, t->linkage, 0); + tf->mod = t->mod; + tf->fargs = fargs; + tf->purity = t->purity; + tf->isnothrow = t->isnothrow; + tf->isproperty = t->isproperty; + tf->isref = t->isref; + tf->trust = t->trust; + + if (stc & STCpure) + tf->purity = PUREfwdref; + if (stc & STCnothrow) + tf->isnothrow = true; + if (stc & STCsafe) + tf->trust = TRUSTsafe; + +#if IN_LLVM + tf->funcdecl = t->funcdecl; +#endif + + tf->deco = tf->merge()->deco; + t = tf; + } + return t; +} + /***************************** TypeDelegate *****************************/ TypeDelegate::TypeDelegate(Type *t) @@ -6429,7 +6575,19 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, else { Lerror: - error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); + if (id->dyncast() == DYNCAST_DSYMBOL) + { // searchX already handles errors for template instances + assert(global.errors); + } + else + { + sm = s->search_correct(id); + if (sm) + error(loc, "identifier '%s' of '%s' is not defined, did you mean '%s %s'?", + id->toChars(), toChars(), sm->kind(), sm->toChars()); + else + error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); + } *pe = new ErrorExp(); } return; @@ -6666,10 +6824,6 @@ Type *TypeIdentifier::semantic(Loc loc, Scope *sc) } else { -#ifdef DEBUG - if (!global.gag) - printf("1: "); -#endif if (s) { s->error(loc, "is used as a type"); @@ -6683,9 +6837,23 @@ Type *TypeIdentifier::semantic(Loc loc, Scope *sc) return t; } -Type *TypeIdentifier::reliesOnTident() +Type *TypeIdentifier::reliesOnTident(TemplateParameters *tparams) { - return this; + if (tparams) + { + if (idents.dim == 0) + { + for (size_t i = 0; i < tparams->dim; i++) + { TemplateParameter *tp = tparams->tdata()[i]; + + if (tp->ident->equals(ident)) + return this; + } + } + return NULL; + } + else + return this; } Expression *TypeIdentifier::toExpression() @@ -6766,12 +6934,11 @@ Type *TypeInstance::semantic(Loc loc, Scope *sc) Expression *e; Dsymbol *s; - //printf("TypeInstance::semantic(%s)\n", toChars()); + //printf("TypeInstance::semantic(%p, %s)\n", this, toChars()); if (sc->parameterSpecialization) { unsigned errors = global.startGagging(); - resolve(loc, sc, &e, &t, &s); if (global.endGagging(errors)) @@ -6920,9 +7087,15 @@ Type *TypeTypeof::semantic(Loc loc, Scope *sc) { Scope *sc2 = sc->push(); sc2->intypeof++; + sc2->speculative = true; sc2->ignoreTemplates++; sc2->flags |= sc->flags & SCOPEstaticif; + unsigned oldspecgag = global.speculativeGag; + if (global.gag) + global.speculativeGag = global.gag; exp = exp->semantic(sc2); + global.speculativeGag = oldspecgag; + #if DMDV2 if (exp->type && exp->type->ty == Tfunction && ((TypeFunction *)exp->type)->isproperty) @@ -7113,9 +7286,6 @@ unsigned TypeEnum::alignsize() { if (!sym->memtype) { -#ifdef DEBUG - printf("1: "); -#endif error(0, "enum %s is forward referenced", sym->toChars()); return 4; } @@ -7142,9 +7312,6 @@ Type *TypeEnum::toBasetype() } if (!sym->memtype) { -#ifdef DEBUG - printf("2: "); -#endif error(sym->loc, "enum %s is forward referenced", sym->toChars()); return tint32; } @@ -7329,9 +7496,6 @@ int TypeEnum::isZeroInit(Loc loc) } if (!sym->defaultval) { -#ifdef DEBUG - printf("3: "); -#endif error(loc, "enum %s is forward referenced", sym->toChars()); return 0; } @@ -7939,10 +8103,19 @@ Expression *TypeStruct::defaultInitLiteral(Loc loc) e = vd->init->toExpression(); } else - e = vd->type->defaultInitLiteral(); - structelems->tdata()[j] = e; + e = vd->type->defaultInitLiteral(loc); + (*structelems)[j] = e; } StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems); + +#if IN_DMD + /* Copy from the initializer symbol for larger symbols, + * otherwise the literals expressed as code get excessively large. + */ + if (size(loc) > PTRSIZE * 4) + structinit->sinit = sym->toInitializer(); +#endif + // Why doesn't the StructLiteralExp constructor do this, when // sym->type != NULL ? structinit->type = sym->type; @@ -8020,7 +8193,7 @@ MATCH TypeStruct::implicitConvTo(Type *to) { MATCH m; //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to->toChars()); - if (to->ty == Taarray) + if (to->ty == Taarray && sym->ident == Id::AssociativeArray) { /* If there is an error instantiating AssociativeArray!(), it shouldn't * be reported -- it just means implicit conversion is impossible. @@ -8525,7 +8698,7 @@ L1: return e; } - DotVarExp *de = new DotVarExp(e->loc, e, d); + DotVarExp *de = new DotVarExp(e->loc, e, d, d->hasOverloads()); return de->semantic(sc); } @@ -8761,14 +8934,14 @@ int TypeTuple::equals(Object *o) return 0; } -Type *TypeTuple::reliesOnTident() +Type *TypeTuple::reliesOnTident(TemplateParameters *tparams) { if (arguments) { for (size_t i = 0; i < arguments->dim; i++) { Parameter *arg = arguments->tdata()[i]; - Type *t = arg->type->reliesOnTident(); + Type *t = arg->type->reliesOnTident(tparams); if (t) return t; } @@ -8819,6 +8992,10 @@ Expression *TypeTuple::getProperty(Loc loc, Identifier *ident) { e = new IntegerExp(loc, arguments->dim, Type::tsize_t); } + else if (ident == Id::init) + { + e = defaultInitLiteral(loc); + } else { error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars()); @@ -8827,6 +9004,22 @@ Expression *TypeTuple::getProperty(Loc loc, Identifier *ident) return e; } +Expression *TypeTuple::defaultInit(Loc loc) +{ + Expressions *exps = new Expressions(); + exps->setDim(arguments->dim); + for (size_t i = 0; i < arguments->dim; i++) + { + Parameter *p = (*arguments)[i]; + assert(p->type); + Expression *e = p->type->defaultInitLiteral(loc); + if (e->op == TOKerror) + return e; + (*exps)[i] = e; + } + return new TupleExp(loc, exps); +} + /***************************** TypeSlice *****************************/ /* This is so we can slice a TypeTuple */ @@ -8869,7 +9062,7 @@ Type *TypeSlice::semantic(Loc loc, Scope *sc) uinteger_t i2 = upr->toUInteger(); if (!(i1 <= i2 && i2 <= tt->arguments->dim)) - { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, tt->arguments->dim); + { error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, tt->arguments->dim); return Type::terror; } @@ -8915,7 +9108,7 @@ void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol sc = sc->pop(); if (!(i1 <= i2 && i2 <= td->objects->dim)) - { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, td->objects->dim); + { error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, td->objects->dim); goto Ldefault; } diff --git a/dmd2/mtype.h b/dmd2/mtype.h index 00536496..8a2b1a76 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.h @@ -237,7 +237,7 @@ struct Type : Object virtual Type *syntaxCopy(); int equals(Object *o); int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType() - int covariant(Type *t); + int covariant(Type *t, StorageClass *pstc = NULL); char *toChars(); static char needThisPrefix(); #if IN_LLVM @@ -294,7 +294,7 @@ struct Type : Object Type *addSTC(StorageClass stc); Type *castMod(unsigned mod); Type *addMod(unsigned mod); - Type *addStorageClass(StorageClass stc); + virtual Type *addStorageClass(StorageClass stc); Type *pointerTo(); Type *referenceTo(); Type *arrayOf(); @@ -320,7 +320,8 @@ struct Type : Object Expression *noMember(Scope *sc, Expression *e, Identifier *ident); virtual unsigned memalign(unsigned salign); virtual Expression *defaultInit(Loc loc = 0); - virtual Expression *defaultInitLiteral(Loc loc = 0); + virtual Expression *defaultInitLiteral(Loc loc); + virtual Expression *voidInitLiteral(VarDeclaration *var); virtual int isZeroInit(Loc loc = 0); // if initializer is 0 #if IN_DMD virtual dt_t **toDt(dt_t **pdt); @@ -332,7 +333,7 @@ struct Type : Object Expression *getTypeInfo(Scope *sc); virtual TypeInfoDeclaration *getTypeInfoDeclaration(); virtual int builtinTypeInfo(); - virtual Type *reliesOnTident(); + virtual Type *reliesOnTident(TemplateParameters *tparams = NULL); virtual int hasWild(); virtual Expression *toExpression(); virtual int hasPointers(); @@ -383,7 +384,7 @@ struct TypeNext : Type TypeNext(TY ty, Type *next); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void checkDeprecated(Loc loc, Scope *sc); - Type *reliesOnTident(); + Type *reliesOnTident(TemplateParameters *tparams = NULL); int hasWild(); Type *nextOf(); Type *makeConst(); @@ -448,6 +449,7 @@ struct TypeVector : Type char *toChars(); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); #if CPP_MANGLE void toCppMangle(OutBuffer *buf, CppMangleState *cms); #endif @@ -491,6 +493,7 @@ struct TypeSArray : TypeArray MATCH implicitConvTo(Type *to); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); + Expression *voidInitLiteral(VarDeclaration *var); #if IN_DMD dt_t **toDt(dt_t **pdt); dt_t **toDtElem(dt_t **pdt, Expression *e); @@ -519,6 +522,7 @@ struct TypeDArray : TypeArray d_uns64 size(Loc loc); unsigned alignsize(); Type *semantic(Loc loc, Scope *sc); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); @@ -563,6 +567,7 @@ struct TypeAArray : TypeArray int isZeroInit(Loc loc); int checkBoolean(); TypeInfoDeclaration *getTypeInfoDeclaration(); + Expression *toExpression(); int hasPointers(); TypeTuple *toArgTypes(); MATCH implicitConvTo(Type *to); @@ -656,6 +661,7 @@ struct TypeFunction : TypeNext enum LINK linkage; // calling convention enum TRUST trust; // level of trust enum PURE purity; // PURExxxx + bool iswild; // is inout function Expressions *fargs; // function arguments int inuse; @@ -671,12 +677,13 @@ struct TypeFunction : TypeNext void attributesToCBuffer(OutBuffer *buf, int mod); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); TypeInfoDeclaration *getTypeInfoDeclaration(); - Type *reliesOnTident(); + Type *reliesOnTident(TemplateParameters *tparams = NULL); bool hasLazyParameters(); #if CPP_MANGLE void toCppMangle(OutBuffer *buf, CppMangleState *cms); #endif bool parameterEscapes(Parameter *p); + Type *addStorageClass(StorageClass stc); int callMatch(Expression *ethis, Expressions *toargs, int flag = 0); #if IN_DMD @@ -753,7 +760,7 @@ struct TypeIdentifier : TypeQualified Dsymbol *toDsymbol(Scope *sc); Type *semantic(Loc loc, Scope *sc); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - Type *reliesOnTident(); + Type *reliesOnTident(TemplateParameters *tparams = NULL); Expression *toExpression(); }; @@ -813,6 +820,7 @@ struct TypeStruct : Type unsigned memalign(unsigned salign); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); + Expression *voidInitLiteral(VarDeclaration *var); int isZeroInit(Loc loc); int isAssignable(); int checkBoolean(); @@ -986,10 +994,11 @@ struct TypeTuple : Type Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); int equals(Object *o); - Type *reliesOnTident(); + Type *reliesOnTident(TemplateParameters *tparams = NULL); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); Expression *getProperty(Loc loc, Identifier *ident); + Expression *defaultInit(Loc loc); TypeInfoDeclaration *getTypeInfoDeclaration(); }; @@ -1054,6 +1063,7 @@ struct Parameter : Object extern int PTRSIZE; extern int REALSIZE; extern int REALPAD; +extern int REALALIGNSIZE; extern int Tsize_t; extern int Tptrdiff_t; diff --git a/dmd2/opover.c b/dmd2/opover.c index 27e2c7d1..bcf1828c 100644 --- a/dmd2/opover.c +++ b/dmd2/opover.c @@ -355,11 +355,9 @@ Expression *UnaExp::op_overload(Scope *sc) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; + UnaExp *e = (UnaExp *)syntaxCopy(); + e->e1 = new DotIdExp(loc, e->e1, ad->aliasthis->ident); + return e->trySemantic(sc); } #endif } @@ -414,11 +412,9 @@ Expression *ArrayExp::op_overload(Scope *sc) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; + UnaExp *e = (UnaExp *)syntaxCopy(); + e->e1 = new DotIdExp(loc, e->e1, ad->aliasthis->ident); + return e->trySemantic(sc); } } return NULL; @@ -461,11 +457,9 @@ Expression *CastExp::op_overload(Scope *sc) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; + UnaExp *e = (UnaExp *)syntaxCopy(); + e->e1 = new DotIdExp(loc, e->e1, ad->aliasthis->ident); + return e->trySemantic(sc); } } return NULL; @@ -721,11 +715,9 @@ L1: /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; + BinExp *e = (BinExp *)syntaxCopy(); + e->e1 = new DotIdExp(loc, e->e1, ad1->aliasthis->ident); + return e->trySemantic(sc); } // Try alias this on second operand @@ -738,11 +730,9 @@ L1: /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e2 = e2; - e = e->trySemantic(sc); - return e; + BinExp *e = (BinExp *)syntaxCopy(); + e->e2 = new DotIdExp(loc, e->e2, ad2->aliasthis->ident); + return e->trySemantic(sc); } #endif return NULL; @@ -894,11 +884,9 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; + BinExp *e = (BinExp *)syntaxCopy(); + e->e1 = new DotIdExp(loc, e->e1, ad1->aliasthis->ident); + return e->trySemantic(sc); } // Try alias this on second operand @@ -907,11 +895,9 @@ Expression *BinExp::compare_overload(Scope *sc, Identifier *id) /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e2 = e2; - e = e->trySemantic(sc); - return e; + BinExp *e = (BinExp *)syntaxCopy(); + e->e2 = new DotIdExp(loc, e->e2, ad2->aliasthis->ident); + return e->trySemantic(sc); } return NULL; @@ -1056,6 +1042,10 @@ Expression *BinAssignExp::op_overload(Scope *sc) e1 = resolveProperties(sc, e1); e2 = resolveProperties(sc, e2); + // Don't attempt 'alias this' if an error occured + if (e1->type->ty == Terror || e2->type->ty == Terror) + return new ErrorExp(); + Identifier *id = opId(); Expressions args2; @@ -1142,11 +1132,9 @@ L1: /* Rewrite (e1 op e2) as: * (e1.aliasthis op e2) */ - Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; + BinExp *e = (BinExp *)syntaxCopy(); + e->e1 = new DotIdExp(loc, e->e1, ad1->aliasthis->ident); + return e->trySemantic(sc); } // Try alias this on second operand @@ -1156,11 +1144,9 @@ L1: /* Rewrite (e1 op e2) as: * (e1 op e2.aliasthis) */ - Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e2 = e2; - e = e->trySemantic(sc); - return e; + BinExp *e = (BinExp *)syntaxCopy(); + e->e2 = new DotIdExp(loc, e->e2, ad2->aliasthis->ident); + return e->trySemantic(sc); } #endif return NULL; diff --git a/dmd2/optimize.c b/dmd2/optimize.c index 82bfe9c1..f007751c 100644 --- a/dmd2/optimize.c +++ b/dmd2/optimize.c @@ -406,7 +406,7 @@ Expression *AddrExp::optimize(int result) TypeSArray *ts = (TypeSArray *)ve->type; dinteger_t dim = ts->dim->toInteger(); if (index < 0 || index >= dim) - error("array index %jd is out of bounds [0..%jd]", index, dim); + error("array index %lld is out of bounds [0..%lld]", index, dim); e = new SymOffExp(loc, ve->var, index * ts->nextOf()->size()); e->type = type; return e; @@ -670,7 +670,7 @@ Expression *CastExp::optimize(int result) } // We can convert 'head const' to mutable - if (to->constOf()->equals(e1->type->constOf())) + if (to->mutableOf()->constOf()->equals(e1->type->mutableOf()->constOf())) { e1->type = type; if (X) printf(" returning5 %s\n", e1->toChars()); @@ -716,7 +716,7 @@ 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 - 1); + { error("shift assign by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1); e2 = new IntegerExp(0); } } @@ -811,7 +811,7 @@ 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 - 1); + { e->error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1); e->e2 = new IntegerExp(0); } if (e->e1->isConst() == 1) @@ -900,7 +900,7 @@ Expression *PowExp::optimize(int result) if (e1->type->isintegral()) e = new IntegerExp(loc, 1, e1->type); else - e = new RealExp(loc, 1.0, e1->type); + e = new RealExp(loc, ldouble(1.0), e1->type); e = new CommaExp(loc, e1, e); } @@ -913,7 +913,7 @@ Expression *PowExp::optimize(int result) // Replace x ^^ -1.0 by (1.0 / x) else if ((e2->op == TOKfloat64 && e2->toReal() == -1.0)) { - e = new DivExp(loc, new RealExp(loc, 1.0, e2->type), e1); + e = new DivExp(loc, new RealExp(loc, ldouble(1.0), e2->type), e1); } // All other negative integral powers are illegal else if ((e1->type->isintegral()) && (e2->op == TOKint64) && (sinteger_t)e2->toInteger() < 0) diff --git a/dmd2/parse.c b/dmd2/parse.c index 17ae1df5..6119ec54 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -130,7 +130,7 @@ Dsymbols *Parser::parseModule() decldefs = parseDeclDefs(0); if (token.value != TOKeof) - { error("unrecognized declaration"); + { error(loc, "unrecognized declaration"); goto Lerr; } return decldefs; @@ -1380,8 +1380,15 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) error("scope cannot be ref or out"); Token *t; +#if 0 if (tpl && !stc && token.value == TOKidentifier && (t = peek(&token), (t->value == TOKcomma || t->value == TOKrparen))) +#else + if (tpl && token.value == TOKidentifier && + (t = peek(&token), (t->value == TOKcomma || + t->value == TOKrparen || + t->value == TOKdotdotdot))) +#endif { Identifier *id = Lexer::uniqueId("__T"); at = new TypeIdentifier(loc, id); if (!*tpl) @@ -3564,6 +3571,9 @@ Statement *Parser::parseStatement(int flags) goto Ldeclaration; case BASIC_TYPES: + // bug 7773: int.max is always a part of expression + if (peekNext() == TOKdot) + goto Lexp; case TOKtypedef: case TOKalias: case TOKconst: @@ -5475,15 +5485,18 @@ Expression *Parser::parsePrimaryExp() } case TOKlparen: - { enum TOK past = peekPastParen(&token)->value; - - if (past == TOKgoesto) - { // (arguments) => expression - goto case_delegate; - } - else if (past == TOKlcurly) - { // (arguments) { statements... } - goto case_delegate; + { Token *tk = peekPastParen(&token); + if (skipAttributes(tk, &tk)) + { + enum TOK past = tk->value; + if (past == TOKgoesto) + { // (arguments) => expression + goto case_delegate; + } + else if (past == TOKlcurly) + { // (arguments) { statements... } + goto case_delegate; + } } // ( expression ) nextToken(); @@ -6592,6 +6605,7 @@ void initPrecedence() precedence[TOKtraits] = PREC_primary; precedence[TOKdefault] = PREC_primary; precedence[TOKoverloadset] = PREC_primary; + precedence[TOKvoid] = PREC_primary; #endif // post diff --git a/dmd2/root/dchar.h b/dmd2/root/dchar.h index 2b8df523..6ac7994c 100644 --- a/dmd2/root/dchar.h +++ b/dmd2/root/dchar.h @@ -152,10 +152,10 @@ typedef char dchar; struct Dchar { static dchar *inc(dchar *p) { return p + 1; } - static dchar *dec(dchar *pstart, dchar *p) { return p - 1; } + static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; } static int len(const dchar *p) { return strlen(p); } static int get(dchar *p) { return *p & 0xFF; } - static int getprev(dchar *pstart, dchar *p) { return p[-1] & 0xFF; } + static int getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1] & 0xFF; } static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; } static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); } static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } diff --git a/dmd2/root/longdouble.c b/dmd2/root/longdouble.c new file mode 100644 index 00000000..8a0f00e7 --- /dev/null +++ b/dmd2/root/longdouble.c @@ -0,0 +1,636 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2011 by Digital Mars +// All Rights Reserved +// written by Rainer Schuetze +// 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. + +// 80 bit floating point value implementation for Microsoft compiler + +#if _MSC_VER +#include "longdouble.h" + +#include "assert.h" + +#include +#include +#include + +extern "C" +{ + // implemented in ldfpu.asm for _WIN64 + int ld_initfpu(int bits, int mask); + void ld_expl(longdouble* ld, int exp); + longdouble ld_add(longdouble ld1, longdouble ld2); + longdouble ld_sub(longdouble ld1, longdouble ld2); + longdouble ld_mul(longdouble ld1, longdouble ld2); + longdouble ld_div(longdouble ld1, longdouble ld2); + longdouble ld_mod(longdouble ld1, longdouble ld2); + bool ld_cmpb(longdouble ld1, longdouble ld2); + bool ld_cmpbe(longdouble ld1, longdouble ld2); + bool ld_cmpa(longdouble ld1, longdouble ld2); + bool ld_cmpae(longdouble ld1, longdouble ld2); + bool ld_cmpe(longdouble ld1, longdouble ld2); + bool ld_cmpne(longdouble ld1, longdouble ld2); + longdouble ld_sqrt(longdouble ld1); + longdouble ld_sin(longdouble ld1); + longdouble ld_cos(longdouble ld1); + longdouble ld_tan(longdouble ld1); +} + +bool initFPU() +{ +#ifdef _WIN64 +// int old_cw = ld_initfpu(_RC_NEAR); + int old_cw = ld_initfpu(0x300 /*_PC_64 | _RC_NEAR*/, // #defines NOT identical to CPU FPU control word! + 0xF00 /*_MCW_PC | _MCW_RC*/); +#else + int old_cw = _control87(_MCW_EM | _PC_64 | _RC_NEAR, + _MCW_EM | _MCW_PC | _MCW_RC); +#endif + return true; +} +static bool doInitFPU = initFPU(); + +#ifndef _WIN64 +extern "C" +{ + +double ld_read(const longdouble* pthis) +{ + double res; + __asm + { + mov eax, pthis + fld tbyte ptr [eax] + fstp res + } + return res; +} +long long ld_readll(const longdouble* pthis) +{ +#if 1 + return ld_readull(pthis); +#elif defined _WIN64 + return ld_readll(this); +#else + longdouble* pthis = this; + long long res; + __asm + { + mov eax, pthis + fld tbyte ptr [eax] + fistp qword ptr res + } + return res; +#endif +} + +unsigned long long ld_readull(const longdouble* pthis) +{ +#if 1 + // somehow the FPU does not respect the CHOP mode of the rounding control + // in 64-bit mode + // so we roll our own conversion (it also allows the usual C wrap-around + // instead of the "invalid value" created by the FPU) + int expo = pthis->exponent - 0x3fff; + unsigned long long u; + if(expo < 0 || expo > 127) + return 0; + if(expo < 64) + u = pthis->mantissa >> (63 - expo); + else + u = pthis->mantissa << (expo - 63); + if(pthis->sign) + u = ~u + 1; + return u; +#else + longdouble* pthis = this; + long long res; // cannot use unsigned, VC will not generate "fistp qword" + longdouble twoPow63 = { 1ULL << 63, 0x3fff + 63, 0 }; + __asm + { + mov eax, pthis + fld tbyte ptr [eax] + fld tbyte ptr twoPow63 + fsubp ST(1),ST(0) // move it into signed range + + lea eax, res + fistp qword ptr [eax] + } + res ^= (1LL << 63); + return res; +#endif +} + +void ld_set(longdouble* pthis, double d) +{ + __asm + { + mov eax, pthis + fld d + fstp tbyte ptr [eax] + } +} +void ld_setll(longdouble* pthis, long long d) +{ + __asm + { + fild qword ptr d + mov eax, pthis + fstp tbyte ptr [eax] + } +} +void ld_setull(longdouble* pthis, unsigned long long d) +{ + d ^= (1LL << 63); + longdouble twoPow63 = { 1ULL << 63, 0x3fff + 63, 0 }; + __asm + { + fild qword ptr d + fld tbyte ptr twoPow63 + faddp ST(1),ST(0) + mov eax, pthis + fstp tbyte ptr [eax] + } +} + +} // extern "C" +#endif // !_WIN64 + +longdouble ldexpl(longdouble ld, int exp) +{ +#ifdef _WIN64 + ld_expl(&ld, exp); +#else + __asm + { + fild dword ptr exp + fld tbyte ptr ld + fscale // ST(0) = ST(0) * (2**ST(1)) + fstp ST(1) + fstp tbyte ptr ld + } +#endif + return ld; +} + +/////////////////////////////////////////////////////////////////////// +longdouble operator+(longdouble ld1, longdouble ld2) +{ +#ifdef _WIN64 + return ld_add(ld1, ld2); +#else + longdouble res; + __asm + { + fld tbyte ptr ld1 + fld tbyte ptr ld2 + fadd + fstp tbyte ptr res; + } + return res; +#endif +} + +longdouble operator-(longdouble ld1, longdouble ld2) +{ +#ifdef _WIN64 + return ld_sub(ld1, ld2); +#else + longdouble res; + __asm + { + fld tbyte ptr ld1 + fld tbyte ptr ld2 + fsub + fstp tbyte ptr res; + } + return res; +#endif +} + +longdouble operator*(longdouble ld1, longdouble ld2) +{ +#ifdef _WIN64 + return ld_mul(ld1, ld2); +#else + longdouble res; + __asm + { + fld tbyte ptr ld1 + fld tbyte ptr ld2 + fmul + fstp tbyte ptr res; + } + return res; +#endif +} + +longdouble operator/(longdouble ld1, longdouble ld2) +{ +#ifdef _WIN64 + return ld_div(ld1, ld2); +#else + longdouble res; + __asm + { + fld tbyte ptr ld1 + fld tbyte ptr ld2 + fdiv + fstp tbyte ptr res; + } + return res; +#endif +} + +bool operator< (longdouble x, longdouble y) +{ +#ifdef _WIN64 + return ld_cmpb(x, y); +#else + short sw; + bool res; + __asm + { + fld tbyte ptr y + fld tbyte ptr x // ST = x, ST1 = y + fucomip ST(0),ST(1) + setb AL + setnp AH + and AL,AH + mov res,AL + fstp ST(0) + } + return res; +#endif +} +bool operator<=(longdouble x, longdouble y) +{ +#ifdef _WIN64 + return ld_cmpbe(x, y); +#else + short sw; + bool res; + __asm + { + fld tbyte ptr y + fld tbyte ptr x // ST = x, ST1 = y + fucomip ST(0),ST(1) + setbe AL + setnp AH + and AL,AH + mov res,AL + fstp ST(0) + } + return res; +#endif +} +bool operator> (longdouble x, longdouble y) +{ +#ifdef _WIN64 + return ld_cmpa(x, y); +#else + short sw; + bool res; + __asm + { + fld tbyte ptr y + fld tbyte ptr x // ST = x, ST1 = y + fucomip ST(0),ST(1) + seta AL + setnp AH + and AL,AH + mov res,AL + fstp ST(0) + } + return res; +#endif +} +bool operator>=(longdouble x, longdouble y) +{ +#ifdef _WIN64 + return ld_cmpae(x, y); +#else + short sw; + bool res; + __asm + { + fld tbyte ptr y + fld tbyte ptr x // ST = x, ST1 = y + fucomip ST(0),ST(1) + setae AL + setnp AH + and AL,AH + mov res,AL + fstp ST(0) + } + return res; +#endif +} +bool operator==(longdouble x, longdouble y) +{ +#ifdef _WIN64 + return ld_cmpe(x, y); +#else + short sw; + bool res; + __asm + { + fld tbyte ptr y + fld tbyte ptr x // ST = x, ST1 = y + fucomip ST(0),ST(1) + sete AL + setnp AH + and AL,AH + mov res,AL + fstp ST(0) + } + return res; +#endif +} +bool operator!=(longdouble x, longdouble y) +{ +#ifdef _WIN64 + return ld_cmpne(x, y); +#else + short sw; + bool res; + __asm + { + fld tbyte ptr y + fld tbyte ptr x // ST = x, ST1 = y + fucomip ST(0),ST(1) + setne AL + setp AH + or AL,AH + mov res,AL + fstp ST(0) + } + return res; +#endif +} + + +int _isnan(longdouble ld) +{ + return (ld.exponent == 0x7fff && ld.mantissa != 0); +} + +longdouble fabsl(longdouble ld) +{ + ld.sign = 0; + return ld; +} + +longdouble sqrtl(longdouble ld) +{ +#ifdef _WIN64 + return ld_sqrt(ld); +#else + longdouble res; + __asm + { + fld tbyte ptr ld; + fsqrt; + fstp tbyte ptr res; + } + return res; +#endif +} + +longdouble sinl (longdouble ld) +{ +#ifdef _WIN64 + return ld_sin(ld); +#else + longdouble res; + __asm + { + fld tbyte ptr ld; + fsin; // exact for |x|<=PI/4 + fstp tbyte ptr res + } + return res; +#endif +} +longdouble cosl (longdouble ld) +{ +#ifdef _WIN64 + return ld_cos(ld); +#else + longdouble res; + __asm + { + fld tbyte ptr ld; + fcos; // exact for |x|<=PI/4 + fstp tbyte ptr res; + } + return res; +#endif +} +longdouble tanl (longdouble ld) +{ +#ifdef _WIN64 + return ld_tan(ld); +#else + longdouble res; + __asm + { + fld tbyte ptr ld; + fptan; + fstp ST(0); // always 1 + fstp tbyte ptr res; + } + return res; +#endif +} + +longdouble fmodl(longdouble x, longdouble y) +{ +#ifdef _WIN64 + return ld_mod(x, y); +#else + short sw; + longdouble res; + __asm + { + fld tbyte ptr y + fld tbyte ptr x // ST = x, ST1 = y +FM1: // We don't use fprem1 because for some inexplicable + // reason we get -5 when we do _modulo(15, 10) + fprem // ST = ST % ST1 + fstsw word ptr sw + fwait + mov AH,byte ptr sw+1 // get msb of status word in AH + sahf // transfer to flags + jp FM1 // continue till ST < ST1 + fstp ST(1) // leave remainder on stack + fstp tbyte ptr res; + } + return res; +#endif +} + +////////////////////////////////////////////////////////////// + +longdouble ld_qnan = { 0x8000000000000000ULL, 0x7fff, 0 }; +longdouble ld_snan = { 0x0000000000000001ULL, 0x7fff, 0 }; +longdouble ld_inf = { 0x0000000000000000ULL, 0x7fff, 0 }; + +longdouble ld_zero = { 0, 0, 0 }; +longdouble ld_one = { 0x8000000000000000ULL, 0x3fff, 0 }; +longdouble ld_pi = { 0xc90fdaa22168c235ULL, 0x4000, 0 }; +longdouble ld_log2t = { 0xd49a784bcd1b8afeULL, 0x4000, 0 }; +longdouble ld_log2e = { 0xb8aa3b295c17f0bcULL, 0x3fff, 0 }; +longdouble ld_log2 = { 0x9a209a84fbcff799ULL, 0x3ffd, 0 }; +longdouble ld_ln2 = { 0xb17217f7d1cf79acULL, 0x3ffe, 0 }; + +longdouble ld_pi2 = ld_pi*2; +longdouble ld_piOver2 = ld_pi*0.5; +longdouble ld_piOver4 = ld_pi*0.25; + +////////////////////////////////////////////////////////////// + +#define LD_TYPE_OTHER 0 +#define LD_TYPE_ZERO 1 +#define LD_TYPE_INFINITE 2 +#define LD_TYPE_SNAN 3 +#define LD_TYPE_QNAN 4 + +int ld_type(longdouble x) +{ + if(x.exponent == 0) + return x.mantissa == 0 ? LD_TYPE_ZERO : LD_TYPE_OTHER; // dnormal if not zero + if(x.exponent != 0x7fff) + return LD_TYPE_OTHER; + if(x.mantissa == 0) + return LD_TYPE_INFINITE; + if(x.mantissa & (1LL << 63)) + return LD_TYPE_QNAN; + return LD_TYPE_SNAN; +} + +int ld_sprint(char* str, int fmt, longdouble x) +{ + // fmt is 'a','A','f' or 'g' + if(fmt != 'a' && fmt != 'A') + { + char format[] = { '%', fmt, 0 }; + return sprintf(str, format, ld_read(&x)); + } + + unsigned short exp = x.exponent; + unsigned long long mantissa = x.mantissa; + + switch(ld_type(x)) + { + case LD_TYPE_ZERO: + return sprintf(str, "0x0.0L"); + case LD_TYPE_QNAN: + case LD_TYPE_SNAN: + return sprintf(str, "NAN"); + case LD_TYPE_INFINITE: + return sprintf(str, x.sign ? "-INF" : "INF"); + } + + int len = 0; + if(x.sign) + str[len++] = '-'; + len += sprintf(str + len, mantissa & (1LL << 63) ? "0x1." : "0x0."); + mantissa = mantissa << 1; + while(mantissa) + { + int dig = (mantissa >> 60) & 0xf; + dig += dig < 10 ? '0' : fmt - 10; + str[len++] = dig; + mantissa = mantissa << 4; + } + str[len++] = 'p'; + if(exp < 0x3fff) + { + str[len++] = '-'; + exp = 0x3fff - exp; + } + else + { + str[len++] = '+'; + exp = exp - 0x3fff; + } + int exppos = len; + for(int i = 12; i >= 0; i -= 4) + { + int dig = (exp >> i) & 0xf; + if(dig != 0 || len > exppos || i == 0) + str[len++] = dig + (dig < 10 ? '0' : fmt - 10); + } + str[len] = 0; + return len; +} + +////////////////////////////////////////////////////////////// + +#if UNITTEST +static bool unittest() +{ + char buffer[32]; + ld_sprint(buffer, 'a', ld_pi); + assert(strcmp(buffer, "0x1.921fb54442d1846ap+1") == 0); + + longdouble ldb = ldouble(0.4); + long long b = ldb; + assert(b == 0); + + b = ldouble(0.9); + assert(b == 0); + + long long x = 0x12345678abcdef78LL; + longdouble ldx = ldouble(x); + assert(ldx > 0); + long long y = ldx; + assert(x == y); + + x = -0x12345678abcdef78LL; + ldx = ldouble(x); + assert(ldx < 0); + y = ldx; + assert(x == y); + + unsigned long long u = 0x12345678abcdef78LL; + longdouble ldu = ldouble(u); + assert(ldu > 0); + unsigned long long v = ldu; + assert(u == v); + + u = 0xf234567812345678ULL; + ldu = ldouble(u); + assert(ldu > 0); + v = ldu; + assert(u == v); + + u = 0xf2345678; + ldu = ldouble(u); + ldu = ldu * ldu; + ldu = sqrt(ldu); + v = ldu; + assert(u == v); + + u = 0x123456789A; + ldu = ldouble(u); + ldu = ldu * (1LL << 23); + v = ldu; + u = u * (1LL << 23); + assert(u == v); + + return true; +} + +static bool runUnittest = unittest(); + +#endif // UNITTEST + +#endif // _MSC_VER + diff --git a/dmd2/root/longdouble.h b/dmd2/root/longdouble.h new file mode 100644 index 00000000..d25223a7 --- /dev/null +++ b/dmd2/root/longdouble.h @@ -0,0 +1,254 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2011 by Digital Mars +// All Rights Reserved +// written by Rainer Schuetze +// 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. + +// 80 bit floating point value implementation for Microsoft compiler + +#ifndef __LONG_DOUBLE_H__ +#define __LONG_DOUBLE_H__ + +#if IN_GCC +#include "d-gcc-real.h" +typedef real_t longdouble; + +template longdouble ldouble(T x) { return (longdouble) x; } +inline int ld_sprint(char* str, int fmt, longdouble x) +{ + if(fmt == 'a' || fmt == 'A') + return x.formatHex(buffer, 46); // don't know the size here, but 46 is the max + return x.format(buffer, 46); +} + +#elif !_MSC_VER // has native 10 byte doubles +#include +typedef long double longdouble; +typedef volatile long double volatile_longdouble; + +// also used from within C code, so use a #define rather than a template +// template longdouble ldouble(T x) { return (longdouble) x; } +#define ldouble(x) ((longdouble)(x)) + +inline int ld_sprint(char* str, int fmt, longdouble x) +{ + char sfmt[4] = "%Lg"; + sfmt[2] = fmt; + return sprintf(str, sfmt, x); +} + +#else + +#include +#include + +struct longdouble; + +extern "C" +{ + // implemented in ldfpu.asm for _WIN64 + double ld_read(const longdouble* ld); + long long ld_readll(const longdouble* ld); + unsigned long long ld_readull(const longdouble* ld); + void ld_set(longdouble* ld, double d); + void ld_setll(longdouble* ld, long long d); + void ld_setull(longdouble* ld, unsigned long long d); +} + +struct longdouble +{ + unsigned long long mantissa; + unsigned short exponent:15; // bias 0x3fff + unsigned short sign:1; + unsigned short fill:16; // for 12 byte alignment + + // no constructor to be able to use this class in a union + // use ldouble() to explicitely create a longdouble value + + template longdouble& operator=(T x) { set(x); return *this; } + + void set(longdouble ld) { mantissa = ld.mantissa; exponent = ld.exponent; sign = ld.sign; } + + // we need to list all basic types to avoid ambiguities + void set(float d) { ld_set(this, d); } + void set(double d) { ld_set(this, d); } + void set(long double d) { ld_set(this, d); } + + void set(signed char d) { ld_set(this, d); } + void set(short d) { ld_set(this, d); } + void set(int d) { ld_set(this, d); } + void set(long d) { ld_set(this, d); } + void set(long long d) { ld_setll(this, d); } + + void set(unsigned char d) { ld_set(this, d); } + void set(unsigned short d) { ld_set(this, d); } + void set(unsigned int d) { ld_set(this, d); } + void set(unsigned long d) { ld_set(this, d); } + void set(unsigned long long d) { ld_setull(this, d); } + void set(bool d) { ld_set(this, d); } + + operator float () { return ld_read(this); } + operator double () { return ld_read(this); } + + operator signed char () { return ld_read(this); } + operator short () { return ld_read(this); } + operator int () { return ld_read(this); } + operator long () { return ld_read(this); } + operator long long () { return ld_readll(this); } + + operator unsigned char () { return ld_read(this); } + operator unsigned short () { return ld_read(this); } + operator unsigned int () { return ld_read(this); } + operator unsigned long () { return ld_read(this); } + operator unsigned long long() { return ld_readull(this); } + operator bool () { return mantissa != 0 || exponent != 0; } // correct? +}; + +// some optimizations are avoided by adding volatile to the longdouble +// type, but this introduces bad ambiguities when using the class implementation above +// as we are going through asm these optimizations won't kick in anyway, so "volatile" +// is not required. +typedef longdouble volatile_longdouble; + +inline longdouble ldouble(unsigned long long mantissa, int exp, int sign = 0) +{ + longdouble d; + d.mantissa = mantissa; + d.exponent = exp; + d.sign = sign; + return d; +} +template inline longdouble ldouble(T x) { longdouble d; d.set(x); return d; } +//template inline longdouble ldouble(volatile T x) { longdouble d; d.set(x); return d; } + +longdouble operator+(longdouble ld1, longdouble ld2); +longdouble operator-(longdouble ld1, longdouble ld2); +longdouble operator*(longdouble ld1, longdouble ld2); +longdouble operator/(longdouble ld1, longdouble ld2); + +bool operator< (longdouble ld1, longdouble ld2); +bool operator<=(longdouble ld1, longdouble ld2); +bool operator> (longdouble ld1, longdouble ld2); +bool operator>=(longdouble ld1, longdouble ld2); +bool operator==(longdouble ld1, longdouble ld2); +bool operator!=(longdouble ld1, longdouble ld2); + +inline longdouble operator-(longdouble ld1) { ld1.sign ^= 1; return ld1; } +inline longdouble operator+(longdouble ld1) { return ld1; } + +template inline longdouble operator+(longdouble ld, T x) { return ld + ldouble(x); } +template inline longdouble operator-(longdouble ld, T x) { return ld - ldouble(x); } +template inline longdouble operator*(longdouble ld, T x) { return ld * ldouble(x); } +template inline longdouble operator/(longdouble ld, T x) { return ld / ldouble(x); } + +template inline longdouble operator+(T x, longdouble ld) { return ldouble(x) + ld; } +template inline longdouble operator-(T x, longdouble ld) { return ldouble(x) - ld; } +template inline longdouble operator*(T x, longdouble ld) { return ldouble(x) * ld; } +template inline longdouble operator/(T x, longdouble ld) { return ldouble(x) / ld; } + +template inline longdouble& operator+=(longdouble& ld, T x) { return ld = ld + x; } +template inline longdouble& operator-=(longdouble& ld, T x) { return ld = ld - x; } +template inline longdouble& operator*=(longdouble& ld, T x) { return ld = ld * x; } +template inline longdouble& operator/=(longdouble& ld, T x) { return ld = ld / x; } + +template inline bool operator< (longdouble ld, T x) { return ld < ldouble(x); } +template inline bool operator<=(longdouble ld, T x) { return ld <= ldouble(x); } +template inline bool operator> (longdouble ld, T x) { return ld > ldouble(x); } +template inline bool operator>=(longdouble ld, T x) { return ld >= ldouble(x); } +template inline bool operator==(longdouble ld, T x) { return ld == ldouble(x); } +template inline bool operator!=(longdouble ld, T x) { return ld != ldouble(x); } + +template inline bool operator< (T x, longdouble ld) { return ldouble(x) < ld; } +template inline bool operator<=(T x, longdouble ld) { return ldouble(x) <= ld; } +template inline bool operator> (T x, longdouble ld) { return ldouble(x) > ld; } +template inline bool operator>=(T x, longdouble ld) { return ldouble(x) >= ld; } +template inline bool operator==(T x, longdouble ld) { return ldouble(x) == ld; } +template inline bool operator!=(T x, longdouble ld) { return ldouble(x) != ld; } + +int _isnan(longdouble ld); + +longdouble fabsl(longdouble ld); +longdouble sqrtl(longdouble ld); +longdouble sinl (longdouble ld); +longdouble cosl (longdouble ld); +longdouble tanl (longdouble ld); + +longdouble fmodl(longdouble x, longdouble y); +longdouble ldexpl(longdouble ldval, int exp); // see strtold + +inline longdouble fabs (longdouble ld) { return fabsl(ld); } +inline longdouble sqrt (longdouble ld) { return sqrtl(ld); } + +#undef LDBL_DIG +#undef LDBL_MAX +#undef LDBL_MIN +#undef LDBL_EPSILON +#undef LDBL_MANT_DIG +#undef LDBL_MAX_EXP +#undef LDBL_MIN_EXP +#undef LDBL_MAX_10_EXP +#undef LDBL_MIN_10_EXP + +#define LDBL_DIG 18 +#define LDBL_MAX ldouble(0xffffffffffffffffULL, 0x7ffe) +#define LDBL_MIN ldouble(0x8000000000000000ULL, 1) +#define LDBL_EPSILON ldouble(0x8000000000000000ULL, 0x3fff - 63) // allow denormal? +#define LDBL_MANT_DIG 64 +#define LDBL_MAX_EXP 16384 +#define LDBL_MIN_EXP (-16381) +#define LDBL_MAX_10_EXP 4932 +#define LDBL_MIN_10_EXP (-4932) + +extern longdouble ld_zero; +extern longdouble ld_one; +extern longdouble ld_pi; +extern longdouble ld_log2t; +extern longdouble ld_log2e; +extern longdouble ld_log2; +extern longdouble ld_ln2; + +extern longdouble ld_inf; +extern longdouble ld_qnan; +extern longdouble ld_snan; + +/////////////////////////////////////////////////////////////////////// +// CLASS numeric_limits +template<> class _CRTIMP2_PURE std::numeric_limits +: public _Num_float_base +{ // limits for type long double +public: + typedef longdouble _Ty; + + static _Ty (__CRTDECL min)() _THROW0() { return LDBL_MIN; } + static _Ty (__CRTDECL max)() _THROW0() { return LDBL_MAX; } + static _Ty __CRTDECL epsilon() _THROW0() { return LDBL_EPSILON; } + static _Ty __CRTDECL round_error() _THROW0() { return ldouble(0.5); } + static _Ty __CRTDECL denorm_min() _THROW0() { return ldouble(0x0000000000000001ULL, 1); } + static _Ty __CRTDECL infinity() _THROW0() { return ld_inf; } + static _Ty __CRTDECL quiet_NaN() _THROW0() { return ld_qnan; } + static _Ty __CRTDECL signaling_NaN() _THROW0() { return ld_snan; } + + _STCONS(int, digits, LDBL_MANT_DIG); + _STCONS(int, digits10, LDBL_DIG); + _STCONS(int, max_exponent, (int)LDBL_MAX_EXP); + _STCONS(int, max_exponent10, (int)LDBL_MAX_10_EXP); + _STCONS(int, min_exponent, (int)LDBL_MIN_EXP); + _STCONS(int, min_exponent10, (int)LDBL_MIN_10_EXP); +}; + +//_STCONSDEF(numeric_limits, int, digits) +//_STCONSDEF(numeric_limits, int, digits10) +//_STCONSDEF(numeric_limits, int, max_exponent) +//_STCONSDEF(numeric_limits, int, max_exponent10) +//_STCONSDEF(numeric_limits, int, min_exponent) +//_STCONSDEF(numeric_limits, int, min_exponent10) + +int ld_sprint(char* str, int fmt, longdouble x); + +#endif // !_MSC_VER + +#endif // __LONG_DOUBLE_H__ diff --git a/dmd2/root/lstring.h b/dmd2/root/lstring.h index 17a8e447..0c545790 100644 --- a/dmd2/root/lstring.h +++ b/dmd2/root/lstring.h @@ -19,8 +19,10 @@ struct Lstring { unsigned length; +#ifndef IN_GCC // Disable warning about nonstandard extension #pragma warning (disable : 4200) +#endif dchar string[]; static Lstring zero; // 0 length string diff --git a/dmd2/root/port.c b/dmd2/root/port.c index 232faefc..29b0b1e8 100644 --- a/dmd2/root/port.c +++ b/dmd2/root/port.c @@ -17,14 +17,14 @@ double Port::nan = NAN; double Port::infinity = INFINITY; double Port::dbl_max = DBL_MAX; double Port::dbl_min = DBL_MIN; -long double Port::ldbl_max = LDBL_MAX; +longdouble Port::ldbl_max = LDBL_MAX; int Port::isNan(double r) { return ::isnan(r); } -int Port::isNan(long double r) +int Port::isNan(longdouble r) { return ::isnan(r); } @@ -37,7 +37,7 @@ int Port::isSignallingNan(double r) return isNan(r) && !((((unsigned char*)&r)[6]) & 8); } -int Port::isSignallingNan(long double r) +int Port::isSignallingNan(longdouble r) { /* A signalling NaN is a NaN with 0 as the most significant bit of * its significand, which is bit 62 of 0..79 for 80 bit reals. @@ -70,7 +70,7 @@ double Port::pow(double x, double y) return ::pow(x, y); } -long double Port::fmodl(long double x, long double y) +longdouble Port::fmodl(longdouble x, longdouble y) { return ::fmodl(x, y); } @@ -140,7 +140,7 @@ double Port::infinity = 1 / zero; double Port::dbl_max = DBL_MAX; double Port::dbl_min = DBL_MIN; -long double Port::ldbl_max = LDBL_MAX; +longdouble Port::ldbl_max = LDBL_MAX; struct PortInitializer { @@ -151,7 +151,7 @@ static PortInitializer portinitializer; PortInitializer::PortInitializer() { - Port::infinity = std::numeric_limits::infinity(); + Port::infinity = std::numeric_limits::infinity(); } int Port::isNan(double r) @@ -159,7 +159,7 @@ int Port::isNan(double r) return ::_isnan(r); } -int Port::isNan(long double r) +int Port::isNan(longdouble r) { return ::_isnan(r); } @@ -172,7 +172,7 @@ int Port::isSignallingNan(double r) return isNan(r) && !((((unsigned char*)&r)[6]) & 8); } -int Port::isSignallingNan(long double r) +int Port::isSignallingNan(longdouble r) { /* MSVC doesn't have 80 bit long doubles */ @@ -206,7 +206,7 @@ double Port::pow(double x, double y) return ::pow(x, y); } -long double Port::fmodl(long double x, long double y) +longdouble Port::fmodl(longdouble x, longdouble y) { return ::fmodl(x, y); } @@ -351,7 +351,7 @@ double Port::nan = copysign(NAN, 1.0); double Port::infinity = 1 / zero; double Port::dbl_max = 1.7976931348623157e308; double Port::dbl_min = 5e-324; -long double Port::ldbl_max = LDBL_MAX; +longdouble Port::ldbl_max = LDBL_MAX; struct PortInitializer { @@ -366,9 +366,9 @@ PortInitializer::PortInitializer() #if __FreeBSD__ && __i386__ // LDBL_MAX comes out as infinity. Fix. - static unsigned char x[sizeof(long double)] = + static unsigned char x[sizeof(longdouble)] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F }; - Port::ldbl_max = *(long double *)&x[0]; + Port::ldbl_max = *(longdouble *)&x[0]; // FreeBSD defaults to double precision. Switch to extended precision. fpsetprec(FP_PE); #endif @@ -388,7 +388,7 @@ int Port::isNan(double r) #endif } -int Port::isNan(long double r) +int Port::isNan(longdouble r) { #if __APPLE__ return __inline_isnan(r); @@ -408,7 +408,7 @@ int Port::isSignallingNan(double r) return isNan(r) && !((((unsigned char*)&r)[6]) & 8); } -int Port::isSignallingNan(long double r) +int Port::isSignallingNan(longdouble r) { /* A signalling NaN is a NaN with 0 as the most significant bit of * its significand, which is bit 62 of 0..79 for 80 bit reals. @@ -454,7 +454,7 @@ double Port::pow(double x, double y) return ::pow(x, y); } -long double Port::fmodl(long double x, long double y) +longdouble Port::fmodl(longdouble x, longdouble y) { #if __FreeBSD__ || __OpenBSD__ return ::fmod(x, y); // hack for now, fix later @@ -532,7 +532,7 @@ double Port::nan = NAN; double Port::infinity = 1 / zero; double Port::dbl_max = 1.7976931348623157e308; double Port::dbl_min = 5e-324; -long double Port::ldbl_max = LDBL_MAX; +longdouble Port::ldbl_max = LDBL_MAX; struct PortInitializer { @@ -546,7 +546,7 @@ 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; + volatile longdouble foo; foo = NAN; if (signbit(foo)) // signbit sometimes, not always, set foo = -foo; // turn off sign bit @@ -558,7 +558,7 @@ int Port::isNan(double r) return isnan(r); } -int Port::isNan(long double r) +int Port::isNan(longdouble r) { return isnan(r); } @@ -571,7 +571,7 @@ int Port::isSignallingNan(double r) return isNan(r) && !((((unsigned char*)&r)[6]) & 8); } -int Port::isSignallingNan(long double r) +int Port::isSignallingNan(longdouble r) { /* A signalling NaN is a NaN with 0 as the most significant bit of * its significand, which is bit 62 of 0..79 for 80 bit reals. @@ -653,144 +653,3 @@ char *Port::strupr(char *s) #endif -#if IN_GCC - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static double zero = 0; -double Port::nan = NAN; -double Port::infinity = 1 / zero; -double Port::dbl_max = 1.7976931348623157e308; -double Port::dbl_min = 5e-324; -long double Port::ldbl_max = LDBL_MAX; - -#include "d-gcc-real.h" -extern "C" bool real_isnan (const real_t *); - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - Port::infinity = real_t::getinfinity(); - Port::nan = real_t::getnan(real_t::LongDouble); -} - -#undef isnan -int Port::isNan(double r) -{ -#if __APPLE__ - return __inline_isnan(r); -#else - return ::isnan(r); -#endif -} - -int Port::isNan(long double r) -{ - return real_isnan(&r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -#undef isfinite -int Port::isFinite(double r) -{ - return ::finite(r); -} - -#undef isinf -int Port::isInfinity(double r) -{ - return ::isinf(r); -} - -#undef signbit -int Port::Signbit(double r) -{ - return (long)(((long *)&r)[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; -} - -char *Port::strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} - -#endif - diff --git a/dmd2/root/port.h b/dmd2/root/port.h index d915991d..dd1ad97d 100644 --- a/dmd2/root/port.h +++ b/dmd2/root/port.h @@ -10,6 +10,8 @@ // Portable wrapper around compiler/system specific things. // The idea is to minimize #ifdef's in the app code. +#include "longdouble.h" + #ifndef TYPEDEFS #define TYPEDEFS @@ -20,7 +22,7 @@ typedef __int64 longlong; typedef unsigned __int64 ulonglong; // According to VC 8.0 docs, long double is the same as double -#define strtold strtod +longdouble strtold(const char *p,char **endp); #define strtof strtod #else @@ -38,7 +40,7 @@ struct Port static double infinity; static double dbl_max; static double dbl_min; - static long double ldbl_max; + static longdouble ldbl_max; #if !defined __HAIKU__ || __OpenBSD__ #elif __GNUC__ @@ -49,10 +51,10 @@ struct Port #undef signbit #endif static int isNan(double); - static int isNan(long double); + static int isNan(longdouble); static int isSignallingNan(double); - static int isSignallingNan(long double); + static int isSignallingNan(longdouble); static int isFinite(double); static int isInfinity(double); @@ -61,7 +63,7 @@ struct Port static double floor(double); static double pow(double x, double y); - static long double fmodl(long double x, long double y); + static longdouble fmodl(longdouble x, longdouble y); static ulonglong strtoull(const char *p, char **pend, int base); diff --git a/dmd2/root/response.c b/dmd2/root/response.c index 2096f11b..31e35686 100644 --- a/dmd2/root/response.c +++ b/dmd2/root/response.c @@ -29,6 +29,13 @@ #include #endif +#if _MSC_VER +#include +#include +#include +#include +#endif + /********************************* * #include * int response_expand(int *pargc,char ***pargv); diff --git a/dmd2/root/root.c b/dmd2/root/root.c index 926dae28..773a542a 100644 --- a/dmd2/root/root.c +++ b/dmd2/root/root.c @@ -1533,7 +1533,7 @@ void File::stat() void File::checkoffset(size_t offset, size_t nbytes) { if (offset > len || offset + nbytes > len) - error("Corrupt file '%s': offset x%zx off end of file",toChars(),offset); + error("Corrupt file '%s': offset x%llx off end of file",toChars(),(ulonglong)offset); } char *File::toChars() @@ -1802,7 +1802,7 @@ void OutBuffer::align(unsigned size) // The compiler shipped with Visual Studio 2005 (and possible // other versions) does not support C99 printf format specfiers // such as %z and %j -#if _MSC_VER +#if 0 && _MSC_VER using std::string; using std::wstring; @@ -1821,7 +1821,7 @@ search_and_replace(S& str, const S& what, const S& replacement) #define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) \ S tmp = f; \ search_and_replace(fmt, S("%z"), S("%l")); \ - search_and_replace(fmt, S("%j"), S("%i")); \ + search_and_replace(fmt, S("%j"), S("%l")); \ f = tmp.c_str(); #else #define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) diff --git a/dmd2/root/root.h b/dmd2/root/root.h index bac6036e..830ea43b 100644 --- a/dmd2/root/root.h +++ b/dmd2/root/root.h @@ -23,6 +23,7 @@ typedef size_t hash_t; +#include "longdouble.h" #include "dchar.h" char *wchar2ascii(wchar_t *); @@ -32,9 +33,6 @@ int wcharIsAscii(wchar_t *, unsigned len); int bstrcmp(unsigned char *s1, unsigned char *s2); char *bstr2str(unsigned char *b); -void error(const char *format, ...); -void error(const wchar_t *format, ...); -void warning(const char *format, ...); #ifndef TYPEDEFS #define TYPEDEFS @@ -43,7 +41,7 @@ void warning(const char *format, ...); #include // for _isnan #include // for alloca // According to VC 8.0 docs, long double is the same as double -#define strtold strtod +longdouble strtold(const char *p,char **endp); #define strtof strtod #define isnan _isnan diff --git a/dmd2/root/speller.c b/dmd2/root/speller.c index d6437379..373baf6d 100644 --- a/dmd2/root/speller.c +++ b/dmd2/root/speller.c @@ -4,7 +4,7 @@ #include #include -#if __sun&&__SVR4 +#if __sun&&__SVR4 || _MSC_VER #include #endif diff --git a/dmd2/scope.c b/dmd2/scope.c index a23654e9..010cdb1a 100644 --- a/dmd2/scope.c +++ b/dmd2/scope.c @@ -75,11 +75,11 @@ Scope::Scope() this->noaccesscheck = 0; this->mustsemantic = 0; this->intypeof = 0; + this->speculative = 0; this->parameterSpecialization = 0; this->ignoreTemplates = 0; this->callSuper = 0; this->flags = 0; - this->anonAgg = NULL; this->lastdc = NULL; this->lastoffset = 0; this->docbuf = NULL; @@ -125,11 +125,11 @@ Scope::Scope(Scope *enclosing) this->noaccesscheck = enclosing->noaccesscheck; this->mustsemantic = enclosing->mustsemantic; this->intypeof = enclosing->intypeof; + this->speculative = enclosing->speculative; this->parameterSpecialization = enclosing->parameterSpecialization; this->ignoreTemplates = enclosing->ignoreTemplates; this->callSuper = enclosing->callSuper; this->flags = 0; - this->anonAgg = NULL; this->lastdc = NULL; this->lastoffset = 0; this->docbuf = enclosing->docbuf; diff --git a/dmd2/scope.h b/dmd2/scope.h index ea725f09..4fee6539 100644 --- a/dmd2/scope.h +++ b/dmd2/scope.h @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -63,11 +63,16 @@ struct Scope Statement *scontinue; // enclosing statement that supports "continue" ForeachStatement *fes; // if nested function for ForeachStatement, this is it unsigned offset; // next offset to use in aggregate + // This really shouldn't be a part of Scope, because it requires + // semantic() to be done in the lexical field order. It should be + // set in a pass after semantic() on all fields so they can be + // semantic'd in any order. int inunion; // we're processing members of a union int incontract; // we're inside contract code int nofree; // set if shouldn't free it int noctor; // set if constructor calls aren't allowed int intypeof; // in typeof(exp) + bool speculative; // in __traits(compiles) or typeof(exp) int parameterSpecialization; // if in template parameter specialization int noaccesscheck; // don't do access checks int mustsemantic; // cannot defer semantic() @@ -97,7 +102,9 @@ struct Scope #define SCOPEstaticassert 8 // inside static assert #define SCOPEdebug 0x10 // inside debug conditional - AnonymousAggregateDeclaration *anonAgg; // for temporary analysis +#if IN_GCC + Expressions *attributes; // GCC decl/type attributes +#endif DocComment *lastdc; // documentation comment for last symbol at this scope unsigned lastoffset; // offset in docbuf of where to insert next dec diff --git a/dmd2/statement.c b/dmd2/statement.c index 61aca6d4..a0be3353 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -1243,6 +1243,7 @@ ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expr this->condition = condition; this->increment = increment; this->body = body; + this->nest = 0; } Statement *ForStatement::syntaxCopy() @@ -1260,17 +1261,145 @@ Statement *ForStatement::syntaxCopy() return s; } +/* + * Run semantic on init recursively. + * Rewrite: + * for (auto x=X(), y = Y(); ...; ...) {} + * as: + * try { + * try { + * for (auto x=X(), auto y=Y(); ...; ...) {} + * } + * finally { y.~this(); } + * } + * finally { x.~this(); } + */ +Statement *ForStatement::semanticInit(Scope *sc) +{ + assert(init); + ++nest; + + Loc locinit = init->loc; + Statements *ainit = init->flatten(sc); + if (!ainit) + (ainit = new Statements())->push(init); + init = NULL; + + Statement *statement = this; + + for (size_t i = 0; i < ainit->dim; i++) + { Statement *s = (*ainit)[i]; + s = s->semantic(sc); + (*ainit)[i] = s; + if (s) + { + Statement *sentry; + Statement *sexception; + Statement *sfinally; + + (*ainit)[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally); + + if (sentry) + { sentry = sentry->semantic(sc); + if (sentry) + ainit->insert(i++, sentry); + } + if (sexception) + sexception = sexception->semantic(sc); + if (sexception) + { // Re-initialize this->init + if (i + 1 < ainit->dim) + { + Statements *a = new Statements(); + for (size_t j = i + 1; j < ainit->dim; j++) + a->push((*ainit)[j]); + init = new CompoundStatement(0, a); + } + + Identifier *id = Lexer::uniqueId("__o"); + 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); + catches->push(ctch); + s = new TryCatchStatement(0, this, catches); + + if (sfinally) + s = new TryFinallyStatement(0, s, sfinally); + //printf("ex {{{\n"); + s = s->semantic(sc); + //printf("}}}\n"); + statement = s; + + if (init) + { Statements *a = init->flatten(sc); + if (!a) + (a = new Statements())->push(init); + for (size_t j = 0; j < i + 1; j++) + a->insert(j, (*ainit)[j]); + init = new CompoundStatement(locinit, a); + } + break; + } + else if (sfinally) + { // Re-initialize this->init + if (i + 1 < ainit->dim) + { + Statements *a = new Statements(); + for (size_t j = i + 1; j < ainit->dim; j++) + a->push((*ainit)[j]); + init = new CompoundStatement(0, a); + } + + s = new TryFinallyStatement(0, this, sfinally); + //printf("fi {{{\n"); + s = s->semantic(sc); + //printf("}}} fi\n"); + statement = s; + + if (init) + { Statements *a = init->flatten(sc); + if (!a) + (a = new Statements())->push(init); + for (size_t j = 0; j < i + 1; j++) + a->insert(j, (*ainit)[j]); + init = new CompoundStatement(locinit, a); + } + break; + } + } + } + if (!init) + { // whole init semantic is completely done. + init = new CompoundStatement(locinit, ainit); + } + + --nest; + return statement; +} + Statement *ForStatement::semantic(Scope *sc) { - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); + if (!nest) + { ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + } + else if (init) + { // Process this->init recursively + return semanticInit(sc); + } + + Statement *statement = this; if (init) - init = init->semantic(sc); + statement = semanticInit(sc); + sc->noctor++; if (condition) - { - condition = condition->semantic(sc); + { condition = condition->semantic(sc); condition = resolveProperties(sc, condition); condition = condition->optimize(WANTvalue); condition = condition->checkToBoolean(sc); @@ -1287,18 +1416,16 @@ Statement *ForStatement::semantic(Scope *sc) body = body->semanticNoScope(sc); sc->noctor--; - sc->pop(); - return this; + if (!nest) + sc->pop(); + //if (!nest) statement->print(); + return statement; } Statement *ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) { //printf("ForStatement::scopeCode()\n"); - //print(); - if (init) - init = init->scopeCode(sc, sentry, sexception, sfinally); - else - Statement::scopeCode(sc, sentry, sexception, sfinally); + Statement::scopeCode(sc, sentry, sexception, sfinally); return this; } @@ -1538,6 +1665,10 @@ Statement *ForeachStatement::semantic(Scope *sc) if (arg->storageClass & STCref) error("symbol %s cannot be ref", s->toChars()); } + else if (e->op == TOKtype) + { + var = new AliasDeclaration(loc, arg->ident, e->type); + } else { arg->type = e->type; @@ -2111,11 +2242,7 @@ Lagain: default: assert(0); } const char *r = (op == TOKforeach_reverse) ? "R" : ""; -#ifdef __MINGW32__ - int j = sprintf(fdname, "_aApply%s%.*s%lu", r, 2, fntab[flag], dim); -#else - int j = sprintf(fdname, "_aApply%s%.*s%zu", r, 2, fntab[flag], dim); -#endif + int j = sprintf(fdname, "_aApply%s%.*s%llu", r, 2, fntab[flag], (ulonglong)dim); assert(j < sizeof(fdname)); //LDC: Build arguments. Parameters* args = new Parameters; @@ -2844,7 +2971,12 @@ Statement *PragmaStatement::semantic(Scope *sc) Expression *e = (*args)[i]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + if (e->op != TOKerror) + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKerror) + { errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars()); + goto Lerror; + } StringExp *se = e->toString(); if (se) { @@ -2916,7 +3048,7 @@ Statement *PragmaStatement::semantic(Scope *sc) #endif else error("unrecognized pragma(%s)", ident->toChars()); - +Lerror: if (body) { body = body->semantic(sc); @@ -3021,6 +3153,7 @@ SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFi Statement *SwitchStatement::syntaxCopy() { + //printf("SwitchStatement::syntaxCopy(%p)\n", this); SwitchStatement *s = new SwitchStatement(loc, condition->syntaxCopy(), body->syntaxCopy(), isFinal); return s; @@ -3029,7 +3162,8 @@ Statement *SwitchStatement::syntaxCopy() Statement *SwitchStatement::semantic(Scope *sc) { //printf("SwitchStatement::semantic(%p)\n", this); - assert(!cases); // ensure semantic() is only run once + if (cases) + return this; // already run #if IN_LLVM enclosingScopeExit = sc->enclosingScopeExit; @@ -3441,7 +3575,7 @@ DefaultStatement::DefaultStatement(Loc loc, Statement *s) { this->statement = s; #if IN_GCC -+ cblock = NULL; + cblock = NULL; #endif bodyBB = NULL; // LDC @@ -3676,9 +3810,8 @@ Statement *ReturnStatement::semantic(Scope *sc) { fd->hasReturnExp |= 1; - if (exp->op == TOKfunction && tbret) - ((FuncExp *)exp)->setType(tbret); - + if (tret) + exp = exp->inferType(tbret); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); if (!((TypeFunction *)fd->type)->isref) @@ -4211,6 +4344,8 @@ Statement *SynchronizedStatement::semantic(Scope *sc) { exp = exp->semantic(sc); exp = resolveProperties(sc, exp); + if (exp->op == TOKerror) + goto Lbody; ClassDeclaration *cd = exp->type->isClassHandle(); if (!cd) error("can only synchronize on class objects, not '%s'", exp->type->toChars()); @@ -4312,6 +4447,7 @@ Statement *SynchronizedStatement::semantic(Scope *sc) return s->semantic(sc); } #endif +Lbody: if (body) { Statement* oldScopeExit = sc->enclosingScopeExit; @@ -4416,6 +4552,13 @@ Statement *WithStatement::semantic(Scope *sc) } else if (t->ty == Tstruct) { + if (!exp->isLvalue()) + { + init = new ExpInitializer(loc, exp); + wthis = new VarDeclaration(loc, exp->type, Lexer::uniqueId("__withtmp"), init); + exp = new CommaExp(loc, new DeclarationExp(loc, wthis), new VarExp(loc, wthis)); + exp = exp->semantic(sc); + } Expression *e = exp->addressOf(sc); init = new ExpInitializer(loc, e); wthis = new VarDeclaration(loc, e->type, Id::withSym, init); diff --git a/dmd2/statement.h b/dmd2/statement.h index 06fbe750..2bd213dc 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -356,9 +356,11 @@ struct ForStatement : Statement Expression *condition; Expression *increment; Statement *body; + int nest; ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); Statement *syntaxCopy(); + Statement *semanticInit(Scope *sc); Statement *semantic(Scope *sc); Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); int hasBreak(); diff --git a/dmd2/struct.c b/dmd2/struct.c index b2ffef2a..b3c8cba3 100644 --- a/dmd2/struct.c +++ b/dmd2/struct.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 @@ -39,7 +39,7 @@ AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) alignsize = 0; // size of struct for alignment purposes structalign = 0; // struct member alignment in effect hasUnions = 0; - sizeok = 0; // size not determined yet + sizeok = SIZEOKnone; // size not determined yet deferred = NULL; isdeprecated = false; inv = NULL; @@ -129,9 +129,46 @@ unsigned AggregateDeclaration::size(Loc loc) //printf("AggregateDeclaration::size() %s, scope = %p\n", toChars(), scope); if (!members) error(loc, "unknown size"); - if (sizeok != 1 && scope) + if (sizeok != SIZEOKdone && scope) semantic(NULL); - if (sizeok != 1) + + StructDeclaration *sd = isStructDeclaration(); + if (sizeok != SIZEOKdone && sd && sd->members) + { + /* See if enough is done to determine the size, + * meaning all the fields are done. + */ + struct SV + { + static int func(Dsymbol *s, void *param) + { SV *psv = (SV *)param; + VarDeclaration *v = s->isVarDeclaration(); + if (v) + { + if (v->scope) + v->semantic(NULL); + if (v->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCconst | STCimmutable | STCmanifest | STCctfe | STCtemplateparameter)) + return 0; + if (v->storage_class & STCfield && v->sem >= SemanticDone) + return 0; + return 1; + } + return 0; + } + }; + SV sv; + + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + if (s->apply(&SV::func, &sv)) + goto L1; + } + sd->finalizeSize(NULL); + + L1: ; + } + + if (sizeok != SIZEOKdone) { error(loc, "no size yet for forward reference"); //*(char*)0=0; } @@ -175,76 +212,38 @@ void AggregateDeclaration::alignmember( //printf("result = %d\n",offset); } - -void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) +/**************************************** + * Place a member (mem) into an aggregate (agg), which can be a struct, union or class + * Returns: + * offset to place field at + */ +unsigned AggregateDeclaration::placeField( + unsigned *nextoffset, // next location in aggregate + unsigned memsize, // size of member + unsigned memalignsize, // size of member for alignment purposes + unsigned memalign, // alignment in effect for this member + unsigned *paggsize, // size of aggregate (updated) + unsigned *paggalignsize, // size of aggregate for alignment purposes (updated) + bool isunion // the aggregate is a union + ) { - unsigned memsize; // size of member - unsigned memalignsize; // size of member for alignment purposes - unsigned xalign; // alignment boundaries - - //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars()); - assert(!(v->storage_class & (STCstatic | STCextern | STCparameter | STCtls))); - - // Check for forward referenced types which will fail the size() call - Type *t = v->type->toBasetype(); - if (v->storage_class & STCref) - { // References are the size of a pointer - t = Type::tvoidptr; - } - if (t->ty == Tstruct /*&& isStructDeclaration()*/) - { TypeStruct *ts = (TypeStruct *)t; -#if DMDV2 - if (ts->sym == this) - { - error("cannot have field %s with same struct type", v->toChars()); - } -#endif - - if (ts->sym->sizeok != 1 && ts->sym->scope) - ts->sym->semantic(NULL); - if (ts->sym->sizeok != 1) - { - sizeok = 2; // cannot finish; flag as forward referenced - return; - } - } - if (t->ty == Tident) - { - sizeok = 2; // cannot finish; flag as forward referenced - return; - } - - memsize = t->size(loc); - memalignsize = t->alignsize(); - xalign = t->memalign(sc->structalign); -#if 0 - alignmember(xalign, memalignsize, &sc->offset); - v->offset = sc->offset; - sc->offset += memsize; - if (sc->offset > structsize) - structsize = sc->offset; -#else - unsigned ofs = sc->offset; - alignmember(xalign, memalignsize, &ofs); - v->offset = ofs; + unsigned ofs = *nextoffset; + alignmember(memalign, memalignsize, &ofs); + unsigned memoffset = ofs; ofs += memsize; - if (ofs > structsize) - structsize = ofs; - if (!isUnionDeclaration()) - sc->offset = ofs; -#endif - if (global.params.is64bit && sc->structalign == 8 && memalignsize == 16 && isUnionDeclaration()) + if (ofs > *paggsize) + *paggsize = ofs; + if (!isunion) + *nextoffset = ofs; + if (global.params.is64bit && memalign == 8 && memalignsize == 16) /* Not sure how to handle this */ ; - else if (sc->structalign < memalignsize) - memalignsize = sc->structalign; - if (alignsize < memalignsize) - alignsize = memalignsize; - //printf("\t%s: alignsize = %d\n", toChars(), alignsize); + else if (memalign < memalignsize) + memalignsize = memalign; + if (*paggalignsize < memalignsize) + *paggalignsize = memalignsize; - v->storage_class |= STCfield; - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize); - fields.push(v); + return memoffset; } @@ -363,7 +362,7 @@ void StructDeclaration::semantic(Scope *sc) return; if (symtab) - { if (sizeok == 1 || !scope) + { if (sizeok == SIZEOKdone || !scope) { //printf("already completed\n"); scope = NULL; return; // semantic() already completed @@ -398,16 +397,8 @@ void StructDeclaration::semantic(Scope *sc) assert(!isAnonymous()); if (sc->stc & STCabstract) error("structs, unions cannot be abstract"); -#if DMDV2 - if (storage_class & STCimmutable) - type = type->addMod(MODimmutable); - if (storage_class & STCconst) - type = type->addMod(MODconst); - if (storage_class & STCshared) - type = type->addMod(MODshared); -#endif - if (sizeok == 0) // if not already done the addMember step + if (sizeok == SIZEOKnone) // if not already done the addMember step { int hasfunctions = 0; for (size_t i = 0; i < members->dim; i++) @@ -453,7 +444,7 @@ void StructDeclaration::semantic(Scope *sc) } } - sizeok = 0; + sizeok = SIZEOKnone; sc2 = sc->push(this); sc2->stc &= STCsafe | STCtrusted | STCsystem; sc2->parent = this; @@ -472,7 +463,7 @@ void StructDeclaration::semantic(Scope *sc) /* There are problems doing this in the general case because * Scope keeps track of things like 'offset' */ - if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) + //if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) { //printf("setScope %s %s\n", s->kind(), s->toChars()); s->setScope(sc2); @@ -490,15 +481,27 @@ void StructDeclaration::semantic(Scope *sc) */ if (i + 1 == members_dim) { - if (sizeok == 0 && s->isAliasDeclaration()) - finalizeSize(); + if (sizeok == SIZEOKnone && s->isAliasDeclaration()) + finalizeSize(sc2); } + // Ungag errors when not speculative + unsigned oldgag = global.gag; + if (global.isSpeculativeGagging() && !isSpeculative()) + global.gag = 0; s->semantic(sc2); + global.gag = oldgag; } + finalizeSize(sc2); - if (sizeok == 2) + if (sizeok == SIZEOKfwd) { // semantic() failed because of forward references. // Unwind what we did, and defer it for later + for (size_t i = 0; i < fields.dim; i++) + { Dsymbol *s = fields[i]; + VarDeclaration *vd = s->isVarDeclaration(); + if (vd) + vd->offset = 0; + } fields.setDim(0); structsize = 0; alignsize = 0; @@ -513,7 +516,6 @@ void StructDeclaration::semantic(Scope *sc) return; } - finalizeSize(); Module::dprogress++; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); @@ -522,7 +524,7 @@ void StructDeclaration::semantic(Scope *sc) zeroInit = 1; for (size_t i = 0; i < fields.dim; i++) { - Dsymbol *s = fields.tdata()[i]; + Dsymbol *s = fields[i]; VarDeclaration *vd = s->isVarDeclaration(); if (vd && !vd->isDataseg()) { @@ -661,8 +663,21 @@ Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) return ScopeDsymbol::search(loc, ident, flags); } -void StructDeclaration::finalizeSize() +void StructDeclaration::finalizeSize(Scope *sc) { + if (sizeok != SIZEOKnone) + return; + + // Set the offsets of the fields and determine the size of the struct + unsigned offset = 0; + bool isunion = isUnionDeclaration() != NULL; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->setFieldOffset(this, &offset, isunion); + } + if (sizeok == SIZEOKfwd) + return; + // 0 sized struct's are set to 1 byte if (structsize == 0) { @@ -675,7 +690,7 @@ void StructDeclaration::finalizeSize() // aligned properly. structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - sizeok = 1; + sizeok = SIZEOKdone; } void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) diff --git a/dmd2/template.c b/dmd2/template.c index fa634815..70a0b934 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -201,7 +201,7 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) { if (sc1->scopesym == ti1) { - error("recursive template expansion for template argument %s", t1->toChars()); + tempdecl->error("recursive template expansion for template argument %s", t1->toChars()); return 1; // fake a match } } @@ -379,7 +379,7 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, this->members = decldefs; this->overnext = NULL; this->overroot = NULL; - this->semanticRun = 0; + this->semanticRun = PASSinit; this->onemember = NULL; this->literal = 0; this->ismixin = ismixin; @@ -435,7 +435,7 @@ void TemplateDeclaration::semantic(Scope *sc) #endif if (semanticRun) return; // semantic() already run - semanticRun = 1; + semanticRun = PASSsemantic; if (sc->module && sc->module->ident == Id::object && ident == Id::AssociativeArray) { Type::associativearray = this; @@ -496,7 +496,7 @@ void TemplateDeclaration::semantic(Scope *sc) origParameters->setDim(parameters->dim); for (size_t i = 0; i < parameters->dim; i++) { - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; origParameters->tdata()[i] = tp->syntaxCopy(); } } @@ -510,11 +510,13 @@ void TemplateDeclaration::semantic(Scope *sc) for (size_t i = 0; i < parameters->dim; i++) { - TemplateParameter *tp = parameters->tdata()[i]; + TemplateParameter *tp = (*parameters)[i]; tp->semantic(paramscope); if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) - error("template tuple parameter must be last one"); + { error("template tuple parameter must be last one"); + errors = true; + } } paramscope->pop(); @@ -688,6 +690,9 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, #endif dedtypes->zero(); + if (errors) + return MATCHnomatch; + size_t parameters_dim = parameters->dim; int variadic = isVariadic() != NULL; @@ -968,6 +973,9 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec dedtypes.setDim(parameters->dim); dedtypes.zero(); + if (errors) + return MATCHnomatch; + // Set up scope for parameters ScopeDsymbol *paramsym = new ScopeDsymbol(); paramsym->parent = scope->parent; @@ -1108,6 +1116,14 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objec t->objects.setDim(tuple_dim); for (size_t i = 0; i < tuple_dim; i++) { Expression *farg = fargs->tdata()[fptupindex + i]; + + // Check invalid arguments to detect errors early. + if (farg->op == TOKerror || farg->type->ty == Terror) + goto Lnomatch; + + if (!(fparam->storageClass & STClazy) && farg->type->ty == Tvoid) + goto Lnomatch; + unsigned mod = farg->type->mod; Type *tt; MATCH m; @@ -1384,6 +1400,11 @@ L2: else { Expression *farg = fargs->tdata()[i]; + + // Check invalid arguments to detect errors early. + if (farg->op == TOKerror || farg->type->ty == Terror) + goto Lnomatch; + Lretry: #if 0 printf("\tfarg->type = %s\n", farg->type->toChars()); @@ -1413,22 +1434,16 @@ Lretry: 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; - } + Expression *e = fe->inferType(tp, 1, parameters); + if (!e) + goto Lvarargs; + farg = e; argtype = farg->type; } + if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid) + goto Lnomatch; + /* Remove top const for dynamic array types and pointer types */ if ((argtype->ty == Tarray || argtype->ty == Tpointer) && @@ -1443,12 +1458,11 @@ Lretry: 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); + unsigned wm = 0; + MATCH m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes, &wm); //printf("\tdeduceType m = %d\n", m); - //if (tf->hasWild()) - // printf("\twildmatch = x%x m = %d\n", wildmatch, m); + //printf("\twildmatch = x%x m = %d\n", wildmatch, m); + wildmatch |= wm; /* If no match, see if there's a conversion to a delegate */ @@ -1483,9 +1497,7 @@ Lretry: * 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); + Expression *e = resolveAliasThis(sc, farg); if (!global.endGagging(olderrors)) { farg = e; goto Lretry; @@ -1542,19 +1554,11 @@ Lretry: 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; - } + + Expression *e = fe->inferType(tp, 1, parameters); + if (!e) + goto Lnomatch; + arg = e; } MATCH m; @@ -1897,11 +1901,10 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, goto Lerror; } - MATCH m; Objects dedargs; FuncDeclaration *fd = NULL; - m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); + MATCH m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); //printf("deduceFunctionTemplateMatch = %d\n", m); if (!m) // if no match continue; @@ -1930,9 +1933,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, goto Lerror; } { - tdargs->setDim(dedargs.dim); - memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *)); - fd = td->doHeaderInstantiation(sc, tdargs, fargs); + fd = td->doHeaderInstantiation(sc, &dedargs, fargs); if (!fd) goto Lerror; } @@ -1985,13 +1986,14 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, if (!td_best) { if (!(flags & 1)) - error(loc, "does not match any function template declaration"); + ::error(loc, "%s %s.%s does not match any function template declaration", + kind(), parent->toPrettyChars(), ident->toChars()); goto Lerror; } if (td_ambig) { - error(loc, "%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - toChars(), + ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", + kind(), parent->toPrettyChars(), ident->toChars(), td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); } @@ -2005,6 +2007,16 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, fd_best = ti->toAlias()->isFuncDeclaration(); if (!fd_best || !((TypeFunction*)fd_best->type)->callMatch(ethis, fargs, flags)) goto Lerror; + + /* As Bugzilla 3682 shows, a template instance can be matched while instantiating + * that same template. Thus, the function type can be incomplete. Complete it. + */ + { TypeFunction *tf = (TypeFunction *)fd_best->type; + assert(tf->ty == Tfunction); + if (tf->next) + fd_best->type = tf->semantic(loc, sc); + } + return fd_best; Lerror: @@ -2028,8 +2040,13 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, OutBuffer buf; argExpTypesToCBuffer(&buf, fargs, &hgs); - error(loc, "cannot deduce template function from argument types !(%s)(%s)", - bufa.toChars(), buf.toChars()); + if (this->overnext) + ::error(loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", + kind(), parent->toPrettyChars(), ident->toChars(), + bufa.toChars(), buf.toChars()); + else + error("cannot deduce template function from argument types !(%s)(%s)", + bufa.toChars(), buf.toChars()); } return NULL; } @@ -2225,7 +2242,7 @@ int templateParameterLookup(Type *tparam, TemplateParameters *parameters) * Foo!(int*) // template instantiation * Input: * this = int* - * tparam = T + * tparam = T* * parameters = [ T:T* ] // Array of TemplateParameter's * Output: * dedtypes = [ int ] // Array of Expression/Type's @@ -2287,13 +2304,17 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, { switch (X(tparam->mod, mod)) { - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): case X(MODwild, 0): + case X(MODwild, MODshared): case X(MODwild, MODconst): + case X(MODwild, MODconst | MODshared): case X(MODwild, MODimmutable): + case X(MODwild, MODwild): + case X(MODwild, MODwild | MODshared): case X(MODwild | MODshared, MODshared): case X(MODwild | MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODimmutable): + case X(MODwild | MODshared, MODwild | MODshared): if (!at) { @@ -2407,11 +2428,18 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, } break; + case X(MODconst, MODshared): + // foo(U:const(U)) shared(T) => shared(T) + if (!at) + { (*dedtypes)[i] = tt; + goto Lconst; + } + break; + case X(MODimmutable, 0): case X(MODimmutable, MODconst): case X(MODimmutable, MODshared): case X(MODimmutable, MODconst | MODshared): - case X(MODconst, MODshared): case X(MODshared, 0): case X(MODshared, MODconst): case X(MODshared, MODimmutable): @@ -2534,6 +2562,23 @@ Lconst: #endif } +#if DMDV2 +MATCH TypeVector::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes, unsigned *wildmatch) +{ +#if 0 + printf("TypeVector::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + if (tparam->ty == Tvector) + { TypeVector *tp = (TypeVector *)tparam; + return basetype->deduceType(sc, tp->basetype, parameters, dedtypes, wildmatch); + } + return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); +} +#endif + #if DMDV2 MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) @@ -3825,7 +3870,16 @@ void TemplateValueParameter::declareParameter(Scope *sc) void TemplateValueParameter::semantic(Scope *sc) { + bool wasSame = (sparam->type == valType); sparam->semantic(sc); + if (sparam->type == Type::terror && wasSame) + { /* If sparam has a type error, avoid duplicate errors + * The simple solution of leaving that function if sparam->type == Type::terror + * doesn't quite work because it causes failures in xtest46 for bug 6295 + */ + valType = Type::terror; + return; + } valType = valType->semantic(loc, sc); if (!(valType->isintegral() || valType->isfloating() || valType->isString()) && valType->ty != Tident) @@ -3834,6 +3888,7 @@ void TemplateValueParameter::semantic(Scope *sc) error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars()); } +#if 0 // defer semantic analysis to arg match if (specValue) { Expression *e = specValue; @@ -3846,7 +3901,6 @@ void TemplateValueParameter::semantic(Scope *sc) //e->toInteger(); } -#if 0 // defer semantic analysis to arg match if (defaultValue) { Expression *e = defaultValue; @@ -3883,8 +3937,8 @@ Lnomatch: } -MATCH TemplateValueParameter::matchArg(Scope *sc, Objects *tiargs, - size_t i, TemplateParameters *parameters, Objects *dedtypes, +MATCH TemplateValueParameter::matchArg(Scope *sc, + Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) { //printf("TemplateValueParameter::matchArg()\n"); @@ -3941,7 +3995,7 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, Objects *tiargs, Expression *e = specValue; e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); + e = e->implicitCastTo(sc, vt); e = e->optimize(WANTvalue | WANTinterpret); ei = ei->syntaxCopy(); @@ -4199,13 +4253,12 @@ TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) this->tinst = NULL; this->argsym = NULL; this->aliasdecl = NULL; - this->semanticRun = 0; + this->semanticRun = PASSinit; this->semantictiargsdone = 0; this->withsym = NULL; this->nest = 0; this->havetempdecl = 0; this->isnested = NULL; - this->errors = 0; this->speculative = 0; this->ignore = true; @@ -4234,13 +4287,12 @@ TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *ti this->tinst = NULL; this->argsym = NULL; this->aliasdecl = NULL; - this->semanticRun = 0; + this->semanticRun = PASSinit; this->semantictiargsdone = 1; this->withsym = NULL; this->nest = 0; this->havetempdecl = 1; this->isnested = NULL; - this->errors = 0; this->speculative = 0; this->ignore = true; @@ -4289,23 +4341,96 @@ void TemplateInstance::semantic(Scope *sc) semantic(sc, NULL); } +void TemplateInstance::expandMembers(Scope *sc2) +{ + 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]; + //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); + //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); +// if (isnested) +// s->parent = sc->parent; + //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); + s->semantic(sc2); + //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); + sc2->module->runDeferredSemantic(); + } +} + +void TemplateInstance::tryExpandMembers(Scope *sc2) +{ + static int nest; + // extracted to a function to allow windows SEH to work without destructors in the same function + //printf("%d\n", nest); + if (++nest > 500) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + +#if WINDOWS_SEH + if(nest == 1) + { + // do not catch at every nesting level, because generating the output error might cause more stack + // errors in the __except block otherwise + __try + { + expandMembers(sc2); + } + __except (__ehfilter(GetExceptionInformation())) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + } + else +#endif + expandMembers(sc2); + nest--; +} + +void TemplateInstance::trySemantic3(Scope *sc2) +{ + // extracted to a function to allow windows SEH to work without destructors in the same function + static int nest; + if (++nest > 300) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } +#if WINDOWS_SEH + if(nest == 1) + { + // do not catch at every nesting level, because generating the output error might cause more stack + // errors in the __except block otherwise + __try + { + semantic3(sc2); + } + __except (__ehfilter(GetExceptionInformation())) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + } + else +#endif + semantic3(sc2); + + --nest; +} + void TemplateInstance::semantic(Scope *sc, Expressions *fargs) { //printf("TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", toChars(), this, global.gag, sc); - if (global.errors && name != Id::AssociativeArray) - { - //printf("not instantiating %s due to %d errors\n", toChars(), global.errors); - if (!global.gag) - { - /* Trying to soldier on rarely generates useful messages - * at this point. - */ - fatal(); - } -// return; - } - if (!sc->ignoreTemplates) - ignore = false; #if LOG printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); #endif @@ -4316,11 +4441,15 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) #endif return; } + + if (!sc->ignoreTemplates) + ignore = false; + // get the enclosing template instance from the scope tinst tinst = sc->tinst; - if (semanticRun != 0) + if (semanticRun != PASSinit) { #if LOG printf("Recursive template expansion\n"); @@ -4329,7 +4458,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) // inst = this; return; } - semanticRun = 1; + semanticRun = PASSsemantic; #if IN_LLVM // get the enclosing template instance from the scope tinst tinst = sc->tinst; @@ -4368,11 +4497,11 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) //printf("error return %p, %d\n", tempdecl, global.errors); return; // error recovery } - + unsigned errs = global.errors; tempdecl = findTemplateDeclaration(sc); if (tempdecl) tempdecl = findBestMatch(sc, fargs); - if (!tempdecl || global.errors) + if (!tempdecl || (errs != global.errors)) { inst = this; //printf("error return %p, %d\n", tempdecl, global.errors); return; // error recovery @@ -4403,10 +4532,8 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) //printf("test2 isnested %s ti->isnested %s\n", isnested ? isnested->toChars() : "", ti->isnested ? ti->isnested->toChars() : ""); continue; } -#if 0 - if (isnested && sc->parent != ti->parent) - continue; -#endif + //printf("parent = %s, ti->parent = %s\n", tempdecl->parent->toPrettyChars(), ti->parent->toPrettyChars()); + if (!arrayObjectMatch(&tdtypes, &ti->tdtypes, tempdecl, sc)) goto L1; @@ -4463,7 +4590,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) } #if LOG - printf("\tit's a match with instance %p\n", inst); + printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun); #endif return; @@ -4480,7 +4607,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) unsigned errorsave = global.errors; inst = this; // Mark as speculative if we are instantiated from inside is(typeof()) - if (global.gag && sc->intypeof) + if (global.gag && sc->speculative) speculative = 1; int tempdecl_instance_idx = tempdecl->instances.dim; @@ -4651,46 +4778,9 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) sc2->parent = /*isnested ? sc->parent :*/ this; sc2->tinst = this; -#if WINDOWS_SEH - __try - { -#endif - static int nest; - //printf("%d\n", nest); - if (++nest > 500) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } + tryExpandMembers(sc2); - 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]; - //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); - //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); -// if (isnested) -// s->parent = sc->parent; - //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - s->semantic(sc2); - //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - sc2->module->runDeferredSemantic(); - } - --nest; -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } -#endif + semanticRun = PASSsemanticdone; /* If any of the instantiation members didn't get semantic() run * on them due to forward references, we cannot run semantic2() @@ -4744,28 +4834,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) if (sc->func || dosemantic3) { -#if WINDOWS_SEH - __try - { -#endif - static int nest; - if (++nest > 300) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - semantic3(sc2); - --nest; -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } -#endif + trySemantic3(sc2); } Laftersemantic: @@ -4795,7 +4864,7 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) assert(target_symbol_list->tdata()[target_symbol_list_idx] == this); target_symbol_list->remove(target_symbol_list_idx); } - semanticRun = 0; + semanticRun = PASSinit; inst = NULL; } } @@ -5172,13 +5241,14 @@ TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc, Expressions *far // Only one template, so we can give better error message error("%s does not match template declaration %s", toChars(), tempdecl->toChars()); else - error("%s does not match any template declaration", toChars()); + ::error(loc, "%s %s.%s does not match any template declaration", + tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars()); return NULL; } if (td_ambig) { - error("%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - toChars(), + ::error(loc, "%s %s.%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", + td_best->kind(), td_best->parent->toPrettyChars(), td_best->ident->toChars(), td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); } @@ -5237,6 +5307,11 @@ int TemplateInstance::hasNestedArgs(Objects *args) sa = ((VarExp *)ea)->var; goto Lsa; } + if (ea->op == TOKthis) + { + sa = ((ThisExp *)ea)->var; + goto Lsa; + } if (ea->op == TOKfunction) { sa = ((FuncExp *)ea)->fd; @@ -5309,7 +5384,7 @@ Identifier *TemplateInstance::genIdent(Objects *args) //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); char *id = tempdecl->ident->toChars(); - buf.printf("__T%zu%s", strlen(id), id); + buf.printf("__T%llu%s", (ulonglong)strlen(id), id); for (size_t i = 0; i < args->dim; i++) { Object *o = args->tdata()[i]; Type *ta = isType(o); @@ -5325,7 +5400,8 @@ Identifier *TemplateInstance::genIdent(Objects *args) else { #ifdef DEBUG - printf("ta = %d, %s\n", ta->ty, ta->toChars()); + if (!global.errors) + printf("ta = %d, %s\n", ta->ty, ta->toChars()); #endif assert(global.errors); } @@ -5358,8 +5434,9 @@ Identifier *TemplateInstance::genIdent(Objects *args) continue; } // Now that we know it is not an alias, we MUST obtain a value + unsigned olderr = global.errors; ea = ea->optimize(WANTvalue | WANTinterpret); - if (ea->op == TOKerror) + if (ea->op == TOKerror || olderr != global.errors) continue; #if 1 /* Use deco that matches what it would be for a function parameter @@ -5404,7 +5481,7 @@ Identifier *TemplateInstance::genIdent(Objects *args) * Unfortunately, fixing this ambiguity will break existing binary * compatibility and the demanglers, so we'll leave it as is. */ - buf.printf("%zu%s", strlen(p), p); + buf.printf("%llu%s", (ulonglong)strlen(p), p); } else if (va) { @@ -5477,12 +5554,33 @@ int TemplateInstance::needsTypeInference(Scope *sc) /* Determine if the instance arguments, tiargs, are all that is necessary * to instantiate the template. */ - TemplateTupleParameter *tp = td->isVariadic(); //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); TypeFunction *fdtype = (TypeFunction *)fd->type; - if (Parameter::dim(fdtype->parameters) && - ((tp && td->parameters->dim > 1) || tiargs->dim < td->parameters->dim)) - return TRUE; + if (Parameter::dim(fdtype->parameters)) + { + TemplateParameter *tp = td->isVariadic(); + if (tp && td->parameters->dim > 1) + return TRUE; + + if (tiargs->dim < td->parameters->dim) + { // Can remain tiargs be filled by default arguments? + for (size_t i = tiargs->dim; i < td->parameters->dim; i++) + { tp = (*td->parameters)[i]; + if (TemplateTypeParameter *ttp = tp->isTemplateTypeParameter()) + { if (!ttp->defaultType) + return TRUE; + } + else if (TemplateAliasParameter *tap = tp->isTemplateAliasParameter()) + { if (!tap->defaultAlias) + return TRUE; + } + else if (TemplateValueParameter *tvp = tp->isTemplateValueParameter()) + { if (!tvp->defaultValue) + return TRUE; + } + } + } + } /* If there is more than one function template which matches, we may * need type inference (see Bugzilla 4430) */ @@ -5496,9 +5594,9 @@ int TemplateInstance::needsTypeInference(Scope *sc) void TemplateInstance::semantic2(Scope *sc) { int i; - if (semanticRun >= 2) + if (semanticRun >= PASSsemantic2) return; - semanticRun = 2; + semanticRun = PASSsemantic2; #if LOG printf("+TemplateInstance::semantic2('%s')\n", toChars()); #endif @@ -5531,9 +5629,9 @@ void TemplateInstance::semantic3(Scope *sc) printf("TemplateInstance::semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun); #endif //if (toChars()[0] == 'D') *(char*)0=0; - if (semanticRun >= 3) + if (semanticRun >= PASSsemantic3) return; - semanticRun = 3; + semanticRun = PASSsemantic3; if (!errors && members) { sc = tempdecl->scope; @@ -5702,7 +5800,7 @@ void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { if (i) buf->writeByte(','); - Object *oarg = args->tdata()[i]; + Object *oarg = (*args)[i]; ObjectToCBuffer(buf, hgs, oarg); } nest--; @@ -5717,9 +5815,24 @@ Dsymbol *TemplateInstance::toAlias() printf("TemplateInstance::toAlias()\n"); #endif if (!inst) - { error("cannot resolve forward reference"); - errors = 1; - return this; + { + // Maybe we can resolve it + if (scope) + { + /* Anything that affects scope->offset must be + * done in lexical order. Fwd ref error if it is affected, otherwise allow. + */ + unsigned offset = scope->offset; + Scope *sc = scope; + semantic(scope); +// if (offset != sc->offset) +// inst = NULL; // trigger fwd ref error + } + if (!inst) + { error("cannot resolve forward reference"); + errors = 1; + return this; + } } if (inst != this) @@ -5851,7 +5964,7 @@ void TemplateMixin::semantic(Scope *sc) // This for when a class/struct contains mixin members, and // is done over because of forward references if (parent && toParent()->isAggregateDeclaration()) - semanticRun = 1; // do over + semanticRun = PASSsemantic; // do over else { #if LOG @@ -5861,12 +5974,12 @@ void TemplateMixin::semantic(Scope *sc) } } if (!semanticRun) - semanticRun = 1; + semanticRun = PASSsemantic; #if LOG printf("\tdo semantic\n"); #endif -#if !IN_LLVM +#if !IN_LLVM && !IN_GCC // dont know what this is util_progress(); #endif @@ -5944,10 +6057,10 @@ void TemplateMixin::semantic(Scope *sc) * runDeferred will re-run mixin's semantic outside of the struct's * semantic. */ - semanticRun = 0; + semanticRun = PASSinit; AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); if (ad) - ad->sizeok = 2; + ad->sizeok = SIZEOKfwd; else { // Forward reference @@ -5992,11 +6105,11 @@ void TemplateMixin::semantic(Scope *sc) continue; for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = tiargs->tdata()[i]; + { Object *o = (*tiargs)[i]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); - Object *tmo = tm->tiargs->tdata()[i]; + Object *tmo = (*tm->tiargs)[i]; if (ta) { Type *tmta = isType(tmo); @@ -6060,10 +6173,8 @@ void TemplateMixin::semantic(Scope *sc) declareParameters(argscope); // Add members to enclosing scope, as well as this scope - for (unsigned i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = members->tdata()[i]; + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; s->addMember(argscope, this, i); //sc->insert(s); //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); @@ -6089,7 +6200,7 @@ void TemplateMixin::semantic(Scope *sc) for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->semantic(sc2); } @@ -6131,9 +6242,9 @@ void TemplateMixin::semantic(Scope *sc) void TemplateMixin::semantic2(Scope *sc) { - if (semanticRun >= 2) + if (semanticRun >= PASSsemantic2) return; - semanticRun = 2; + semanticRun = PASSsemantic2; #if LOG printf("+TemplateMixin::semantic2('%s')\n", toChars()); #endif @@ -6144,7 +6255,7 @@ void TemplateMixin::semantic2(Scope *sc) sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; #if LOG printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); #endif @@ -6160,9 +6271,9 @@ void TemplateMixin::semantic2(Scope *sc) void TemplateMixin::semantic3(Scope *sc) { - if (semanticRun >= 3) + if (semanticRun >= PASSsemantic3) return; - semanticRun = 3; + semanticRun = PASSsemantic3; #if LOG printf("TemplateMixin::semantic3('%s')\n", toChars()); #endif @@ -6195,6 +6306,22 @@ int TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident) return Dsymbol::oneMember(ps, ident); } +int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param) +{ + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + if (s) + { + if (s->apply(fp, param)) + return 1; + } + } + } + return 0; +} + int TemplateMixin::hasPointers() { //printf("TemplateMixin::hasPointers() %s\n", toChars()); @@ -6212,6 +6339,17 @@ int TemplateMixin::hasPointers() return 0; } +void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) +{ + if (members) + { + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (*members)[i]; + s->setFieldOffset(ad, poffset, isunion); + } + } +} + char *TemplateMixin::toChars() { OutBuffer buf; diff --git a/dmd2/template.h b/dmd2/template.h index b659b46b..811bdcbf 100644 --- a/dmd2/template.h +++ b/dmd2/template.h @@ -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 @@ -41,6 +41,7 @@ struct AliasDeclaration; struct FuncDeclaration; struct HdrGenState; enum MATCH; +enum PASS; struct Tuple : Object { @@ -61,7 +62,7 @@ struct TemplateDeclaration : ScopeDsymbol TemplateDeclaration *overnext; // next overloaded TemplateDeclaration TemplateDeclaration *overroot; // first in overnext list - int semanticRun; // 1 semantic() run + enum PASS semanticRun; // 1 semantic() run Dsymbol *onemember; // if !=NULL then one member of this template @@ -190,8 +191,6 @@ struct TemplateThisParameter : TemplateTypeParameter /* Syntax: * this ident : specType = defaultType */ - Type *specType; // type parameter: if !=NULL, this is the type specialization - Type *defaultType; TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); @@ -299,12 +298,11 @@ struct TemplateInstance : ScopeDsymbol AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its // sole member WithScopeSymbol *withsym; // if a member of a with statement - int semanticRun; // has semantic() been done? + enum PASS semanticRun; // has semantic() been done? int semantictiargsdone; // has semanticTiargs() been done? int nest; // for recursion detection int havetempdecl; // 1 if used second constructor Dsymbol *isnested; // if referencing local symbols, this is the context - int errors; // 1 if compiled with errors int speculative; // 1 if only instantiated with errors gagged bool ignore; // true if the instance must be ignored when codegen'ing #ifdef IN_GCC @@ -344,6 +342,9 @@ struct TemplateInstance : ScopeDsymbol void declareParameters(Scope *sc); int hasNestedArgs(Objects *tiargs); Identifier *genIdent(Objects *args); + void expandMembers(Scope *sc); + void tryExpandMembers(Scope *sc); + void trySemantic3(Scope *sc2); TemplateInstance *isTemplateInstance() { return this; } AliasDeclaration *isAliasDeclaration(); @@ -369,7 +370,9 @@ struct TemplateMixin : TemplateInstance void inlineScan(); const char *kind(); int oneMember(Dsymbol **ps, Identifier *ident); + int apply(Dsymbol_apply_ft_t fp, void *param); int hasPointers(); + void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion); char *toChars(); char *mangle(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); diff --git a/dmd2/traits.c b/dmd2/traits.c index ee3fa3ff..18e38ecb 100644 --- a/dmd2/traits.c +++ b/dmd2/traits.c @@ -64,10 +64,10 @@ static int fptraits(void *param, FuncDeclaration *f) if (p->e1->op == TOKdotvar) { DotVarExp *dve = (DotVarExp *)p->e1; - e = new DotVarExp(0, dve->e1, f); + e = new DotVarExp(0, dve->e1, new FuncAliasDeclaration(f, 0)); } else - e = new DsymbolExp(0, f); + e = new DsymbolExp(0, new FuncAliasDeclaration(f, 0)); p->exps->push(e); return 0; } @@ -451,6 +451,10 @@ Expression *TraitsExp::semantic(Scope *sc) Expression *e; unsigned errors = global.startGagging(); + unsigned oldspec = global.speculativeGag; + global.speculativeGag = global.gag; + bool scSpec = sc->speculative; + sc->speculative = true; Type *t = isType(o); if (t) @@ -471,6 +475,8 @@ Expression *TraitsExp::semantic(Scope *sc) } } + sc->speculative = scSpec; + global.speculativeGag = oldspec; if (global.endGagging(errors)) { goto Lfalse; diff --git a/dmd2/vcbuild/alloca.h b/dmd2/vcbuild/alloca.h new file mode 100644 index 00000000..c0d7985b --- /dev/null +++ b/dmd2/vcbuild/alloca.h @@ -0,0 +1 @@ +#include diff --git a/dmd2/vcbuild/builddmd.bat b/dmd2/vcbuild/builddmd.bat new file mode 100644 index 00000000..b355610d --- /dev/null +++ b/dmd2/vcbuild/builddmd.bat @@ -0,0 +1,13 @@ +@echo off +rem Run this batch file from the src folder like this: +rem vcbuild\builddmd.bat +rem +rem Make sure that you do not have cl.exe from the dmc compiler +rem in your path! +rem +rem "make" should be the Digital Mars make, this can be found +rem if dmd's bin folder is in the path + +set DEBUG=/Zi +if "%1" == "release" set DEBUG=/O2 +make -f win32.mak CC=vcbuild\dmc_cl INCLUDE=vcbuild DEBUG=%DEBUG% dmd.exe diff --git a/dmd2/vcbuild/dmc_cl.bat b/dmd2/vcbuild/dmc_cl.bat new file mode 100644 index 00000000..f6dab6a2 --- /dev/null +++ b/dmd2/vcbuild/dmc_cl.bat @@ -0,0 +1,44 @@ +@echo off +rem echo called with: %* +set def=/DLITTLE_ENDIAN=1 /D__pascal= /D_M_I86=1 +rem copt defaults to linker options +set copt=/nologo /link /LARGEADDRESSAWARE +set cmd= +:next +if "%1" == "" goto done +rem echo %1 + +set opt=%1 +if "%opt:~0,1%" == "-" goto opt +if "%opt:~0,1%" == "/" goto opt + +if "%opt:~-2%" == ".c" goto isC +if "%opt:~-4%" == ".obj" goto add +set opt=%opt%.c +:isC +set copt=/TP /Ivcbuild /Iroot /nologo /EHsc /Zp1 %def% +goto add + +:opt +if "%opt:~0,2%" == "-o" ( + if "%opt:~-4%" == ".exe" set opt=/Fe%opt:~2% + if "%opt:~-4%" == ".obj" set opt=/Fo%opt:~2% +) +if "%opt%" == "-e" goto shift +if "%opt%" == "-Ae" goto shift +if "%opt%" == "-Ar" goto shift +if "%opt%" == "-mn" goto shift +if "%opt%" == "-cpp" goto shift +if "%opt%" == "-wx" goto shift +if "%opt%" == "-m32" goto shift + +:add +set cmd=%cmd% %opt% + +:shift +shift +goto next + +:done +rem echo cl %copt% %cmd% +cl %cmd% %copt% diff --git a/dmd2/vcbuild/fenv.h b/dmd2/vcbuild/fenv.h new file mode 100644 index 00000000..e8ccb9ce --- /dev/null +++ b/dmd2/vcbuild/fenv.h @@ -0,0 +1,5 @@ + +#include + +#define isnan _isnan + diff --git a/dmd2/vcbuild/ldfpu.asm b/dmd2/vcbuild/ldfpu.asm new file mode 100644 index 00000000..c7958d69 --- /dev/null +++ b/dmd2/vcbuild/ldfpu.asm @@ -0,0 +1,336 @@ +;; Compiler implementation of the D programming language +;; Copyright (c) 1999-2011 by Digital Mars +;; All Rights Reserved +;; written by Rainer Schuetze +;; 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. + +;; 80 bit floating point value implementation for Microsoft compiler + +;.386 +;.model flat, c + +; Custom Build Step, including a listing file placed in intermediate directory +; debug: +; ml -c -Zi "-Fl$(IntDir)\$(InputName).lst" "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)" +; release: +; ml -c "-Fl$(IntDir)\$(InputName).lst" "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)" +; outputs: +; $(IntDir)\$(InputName).obj + +.data + +twoPow63 dd 0, 80000000h, 03fffh + 63 + +.code + +; double ld_read(longdouble* ld); +; rcx: ld +ld_read PROC + fld tbyte ptr [rcx] + push rax + fstp qword ptr [esp] + movq xmm0,qword ptr [rsp] + pop rax + ret +ld_read ENDP + +; long long ld_readll(longdouble* ld); +; rcx: ld +ld_readll PROC + fld tbyte ptr [rcx] + push rax + fistp qword ptr [esp] + pop rax + ret +ld_readll ENDP + +; unsigned long long ld_readull(longdouble* ld); +; rcx: ld +ld_readull PROC + fld tbyte ptr [rcx] + push rax + lea rax,twoPow63 + fld tbyte ptr [rax] + fsubp ST(1),ST(0) ; move it into signed range + fistp qword ptr [esp] + pop rax + btc rax,63 + ret +ld_readull ENDP + +; void ld_set(longdouble* ld, double d); +; rcx: ld +; xmm1: d +ld_set PROC + push rax + movq qword ptr [rsp],xmm1 + fld qword ptr [rsp] + fstp tbyte ptr [rcx] + pop rax + ret +ld_set ENDP + +; void ld_setll(longdouble* ld, long long d); +; rcx: ld +; rdx: d +ld_setll PROC + push rdx + fild qword ptr [esp] + fstp tbyte ptr [rcx] + pop rax + ret +ld_setll ENDP + +; void ld_setull(longdouble* ld, long long d); +; rcx: ld +; rax: d +ld_setull PROC + btc rdx,63 + push rdx + fild qword ptr [esp] + lea rax,twoPow63 + fld tbyte ptr [rax] + faddp ST(1),ST(0) + fstp tbyte ptr [rcx] + pop rax + ret +ld_setull ENDP + +; void ld_expl(longdouble* ld, int exp); +; rcx: ld +; edx: exp +ld_expl PROC + push rdx + fild dword ptr [esp] + fld tbyte ptr [rcx] + fscale ; ST(0) = ST(0) * (2**ST(1)) + fstp ST(1) + fstp tbyte ptr [rcx] + pop rax + ret +ld_expl ENDP + +; long_double ld_add(long_double ld1, long_double ld2); +; rcx: &res +; rdx: &ld1 +; r8: &ld2 +ld_add PROC + fld tbyte ptr [r8] + fld tbyte ptr [rdx] + fadd + fstp tbyte ptr [rcx] + mov rax,rcx + ret +ld_add ENDP + +; long_double ld_sub(long_double ld1, long_double ld2); +; rcx: &res +; rdx: &ld1 +; r8: &ld2 +ld_sub PROC + fld tbyte ptr [rdx] + fld tbyte ptr [r8] + fsub + fstp tbyte ptr [rcx] + mov rax,rcx + ret +ld_sub ENDP + +; long_double ld_mul(long_double ld1, long_double ld2); +; rcx: &res +; rdx: &ld1 +; r8: &ld2 +ld_mul PROC + fld tbyte ptr [r8] + fld tbyte ptr [rdx] + fmul + fstp tbyte ptr [rcx] + mov rax,rcx + ret +ld_mul ENDP + +; long_double ld_div(long_double ld1, long_double ld2); +; rcx: &res +; rdx: &ld1 +; r8: &ld2 +ld_div PROC + fld tbyte ptr [rdx] + fld tbyte ptr [r8] + fdiv + fstp tbyte ptr [rcx] + mov rax,rcx + ret +ld_div ENDP + +; long_double ld_mod(long_double ld1, long_double ld2); +; rcx: &res +; rdx: &ld1 +; r8: &ld2 +ld_mod PROC + push rax + fld tbyte ptr [r8] + fld tbyte ptr [rdx] ; ST = x, ST1 = y +FM1: ; We don't use fprem1 because for some inexplicable + ; reason we get -5 when we do _modulo(15, 10) + fprem ; ST = ST % ST1 + fstsw word ptr [rsp] + fwait + mov AH,byte ptr [rsp+1] ; get msb of status word in AH + sahf ; transfer to flags + jp FM1 ; continue till ST < ST1 + fstp ST(1) ; leave remainder on stack + fstp tbyte ptr [ecx] + pop rax + mov rax,rcx + ret +ld_mod ENDP + +; bool ld_cmpb(long_double x, long_double y); +; rcx: &x +; rdx: &y +ld_cmpb PROC + fld tbyte ptr [rdx] + fld tbyte ptr [rcx] + fucomip ST(0),ST(1) + setb AL + setnp AH + and AL,AH + fstp ST(0) + ret +ld_cmpb ENDP + +; bool ld_cmpbe(long_double x, long_double y); +; rcx: &x +; rdx: &y +ld_cmpbe PROC + fld tbyte ptr [rdx] + fld tbyte ptr [rcx] + fucomip ST(0),ST(1) + setbe AL + setnp AH + and AL,AH + fstp ST(0) + ret +ld_cmpbe ENDP + +; bool ld_cmpa(long_double x, long_double y); +; rcx: &x +; rdx: &y +ld_cmpa PROC + fld tbyte ptr [rdx] + fld tbyte ptr [rcx] + fucomip ST(0),ST(1) + seta AL + setnp AH + and AL,AH + fstp ST(0) + ret +ld_cmpa ENDP + +; bool ld_cmpae(long_double x, long_double y); +; rcx: &x +; rdx: &y +ld_cmpae PROC + fld tbyte ptr [rdx] + fld tbyte ptr [rcx] + fucomip ST(0),ST(1) + setae AL + setnp AH + and AL,AH + fstp ST(0) + ret +ld_cmpae ENDP + +; bool ld_cmpe(long_double x, long_double y); +; rcx: &x +; rdx: &y +ld_cmpe PROC + fld tbyte ptr [rdx] + fld tbyte ptr [rcx] + fucomip ST(0),ST(1) + sete AL + setnp AH + and AL,AH + fstp ST(0) + ret +ld_cmpe ENDP + +; bool ld_cmpne(long_double x, long_double y); +; rcx: &x +; rdx: &y +ld_cmpne PROC + fld tbyte ptr [rdx] + fld tbyte ptr [rcx] + fucomip ST(0),ST(1) + setne AL + setp AH + or AL,AH + fstp ST(0) + ret +ld_cmpne ENDP + +; long_double ld_sqrt(long_double x); +; rcx: &res +; rdx: &x +ld_sqrt PROC + fld tbyte ptr [rdx] + fsqrt + fstp tbyte ptr [rcx] + mov rax,rcx + ret +ld_sqrt ENDP + +; long_double ld_sin(long_double x); +; rcx: &res +; rdx: &x +ld_sin PROC + fld tbyte ptr [rdx] + fsin + fstp tbyte ptr [rcx] + mov rax,rcx + ret +ld_sin ENDP + +; long_double ld_cos(long_double x); +; rcx: &res +; rdx: &x +ld_cos PROC + fld tbyte ptr [rdx] + fcos + fstp tbyte ptr [rcx] + mov rax,rcx + ret +ld_cos ENDP + +; long_double ld_tan(long_double x); +; rcx: &res +; rdx: &x +ld_tan PROC + fld tbyte ptr [rdx] + fptan + fstp st(0) + fstp tbyte ptr [rcx] + mov rax,rcx + ret +ld_tan ENDP + +; int ld_initfpu(int bits, int mask) +; ecx: bits +; edx: mask +ld_initfpu PROC + push rcx + fstcw word ptr [rsp] + movzx EAX,word ptr [rsp] ; also return old CW in EAX + not EDX + and EDX,EAX + or ECX,EDX + mov dword ptr [rsp],ECX + fldcw word ptr [rsp] + pop rcx + ret +ld_initfpu ENDP + +end diff --git a/dmd2/vcbuild/stdint.h b/dmd2/vcbuild/stdint.h new file mode 100644 index 00000000..57db989c --- /dev/null +++ b/dmd2/vcbuild/stdint.h @@ -0,0 +1,206 @@ +/* ISO C9x 7.18 Integer types + * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * Contributor: Danny Smith + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Date: 2000-12-02 + */ + + +#ifndef _STDINT_H +#define _STDINT_H +#define __need_wint_t +#define __need_wchar_t +#include + +/* 7.18.1.1 Exact-width integer types */ +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; + +/* 7.18.1.2 Minimum-width integer types */ +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +typedef short int_least16_t; +typedef unsigned short uint_least16_t; +typedef int int_least32_t; +typedef unsigned uint_least32_t; +typedef long long int_least64_t; +typedef unsigned long long uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types + * Not actually guaranteed to be fastest for all purposes + * Here we use the exact-width types for 8 and 16-bit ints. + */ +typedef char int_fast8_t; +typedef unsigned char uint_fast8_t; +typedef short int_fast16_t; +typedef unsigned short uint_fast16_t; +typedef int int_fast32_t; +typedef unsigned int uint_fast32_t; +typedef long long int_fast64_t; +typedef unsigned long long uint_fast64_t; + +/* 7.18.1.4 Integer types capable of holding object pointers */ + +#ifndef _INTPTR_T_DEFINED +#define _INTPTR_T_DEFINED +#ifdef _WIN64 + typedef __int64 intptr_t; +#else + typedef int intptr_t; +#endif +#endif + +#ifndef _UINTPTR_T_DEFINED +#define _UINTPTR_T_DEFINED +#ifdef _WIN64 + typedef unsigned __int64 uintptr_t; +#else + typedef unsigned int uintptr_t; +#endif +#endif + +/* 7.18.1.5 Greatest-width integer types */ +typedef long long intmax_t; +typedef unsigned long long uintmax_t; + +/* 7.18.2 Limits of specified-width integer types */ +#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) + +/* 7.18.2.1 Limits of exact-width integer types */ +#define INT8_MIN (-128) +#define INT16_MIN (-32768) +#define INT32_MIN (-2147483647 - 1) +#define INT64_MIN (-9223372036854775807LL - 1) + +#define INT8_MAX 127 +#define INT16_MAX 32767 +#define INT32_MAX 2147483647 +#define INT64_MAX 9223372036854775807LL + +#define UINT8_MAX 0xff /* 255U */ +#define UINT16_MAX 0xffff /* 65535U */ +#define UINT32_MAX 0xffffffff /* 4294967295U */ +#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ + +/* 7.18.2.2 Limits of minimum-width integer types */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding + object pointers */ +#ifdef _WIN64 +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX +#else +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#endif + +/* 7.18.2.5 Limits of greatest-width integer types */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* 7.18.3 Limits of other integer types */ +#define PTRDIFF_MIN INTPTR_MIN +#define PTRDIFF_MAX INTPTR_MAX + +#define SIG_ATOMIC_MIN INTPTR_MIN +#define SIG_ATOMIC_MAX INTPTR_MAX + +#define SIZE_MAX UINTPTR_MAX + +#ifndef WCHAR_MIN /* also in wchar.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX 0xffff /* UINT16_MAX */ +#endif + +/* + * wint_t is unsigned short for compatibility with MS runtime + */ +#define WINT_MIN 0 +#define WINT_MAX 0xffff /* UINT16_MAX */ + +#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ + + +/* 7.18.4 Macros for integer constants */ +#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) + +/* 7.18.4.1 Macros for minimum-width integer constants + + Accoding to Douglas Gwyn : + "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC + 9899:1999 as initially published, the expansion was required + to be an integer constant of precisely matching type, which + is impossible to accomplish for the shorter types on most + platforms, because C99 provides no standard way to designate + an integer constant with width less than that of type int. + TC1 changed this to require just an integer constant + *expression* with *promoted* type." +*/ + +#define INT8_C(val) ((int8_t) + (val)) +#define UINT8_C(val) ((uint8_t) + (val##U)) +#define INT16_C(val) ((int16_t) + (val)) +#define UINT16_C(val) ((uint16_t) + (val##U)) + +#define INT32_C(val) val##L +#define UINT32_C(val) val##UL +#define INT64_C(val) val##LL +#define UINT64_C(val) val##ULL + +/* 7.18.4.2 Macros for greatest-width integer constants */ +#define INTMAX_C(val) INT64_C(val) +#define UINTMAX_C(val) UINT64_C(val) + +#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ + +#endif diff --git a/dmd2/vcbuild/warnings.h b/dmd2/vcbuild/warnings.h new file mode 100644 index 00000000..3e60ae6f --- /dev/null +++ b/dmd2/vcbuild/warnings.h @@ -0,0 +1,30 @@ +#pragma warning(disable:4996) // This function or variable may be unsafe. +#pragma warning(disable:4127) // conditional expression is constant +#pragma warning(disable:4101) // unreferenced local variable +#pragma warning(disable:4100) // unreferenced formal parameter +#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned +#pragma warning(disable:4244) // conversion from 'int' to 'unsigned short', possible loss of data +#pragma warning(disable:4245) // conversion from 'int' to 'unsigned int', signed/unsigned mismatch +#pragma warning(disable:4018) // signed/unsigned mismatch +#pragma warning(disable:4389) // signed/unsigned mismatch +#pragma warning(disable:4505) // unreferenced local function has been removed +#pragma warning(disable:4701) // potentially uninitialized local variable 'm' used +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union +#pragma warning(disable:4189) // local variable is initialized but not referenced +#pragma warning(disable:4102) // unreferenced label +#pragma warning(disable:4800) // forcing value to bool 'true' or 'false' (performance warning) +#pragma warning(disable:4390) // ';' : empty controlled statement found; is this the intent? +#pragma warning(disable:4702) // unreachable code +#pragma warning(disable:4703) // potentially uninitialized local pointer variable 'm' used + +#ifdef _WIN64 +#pragma warning(disable:4366) // The result of the unary '&' operator may be unaligned +#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int', possible loss of data +#pragma warning(disable:4310) // cast truncates constant value +#endif + +#define LITTLE_ENDIAN 1 +#define __pascal +#define MARS 1 +#define UNITTEST 1 +#define _M_I86 1 diff --git a/gen/cl_helpers.cpp b/gen/cl_helpers.cpp index 0fdb1dde..6b09c384 100644 --- a/gen/cl_helpers.cpp +++ b/gen/cl_helpers.cpp @@ -1,5 +1,6 @@ #include "gen/cl_helpers.h" +#include "mars.h" #include "root.h" #include "rmem.h" diff --git a/gen/optimizer.cpp b/gen/optimizer.cpp index d3773978..89af52e6 100644 --- a/gen/optimizer.cpp +++ b/gen/optimizer.cpp @@ -12,7 +12,7 @@ #include "llvm/Support/PassNameParser.h" #include "llvm/Transforms/IPO.h" -#include "root.h" // error() +#include "mars.h" // error() #include // strcmp(); using namespace llvm; diff --git a/gen/pragma.cpp b/gen/pragma.cpp index d10f3fc9..d6ed8217 100644 --- a/gen/pragma.cpp +++ b/gen/pragma.cpp @@ -379,6 +379,6 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s, break; default: - warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); + warning(Loc(), "the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); } } diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 037e2208..ae54b345 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -72,7 +72,7 @@ DValue* DtoVaArg(Loc& loc, Type* type, Expression* valistArg) llt = getPtrToType(llt); // issue a warning for broken va_arg instruction. if (global.params.cpu != ARCHx86) - warning("%s: va_arg for C variadic functions is probably broken for anything but x86", loc.toChars()); + warning(Loc(), "%s: va_arg for C variadic functions is probably broken for anything but x86", loc.toChars()); // done return new DImValue(type, gIR->ir->CreateVAArg(expelem->getLVal(), llt, "tmp")); } diff --git a/ir/irtypeclass.cpp b/ir/irtypeclass.cpp index 53cf321e..f725ecf8 100644 --- a/ir/irtypeclass.cpp +++ b/ir/irtypeclass.cpp @@ -306,7 +306,15 @@ std::vector IrTypeClass::buildVtblType(Type* first, Array* vtbl_arr IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); + if (fd->type->nextOf() == NULL) { + // Return type of the virtual function has not been inferred. + // FIXME: is it a frontend bug? + types.push_back(getVoidPtrType()); + continue; + } + types.push_back(DtoType(fd->type->pointerTo())); + } return types; diff --git a/runtime/druntime b/runtime/druntime index 5135dcfe..946b499b 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 5135dcfeca8b11f3b295a84ef7cd8c2fb27e2e8b +Subproject commit 946b499bd64a7c1714baa5627a8b76b1a14859a3 diff --git a/runtime/phobos b/runtime/phobos index 2cc90b12..d8574009 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 2cc90b12a6d21e1d9c674aae3b6475498315f126 +Subproject commit d857400952d9d9d33ac8768c400b61e2ee1abd83