diff --git a/dmd/aggregate.h b/dmd/aggregate.h index 5cac12aa..3ba0306a 100644 --- a/dmd/aggregate.h +++ b/dmd/aggregate.h @@ -66,7 +66,7 @@ struct AggregateDeclaration : ScopeDsymbol Type *handle; // 'this' type unsigned structsize; // size of struct unsigned alignsize; // size of struct for alignment purposes - unsigned structalign; // struct member alignment in effect + structalign_t structalign; // struct member alignment in effect int hasUnions; // set if aggregate has overlapping fields VarDeclarations fields; // VarDeclaration fields enum Sizeok sizeok; // set when structsize contains valid data @@ -102,9 +102,9 @@ struct AggregateDeclaration : ScopeDsymbol void semantic3(Scope *sc); void inlineScan(); unsigned size(Loc loc); - static void alignmember(unsigned salign, unsigned size, unsigned *poffset); + static void alignmember(structalign_t salign, unsigned size, unsigned *poffset); static unsigned placeField(unsigned *nextoffset, - unsigned memsize, unsigned memalignsize, unsigned memalign, + unsigned memsize, unsigned memalignsize, structalign_t memalign, unsigned *paggsize, unsigned *paggalignsize, bool isunion); Type *getType(); int firstFieldInUnion(int indx); // first field in union that includes indx @@ -156,13 +156,19 @@ struct StructDeclaration : AggregateDeclaration int zeroInit; // !=0 if initialize with 0 fill #if DMDV2 int hasIdentityAssign; // !=0 if has identity opAssign + int hasIdentityEquals; // !=0 if has identity opEquals FuncDeclaration *cpctor; // generated copy-constructor, if any - FuncDeclaration *eq; // bool opEquals(ref const T), if any - FuncDeclarations postblits; // Array of postblit functions FuncDeclaration *postblit; // aggregate postblit + + FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals + static FuncDeclaration *xerreq; // object.xopEquals #endif + // For 64 bit Efl function call/return ABI + Type *arg1type; + Type *arg2type; + StructDeclaration(Loc loc, Identifier *id); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); @@ -171,6 +177,7 @@ struct StructDeclaration : AggregateDeclaration char *mangle(); const char *kind(); void finalizeSize(Scope *sc); + bool isPOD(); #if DMDV1 Expression *cloneMembers(); #endif diff --git a/dmd/argtypes.c b/dmd/argtypes.c index 2ed89f3a..1021b390 100644 --- a/dmd/argtypes.c +++ b/dmd/argtypes.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 2010-2011 by Digital Mars +// Copyright (c) 2010-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -27,6 +27,9 @@ #include "aggregate.h" #include "hdrgen.h" +#define tfloat2 tfloat64 +//#define tfloat2 tcomplex32 + /**************************************************** * This breaks a type down into 'simpler' types that can be passed to a function * in registers, and returned in registers. @@ -40,6 +43,10 @@ TypeTuple *Type::toArgTypes() return NULL; // not valid for a parameter } +TypeTuple *TypeError::toArgTypes() +{ + return new TypeTuple(Type::terror); +} TypeTuple *TypeBasic::toArgTypes() { Type *t1 = NULL; @@ -78,7 +85,7 @@ TypeTuple *TypeBasic::toArgTypes() case Tcomplex32: if (global.params.is64bit) - t1 = Type::tfloat64; // weird, eh? + t1 = Type::tfloat2; else { t1 = Type::tfloat64; @@ -87,8 +94,8 @@ TypeTuple *TypeBasic::toArgTypes() break; case Tcomplex64: - //t1 = Type::tfloat64; - //t2 = Type::tfloat64; + t1 = Type::tfloat64; + t2 = Type::tfloat64; break; case Tcomplex80: @@ -124,18 +131,39 @@ TypeTuple *TypeBasic::toArgTypes() return t; } +#if DMDV2 +TypeTuple *TypeVector::toArgTypes() +{ + return new TypeTuple(this); +} +#endif + TypeTuple *TypeSArray::toArgTypes() { #if DMDV2 + if (dim) + { + /* Should really be done as if it were a struct with dim members + * of the array's elements. + * I.e. int[2] should be done like struct S { int a; int b; } + */ + dinteger_t sz = dim->toInteger(); + if (sz == 1) + // T[1] should be passed like T + return next->toArgTypes(); + } return new TypeTuple(); // pass on the stack for efficiency #else - return new TypeTuple(Type::tvoidptr); + return new TypeTuple(); // pass on the stack for efficiency #endif } TypeTuple *TypeDArray::toArgTypes() { - return new TypeTuple(); // pass on the stack for efficiency + /* Should be done as if it were: + * struct S { size_t length; void* ptr; } + */ + return new TypeTuple(Type::tsize_t, Type::tvoidptr); } TypeTuple *TypeAArray::toArgTypes() @@ -145,30 +173,255 @@ TypeTuple *TypeAArray::toArgTypes() TypeTuple *TypePointer::toArgTypes() { - return new TypeTuple(this); + return new TypeTuple(Type::tvoidptr); } TypeTuple *TypeDelegate::toArgTypes() { - return new TypeTuple(); // pass on the stack for efficiency + /* Should be done as if it were: + * struct S { void* ptr; void* funcptr; } + */ + return new TypeTuple(Type::tvoidptr, Type::tvoidptr); +} + +/************************************* + * Convert a floating point type into the equivalent integral type. + */ + +Type *mergeFloatToInt(Type *t) +{ + switch (t->ty) + { + case Tfloat32: + case Timaginary32: + t = Type::tint32; + break; + case Tfloat64: + case Timaginary64: + case Tcomplex32: + t = Type::tint64; + break; + default: +#ifdef DEBUG + printf("mergeFloatToInt() %s\n", t->toChars()); +#endif + assert(0); + } + return t; +} + +/************************************* + * This merges two types into an 8byte type. + */ + +Type *argtypemerge(Type *t1, Type *t2, unsigned offset2) +{ + //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1->toChars() : "", t2 ? t2->toChars() : "", offset2); + if (!t1) + { assert(!t2 || offset2 == 0); + return t2; + } + if (!t2) + return t1; + + unsigned sz1 = t1->size(0); + unsigned sz2 = t2->size(0); + + if (t1->ty != t2->ty && + (t1->ty == Tfloat80 || t2->ty == Tfloat80)) + return NULL; + + // [float,float] => [cfloat] + if (t1->ty == Tfloat32 && t2->ty == Tfloat32 && offset2 == 4) + return Type::tfloat2; + + // Merging floating and non-floating types produces the non-floating type + if (t1->isfloating()) + { + if (!t2->isfloating()) + t1 = mergeFloatToInt(t1); + } + else if (t2->isfloating()) + t2 = mergeFloatToInt(t2); + + Type *t; + + // Pick type with larger size + if (sz1 < sz2) + t = t2; + else + t = t1; + + // If t2 does not lie within t1, need to increase the size of t to enclose both + if (offset2 && sz1 < offset2 + sz2) + { + switch (offset2 + sz2) + { + case 2: + t = Type::tint16; + break; + case 3: + case 4: + t = Type::tint32; + break; + case 5: + case 6: + case 7: + case 8: + t = Type::tint64; + break; + default: + assert(0); + } + } + return t; } TypeTuple *TypeStruct::toArgTypes() { + //printf("TypeStruct::toArgTypes() %s\n", toChars()); + if (!sym->isPOD()) + { + Lmemory: + //printf("\ttoArgTypes() %s => [ ]\n", toChars()); + return new TypeTuple(); // pass on the stack + } + Type *t1 = NULL; + Type *t2 = NULL; d_uns64 sz = size(0); assert(sz < 0xFFFFFFFF); switch ((unsigned)sz) { case 1: - return new TypeTuple(Type::tint8); + t1 = Type::tint8; + break; case 2: - return new TypeTuple(Type::tint16); + t1 = Type::tint16; + break; case 4: - return new TypeTuple(Type::tint32); + t1 = Type::tint32; + break; case 8: - return new TypeTuple(Type::tint64); + t1 = Type::tint64; + break; + case 16: + t1 = NULL; // could be a TypeVector + break; + default: + goto Lmemory; } - return new TypeTuple(); // pass on the stack + if (global.params.is64bit && sym->fields.dim) + { +#if 1 + unsigned sz1 = 0; + unsigned sz2 = 0; + t1 = NULL; + for (size_t i = 0; i < sym->fields.dim; i++) + { VarDeclaration *f = sym->fields[i]; + //printf("f->type = %s\n", f->type->toChars()); + + TypeTuple *tup = f->type->toArgTypes(); + if (!tup) + goto Lmemory; + size_t dim = tup->arguments->dim; + Type *ft1 = NULL; + Type *ft2 = NULL; + switch (dim) + { + case 2: + ft1 = (*tup->arguments)[0]->type; + ft2 = (*tup->arguments)[1]->type; + break; + case 1: + if (f->offset < 8) + ft1 = (*tup->arguments)[0]->type; + else + ft2 = (*tup->arguments)[0]->type; + break; + default: + goto Lmemory; + } + + if (f->offset & 7) + { + // Misaligned fields goto Lmemory + unsigned alignsz = f->type->alignsize(); + if (f->offset & (alignsz - 1)) + goto Lmemory; + + // Fields that overlap the 8byte boundary goto Lmemory + unsigned fieldsz = f->type->size(0); + if (f->offset < 8 && (f->offset + fieldsz) > 8) + goto Lmemory; + } + + // First field in 8byte must be at start of 8byte + assert(t1 || f->offset == 0); + + if (ft1) + { + t1 = argtypemerge(t1, ft1, f->offset); + if (!t1) + goto Lmemory; + } + + if (ft2) + { + unsigned off2 = f->offset; + if (ft1) + off2 = 8; + assert(t2 || off2 == 8); + t2 = argtypemerge(t2, ft2, off2 - 8); + if (!t2) + goto Lmemory; + } + } + + if (t2) + { + if (t1->isfloating() && t2->isfloating()) + { + if (t1->ty == Tfloat64 && t2->ty == Tfloat64) + ; + else + goto Lmemory; + } + else if (t1->isfloating()) + goto Lmemory; + else if (t2->isfloating()) + goto Lmemory; + else + ; + } +#else + if (sym->fields.dim == 1) + { VarDeclaration *f = sym->fields[0]; + //printf("f->type = %s\n", f->type->toChars()); + TypeTuple *tup = f->type->toArgTypes(); + if (tup) + { + size_t dim = tup->arguments->dim; + if (dim == 1) + t1 = (*tup->arguments)[0]->type; + } + } +#endif + } + + //printf("\ttoArgTypes() %s => [%s,%s]\n", toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : ""); + + TypeTuple *t; + if (t1) + { + //if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars()); + if (t2) + t = new TypeTuple(t1, t2); + else + t = new TypeTuple(t1); + } + else + goto Lmemory; + return t; } TypeTuple *TypeEnum::toArgTypes() diff --git a/dmd/arrayop.c b/dmd/arrayop.c index d3f1c681..c6e17869 100644 --- a/dmd/arrayop.c +++ b/dmd/arrayop.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -92,7 +92,9 @@ Expression *BinExp::arrayOp(Scope *sc) { //printf("BinExp::arrayOp() %s\n", toChars()); - if (type->toBasetype()->nextOf()->toBasetype()->ty == Tvoid) + Type *tb = type->toBasetype(); + assert(tb->ty == Tarray || tb->ty == Tsarray); + if (tb->nextOf()->toBasetype()->ty == Tvoid) { error("Cannot perform array operations on void[] arrays"); return new ErrorExp(); @@ -123,7 +125,10 @@ Expression *BinExp::arrayOp(Scope *sc) buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); #endif - size_t namelen = buf.offset; +#if IN_LLVM + const size_t namelen = buf.offset; +#endif + buf.writeByte(0); char *name = buf.toChars(); Identifier *ident = Lexer::idPool(name); @@ -337,7 +342,7 @@ Expression *BinExp::arrayOp(Scope *sc) // foreach (i; 0 .. p.length) Statement *s1 = new ForeachRangeStatement(0, TOKforeach, new Parameter(0, NULL, Id::p, NULL), - new IntegerExp(0, 0, Type::tint32), + new IntegerExp(0, 0, Type::tsize_t), new ArrayLengthExp(0, new IdentifierExp(0, p->ident)), new ExpStatement(0, loopbody)); #endif diff --git a/dmd/attrib.c b/dmd/attrib.c index 2d8f71ac..62b38568 100644 --- a/dmd/attrib.c +++ b/dmd/attrib.c @@ -11,6 +11,7 @@ #include #include #include +#include // memcpy() #include "rmem.h" @@ -34,7 +35,7 @@ #endif -extern void obj_includelib(const char *name); +extern bool obj_includelib(const char *name); #if IN_DMD void obj_startaddress(Symbol *s); @@ -90,7 +91,7 @@ int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) void AttribDeclaration::setScopeNewSc(Scope *sc, StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, - unsigned structalign) + structalign_t structalign) { if (decl) { @@ -125,7 +126,7 @@ void AttribDeclaration::setScopeNewSc(Scope *sc, void AttribDeclaration::semanticNewSc(Scope *sc, StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, - unsigned structalign) + structalign_t structalign) { if (decl) { @@ -425,6 +426,7 @@ void StorageClassDeclaration::setScope(Scope *sc) if (stc & (STCsafe | STCtrusted | STCsystem)) scstc &= ~(STCsafe | STCtrusted | STCsystem); scstc |= stc; + //printf("scstc = x%llx\n", scstc); setScopeNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); } @@ -732,6 +734,9 @@ void AlignDeclaration::semantic(Scope *sc) void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { + if (salign == STRUCTALIGN_DEFAULT) + buf->printf("align"); + else buf->printf("align (%d)", salign); AttribDeclaration::toCBuffer(buf, hgs); } @@ -924,7 +929,7 @@ void PragmaDeclaration::setScope(Scope *sc) { Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; StringExp* se = e->toString(); if (!se) @@ -963,7 +968,8 @@ void PragmaDeclaration::semantic(Scope *sc) Expression *e = (*args)[i]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + if (e->op != TOKerror && e->op != TOKtype) + e = e->ctfeInterpret(); StringExp *se = e->toString(); if (se) { @@ -985,7 +991,7 @@ void PragmaDeclaration::semantic(Scope *sc) Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; if (e->op == TOKerror) goto Lnodecl; @@ -1049,7 +1055,7 @@ void PragmaDeclaration::semantic(Scope *sc) { Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) @@ -1088,7 +1094,7 @@ void PragmaDeclaration::semantic(Scope *sc) Expression *e = (*args)[i]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (i == 0) printf(" ("); else @@ -1161,21 +1167,19 @@ void PragmaDeclaration::toObjFile(int multiobj) char *name = (char *)mem.malloc(se->len + 1); memcpy(name, se->string, se->len); name[se->len] = 0; -#if OMFOBJ - /* The OMF format allows library names to be inserted - * into the object file. The linker will then automatically + + /* Embed the library names into the object file. + * The linker will then automatically * search that library, too. */ - obj_includelib(name); -#elif ELFOBJ || MACHOBJ + if (!obj_includelib(name)) + { /* The format does not allow embedded library names, * so instead append the library name to the list to be passed * to the linker. */ global.params.libfiles->push(name); -#else - error("pragma lib not supported"); -#endif + } } #if DMDV2 else if (ident == Id::startaddress) @@ -1431,6 +1435,26 @@ void StaticIfDeclaration::importAll(Scope *sc) void StaticIfDeclaration::setScope(Scope *sc) { // do not evaluate condition before semantic pass + + // But do set the scope, in case we need it for forward referencing + Dsymbol::setScope(sc); + + // Set the scopes for both the decl and elsedecl, as we don't know yet + // which will be selected, and the scope will be the same regardless + Dsymbols *d = decl; + for (int j = 0; j < 2; j++) + { + if (d) + { + for (size_t i = 0; i < d->dim; i++) + { + Dsymbol *s = (*d)[i]; + + s->setScope(sc); + } + } + d = elsedecl; + } } void StaticIfDeclaration::semantic(Scope *sc) @@ -1462,6 +1486,8 @@ const char *StaticIfDeclaration::kind() /***************************** CompileDeclaration *****************************/ +// These are mixin declarations, like mixin("int x"); + CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) : AttribDeclaration(NULL) { @@ -1481,7 +1507,7 @@ Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { - //printf("CompileDeclaration::addMember(sc = %p, memnum = %d)\n", sc, memnum); + //printf("CompileDeclaration::addMember(sc = %p, sd = %p, memnum = %d)\n", sc, sd, memnum); this->sd = sd; if (memnum == 0) { /* No members yet, so parse the mixin now @@ -1495,10 +1521,10 @@ int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) void CompileDeclaration::compileIt(Scope *sc) { - //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum); + //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->ctfeInterpret(); StringExp *se = exp->toString(); if (!se) { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); diff --git a/dmd/attrib.h b/dmd/attrib.h index 27c71f86..91b135cd 100644 --- a/dmd/attrib.h +++ b/dmd/attrib.h @@ -37,10 +37,10 @@ struct AttribDeclaration : Dsymbol int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void setScopeNewSc(Scope *sc, StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - unsigned structalign); + structalign_t structalign); void semanticNewSc(Scope *sc, StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - unsigned structalign); + structalign_t structalign); void semantic(Scope *sc); void semantic2(Scope *sc); void semantic3(Scope *sc); @@ -121,7 +121,7 @@ struct AlignDeclaration : AttribDeclaration struct AnonDeclaration : AttribDeclaration { bool isunion; - unsigned alignment; + structalign_t alignment; int sem; // 1 if successful semantic() AnonDeclaration(Loc loc, int isunion, Dsymbols *decl); diff --git a/dmd/cast.c b/dmd/cast.c index 562d09dc..fbd03637 100644 --- a/dmd/cast.c +++ b/dmd/cast.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -9,6 +9,7 @@ #include #include +#include // mem{set|cpy}() #include "rmem.h" @@ -172,6 +173,7 @@ MATCH IntegerExp::implicitConvTo(Type *t) enum TY ty = type->toBasetype()->ty; enum TY toty = t->toBasetype()->ty; + enum TY oldty = ty; if (type->implicitConvTo(t) == MATCHnomatch && t->ty == Tenum) { @@ -237,6 +239,8 @@ MATCH IntegerExp::implicitConvTo(Type *t) goto Lyes; case Tchar: + if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F) + goto Lno; case Tuns8: //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); if ((unsigned char)value != value) @@ -248,6 +252,9 @@ MATCH IntegerExp::implicitConvTo(Type *t) goto Lno; goto Lyes; + case Twchar: + if (oldty == Tdchar && value > 0xD7FF && value < 0xE000) + goto Lno; case Tuns16: if ((unsigned short)value != value) goto Lno; @@ -274,11 +281,6 @@ MATCH IntegerExp::implicitConvTo(Type *t) goto Lno; goto Lyes; - case Twchar: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - case Tfloat32: { volatile float f; @@ -467,13 +469,17 @@ MATCH ArrayLiteralExp::implicitConvTo(Type *t) result = MATCHnomatch; } + if (!elements->dim && typeb->nextOf()->toBasetype()->ty != Tvoid) + result = MATCHnomatch; + + Type *telement = tb->nextOf(); for (size_t i = 0; i < elements->dim; i++) { Expression *e = (*elements)[i]; - MATCH m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match if (result == MATCHnomatch) break; // no need to check for worse + MATCH m = (MATCH)e->implicitConvTo(telement); + if (m < result) + result = m; // remember worst match } if (!result) @@ -481,6 +487,29 @@ MATCH ArrayLiteralExp::implicitConvTo(Type *t) return result; } +#if DMDV2 + else if (tb->ty == Tvector && + (typeb->ty == Tarray || typeb->ty == Tsarray)) + { + // Convert array literal to vector type + TypeVector *tv = (TypeVector *)tb; + TypeSArray *tbase = (TypeSArray *)tv->basetype; + assert(tbase->ty == Tsarray); + if (elements->dim != tbase->dim->toInteger()) + return MATCHnomatch; + + Type *telement = tv->elementType(); + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (*elements)[i]; + MATCH m = (MATCH)e->implicitConvTo(telement); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + } + return result; + } +#endif else return Expression::implicitConvTo(t); } @@ -1063,6 +1092,30 @@ Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) e = (ArrayLiteralExp *)copy(); e->type = typeb->nextOf()->pointerTo(); } +#if DMDV2 + else if (tb->ty == Tvector && + (typeb->ty == Tarray || typeb->ty == Tsarray)) + { + // Convert array literal to vector type + TypeVector *tv = (TypeVector *)tb; + TypeSArray *tbase = (TypeSArray *)tv->basetype; + assert(tbase->ty == Tsarray); + if (elements->dim != tbase->dim->toInteger()) + goto L1; + + e = (ArrayLiteralExp *)copy(); + e->elements = (Expressions *)elements->copy(); + Type *telement = tv->elementType(); + for (size_t i = 0; i < elements->dim; i++) + { Expression *ex = (*elements)[i]; + ex = ex->castTo(sc, telement); + (*e->elements)[i] = ex; + } + Expression *ev = new VectorExp(loc, e, tb); + ev = ev->semantic(sc); + return ev; + } +#endif L1: return e->Expression::castTo(sc, t); } diff --git a/dmd/class.c b/dmd/class.c index 5f9a60c1..84300229 100644 --- a/dmd/class.c +++ b/dmd/class.c @@ -11,6 +11,7 @@ #include #include #include +#include // mem{cpy|set}() #include "root.h" #include "rmem.h" @@ -228,9 +229,9 @@ Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) cd->baseclasses->setDim(this->baseclasses->dim); for (size_t i = 0; i < cd->baseclasses->dim; i++) { - BaseClass *b = this->baseclasses->tdata()[i]; + BaseClass *b = (*this->baseclasses)[i]; BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); - cd->baseclasses->tdata()[i] = b2; + (*cd->baseclasses)[i] = b2; } ScopeDsymbol::syntaxCopy(cd); @@ -290,7 +291,7 @@ void ClassDeclaration::semantic(Scope *sc) // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = baseclasses->tdata()[i]; + { BaseClass *b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); @@ -315,7 +316,7 @@ void ClassDeclaration::semantic(Scope *sc) BaseClass *b; Type *tb; - b = baseclasses->tdata()[0]; + b = (*baseclasses)[0]; //b->type = b->type->semantic(loc, sc); tb = b->type->toBasetype(); if (tb->ty != Tclass) @@ -385,7 +386,7 @@ void ClassDeclaration::semantic(Scope *sc) BaseClass *b; Type *tb; - b = baseclasses->tdata()[i]; + b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); tb = b->type->toBasetype(); if (tb->ty == Tclass) @@ -414,7 +415,7 @@ void ClassDeclaration::semantic(Scope *sc) // Check for duplicate interfaces for (size_t j = (baseClass ? 1 : 0); j < i; j++) { - BaseClass *b2 = baseclasses->tdata()[j]; + BaseClass *b2 = (*baseclasses)[j]; if (b2->base == tc->sym) error("inherits from duplicate interface %s", b2->base->toChars()); } @@ -446,22 +447,20 @@ void ClassDeclaration::semantic(Scope *sc) // If no base class, and this is not an Object, use Object as base class if (!baseClass && ident != Id::Object) { - // BUG: what if Object is redefined in an inner scope? - Type *tbase = new TypeIdentifier(0, Id::Object); - BaseClass *b; - TypeClass *tc; - Type *bt; - if (!object) { error("missing or corrupt object.d"); fatal(); } - bt = tbase->semantic(loc, sc)->toBasetype(); - b = new BaseClass(bt, PROTpublic); + + Type *t = object->type; + t = t->semantic(loc, sc)->toBasetype(); + assert(t->ty == Tclass); + TypeClass *tc = (TypeClass *)t; + + BaseClass *b = new BaseClass(tc, PROTpublic); baseclasses->shift(b); - assert(b->type->ty == Tclass); - tc = (TypeClass *)(b->type); + baseClass = tc->sym; assert(!baseClass->isInterfaceDeclaration()); b->base = baseClass; @@ -516,7 +515,9 @@ void ClassDeclaration::semantic(Scope *sc) isnested = 1; if (storage_class & STCstatic) error("static class cannot inherit from nested class %s", baseClass->toChars()); - if (toParent2() != baseClass->toParent2()) + if (toParent2() != baseClass->toParent2() && + (!toParent2() || + !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL))) { if (toParent2()) { @@ -592,7 +593,7 @@ void ClassDeclaration::semantic(Scope *sc) } sc->protection = PROTpublic; sc->explicitProtection = 0; - sc->structalign = 8; + sc->structalign = STRUCTALIGN_DEFAULT; structalign = sc->structalign; if (baseClass) { sc->offset = baseClass->structsize; @@ -620,9 +621,10 @@ void ClassDeclaration::semantic(Scope *sc) if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident) || s->isTemplateMixin() || + s->isAttribDeclaration() || s->isAliasDeclaration()) { - //printf("setScope %s %s\n", s->kind(), s->toChars()); + //printf("[%d] setScope %s %s, sc = %p\n", i, s->kind(), s->toChars(), sc); s->setScope(sc); } } @@ -756,7 +758,7 @@ void ClassDeclaration::semantic(Scope *sc) // Fill in base class vtbl[]s for (i = 0; i < vtblInterfaces->dim; i++) { - BaseClass *b = vtblInterfaces->tdata()[i]; + BaseClass *b = (*vtblInterfaces)[i]; //b->fillVtbl(this, &b->vtbl, 1); } @@ -775,7 +777,7 @@ void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } for (size_t i = 0; i < baseclasses->dim; i++) { - BaseClass *b = baseclasses->tdata()[i]; + BaseClass *b = (*baseclasses)[i]; if (i) buf->writeByte(','); @@ -789,7 +791,7 @@ void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); @@ -824,7 +826,7 @@ int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) return 0; //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = cd->baseclasses->tdata()[i]; + { BaseClass *b = (*cd->baseclasses)[i]; if (b->base == this || isBaseOf2(b->base)) return 1; @@ -870,7 +872,7 @@ int ClassDeclaration::isBaseInfoComplete() if (!baseClass) return ident == Id::Object; for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = baseclasses->tdata()[i]; + { BaseClass *b = (*baseclasses)[i]; if (!b->base || !b->base->isBaseInfoComplete()) return 0; } @@ -908,7 +910,7 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) for (size_t i = 0; i < baseclasses->dim; i++) { - BaseClass *b = baseclasses->tdata()[i]; + BaseClass *b = (*baseclasses)[i]; if (b->base) { @@ -1001,9 +1003,11 @@ FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) //printf("\t[%d] = %s\n", i, fd->toChars()); if (ident == fd->ident && fd->type->covariant(tf) == 1) - { //printf("fd->parent->isClassDeclaration() = %p", fd->parent->isClassDeclaration()); + { //printf("fd->parent->isClassDeclaration() = %p\n", fd->parent->isClassDeclaration()); if (!fdmatch) goto Lfd; + if (fd == fdmatch) + goto Lfdmatch; { // Function type matcing: exact > covariant @@ -1100,7 +1104,7 @@ int ClassDeclaration::isAbstract() return TRUE; for (size_t i = 1; i < vtbl.dim; i++) { - FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration(); + FuncDeclaration *fd = vtbl[i]->isFuncDeclaration(); //printf("\tvtbl[%d] = %p\n", i, fd); if (!fd || fd->isAbstract()) @@ -1213,7 +1217,7 @@ void InterfaceDeclaration::semantic(Scope *sc) // Expand any tuples in baseclasses[] for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = (*baseclasses)[0]; + { BaseClass *b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); Type *tb = b->type->toBasetype(); @@ -1238,7 +1242,7 @@ void InterfaceDeclaration::semantic(Scope *sc) BaseClass *b; Type *tb; - b = baseclasses->tdata()[i]; + b = (*baseclasses)[i]; b->type = b->type->semantic(loc, sc); tb = b->type->toBasetype(); if (tb->ty == Tclass) @@ -1256,7 +1260,7 @@ void InterfaceDeclaration::semantic(Scope *sc) // Check for duplicate interfaces for (size_t j = 0; j < i; j++) { - BaseClass *b2 = baseclasses->tdata()[j]; + BaseClass *b2 = (*baseclasses)[j]; if (b2->base == tc->sym) error("inherits from duplicate interface %s", b2->base->toChars()); } @@ -1288,7 +1292,7 @@ void InterfaceDeclaration::semantic(Scope *sc) } interfaces_dim = baseclasses->dim; - interfaces = (BaseClass **)baseclasses->data; + interfaces = baseclasses->tdata(); interfaceSemantic(sc); @@ -1313,7 +1317,7 @@ void InterfaceDeclaration::semantic(Scope *sc) { vtbl.reserve(d - 1); for (size_t j = 1; j < d; j++) - vtbl.push((Dsymbol *)b->base->vtbl.data[j]); + vtbl.push(b->base->vtbl[j]); } } else @@ -1336,7 +1340,7 @@ void InterfaceDeclaration::semantic(Scope *sc) sc->parent = this; if (isCOMinterface()) sc->linkage = LINKwindows; - sc->structalign = 8; + sc->structalign = STRUCTALIGN_DEFAULT; sc->protection = PROTpublic; sc->explicitProtection = 0; structalign = sc->structalign; @@ -1438,7 +1442,7 @@ int InterfaceDeclaration::isBaseInfoComplete() { assert(!baseClass); for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = baseclasses->tdata()[i]; + { BaseClass *b = (*baseclasses)[i]; if (!b->base || !b->base->isBaseInfoComplete ()) return 0; } @@ -1522,7 +1526,7 @@ int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newins // first entry is ClassInfo reference for (size_t j = base->vtblOffset(); j < base->vtbl.dim; j++) { - FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration(); + FuncDeclaration *ifd = base->vtbl[j]->isFuncDeclaration(); FuncDeclaration *fd; TypeFunction *tf; @@ -1559,7 +1563,7 @@ int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newins fd = NULL; } if (vtbl) - vtbl->data[j] = fd; + (*vtbl)[j] = fd; } return result; diff --git a/dmd/cond.c b/dmd/cond.c index afce513e..f54fd467 100644 --- a/dmd/cond.c +++ b/dmd/cond.c @@ -10,6 +10,7 @@ #include #include +#include // strcmp() #include "id.h" #include "init.h" @@ -266,7 +267,14 @@ int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) sc->flags |= SCOPEstaticif; Expression *e = exp->semantic(sc); sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); + if (!e->type->checkBoolean()) + { + if (e->type->toBasetype() != Type::terror) + exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); + inc = 0; + return 0; + } + e = e->ctfeInterpret(); --nest; if (e->op == TOKerror) { exp = e; diff --git a/dmd/constfold.c b/dmd/constfold.c index a04fa292..e630ba1c 100644 --- a/dmd/constfold.c +++ b/dmd/constfold.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 @@ -11,6 +11,7 @@ #include #include #include +#include // mem{cpy|set|cmp}() #include #if __DMC__ @@ -1158,7 +1159,7 @@ Expression *Cast(Type *type, Type *to, Expression *e1) assert(sd); Expressions *elements = new Expressions; for (size_t i = 0; i < sd->fields.dim; i++) - { Dsymbol *s = sd->fields.tdata()[i]; + { Dsymbol *s = sd->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); @@ -1242,7 +1243,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) } else if (e1->op == TOKarrayliteral) { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - e = ale->elements->tdata()[i]; + e = (*ale->elements)[i]; e->type = type; if (e->hasSideEffect()) e = EXP_CANT_INTERPRET; @@ -1260,7 +1261,7 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) e = new ErrorExp(); } else - { e = ale->elements->tdata()[i]; + { e = (*ale->elements)[i]; e->type = type; if (e->hasSideEffect()) e = EXP_CANT_INTERPRET; @@ -1275,12 +1276,12 @@ Expression *Index(Type *type, Expression *e1, Expression *e2) for (size_t i = ae->keys->dim; i;) { i--; - Expression *ekey = ae->keys->tdata()[i]; + Expression *ekey = (*ae->keys)[i]; Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); if (ex == EXP_CANT_INTERPRET) return ex; if (ex->isBool(TRUE)) - { e = ae->values->tdata()[i]; + { e = (*ae->values)[i]; e->type = type; if (e->hasSideEffect()) e = EXP_CANT_INTERPRET; @@ -1351,7 +1352,7 @@ Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) elements->setDim(iupr - ilwr); memcpy(elements->tdata(), es1->elements->tdata() + ilwr, - (iupr - ilwr) * sizeof(es1->elements->tdata()[0])); + (iupr - ilwr) * sizeof((*es1->elements)[0])); e = new ArrayLiteralExp(e1->loc, elements); e->type = type; } @@ -1380,7 +1381,7 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *n assert(0); break; } - existingAE->elements->tdata()[j+firstIndex] + (*existingAE->elements)[j+firstIndex] = new IntegerExp(newval->loc, val, elemType); } } @@ -1393,7 +1394,7 @@ void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *n unsigned char *s = (unsigned char *)existingSE->string; for (size_t j = 0; j < newae->elements->dim; j++) { - unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger()); + unsigned value = (unsigned)((*newae->elements)[j]->toInteger()); switch (existingSE->sz) { case 1: s[j+firstIndex] = value; break; @@ -1417,6 +1418,48 @@ void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int f memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len); } +/* Compare a string slice with another string slice. + * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len]) + */ +int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len) +{ + unsigned char *s1 = (unsigned char *)se1->string; + unsigned char *s2 = (unsigned char *)se2->string; + size_t sz = se1->sz; + assert(sz == se2->sz); + + return memcmp(s1 + sz * lo1, s2 + sz * lo2, sz * len); +} + +/* Compare a string slice with an array literal slice + * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len]) + */ +int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len) +{ + unsigned char *s = (unsigned char *)se1->string; + size_t sz = se1->sz; + + int c = 0; + + for (size_t j = 0; j < len; j++) + { + unsigned value = (unsigned)((*ae2->elements)[j + lo2]->toInteger()); + unsigned svalue; + switch (sz) + { + case 1: svalue = s[j + lo1]; break; + case 2: svalue = ((unsigned short *)s)[j+lo1]; break; + case 4: svalue = ((unsigned *)s)[j + lo1]; break; + default: + assert(0); + } + int c = svalue - value; + if (c) + return c; + } + return 0; +} + /* Also return EXP_CANT_INTERPRET if this fails */ Expression *Cat(Type *type, Expression *e1, Expression *e2) @@ -1534,7 +1577,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) elems->setDim(len); for (size_t i= 0; i < ea->elements->dim; ++i) { - elems->tdata()[i] = ea->elements->tdata()[i]; + (*elems)[i] = (*ea->elements)[i]; } ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); dest->type = type; @@ -1552,7 +1595,7 @@ Expression *Cat(Type *type, Expression *e1, Expression *e2) elems->setDim(len); for (size_t i= 0; i < ea->elements->dim; ++i) { - elems->tdata()[es->len + i] = ea->elements->tdata()[i]; + (*elems)[es->len + i] = (*ea->elements)[i]; } ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); dest->type = type; diff --git a/dmd/declaration.c b/dmd/declaration.c index 2ecad32c..2075e4c7 100644 --- a/dmd/declaration.c +++ b/dmd/declaration.c @@ -92,6 +92,7 @@ enum PROT Declaration::prot() */ #if DMDV2 + void Declaration::checkModify(Loc loc, Scope *sc, Type *t) { if (sc->incontract && isParameter()) @@ -100,40 +101,10 @@ void Declaration::checkModify(Loc loc, Scope *sc, Type *t) if (sc->incontract && isResult()) error(loc, "cannot modify result '%s' in contract", toChars()); - if (isCtorinit() && !t->isMutable()) + if (isCtorinit() && !t->isMutable() || + (storage_class & STCnodefaultctor)) { // It's only modifiable if inside the right constructor - Dsymbol *s = sc->func; - while (1) - { - FuncDeclaration *fd = NULL; - if (s) - fd = s->isFuncDeclaration(); - if (fd && - ((fd->isCtorDeclaration() && storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) && - fd->toParent2() == toParent() - ) - { - VarDeclaration *v = isVarDeclaration(); - assert(v); - v->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else - { - const char *p = isStatic() ? "static " : ""; - error(loc, "can only initialize %sconst %s inside %sconstructor", - p, toChars(), p); - } - } - break; - } + modifyFieldVar(loc, sc, isVarDeclaration(), NULL); } else { @@ -145,6 +116,8 @@ void Declaration::checkModify(Loc loc, Scope *sc, Type *t) p = "const"; else if (isImmutable()) p = "immutable"; + else if (isWild()) + p = "inout"; else if (storage_class & STCmanifest) p = "enum"; else if (!t->isAssignable()) @@ -205,12 +178,13 @@ Type *TupleDeclaration::getType() /* We know it's a type tuple, so build the TypeTuple */ + Types *types = (Types *)objects; Parameters *args = new Parameters(); args->setDim(objects->dim); OutBuffer buf; int hasdeco = 1; - for (size_t i = 0; i < objects->dim; i++) - { Type *t = (Type *)objects->data[i]; + for (size_t i = 0; i < types->dim; i++) + { Type *t = (*types)[i]; //printf("type = %s\n", t->toChars()); #if 0 @@ -351,7 +325,7 @@ void TypedefDeclaration::semantic2(Scope *sc) { Initializer *savedinit = init; int errors = global.errors; - init = init->semantic(sc, basetype, WANTinterpret); + init = init->semantic(sc, basetype, INITinterpret); if (errors != global.errors) { init = savedinit; @@ -538,6 +512,18 @@ void AliasDeclaration::semantic(Scope *sc) else if (t) { type = t->semantic(loc, sc); + + /* If type is class or struct, convert to symbol. + * See bugzilla 6475. + */ + s = type->toDsymbol(sc); + if (s +#if DMDV2 + && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) +#endif + ) + goto L2; + //printf("\talias resolved to type %s\n", type->toChars()); } if (overnext) @@ -658,7 +644,9 @@ Dsymbol *AliasDeclaration::toAlias() aliassym = new AliasDeclaration(loc, ident, Type::terror); type = Type::terror; } - else if (!aliassym && scope) + else if (aliassym || type->deco) + ; // semantic is already done. + else if (scope) semantic(scope); Dsymbol *s = aliassym ? aliassym->toAlias() : this; return s; @@ -846,9 +834,32 @@ void VarDeclaration::semantic(Scope *sc) //printf("storage_class = x%x\n", storage_class); #if DMDV2 - if (storage_class & STCgshared && global.params.safe && !sc->module->safe) + // Safety checks + if (sc->func && !sc->intypeof) { - error("__gshared not allowed in safe mode; use shared"); + if (storage_class & STCgshared) + { + if (sc->func->setUnsafe()) + error("__gshared not allowed in safe functions; use shared"); + } + if (init && init->isVoidInitializer() && type->hasPointers()) + { + if (sc->func->setUnsafe()) + error("void initializers for pointers not allowed in safe functions"); + } + if (type->hasPointers() && type->toDsymbol(sc)) + { + Dsymbol *s = type->toDsymbol(sc); + if (s) + { + AggregateDeclaration *ad2 = s->isAggregateDeclaration(); + if (ad2 && ad2->hasUnions) + { + if (sc->func->setUnsafe()) + error("unions containing pointers are not allowed in @safe functions"); + } + } + } } #endif @@ -1115,7 +1126,7 @@ void VarDeclaration::semantic(Scope *sc) Expression *e = init->toExpression(); if (!e) { - init = init->semantic(sc, type, 0); // Don't need to interpret + init = init->semantic(sc, type, INITnointerpret); e = init->toExpression(); if (!e) { error("is not a static and cannot have static initializer"); @@ -1216,7 +1227,7 @@ void VarDeclaration::semantic(Scope *sc) } else { - init = init->semantic(sc, type, WANTinterpret); + init = init->semantic(sc, type, INITinterpret); if (fd && isConst() && !isStatic()) { // Make it static storage_class |= STCstatic; @@ -1246,7 +1257,7 @@ void VarDeclaration::semantic(Scope *sc) } else if (si || ai) { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type, WANTinterpret); + i2 = i2->semantic(sc, type, INITinterpret); } inuse--; if (global.endGagging(errors)) // if errors happened @@ -1261,7 +1272,7 @@ void VarDeclaration::semantic(Scope *sc) else if (ei) { if (isDataseg() || (storage_class & STCmanifest)) - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); else e = e->optimize(WANTvalue); switch (e->op) @@ -1349,7 +1360,7 @@ void VarDeclaration::semantic2(Scope *sc) printf("type = %p\n", ei->exp->type); } #endif - init = init->semantic(sc, type, WANTinterpret); + init = init->semantic(sc, type, INITinterpret); inuse--; } } @@ -1429,7 +1440,7 @@ void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, 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 + structalign_t memalign = t->memalign(alignment); // alignment boundaries offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, memalign, &ad->structsize, &ad->alignsize, isunion); diff --git a/dmd/declaration.h b/dmd/declaration.h index 03c10ae8..110a169b 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.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 @@ -283,7 +283,7 @@ struct VarDeclaration : Declaration #else int nestedref; // referenced by a lexically nested function #endif - unsigned short alignment; + structalign_t 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 @@ -702,6 +702,7 @@ struct FuncDeclaration : Declaration Identifier *outId; // identifier for out statement VarDeclaration *vresult; // variable corresponding to outId LabelDsymbol *returnLabel; // where the return goes + Scope *scout; // out contract scope for vresult->semantic DsymbolTable *localsymtab; // used to prevent symbols in different // scopes from having the same name @@ -779,7 +780,7 @@ struct FuncDeclaration : Declaration void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); int overrides(FuncDeclaration *fd); - int findVtblIndex(Array *vtbl, int dim); + int findVtblIndex(Dsymbols *vtbl, int dim); int overloadInsert(Dsymbol *s); FuncDeclaration *overloadExactMatch(Type *t, Module* from); FuncDeclaration *overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, Module *from, int flags = 0); @@ -821,6 +822,7 @@ struct FuncDeclaration : Declaration FuncDeclaration *isUnique(); int needsClosure(); int hasNestedFrameRefs(); + void buildResultVar(); Statement *mergeFrequire(Statement *); Statement *mergeFensure(Statement *); Parameters *getParameters(int *pvarargs); diff --git a/dmd/doc.c b/dmd/doc.c index cff0fd43..a616b84f 100644 --- a/dmd/doc.c +++ b/dmd/doc.c @@ -19,6 +19,10 @@ #include "rmem.h" #include "root.h" +#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ +#include "gnuc.h" +#endif + #include "mars.h" #include "dsymbol.h" #include "macro.h" @@ -77,7 +81,9 @@ struct DocComment Macro **pmacrotable; Escape **pescapetable; - DocComment(); + DocComment() : + summary(NULL), copyright(NULL), macros(NULL), pmacrotable(NULL), pescapetable(NULL) + { } static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); @@ -227,7 +233,7 @@ void Module::gendocfile() // Override with the ddoc macro files from the command line for (size_t i = 0; i < global.params.ddocfiles->dim; i++) { - FileName f(global.params.ddocfiles->tdata()[i], 0); + FileName f((*global.params.ddocfiles)[i], 0); File file(&f); file.readv(); // BUG: convert file contents to UTF-8 before use @@ -1014,11 +1020,6 @@ void EnumMember::toDocBuffer(OutBuffer *buf) /********************************* DocComment *********************************/ -DocComment::DocComment() -{ - memset(this, 0, sizeof(DocComment)); -} - DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) { //printf("parse(%s): '%s'\n", s->toChars(), comment); @@ -1780,7 +1781,7 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) int leadingBlank = 1; int inCode = 0; - int inComment = 0; // in comment + //int inComment = 0; // in comment unsigned iCodeStart; // start of code section unsigned iLineStart = offset; diff --git a/dmd/dsymbol.c b/dmd/dsymbol.c index 2689022c..fe727ab5 100644 --- a/dmd/dsymbol.c +++ b/dmd/dsymbol.c @@ -607,7 +607,7 @@ void Dsymbol::error(const char *format, ...) } va_list ap; va_start(ap, format); - verror(loc, format, ap); + verror(loc, format, ap, kind(), toPrettyChars()); va_end(ap); } @@ -615,41 +615,10 @@ void Dsymbol::error(Loc loc, const char *format, ...) { va_list ap; va_start(ap, format); - verror(loc, format, ap); + verror(loc, format, ap, kind(), toPrettyChars()); va_end(ap); } -void Dsymbol::verror(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - char *p = loc.toChars(); - if (!*p) - p = locToChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - - vfprintf(stdmsg, format, ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); -//halt(); - } - else - { - global.gaggedErrors++; - } - - global.errors++; - - //fatal(); -} - void Dsymbol::checkDeprecated(Loc loc, Scope *sc) { if (!global.params.useDeprecated && isDeprecated()) @@ -1286,6 +1255,7 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) VoidInitializer *e = new VoidInitializer(0); e->type = Type::tsize_t; v->init = e; + v->storage_class |= STCctfe; // it's never a true static variable } *pvar = v; } diff --git a/dmd/dsymbol.h b/dmd/dsymbol.h index 7e4fce98..77c03810 100644 --- a/dmd/dsymbol.h +++ b/dmd/dsymbol.h @@ -152,7 +152,6 @@ struct Dsymbol : Object int isAnonymous(); void error(Loc loc, const char *format, ...) IS_PRINTF(3); void error(const char *format, ...) IS_PRINTF(2); - void verror(Loc loc, const char *format, va_list ap); void checkDeprecated(Loc loc, Scope *sc); Module *getModule(); // module where declared Module *getCompilationModule(); // possibly different for templates diff --git a/dmd/expression.c b/dmd/expression.c index bf618058..f8ab2052 100644 --- a/dmd/expression.c +++ b/dmd/expression.c @@ -1114,12 +1114,12 @@ dump(0); /*************************************** * Return !=0 if expression is an lvalue. */ -#if DMDV2 + int Expression::isLvalue() { return 0; } -#endif + /******************************* * Give error if we're not an lvalue. @@ -1133,7 +1133,7 @@ Expression *Expression::toLvalue(Scope *sc, Expression *e) else if (!loc.filename) loc = e->loc; error("%s is not an lvalue", e->toChars()); - return this; + return new ErrorExp(); } Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) @@ -1143,11 +1143,14 @@ Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) // See if this expression is a modifiable lvalue (i.e. not const) #if DMDV2 if (type && (!type->isMutable() || !type->isAssignable())) - error("%s is not mutable", e->toChars()); + { error("%s is not mutable", e->toChars()); + return new ErrorExp(); + } #endif return toLvalue(sc, e); } + /************************************ * Detect cases where pointers to the stack can 'escape' the * lifetime of the stack frame. @@ -1916,16 +1919,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(buf1, 'g', creall(value)); + ld_sprint(buf2, 'g', cimagl(value)); #endif + sprintf(buffer, "(%s+%si)", buf1, buf2); + assert(strlen(buffer) < sizeof(buffer)); return mem.strdup(buffer); } @@ -2126,12 +2130,12 @@ void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(ident->toChars()); } -#if DMDV2 + int IdentifierExp::isLvalue() { return 1; } -#endif + Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e) { @@ -2180,7 +2184,7 @@ Lagain: //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind()); - if (type) + if (type && !s->needThis()) return this; if (!s->isFuncDeclaration()) // functions are checked after overloading checkDeprecated(sc, s); @@ -2356,6 +2360,24 @@ Lagain: TupleDeclaration *tup = s->isTupleDeclaration(); if (tup) { + for (size_t i = 0; i < tup->objects->dim; i++) + { + Dsymbol *sa = getDsymbol((*tup->objects)[i]); + if (sa && sa->needThis()) + { + if (hasThis(sc) +#if DMDV2 + && !sa->isFuncDeclaration() +#endif + ) + { + // Supply an implicit 'this', as in + // this.ident + (*tup->objects)[i] = new DotVarExp(loc, new ThisExp(loc), sa->isDeclaration()); + } + } + } + e = new TupleExp(loc, tup); e = e->semantic(sc); return e; @@ -2368,6 +2390,8 @@ Lagain: s = ti->toAlias(); if (!s->isTemplateInstance()) goto Lagain; + if (ti->errors) + return new ErrorExp(); e = new ScopeExp(loc, ti); e = e->semantic(sc); return e; @@ -2395,12 +2419,12 @@ void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(s->toChars()); } -#if DMDV2 + int DsymbolExp::isLvalue() { return 1; } -#endif + Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) { @@ -2493,12 +2517,12 @@ void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring("this"); } -#if DMDV2 + int ThisExp::isLvalue() { return 1; } -#endif + Expression *ThisExp::toLvalue(Scope *sc, Expression *e) { @@ -2917,12 +2941,15 @@ int StringExp::isBool(int result) return result ? TRUE : FALSE; } -#if DMDV2 + int StringExp::isLvalue() { - return 1; + /* string literal is rvalue in default, but + * conversion to reference of static array is only allowed. + */ + return 0; } -#endif + unsigned StringExp::charAt(size_t i) { unsigned value; @@ -3059,6 +3086,7 @@ ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) { elements = new Expressions; elements->push(e); + this->ownedByCtfe = false; } Expression *ArrayLiteralExp::syntaxCopy() @@ -3121,7 +3149,9 @@ Expression *ArrayLiteralExp::semantic(Scope *sc) /* Disallow array literals of type void being used. */ if (elements->dim > 0 && t0->ty == Tvoid) - error("%s of type %s has no value", toChars(), type->toChars()); + { error("%s of type %s has no value", toChars(), type->toChars()); + return new ErrorExp(); + } return this; } @@ -3145,13 +3175,6 @@ int ArrayLiteralExp::isBool(int result) return result ? (dim != 0) : (dim == 0); } -#if DMDV2 -int ArrayLiteralExp::canThrow() -{ - return 1; // because it can fail allocating memory -} -#endif - StringExp *ArrayLiteralExp::toString() { TY telem = type->nextOf()->toBasetype()->ty; @@ -3163,10 +3186,10 @@ StringExp *ArrayLiteralExp::toString() if (elements) for (int i = 0; i < elements->dim; ++i) { - Expression *ch = elements->tdata()[i]; + Expression *ch = (*elements)[i]; if (ch->op != TOKint64) return NULL; - buf.writedchar(ch->toInteger()); + buf.writeUTF8(ch->toInteger()); } buf.writebyte(0); @@ -3174,7 +3197,8 @@ StringExp *ArrayLiteralExp::toString() if (telem == Twchar) prefix = 'w'; else if (telem == Tdchar) prefix = 'd'; - StringExp *se = new StringExp(loc, buf.extractData(), buf.size - 1, prefix); + const size_t len = buf.offset - 1; + StringExp *se = new StringExp(loc, buf.extractData(), len, prefix); se->type = type; return se; } @@ -3193,7 +3217,7 @@ void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = elements ? elements->dim : 0; buf->printf("A%u", dim); for (size_t i = 0; i < dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; e->toMangleBuffer(buf); } } @@ -3283,8 +3307,8 @@ void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('['); for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; + { Expression *key = (*keys)[i]; + Expression *value = (*values)[i]; if (i) buf->writeByte(','); @@ -3300,8 +3324,8 @@ void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = keys->dim; buf->printf("A%u", dim); for (size_t i = 0; i < dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; + { Expression *key = (*keys)[i]; + Expression *value = (*values)[i]; key->toMangleBuffer(buf); value->toMangleBuffer(buf); @@ -3323,6 +3347,7 @@ StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions * #endif this->soffset = 0; this->fillHoles = 1; + this->ownedByCtfe = false; #if IN_LLVM constType = NULL; #endif @@ -3411,7 +3436,7 @@ Expression *StructLiteralExp::semantic(Scope *sc) else if (v->scope) { // Do deferred semantic analysis Initializer *i2 = v->init->syntaxCopy(); - i2 = i2->semantic(v->scope, v->type, WANTinterpret); + i2 = i2->semantic(v->scope, v->type, INITinterpret); e = i2->toExpression(); // remove v->scope (see bug 3426) // but not if gagged, for we might be called again. @@ -3554,7 +3579,7 @@ void StructLiteralExp::toMangleBuffer(OutBuffer *buf) size_t dim = elements ? elements->dim : 0; buf->printf("S%u", dim); for (size_t i = 0; i < dim; i++) - { Expression *e = (Expression *)elements->data[i]; + { Expression *e = (*elements)[i]; if (e) e->toMangleBuffer(buf); else @@ -3641,6 +3666,8 @@ Lagain: ti->semantic(sc); if (ti->inst) { + if (ti->inst->errors) + return new ErrorExp(); Dsymbol *s = ti->inst->toAlias(); sds2 = s->isScopeDsymbol(); if (!sds2) @@ -4356,14 +4383,14 @@ void VarExp::checkEscapeRef() } } -#if DMDV2 + int VarExp::isLvalue() { if (var->storage_class & STClazy) return 0; return 1; } -#endif + Expression *VarExp::toLvalue(Scope *sc, Expression *e) { @@ -5505,6 +5532,11 @@ Expression *BinAssignExp::semantic(Scope *sc) return this; } +int BinAssignExp::isLvalue() +{ + return 1; +} + /************************************************************/ CompileExp::CompileExp(Loc loc, Expression *e) @@ -5526,7 +5558,7 @@ Expression *CompileExp::semantic(Scope *sc) error("argument to mixin must be a string type, not %s\n", e1->type->toChars()); return new ErrorExp(); } - e1 = e1->optimize(WANTvalue | WANTinterpret); + e1 = e1->ctfeInterpret(); StringExp *se = e1->toString(); if (!se) { error("argument to mixin must be a string, not (%s)", e1->toChars()); @@ -5566,7 +5598,7 @@ Expression *FileExp::semantic(Scope *sc) #endif UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue | WANTinterpret); + e1 = e1->ctfeInterpret(); if (e1->op != TOKstring) { error("file name argument must be a string, not (%s)", e1->toChars()); goto Lerror; @@ -6166,12 +6198,12 @@ Expression *DotVarExp::semantic(Scope *sc) return this; } -#if DMDV2 + int DotVarExp::isLvalue() { return 1; } -#endif + Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) { @@ -7272,17 +7304,23 @@ int CallExp::canThrow() } #endif -#if DMDV2 int CallExp::isLvalue() { -// if (type->toBasetype()->ty == Tstruct) -// return 1; Type *tb = e1->type->toBasetype(); + if (tb->ty == Tdelegate || tb->ty == Tpointer) + tb = tb->nextOf(); +#if DMDV2 if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) + { + if (e1->op == TOKdotvar) + if (((DotVarExp *)e1)->var->isCtorDeclaration()) + return 0; return 1; // function returns a reference + } +#endif return 0; } -#endif + Expression *CallExp::toLvalue(Scope *sc, Expression *e) { @@ -7478,12 +7516,12 @@ Expression *PtrExp::semantic(Scope *sc) return this; } -#if DMDV2 + int PtrExp::isLvalue() { return 1; } -#endif + void PtrExp::checkEscapeRef() { @@ -8014,8 +8052,8 @@ Expression *SliceExp::semantic(Scope *sc) if (t->ty == Ttuple) { - lwr = lwr->optimize(WANTvalue | WANTinterpret); - upr = upr->optimize(WANTvalue | WANTinterpret); + lwr = lwr->ctfeInterpret(); + upr = upr->ctfeInterpret(); uinteger_t i1 = lwr->toUInteger(); uinteger_t i2 = upr->toUInteger(); @@ -8098,12 +8136,12 @@ void SliceExp::checkEscapeRef() e1->checkEscapeRef(); } -#if DMDV2 + int SliceExp::isLvalue() { return 1; } -#endif + Expression *SliceExp::toLvalue(Scope *sc, Expression *e) { @@ -8199,6 +8237,8 @@ Expression *ArrayExp::semantic(Scope *sc) #endif UnaExp::semantic(sc); e1 = resolveProperties(sc, e1); + if (e1->op == TOKerror) + return e1; t1 = e1->type->toBasetype(); if (t1->ty != Tclass && t1->ty != Tstruct) @@ -8207,13 +8247,13 @@ Expression *ArrayExp::semantic(Scope *sc) { error("only one index allowed to index %s", t1->toChars()); goto Lerr; } - e = new IndexExp(loc, e1, (Expression *)arguments->data[0]); + e = new IndexExp(loc, e1, (*arguments)[0]); return e->semantic(sc); } // Run semantic() on each argument for (size_t i = 0; i < arguments->dim; i++) - { e = (Expression *)arguments->data[i]; + { e = (*arguments)[i]; e = e->semantic(sc); if (!e->type) @@ -8222,7 +8262,7 @@ Expression *ArrayExp::semantic(Scope *sc) } else if (e->type == Type::terror) goto Lerr; - arguments->data[i] = (void *)e; + (*arguments)[i] = e; } expandTuples(arguments); @@ -8239,14 +8279,14 @@ Lerr: return new ErrorExp(); } -#if DMDV2 + int ArrayExp::isLvalue() { if (type && type->toBasetype()->ty == Tvoid) return 0; return 1; } -#endif + Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) { @@ -8328,12 +8368,12 @@ void CommaExp::checkEscapeRef() e2->checkEscapeRef(); } -#if DMDV2 + int CommaExp::isLvalue() { return e2->isLvalue(); } -#endif + Expression *CommaExp::toLvalue(Scope *sc, Expression *e) { @@ -8510,12 +8550,12 @@ Lerr: return new ErrorExp(); } -#if DMDV2 + int IndexExp::isLvalue() { return 1; } -#endif + Expression *IndexExp::toLvalue(Scope *sc, Expression *e) { @@ -10514,12 +10554,12 @@ Expression *CondExp::semantic(Scope *sc) return this; } -#if DMDV2 + int CondExp::isLvalue() { return e1->isLvalue() && e2->isLvalue(); } -#endif + Expression *CondExp::toLvalue(Scope *sc, Expression *ex) { diff --git a/dmd/expression.h b/dmd/expression.h index 5fe30801..e8ffdcda 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -136,6 +136,7 @@ struct Expression : Object virtual StringExp *toString(); virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual void toMangleBuffer(OutBuffer *buf); + virtual int isLvalue(); virtual Expression *toLvalue(Scope *sc, Expression *e); virtual Expression *modifiableLvalue(Scope *sc, Expression *e); virtual Expression *implicitCastTo(Scope *sc, Type *t); @@ -164,6 +165,11 @@ struct Expression : Object // Same as WANTvalue, but also expand variables as far as possible #define WANTexpand 8 + // Entry point for CTFE. + // A compile-time result is required. Give an error if not possible + Expression *ctfeInterpret(); + + // Implementation of CTFE for this expression virtual Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); virtual int isConst(); @@ -313,6 +319,7 @@ struct IdentifierExp : Expression char *toChars(); void dump(int indent); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); }; @@ -331,6 +338,7 @@ struct DsymbolExp : Expression char *toChars(); void dump(int indent); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); }; @@ -343,6 +351,7 @@ struct ThisExp : Expression Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); int isBool(int result); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); int inlineCost3(InlineCostState *ics); @@ -415,6 +424,7 @@ struct StringExp : Expression Expression *castTo(Scope *sc, Type *t); int compare(Object *obj); int isBool(int result); + int isLvalue(); unsigned charAt(size_t i); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); void toMangleBuffer(OutBuffer *buf); @@ -915,9 +925,10 @@ struct BinExp : Expression Expression *interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *, Expression *)); Expression *interpretCommon2(InterState *istate, CtfeGoal goal, - Expression *(*fp)(TOK, Type *, Expression *, Expression *)); + Expression *(*fp)(Loc, TOK, Type *, Expression *, Expression *)); Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); + Expression *interpretFourPointerRelation(InterState *istate, CtfeGoal goal); Expression *arrayOp(Scope *sc); Expression *doInline(InlineDoState *ids); @@ -938,6 +949,7 @@ struct BinAssignExp : BinExp } Expression *semantic(Scope *sc); + int isLvalue(); }; /****************************************************************/ @@ -1004,6 +1016,7 @@ struct DotVarExp : UnaExp DotVarExp(Loc loc, Expression *e, Declaration *var); Expression *semantic(Scope *sc); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); Expression *optimize(int result); @@ -1091,6 +1104,7 @@ struct CallExp : UnaExp #if IN_DMD elem *toElem(IRState *irs); #endif + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -1130,6 +1144,7 @@ struct PtrExp : UnaExp PtrExp(Loc loc, Expression *e); PtrExp(Loc loc, Expression *e, Type *t); Expression *semantic(Scope *sc); + int isLvalue(); void checkEscapeRef(); Expression *toLvalue(Scope *sc, Expression *e); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1285,6 +1300,7 @@ struct SliceExp : UnaExp Expression *semantic(Scope *sc); void checkEscape(); void checkEscapeRef(); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); int isBool(int result); @@ -1334,6 +1350,7 @@ struct ArrayExp : UnaExp Expression *syntaxCopy(); int apply(apply_fp_t fp, void *param); Expression *semantic(Scope *sc); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1359,6 +1376,7 @@ struct CommaExp : BinExp Expression *semantic(Scope *sc); void checkEscape(); void checkEscapeRef(); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); int isBool(int result); @@ -1382,6 +1400,7 @@ struct IndexExp : BinExp IndexExp(Loc loc, Expression *e1, Expression *e2); Expression *semantic(Scope *sc); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -1921,6 +1940,7 @@ struct CondExp : BinExp Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); void checkEscape(); void checkEscapeRef(); + int isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); Expression *checkToBoolean(); @@ -2036,5 +2056,8 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *n void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex); void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex); +int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len); +int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len); + #endif /* DMD_EXPRESSION_H */ diff --git a/dmd/func.c b/dmd/func.c index 426bad52..540bb8ef 100644 --- a/dmd/func.c +++ b/dmd/func.c @@ -47,6 +47,7 @@ FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageCla outId = NULL; vresult = NULL; returnLabel = NULL; + scout = NULL; fensure = NULL; fbody = NULL; localsymtab = NULL; @@ -436,9 +437,6 @@ void FuncDeclaration::semantic(Scope *sc) break; if (!this->parent->isClassDeclaration() // if both are mixins then error -#if !BREAKABI - && !isDtorDeclaration() -#endif #if DMDV2 && !isPostBlitDeclaration() #endif @@ -484,7 +482,7 @@ void FuncDeclaration::semantic(Scope *sc) for (int i = 0; i < cd->interfaces_dim; i++) { BaseClass *b = cd->interfaces[i]; - vi = findVtblIndex(&b->base->vtbl, b->base->vtbl.dim); + vi = findVtblIndex((Dsymbols *)&b->base->vtbl, b->base->vtbl.dim); switch (vi) { case -1: @@ -671,7 +669,7 @@ void FuncDeclaration::semantic(Scope *sc) fdrequire = fd; } - if (!outId && f->nextOf()->toBasetype()->ty != Tvoid) + if (!outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid) outId = Id::result; // provide a default if (fensure) @@ -771,6 +769,12 @@ void FuncDeclaration::semantic3(Scope *sc) } } + if (!fbody && inferRetType && !type->nextOf()) + { + error("has no function body with return type inference"); + return; + } + if (frequire) { for (int i = 0; i < foverrides.dim; i++) @@ -813,7 +817,7 @@ void FuncDeclaration::semantic3(Scope *sc) STCproperty | STCsafe | STCtrusted | STCsystem); sc2->protection = PROTpublic; sc2->explicitProtection = 0; - sc2->structalign = 8; + sc2->structalign = STRUCTALIGN_DEFAULT; sc2->incontract = 0; sc2->enclosingFinally = NULL; sc2->enclosingScopeExit = NULL; @@ -887,7 +891,6 @@ void FuncDeclaration::semantic3(Scope *sc) if (f->linkage == LINKd) { // Declare _arguments[] -#if BREAKABI v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); v_arguments->storage_class = STCparameter | STCin; v_arguments->semantic(sc2); @@ -899,14 +902,6 @@ void FuncDeclaration::semantic3(Scope *sc) _arguments->semantic(sc2); sc2->insert(_arguments); _arguments->parent = this; -#else - t = Type::typeinfo->type->arrayOf(); - v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; -#endif } if (f->linkage == LINKd || (f->parameters && Parameter::dim(f->parameters))) { // Declare _argptr @@ -1010,7 +1005,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (f->parameters) { for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = (Parameter *)f->parameters->data[i]; + { Parameter *arg = (*f->parameters)[i]; if (!arg->ident) continue; // never used, so ignore @@ -1025,7 +1020,7 @@ void FuncDeclaration::semantic3(Scope *sc) VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); assert(v); Expression *e = new VarExp(v->loc, v); - exps->data[j] = (void *)e; + (*exps)[j] = e; } assert(arg->ident); TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); @@ -1039,145 +1034,106 @@ void FuncDeclaration::semantic3(Scope *sc) } } - /* Do the semantic analysis on the [in] preconditions and - * [out] postconditions. - */ - sc2->incontract++; + // Precondition invariant + Statement *fpreinv = NULL; + if (addPreInvariant()) + { + Expression *e = NULL; + if (isDtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); - if (frequire) - { /* frequire is composed of the [in] contracts - */ - // BUG: need to error if accessing out parameters - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - // BUG: verify that all in and ref parameters are read - frequire = frequire->semantic(sc2); - labtab = NULL; // so body can't refer to labels + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + Expression *v = new ThisExp(0); + v->type = vthis->type; +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif + Expression *se = new StringExp(0, (char *)"null this"); + se = se->semantic(sc); + se->type = Type::tchar->arrayOf(); + e = new AssertExp(loc, v, se); + } + if (e) + fpreinv = new ExpStatement(0, e); + } + + // Postcondition invariant + Statement *fpostinv = NULL; + if (addPostInvariant()) + { + Expression *e = NULL; + if (isCtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + Expression *v = new ThisExp(0); + v->type = vthis->type; +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif + e = new AssertExp(0, v); + } + if (e) + fpostinv = new ExpStatement(0, e); } if (fensure || addPostInvariant()) - { /* fensure is composed of the [out] contracts - */ - if (!type->nextOf()) - { // Have to do semantic() on fbody first - error("post conditions are not supported if the return type is inferred"); - return; + { + if ((fensure && global.params.useOut) || fpostinv) + { returnLabel = new LabelDsymbol(Id::returnLabel); } + // scope of out contract (need for vresult->semantic) + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc2->scopesym; + scout = sc2->push(sym); + } + + if (fbody) + { ScopeDsymbol *sym = new ScopeDsymbol(); sym->parent = sc2->scopesym; sc2 = sc2->push(sym); - assert(type->nextOf()); - if (type->nextOf()->ty == Tvoid) - { - if (outId) - error("void functions have no result"); - } - else - { - if (!outId) - outId = Id::result; // provide a default - } - - if (outId) - { // Declare result variable - VarDeclaration *v; - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - v->noscope = 1; -#if DMDV2 - if (!isVirtual()) - v->storage_class |= STCconst; - if (f->isref) - { - v->storage_class |= STCref | STCforeach; - } -#endif - sc2->incontract--; - v->semantic(sc2); - sc2->incontract++; - if (!sc2->insert(v)) - error("out result %s is already defined", v->toChars()); - v->parent = this; - vresult = v; - - // vresult gets initialized with the function return value - // in ReturnStatement::semantic() - } - - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - if (fensure) - { fensure = fensure->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (!global.params.useOut) - { fensure = NULL; // discard - vresult = NULL; - } - - // Postcondition invariant - if (addPostInvariant()) - { - Expression *e = NULL; - if (isCtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - Expression *v = new ThisExp(0); - v->type = vthis->type; -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - e = new AssertExp(0, v); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - if (fensure) - fensure = new CompoundStatement(0, s, fensure); - else - fensure = s; - } - } - - if (fensure) - { returnLabel = new LabelDsymbol(Id::returnLabel); - LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); - returnLabel->statement = ls; - } - sc2 = sc2->pop(); - } - - sc2->incontract--; - - if (fbody) - { ClassDeclaration *cd = isClassMember(); + ClassDeclaration *cd = isClassMember(); /* If this is a class constructor */ @@ -1220,7 +1176,7 @@ void FuncDeclaration::semantic3(Scope *sc) } else { - for (int i = 0; i < ad->members->dim; i++) + for (size_t i = 0; i < ad->members->dim; i++) { Dsymbol *s = (Dsymbol *)ad->members->data[i]; s->checkCtorConstInit(); @@ -1235,7 +1191,7 @@ void FuncDeclaration::semantic3(Scope *sc) // Verify that all the ctorinit fields got initialized if (!(sc2->callSuper & CSXthis_ctor)) { - for (int i = 0; i < cd->fields.dim; i++) + for (size_t i = 0; i < cd->fields.dim; i++) { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; if (v->ctorinit == 0 && v->isCtorinit()) @@ -1280,15 +1236,7 @@ void FuncDeclaration::semantic3(Scope *sc) int offend = blockexit & BEfallthru; #endif - if (type->nextOf()->ty == Tvoid) - { - if (offend && isMain()) - { // Add a return 0; statement - Statement *s = new ReturnStatement(0, new IntegerExp(0)); - fbody = new CompoundStatement(0, fbody, s); - } - } - else + if (type->nextOf()->ty != Tvoid) { if (offend) { Expression *e; @@ -1317,6 +1265,66 @@ void FuncDeclaration::semantic3(Scope *sc) } } } + + sc2 = sc2->pop(); + } + + Statement *freq = frequire; + Statement *fens = fensure; + + /* Do the semantic analysis on the [in] preconditions and + * [out] postconditions. + */ + if (freq) + { /* frequire is composed of the [in] contracts + */ + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc2->scopesym; + sc2 = sc2->push(sym); + sc2->incontract++; + + // BUG: need to error if accessing out parameters + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + // BUG: verify that all in and ref parameters are read + DsymbolTable *labtab_save = labtab; + labtab = NULL; // so in contract can't refer to out/body labels + freq = freq->semantic(sc2); + labtab = labtab_save; + + sc2->incontract--; + sc2 = sc2->pop(); + + if (!global.params.useIn) + freq = NULL; + } + + if (fens) + { /* fensure is composed of the [out] contracts + */ + if (type->nextOf()->ty == Tvoid && outId) + { + error("void functions have no result"); + } + + if (type->nextOf()->ty != Tvoid) + buildResultVar(); + + sc2 = scout; //push + sc2->incontract++; + + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + DsymbolTable *labtab_save = labtab; + labtab = NULL; // so out contract can't refer to in/body labels + fens = fens->semantic(sc2); + labtab = labtab_save; + + sc2->incontract--; + sc2 = sc2->pop(); + + if (!global.params.useOut) + fens = NULL; } { @@ -1420,91 +1428,34 @@ void FuncDeclaration::semantic3(Scope *sc) // Merge contracts together with body into one compound statement - if (frequire && global.params.useIn) - { frequire->incontract = 1; - a->push(frequire); - } - - // Precondition invariant - if (addPreInvariant()) + if (freq || fpreinv) { - Expression *e = NULL; - Expression *ee = NULL; - if (isDtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); + if (!freq) + freq = fpreinv; + else if (fpreinv) + freq = new CompoundStatement(0, freq, fpreinv); - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - // LDC: unless this is a struct without invariant - StructDeclaration* sd = ad->isStructDeclaration(); - if (!sd || sd->inv) - { - ThisExp *v = new ThisExp(0); - v->type = vthis->type; - e = new AssertExp(loc, v, NULL); - } - - // LDC: check for null this - ThisExp* v = new ThisExp(0); - v->type = vthis->type; -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - v->var = vthis; - - NullExp *nv = new NullExp(0); - nv->type = v->type; - - IdentityExp *ie = new IdentityExp(TOKnotidentity, 0, v, nv); - ie->type = Type::tbool; - - Expression *se = new StringExp(0, (char *)"null this"); - se = se->semantic(sc); - se->type = Type::tchar->arrayOf(); - - ee = new AssertExp(loc, ie, se); - } - if (ee) - { - ExpStatement *s = new ExpStatement(0, ee); - a->push(s); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - a->push(s); - } + freq->incontract = 1; + a->push(freq); } if (fbody) a->push(fbody); - if (fensure) + if (fens || fpostinv) { + if (!fens) + fens = fpostinv; + else if (fpostinv) + fens = new CompoundStatement(0, fpostinv, fens); + + LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fens); + returnLabel->statement = ls; a->push(returnLabel->statement); - if (type->nextOf()->ty != Tvoid) + if (type->nextOf()->ty != Tvoid && vresult) { // Create: return vresult; - assert(vresult); Expression *e = new VarExp(0, vresult); if (tintro) { e = e->implicitCastTo(sc, tintro->nextOf()); @@ -1514,6 +1465,11 @@ void FuncDeclaration::semantic3(Scope *sc) a->push(s); } } + if (isMain() && type->nextOf()->ty == Tvoid) + { // Add a return 0; statement + Statement *s = new ReturnStatement(0, new IntegerExp(0)); + a->push(s); + } fbody = new CompoundStatement(0, a); #if DMDV2 @@ -1522,7 +1478,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + VarDeclaration *v = (*parameters)[i]; if (v->storage_class & (STCref | STCout)) continue; @@ -1649,6 +1605,48 @@ void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) } } +/**************************************************** + * Declare result variable lazily. + */ + +void FuncDeclaration::buildResultVar() +{ + if (vresult) + return; + + assert(type->nextOf()); + assert(type->nextOf()->toBasetype()->ty != Tvoid); + TypeFunction *tf = (TypeFunction *)(type); + + Loc loc = this->loc; + + if (fensure) + loc = fensure->loc; + + if (!outId) + outId = Id::result; // provide a default + + VarDeclaration *v = new VarDeclaration(loc, type->nextOf(), outId, NULL); + v->noscope = 1; + v->storage_class |= STCresult; +#if DMDV2 + if (!isVirtual()) + v->storage_class |= STCconst; + if (tf->isref) + { + v->storage_class |= STCref | STCforeach; + } +#endif + v->semantic(scout); + if (!scout->insert(v)) + error("out result %s is already defined", v->toChars()); + v->parent = this; + vresult = v; + + // vresult gets initialized with the function return value + // in ReturnStatement::semantic() +} + /**************************************************** * Merge into this function the 'in' contracts of all it overrides. * 'in's are OR'd together, i.e. only one of them needs to pass. @@ -1674,7 +1672,7 @@ Statement *FuncDeclaration::mergeFrequire(Statement *sf) */ for (int i = 0; i < foverrides.dim; i++) { - FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; + FuncDeclaration *fdv = foverrides[i]; /* The semantic pass on the contracts of the overridden functions must * be completed before code generation occurs (bug 3602). @@ -1729,7 +1727,7 @@ Statement *FuncDeclaration::mergeFensure(Statement *sf) */ for (int i = 0; i < foverrides.dim; i++) { - FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; + FuncDeclaration *fdv = foverrides[i]; /* The semantic pass on the contracts of the overridden functions must * be completed before code generation occurs (bug 3602 and 5230). @@ -1796,17 +1794,31 @@ int FuncDeclaration::overrides(FuncDeclaration *fd) * -2 can't determine because of forward references */ -int FuncDeclaration::findVtblIndex(Array *vtbl, int dim) +int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) { FuncDeclaration *mismatch = NULL; + int exactvi = -1; int bestvi = -1; for (int vi = 0; vi < dim; vi++) { - FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration(); + FuncDeclaration *fdv = (*vtbl)[vi]->isFuncDeclaration(); if (fdv && fdv->ident == ident) { if (type->equals(fdv->type)) // if exact match - return vi; // no need to look further + { + if (fdv->parent->isClassDeclaration()) + return vi; // no need to look further + + if (exactvi >= 0) + { + error("cannot determine overridden function"); + return exactvi; + } + exactvi = vi; + + bestvi = vi; + continue; + } int cov = type->covariant(fdv->type); //printf("\tbaseclass cov = %d\n", cov); @@ -3079,14 +3091,8 @@ char *DtorDeclaration::toChars() int DtorDeclaration::isVirtual() { - /* This should be FALSE so that dtor's don't get put into the vtbl[], - * but doing so will require recompiling everything. - */ -#if BREAKABI + // FALSE so that dtor's don't get put into the vtbl[] return FALSE; -#else - return FuncDeclaration::isVirtual(); -#endif } void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) diff --git a/dmd/hdrgen.h b/dmd/hdrgen.h index 79cfb732..44e3a5dd 100644 --- a/dmd/hdrgen.h +++ b/dmd/hdrgen.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // initial header generation implementation by Dave Fladebo // http://www.digitalmars.com @@ -8,6 +8,7 @@ // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. +#include // memset() struct HdrGenState { diff --git a/dmd/import.c b/dmd/import.c index 6497adf2..575fb340 100644 --- a/dmd/import.c +++ b/dmd/import.c @@ -98,8 +98,18 @@ void Import::load(Scope *sc) if (s->isModule()) mod = (Module *)s; else + { + if (pkg) + { ::error(loc, "can only import from a module, not from package %s.%s", pkg->toPrettyChars(), id->toChars()); + } + else + { + ::error(loc, "can only import from a module, not from package %s", + id->toChars()); + } + } #endif } @@ -374,26 +384,24 @@ void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) } } buf->printf("%s", id->toChars()); - if (names.dim > 0) { - buf->writebyte(':'); + if (names.dim) + { + buf->writestring(" : "); for (size_t i = 0; i < names.dim; i++) { - if (i > 0) { - buf->writebyte(','); - } + Identifier *name = names[i]; + Identifier *alias = aliases[i]; - Identifier *name = (Identifier *)names.data[i]; - Identifier *alias = (Identifier *)aliases.data[i]; - - if (!alias) { + if (alias) + buf->printf("%s = %s", alias->toChars(), name->toChars()); + else buf->printf("%s", name->toChars()); - alias = name; - } else { - buf->printf("%s=%s", alias->toChars(), name->toChars()); - } + + if (i < names.dim - 1) + buf->writestring(", "); } } - buf->writebyte(';'); + buf->printf(";"); buf->writenl(); } diff --git a/dmd/init.c b/dmd/init.c index c8dab487..b58468a2 100644 --- a/dmd/init.c +++ b/dmd/init.c @@ -34,7 +34,7 @@ Initializer *Initializer::syntaxCopy() return this; } -Initializer *Initializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *Initializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { return this; } @@ -87,7 +87,7 @@ Initializer *VoidInitializer::syntaxCopy() } -Initializer *VoidInitializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *VoidInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("VoidInitializer::semantic(t = %p)\n", t); type = t; @@ -144,7 +144,7 @@ void StructInitializer::addInit(Identifier *field, Initializer *value) this->value.push(value); } -Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { int errors = 0; @@ -333,7 +333,12 @@ Expression *StructInitializer::toExpression() if (unionSize == 1) { // Not a union -- default initialize if missing if (!(*elements)[i]) - (*elements)[i] = vd->type->defaultInit(); + { // Default initialize + if (vd->init) + (*elements)[i] = vd->init->toExpression(); + else + (*elements)[i] = vd->type->defaultInit(); + } } else { // anonymous union -- check for errors @@ -433,7 +438,7 @@ void ArrayInitializer::addInit(Expression *index, Initializer *value) type = NULL; } -Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { unsigned i; unsigned length; const unsigned amax = 0x80000000; @@ -462,14 +467,39 @@ Initializer *ArrayInitializer::semantic(Scope *sc, Type *t, int needInterpret) Expression *idx = index[i]; if (idx) { idx = idx->semantic(sc); - idx = idx->optimize(WANTvalue | WANTinterpret); + idx = idx->ctfeInterpret(); index[i] = idx; length = idx->toInteger(); } Initializer *val = value[i]; + ExpInitializer *ei = val->isExpInitializer(); + if (ei && !idx) + ei->expandTuples = 1; val = val->semantic(sc, t->nextOf(), needInterpret); - value[i] = val; + + ei = val->isExpInitializer(); + // found a tuple, expand it + if (ei && ei->exp->op == TOKtuple) + { + TupleExp *te = (TupleExp *)ei->exp; + index.remove(i); + value.remove(i); + + for (size_t j = 0; j < te->exps->dim; ++j) + { + Expression *e = (*te->exps)[j]; + index.insert(i + j, (Expression *)NULL); + value.insert(i + j, new ExpInitializer(e->loc, e)); + } + i--; + continue; + } + else + { + value[i] = val; + } + length++; if (length == 0) { error(loc, "array dimension overflow"); @@ -694,6 +724,7 @@ ExpInitializer::ExpInitializer(Loc loc, Expression *exp) : Initializer(loc) { this->exp = exp; + this->expandTuples = 0; } Initializer *ExpInitializer::syntaxCopy() @@ -701,14 +732,18 @@ Initializer *ExpInitializer::syntaxCopy() return new ExpInitializer(loc, exp->syntaxCopy()); } -Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) +Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret) { //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); exp = exp->semantic(sc); - int wantOptimize = needInterpret ? WANTinterpret|WANTvalue : WANTvalue; + if (exp->op == TOKerror) + return this; int olderrors = global.errors; - exp = exp->optimize(wantOptimize); + if (needInterpret) + exp = exp->ctfeInterpret(); + else + exp = exp->optimize(WANTvalue); if (!global.gag && olderrors != global.errors) return this; // Failed, suppress duplicate error messages @@ -716,6 +751,11 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) exp->error("initializer must be an expression, not '%s'", exp->toChars()); Type *tb = t->toBasetype(); + if (exp->op == TOKtuple && + expandTuples && + !exp->implicitConvTo(t)) + return new ExpInitializer(loc, exp); + /* Look for case of initializing a static array with a too-short * string literal, such as: * char[5] foo = "abc"; @@ -745,8 +785,13 @@ Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) } exp = exp->implicitCastTo(sc, t); + if (exp->op == TOKerror) + return this; L1: - exp = exp->optimize(wantOptimize); + if (needInterpret) + exp = exp->ctfeInterpret(); + else + exp = exp->optimize(WANTvalue); //printf("-ExpInitializer::semantic(): "); exp->print(); return this; } diff --git a/dmd/init.h b/dmd/init.h index 35e314e2..08503335 100644 --- a/dmd/init.h +++ b/dmd/init.h @@ -28,6 +28,7 @@ struct ArrayInitializer; struct ExpInitializer; struct HdrGenState; +enum NeedInterpret { INITnointerpret, INITinterpret }; #if IN_LLVM namespace llvm { @@ -41,8 +42,7 @@ struct Initializer : Object Initializer(Loc loc); virtual Initializer *syntaxCopy(); - // needInterpret is WANTinterpret if must be a manifest constant, 0 if not. - virtual Initializer *semantic(Scope *sc, Type *t, int needInterpret); + virtual Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); virtual Type *inferType(Scope *sc); virtual Expression *toExpression() = 0; virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; @@ -66,7 +66,7 @@ struct VoidInitializer : Initializer VoidInitializer(Loc loc); Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); + Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -88,7 +88,7 @@ struct StructInitializer : Initializer StructInitializer(Loc loc); Initializer *syntaxCopy(); void addInit(Identifier *field, Initializer *value); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); + Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -113,7 +113,7 @@ struct ArrayInitializer : Initializer ArrayInitializer(Loc loc); Initializer *syntaxCopy(); void addInit(Expression *index, Initializer *value); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); + Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Type *inferType(Scope *sc); Expression *toExpression(); Initializer *toAssocArrayInitializer(); @@ -130,10 +130,11 @@ struct ArrayInitializer : Initializer struct ExpInitializer : Initializer { Expression *exp; + int expandTuples; ExpInitializer(Loc loc, Expression *exp); Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); + Initializer *semantic(Scope *sc, Type *t, NeedInterpret needInterpret); Type *inferType(Scope *sc); Expression *toExpression(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); diff --git a/dmd/inline.c b/dmd/inline.c index b567ea5a..78438659 100644 --- a/dmd/inline.c +++ b/dmd/inline.c @@ -14,6 +14,7 @@ #include #include #include +#include // memset() #include "id.h" #include "init.h" diff --git a/dmd/interpret.c b/dmd/interpret.c index 26d04fac..da2d1561 100644 --- a/dmd/interpret.c +++ b/dmd/interpret.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 @@ -10,6 +10,7 @@ #include #include #include +#include // mem{cpy|set}() #include "rmem.h" @@ -27,6 +28,8 @@ #include "attrib.h" // for AttribDeclaration #include "template.h" +#include "port.h" +int RealEquals(real_t x1, real_t x2); #define LOG 0 @@ -62,7 +65,7 @@ private: size_t framepointer; // current frame pointer size_t maxStackPointer; // most stack we've ever used public: - CtfeStack() : framepointer(0) + CtfeStack() : framepointer(0), maxStackPointer(0) { } size_t stackPointer() @@ -92,16 +95,16 @@ public: { assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < globalValues.dim); - return globalValues.tdata()[v->ctfeAdrOnStack]; + return globalValues[v->ctfeAdrOnStack]; } assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - return values.tdata()[v->ctfeAdrOnStack]; + return values[v->ctfeAdrOnStack]; } void setValue(VarDeclaration *v, Expression *e) { assert(!v->isDataseg() || v->isCTFE()); assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - values.tdata()[v->ctfeAdrOnStack] = e; + values[v->ctfeAdrOnStack] = e; } void push(VarDeclaration *v) { @@ -109,7 +112,7 @@ public: if (v->ctfeAdrOnStack!= (size_t)-1 && v->ctfeAdrOnStack >= framepointer) { // Already exists in this frame, reuse it. - values.tdata()[v->ctfeAdrOnStack] = NULL; + values[v->ctfeAdrOnStack] = NULL; return; } savedId.push((void *)(v->ctfeAdrOnStack)); @@ -122,7 +125,7 @@ public: assert(!v->isDataseg() || v->isCTFE()); assert(!(v->storage_class & (STCref | STCout))); int oldid = v->ctfeAdrOnStack; - v->ctfeAdrOnStack = (size_t)(savedId.tdata()[oldid]); + v->ctfeAdrOnStack = (size_t)(savedId[oldid]); if (v->ctfeAdrOnStack == values.dim - 1) { values.pop(); @@ -137,8 +140,8 @@ public: assert(values.dim >= stackpointer && stackpointer >= 0); for (size_t i = stackpointer; i < values.dim; ++i) { - VarDeclaration *v = vars.tdata()[i]; - v->ctfeAdrOnStack = (size_t)(savedId.tdata()[i]); + VarDeclaration *v = vars[i]; + v->ctfeAdrOnStack = (size_t)(savedId[i]); } values.setDim(stackpointer); vars.setDim(stackpointer); @@ -221,6 +224,7 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, Expression *scrubReturnValue(Loc loc, Expression *e); bool isAssocArray(Type *t); bool isPointer(Type *t); +Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2); // CTFE only expressions #define TOKclassreference ((TOK)(TOKMAX+1)) @@ -258,7 +262,7 @@ struct ClassReferenceExp : Expression { fieldsSoFar += cd->fields.dim; cd = cd->baseClass; } - return cd->fields.tdata()[index - fieldsSoFar]; + return cd->fields[index - fieldsSoFar]; } // Return index of the field, or -1 if not found int getFieldIndex(Type *fieldtype, size_t fieldoffset) @@ -270,7 +274,7 @@ struct ClassReferenceExp : Expression { fieldsSoFar += cd->fields.dim; cd = cd->baseClass; } - Dsymbol *s = cd->fields.tdata()[j - fieldsSoFar]; + Dsymbol *s = cd->fields[j - fieldsSoFar]; VarDeclaration *v2 = s->isVarDeclaration(); if (fieldoffset == v2->offset && fieldtype->size() == v2->type->size()) @@ -290,7 +294,7 @@ struct ClassReferenceExp : Expression { fieldsSoFar += cd->fields.dim; cd = cd->baseClass; } - Dsymbol *s = cd->fields.tdata()[j - fieldsSoFar]; + Dsymbol *s = cd->fields[j - fieldsSoFar]; VarDeclaration *v2 = s->isVarDeclaration(); if (v == v2) { return value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar); @@ -328,7 +332,7 @@ int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v) { for (int i = 0; i < sd->fields.dim; ++i) { - if (sd->fields.tdata()[i] == v) + if (sd->fields[i] == v) return i; } return -1; @@ -449,8 +453,8 @@ void showCtfeExpr(Expression *e, int level = 0) return; } if (sd) - { s = sd->fields.tdata()[i]; - z = elements->tdata()[i]; + { s = sd->fields[i]; + z = (*elements)[i]; } else if (cd) { while (i - fieldsSoFar >= cd->fields.dim) @@ -459,11 +463,11 @@ void showCtfeExpr(Expression *e, int level = 0) for (int j = level; j>0; --j) printf(" "); printf(" BASE CLASS: %s\n", cd->toChars()); } - s = cd->fields.tdata()[i - fieldsSoFar]; + s = cd->fields[i - fieldsSoFar]; size_t indx = (elements->dim - fieldsSoFar)- cd->fields.dim + i; assert(indx >= 0); assert(indx < elements->dim); - z = elements->tdata()[indx]; + z = (*elements)[indx]; } if (!z) { for (int j = level; j>0; --j) printf(" "); @@ -488,6 +492,16 @@ void showCtfeExpr(Expression *e, int level = 0) } } +/************************************* + * + * Entry point for CTFE. + * A compile-time result is required. Give an error if not possible + */ +Expression *Expression::ctfeInterpret() +{ + return optimize(WANTvalue | WANTinterpret); +} + /************************************* * Attempt to interpret a function given the arguments. * Input: @@ -580,7 +594,7 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument Expressions eargs; eargs.setDim(dim); for (size_t i = 0; i < dim; i++) - { Expression *earg = arguments->tdata()[i]; + { Expression *earg = (*arguments)[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); if (arg->storageClass & (STCout | STCref)) @@ -633,13 +647,13 @@ Expression *FuncDeclaration::interpret(InterState *istate, Expressions *argument ((ThrownExceptionExp *)earg)->generateUncaughtError(); return EXP_CANT_INTERPRET; } - eargs.tdata()[i] = earg; + eargs[i] = earg; } for (size_t i = 0; i < dim; i++) - { Expression *earg = eargs.tdata()[i]; + { Expression *earg = eargs[i]; Parameter *arg = Parameter::getNth(tf->parameters, i); - VarDeclaration *v = parameters->tdata()[i]; + VarDeclaration *v = (*parameters)[i]; #if LOG printf("arg[%d] = %s\n", i, earg->toChars()); #endif @@ -805,7 +819,7 @@ Expression *CompoundStatement::interpret(InterState *istate) if (statements) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; if (s) { @@ -832,7 +846,7 @@ Expression *UnrolledLoopStatement::interpret(InterState *istate) if (statements) { for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; + { Statement *s = (*statements)[i]; e = s->interpret(istate); if (e == EXP_CANT_INTERPRET) @@ -952,19 +966,6 @@ uinteger_t resolveArrayLength(Expression *e) return 0; } -// As Equal, but resolves slices before comparing -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); - 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) { Loc loc = e1->loc; @@ -1217,38 +1218,14 @@ Expression *DoStatement::interpret(InterState *istate) istate->start = NULL; Expression *e; - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - return e; - } - if (e == EXP_CONTINUE_INTERPRET) - if (!istate->gotoTarget || istate->gotoTarget == this) - { - goto Lcontinue; - } - else // else continue at a higher level - return e; - if (e) - return e; - } - while (1) { + bool wasGoto = !!istate->start; e = body ? body->interpret(istate) : NULL; if (e == EXP_CANT_INTERPRET) break; + if (wasGoto && istate->start) + return NULL; if (e == EXP_BREAK_INTERPRET) { if (!istate->gotoTarget || istate->gotoTarget == this) @@ -1301,79 +1278,53 @@ Expression *ForStatement::interpret(InterState *istate) return e; assert(!e); } - - if (istate->start) + while (1) { + if (condition && !istate->start) + { + e = condition->interpret(istate); + if (exceptionOrCantInterpret(e)) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(FALSE)) + { e = NULL; + break; + } + assert( isTrueBool(e) ); + } + + bool wasGoto = !!istate->start; e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; if (e == EXP_CANT_INTERPRET) - return e; + break; + if (wasGoto && istate->start) + return NULL; + if (e == EXP_BREAK_INTERPRET) { if (!istate->gotoTarget || istate->gotoTarget == this) { istate->gotoTarget = NULL; - return NULL; + e = NULL; } // else break at a higher level + break; } - if (e == EXP_CONTINUE_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - goto Lcontinue; - } // else continue at a higher level - } - if (e) - return e; - } + if (e && e != EXP_CONTINUE_INTERPRET) + break; - while (1) - { - if (!condition) - goto Lhead; - e = condition->interpret(istate); - if (exceptionOrCantInterpret(e)) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (isTrueBool(e)) + if (istate->gotoTarget && istate->gotoTarget != this) + break; // continue at a higher level + istate->gotoTarget = NULL; + + if (increment) { - Lhead: - e = body ? body->interpret(istate) : NULL; + e = increment->interpret(istate); if (e == EXP_CANT_INTERPRET) break; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - if (istate->gotoTarget && istate->gotoTarget != this) - break; // continue at a higher level - Lcontinue: - istate->gotoTarget = NULL; - if (increment) - { - e = increment->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - } } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); } return e; } @@ -1431,7 +1382,7 @@ Expression *SwitchStatement::interpret(InterState *istate) { for (size_t i = 0; i < cases->dim; i++) { - CaseStatement *cs = cases->tdata()[i]; + CaseStatement *cs = (*cases)[i]; Expression * caseExp = cs->exp->interpret(istate); if (exceptionOrCantInterpret(caseExp)) return caseExp; @@ -1915,11 +1866,12 @@ Expression * resolveReferences(Expression *e, Expression *thisval) { VarExp *ve = (VarExp *)e; VarDeclaration *v = ve->var->isVarDeclaration(); + assert(v); if (v->type->ty == Tpointer) break; if (v->ctfeAdrOnStack == (size_t)-1) // If not on the stack, can't possibly be a ref. break; - if (v && v->getValue() && (v->getValue()->op == TOKslice)) + if (v->getValue() && (v->getValue()->op == TOKslice)) { SliceExp *se = (SliceExp *)v->getValue(); if (se->e1->op == TOKarrayliteral || se->e1->op == TOKassocarrayliteral || se->e1->op == TOKstring) @@ -1927,7 +1879,7 @@ Expression * resolveReferences(Expression *e, Expression *thisval) e = v->getValue(); continue; } - else if (v && v->getValue() && (v->getValue()->op==TOKindex || v->getValue()->op == TOKdotvar + else if (v->getValue() && (v->getValue()->op==TOKindex || v->getValue()->op == TOKdotvar || v->getValue()->op == TOKthis )) { e = v->getValue(); @@ -2018,10 +1970,10 @@ Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal e = EXP_CANT_INTERPRET; } else if (!e) - { - assert(0); - assert(v->init && v->init->isVoidInitializer()); - e = v->type->voidInitLiteral(v); + { assert(!(v->init && v->init->isVoidInitializer())); + // CTFE initiated from inside a function + error(loc, "variable %s cannot be read at compile time", v->toChars()); + return EXP_CANT_INTERPRET; } else if (exceptionOrCantInterpret(e)) return e; @@ -2205,7 +2157,7 @@ Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal) Expressions *expsx = NULL; for (size_t i = 0; i < exps->dim; i++) - { Expression *e = exps->tdata()[i]; + { Expression *e = (*exps)[i]; Expression *ex; ex = e->interpret(istate); @@ -2233,10 +2185,10 @@ Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal) expsx->setDim(exps->dim); for (size_t j = 0; j < i; j++) { - expsx->tdata()[j] = exps->tdata()[j]; + (*expsx)[j] = (*exps)[j]; } } - expsx->tdata()[i] = ex; + (*expsx)[i] = ex; } } if (expsx) @@ -2259,7 +2211,7 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; Expression *ex; if (e->op == TOKindex) // segfault bug 6250 @@ -2280,10 +2232,10 @@ Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) expsx->setDim(elements->dim); for (size_t j = 0; j < elements->dim; j++) { - expsx->tdata()[j] = elements->tdata()[j]; + (*expsx)[j] = (*elements)[j]; } } - expsx->tdata()[i] = ex; + (*expsx)[i] = ex; } } } @@ -2425,7 +2377,7 @@ Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) if (elements) { for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; + { Expression *e = (*elements)[i]; if (!e) continue; @@ -2445,10 +2397,10 @@ Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) expsx->setDim(elements->dim); for (size_t j = 0; j < elements->dim; j++) { - expsx->tdata()[j] = elements->tdata()[j]; + (*expsx)[j] = (*elements)[j]; } } - expsx->tdata()[i] = ex; + (*expsx)[i] = ex; } } } @@ -2480,7 +2432,7 @@ ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type, for (size_t i = 0; i < dim; i++) { if (mustCopy) elem = copyLiteral(elem); - elements->tdata()[i] = elem; + (*elements)[i] = elem; } ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); ae->type = type; @@ -2520,7 +2472,7 @@ StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type, Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *istate, Expressions *arguments, int argnum) { - Expression *lenExpr = ((arguments->tdata()[argnum]))->interpret(istate); + Expression *lenExpr = (((*arguments)[argnum]))->interpret(istate); if (exceptionOrCantInterpret(lenExpr)) return lenExpr; size_t len = (size_t)(lenExpr->toInteger()); @@ -2535,7 +2487,7 @@ Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *is Expressions *elements = new Expressions(); elements->setDim(len); for (size_t i = 0; i < len; i++) - elements->tdata()[i] = copyLiteral(elem); + (*elements)[i] = copyLiteral(elem); ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); ae->type = newtype; ae->ownedByCtfe = true; @@ -2596,7 +2548,7 @@ Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) fieldsSoFar -= c->fields.dim; for (size_t i = 0; i < c->fields.dim; i++) { - Dsymbol *s = c->fields.tdata()[i]; + Dsymbol *s = c->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(loc); @@ -2867,20 +2819,24 @@ BIN_INTERPRET(Pow) #endif -typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); +typedef Expression *(*fp2_t)(Loc loc, enum TOK, Type *, Expression *, Expression *); -// Return EXP_CANT_INTERPRET if they point to independent memory blocks -Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) +/** Return true if agg1 and agg2 are pointers to the same memory block +*/ +bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2) { - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(e1, &ofs1); - Expression *agg2 = getAggregateFromPointer(e2, &ofs2); // Note that type painting can occur with VarExp, so we // must compare the variables being pointed to. - if (agg1 == agg2 || - (agg1->op == TOKvar && agg2->op == TOKvar && - ((VarExp *)agg1)->var == ((VarExp *)agg2)->var) - ) + return agg1 == agg2 || + (agg1->op == TOKvar && agg2->op == TOKvar && + ((VarExp *)agg1)->var == ((VarExp *)agg2)->var); +} + +// Return 1 if true, 0 if false +// -1 if comparison is illegal because they point to non-comparable memory blocks +int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2) +{ + if ( pointToSameMemoryBlock(agg1, agg2) ) { dinteger_t cm = ofs1 - ofs2; dinteger_t n; @@ -2898,16 +2854,27 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex default: assert(0); } - return new IntegerExp(loc, n, type); + return n; } + bool null1 = ( agg1->op == TOKnull ); + bool null2 = ( agg2->op == TOKnull ); + int cmp; - if (agg1->op == TOKnull) + if (null1 || null2) { - cmp = (agg2->op == TOKnull); - } - else if (agg2->op == TOKnull) - { - cmp = 0; + switch (op) + { + case TOKlt: cmp = null1 && !null2; break; + case TOKgt: cmp = !null1 && null2; break; + case TOKle: cmp = null1; break; + case TOKge: cmp = null2; break; + case TOKidentity: + case TOKequal: + case TOKnotidentity: // 'cmp' gets inverted below + case TOKnotequal: + cmp = (null1 == null2); + break; + } } else { @@ -2920,30 +2887,237 @@ Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Ex cmp = 0; break; default: - return EXP_CANT_INTERPRET; + return -1; // memory blocks are different } } + if (op == TOKnotidentity || op == TOKnotequal) + cmp ^= 1; + return cmp; +} + + +int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2); + +/* Conceptually the same as memcmp(e1, e2). + * e1 and e2 may be strings, arrayliterals, or slices. + * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. + * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. + */ +int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len) +{ + // Resolve slices, if necessary + uinteger_t lo1 = 0; + uinteger_t lo2 = 0; + + Expression *x = e1; + if (x->op == TOKslice) + { lo1 = ((SliceExp *)x)->lwr->toInteger(); + x = ((SliceExp*)x)->e1; + } + StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : 0; + ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; + + x = e2; + if (x->op == TOKslice) + { lo2 = ((SliceExp *)x)->lwr->toInteger(); + x = ((SliceExp*)x)->e1; + } + StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : 0; + ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : 0; + + // Now both must be either TOKarrayliteral or TOKstring + if (se1 && se2) + return sliceCmpStringWithString(se1, se2, lo1, lo2, len); + if (se1 && ae2) + return sliceCmpStringWithArray(se1, ae2, lo1, lo2, len); + if (se2 && ae1) + return -sliceCmpStringWithArray(se2, ae1, lo2, lo1, len); + + assert (ae1 && ae2); + // Comparing two array literals. This case is potentially recursive. + // If they aren't strings, we just need an equality check rather than + // a full cmp. + bool needCmp = ae1->type->nextOf()->isintegral(); + for (size_t i = 0; i < len; i++) + { Expression *ee1 = (*ae1->elements)[lo1 + i]; + Expression *ee2 = (*ae2->elements)[lo2 + i]; + if (needCmp) + { int c = ee1->toInteger() - ee2->toInteger(); + if (c) + return c; + } + else + { if (ctfeRawCmp(loc, ee1, ee2)) + return 1; + } + } + return 0; +} + +bool isArray(Expression *e) +{ + return e->op == TOKarrayliteral || e->op == TOKstring || + e->op == TOKslice || e->op == TOKnull; +} + +/* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. + * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. + */ +int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2) +{ + if (e1->op == TOKclassreference || e2->op == TOKclassreference) + { if (e1->op == TOKclassreference && e2->op == TOKclassreference && + ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value) + return 0; + return 1; + } + if (e1->op == TOKnull && e2->op == TOKnull) + return 0; + + if (e1->type->ty == Tpointer && e2->type->ty == Tpointer) + { // Can only be an equality test. + if (e1->op == TOKnull && e2->op == TOKnull) + return 0; + dinteger_t ofs1, ofs2; + Expression *agg1 = getAggregateFromPointer(e1, &ofs1); + Expression *agg2 = getAggregateFromPointer(e2, &ofs2); + if ((agg1 == agg2) || (agg1->op == TOKvar && agg2->op == TOKvar && + ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)) + { if (ofs1 == ofs2) + return 0; + } + return 1; + } + if (isArray(e1) && isArray(e2)) + { + uinteger_t len1 = resolveArrayLength(e1); + uinteger_t len2 = resolveArrayLength(e2); + if (len1 != len2) // only for equality + return len1 - len2; + if (len1 == 0 || len2 == 0) + return len1 - len2; // Equal - both are empty + return ctfeCmpArrays(loc, e1, e2, len1); + } + if (e1->type->isintegral()) + { + return e1->toInteger() - e2->toInteger(); + } + real_t r1; + real_t r2; + if (e1->type->isreal()) + { + r1 = e1->toReal(); + r2 = e2->toReal(); + goto L1; + } + else if (e1->type->isimaginary()) + { + r1 = e1->toImaginary(); + r2 = e2->toImaginary(); + L1: +#if __DMC__ + return (r1 != r2); +#else + if (Port::isNan(r1) || Port::isNan(r2)) // if unordered + { + return 1; + } + else + { + return (r1 != r2); + } +#endif + } + else if (e1->type->iscomplex()) + { + return e1->toComplex() != e2->toComplex(); + } + + if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) + { StructLiteralExp *es1 = (StructLiteralExp *)e1; + StructLiteralExp *es2 = (StructLiteralExp *)e2; + // For structs, we only need to return 0 or 1 (< and > aren't legal). + + if (es1->sd != es2->sd) + return 1; + else if ((!es1->elements || !es1->elements->dim) && + (!es2->elements || !es2->elements->dim)) + return 0; // both arrays are empty + else if (!es1->elements || !es2->elements) + return 1; + else if (es1->elements->dim != es2->elements->dim) + return 1; + else + { + for (size_t i = 0; i < es1->elements->dim; i++) + { Expression *ee1 = (*es1->elements)[i]; + Expression *ee2 = (*es2->elements)[i]; + + if (ee1 == ee2) + continue; + if (!ee1 || !ee2) + return 1; + int cmp = ctfeRawCmp(loc, ee1, ee2); + if (cmp) + return 1; + } + return 0; // All elements are equal + } + } + error(loc, "CTFE internal error: bad compare"); + assert(0); + return 0; +} + +// As Equal, but resolves slices before comparing +Expression *ctfeEqual(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) +{ + int cmp = !ctfeRawCmp(loc, e1, e2); + if (op == TOKnotequal) + cmp ^= 1; + return new IntegerExp(loc, cmp, type); +} + +Expression *ctfeIdentity(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) +{ + int cmp; + if (e1->op == TOKnull) + { + cmp = (e2->op == TOKnull); + } + else if (e2->op == TOKnull) + { + cmp = 0; + } + else if (e1->op == TOKsymoff && e2->op == TOKsymoff) + { + SymOffExp *es1 = (SymOffExp *)e1; + SymOffExp *es2 = (SymOffExp *)e2; + cmp = (es1->var == es2->var && es1->offset == es2->offset); + } + else if (e1->type->isreal()) + cmp = RealEquals(e1->toReal(), e2->toReal()); + else if (e1->type->isimaginary()) + cmp = RealEquals(e1->toImaginary(), e2->toImaginary()); + else if (e1->type->iscomplex()) + { complex_t v1 = e1->toComplex(); + complex_t v2 = e2->toComplex(); + cmp = RealEquals(creall(v1), creall(v2)) && + RealEquals(cimagl(v1), cimagl(v1)); + } + else + cmp = !ctfeRawCmp(loc, e1, e2); + if (op == TOKnotidentity || op == TOKnotequal) cmp ^= 1; return new IntegerExp(loc, cmp, type); } -Expression *ctfeIdentity(enum TOK op, Type *type, Expression *e1, Expression *e2) +Expression *ctfeCmp(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) { - if (e1->op == TOKclassreference || e2->op == TOKclassreference) - { - int cmp = 0; - if (e1->op == TOKclassreference && e2->op == TOKclassreference && - ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value) - cmp = 1; - if (op == TOKnotidentity || op == TOKnotequal) - cmp ^= 1; - return new IntegerExp(e1->loc, cmp, type); - } - return Identity(op, type, e1, e2); + return Cmp(op, type, e1, e2); } - Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp) { Expression *e; Expression *e1; @@ -2960,14 +3134,20 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp e2 = this->e2->interpret(istate, ctfeNeedLvalue); if (exceptionOrCantInterpret(e2)) return e2; - e = comparePointers(loc, op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) + dinteger_t ofs1, ofs2; + Expression *agg1 = getAggregateFromPointer(e1, &ofs1); + Expression *agg2 = getAggregateFromPointer(e2, &ofs2); + int cmp = comparePointers(loc, op, type, agg1, ofs1, agg2, ofs2); + if (cmp == -1) { - error("%s and %s point to independent memory blocks and " - "cannot be compared at compile time", this->e1->toChars(), - this->e2->toChars()); + char dir = (op == TOKgt || op == TOKge) ? '<' : '>'; + error("The ordering of pointers to unrelated memory blocks is indeterminate in CTFE." + " To check if they point to the same memory block, use both > and < inside && or ||, " + "eg (%s && %s %c= %s + 1)", + toChars(), this->e1->toChars(), dir, this->e2->toChars()); + return EXP_CANT_INTERPRET; } - return e; + return new IntegerExp(loc, cmp, type); } e1 = this->e1->interpret(istate); if (exceptionOrCantInterpret(e1)) @@ -3001,7 +3181,7 @@ Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp error("cannot compare %s at compile time", e2->toChars()); goto Lcant; } - e = (*fp)(op, type, e1, e2); + e = (*fp)(loc, op, type, e1, e2); if (e == EXP_CANT_INTERPRET) error("%s cannot be interpreted at compile time", toChars()); return e; @@ -3016,9 +3196,9 @@ Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ return interpretCommon2(istate, goal, &opfunc); \ } -BIN_INTERPRET2(Equal, Equal) +BIN_INTERPRET2(Equal, ctfeEqual) BIN_INTERPRET2(Identity, ctfeIdentity) -BIN_INTERPRET2(Cmp, Cmp) +BIN_INTERPRET2(Cmp, ctfeCmp) /* Helper functions for BinExp::interpretAssignCommon */ @@ -3034,9 +3214,9 @@ Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expre for (size_t j = 0; j < expsx->dim; j++) { if (j == indexToChange) - expsx->tdata()[j] = newelem; + (*expsx)[j] = newelem; else - expsx->tdata()[j] = oldelems->tdata()[j]; + (*expsx)[j] = oldelems->tdata()[j]; } return expsx; } @@ -3236,7 +3416,7 @@ Expression *copyLiteral(Expression *e) Expression *m = oldelems->tdata()[i]; // We need the struct definition to detect block assignment AggregateDeclaration *sd = se->sd; - Dsymbol *s = sd->fields.tdata()[i]; + Dsymbol *s = sd->fields[i]; VarDeclaration *v = s->isVarDeclaration(); assert(v); // If it is a void assignment, use the default initializer @@ -3528,7 +3708,8 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ } bool wantRef = false; if (!fp && this->e1->type->toBasetype() == this->e2->type->toBasetype() && - (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type)) + (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type) + || e1->type->toBasetype()->ty == Tclass) // e = *x is never a reference, because *x is always a value && this->e2->op != TOKstar ) @@ -3768,18 +3949,18 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ assert(oldval->op == TOKarrayliteral); ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval; for (size_t i = 0; i < copylen; i++) - elements->tdata()[i] = ae->elements->tdata()[i]; + (*elements)[i] = ae->elements->tdata()[i]; if (elemType->ty == Tstruct || elemType->ty == Tsarray) { /* If it is an aggregate literal representing a value type, * we need to create a unique copy for each element */ for (size_t i = copylen; i < newlen; i++) - elements->tdata()[i] = copyLiteral(defaultElem); + (*elements)[i] = copyLiteral(defaultElem); } else { for (size_t i = copylen; i < newlen; i++) - elements->tdata()[i] = defaultElem; + (*elements)[i] = defaultElem; } ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements); aae->type = t; @@ -3983,7 +4164,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_ // (in which case, we already have the lvalue). if (this->e1->op != TOKcall && !(this->e1->op==TOKvar && ((VarExp*)this->e1)->var->storage_class & (STCref | STCout))) - e1 = e1->interpret(istate, ctfeNeedLvalue); + e1 = e1->interpret(istate, isPointer(type)? ctfeNeedLvalueRef : ctfeNeedLvalue); if (exceptionOrCantInterpret(e1)) return e1; if (e1->op == TOKstructliteral && newval->op == TOKstructliteral) @@ -4621,12 +4802,184 @@ Expression *PostExp::interpret(InterState *istate, CtfeGoal goal) return e; } +/* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison; + * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison; + * 0 otherwise + */ +int isPointerCmpExp(Expression *e, Expression **p1, Expression **p2) +{ + int ret = 1; + while (e->op == TOKnot) + { ret *= -1; + e = ((NotExp *)e)->e1; + } + switch(e->op) + { + case TOKlt: + case TOKle: + ret *= -1; + /* fall through */ + case TOKgt: + case TOKge: + *p1 = ((BinExp *)e)->e1; + *p2 = ((BinExp *)e)->e2; + if ( !(isPointer((*p1)->type) && isPointer((*p2)->type)) ) + ret = 0; + break; + default: + ret = 0; + break; + } + return ret; +} + +/** Negate a relational operator, eg >= becomes < + */ +TOK reverseRelation(TOK op) +{ + switch(op) + { + case TOKge: return TOKlt; + case TOKgt: return TOKle; + case TOKle: return TOKgt; + case TOKlt: return TOKge; + default: + return assert(0), TOKreserved; + } +} + +/** If this is a four pointer relation, evaluate it, else return NULL. + * + * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2) + * where p1, p2 are expressions yielding pointers to memory block p, + * and q1, q2 are expressions yielding pointers to memory block q. + * This expression is valid even if p and q are independent memory + * blocks and are therefore not normally comparable; the && form returns true + * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns + * true if [p1..p2] lies outside [q1..q2], and false otherwise. + * + * Within the expression, any ordering of p1, p2, q1, q2 is permissible; + * the comparison operators can be any of >, <, <=, >=, provided that + * both directions (p > q and p < q) are checked. Additionally the + * relational sub-expressions can be negated, eg + * ( !(q1 < p1) && p2 <= q2 ) is valid. + */ +Expression *BinExp::interpretFourPointerRelation(InterState *istate, CtfeGoal goal) +{ + assert(op == TOKandand || op == TOKoror); + + /* It can only be an isInside expression, if both e1 and e2 are + * directional pointer comparisons. + * Note that this check can be made statically; it does not depends on + * any runtime values. This allows a JIT implementation to compile a + * special AndAndPossiblyInside, keeping the normal AndAnd case efficient. + */ + + // Save the pointer expressions and the comparison directions, + // so we can use them later. + Expression *p1, *p2, *p3, *p4; + int dir1 = isPointerCmpExp(e1, &p1, &p2); + int dir2 = isPointerCmpExp(e2, &p3, &p4); + if ( dir1 == 0 || dir2 == 0 ) + return NULL; + + //printf("FourPointerRelation %s\n", toChars()); + + // Evaluate the first two pointers + p1 = p1->interpret(istate); + if (exceptionOrCantInterpret(p1)) + return p1; + p2 = p2->interpret(istate); + if (exceptionOrCantInterpret(p1)) + return p1; + dinteger_t ofs1, ofs2; + Expression *agg1 = getAggregateFromPointer(p1, &ofs1); + Expression *agg2 = getAggregateFromPointer(p2, &ofs2); + + if ( !pointToSameMemoryBlock(agg1, agg2) + && agg1->op != TOKnull && agg2->op != TOKnull) + { // Here it is either CANT_INTERPRET, + // or an IsInside comparison returning FALSE. + p3 = p3->interpret(istate); + if (p3 == EXP_CANT_INTERPRET) + return p3; + // Note that it is NOT legal for it to throw an exception! + Expression *except = NULL; + if (exceptionOrCantInterpret(p3)) + except = p3; + else + { + p4 = p4->interpret(istate); + if (p4 == EXP_CANT_INTERPRET) + return p4; + if (exceptionOrCantInterpret(p3)) + except = p4; + } + if (except) + { error("Comparison %s of pointers to unrelated memory blocks remains " + "indeterminate at compile time " + "because exception %s was thrown while evaluating %s", + this->e1->toChars(), except->toChars(), this->e2->toChars()); + return EXP_CANT_INTERPRET; + } + dinteger_t ofs3,ofs4; + Expression *agg3 = getAggregateFromPointer(p3, &ofs3); + Expression *agg4 = getAggregateFromPointer(p4, &ofs4); + // The valid cases are: + // p1 > p2 && p3 > p4 (same direction, also for < && <) + // p1 > p2 && p3 < p4 (different direction, also < && >) + // Changing any > into >= doesnt affect the result + if ( (dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) + && pointToSameMemoryBlock(agg2, agg3)) + || (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) + && pointToSameMemoryBlock(agg2, agg4)) ) + { // it's a legal two-sided comparison + return new IntegerExp(loc, (op == TOKandand) ? 0 : 1, type); + } + // It's an invalid four-pointer comparison. Either the second + // comparison is in the same direction as the first, or else + // more than two memory blocks are involved (either two independent + // invalid comparisons are present, or else agg3 == agg4). + error("Comparison %s of pointers to unrelated memory blocks is " + "indeterminate at compile time, even when combined with %s.", + e1->toChars(), e2->toChars()); + return EXP_CANT_INTERPRET; + } + // The first pointer expression didn't need special treatment, so we + // we need to interpret the entire expression exactly as a normal && or ||. + // This is easy because we haven't evaluated e2 at all yet, and we already + // know it will return a bool. + // But we mustn't evaluate the pointer expressions in e1 again, in case + // they have side-effects. + bool nott = false; + Expression *e = e1; + while (e->op == TOKnot) + { nott= !nott; + e = ((NotExp *)e)->e1; + } + TOK cmpop = e->op; + if (nott) + cmpop = reverseRelation(cmpop); + int cmp = comparePointers(loc, cmpop, e1->type, agg1, ofs1, agg2, ofs2); + // We already know this is a valid comparison. + assert(cmp >= 0); + if ( (op == TOKandand && cmp == 1) || (op == TOKoror && cmp == 0) ) + return e2->interpret(istate); + return new IntegerExp(loc, (op == TOKandand) ? 0 : 1, type); +} + Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) { #if LOG printf("AndAndExp::interpret() %s\n", toChars()); #endif - Expression *e = e1->interpret(istate); + + // Check for an insidePointer expression, evaluate it if so + Expression *e = interpretFourPointerRelation(istate, goal); + if (e) + return e; + + e = e1->interpret(istate); if (exceptionOrCantInterpret(e)) return e; @@ -4645,17 +4998,14 @@ Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) assert(type->ty == Tvoid); return NULL; } - if (e != EXP_CANT_INTERPRET) + if (e->isBool(FALSE)) + result = 0; + else if (isTrueBool(e)) + result = 1; + else { - if (e->isBool(FALSE)) - result = 0; - else if (isTrueBool(e)) - result = 1; - else - { - error("%s does not evaluate to a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } + error("%s does not evaluate to a boolean", e->toChars()); + e = EXP_CANT_INTERPRET; } } else @@ -4674,7 +5024,13 @@ Expression *OrOrExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("OrOrExp::interpret() %s\n", toChars()); #endif - Expression *e = e1->interpret(istate); + + // Check for an insidePointer expression, evaluate it if so + Expression *e = interpretFourPointerRelation(istate, goal); + if (e) + return e; + + e = e1->interpret(istate); if (exceptionOrCantInterpret(e)) return e; @@ -4926,7 +5282,7 @@ Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) // Inline .dup. Special case because it needs the return type. if (!pthis && fd->ident == Id::adDup && arguments && arguments->dim == 2) { - e = arguments->tdata()[1]; + e = (*arguments)[1]; e = e->interpret(istate); if (exceptionOrCantInterpret(e)) return e; @@ -5162,7 +5518,7 @@ Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) if ( agg->op == TOKarrayliteral || agg->op == TOKstring) { dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); - Type *pointee = ((TypePointer *)agg->type)->next; + //Type *pointee = ((TypePointer *)agg->type)->next; if ((indx + ofs) < 0 || (indx+ofs) > len) { error("pointer index [%lld] exceeds allocated memory block [0..%lld]", @@ -5331,7 +5687,7 @@ Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) } assert(agg->op == TOKarrayliteral || agg->op == TOKstring); dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); - Type *pointee = ((TypePointer *)agg->type)->next; + //Type *pointee = ((TypePointer *)agg->type)->next; if ((ilwr + ofs) < 0 || (iupr+ofs) > (len + 1) || iupr < ilwr) { error("pointer slice [%lld..%lld] exceeds allocated memory block [0..%lld]", @@ -5490,7 +5846,9 @@ Expression *CatExp::interpret(InterState *istate, CtfeGoal goal) e2 = resolveSlice(e2); e = ctfeCat(type, e1, e2); if (e == EXP_CANT_INTERPRET) - error("%s cannot be interpreted at compile time", toChars()); + { error("%s cannot be interpreted at compile time", toChars()); + return e; + } // We know we still own it, because we interpreted both e1 and e2 if (e->op == TOKarrayliteral) ((ArrayLiteralExp *)e)->ownedByCtfe = true; @@ -5688,9 +6046,16 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) } } if (to->ty == Tarray && e1->op == TOKslice) - { - e1 = new SliceExp(e1->loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr, - ((SliceExp *)e1)->upr); + { // Note that the slice may be void[], so when checking for dangerous + // casts, we need to use the original type, which is se->e1. + SliceExp *se = (SliceExp *)e1; + if ( !isSafePointerCast( se->e1->type->nextOf(), to->nextOf() ) ) + { + error("array cast from %s to %s is not supported at compile time", + se->e1->type->toChars(), to->toChars()); + return EXP_CANT_INTERPRET; + } + e1 = new SliceExp(e1->loc, se->e1, se->lwr, se->upr); e1->type = to; return e1; } @@ -5849,7 +6214,9 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) } if (ie->e1->op == TOKassocarrayliteral) { - e = Index(type, ie->e1, ie->e2); + e = findKeyInAA(loc, (AssocArrayLiteralExp *)ie->e1, ie->e2); + assert(e != EXP_CANT_INTERPRET); + e = paintTypeOntoLiteral(type, e); if (isGenuineIndex) { if (e->op == TOKindex) @@ -6135,8 +6502,8 @@ Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *de { Expression *ekey = ae->keys->tdata()[i]; Expression *evalue = ae->values->tdata()[i]; - args.tdata()[numParams - 1] = evalue; - if (numParams == 2) args.tdata()[0] = ekey; + args[numParams - 1] = evalue; + if (numParams == 2) args[0] = ekey; eresult = fd->interpret(istate, &args, pthis); if (exceptionOrCantInterpret(eresult)) @@ -6367,7 +6734,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del // The index only needs to be set once if (numParams == 2) - args.tdata()[0] = new IntegerExp(deleg->loc, currentIndex, indexType); + args[0] = new IntegerExp(deleg->loc, currentIndex, indexType); Expression *val = NULL; @@ -6390,7 +6757,7 @@ Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *del } val = new IntegerExp(str->loc, codepoint, charType); - args.tdata()[numParams - 1] = val; + args[numParams - 1] = val; eresult = fd->interpret(istate, &args, pthis); if (exceptionOrCantInterpret(eresult)) @@ -6431,11 +6798,11 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, args.setDim(nargs); for (size_t i = 0; i < args.dim; i++) { - Expression *earg = arguments->tdata()[i]; + Expression *earg = (*arguments)[i]; earg = earg->interpret(istate); if (exceptionOrCantInterpret(earg)) return earg; - args.tdata()[i] = earg; + args[i] = earg; } e = eval_builtin(loc, b, &args); if (!e) @@ -6508,7 +6875,7 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, assert(arguments->dim <= se->elements->dim); for (int i = 0; i < arguments->dim; ++i) { - Expression *e = arguments->tdata()[i]->interpret(istate); + Expression *e = (*arguments)[i]->interpret(istate); if (exceptionOrCantInterpret(e)) return e; se->elements->tdata()[i] = e; @@ -6536,11 +6903,11 @@ Expression *evaluateIfBuiltin(InterState *istate, Loc loc, if ( (n == '1' || n == '2') && (c == 'c' || c == 'w' || c == 'd') && (s == 'c' || s == 'w' || s == 'd') && c != s) - { Expression *str = arguments->tdata()[0]; + { Expression *str = (*arguments)[0]; str = str->interpret(istate); if (exceptionOrCantInterpret(str)) return str; - return foreachApplyUtf(istate, str, arguments->tdata()[1], rvs); + return foreachApplyUtf(istate, str, (*arguments)[1], rvs); } } } diff --git a/dmd/lexer.c b/dmd/lexer.c index c1531c7a..98de26e8 100644 --- a/dmd/lexer.c +++ b/dmd/lexer.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 @@ -304,7 +304,7 @@ void Lexer::error(const char *format, ...) { va_list ap; va_start(ap, format); - verror(tokenLoc(), format, ap); + ::verror(tokenLoc(), format, ap); va_end(ap); } @@ -312,34 +312,10 @@ void Lexer::error(Loc loc, const char *format, ...) { va_list ap; va_start(ap, format); - verror(loc, format, ap); + ::verror(loc, format, ap); va_end(ap); } -void Lexer::verror(Loc loc, const char *format, va_list ap) -{ - if (mod && !global.gag) - { - char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - vfprintf(stdmsg, format, ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); - } - else - { - global.gaggedErrors++; - } - global.errors++; -} - TOK Lexer::nextToken() { Token *t; @@ -669,7 +645,7 @@ void Lexer::scan(Token *t) StringValue *sv = stringtable.update((char *)t->ptr, p - t->ptr); Identifier *id = (Identifier *) sv->ptrvalue; if (!id) - { id = new Identifier(sv->lstring.string,TOKidentifier); + { id = new Identifier(sv->toDchars(),TOKidentifier); sv->ptrvalue = id; } t->ident = id; @@ -1202,9 +1178,7 @@ void Lexer::scan(Token *t) SINGLE(';', TOKsemicolon) SINGLE(':', TOKcolon) SINGLE('$', TOKdollar) -#if DMDV2 SINGLE('@', TOKat) -#endif #undef SINGLE #define DOUBLE(c1,tok1,c2,tok2) \ @@ -2629,8 +2603,9 @@ void Lexer::pragma() { p += 8; filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); + continue; } - continue; + goto Lerr; case '"': if (filespec) @@ -2913,7 +2888,7 @@ Identifier *Lexer::idPool(const char *s) Identifier *id = (Identifier *) sv->ptrvalue; if (!id) { - id = new Identifier(sv->lstring.string, TOKidentifier); + id = new Identifier(sv->toDchars(), TOKidentifier); sv->ptrvalue = id; } return id; @@ -3091,7 +3066,7 @@ void Lexer::initKeywords() { unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]); - stringtable.init(1543); + stringtable.init(6151); if (global.params.Dversion == 1) nkeywords -= 2; @@ -3104,7 +3079,7 @@ void Lexer::initKeywords() const char *s = keywords[u].name; enum TOK v = keywords[u].value; StringValue *sv = stringtable.insert(s, strlen(s)); - sv->ptrvalue = (void *) new Identifier(sv->lstring.string,v); + sv->ptrvalue = (void *) new Identifier(sv->toDchars(),v); //printf("tochars[%d] = '%s'\n",v, s); Token::tochars[v] = s; @@ -3201,6 +3176,7 @@ void Lexer::initKeywords() Token::tochars[TOKpow] = "^^"; Token::tochars[TOKpowass] = "^^="; Token::tochars[TOKgoesto] = "=>"; + Token::tochars[TOKpound] = "#"; #endif // For debugging diff --git a/dmd/lexer.h b/dmd/lexer.h index 9919e11d..b8b51d7a 100644 --- a/dmd/lexer.h +++ b/dmd/lexer.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -155,6 +155,7 @@ enum TOK TOKargTypes, TOKref, TOKmacro, + TOKat, #if DMDV2 TOKtraits, TOKoverloadset, @@ -165,9 +166,11 @@ enum TOK TOKline, TOKfile, TOKshared, - TOKat, TOKpow, TOKpowass, + TOKgoesto, + TOKvector, + TOKpound, #endif // LDC specific @@ -305,7 +308,6 @@ struct Lexer TOK inreal(Token *t); 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(); unsigned decodeUTF(); void getDocComment(Token *t, unsigned lineComment); diff --git a/dmd/mars.c b/dmd/mars.c index 3313309b..77483466 100644 --- a/dmd/mars.c +++ b/dmd/mars.c @@ -13,8 +13,8 @@ #include #include #include +#include #if IN_LLVM -#include #include #endif @@ -70,10 +70,10 @@ Global::Global() copyright = "Copyright (c) 1999-2012 by Digital Mars and Tomas Lindquist Olsen"; written = "written by Walter Bright and Tomas Lindquist Olsen"; - version = "v1.074"; + version = "v1.075"; ldc_version = "LDC trunk"; llvm_version = "LLVM "LDC_LLVM_VERSION_STRING; - global.structalign = 8; + global.structalign = STRUCTALIGN_DEFAULT; // This should only be used as a global, so the other fields are // automatically initialized to zero when the program is loaded. @@ -164,7 +164,7 @@ void errorSupplemental(Loc loc, const char *format, ...) va_end( ap ); } -void verror(Loc loc, const char *format, va_list ap) +void verror(Loc loc, const char *format, va_list ap, const char *p1, const char *p2) { if (!global.gag) { @@ -175,9 +175,22 @@ void verror(Loc loc, const char *format, va_list ap) mem.free(p); fprintf(stdmsg, "Error: "); + if (p1) + fprintf(stdmsg, "%s ", p1); + if (p2) + fprintf(stdmsg, "%s ", p2); +#if _MSC_VER + // MS doesn't recognize %zu format + OutBuffer tmp; + tmp.vprintf(format, ap); + fprintf(stdmsg, "%s", tmp.toChars()); +#else vfprintf(stdmsg, format, ap); +#endif fprintf(stdmsg, "\n"); fflush(stdmsg); + if (global.errors >= 20) // moderate blizzard of cascading messages + fatal(); //halt(); } else diff --git a/dmd/mars.h b/dmd/mars.h index 050a9f00..af664dfb 100644 --- a/dmd/mars.h +++ b/dmd/mars.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 @@ -103,7 +103,6 @@ the target object file format: #endif #define DMDV2 0 // Version 2.0 features -#define BREAKABI 1 // 0 if not ready to break the ABI just yet #define STRUCTTHISREF DMDV2 // if 'this' for struct is a reference, not a pointer #define SNAN_DEFAULT_INIT DMDV2 // if floats are default initialized to signalling NaN #define SARRAYVALUE DMDV2 // static arrays are value types @@ -316,15 +315,21 @@ struct Param #endif }; +typedef unsigned structalign_t; +#define STRUCTALIGN_DEFAULT ~0 // magic value means "match whatever the underlying C compiler does" +// other values are all powers of 2 + struct Global { const char *mars_ext; const char *sym_ext; const char *obj_ext; +#if IN_LLVM const char *obj_ext_alt; const char *ll_ext; const char *bc_ext; const char *s_ext; +#endif const char *lib_ext; const char *dll_ext; const char *doc_ext; // for Ddoc generated files @@ -336,7 +341,9 @@ struct Global const char *written; Strings *path; // Array of char*'s which form the import lookup path Strings *filePath; // Array of char*'s which form the file import lookup path - int structalign; + + structalign_t structalign; // default alignment for struct fields + const char *version; char *ldc_version; char *llvm_version; @@ -506,7 +513,7 @@ typedef uint64_t StorageClass; void warning(Loc loc, const char *format, ...) IS_PRINTF(2); void error(Loc loc, const char *format, ...) IS_PRINTF(2); void errorSupplemental(Loc loc, const char *format, ...); -void verror(Loc loc, const char *format, va_list); +void verror(Loc loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL); void vwarning(Loc loc, const char *format, va_list); void verrorSupplemental(Loc loc, const char *format, va_list); #ifdef __GNUC__ diff --git a/dmd/module.c b/dmd/module.c index 248cdc75..214f9864 100644 --- a/dmd/module.c +++ b/dmd/module.c @@ -20,7 +20,7 @@ #include #endif -#if IN_GCC +#ifdef IN_GCC #include "gdc_alloca.h" #endif @@ -51,6 +51,11 @@ #include "llvm/Support/CommandLine.h" #include +// stricmp +#if __GNUC__ && !_WIN32 +#include "gnuc.h" +#endif + static llvm::cl::opt preservePaths("op", llvm::cl::desc("Do not strip paths from source file"), llvm::cl::ZeroOrMore); @@ -319,7 +324,7 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) OutBuffer buf; for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; buf.writestring(pid->toChars()); #if _WIN32 @@ -380,7 +385,7 @@ Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident) if (packages) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; printf("%s.", pid->toChars()); } } @@ -411,8 +416,8 @@ bool 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); + char *p = (*global.path)[i]; + fprintf(stdmsg, "import path[%llu] = %s\n", (ulonglong)i, p); } } else @@ -460,24 +465,17 @@ inline unsigned readlongBE(unsigned *p) #if IN_LLVM void Module::parse(bool gen_docs) -#elif IN_GCC -void Module::parse(bool dump_source) #else void Module::parse() #endif -{ char *srcname; - unsigned char *buf; - unsigned buflen; - unsigned le; - unsigned bom; - +{ //printf("Module::parse()\n"); - srcname = srcfile->name->toChars(); + char *srcname = srcfile->name->toChars(); //printf("Module::parse(srcname = '%s')\n", srcname); - buf = srcfile->buffer; - buflen = srcfile->len; + unsigned char *buf = srcfile->buffer; + unsigned buflen = srcfile->len; if (buflen >= 2) { @@ -490,7 +488,8 @@ void Module::parse() * EF BB BF UTF-8 */ - bom = 1; // assume there's a BOM + unsigned le; + unsigned bom = 1; // assume there's a BOM if (buf[0] == 0xFF && buf[1] == 0xFE) { if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) @@ -641,7 +640,7 @@ void Module::parse() #ifdef IN_GCC // dump utf-8 encoded source - if (dump_source) + if (global.params.dump_source) { // %% srcname could contain a path ... d_gcc_dump_source(srcname, "utf-8", buf, buflen); } @@ -665,7 +664,7 @@ void Module::parse() buflen = dbuf->offset; #ifdef IN_GCC // dump extracted source - if (dump_source) + if (global.params.dump_source) d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); #endif } @@ -767,7 +766,7 @@ void Module::importAll(Scope *prevsc) symtab = new DsymbolTable(); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->addMember(NULL, sc->scopesym, 1); } } @@ -780,13 +779,13 @@ void Module::importAll(Scope *prevsc) */ setScope(sc); // remember module scope for semantic for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; s->setScope(sc); } for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->importAll(sc); } @@ -841,7 +840,7 @@ void Module::semantic() // Do semantic() on members that don't depend on others for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; //printf("\tModule('%s'): '%s'.semantic0()\n", toChars(), s->toChars()); s->semantic0(sc); @@ -849,7 +848,7 @@ void Module::semantic() // Pass 1 semantic routines: do public side of the definition for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); s->semantic(sc); @@ -870,7 +869,7 @@ void Module::semantic2() { for (size_t i = 0; i < deferred.dim; i++) { - Dsymbol *sd = deferred.tdata()[i]; + Dsymbol *sd = deferred[i]; sd->error("unable to resolve forward reference in definition"); } @@ -892,7 +891,7 @@ void Module::semantic2() for (size_t i = 0; i < members->dim; i++) { Dsymbol *s; - s = members->tdata()[i]; + s = (*members)[i]; s->semantic2(sc); } @@ -920,7 +919,7 @@ void Module::semantic3() for (size_t i = 0; i < members->dim; i++) { Dsymbol *s; - s = members->tdata()[i]; + s = (*members)[i]; //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars()); s->semantic3(sc); } @@ -943,7 +942,7 @@ void Module::inlineScan() //printf("Module = %p\n", sc.scopesym); for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; //if (global.params.verbose) //printf("inline scan symbol %s\n", s->toChars()); @@ -968,7 +967,7 @@ void Module::gensymfile() buf.writenl(); for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; + { Dsymbol *s = (*members)[i]; s->toCBuffer(&buf, &hgs); } @@ -1029,7 +1028,7 @@ Dsymbol *Module::symtabInsert(Dsymbol *s) void Module::clearCache() { for (size_t i = 0; i < amodules.dim; i++) - { Module *m = amodules.tdata()[i]; + { Module *m = amodules[i]; m->searchCacheIdent = NULL; } } @@ -1043,7 +1042,7 @@ void Module::addDeferredSemantic(Dsymbol *s) // Don't add it if it is already there for (size_t i = 0; i < deferred.dim; i++) { - Dsymbol *sd = deferred.tdata()[i]; + Dsymbol *sd = deferred[i]; if (sd == s) return; @@ -1121,7 +1120,7 @@ int Module::imports(Module *m) } #endif for (size_t i = 0; i < aimports.dim; i++) - { Module *mi = aimports.tdata()[i]; + { Module *mi = aimports[i]; if (mi == m) return TRUE; if (!mi->insearch) @@ -1145,7 +1144,7 @@ int Module::selfImports() if (!selfimports) { for (size_t i = 0; i < amodules.dim; i++) - { Module *mi = amodules.tdata()[i]; + { Module *mi = amodules[i]; //printf("\t[%d] %s\n", i, mi->toChars()); mi->insearch = 0; } @@ -1153,7 +1152,7 @@ int Module::selfImports() selfimports = imports(this) + 1; for (size_t i = 0; i < amodules.dim; i++) - { Module *mi = amodules.tdata()[i]; + { Module *mi = amodules[i]; //printf("\t[%d] %s\n", i, mi->toChars()); mi->insearch = 0; } @@ -1177,7 +1176,7 @@ char *ModuleDeclaration::toChars() if (packages && packages->dim) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; buf.writestring(pid->toChars()); buf.writeByte('.'); @@ -1214,7 +1213,7 @@ DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package if (packages) { for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; + { Identifier *pid = (*packages)[i]; Dsymbol *p; p = dst->lookup(pid); diff --git a/dmd/module.h b/dmd/module.h index 6e998ee6..dabc9a31 100644 --- a/dmd/module.h +++ b/dmd/module.h @@ -137,10 +137,8 @@ struct Module : Package 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 - void setDocfile(); // set docfile member - void parse(bool dump_source = false); // syntactic parse #else + void setDocfile(); // set docfile member void parse(); // syntactic parse #endif void importAll(Scope *sc); diff --git a/dmd/mtype.c b/dmd/mtype.c index 5130dec6..46bfcd52 100644 --- a/dmd/mtype.c +++ b/dmd/mtype.c @@ -494,7 +494,7 @@ Type *Type::merge() else { sv2->ptrvalue = this; - deco = (char *)sv2->lstring.string; + deco = (char *)sv2->toDchars(); } //printf("new value, deco = '%s' %p\n", t->deco, t->deco); } @@ -776,7 +776,7 @@ Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident) e = v->type->defaultInit(loc); } } - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); // if (!e->isConst()) // error(loc, ".init cannot be evaluated at compile time"); } @@ -804,7 +804,7 @@ Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident) return getProperty(e->loc, ident); } -unsigned Type::memalign(unsigned salign) +structalign_t Type::memalign(structalign_t salign) { return salign; } @@ -1923,7 +1923,7 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol sc = sc->push(sym); dim = dim->semantic(sc); - dim = dim->optimize(WANTvalue | WANTinterpret); + dim = dim->ctfeInterpret(); uinteger_t d = dim->toUInteger(); sc = sc->pop(); @@ -1985,7 +1985,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) { TupleDeclaration *sd = s->isTupleDeclaration(); dim = semanticLength(sc, sd, dim); - dim = dim->optimize(WANTvalue | WANTinterpret); + dim = dim->ctfeInterpret(); uinteger_t d = dim->toUInteger(); if (d >= sd->objects->dim) @@ -2012,7 +2012,7 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) if (errors != global.errors) goto Lerror; - dim = dim->optimize(WANTvalue | WANTinterpret); + dim = dim->ctfeInterpret(); if (sc && sc->parameterSpecialization && dim->op == TOKvar && ((VarExp *)dim)->var->storage_class & STCtemplateparameter) { @@ -2132,7 +2132,7 @@ int TypeSArray::isString() return nty == Tchar || nty == Twchar || nty == Tdchar; } -unsigned TypeSArray::memalign(unsigned salign) +structalign_t TypeSArray::memalign(structalign_t salign) { return next->memalign(salign); } @@ -3036,8 +3036,6 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd return; } inuse++; - if (next && (!ident || ident->toHChars2() == ident->toChars())) - next->toCBuffer2(buf, hgs, 0); if (hgs->ddoc != 1) { switch (linkage) @@ -3054,10 +3052,17 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd default: assert(0); } + if (!hgs->hdrgen && p) + { + buf->writestring("extern ("); + buf->writestring(p); + buf->writestring(") "); + } + } + if (next && (!ident || ident->toHChars2() == ident->toChars())) + { next->toCBuffer2(buf, hgs, 0); } - if (!hgs->hdrgen && p) - buf->writestring(p); if (ident) { buf->writeByte(' '); buf->writestring(ident->toHChars2()); @@ -3077,39 +3082,52 @@ void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, Hd inuse--; } +// kind is inserted before the argument list and will usually be "function" or "delegate". +void functionToCBuffer2(TypeFunction *t, OutBuffer *buf, HdrGenState *hgs, int mod, const char *kind) +{ + if (hgs->ddoc != 1) + { + const char *p = NULL; + switch (t->linkage) + { + case LINKd: p = NULL; break; + case LINKc: p = "C"; break; + case LINKwindows: p = "Windows"; break; + case LINKpascal: p = "Pascal"; break; + case LINKcpp: p = "C++"; break; +#if IN_LLVM + case LINKintrinsic: p = "Intrinsic"; break; +#endif + default: + assert(0); + } + if (!hgs->hdrgen && p) + { + buf->writestring("extern ("); + buf->writestring(p); + buf->writestring(") "); + } + } + if (t->next) + { + t->next->toCBuffer2(buf, hgs, 0); + buf->writeByte(' '); + } + buf->writestring(kind); + Parameter::argsToCBuffer(buf, hgs, t->parameters, t->varargs); +} + void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { - const char *p = NULL; - + //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); if (inuse) { inuse = 2; // flag error to caller return; } inuse++; - if (next) - next->toCBuffer2(buf, hgs, 0); - if (hgs->ddoc != 1) - { - switch (linkage) - { - case LINKd: p = NULL; break; - case LINKc: p = " C"; break; - case LINKwindows: p = " Windows"; break; - case LINKpascal: p = " Pascal"; break; - case LINKcpp: p = " C++"; break; - // LDC - case LINKintrinsic: p = "Intrinsic"; break; + functionToCBuffer2(this, buf, hgs, mod, "function"); - default: - assert(0); - } - } - - if (!hgs->hdrgen && p) - buf->writestring(p); - buf->writestring(" function"); - Parameter::argsToCBuffer(buf, hgs, parameters, varargs); inuse--; } @@ -3464,11 +3482,8 @@ void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { toCBuffer3(buf, hgs, mod); return; } - TypeFunction *tf = (TypeFunction *)next; - tf->next->toCBuffer2(buf, hgs, 0); - buf->writestring(" delegate"); - Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); + functionToCBuffer2((TypeFunction *)next, buf, hgs, mod, "delegate"); } Expression *TypeDelegate::defaultInit(Loc loc) @@ -3496,14 +3511,33 @@ Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident) #endif if (ident == Id::ptr) { +#if IN_LLVM e = new GEPExp(e->loc, e, ident, 0); +#endif e->type = tvoidptr; return e; } else if (ident == Id::funcptr) { + if (!e->isLvalue()) + { + Identifier *idtmp = Lexer::uniqueId("__dgtmp"); + VarDeclaration *tmp = new VarDeclaration(e->loc, this, idtmp, new ExpInitializer(0, e)); + tmp->storage_class |= STCctfe; + e = new DeclarationExp(e->loc, tmp); + e = new CommaExp(e->loc, e, new VarExp(e->loc, tmp)); + e = e->semantic(sc); + } +#if IN_LLVM e = new GEPExp(e->loc, e, ident, 1); +#else + e = e->addressOf(sc); e->type = tvoidptr; + e = new AddExp(e->loc, e, new IntegerExp(PTRSIZE)); + e->type = tvoidptr; + e = new PtrExp(e->loc, e); +#endif + e->type = next->pointerTo(); return e; } else @@ -3534,7 +3568,7 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) idents.setDim(t->idents.dim); for (size_t i = 0; i < idents.dim; i++) { - Identifier *id = (Identifier *)t->idents.data[i]; + Identifier *id = t->idents[i]; if (id->dyncast() == DYNCAST_DSYMBOL) { TemplateInstance *ti = (TemplateInstance *)id; @@ -3542,7 +3576,7 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) ti = (TemplateInstance *)ti->syntaxCopy(NULL); id = (Identifier *)ti; } - idents.data[i] = id; + idents[i] = id; } } @@ -3555,7 +3589,7 @@ void TypeQualified::addIdent(Identifier *ident) void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs) { for (size_t i = 0; i < idents.dim; i++) - { Identifier *id = (Identifier *)idents.data[i]; + { Identifier *id = idents[i]; buf->writeByte('.'); @@ -4741,7 +4775,12 @@ unsigned TypeStruct::alignsize() sym->size(0); // give error for forward references sz = sym->alignsize; - if (sz > sym->structalign) + if (sym->structalign == STRUCTALIGN_DEFAULT) + { + if (sz > 8) + sz = 8; + } + else if (sz > sym->structalign) sz = sym->structalign; return sz; } @@ -4965,7 +5004,7 @@ L1: return de->semantic(sc); } -unsigned TypeStruct::memalign(unsigned salign) +structalign_t TypeStruct::memalign(structalign_t salign) { sym->size(0); // give error for forward references return sym->structalign; @@ -5692,11 +5731,11 @@ Type *TypeSlice::semantic(Loc loc, Scope *sc) TypeTuple *tt = (TypeTuple *)tbn; lwr = semanticLength(sc, tbn, lwr); - lwr = lwr->optimize(WANTvalue | WANTinterpret); + lwr = lwr->ctfeInterpret(); uinteger_t i1 = lwr->toUInteger(); upr = semanticLength(sc, tbn, upr); - upr = upr->optimize(WANTvalue | WANTinterpret); + upr = upr->ctfeInterpret(); uinteger_t i2 = upr->toUInteger(); if (!(i1 <= i2 && i2 <= tt->arguments->dim)) @@ -5736,11 +5775,11 @@ void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol sc = sc->push(sym); lwr = lwr->semantic(sc); - lwr = lwr->optimize(WANTvalue | WANTinterpret); + lwr = lwr->ctfeInterpret(); uinteger_t i1 = lwr->toUInteger(); upr = upr->semantic(sc); - upr = upr->optimize(WANTvalue | WANTinterpret); + upr = upr->ctfeInterpret(); uinteger_t i2 = upr->toUInteger(); sc = sc->pop(); @@ -5831,27 +5870,8 @@ char *Parameter::argsTypesToChars(Parameters *args, int varargs) { OutBuffer *buf = new OutBuffer(); - buf->writeByte('('); - if (args) - { OutBuffer argbuf; - HdrGenState hgs; - - for (size_t i = 0; i < args->dim; i++) - { if (i) - buf->writeByte(','); - Parameter *arg = args->tdata()[i]; - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, &hgs, 0); - buf->write(&argbuf); - } - if (varargs) - { - if (args->dim && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } - } - buf->writeByte(')'); + HdrGenState hgs; + argsToCBuffer(buf, &hgs, args, varargs); return buf->toChars(); } diff --git a/dmd/mtype.h b/dmd/mtype.h index 9e4979c7..e699be9d 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -252,7 +252,7 @@ struct Type : Object virtual ClassDeclaration *isClassHandle(); virtual Expression *getProperty(Loc loc, Identifier *ident); virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - virtual unsigned memalign(unsigned salign); + virtual structalign_t memalign(structalign_t salign); virtual Expression *defaultInit(Loc loc = 0); virtual Expression *defaultInitLiteral(Loc loc); virtual Expression *voidInitLiteral(VarDeclaration *var); @@ -305,6 +305,7 @@ struct TypeError : Type Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); + TypeTuple *toArgTypes(); }; #if DMDV2 @@ -388,7 +389,7 @@ struct TypeSArray : TypeArray Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); int isString(); int isZeroInit(Loc loc); - unsigned memalign(unsigned salign); + structalign_t memalign(structalign_t salign); MATCH implicitConvTo(Type *to); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); @@ -644,7 +645,7 @@ struct TypeStruct : Type void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - unsigned memalign(unsigned salign); + structalign_t memalign(structalign_t salign); Expression *defaultInit(Loc loc); Expression *defaultInitLiteral(Loc loc); Expression *voidInitLiteral(VarDeclaration *var); diff --git a/dmd/opover.c b/dmd/opover.c index 026543eb..eaa7841c 100644 --- a/dmd/opover.c +++ b/dmd/opover.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 @@ -12,6 +12,7 @@ #include #include #include +#include // memset() #if _MSC_VER #include #else diff --git a/dmd/parse.c b/dmd/parse.c index 2aedae31..59c15af8 100644 --- a/dmd/parse.c +++ b/dmd/parse.c @@ -12,6 +12,7 @@ #include #include +#include // strlen(),memcpy() #include "rmem.h" #include "lexer.h" @@ -78,25 +79,6 @@ Dsymbols *Parser::parseModule() unsigned char *comment = token.blockComment; nextToken(); -#if DMDV2 - if (token.value == TOKlparen) - { - nextToken(); - if (token.value != TOKidentifier) - { error("module (system) identifier expected"); - goto Lerr; - } - Identifier *id = token.ident; - - if (id == Id::system) - safe = TRUE; - else - error("(safe) expected, not %s", id->toChars()); - nextToken(); - check(TOKrparen); - } -#endif - if (token.value != TOKidentifier) { error("Identifier expected following module"); goto Lerr; @@ -397,7 +379,11 @@ Dsymbols *Parser::parseDeclDefs(int once) { nextToken(); if (token.value == TOKint32v && token.uns64value > 0) + { + if (token.uns64value & (token.uns64value - 1)) + error("align(%s) must be a power of 2", token.toChars()); n = (unsigned)token.uns64value; + } else { error("positive integer expected, not %s", token.toChars()); n = 1; @@ -420,7 +406,7 @@ Dsymbols *Parser::parseDeclDefs(int once) nextToken(); check(TOKlparen); if (token.value != TOKidentifier) - { error("pragma(identifier expected"); + { error("pragma(identifier) expected"); goto Lerror; } ident = token.ident; @@ -2746,7 +2732,15 @@ Initializer *Parser::parseInitializer() if (comma == 1) error("comma expected separating array initializers, not %s", token.toChars()); value = parseInitializer(); - ia->addInit(NULL, value); + if (token.value == TOKcolon) + { + nextToken(); + e = value->toExpression(); + value = parseInitializer(); + } + else + e = NULL; + ia->addInit(e, value); comma = 1; continue; @@ -3520,7 +3514,7 @@ Statement *Parser::parseStatement(int flags) Loc loc = this->loc; nextToken(); - if (token.value == TOKlcurly) + if (token.value == TOKlcurly || token.value != TOKlparen) { t = NULL; id = NULL; diff --git a/dmd/root/array.c b/dmd/root/array.c index f3440445..3ef48322 100644 --- a/dmd/root/array.c +++ b/dmd/root/array.c @@ -40,7 +40,6 @@ #include "port.h" #include "root.h" -#include "dchar.h" #include "rmem.h" diff --git a/dmd/root/dchar.c b/dmd/root/dchar.c deleted file mode 100644 index 0b11a8a4..00000000 --- a/dmd/root/dchar.c +++ /dev/null @@ -1,482 +0,0 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include -#include -#include - -#include "dchar.h" -#include "rmem.h" - -#if M_UNICODE - -// Converts a char string to Unicode - -dchar *Dchar::dup(char *p) -{ - dchar *s; - size_t len; - - if (!p) - return NULL; - len = strlen(p); - s = (dchar *)mem.malloc((len + 1) * sizeof(dchar)); - for (unsigned i = 0; i < len; i++) - { - s[i] = (dchar)(p[i] & 0xFF); - } - s[len] = 0; - return s; -} - -dchar *Dchar::memchr(dchar *p, int c, int count) -{ - int u; - - for (u = 0; u < count; u++) - { - if (p[u] == c) - return p + u; - } - return NULL; -} - -#if _WIN32 && __DMC__ -__declspec(naked) -unsigned Dchar::calcHash(const dchar *str, unsigned len) -{ - __asm - { - mov ECX,4[ESP] - mov EDX,8[ESP] - xor EAX,EAX - test EDX,EDX - je L92 - -LC8: cmp EDX,1 - je L98 - cmp EDX,2 - je LAE - - add EAX,[ECX] -// imul EAX,EAX,025h - lea EAX,[EAX][EAX*8] - add ECX,4 - sub EDX,2 - jmp LC8 - -L98: mov DX,[ECX] - and EDX,0FFFFh - add EAX,EDX - ret - -LAE: add EAX,[ECX] -L92: ret - } -} -#else -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - unsigned hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash += *(const uint16_t *)str; - return hash; - - case 2: - hash += *(const uint32_t *)str; - return hash; - - default: - hash += *(const uint32_t *)str; - hash *= 37; - str += 2; - len -= 2; - break; - } - } -} -#endif - -hash_t Dchar::icalcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash += *(const uint16_t *)str | 0x20; - return hash; - - case 2: - hash += *(const uint32_t *)str | 0x200020; - return hash; - - default: - hash += *(const uint32_t *)str | 0x200020; - hash *= 37; - str += 2; - len -= 2; - break; - } - } -} - -#elif MCBS - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; - hash += *(const uint16_t *)str; - return hash; - - case 3: - hash *= 37; - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; - return hash; - - default: - hash *= 37; - hash += *(const uint32_t *)str; - str += 4; - len -= 4; - break; - } - } -} - -#elif UTF8 - -// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335 - -char Dchar::mblen[256] = -{ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1, -}; - -dchar *Dchar::dec(dchar *pstart, dchar *p) -{ - while ((p[-1] & 0xC0) == 0x80) - p--; - return p; -} - -int Dchar::get(dchar *p) -{ - unsigned c; - unsigned char *q = (unsigned char *)p; - - c = q[0]; - switch (mblen[c]) - { - case 2: - c = ((c - 0xC0) << 6) | - (q[1] - 0x80); - break; - - case 3: - c = ((c - 0xE0) << 12) | - ((q[1] - 0x80) << 6) | - (q[2] - 0x80); - break; - - case 4: - c = ((c - 0xF0) << 18) | - ((q[1] - 0x80) << 12) | - ((q[2] - 0x80) << 6) | - (q[3] - 0x80); - break; - - case 5: - c = ((c - 0xF8) << 24) | - ((q[1] - 0x80) << 18) | - ((q[2] - 0x80) << 12) | - ((q[3] - 0x80) << 6) | - (q[4] - 0x80); - break; - - case 6: - c = ((c - 0xFC) << 30) | - ((q[1] - 0x80) << 24) | - ((q[2] - 0x80) << 18) | - ((q[3] - 0x80) << 12) | - ((q[4] - 0x80) << 6) | - (q[5] - 0x80); - break; - } - return c; -} - -dchar *Dchar::put(dchar *p, unsigned c) -{ - if (c <= 0x7F) - { - *p++ = c; - } - else if (c <= 0x7FF) - { - p[0] = 0xC0 + (c >> 6); - p[1] = 0x80 + (c & 0x3F); - p += 2; - } - else if (c <= 0xFFFF) - { - p[0] = 0xE0 + (c >> 12); - p[1] = 0x80 + ((c >> 6) & 0x3F); - p[2] = 0x80 + (c & 0x3F); - p += 3; - } - else if (c <= 0x1FFFFF) - { - p[0] = 0xF0 + (c >> 18); - p[1] = 0x80 + ((c >> 12) & 0x3F); - p[2] = 0x80 + ((c >> 6) & 0x3F); - p[3] = 0x80 + (c & 0x3F); - p += 4; - } - else if (c <= 0x3FFFFFF) - { - p[0] = 0xF8 + (c >> 24); - p[1] = 0x80 + ((c >> 18) & 0x3F); - p[2] = 0x80 + ((c >> 12) & 0x3F); - p[3] = 0x80 + ((c >> 6) & 0x3F); - p[4] = 0x80 + (c & 0x3F); - p += 5; - } - else if (c <= 0x7FFFFFFF) - { - p[0] = 0xFC + (c >> 30); - p[1] = 0x80 + ((c >> 24) & 0x3F); - p[2] = 0x80 + ((c >> 18) & 0x3F); - p[3] = 0x80 + ((c >> 12) & 0x3F); - p[4] = 0x80 + ((c >> 6) & 0x3F); - p[5] = 0x80 + (c & 0x3F); - p += 6; - } - else - assert(0); // not a UCS-4 character - return p; -} - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint16_t *)str; -#else - hash += str[0] * 256 + str[1]; -#endif - return hash; - - case 3: - hash *= 37; -#if LITTLE_ENDIAN - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; -#else - hash += (str[0] * 256 + str[1]) * 256 + str[2]; -#endif - return hash; - - default: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint32_t *)str; -#else - hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; -#endif - - str += 4; - len -= 4; - break; - } - } -} - -#else // ascii - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint16_t *)str; -#else - hash += str[0] * 256 + str[1]; -#endif - return hash; - - case 3: - hash *= 37; -#if LITTLE_ENDIAN - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; -#else - hash += (str[0] * 256 + str[1]) * 256 + str[2]; -#endif - return hash; - - default: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint32_t *)str; -#else - hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; -#endif - str += 4; - len -= 4; - break; - } - } -} - -hash_t Dchar::icalcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str | 0x20; - return hash; - - case 2: - hash *= 37; - hash += *(const uint16_t *)str | 0x2020; - return hash; - - case 3: - hash *= 37; - hash += ((*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]) | 0x202020; - return hash; - - default: - hash *= 37; - hash += *(const uint32_t *)str | 0x20202020; - str += 4; - len -= 4; - break; - } - } -} - -#endif - -#if 0 -#include - -void main() -{ - // Print out values to hardcode into Dchar::mblen[] - int c; - int s; - - for (c = 0; c < 256; c++) - { - s = 1; - if (c >= 0xC0 && c <= 0xDF) - s = 2; - if (c >= 0xE0 && c <= 0xEF) - s = 3; - if (c >= 0xF0 && c <= 0xF7) - s = 4; - if (c >= 0xF8 && c <= 0xFB) - s = 5; - if (c >= 0xFC && c <= 0xFD) - s = 6; - - printf("%d", s); - if ((c & 15) == 15) - printf(",\n"); - else - printf(","); - } -} -#endif diff --git a/dmd/root/dchar.h b/dmd/root/dchar.h deleted file mode 100644 index 6ac7994c..00000000 --- a/dmd/root/dchar.h +++ /dev/null @@ -1,194 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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. - - -#ifndef DCHAR_H -#define DCHAR_H - -#if __GNUC__ && !_WIN32 -#include "gnuc.h" -#endif - -#if _MSC_VER - // Disable useless warnings about unreferenced functions - #pragma warning (disable : 4514) -#endif - -//#include "root.h" -typedef size_t hash_t; - -#undef TEXT - -// NOTE: All functions accepting pointer arguments must not be NULL - -#if M_UNICODE - -#include -#include - -typedef wchar_t dchar; -#define TEXT(x) L##x - -#define Dchar_mbmax 1 - -struct Dchar -{ - static dchar *inc(dchar *p) { return p + 1; } - static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; } - static int len(const dchar *p) { return wcslen(p); } - static dchar get(dchar *p) { return *p; } - static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; } - static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; } - static int cmp(dchar *s1, dchar *s2) - { -#if __DMC__ - if (!*s1 && !*s2) // wcscmp is broken - return 0; -#endif - return wcscmp(s1, s2); -#if 0 - return (*s1 == *s2) - ? wcscmp(s1, s2) - : ((int)*s1 - (int)*s2); -#endif - } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } - static int isAlpha(dchar c) { return iswalpha(c); } - static int isUpper(dchar c) { return iswupper(c); } - static int isLower(dchar c) { return iswlower(c); } - static int isLocaleUpper(dchar c) { return isUpper(c); } - static int isLocaleLower(dchar c) { return isLower(c); } - static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; } - static dchar *dup(dchar *p) { return ::_wcsdup(p); } // BUG: out of memory? - static dchar *dup(char *p); - static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); } - static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); } - static dchar *memchr(dchar *p, int c, int count); - static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions - static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); } - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); } - static hash_t icalcHash(const dchar *str, size_t len); -}; - -#elif MCBS - -#include -#include - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax MB_LEN_MAX - -#elif UTF8 - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax 6 - -struct Dchar -{ - static char mblen[256]; - - static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; } - static dchar *dec(dchar *pstart, dchar *p); - static int len(const dchar *p) { return strlen(p); } - static int get(dchar *p); - static int getprev(dchar *pstart, dchar *p) - { return *dec(pstart, p) & 0xFF; } - static dchar *put(dchar *p, unsigned c); - 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); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } - static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; } - static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; } - static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; } - static int isLocaleUpper(dchar c) { return isUpper(c); } - static int isLocaleLower(dchar c) { return isLower(c); } - static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; } - static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? - static dchar *chr(dchar *p, int c) { return strchr(p, c); } - static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } - static dchar *memchr(dchar *p, int c, int count) - { return (dchar *)::memchr(p, c, count); } - static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions - static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); } - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); } -}; - -#else - -#include - -#ifndef GCC_SAFE_DMD -#include -#endif - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax 1 - -struct Dchar -{ - static dchar *inc(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) { (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); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } -#ifndef GCC_SAFE_DMD - static int isAlpha(dchar c) { return isalpha((unsigned char)c); } - static int isUpper(dchar c) { return isupper((unsigned char)c); } - static int isLower(dchar c) { return islower((unsigned char)c); } - static int isLocaleUpper(dchar c) { return isupper((unsigned char)c); } - static int isLocaleLower(dchar c) { return islower((unsigned char)c); } - static int toLower(dchar c) { return isupper((unsigned char)c) ? tolower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return islower((unsigned char)c) ? toupper(c) : c; } - static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? -#endif - static dchar *chr(dchar *p, int c) { return strchr(p, c); } - static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } - static dchar *memchr(dchar *p, int c, int count) - { return (dchar *)::memchr(p, c, count); } - static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions -#ifdef __GNUC__ - static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); } -#else - static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); } -#endif - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); } - static hash_t icalcHash(const dchar *str, size_t len); -}; - -#endif -#endif - diff --git a/dmd/root/lstring.c b/dmd/root/lstring.c deleted file mode 100644 index a4e41ed5..00000000 --- a/dmd/root/lstring.c +++ /dev/null @@ -1,63 +0,0 @@ -// lstring.c - -// Copyright (c) 1999-2002 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include - -#include "dchar.h" -#include "rmem.h" -#include "lstring.h" - -#ifdef _MSC_VER // prevent compiler internal crash -Lstring Lstring::zero; -#else -Lstring Lstring::zero = LSTRING_EMPTY(); -#endif - -Lstring *Lstring::ctor(const dchar *p, unsigned length) -{ - Lstring *s; - - s = alloc(length); - memcpy(s->string, p, length * sizeof(dchar)); - return s; -} - -Lstring *Lstring::alloc(unsigned length) -{ - Lstring *s; - - s = (Lstring *)mem.malloc(size(length)); - s->length = length; - s->string[length] = 0; - return s; -} - -Lstring *Lstring::append(const Lstring *s) -{ - Lstring *t; - - if (!s->length) - return this; - t = alloc(length + s->length); - memcpy(t->string, string, length * sizeof(dchar)); - memcpy(t->string + length, s->string, s->length * sizeof(dchar)); - return t; -} - -Lstring *Lstring::substring(int start, int end) -{ - Lstring *t; - - if (start == end) - return &zero; - t = alloc(end - start); - memcpy(t->string, string + start, (end - start) * sizeof(dchar)); - return t; -} diff --git a/dmd/root/lstring.h b/dmd/root/lstring.h deleted file mode 100644 index 0c545790..00000000 --- a/dmd/root/lstring.h +++ /dev/null @@ -1,74 +0,0 @@ - -// lstring.h -// length-prefixed strings - -// Copyright (c) 1999-2002 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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. - -#ifndef LSTRING_H -#define LSTRING_H 1 - -#include "dchar.h" - -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 - - // No constructors because we want to be able to statically - // initialize Lstring's, and Lstrings are of variable size. - - #if M_UNICODE - #define LSTRING(p,length) { length, L##p } - #else - #define LSTRING(p,length) { length, p } - #endif - -#if __GNUC__ - #define LSTRING_EMPTY() { 0 } -#else - #define LSTRING_EMPTY() LSTRING("", 0) -#endif - - static Lstring *ctor(const dchar *p) { return ctor(p, Dchar::len(p)); } - static Lstring *ctor(const dchar *p, unsigned length); - static unsigned size(unsigned length) { return sizeof(Lstring) + (length + 1) * sizeof(dchar); } - static Lstring *alloc(unsigned length); - Lstring *clone(); - - unsigned len() { return length; } - - dchar *toDchars() { return string; } - - hash_t hash() { return Dchar::calcHash(string, length); } - hash_t ihash() { return Dchar::icalcHash(string, length); } - - static int cmp(const Lstring *s1, const Lstring *s2) - { - int c = s2->length - s1->length; - return c ? c : Dchar::memcmp(s1->string, s2->string, s1->length); - } - - static int icmp(const Lstring *s1, const Lstring *s2) - { - int c = s2->length - s1->length; - return c ? c : Dchar::memicmp(s1->string, s2->string, s1->length); - } - - Lstring *append(const Lstring *s); - Lstring *substring(int start, int end); -}; - -#endif diff --git a/dmd/root/root.c b/dmd/root/root.c index 2ba47eb5..71d2bd81 100644 --- a/dmd/root/root.c +++ b/dmd/root/root.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -18,6 +18,7 @@ #include #include #include +#include #if (defined (__SVR4) && defined (__sun)) #include @@ -49,7 +50,6 @@ #include "port.h" #include "root.h" -#include "dchar.h" #include "rmem.h" #include "mars.h" @@ -143,22 +143,6 @@ void error(const char *format, ...) exit(EXIT_FAILURE); } -#if M_UNICODE -void error(const dchar *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Error: "); - vwprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); - - exit(EXIT_FAILURE); -} -#endif - void error_mem() { error("out of memory"); @@ -207,15 +191,6 @@ char *Object::toChars() return (char *)"Object"; } -dchar *Object::toDchars() -{ -#if M_UNICODE - return L"Object"; -#else - return toChars(); -#endif -} - int Object::dyncast() { return 0; @@ -1620,30 +1595,6 @@ void OutBuffer::writestring(const char *string) write(string,strlen(string)); } -void OutBuffer::writedstring(const char *string) -{ -#if M_UNICODE - for (; *string; string++) - { - writedchar(*string); - } -#else - write(string,strlen(string)); -#endif -} - -void OutBuffer::writedstring(const wchar_t *string) -{ -#if M_UNICODE - write(string,wcslen(string) * sizeof(wchar_t)); -#else - for (; *string; string++) - { - writedchar(*string); - } -#endif -} - void OutBuffer::prependstring(const char *string) { unsigned len; @@ -1657,18 +1608,10 @@ void OutBuffer::prependstring(const char *string) void OutBuffer::writenl() { #if _WIN32 -#if M_UNICODE - write4(0x000A000D); // newline is CR,LF on Microsoft OS's -#else writeword(0x0A0D); // newline is CR,LF on Microsoft OS's -#endif -#else -#if M_UNICODE - writeword('\n'); #else writeByte('\n'); #endif -#endif } void OutBuffer::writeByte(unsigned b) @@ -1730,13 +1673,6 @@ void OutBuffer::writeUTF8(unsigned b) assert(0); } -void OutBuffer::writedchar(unsigned b) -{ - reserve(Dchar_mbmax * sizeof(dchar)); - offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) - - this->data; -} - void OutBuffer::prependbyte(unsigned b) { reserve(1); @@ -1884,46 +1820,6 @@ void OutBuffer::vprintf(const char *format, va_list args) write(p,count); } -#if M_UNICODE -void OutBuffer::vprintf(const wchar_t *format, va_list args) -{ - dchar buffer[128]; - dchar *p; - unsigned psize; - int count; - - WORKAROUND_C99_SPECIFIERS_BUG(wstring, fmt, format); - - p = buffer; - psize = sizeof(buffer) / sizeof(buffer[0]); - for (;;) - { -#if _WIN32 - count = _vsnwprintf(p,psize,format,args); - if (count != -1) - break; - psize *= 2; -#elif POSIX - va_list va; - va_copy(va, args); - count = vsnwprintf(p,psize,format,va); - va_end(va); - - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; -#else - assert(0); -#endif - p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size - } - write(p,count * 2); -} -#endif - void OutBuffer::printf(const char *format, ...) { va_list ap; @@ -1932,16 +1828,6 @@ void OutBuffer::printf(const char *format, ...) va_end(ap); } -#if M_UNICODE -void OutBuffer::printf(const wchar_t *format, ...) -{ - va_list ap; - va_start(ap, format); - vprintf(format,ap); - va_end(ap); -} -#endif - void OutBuffer::bracket(char left, char right) { reserve(2); diff --git a/dmd/root/root.h b/dmd/root/root.h index 91d9d9d3..387218b3 100644 --- a/dmd/root/root.h +++ b/dmd/root/root.h @@ -1,5 +1,4 @@ - // Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright @@ -32,7 +31,6 @@ typedef size_t hash_t; #include "longdouble.h" -#include "dchar.h" char *wchar2ascii(wchar_t *); int wcharIsAscii(wchar_t *); @@ -105,7 +103,6 @@ struct Object virtual void print(); virtual char *toChars(); - virtual dchar *toDchars(); virtual void toBuffer(OutBuffer *buf); /** @@ -295,14 +292,11 @@ struct OutBuffer : Object void write(const void *data, unsigned nbytes); void writebstring(unsigned char *string); void writestring(const char *string); - void writedstring(const char *string); - void writedstring(const wchar_t *string); void prependstring(const char *string); void writenl(); // write newline void writeByte(unsigned b); void writebyte(unsigned b) { writeByte(b); } void writeUTF8(unsigned b); - void writedchar(unsigned b); void prependbyte(unsigned b); void writeword(unsigned w); void writeUTF16(unsigned w); diff --git a/dmd/root/stringtable.c b/dmd/root/stringtable.c index f1c0044a..58dcd0b6 100644 --- a/dmd/root/stringtable.c +++ b/dmd/root/stringtable.c @@ -9,15 +9,70 @@ #include -#include +#include // uint{8|16|32}_t +#include // memcpy() #include #include "root.h" -#include "rmem.h" -#include "dchar.h" -#include "lstring.h" +#include "rmem.h" // mem #include "stringtable.h" +hash_t calcHash(const char *str, size_t len) +{ + hash_t hash = 0; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(const uint8_t *)str; + return hash; + + case 2: + hash *= 37; +#if LITTLE_ENDIAN + hash += *(const uint16_t *)str; +#else + hash += str[0] * 256 + str[1]; +#endif + return hash; + + case 3: + hash *= 37; +#if LITTLE_ENDIAN + hash += (*(const uint16_t *)str << 8) + + ((const uint8_t *)str)[2]; +#else + hash += (str[0] * 256 + str[1]) * 256 + str[2]; +#endif + return hash; + + default: + hash *= 37; +#if LITTLE_ENDIAN + hash += *(const uint32_t *)str; +#else + hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; +#endif + str += 4; + len -= 4; + break; + } + } +} + +void StringValue::ctor(const char *p, unsigned length) +{ + this->length = length; + this->lstring[length] = 0; + memcpy(this->lstring, p, length * sizeof(char)); +} + void StringTable::init(unsigned size) { table = (void **)mem.calloc(size, sizeof(void *)); @@ -46,21 +101,20 @@ struct StringEntry StringValue value; - static StringEntry *alloc(const dchar *s, unsigned len); + static StringEntry *alloc(const char *s, unsigned len); }; -StringEntry *StringEntry::alloc(const dchar *s, unsigned len) +StringEntry *StringEntry::alloc(const char *s, unsigned len) { StringEntry *se; - se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) - sizeof(Lstring) + Lstring::size(len)); - se->value.lstring.length = len; - se->hash = Dchar::calcHash(s,len); - memcpy(se->value.lstring.string, s, len * sizeof(dchar)); + se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) + len + 1); + se->value.ctor(s, len); + se->hash = calcHash(s,len); return se; } -void **StringTable::search(const dchar *s, unsigned len) +void **StringTable::search(const char *s, unsigned len) { hash_t hash; unsigned u; @@ -68,7 +122,7 @@ void **StringTable::search(const dchar *s, unsigned len) StringEntry **se; //printf("StringTable::search(%p,%d)\n",s,len); - hash = Dchar::calcHash(s,len); + hash = calcHash(s,len); u = hash % tabledim; se = (StringEntry **)&table[u]; //printf("\thash = %d, u = %d\n",hash,u); @@ -77,10 +131,10 @@ void **StringTable::search(const dchar *s, unsigned len) cmp = (*se)->hash - hash; if (cmp == 0) { - cmp = (*se)->value.lstring.len() - len; + cmp = (*se)->value.len() - len; if (cmp == 0) { - cmp = Dchar::memcmp(s,(*se)->value.lstring.toDchars(),len); + cmp = ::memcmp(s,(*se)->value.toDchars(),len); if (cmp == 0) break; } @@ -94,7 +148,7 @@ void **StringTable::search(const dchar *s, unsigned len) return (void **)se; } -StringValue *StringTable::lookup(const dchar *s, unsigned len) +StringValue *StringTable::lookup(const char *s, unsigned len) { StringEntry *se; se = *(StringEntry **)search(s,len); @@ -104,7 +158,7 @@ StringValue *StringTable::lookup(const dchar *s, unsigned len) return NULL; } -StringValue *StringTable::update(const dchar *s, unsigned len) +StringValue *StringTable::update(const char *s, unsigned len) { StringEntry **pse; StringEntry *se; @@ -118,7 +172,7 @@ StringValue *StringTable::update(const dchar *s, unsigned len) return &se->value; } -StringValue *StringTable::insert(const dchar *s, unsigned len) +StringValue *StringTable::insert(const char *s, unsigned len) { StringEntry **pse; StringEntry *se; @@ -133,7 +187,3 @@ StringValue *StringTable::insert(const dchar *s, unsigned len) } return &se->value; } - - - - diff --git a/dmd/root/stringtable.h b/dmd/root/stringtable.h index ce714587..170894e6 100644 --- a/dmd/root/stringtable.h +++ b/dmd/root/stringtable.h @@ -1,3 +1,4 @@ + // Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright @@ -15,34 +16,56 @@ #endif #include "root.h" -#include "dchar.h" -#include "lstring.h" +struct StringEntry; + +// StringValue is a variable-length structure as indicated by the last array +// member with unspecified size. It has neither proper c'tors nor a factory +// method because the only thing which should be creating these is StringTable. struct StringValue { union - { int intvalue; + { void *ptrvalue; - dchar *string; + char *string; }; - Lstring lstring; +private: + unsigned length; + +#ifndef IN_GCC + // Disable warning about nonstandard extension + #pragma warning (disable : 4200) +#endif + char lstring[]; + +public: + unsigned len() const { return length; } + const char *toDchars() const { return lstring; } + +private: + friend struct StringEntry; + StringValue(); // not constructible + // This is more like a placement new c'tor + void ctor(const char *p, unsigned length); }; struct StringTable { +private: void **table; unsigned count; unsigned tabledim; +public: void init(unsigned size = 37); ~StringTable(); - StringValue *lookup(const dchar *s, unsigned len); - StringValue *insert(const dchar *s, unsigned len); - StringValue *update(const dchar *s, unsigned len); + StringValue *lookup(const char *s, unsigned len); + StringValue *insert(const char *s, unsigned len); + StringValue *update(const char *s, unsigned len); private: - void **search(const dchar *s, unsigned len); + void **search(const char *s, unsigned len); }; #endif diff --git a/dmd/scope.c b/dmd/scope.c index e0971796..0e2592f4 100644 --- a/dmd/scope.c +++ b/dmd/scope.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2010 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -9,6 +9,7 @@ #include #include +#include // strlen() #include "root.h" #include "speller.h" diff --git a/dmd/scope.h b/dmd/scope.h index 339da7b6..2fc23af6 100644 --- a/dmd/scope.h +++ b/dmd/scope.h @@ -86,7 +86,7 @@ struct Scope #define CSXreturn 0x20 // seen a return statement #define CSXany_ctor 0x40 // either this() or super() was called - unsigned structalign; // alignment for struct members + structalign_t structalign; // alignment for struct members enum LINK linkage; // linkage for external functions enum PROT protection; // protection for class members diff --git a/dmd/statement.c b/dmd/statement.c index 0c7c9e4a..ea268d15 100644 --- a/dmd/statement.c +++ b/dmd/statement.c @@ -388,7 +388,7 @@ Statements *CompileStatement::flatten(Scope *sc) //printf("CompileStatement::flatten() %s\n", exp->toChars()); exp = exp->semantic(sc); exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->ctfeInterpret(); if (exp->op == TOKerror) return NULL; StringExp *se = exp->toString(); @@ -1739,18 +1739,6 @@ Statement *ForeachStatement::semantic(Scope *sc) Type *tret = func->type->nextOf(); - // Need a variable to hold value from any return statements in body. - if (!sc->func->vresult && tret && tret != Type::tvoid) - { - VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noscope = 1; - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - sc->func->vresult = v; - } - /* Turn body into the function literal: * int delegate(ref T arg) { body } */ @@ -2558,7 +2546,8 @@ Statement *PragmaStatement::semantic(Scope *sc) Expression *e = (*args)[i]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + if (e->op != TOKerror && e->op != TOKtype) + e = e->ctfeInterpret(); StringExp *se = e->toString(); if (se) { @@ -2584,7 +2573,7 @@ Statement *PragmaStatement::semantic(Scope *sc) Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; StringExp *se = e->toString(); if (!se) @@ -2615,7 +2604,7 @@ Statement *PragmaStatement::semantic(Scope *sc) { Expression *e = (*args)[0]; e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); (*args)[0] = e; Dsymbol *sa = getDsymbol(e); if (!sa || !sa->isFuncDeclaration()) @@ -2954,7 +2943,7 @@ Statement *CaseStatement::semantic(Scope *sc) } exp = exp->implicitCastTo(sc, sw->condition->type); - exp = exp->optimize(WANTvalue | WANTinterpret); + exp = exp->ctfeInterpret(); if (exp->op != TOKstring && exp->op != TOKint64 && exp->op != TOKerror) { error("case must be a string or an integral constant, not %s", exp->toChars()); @@ -3054,11 +3043,11 @@ Statement *CaseRangeStatement::semantic(Scope *sc) first = first->semantic(sc); first = first->implicitCastTo(sc, sw->condition->type); - first = first->optimize(WANTvalue | WANTinterpret); + first = first->ctfeInterpret(); last = last->semantic(sc); last = last->implicitCastTo(sc, sw->condition->type); - last = last->optimize(WANTvalue | WANTinterpret); + last = last->ctfeInterpret(); if (first->op == TOKerror || last->op == TOKerror) return statement ? statement->semantic(sc) : NULL; @@ -3286,6 +3275,7 @@ ReturnStatement::ReturnStatement(Loc loc, Expression *exp) : Statement(loc) { this->exp = exp; + this->implicit0 = 0; } Statement *ReturnStatement::syntaxCopy() @@ -3303,7 +3293,6 @@ Statement *ReturnStatement::semantic(Scope *sc) FuncDeclaration *fd = sc->parent->isFuncDeclaration(); Scope *scx = sc; - int implicit0 = 0; Expression *eorg = NULL; if (fd->fes) @@ -3370,6 +3359,12 @@ Statement *ReturnStatement::semantic(Scope *sc) else fd->nrvo_can = 0; +#if 0 + if (fd->returnLabel && tbret && tbret->ty != Tvoid) + { + } + else +#endif if (fd->inferRetType) { Type *tfret = fd->type->nextOf(); @@ -3455,10 +3450,11 @@ Statement *ReturnStatement::semantic(Scope *sc) // Construct: return vresult; if (!fd->vresult) { // Declare vresult + Scope *sco = fd->scout ? fd->scout : scx; VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); v->noscope = 1; - v->semantic(scx); - if (!scx->insert(v)) + v->semantic(sco); + if (!sco->insert(v)) assert(0); v->parent = fd; fd->vresult = v; @@ -3481,7 +3477,7 @@ Statement *ReturnStatement::semantic(Scope *sc) { if (fd->returnLabel && tbret->ty != Tvoid) { - assert(fd->vresult); + fd->buildResultVar(); VarExp *v = new VarExp(0, fd->vresult); assert(eorg); @@ -3798,9 +3794,16 @@ Statement *SynchronizedStatement::semantic(Scope *sc) { /* Cast the interface to an object, as the object has the monitor, * not the interface. */ - Type *t = new TypeIdentifier(0, Id::Object); + if (!ClassDeclaration::object) + { + error("missing or corrupt object.d"); + fatal(); + } + + Type *t = ClassDeclaration::object->type; + t = t->semantic(0, sc)->toBasetype(); + assert(t->ty == Tclass); - t = t->semantic(0, sc); exp = new CastExp(loc, exp, t); exp = exp->semantic(sc); } diff --git a/dmd/statement.h b/dmd/statement.h index 1fc7c24f..c78816b1 100644 --- a/dmd/statement.h +++ b/dmd/statement.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 @@ -634,6 +634,7 @@ struct SwitchErrorStatement : Statement struct ReturnStatement : Statement { Expression *exp; + int implicit0; ReturnStatement(Loc loc, Expression *exp); Statement *syntaxCopy(); diff --git a/dmd/staticassert.c b/dmd/staticassert.c index 6c358ebc..062219c2 100644 --- a/dmd/staticassert.c +++ b/dmd/staticassert.c @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2011 by Digital Mars +// Copyright (c) 1999-2012 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -54,10 +54,14 @@ void StaticAssert::semantic2(Scope *sc) { //printf("StaticAssert::semantic2() %s\n", toChars()); Expression *e = exp->semantic(sc); - if (e->type == Type::terror) + if (!e->type->checkBoolean()) + { + if (e->type->toBasetype() != Type::terror) + exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); return; + } unsigned olderrs = global.errors; - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (global.errors != olderrs) { errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars()); @@ -69,7 +73,7 @@ void StaticAssert::semantic2(Scope *sc) OutBuffer buf; msg = msg->semantic(sc); - msg = msg->optimize(WANTvalue | WANTinterpret); + msg = msg->ctfeInterpret(); hgs.console = 1; msg->toCBuffer(&buf, &hgs); error("%s", buf.toChars()); diff --git a/dmd/struct.c b/dmd/struct.c index 03e26fa4..ad1f5975 100644 --- a/dmd/struct.c +++ b/dmd/struct.c @@ -97,7 +97,7 @@ void AggregateDeclaration::semantic3(Scope *sc) sc = sc->push(this); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; s->semantic3(sc); } sc->pop(); @@ -111,7 +111,7 @@ void AggregateDeclaration::inlineScan() { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; //printf("inline scan aggregate symbol '%s'\n", s->toChars()); s->inlineScan(); } @@ -120,7 +120,9 @@ void AggregateDeclaration::inlineScan() unsigned AggregateDeclaration::size(Loc loc) { - //printf("AggregateDeclaration::size() = %d\n", structsize); + //printf("AggregateDeclaration::size() %s, scope = %p\n", toChars(), scope); + if (loc.linnum == 0) + loc = this->loc; if (!members) error(loc, "unknown size"); if (sizeok != SIZEOKdone && scope) @@ -153,11 +155,13 @@ int AggregateDeclaration::isExport() */ void AggregateDeclaration::alignmember( - unsigned salign, // struct alignment that is in effect + structalign_t salign, // struct alignment that is in effect unsigned size, // alignment requirement of field unsigned *poffset) { - //printf("salign = %d, size = %d, offset = %d\n",salign,size, *poffset); + //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); + if (salign == STRUCTALIGN_DEFAULT) + salign = 8; if (salign > 1) { assert(size != 3); @@ -178,7 +182,7 @@ 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 + structalign_t 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 @@ -195,6 +199,8 @@ unsigned AggregateDeclaration::placeField( if (global.params.is64bit && memalign == 8 && memalignsize == 16) /* Not sure how to handle this */ ; + else if (memalign == STRUCTALIGN_DEFAULT && 8 < memalignsize) + memalignsize = 8; else if (memalign < memalignsize) memalignsize = memalign; if (*paggalignsize < memalignsize) @@ -212,13 +218,13 @@ int AggregateDeclaration::firstFieldInUnion(int indx) { if (isUnionDeclaration()) return 0; - VarDeclaration * vd = fields.tdata()[indx]; + VarDeclaration * vd = fields[indx]; int firstNonZero = indx; // first index in the union with non-zero size for (; ;) { if (indx == 0) return firstNonZero; - VarDeclaration * v = fields.tdata()[indx - 1]; + VarDeclaration * v = fields[indx - 1]; if (v->offset != vd->offset) return firstNonZero; --indx; @@ -237,7 +243,7 @@ int AggregateDeclaration::firstFieldInUnion(int indx) */ int AggregateDeclaration::numFieldsInUnion(int firstIndex) { - VarDeclaration * vd = fields.tdata()[firstIndex]; + VarDeclaration * vd = fields[firstIndex]; /* If it is a zero-length field, AND we can't find an earlier non-zero * sized field with the same offset, we assume it's not part of a union. */ @@ -247,7 +253,7 @@ int AggregateDeclaration::numFieldsInUnion(int firstIndex) int count = 1; for (size_t i = firstIndex+1; i < fields.dim; ++i) { - VarDeclaration * v = fields.tdata()[i]; + VarDeclaration * v = fields[i]; // If offsets are different, they are not in the same union if (v->offset != vd->offset) break; @@ -268,6 +274,8 @@ StructDeclaration::StructDeclaration(Loc loc, Identifier *id) postblit = NULL; eq = NULL; #endif + arg1type = NULL; + arg2type = NULL; // For forward references type = new TypeStruct(this); @@ -289,7 +297,7 @@ void StructDeclaration::semantic(Scope *sc) { Scope *sc2; - //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, toChars(), sizeok); + //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok); //static int count; if (++count == 20) halt(); @@ -330,18 +338,12 @@ 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->invariantOf(); - else if (storage_class & STCconst) - type = type->constOf(); -#endif if (sizeok == SIZEOKnone) // if not already done the addMember step { for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); s->addMember(sc, this, 1); } @@ -379,7 +381,9 @@ void StructDeclaration::semantic(Scope *sc) // Ungag errors when not speculative unsigned oldgag = global.gag; if (global.isSpeculativeGagging() && !isSpeculative()) + { global.gag = 0; + } s->semantic(sc2); global.gag = oldgag; #if 0 @@ -540,6 +544,15 @@ void StructDeclaration::semantic(Scope *sc) aggNew = (NewDeclaration *)search(0, Id::classNew, 0); aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); + TypeTuple *tup = type->toArgTypes(); + size_t dim = tup->arguments->dim; + if (dim >= 1) + { assert(dim <= 2); + arg1type = (*tup->arguments)[0]->type; + if (dim == 2) + arg2type = (*tup->arguments)[1]->type; + } + if (sc->func) { semantic2(sc); @@ -565,6 +578,7 @@ Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) void StructDeclaration::finalizeSize(Scope *sc) { + //printf("StructDeclaration::finalizeSize() %s\n", toChars()); if (sizeok != SIZEOKnone) return; @@ -593,6 +607,23 @@ void StructDeclaration::finalizeSize(Scope *sc) sizeok = SIZEOKdone; } +/*************************************** + * Return true if struct is POD (Plain Old Data). + * This is defined as: + * not nested + * no postblits, constructors, destructors, or assignment operators + * no fields with with any of those + * The idea being these are compatible with C structs. + * + * Note that D struct constructors can mean POD, since there is always default + * construction with no ctor, but that interferes with OPstrpar which wants it + * on the stack in memory, not in registers. + */ +bool StructDeclaration::isPOD() +{ + return true; +} + void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->printf("%s ", kind()); @@ -609,7 +640,7 @@ void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writenl(); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; buf->writestring(" "); s->toCBuffer(buf, hgs); diff --git a/dmd/template.c b/dmd/template.c index a8989e5c..a0b3943f 100644 --- a/dmd/template.c +++ b/dmd/template.c @@ -86,7 +86,7 @@ int isError(Object *o) return (t->ty == Terror); Expression *e = isExpression(o); if (e) - return (e->op == TOKerror); + return (e->op == TOKerror || !e->type || e->type->ty== Terror); Tuple *v = isTuple(o); if (v) return arrayObjectIsError(&v->objects); @@ -100,7 +100,7 @@ int arrayObjectIsError(Objects *args) { for (size_t i = 0; i < args->dim; i++) { - Object *o = (Object *)args->data[i]; + Object *o = (*args)[i]; if (isError(o)) return 1; } @@ -244,8 +244,8 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) goto Lnomatch; for (size_t i = 0; i < u1->objects.dim; i++) { - if (!match(u1->objects.tdata()[i], - u2->objects.tdata()[i], + if (!match(u1->objects[i], + u2->objects[i], tempdecl, sc)) goto Lnomatch; } @@ -270,8 +270,8 @@ int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, if (oa1->dim != oa2->dim) return 0; for (size_t j = 0; j < oa1->dim; j++) - { Object *o1 = (Object *)oa1->data[j]; - Object *o2 = (Object *)oa2->data[j]; + { Object *o1 = (*oa1)[j]; + Object *o2 = (*oa2)[j]; if (!match(o1, o2, tempdecl, sc)) { return 0; @@ -364,7 +364,7 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, #if 0 if (parameters) for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + { TemplateParameter *tp = (*parameters)[i]; //printf("\tparameter[%d] = %p\n", i, tp); TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); @@ -411,8 +411,8 @@ Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) p = new TemplateParameters(); p->setDim(parameters->dim); for (size_t i = 0; i < p->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - p->data[i] = (void *)tp->syntaxCopy(); + { TemplateParameter *tp = (*parameters)[i]; + (*p)[i] = tp->syntaxCopy(); } } Expression *e = NULL; @@ -477,8 +477,10 @@ void TemplateDeclaration::semantic(Scope *sc) /* Remember Scope for later instantiations, but make * a copy since attributes can change. */ - this->scope = new Scope(*sc); - this->scope->setNoFree(); + if (!this->scope) + { this->scope = new Scope(*sc); + this->scope->setNoFree(); + } // Set up scope for parameters ScopeDsymbol *paramsym = new ScopeDsymbol(); @@ -697,21 +699,51 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, */ for (size_t i = 0; i < dedtypes_dim; i++) { - if (!dedtypes->data[i]) + if (!(*dedtypes)[i]) { assert(i < ti->tiargs->dim); - dedtypes->data[i] = ti->tiargs->data[i]; + (*dedtypes)[i] = (Type *)(*ti->tiargs)[i]; } } } #if DMDV2 - if (m && constraint && !(flag & 1)) + if (m && constraint && !flag) { /* Check to see if constraint is satisfied. */ + makeParamNamesVisibleInConstraint(paramscope, fargs); Expression *e = constraint->syntaxCopy(); - paramscope->flags |= SCOPEstaticif; - e = e->semantic(paramscope); - e = e->optimize(WANTvalue | WANTinterpret); + Scope *sc = paramscope->push(); + + /* There's a chicken-and-egg problem here. We don't know yet if this template + * instantiation will be a local one (isnested is set), and we won't know until + * after selecting the correct template. Thus, function we're nesting inside + * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). + * Workaround the problem by setting a flag to relax the checking on frame errors. + */ + sc->flags |= SCOPEstaticif; + + FuncDeclaration *fd = onemember && onemember->toAlias() ? + onemember->toAlias()->isFuncDeclaration() : NULL; + Dsymbol *s = parent; + while (s->isTemplateInstance() || s->isTemplateMixin()) + s = s->parent; + AggregateDeclaration *ad = s->isAggregateDeclaration(); + VarDeclaration *vthissave; + if (fd && ad) + { + vthissave = fd->vthis; + fd->vthis = fd->declareThis(paramscope, ad); + } + + e = e->semantic(sc); + if (e->op == TOKerror) + goto Lnomatch; + + if (fd && fd->vthis) + fd->vthis = vthissave; + + sc->pop(); + e = e->ctfeInterpret(); if (e->isBool(TRUE)) ; else if (e->isBool(FALSE)) @@ -732,16 +764,16 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, { for (size_t i = 0; i < dedtypes_dim; i++) { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + TemplateParameter *tp = (*parameters)[i]; Object *oarg; printf(" [%d]", i); if (i < ti->tiargs->dim) - oarg = (Object *)ti->tiargs->data[i]; + oarg = (*ti->tiargs)[i]; else oarg = NULL; - tp->print(oarg, (Object *)dedtypes->data[i]); + tp->print(oarg, (*dedtypes)[i]); } } else @@ -1299,12 +1331,71 @@ Lmatch: #if DMDV2 if (constraint) { /* Check to see if constraint is satisfied. + * Most of this code appears twice; this is a good candidate for refactoring. */ - makeParamNamesVisibleInConstraint(paramscope); + makeParamNamesVisibleInConstraint(paramscope, fargs); Expression *e = constraint->syntaxCopy(); paramscope->flags |= SCOPEstaticif; + + /* Detect recursive attempts to instantiate this template declaration, + * Bugzilla 4072 + * void foo(T)(T x) if (is(typeof(foo(x)))) { } + * static assert(!is(typeof(foo(7)))); + * Recursive attempts are regarded as a constraint failure. + */ + int nmatches = 0; + for (Previous *p = previous; p; p = p->prev) + { + if (arrayObjectMatch(p->dedargs, dedargs, this, sc)) + { + //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); + /* It must be a subscope of p->sc, other scope chains are not recursive + * instantiations. + */ + for (Scope *scx = sc; scx; scx = scx->enclosing) + { + if (scx == p->sc) + goto Lnomatch; + } + } + /* BUG: should also check for ref param differences + */ + } + + Previous pr; + pr.prev = previous; + pr.sc = paramscope; + pr.dedargs = dedargs; + previous = ≺ // add this to threaded list + + int nerrors = global.errors; + + FuncDeclaration *fd = onemember && onemember->toAlias() ? + onemember->toAlias()->isFuncDeclaration() : NULL; + Dsymbol *s = parent; + while (s->isTemplateInstance() || s->isTemplateMixin()) + s = s->parent; + AggregateDeclaration *ad = s->isAggregateDeclaration(); + VarDeclaration *vthissave; + if (fd && ad) + { + vthissave = fd->vthis; + fd->vthis = fd->declareThis(paramscope, ad); + } + e = e->semantic(paramscope); - e = e->optimize(WANTvalue | WANTinterpret); + + if (fd && fd->vthis) + fd->vthis = vthissave; + + previous = pr.prev; // unlink from threaded list + + if (nerrors != global.errors) // if any errors from evaluating the constraint, no match + goto Lnomatch; + if (e->op == TOKerror) + goto Lnomatch; + + e = e->ctfeInterpret(); if (e->isBool(TRUE)) ; else if (e->isBool(FALSE)) @@ -1317,8 +1408,8 @@ Lmatch: #endif #if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { Type *t = (Type *)dedargs->data[i]; + for (i = 0; i < dedargs->dim; i++) + { Type *t = (*dedargs)[i]; printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); } #endif @@ -1363,6 +1454,12 @@ void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Obj } } } + if (ea && ea->op == TOKtype) + targ = ea->type; + else if (ea && ea->op == TOKimport) + sa = ((ScopeExp *)ea)->sds; + else if (ea && (ea->op == TOKthis || ea->op == TOKsuper)) + sa = ((ThisExp *)ea)->var; if (targ) { @@ -1457,13 +1554,13 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, printf(" targsi:\n"); if (targsi) { for (size_t i = 0; i < targsi->dim; i++) - { Object *arg = (Object *)targsi->data[i]; + { Object *arg = (*targsi)[i]; printf("\t%s\n", arg->toChars()); } } printf(" fargs:\n"); for (size_t i = 0; i < fargs->dim; i++) - { Expression *arg = fargs->tdata()[i]; + { Expression *arg = (*fargs)[i]; printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); //printf("\tty = %d\n", arg->type->ty); } @@ -1483,10 +1580,9 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, goto Lerror; } - MATCH m; Objects dedargs; - m = td->deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, &dedargs); + MATCH m = td->deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, &dedargs); //printf("deduceFunctionTemplateMatch = %d\n", m); if (!m) // if no match continue; @@ -1524,7 +1620,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, td_best = td; m_best = m; tdargs->setDim(dedargs.dim); - memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *)); + memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); continue; } if (!td_best) @@ -1575,7 +1671,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, { if (i) bufa.writeByte(','); - Object *oarg = args->tdata()[i]; + Object *oarg = (*args)[i]; ObjectToCBuffer(&bufa, &hgs, oarg); } } @@ -1583,7 +1679,7 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, OutBuffer buf; argExpTypesToCBuffer(&buf, fargs, &hgs); if (this->overnext) - ::error(loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", + ::error(this->loc, "%s %s.%s cannot deduce template function from argument types !(%s)(%s)", kind(), parent->toPrettyChars(), ident->toChars(), bufa.toChars(), buf.toChars()); else @@ -1979,7 +2075,7 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para for (; 1; tupi++) { if (tupi == parameters->dim) goto L1; - TemplateParameter *t = (TemplateParameter *)parameters->data[tupi]; + TemplateParameter *t = (*parameters)[tupi]; TemplateTupleParameter *tup = t->isTemplateTupleParameter(); if (tup && tup->ident->equals(tid->ident)) break; @@ -1992,7 +2088,7 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para /* See if existing tuple, and whether it matches or not */ - Object *o = (Object *)dedtypes->data[tupi]; + Object *o = (*dedtypes)[tupi]; if (o) { // Existing deduced argument must be a tuple, and must match Tuple *t = isTuple(o); @@ -2000,7 +2096,7 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para return MATCHnomatch; for (size_t i = 0; i < tuple_dim; i++) { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - if (!arg->type->equals((Object *)t->objects.data[i])) + if (!arg->type->equals(t->objects[i])) return MATCHnomatch; } } @@ -2010,9 +2106,9 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para t->objects.setDim(tuple_dim); for (size_t i = 0; i < tuple_dim; i++) { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - t->objects.data[i] = (void *)arg->type; + t->objects[i] = arg->type; } - dedtypes->data[tupi] = (void *)t; + (*dedtypes)[tupi] = t; } nfparams--; // don't consider the last parameter for type deduction goto L2; @@ -2043,8 +2139,8 @@ MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *pa for (size_t i = 0; i < idents.dim; i++) { - Identifier *id1 = (Identifier *)idents.data[i]; - Identifier *id2 = (Identifier *)tp->idents.data[i]; + Identifier *id1 = idents[i]; + Identifier *id2 = tp->idents[i]; if (!id1->equals(id2)) return MATCHnomatch; @@ -2082,7 +2178,19 @@ MATCH TypeInstance::deduceType(Scope *sc, { /* Didn't find it as a parameter identifier. Try looking * it up and seeing if is an alias. See Bugzilla 1454 */ - Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL); + TypeIdentifier *tid = new TypeIdentifier(0, tp->tempinst->name); + Type *t; + Expression *e; + Dsymbol *s; + tid->resolve(0, sc, &e, &t, &s); + if (t) + { + s = t->toDsymbol(sc); + if (s) + { TemplateInstance *ti = s->parent->isTemplateInstance(); + s = ti ? ti->tempdecl : NULL; + } + } if (s) { s = s->toAlias(); @@ -2092,7 +2200,7 @@ MATCH TypeInstance::deduceType(Scope *sc, } goto Lnomatch; } - TemplateParameter *tpx = (TemplateParameter *)parameters->data[i]; + TemplateParameter *tpx = (*parameters)[i]; // This logic duplicates tpx->matchArg() TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); if (!ta) @@ -2102,14 +2210,14 @@ MATCH TypeInstance::deduceType(Scope *sc, goto Lnomatch; if (ta->specAlias && sa != ta->specAlias) goto Lnomatch; - if (dedtypes->data[i]) + if ((*dedtypes)[i]) { // Must match already deduced symbol - Object *s = (Object *)dedtypes->data[i]; + Object *s = (*dedtypes)[i]; if (s != sa) goto Lnomatch; } - dedtypes->data[i] = sa; + (*dedtypes)[i] = sa; } } else if (tempinst->tempdecl != tp->tempinst->tempdecl) @@ -2120,22 +2228,66 @@ MATCH TypeInstance::deduceType(Scope *sc, for (size_t i = 0; 1; i++) { //printf("\ttest: tempinst->tiargs[%d]\n", i); - Object *o1; + Object *o1 = NULL; if (i < tempinst->tiargs->dim) - o1 = (Object *)tempinst->tiargs->data[i]; + o1 = (*tempinst->tiargs)[i]; else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) // Pick up default arg - o1 = (Object *)tempinst->tdtypes.data[i]; - else + o1 = tempinst->tdtypes[i]; + else if (i >= tp->tempinst->tiargs->dim) break; if (i >= tp->tempinst->tiargs->dim) goto Lnomatch; - Object *o2 = (Object *)tp->tempinst->tiargs->data[i]; + Object *o2 = (*tp->tempinst->tiargs)[i]; + Type *t2 = isType(o2); + + int j; + if (t2 && + t2->ty == Tident && + i == tp->tempinst->tiargs->dim - 1 && + (j = templateParameterLookup(t2, parameters), j != -1) && + j == parameters->dim - 1 && + (*parameters)[j]->isTemplateTupleParameter()) + { + /* Given: + * struct A(B...) {} + * alias A!(int, float) X; + * static if (is(X Y == A!(Z), Z...)) {} + * deduce that Z is a tuple(int, float) + */ + + /* Create tuple from remaining args + */ + Tuple *vt = new Tuple(); + size_t vtdim = (tempinst->tempdecl->isVariadic() + ? tempinst->tiargs->dim : tempinst->tdtypes.dim) - i; + vt->objects.setDim(vtdim); + for (size_t k = 0; k < vtdim; k++) + { + Object *o; + if (k < tempinst->tiargs->dim) + o = (*tempinst->tiargs)[i + k]; + else // Pick up default arg + o = tempinst->tdtypes[i + k]; + vt->objects[k] = o; + } + + Tuple *v = (Tuple *)(*dedtypes)[j]; + if (v) + { + if (!match(v, vt, tempinst->tempdecl, sc)) + goto Lnomatch; + } + else + (*dedtypes)[j] = vt; + break; //return MATCHexact; + } + else if (!o1) + break; Type *t1 = isType(o1); - Type *t2 = isType(o2); Expression *e1 = isExpression(o1); Expression *e2 = isExpression(o2); @@ -2156,44 +2308,6 @@ MATCH TypeInstance::deduceType(Scope *sc, if (v2) printf("v2 = %s\n", v2->toChars()); #endif - TemplateTupleParameter *ttp; - int j; - if (t2 && - t2->ty == Tident && - i == tp->tempinst->tiargs->dim - 1 && - i == tempinst->tempdecl->parameters->dim - 1 && - (ttp = tempinst->tempdecl->isVariadic()) != NULL) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (!is(X Y == A!(Z), Z)) - * deduce that Z is a tuple(int, float) - */ - - j = templateParameterLookup(t2, parameters); - if (j == -1) - goto Lnomatch; - - /* Create tuple from remaining args - */ - Tuple *vt = new Tuple(); - size_t vtdim = tempinst->tiargs->dim - i; - vt->objects.setDim(vtdim); - for (size_t k = 0; k < vtdim; k++) - vt->objects.data[k] = (void *)tempinst->tiargs->data[i + k]; - - Tuple *v = (Tuple *)dedtypes->data[j]; - if (v) - { - if (!match(v, vt, tempinst->tempdecl, sc)) - goto Lnomatch; - } - else - dedtypes->data[j] = vt; - break; //return MATCHexact; - } - if (t1 && t2) { if (!t1->deduceType(sc, t2, parameters, dedtypes)) @@ -2201,6 +2315,12 @@ MATCH TypeInstance::deduceType(Scope *sc, } else if (e1 && e2) { + Le: + e1 = e1->ctfeInterpret(); + e2 = e2->ctfeInterpret(); + + //printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty); + //printf("e2 = %s, type = %s %d\n", e2->toChars(), e2->type->toChars(), e2->type->ty); if (!e1->equals(e2)) { if (e2->op == TOKvar) { @@ -2210,6 +2330,12 @@ MATCH TypeInstance::deduceType(Scope *sc, j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); goto L1; } + if (!e2->implicitConvTo(e1->type)) + goto Lnomatch; + + e2 = e2->implicitCastTo(sc, e1->type); + e2 = e2->ctfeInterpret(); + if (!e1->equals(e2)) goto Lnomatch; } } @@ -2218,13 +2344,18 @@ MATCH TypeInstance::deduceType(Scope *sc, j = templateParameterLookup(t2, parameters); L1: if (j == -1) + { + t2->resolve(loc, sc, &e2, &t2, &s2); + if (e2) + goto Le; goto Lnomatch; - TemplateParameter *tp = (TemplateParameter *)parameters->data[j]; + } + TemplateParameter *tp = (*parameters)[j]; // BUG: use tp->matchArg() instead of the following TemplateValueParameter *tv = tp->isTemplateValueParameter(); if (!tv) goto Lnomatch; - Expression *e = (Expression *)dedtypes->data[j]; + Expression *e = (Expression *)(*dedtypes)[j]; if (e) { if (!e1->equals(e)) @@ -2235,20 +2366,31 @@ MATCH TypeInstance::deduceType(Scope *sc, MATCH m = (MATCH)e1->implicitConvTo(vt); if (!m) goto Lnomatch; - dedtypes->data[j] = e1; + (*dedtypes)[j] = e1; } } + else if (s1 && s2) + { + Ls: + if (!s1->equals(s2)) + goto Lnomatch; + } else if (s1 && t2 && t2->ty == Tident) { j = templateParameterLookup(t2, parameters); if (j == -1) + { + t2->resolve(loc, sc, &e2, &t2, &s2); + if (s2) + goto Ls; goto Lnomatch; - TemplateParameter *tp = (TemplateParameter *)parameters->data[j]; + } + TemplateParameter *tp = (*parameters)[j]; // BUG: use tp->matchArg() instead of the following TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); if (!ta) goto Lnomatch; - Dsymbol *s = (Dsymbol *)dedtypes->data[j]; + Dsymbol *s = (Dsymbol *)(*dedtypes)[j]; if (s) { if (!s1->equals(s)) @@ -2256,15 +2398,9 @@ MATCH TypeInstance::deduceType(Scope *sc, } else { - dedtypes->data[j] = s1; + (*dedtypes)[j] = s1; } } - else if (s1 && s2) - { - if (!s1->equals(s2)) - goto Lnomatch; - } - // BUG: Need to handle tuple parameters else goto Lnomatch; } @@ -2890,14 +3026,14 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, //printf("TemplateAliasParameter::matchArg()\n"); if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; + oarg = (*tiargs)[i]; else { // Get default argument instead oarg = defaultArg(loc, sc); if (!oarg) { assert(i < dedtypes->dim); // It might have already been deduced - oarg = dedtypes->tdata()[i]; + oarg = (*dedtypes)[i]; if (!oarg) goto Lnomatch; } @@ -2911,23 +3047,33 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, { if (!sa || sa == sdummy) goto Lnomatch; - if (sa != specAlias) + if (sa != specAlias && isDsymbol(sa)) + { + TemplateInstance *ti = isDsymbol(sa)->isTemplateInstance(); + Type *ta = isType(specAlias); + if (!ti || !ta) goto Lnomatch; + Type *t = new TypeInstance(0, ti); + MATCH m = t->deduceType(sc, ta, parameters, dedtypes); + if (m == MATCHnomatch) + goto Lnomatch; + } } - else if (dedtypes->data[i]) + else if ((*dedtypes)[i]) { // Must match already deduced symbol - Dsymbol *s = (Dsymbol *)dedtypes->data[i]; + Object *si = (*dedtypes)[i]; - if (!sa || s != sa) + if (!sa || si != sa) goto Lnomatch; } - dedtypes->data[i] = sa; + (*dedtypes)[i] = sa; *psparam = new AliasDeclaration(loc, ident, sa); return MATCHexact; Lnomatch: *psparam = NULL; + //printf("\tm = %d\n", MATCHnomatch); return MATCHnomatch; } @@ -3056,7 +3202,7 @@ void TemplateValueParameter::semantic(Scope *sc) e = e->semantic(sc); e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (e->op == TOKint64 || e->op == TOKfloat64 || e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) specValue = e; @@ -3069,7 +3215,7 @@ void TemplateValueParameter::semantic(Scope *sc) e = e->semantic(sc); e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); if (e->op == TOKint64) defaultValue = e; //e->toInteger(); @@ -3141,11 +3287,11 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, e = e->semantic(sc); e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); + e = e->ctfeInterpret(); ei = ei->syntaxCopy(); ei = ei->semantic(sc); - ei = ei->optimize(WANTvalue | WANTinterpret); + ei = ei->ctfeInterpret(); //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); //printf("e : %s, %s\n", e->toChars(), e->type->toChars()); if (!ei->equals(e)) @@ -3555,21 +3701,31 @@ void TemplateInstance::semantic(Scope *sc) } else { - /* Run semantic on each argument, place results in tiargs[] - * (if we havetempdecl, then tiargs is already evaluated) + /* Find template declaration first. */ - semanticTiargs(sc); - if (arrayObjectIsError(tiargs)) - { inst = this; + tempdecl = findTemplateDeclaration(sc); + if (!tempdecl) + { if (!sc->parameterSpecialization) + inst = this; //printf("error return %p, %d\n", tempdecl, global.errors); return; // error recovery } - tempdecl = findTemplateDeclaration(sc); - if (tempdecl) - tempdecl = findBestMatch(sc); + /* Run semantic on each argument, place results in tiargs[] + * (if we have tempdecl, then tiargs is already evaluated) + */ + semanticTiargs(sc); + if (arrayObjectIsError(tiargs)) + { if (!sc->parameterSpecialization) + inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + return; // error recovery + } + + tempdecl = findBestMatch(sc); if (!tempdecl || global.errors) - { inst = this; + { if (!sc->parameterSpecialization) + inst = this; //printf("error return %p, %d\n", tempdecl, global.errors); return; // error recovery } @@ -3583,7 +3739,7 @@ void TemplateInstance::semantic(Scope *sc) for (size_t i = 0; i < tempdecl->instances.dim; i++) { - TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i]; + TemplateInstance *ti = tempdecl->instances[i]; #if LOG printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); #endif @@ -3720,7 +3876,7 @@ void TemplateInstance::semantic(Scope *sc) a->push(this); break; } - if (this == a->tdata()[i]) // if already in Array + if (this == (*a)[i]) // if already in Array break; } } @@ -3756,7 +3912,7 @@ void TemplateInstance::semantic(Scope *sc) int memnum = 0; for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = members->tdata()[i]; + Dsymbol *s = (*members)[i]; #if LOG printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); #endif @@ -3847,7 +4003,7 @@ void TemplateInstance::semantic(Scope *sc) * or semantic3() yet. */ for (size_t i = 0; i < Module::deferred.dim; i++) - { Dsymbol *sd = Module::deferred.tdata()[i]; + { Dsymbol *sd = Module::deferred[i]; if (sd->parent == this) goto Laftersemantic; @@ -3917,7 +4073,7 @@ void TemplateInstance::semantic(Scope *sc) { // Because we added 'this' in the last position above, we // should be able to remove it without messing other indices up. - assert(target_symbol_list->tdata()[target_symbol_list_idx] == this); + assert((*target_symbol_list)[target_symbol_list_idx] == this); target_symbol_list->remove(target_symbol_list_idx); } semanticRun = PASSinit; @@ -3953,12 +4109,12 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f return; for (size_t j = 0; j < tiargs->dim; j++) { - Object *o = (Object *)tiargs->data[j]; + Object *o = (*tiargs)[j]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); - //printf("1: tiargs->data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); + //printf("1: (*tiargs)[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); if (ta) { //printf("type %s\n", ta->toChars()); @@ -3967,13 +4123,13 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f if (ea) { ea = ea->semantic(sc); - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->data[j] = ea; + ea = ea->ctfeInterpret(); + (*tiargs)[j] = ea; } else if (sa) { Ldsym: - tiargs->tdata()[j] = sa; + (*tiargs)[j] = sa; TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); if (d) { @@ -3994,19 +4150,19 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f if (dim) { tiargs->reserve(dim); for (size_t i = 0; i < dim; i++) - { Parameter *arg = tt->arguments->tdata()[i]; + { Parameter *arg = (*tt->arguments)[i]; tiargs->insert(j + i, arg->type); } } j--; } else - tiargs->tdata()[j] = ta; + (*tiargs)[j] = ta; } else { assert(global.errors); - tiargs->data[j] = Type::terror; + (*tiargs)[j] = Type::terror; } } else if (ea) @@ -4017,8 +4173,8 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f } assert(ea); ea = ea->semantic(sc); - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->data[j] = ea; + ea = ea->ctfeInterpret(); + (*tiargs)[j] = ea; if (ea->op == TOKtype) { ta = ea->type; goto Ltype; @@ -4047,13 +4203,13 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f { assert(0); } - //printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]); + //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); } #if 0 printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this); for (size_t j = 0; j < tiargs->dim; j++) { - Object *o = (Object *)tiargs->data[j]; + Object *o = (*tiargs)[j]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); @@ -4291,7 +4447,7 @@ TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc) { assert(ea); ea = ea->castTo(tvp->valType); - ea = ea->optimize(WANTvalue | WANTinterpret); + ea = ea->ctfeInterpret(); tiargs->data[i] = (Object *)ea; } } @@ -4444,7 +4600,7 @@ Identifier *TemplateInstance::genIdent() } else if (ea) { - ea = ea->optimize(WANTvalue | WANTinterpret); + ea = ea->ctfeInterpret(); if (ea->op == TOKvar) { sa = ((VarExp *)ea)->var; @@ -5359,10 +5515,14 @@ int TemplateMixin::hasPointers() void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion) { + //printf("TemplateMixin::setFieldOffset() %s\n", toChars()); + if (scope) // if fwd reference + semantic(NULL); // try to resolve it if (members) { for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; + //printf("\t%s\n", s->toChars()); s->setFieldOffset(ad, poffset, isunion); } }